Skip to content

Commit fad8daa

Browse files
feat(web): add manifest module selection resolver
1 parent 8698b00 commit fad8daa

9 files changed

Lines changed: 1994 additions & 4 deletions

File tree

.beads/issues.jsonl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -975,7 +975,7 @@
975975
{"id":"bd-pp6h","title":"Test session.sh (export/import streaming)","status":"closed","priority":2,"issue_type":"task","owner":"jeff141421@gmail.com","created_at":"2026-01-15T18:05:19.400397287Z","created_by":"Dicklesworthstone","updated_at":"2026-01-15T18:24:34.981782461Z","closed_at":"2026-01-15T18:24:34.981784635Z","source_repo":".","compaction_level":0,"original_size":0,"dependencies":[{"issue_id":"bd-pp6h","depends_on_id":"bd-dzm4","type":"parent","created_at":"2026-01-15T18:05:19.485025315Z","created_by":"Dicklesworthstone","metadata":"","thread_id":""}]}
976976
{"id":"bd-prqs","title":"Core Library Unit Tests","status":"closed","priority":1,"issue_type":"task","owner":"jeff141421@gmail.com","created_at":"2026-01-15T18:04:07.533145380Z","created_by":"Dicklesworthstone","updated_at":"2026-01-15T18:19:33.243684696Z","closed_at":"2026-01-15T18:19:33.243687291Z","source_repo":".","compaction_level":0,"original_size":0,"dependencies":[{"issue_id":"bd-prqs","depends_on_id":"bd-3xf3","type":"parent","created_at":"2026-01-15T18:04:07.631968593Z","created_by":"Dicklesworthstone","metadata":"","thread_id":""},{"issue_id":"bd-prqs","depends_on_id":"bd-u09z","type":"blocker","created_at":"2026-01-15T18:04:07.657667773Z","created_by":"Dicklesworthstone","metadata":"","thread_id":""}]}
977977
{"id":"bd-pu11","title":"Fix CAAM 'list' to 'ls' in safety-tools-lesson.tsx","description":"BACKGROUND\n==========\nDuring deep-dive analysis of the CAAM source code and README, discovered that the safety-tools-lesson.tsx uses 'caam list' but the correct command is 'caam ls'.\n\nSOURCE VERIFICATION\n===================\nFrom /tmp/dicklesworthstone_tools/caam/README.md line 210:\n | caam ls [tool] | List all saved profiles in vault |\n\nFrom CAAM CLI source code (no 'list' subcommand defined - 'ls' is the command).\n\nThe README Quick Start section (line 193-196) also shows:\n $ caam ls claude\n alice@gmail.com\n bob@gmail.com\n carol@gmail.com\n\nISSUE LOCATIONS\n===============\n1. Line 229: Command list shows 'caam list [tool]'\n Should be: 'caam ls [tool]'\n\n2. Line 344: Quick Reference shows 'caam list [tool]'\n Should be: 'caam ls [tool]'\n\nFIX\n===\nReplace 'caam list' with 'caam ls' in both locations.\n\nREASONING\n=========\n- 'ls' is the canonical command per CAAM README and source code\n- 'list' is NOT a valid CAAM command (will error if user tries it)\n- Lesson content must match official tool documentation to avoid confusion\n\nTESTING\n=======\nAfter fix, verify commands match CAAM README section 'Command Reference > Auth File Swapping'","status":"closed","priority":1,"issue_type":"bug","created_at":"2025-12-25T23:00:17.385730Z","updated_at":"2025-12-25T23:01:00.475866Z","closed_at":"2025-12-25T23:01:00.475866Z","close_reason":"Fixed 'caam list' to 'caam ls' in both command list (line 229) and quick reference (line 345)","source_repo":".","compaction_level":0,"original_size":0,"dependencies":[{"issue_id":"bd-pu11","depends_on_id":"bd-lyf0","type":"blocks","created_at":"2025-12-25T23:00:24.093155Z","created_by":"daemon","metadata":"{}","thread_id":""}]}
978-
{"id":"bd-pzler","title":"Implement manifest-backed module selection resolver","description":"## What\nImplement the shared resolver that turns requested profiles/modules into a concrete install plan.\n\n## Why\nSelection must be deterministic and auditable before installer work begins. The resolver should be reusable from installer preflight, wizard command generation, and tests.\n\n## Approach\n- Use manifest generated metadata for module IDs, categories, phases, dependencies, optionality, and default enablement.\n- Produce machine-readable JSON and human-readable plan output.\n- Fail before mutation when an unknown module, missing dependency, impossible skip, or conflicting profile is requested.\n\n## Tests\nUnit tests must cover empty input, all profiles, dependency expansion, skipped required modules, invalid module IDs, ordering by phase, and stable JSON snapshots.\n\n## Success Criteria\n`--print-plan` and web command previews can call the same resolver behavior and show matching output.\n\n## Acceptance Criteria\n- Scope in this bead is implemented or documented without hidden compatibility shims.\n- Unit, script, Playwright, VM, or fixture tests are added according to the affected surface; skipped live/provider tests name the required environment.\n- Logs and artifacts are detailed enough for support or CI triage and redact credentials, tokens, IPs, and provider-sensitive values where applicable.\n- Website, installer, generated-manifest, onboarding, support-bundle, and docs surfaces stay consistent when the change touches more than one of them.\n- Required quality gates for touched surfaces pass, including shellcheck for Bash, Bun type-check/lint/build for web work, `br lint`, dependency-cycle checks, and `ubs` before commit.","acceptance_criteria":"- Scope in the description is implemented or documented with no hidden compatibility shim.\n- Unit, script, Playwright, VM, or fixture tests are added according to the affected surface; skipped live/provider tests must name the required environment.\n- Logs and artifacts are detailed enough for support or CI triage and redact credentials, tokens, IPs, and provider-sensitive values where applicable.\n- Website, installer, generated-manifest, onboarding, support-bundle, and docs surfaces stay consistent when the change touches more than one of them.\n- Required quality gates for touched surfaces pass, including shellcheck for Bash, Bun type-check/lint/build for web work, `br lint`, dependency-cycle checks, and `ubs` before commit.","notes":"## Refinement Safety Notes\n- Preserve verified-installer checksum discipline; selection or generation work must not create any unverified install path.\n- Required core modules must be locked or explicitly explained before any skip is accepted.\n- Prefer dry-run/plan output before mutation, and include tests for invalid input, required-module refusal, and no hidden side effects.\n- Do not add compatibility shims for deprecated option names; update the canonical path directly.","status":"open","priority":1,"issue_type":"feature","created_at":"2026-05-08T19:47:52.134267326Z","created_by":"ubuntu","updated_at":"2026-05-08T20:07:53.082274412Z","source_repo":".","compaction_level":0,"original_size":0,"labels":["installer","manifest","module-selection","tests"],"dependencies":[{"issue_id":"bd-pzler","depends_on_id":"bd-mitxy","type":"blocks","created_at":"2026-05-08T19:47:57.869996847Z","created_by":"ubuntu","metadata":"{}","thread_id":""}]}
978+
{"id":"bd-pzler","title":"Implement manifest-backed module selection resolver","description":"## What\nImplement the shared resolver that turns requested profiles/modules into a concrete install plan.\n\n## Why\nSelection must be deterministic and auditable before installer work begins. The resolver should be reusable from installer preflight, wizard command generation, and tests.\n\n## Approach\n- Use manifest generated metadata for module IDs, categories, phases, dependencies, optionality, and default enablement.\n- Produce machine-readable JSON and human-readable plan output.\n- Fail before mutation when an unknown module, missing dependency, impossible skip, or conflicting profile is requested.\n\n## Tests\nUnit tests must cover empty input, all profiles, dependency expansion, skipped required modules, invalid module IDs, ordering by phase, and stable JSON snapshots.\n\n## Success Criteria\n`--print-plan` and web command previews can call the same resolver behavior and show matching output.\n\n## Acceptance Criteria\n- Scope in this bead is implemented or documented without hidden compatibility shims.\n- Unit, script, Playwright, VM, or fixture tests are added according to the affected surface; skipped live/provider tests name the required environment.\n- Logs and artifacts are detailed enough for support or CI triage and redact credentials, tokens, IPs, and provider-sensitive values where applicable.\n- Website, installer, generated-manifest, onboarding, support-bundle, and docs surfaces stay consistent when the change touches more than one of them.\n- Required quality gates for touched surfaces pass, including shellcheck for Bash, Bun type-check/lint/build for web work, `br lint`, dependency-cycle checks, and `ubs` before commit.","acceptance_criteria":"- Scope in the description is implemented or documented with no hidden compatibility shim.\n- Unit, script, Playwright, VM, or fixture tests are added according to the affected surface; skipped live/provider tests must name the required environment.\n- Logs and artifacts are detailed enough for support or CI triage and redact credentials, tokens, IPs, and provider-sensitive values where applicable.\n- Website, installer, generated-manifest, onboarding, support-bundle, and docs surfaces stay consistent when the change touches more than one of them.\n- Required quality gates for touched surfaces pass, including shellcheck for Bash, Bun type-check/lint/build for web work, `br lint`, dependency-cycle checks, and `ubs` before commit.","notes":"## Refinement Safety Notes\n- Preserve verified-installer checksum discipline; selection or generation work must not create any unverified install path.\n- Required core modules must be locked or explicitly explained before any skip is accepted.\n- Prefer dry-run/plan output before mutation, and include tests for invalid input, required-module refusal, and no hidden side effects.\n- Do not add compatibility shims for deprecated option names; update the canonical path directly.","status":"closed","priority":1,"issue_type":"feature","created_at":"2026-05-08T19:47:52.134267326Z","created_by":"ubuntu","updated_at":"2026-05-08T20:39:20.691540129Z","closed_at":"2026-05-08T20:39:20.691306521Z","close_reason":"Implemented manifest-backed module selection resolver with generated metadata, profile lowering, plan formatting, command-preview selectors, and unit/build verification.","source_repo":".","compaction_level":0,"original_size":0,"labels":["installer","manifest","module-selection","tests"],"dependencies":[{"issue_id":"bd-pzler","depends_on_id":"bd-mitxy","type":"blocks","created_at":"2026-05-08T19:47:57.869996847Z","created_by":"ubuntu","metadata":"{}","thread_id":""}]}
979979
{"id":"bd-q10","title":"Harden installer: true dry-run, onboard source, HTTPS PGDG","description":"Fix install.sh --dry-run so it makes no system changes and works without sudo; install onboard command from packages/onboard/onboard.sh (single source of truth); switch PGDG apt repo URL to HTTPS; fix checksum computation in scripts/lib/security.sh.","status":"closed","priority":1,"issue_type":"bug","assignee":"FuchsiaCreek","created_at":"2025-12-20T18:18:40.054877Z","updated_at":"2025-12-20T18:22:16.261425Z","closed_at":"2025-12-20T18:22:16.261425Z","close_reason":"Fixed install.sh dry-run to make no system changes + allow running without sudo; install onboard from packages/onboard; switch PGDG repo to HTTPS; fix security.sh checksum logic.","source_repo":".","compaction_level":0,"original_size":0}
980980
{"id":"bd-q1igd","title":"Random code-path audit and obvious-bug remediation","description":"Explore several representative code paths across the ACFS repo, trace their runtime/usage flows through adjacent modules, and fix obvious bugs, inconsistencies, and low-hanging defects found during the audit.\n\nAcceptance criteria:\n- Investigate multiple code areas rather than a single file.\n- Apply only well-justified fixes backed by local tracing/verification.\n- Run the relevant verification commands for the touched areas, using rch for CPU-intensive commands.\n- Report findings/fixes clearly in agent mail and final handoff.","status":"closed","priority":2,"issue_type":"chore","created_at":"2026-03-13T06:41:50.396946539Z","created_by":"ubuntu","updated_at":"2026-03-13T06:52:19.776104895Z","closed_at":"2026-03-13T06:52:19.775100434Z","close_reason":"Completed: traced installer/web/manifest flows and verified doctor checks now preserve manifest run_as context","source_repo":".","compaction_level":0,"original_size":0}
981981
{"id":"bd-q1ttx","title":"Implement RCH offload compliance checker for docs and templates","description":"## Parent program\n`bd-nlb8w`; depends on RCH policy `bd-2kncj`.\n\n## What\nCreate a checker that scans ACFS-maintained agent instructions, new project templates, lessons, and docs for CPU-heavy build/test command examples that should use `rch exec --`.\n\n## Why\nA single stale `cargo test` example can create local build storms when dozens of agents copy it. The checker keeps the high-capacity operating model consistent.\n\n## How\nImplement a focused Bash or Bun checker under existing scripts/tests conventions. Prefer structured allowlists and clear findings over brittle global regex replacements. The checker should report file, line, command example, and suggested compliant form.\n\n## Risks\nAvoid false positives for text explaining noncompliant examples or lightweight commands. The checker should be auditable and easy to update as policy changes.\n\n## Success criteria\n- Checker exits nonzero on real policy violations.\n- Includes allowlist/comment convention for intentional examples.\n- Runs in CI or the relevant test suite without new lockfiles.","status":"closed","priority":1,"issue_type":"task","created_at":"2026-05-08T04:32:02.844800066Z","created_by":"ubuntu","updated_at":"2026-05-08T06:36:00.105171522Z","closed_at":"2026-05-08T06:36:00.104755984Z","close_reason":"Completed by SilentPeak; implementation and verification evidence comments attached.","source_repo":".","compaction_level":0,"original_size":0,"labels":["idea-wizard","rch","swarm","tests"],"dependencies":[{"issue_id":"bd-q1ttx","depends_on_id":"bd-2kncj","type":"blocks","created_at":"2026-05-08T04:35:26.712926612Z","created_by":"ubuntu","metadata":"{}","thread_id":""}],"comments":[{"id":89,"issue_id":"bd-q1ttx","author":"SilentPeak","text":"RCH offload compliance checker completed. Evidence: scripts/tests/lint_rch_offload_policy.sh reports file/line/fix suggestions, supports the rch-policy: allow suppression marker, exits nonzero on violations, and is wired into .github/workflows/installer.yml. Current run checked 8 files with 0 violations.","created_at":"2026-05-08T06:35:12Z"}]}

