fix(windows): vswhere detection + winget build-tools install; reconcile fork-origin onto current main - #3
Conversation
…concile fork-origin onto post-rename repo name Reconciles the field-proven Windows installer fix (PR #1, fix/windows-install-mjs, which got Foothills PM running) onto current main, and adds the Windows guide (PR #2, docs/windows-install-guide). install.mjs: - Replace the dead `npm install -g windows-build-tools` path (package deprecated/ removed) with vswhere DETECTION + `winget install Microsoft.VisualStudio.2022. BuildTools` install. vswhere finds the toolset even when cl.exe isn't on PATH (the false "build tools missing" failure mid-install). - Drop the redundant `cl.exe /?` probe; keep `where cl.exe` + vswhere fallback. - Update the final C++-error hint (was L613) to the winget command. - Adopt PR #1's richer isCanonicalOrigin / isForkOrigin fork-migration logic, reconciled to the POST-RENAME canonical name noogalabs/ascendops (PR #1 was authored pre-rename and referenced noogalabs/ascendops-install). Guides (WINDOWS-INSTALL.md, PRE-CALL-CHECKLIST.md): install URLs updated to the canonical noogalabs/ascendops name. Mac and Linux code paths are byte-untouched (verified: outside the Windows build-tools hunk and the fork-origin hunk, the file is identical to main). node --check passes. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 24a4ac72a8
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| > **Why a separate Windows guide?** The Mac install (SKOOL-INSTALL.md) is a couple | ||
| > of commands. Windows needs three extra things set up by hand — Node.js, Git, and | ||
| > the Visual C++ build tools — and the order matters. This guide walks each one. |
There was a problem hiding this comment.
Add WSL to the Windows setup path
For a zero-start Windows machine without WSL, this guide walks through only Node, Git, and Visual C++ Build Tools before running the installer, but the installer itself checks wsl and warns that “agents will not work without it on Windows” because shell scripts run in bash. Following this guide as written can therefore complete the install flow and proceed to onboarding with a fleet that cannot run its Windows shell-script dependency; add a WSL install/restart step before Step 6 or list it as a required prerequisite here.
Useful? React with 👍 / 👎.
…o-write (Codex P2 #3, docs side) Third trigger of the same onboarded-without-crons class: the daemon retro-write (agent-process.ts:1006-1029) marks an agent onboarded if MEMORY.md is >80 chars AND has no <!--, OR a heartbeat.json exists. The interview fills IDENTITY ## Name early, so MEMORY.md's <!-- comment is the only remaining content-guard; if it is dropped before .onboarded is written, a crash/restart lets the daemon retro-write and skip cron registration. Docs-side fix (this commit): strip the MEMORY.md template comment ONLY inside the final &&-chain, AFTER the role crons register and immediately BEFORE touch .onboarded (portable grep -vF into a same-dir tmp + mv, && chained so a strip failure halts before touch). The interview keeps the comment until then. Added an INVARIANT guard comment in all 3 ONBOARDING.md: no heartbeat write before the final block (it would reopen the existsSync(heartbeatPath) branch). Committed MEMORY.md retains <!-- so the bundle ships un-onboarded by content. Tests: +3 assertions (committed MEMORY.md has <!--; strip sits between crons and touch; negative-control guard that strip is not before the crons). 20/20 green, bash -n clean x3, halt-proof both branches (leftover -> comment RETAINED + no .onboarded; clean -> comment GONE after 6 crons), negative-control verified red. NOTE: the heartbeat OR-branch (fast-checker.ts 50-min watchdog) is daemon-side and handled in a SEPARATE cortextos fork PR (fire-time .onboarded gate). This bundle PR HOLDS to merge together with that daemon PR; the content branch alone is not sufficient.
…or classroom bundles (#18) * feat(community): guided onboarding v2 - reverse-prompting interview for classroom bundles The classroom download bundles previously required hand-editing ~13 bootstrap files. v2 makes a fresh agent INTERVIEW the operator over Telegram on first boot and configure itself from the answers (reverse prompting: the agent asks, the operator answers, the agent writes its own config). Trigger (the framework's own mechanism, restored): - IDENTITY '## Name' ships an HTML-comment marker ('<!-- Set during onboarding -->') instead of {{agent_name}}, plus a '<!--' marker in MEMORY. hasCompletedBootstrapContent (agent-process.ts) treats '<!--' as "still a template", so it does NOT retro-write .onboarded on first boot -> isOnboarded=false -> buildStartupPrompt injects the first-boot prompt -> the onboarding skill runs the interview. The interview writes .onboarded at the end, so it never re-fires. This is exactly how the hub's own templates/agent-leasing-coordinator onboards; the classroom bundles had lacked it ({{agent_name}} in ## Name read as "complete" -> onboarding was skipped). Adds per bundle: - ONBOARDING.md: the role-specific reverse-prompting interview (accounting / leasing / maintenance). Asks for company/owner/timezone, software stack, and the operator's SOPs/preferences; writes IDENTITY/USER/SYSTEM/goals + ingests SOPs to the KB; adds the recommended role crons as the final step; writes .onboarded. Copilot-first. - .claude/skills/onboarding/SKILL.md: the generic onboarding skill (scrubbed clean). Ship-time config stays enabled=true + crons=[] (the interview adds crons post-config), so the cron-safety test still holds. The onboarding files pass verify-clean-gate (scrub gate-enforced: planting our-data in them goes DIRTY). Test: classroom-agents-cron-safe.test.ts now also guards the trigger contract (IDENTITY marker + ONBOARDING.md + onboarding skill present per bundle) and exempts ONBOARDING.md / the onboarding skill from the no-cron-in-docs check (adding crons post-interview is intended). 13/13 pass. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018XzqKvXygRBULsAxEHMyse * fix(community): onboarding sets ## Name to the add-agent slug (Codex P2) cortextos add-agent's copyTemplateFiles rewrites {{agent_name}} -> the CLI agent slug BEFORE ONBOARDING.md is ever read (add-agent.ts:421). So by interview time there are no {{agent_name}} placeholders left, only the ## Name marker. Asking the operator for a name in the interview therefore only changed ## Name while SOUL/SYSTEM/cron-prompts kept the slug = inconsistent. Fix: the agent's name IS the slug the operator chose at `add-agent <name>` (already filled consistently everywhere). Onboarding now sets ## Name to $CTX_AGENT_NAME, drops the no-op "replace {{agent_name}} everywhere" instruction, and the add-cron / list-crons commands use "$CTX_AGENT_NAME". The page docs note: pick the name you want at add-agent time. (A different display name remains optional, with a note to keep $CTX_AGENT_NAME for commands/bus.) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018XzqKvXygRBULsAxEHMyse * fix(community): normalize remaining list-crons agent arg to $CTX_AGENT_NAME (Aussie) Aussie's completeness pass caught a residual of the same name-consistency class: a leasing ONBOARDING.md list-crons command still used the <your-agent-name> placeholder. Swept ALL three ONBOARDING.md for any placeholder-agent-arg (<your-agent-name>/<this-agent-name>/<agent-name>) in agent-run commands and normalized them all to "$CTX_AGENT_NAME". The README keeps <your-agent-name> on purpose: that is the member-run MANUAL path where it is a fill-in placeholder, not an agent-run command. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018XzqKvXygRBULsAxEHMyse * fix(community): comprehensive placeholder hard-gate + Telegram-cred restart (Codex 3xP2) Codex caught 3 real P2s on the guided-onboarding v2 (add-agent only fills {{agent_name}}/{{org}}, so every other {{...}} is the interview's job): 1+2. Placeholder coverage gap: {{company_name}} lives in CLAUDE.md, sibling-agent names ({{leasing_agent_name}}/{{maintenance_agent_name}}) and rubric vars live in .claude/skills/**/SKILL.md - none covered by the old hardcoded bootstrap-file replacement lists. A member could write .onboarded with literal placeholders in Claude's main prompt or a scheduled skill. Fix: a HARD GATE before .onboarded in both the shared onboarding skill (Step 4) and each ONBOARDING.md: if grep -rlE '\{\{[^{}]+\}\}' . --include='*.md' --include='*.json' \ | grep -vE 'ONBOARDING.md|README.md|skills/onboarding/|node_modules'; then STOP else touch .onboarded; fi Recursive (reaches CLAUDE.md + all skills), format-COMPLETE ({{[^{}]+}} catches any placeholder format incl digits/hyphens/uppercase, not just lowercase_underscore), and excludes the self-referencing setup docs so it PASSES once runtime files are filled (verified halts-on-leftover AND passes-when-clean). 3. Telegram-cred restart: a fresh agent that writes BOT_TOKEN/CHAT_ID via detect-chat-id mid-interview wont receive inbound replies until restart (the poller is built from .env at spawn). Step 0 now restarts after writing creds; primary path stays "set .env before first start" per the page docs. CI guard: classroom-agents-cron-safe.test.ts asserts each ONBOARDING.md + skill carry the hard gate (recursive, format-complete, excludes setup docs) and a behavioral test that the gate regex catches a future-format placeholder and passes clean text. 17/17. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018XzqKvXygRBULsAxEHMyse * fix(community): gate-before-crons + name-marker in the onboarding gate (Codex 2xP2) Two ordering/signal edges on the placeholder hard gate: A. The add-cron commands ran BEFORE the gate, so a missed placeholder let the crons persist to daemon state (and fire against a still-templated agent) even though the gate then refused .onboarded. Fix: the gate now WRAPS the crons - they live in the else branch, so crons are persisted only when the gate passes clean. Gate-then-crons. B. The gate grepped only {{...}}, not the ## Name '<!-- Set during onboarding -->' marker. Fill-every-placeholder-but-leave-the-marker passed the gate and wrote .onboarded, leaving the agent booting "onboarded" with a template marker as its display name (the daemon's hasCompletedBootstrapContent keys on '<!--' in ## Name). Fix: the gate also rejects the marker - it now covers every signal the daemon trigger keys on ({{...}} OR the name marker), in both the ONBOARDING.md and the shared onboarding skill. Halt-proofed both directions: ship-time -> gate halts (0 crons); all {{...}} filled but marker left -> halts on the marker; all filled + marker replaced -> passes (crons + .onboarded). CI test extended: gate covers {{...}}|marker, crons are inside the else (no add-cron before the gate), and the behavioral check halts on a leftover, a future format, and the marker, and passes clean. 17/17. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018XzqKvXygRBULsAxEHMyse * fix(community): restore eaten kb-ingest + drop stray template line + Step 0 restart (Codex 2xP2) Two paste-path edges on b533836: 1. The shared onboarding skill Step 0 had the restart-after-detect-chat-id caveat but each ONBOARDING.md's own Step 0 (which the first-boot prompt sends the agent to) did not. A member who did not prefill .env wires the bot there, then cannot receive replies until restart. Added the restart caveat to the accounting and maintenance ONBOARDING.md Step 0 (leasing Step 0 does not write creds). 2. Maintenance: the gate-wrap restructure matched the PROSE template line (`add-cron "$CTX_AGENT_NAME" <name> "<schedule>"...`) as if a real cron, which region-shifted and (a) left that literal-<name> line inside the gate else (would break the pasted block) and (b) ate the make-ready-sops kb-ingest command. Removed the stray line and restored the kb-ingest. accounting/leasing were unaffected (their first add-cron is a real cron, not prose). Verified the WHOLE maintenance file (not just the 3 spots): paste-path `bash -n` clean (no literal <name>/<schedule>), code fences balanced, Steps 0-7 coherent, all 3 kb-ingests present, 5 crons in the else matching the README. 17/17. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018XzqKvXygRBULsAxEHMyse * fix(community): leasing Step 0 Telegram wiring + atomic-on-success cron completion (Codex P2+P3) 1. P2 - leasing parity: leasing ONBOARDING.md had no Telegram-credential check (cred- check presence was accounting=1, maintenance=3, leasing=0), yet its reverse-prompting interview is over Telegram and starts by SENDING a message. A fresh leasing agent with an empty .env would stall. Added the same Step 0 bot-wiring + restart caveat as the other two (before the intro). 2. P3 - atomic-on-success: the gate else-block ran the add-cron commands then `touch .onboarded` SEQUENTIALLY with no `set -e`/`&&`, so a failed add-cron (non-zero on a bad arg) fell through and marked onboarding complete with a missing cron (silent failure, no retry). All 3 bundles now &&-chain crons -> list-crons -> mkdir -> touch .onboarded -> echo, with an `|| echo "STOP: a cron failed ... .onboarded was NOT written ..."` fallback. The marker is written only on a fully-successful setup. Halt-proofed: bash -n clean on all 3 gate blocks; a simulated add-cron failure aborts the && chain BEFORE touch, so .onboarded is NOT written and the operator is told to fix+re-run. 17/17. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018XzqKvXygRBULsAxEHMyse * fix(community): idempotent cron cleanup so a partial-fail re-run is not stuck (Aussie) The &&-chain (atomic-on-success) correctly refuses .onboarded if an add-cron fails, but cortextos bus add-cron throws on a duplicate cron name (crons.ts:229, not idempotent). So a PARTIAL failure (crons 1-2 persist, 3 fails) left .onboarded unwritten AND crons 1-2 persisted - re-running the block would re-add the existing crons 1-2, error on the duplicate, and never reach .onboarded = permanently stuck. Fix: each gate else-block first runs an idempotent remove-cron cleanup over all the cron names (remove-cron never throws, returns false if absent), THEN the &&-chained add-cron sequence. So a re-run after a partial failure clears the prior crons and re-adds them cleanly; a real add-cron failure (bad arg) still aborts the chain before .onboarded. Halt-proofed: bash -n clean; partial-prior-run (a cron pre-persisted) -> cleanup clears it -> add-chain completes -> reaches .onboarded (rerun-safe). 17/17. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018XzqKvXygRBULsAxEHMyse * fix(community): single .onboarded completion authority - skill defers to ONBOARDING.md post-cron block (Codex P2) Dual-completion-path bug: the onboarding SKILL Step 4 ran its own placeholder sweep and touched .onboarded WITHOUT the role crons, while ONBOARDING.md's final block touched .onboarded AFTER adding them. An agent following the skill path reached ONBOARDED-WITHOUT-CRONS, and .onboarded suppresses re-onboarding so the crons never got added. Fix: one .onboarded writer. SKILL Step 4 no longer writes .onboarded; it defers to ONBOARDING.md's final block, which gates on placeholders+marker, adds the role crons, and only then writes .onboarded (&&-chained, so a cron failure blocks it). Applied across all 3 bundles (accounting/leasing/maintenance). Test: the cron-safe contract previously asserted BOTH ONBOARDING.md AND the skill carry the touch-.onboarded gate (it encoded the dual path). Reworked to enforce single-authority: ONBOARDING.md carries the full gate+crons+touch; the skill must NOT touch .onboarded and must point at ONBOARDING.md. 17/17 green. * fix(community): close MEMORY.md content-branch of the .onboarded retro-write (Codex P2 #3, docs side) Third trigger of the same onboarded-without-crons class: the daemon retro-write (agent-process.ts:1006-1029) marks an agent onboarded if MEMORY.md is >80 chars AND has no <!--, OR a heartbeat.json exists. The interview fills IDENTITY ## Name early, so MEMORY.md's <!-- comment is the only remaining content-guard; if it is dropped before .onboarded is written, a crash/restart lets the daemon retro-write and skip cron registration. Docs-side fix (this commit): strip the MEMORY.md template comment ONLY inside the final &&-chain, AFTER the role crons register and immediately BEFORE touch .onboarded (portable grep -vF into a same-dir tmp + mv, && chained so a strip failure halts before touch). The interview keeps the comment until then. Added an INVARIANT guard comment in all 3 ONBOARDING.md: no heartbeat write before the final block (it would reopen the existsSync(heartbeatPath) branch). Committed MEMORY.md retains <!-- so the bundle ships un-onboarded by content. Tests: +3 assertions (committed MEMORY.md has <!--; strip sits between crons and touch; negative-control guard that strip is not before the crons). 20/20 green, bash -n clean x3, halt-proof both branches (leftover -> comment RETAINED + no .onboarded; clean -> comment GONE after 6 crons), negative-control verified red. NOTE: the heartbeat OR-branch (fast-checker.ts 50-min watchdog) is daemon-side and handled in a SEPARATE cortextos fork PR (fire-time .onboarded gate). This bundle PR HOLDS to merge together with that daemon PR; the content branch alone is not sufficient. --------- Co-authored-by: David Hunter <davidhunter@Davids-Mac-mini.local> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
What & why
Reconciles the field-proven Windows installer fix (PR #1
fix/windows-install-mjs, which got Foothills PM running on Windows) onto current main, and adds the Windows guide (PR #2docs/windows-install-guide). PR #1 didn't cherry-pick cleanly because main already had a simpler post-rename origin check while PR #1 carried richer logic against the old pre-rename name. Resolved by hand.Blast radius note:
install.mjsis the live public install script every new member runs. Mac/Linux zero-regression is the gate, and is verified byte-level below.1. Windows build-tools block — before/after
The dead
npm install -g windows-build-toolspackage (long deprecated/removed) is GONE. Replaced with vswhere DETECTION + winget install.Before (main):
After (this branch):
The final C++-compilation-error hint (was L613) was also switched from the dead npm package to the winget command.
AUTO_BUILD_TOOLS=1env gate is retained — it now triggers the winget auto-install, not the dead package.2. Resolved fork-origin block
Kept PR #1's richer
isCanonicalOrigin/isForkOriginlogic (handles a personal fork as origin → adds canonicalupstreaminstead of silently skipping migration), but corrected the repo-name references to the post-renamenoogalabs/ascendops(PR #1 referenced the oldnoogalabs/ascendops-install). Main's existing canonical-match behavior (includes('noogalabs/ascendops'),grandamenium/cortextos,=== REPO_URL) is preserved verbatim — the new branch only adds the fork case on top.3. Mac/Linux paths untouched — verification
The full diff to
install.mjsis exactly these hunks (git diff main):All four hunks are inside the
IS_WINDOWSbranch or the fork-origin migration block. A line-by-line script that strips those three regions from both main and this branch confirms the remainder is byte-identical — the only other delta is the deliberate removal of one now-inaccurate comment line in the fork block. TheIS_MAC(brew/xcode-select) andIS_LINUX(apt-get/build-essential) paths are unchanged.No
ascendops-installregression ininstall.mjs(main's canonical name preserved). Guide install URLs updated to the canonical name.4. Gates
node --check install.mjs→ CLEANDo not merge — leaving for human review.