apps/web/lib/commandBuilder.test.ts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,26 @@ describe("buildInstallCommand", () => {
3939
expect(command).not.toContain("/master/install.sh");
4040
expect(command).not.toContain('--ref "master"');
4141
});
42+
43+
test("appends manifest-backed module selectors for profile previews", () => {
44+
const command = buildInstallCommand("vibe", null, "ubuntu", {
45+
profile: "cloud-only",
46+
});
47+
48+
expect(command).toContain('--only "cloud.wrangler"');
49+
expect(command).toContain('--only "cloud.supabase"');
50+
expect(command).toContain('--only "cloud.vercel"');
51+
expect(command).not.toContain("--profile");
52+
expect(command).not.toContain("db.postgres18");
53+
});
54+
55+
test("refuses invalid module selectors instead of serializing them", () => {
56+
expect(() =>
57+
buildInstallCommand("vibe", null, "ubuntu", {
58+
onlyModules: ["agents.codex;sudo"],
59+
}),
60+
).toThrow("Unknown module id in --only: agents.codex;sudo");
61+
});
4262
});
4363

4464
describe("buildCommands", () => {
@@ -92,6 +112,21 @@ describe("buildCommands", () => {
92112
expect(sshUser?.label).toBe("SSH as dev-user.1");
93113
expect(sshUser?.command).toContain("dev-user.1@10.20.30.40");
94114
});
115+
116+
test("propagates optional module selection into the installer command", () => {
117+
const commands = buildCommands({
118+
ip: "10.20.30.40",
119+
os: "mac",
120+
username: "ubuntu",
121+
mode: "vibe",
122+
ref: null,
123+
moduleSelection: { profile: "stack-only" },
124+
});
125+
126+
const installer = commands.find((command) => command.id === "installer");
127+
128+
expect(installer?.command).toContain('--only-phase "9"');
129+
});
95130
});
96131

97132
describe("buildHandoffRunbook", () => {

apps/web/lib/commandBuilder.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
*/
99

1010
import type { OperatingSystem, InstallMode } from "./userPreferences";
11+
import { buildInstallSelectorArgs, type ModuleSelectionInput } from "./moduleSelection";
1112
import { isValidIP, normalizeGitRef, normalizeSSHUsername } from "./userPreferences";
1213

1314
const INSTALL_SCRIPT_BASE_URL =
@@ -22,6 +23,7 @@ export interface CommandBuilderInputs {
2223
username: string;
2324
mode: InstallMode;
2425
ref: string | null;
26+
moduleSelection?: ModuleSelectionInput;
2527
}
2628

2729
export interface GeneratedCommand {
@@ -121,15 +123,18 @@ export function buildInstallCommand(
121123
mode: InstallMode,
122124
ref: string | null,
123125
username?: string | null,
126+
moduleSelection?: ModuleSelectionInput,
124127
): string {
125128
const safeRef = normalizeGitRef(ref);
126129
const safeUsername = normalizeInstallUsername(username);
127130
const installRef = safeRef ?? DEFAULT_INSTALL_REF;
128131
const userEnv = safeUsername ? `TARGET_USER="${safeUsername}" ` : "";
129132
const refArg = safeRef ? ` --ref "${safeRef}"` : "";
133+
const selectorArgs = buildInstallSelectorArgs(moduleSelection).join(" ");
134+
const selectorArgSuffix = selectorArgs ? ` ${selectorArgs}` : "";
130135
const installerUrl = `${INSTALL_SCRIPT_BASE_URL}/${installRef}/install.sh`;
131136

132-
return `curl -fsSL "${installerUrl}?$(date +%s)" | ${userEnv}bash -s -- --yes --mode ${mode}${refArg}`;
137+
return `curl -fsSL "${installerUrl}?$(date +%s)" | ${userEnv}bash -s -- --yes --mode ${mode}${refArg}${selectorArgSuffix}`;
133138
}
134139

135140
/**
@@ -161,7 +166,7 @@ export function buildCommands(inputs: CommandBuilderInputs): GeneratedCommand[]
161166
id: "installer",
162167
label: "Run installer",
163168
description: `Install ACFS in ${mode} mode${safeRef ? ` pinned to ${safeRef}` : ""}`,
164-
command: buildInstallCommand(mode, ref, safeUsername),
169+
command: buildInstallCommand(mode, ref, safeUsername, inputs.moduleSelection),
165170
runLocation: "vps",
166171
});
167172

@@ -217,7 +222,7 @@ export function buildHandoffRunbook(inputs: CommandBuilderInputs): HandoffRunboo
217222
const targetUsername = normalizeCommandUsername(inputs.username);
218223
const redactedHost = redactedTargetHost(inputs.ip);
219224
const targetHostKind = classifyTargetHost(inputs.ip);
220-
const installCommand = buildInstallCommand(inputs.mode, safeRef, targetUsername);
225+
const installCommand = buildInstallCommand(inputs.mode, safeRef, targetUsername, inputs.moduleSelection);
221226
const rootLoginCommand = `ssh root@${redactedHost}`;
222227
const postInstallLoginCommand = `ssh -i ${SSH_KEY_PATH_UNIX} ${targetUsername}@${redactedHost}`;
223228
const postInstallLoginCommandWindows = `ssh -i ${SSH_KEY_PATH_WINDOWS} ${targetUsername}@${redactedHost}`;

0 commit comments

Comments
 (0)