create-agent-rig 0.9.1 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +419 -3
- package/README.md +267 -305
- package/package.json +8 -14
- package/packages/cli/dist/commands/create.js +56 -88
- package/packages/cli/dist/commands/doctor.js +213 -0
- package/packages/cli/dist/commands/init.js +111 -50
- package/packages/cli/dist/commands/integrations.js +468 -0
- package/packages/cli/dist/commands/setup-wizard.js +61 -0
- package/packages/cli/dist/commands/uninstall.js +1223 -0
- package/packages/cli/dist/commands/upgrade.js +472 -90
- package/packages/cli/dist/index.js +651 -46
- package/packages/cli/dist/integrations/declaration.js +158 -0
- package/packages/cli/dist/integrations/doctor-guards.js +126 -0
- package/packages/cli/dist/integrations/doctor-workflow.js +25 -0
- package/packages/cli/dist/integrations/mcp-json.js +107 -0
- package/packages/cli/dist/integrations/memory-doctor.js +124 -0
- package/packages/cli/dist/integrations/registry.js +22 -0
- package/packages/cli/dist/integrations/spawn.js +228 -0
- package/packages/cli/dist/integrations/spec-kit.js +280 -0
- package/packages/cli/dist/integrations/verify.js +193 -0
- package/packages/cli/dist/integrations/windows-job.js +275 -0
- package/packages/cli/dist/lib/elevated-paths.js +74 -0
- package/packages/cli/dist/lib/install-set.js +1 -44
- package/packages/cli/dist/lib/manifest.js +64 -5
- package/packages/cli/dist/lib/prompts.js +0 -23
- package/packages/cli/dist/lib/safe-path.js +193 -2
- package/packages/cli/dist/lib/safe-text.js +78 -0
- package/packages/cli/dist/lib/substitute.js +1 -52
- package/packages/cli/dist/lib/summary.js +5 -5
- package/packages/cli/dist/templates.js +4 -14
- package/scripts/prepare.mjs +28 -12
- package/templates/agent-os/subagent-routing.json +4 -4
- package/templates/agent-os/universal/.agents/skills/check-premises/SKILL.md +13 -9
- package/templates/agent-os/universal/.agents/skills/loop/SKILL.md +31 -6
- package/templates/agent-os/universal/.agents/skills/new-invariant/SKILL.md +5 -5
- package/templates/agent-os/universal/.agents/skills/pr-ship/SKILL.md +1 -1
- package/templates/agent-os/universal/.agents/skills/worktree-task/SKILL.md +3 -3
- package/templates/agent-os/universal/.claude/agents/code-reviewer.md +8 -6
- package/templates/agent-os/universal/.claude/agents/implementation-agent.md +41 -0
- package/templates/agent-os/universal/.claude/agents/prose-reviewer.md +8 -4
- package/templates/agent-os/universal/.claude/agents/security-scanner.md +4 -2
- package/templates/agent-os/universal/.claude/agents/test-writer.md +2 -2
- package/templates/agent-os/universal/.claude/hooks/inject-rules.mjs +83 -4
- package/templates/agent-os/universal/.claude/rules/autonomy.md +55 -27
- package/templates/agent-os/universal/.claude/rules/invariants.md +9 -8
- package/templates/agent-os/universal/.claude/rules/workflow.md +47 -22
- package/templates/agent-os/universal/.claude/scripts/decision-router.mjs +1 -1
- package/templates/agent-os/universal/.claude/scripts/detect-missed-gate.mjs +12 -9
- package/templates/agent-os/universal/.claude/scripts/doctor.mjs +100 -2
- package/templates/agent-os/universal/.claude/scripts/lib/claim-records.mjs +236 -6
- package/templates/agent-os/universal/.claude/scripts/queue/state.mjs +2 -2
- package/templates/agent-os/universal/.claude/scripts/reconcile-external-prs.mjs +4 -3
- package/templates/agent-os/universal/.claude/scripts/revalidate.mjs +16 -0
- package/templates/agent-os/universal/.claude/settings.json +0 -8
- package/templates/agent-os/universal/.claude/skills/check-premises/SKILL.md +13 -9
- package/templates/agent-os/universal/.claude/skills/loop/SKILL.md +31 -6
- package/templates/agent-os/universal/.claude/skills/new-invariant/SKILL.md +5 -5
- package/templates/agent-os/universal/.claude/skills/pr-ship/SKILL.md +1 -1
- package/templates/agent-os/universal/.claude/skills/worktree-task/SKILL.md +3 -3
- package/templates/agent-os/universal/.codex/agents/code-reviewer.toml +2 -2
- package/templates/agent-os/universal/.codex/agents/implementation-agent.toml +6 -0
- package/templates/agent-os/universal/.codex/agents/prose-reviewer.toml +2 -2
- package/templates/agent-os/universal/.codex/agents/security-scanner.toml +1 -1
- package/templates/agent-os/universal/.codex/agents/test-writer.toml +1 -1
- package/templates/agent-os/universal/.codex/hooks.json +0 -10
- package/templates/agent-os/universal/AGENTS.md +208 -107
- package/templates/agent-os/universal/CLAUDE.md +15 -162
- package/templates/agent-os/universal/PLAN.md +17 -10
- package/templates/agent-os/universal/docs/decisions/agents-md-canonical.md +313 -0
- package/templates/agent-os/universal/docs/decisions/codex-adapter.md +15 -10
- package/templates/agent-os/universal/docs/decisions/review-lanes.md +12 -8
- package/templates/agent-os/universal/docs/decisions/session-start-wire-format.md +206 -0
- package/templates/agent-os/universal/docs/decisions/subagent-routing.md +6 -3
- package/templates/agent-os/universal/docs/decisions/workflow-layer-split.md +235 -0
- package/templates/agent-os/universal/layers.json +25 -30
- package/templates/hash-history.json +8 -4
- package/templates/release-ledger.json +2 -1
- package/packages/cli/dist/lib/composition.js +0 -20
- package/packages/cli/dist/lib/targets.js +0 -28
- package/packages/cli/dist/policy/benchmark/corpus.js +0 -165
- package/packages/cli/dist/policy/core/adapter.js +0 -18
- package/packages/cli/dist/policy/core/coverage.js +0 -253
- package/packages/cli/dist/policy/core/decision-record.js +0 -287
- package/packages/cli/dist/policy/core/declaration.js +0 -127
- package/packages/cli/dist/policy/core/evidence-matrix.js +0 -94
- package/packages/cli/dist/policy/core/probe.js +0 -442
- package/packages/cli/dist/policy/core/registry.js +0 -115
- package/packages/cli/dist/policy/core/validation.js +0 -275
- package/packages/cli/dist/policy/core/vocabulary.js +0 -123
- package/packages/cli/dist/policy/harness/claude.js +0 -47
- package/packages/cli/dist/policy/harness/codex.js +0 -87
- package/packages/cli/dist/policy/harness/index.js +0 -15
- package/packages/cli/dist/policy/harness/shared-hooks.js +0 -28
- package/packages/cli/dist/policy/index.js +0 -17
- package/templates/agent-os/init/AGENTS.md +0 -201
- package/templates/agent-os/init/CLAUDE.md +0 -201
- package/templates/agent-os/stack/aws-cdk/.agents/skills/post-deploy-verify/SKILL.md +0 -105
- package/templates/agent-os/stack/aws-cdk/.agents/skills/ro-debug/SKILL.md +0 -117
- package/templates/agent-os/stack/aws-cdk/.claude/agents/cdk-diff-reviewer.md +0 -89
- package/templates/agent-os/stack/aws-cdk/.claude/rules/aws-cdk.md +0 -105
- package/templates/agent-os/stack/aws-cdk/.claude/skills/post-deploy-verify/SKILL.md +0 -105
- package/templates/agent-os/stack/aws-cdk/.claude/skills/ro-debug/SKILL.md +0 -117
- package/templates/agent-os/stack/aws-cdk/.codex/agents/cdk-diff-reviewer.toml +0 -6
- package/templates/agent-os/stack/node-ts/.claude/hooks/dod-checks.json +0 -1
- package/templates/agent-os/stack/node-ts/.claude/rules/node-ts.md +0 -85
- package/templates/agent-os/universal/.claude/hooks/guard-core-purity.mjs +0 -89
- package/templates/agent-os/universal/.claude/hooks/guard-web-boundary.mjs +0 -68
- package/templates/agent-os/universal/.claude/rules/architecture.md +0 -81
- package/templates/skeleton/aws-serverless/.github/workflows/ci.yml +0 -28
- package/templates/skeleton/aws-serverless/.github/workflows/deploy.yml +0 -90
- package/templates/skeleton/aws-serverless/README.md +0 -181
- package/templates/skeleton/aws-serverless/apps/web/next.config.mjs +0 -17
- package/templates/skeleton/aws-serverless/apps/web/package.json +0 -19
- package/templates/skeleton/aws-serverless/apps/web/src/app/layout.tsx +0 -17
- package/templates/skeleton/aws-serverless/apps/web/src/app/page.tsx +0 -96
- package/templates/skeleton/aws-serverless/apps/web/src/lib/api.ts +0 -36
- package/templates/skeleton/aws-serverless/apps/web/src/lib/validate.ts +0 -23
- package/templates/skeleton/aws-serverless/apps/web/test/shared-validation.test.ts +0 -38
- package/templates/skeleton/aws-serverless/apps/web/tsconfig.json +0 -14
- package/templates/skeleton/aws-serverless/eslint.config.mjs +0 -20
- package/templates/skeleton/aws-serverless/gitignore +0 -56
- package/templates/skeleton/aws-serverless/infra/bin/app.ts +0 -79
- package/templates/skeleton/aws-serverless/infra/cdk.json +0 -3
- package/templates/skeleton/aws-serverless/infra/lib/app-stack.ts +0 -248
- package/templates/skeleton/aws-serverless/infra/lib/web-stack.ts +0 -45
- package/templates/skeleton/aws-serverless/infra/package.json +0 -18
- package/templates/skeleton/aws-serverless/infra/test/allowed-origins.test.ts +0 -301
- package/templates/skeleton/aws-serverless/infra/test/app-composition.test.ts +0 -137
- package/templates/skeleton/aws-serverless/infra/test/app-stack.test.ts +0 -120
- package/templates/skeleton/aws-serverless/infra/test/web-stack.test.ts +0 -44
- package/templates/skeleton/aws-serverless/package.json +0 -30
- package/templates/skeleton/aws-serverless/packages/core/package.json +0 -11
- package/templates/skeleton/aws-serverless/packages/core/src/events.ts +0 -14
- package/templates/skeleton/aws-serverless/packages/core/src/index.ts +0 -15
- package/templates/skeleton/aws-serverless/packages/core/src/note.ts +0 -69
- package/templates/skeleton/aws-serverless/packages/core/test/events.test.ts +0 -23
- package/templates/skeleton/aws-serverless/packages/core/test/note.test.ts +0 -101
- package/templates/skeleton/aws-serverless/packages/db/package.json +0 -14
- package/templates/skeleton/aws-serverless/packages/db/src/client.ts +0 -17
- package/templates/skeleton/aws-serverless/packages/db/src/index.ts +0 -2
- package/templates/skeleton/aws-serverless/packages/db/src/note-model.ts +0 -52
- package/templates/skeleton/aws-serverless/packages/db/test/note-model.test.ts +0 -91
- package/templates/skeleton/aws-serverless/packages/shared/package.json +0 -11
- package/templates/skeleton/aws-serverless/packages/shared/src/env.ts +0 -17
- package/templates/skeleton/aws-serverless/packages/shared/src/errors.ts +0 -33
- package/templates/skeleton/aws-serverless/packages/shared/src/index.ts +0 -3
- package/templates/skeleton/aws-serverless/packages/shared/src/logger.ts +0 -20
- package/templates/skeleton/aws-serverless/packages/shared/test/env.test.ts +0 -26
- package/templates/skeleton/aws-serverless/packages/shared/test/errors.test.ts +0 -28
- package/templates/skeleton/aws-serverless/packages/shared/test/logger.test.ts +0 -19
- package/templates/skeleton/aws-serverless/pnpm-lock.yaml +0 -2855
- package/templates/skeleton/aws-serverless/pnpm-workspace.yaml +0 -14
- package/templates/skeleton/aws-serverless/services/api/package.json +0 -15
- package/templates/skeleton/aws-serverless/services/api/src/adapters/sqs-publisher.ts +0 -26
- package/templates/skeleton/aws-serverless/services/api/src/handlers/create-note.ts +0 -69
- package/templates/skeleton/aws-serverless/services/api/src/handlers/list-notes.ts +0 -37
- package/templates/skeleton/aws-serverless/services/api/src/list-main.ts +0 -12
- package/templates/skeleton/aws-serverless/services/api/src/main.ts +0 -21
- package/templates/skeleton/aws-serverless/services/api/src/usecases/create-note.ts +0 -41
- package/templates/skeleton/aws-serverless/services/api/src/usecases/list-notes.ts +0 -14
- package/templates/skeleton/aws-serverless/services/api/test/create-note.handler.test.ts +0 -211
- package/templates/skeleton/aws-serverless/services/api/test/create-note.usecase.test.ts +0 -45
- package/templates/skeleton/aws-serverless/services/api/test/list-notes.test.ts +0 -122
- package/templates/skeleton/aws-serverless/services/api/test/sqs-publisher.test.ts +0 -22
- package/templates/skeleton/aws-serverless/services/worker/package.json +0 -12
- package/templates/skeleton/aws-serverless/services/worker/src/handlers/note-created.ts +0 -15
- package/templates/skeleton/aws-serverless/services/worker/src/main.ts +0 -7
- package/templates/skeleton/aws-serverless/services/worker/src/usecases/process-note-created.ts +0 -37
- package/templates/skeleton/aws-serverless/services/worker/test/note-created.test.ts +0 -61
- package/templates/skeleton/aws-serverless/tsconfig.base.json +0 -15
- package/templates/skeleton/aws-serverless/tsconfig.json +0 -16
- package/templates/skeleton/aws-serverless/vitest.config.ts +0 -14
- package/templates/skeleton/node-service/.github/workflows/ci.yml +0 -27
- package/templates/skeleton/node-service/.github/workflows/deploy.yml +0 -29
- package/templates/skeleton/node-service/README.md +0 -104
- package/templates/skeleton/node-service/apps/web/next.config.mjs +0 -17
- package/templates/skeleton/node-service/apps/web/package.json +0 -19
- package/templates/skeleton/node-service/apps/web/src/app/layout.tsx +0 -17
- package/templates/skeleton/node-service/apps/web/src/app/page.tsx +0 -96
- package/templates/skeleton/node-service/apps/web/src/lib/api.ts +0 -29
- package/templates/skeleton/node-service/apps/web/src/lib/validate.ts +0 -23
- package/templates/skeleton/node-service/apps/web/test/shared-validation.test.ts +0 -38
- package/templates/skeleton/node-service/apps/web/tsconfig.json +0 -14
- package/templates/skeleton/node-service/eslint.config.mjs +0 -20
- package/templates/skeleton/node-service/gitignore +0 -54
- package/templates/skeleton/node-service/package.json +0 -30
- package/templates/skeleton/node-service/packages/core/package.json +0 -11
- package/templates/skeleton/node-service/packages/core/src/events.ts +0 -14
- package/templates/skeleton/node-service/packages/core/src/index.ts +0 -15
- package/templates/skeleton/node-service/packages/core/src/note.ts +0 -69
- package/templates/skeleton/node-service/packages/core/test/events.test.ts +0 -23
- package/templates/skeleton/node-service/packages/core/test/note.test.ts +0 -101
- package/templates/skeleton/node-service/packages/db/package.json +0 -12
- package/templates/skeleton/node-service/packages/db/src/index.ts +0 -1
- package/templates/skeleton/node-service/packages/db/src/note-store.ts +0 -100
- package/templates/skeleton/node-service/packages/db/test/note-store.test.ts +0 -100
- package/templates/skeleton/node-service/packages/shared/package.json +0 -11
- package/templates/skeleton/node-service/packages/shared/src/env.ts +0 -17
- package/templates/skeleton/node-service/packages/shared/src/errors.ts +0 -33
- package/templates/skeleton/node-service/packages/shared/src/index.ts +0 -3
- package/templates/skeleton/node-service/packages/shared/src/logger.ts +0 -20
- package/templates/skeleton/node-service/packages/shared/test/env.test.ts +0 -26
- package/templates/skeleton/node-service/packages/shared/test/errors.test.ts +0 -28
- package/templates/skeleton/node-service/packages/shared/test/logger.test.ts +0 -19
- package/templates/skeleton/node-service/pnpm-lock.yaml +0 -2402
- package/templates/skeleton/node-service/pnpm-workspace.yaml +0 -13
- package/templates/skeleton/node-service/scripts/build-artifact.mjs +0 -34
- package/templates/skeleton/node-service/services/api/package.json +0 -17
- package/templates/skeleton/node-service/services/api/src/adapters/spool-publisher.ts +0 -23
- package/templates/skeleton/node-service/services/api/src/handlers/create-note.ts +0 -40
- package/templates/skeleton/node-service/services/api/src/handlers/list-notes.ts +0 -23
- package/templates/skeleton/node-service/services/api/src/main.ts +0 -40
- package/templates/skeleton/node-service/services/api/src/server.ts +0 -172
- package/templates/skeleton/node-service/services/api/src/static-dir.ts +0 -20
- package/templates/skeleton/node-service/services/api/src/usecases/create-note.ts +0 -30
- package/templates/skeleton/node-service/services/api/src/usecases/list-notes.ts +0 -14
- package/templates/skeleton/node-service/services/api/test/artifact.test.ts +0 -92
- package/templates/skeleton/node-service/services/api/test/create-note.handler.test.ts +0 -64
- package/templates/skeleton/node-service/services/api/test/create-note.usecase.test.ts +0 -43
- package/templates/skeleton/node-service/services/api/test/list-notes.test.ts +0 -48
- package/templates/skeleton/node-service/services/api/test/package-manager.test.ts +0 -40
- package/templates/skeleton/node-service/services/api/test/package-manager.ts +0 -51
- package/templates/skeleton/node-service/services/api/test/server.test.ts +0 -208
- package/templates/skeleton/node-service/services/api/test/spool-publisher.test.ts +0 -32
- package/templates/skeleton/node-service/services/api/test/static-dir.test.ts +0 -29
- package/templates/skeleton/node-service/services/worker/package.json +0 -16
- package/templates/skeleton/node-service/services/worker/src/main.ts +0 -28
- package/templates/skeleton/node-service/services/worker/src/spool.ts +0 -60
- package/templates/skeleton/node-service/services/worker/src/usecases/process-note-created.ts +0 -38
- package/templates/skeleton/node-service/services/worker/test/process-note-created.test.ts +0 -34
- package/templates/skeleton/node-service/services/worker/test/spool.test.ts +0 -76
- package/templates/skeleton/node-service/tsconfig.base.json +0 -15
- package/templates/skeleton/node-service/tsconfig.json +0 -13
- package/templates/skeleton/node-service/vitest.config.ts +0 -12
|
@@ -2,22 +2,59 @@ import { access, lstat, mkdir, readFile, writeFile } from 'node:fs/promises';
|
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { settingsForInstalledHooks } from '../lib/init-settings.js';
|
|
4
4
|
import { mapConcurrent } from '../lib/copy-tree.js';
|
|
5
|
-
import { readManifest, sha256, writeManifest } from '../lib/manifest.js';
|
|
5
|
+
import { ALL_LAYERS, DEFAULT_LAYERS, MANIFEST_REL, readManifest, sha256, writeManifest, } from '../lib/manifest.js';
|
|
6
|
+
import { resolveWritableInside } from '../lib/safe-path.js';
|
|
6
7
|
import { substituteContent } from '../lib/substitute.js';
|
|
7
|
-
import {
|
|
8
|
+
import { agentOsUniversalDir } from '../templates.js';
|
|
8
9
|
import { packageVersion } from '../lib/version.js';
|
|
9
10
|
/** A user-facing failure: message is printed as-is, no stack trace. */
|
|
10
11
|
export class InitError extends Error {
|
|
11
12
|
}
|
|
12
13
|
/** What `--force` answers with now that `upgrade` owns the case it stood in for. */
|
|
13
14
|
export const FORCE_DEPRECATED = 'deprecated — init --force replaced only CLAUDE.md; run create-agent-rig upgrade instead';
|
|
15
|
+
/**
|
|
16
|
+
* The layers this install writes, given what a previous run (if any)
|
|
17
|
+
* recorded and whether this run opted in.
|
|
18
|
+
*
|
|
19
|
+
* Never narrows what a previous run already installed: `--layer workflow` is
|
|
20
|
+
* additive, and a rig that already carries the workflow layer keeps it on a
|
|
21
|
+
* plain re-run with no flag (RP-180's "existing dogfood repositories can
|
|
22
|
+
* explicitly retain the layer" applies to `init` re-runs, not only to
|
|
23
|
+
* `upgrade`).
|
|
24
|
+
*/
|
|
25
|
+
function effectiveLayers(previous, withWorkflow) {
|
|
26
|
+
const wantsWorkflow = withWorkflow || (previous?.layers.includes('workflow') ?? false);
|
|
27
|
+
return wantsWorkflow ? [...ALL_LAYERS] : [...DEFAULT_LAYERS];
|
|
28
|
+
}
|
|
14
29
|
const SETTINGS = '.claude/settings.json';
|
|
15
30
|
const CODEX_HOOKS = '.codex/hooks.json';
|
|
16
31
|
const MAPS = ['CLAUDE.md', 'AGENTS.md'];
|
|
32
|
+
/**
|
|
33
|
+
* Plain, static files this install always ships alongside the process layer,
|
|
34
|
+
* beside the two generated wiring files and the two maps above — neither
|
|
35
|
+
* architecture-specific (RP-177 retired that group entirely) nor subject to
|
|
36
|
+
* the maps' overwrite refusal, so they are appended here rather than folded
|
|
37
|
+
* into either list.
|
|
38
|
+
*/
|
|
39
|
+
const STATIC_EXTRAS = ['.codex/config.toml'];
|
|
17
40
|
async function loadManifest() {
|
|
18
41
|
const raw = await readFile(path.join(agentOsUniversalDir(), 'layers.json'), 'utf8');
|
|
19
42
|
return JSON.parse(raw);
|
|
20
43
|
}
|
|
44
|
+
/**
|
|
45
|
+
* Exactly `layers.json`'s own array for one layer — never the always-added
|
|
46
|
+
* extras (`SETTINGS`, `CODEX_HOOKS`, `STATIC_EXTRAS`, `MAPS`) `initManifest`
|
|
47
|
+
* appends to every layer regardless of which one was asked for. A caller
|
|
48
|
+
* that wants to know whether a SPECIFIC layer's own files are on disk (RP-180
|
|
49
|
+
* round 3, `commands/upgrade.ts`'s `detectLayersOnDisk`) needs this
|
|
50
|
+
* distinction: those extras exist for any rig at all, Core-only included, so
|
|
51
|
+
* checking `initManifest([layer])`'s full output against disk would report
|
|
52
|
+
* every layer as "present" always.
|
|
53
|
+
*/
|
|
54
|
+
export async function layerOnlyPaths(layer) {
|
|
55
|
+
const manifest = await loadManifest();
|
|
56
|
+
return manifest[layer];
|
|
57
|
+
}
|
|
21
58
|
async function exists(p) {
|
|
22
59
|
try {
|
|
23
60
|
await access(p);
|
|
@@ -41,30 +78,25 @@ export function projectNameFor(repoDir) {
|
|
|
41
78
|
return slug === '' ? 'project' : slug;
|
|
42
79
|
}
|
|
43
80
|
/**
|
|
44
|
-
* `init` installs
|
|
45
|
-
*
|
|
46
|
-
* `
|
|
47
|
-
*
|
|
81
|
+
* `init` installs the PROCESS layer (hooks-and-reach brief §3/§4): rules that
|
|
82
|
+
* assume nothing about the codebase shape. Since RP-177 it is the ONLY
|
|
83
|
+
* flavour `create-agent-rig` ships — the architecture group (rules describing
|
|
84
|
+
* `packages/core` and friends) was retired outright, not merely excluded here,
|
|
85
|
+
* so there is no wider install for `create` to fall back to and no override
|
|
86
|
+
* layer left to shadow a universal file.
|
|
48
87
|
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
* - `CLAUDE.md` — the map, taken from the init override layer, which describes
|
|
53
|
-
* the rig this command installs rather than the generated monorepo;
|
|
54
|
-
* - `.claude/settings.json` — the wiring, derived from the shipped settings so
|
|
55
|
-
* it names exactly the hooks that travelled.
|
|
88
|
+
* `.claude/settings.json` and `.codex/hooks.json` are generated rather than
|
|
89
|
+
* copied: derived from the shipped settings so they name exactly the hooks
|
|
90
|
+
* that travelled.
|
|
56
91
|
*/
|
|
57
|
-
export async function initManifest() {
|
|
92
|
+
export async function initManifest(layers = DEFAULT_LAYERS) {
|
|
58
93
|
const manifest = await loadManifest();
|
|
59
94
|
const universal = agentOsUniversalDir();
|
|
60
|
-
const
|
|
61
|
-
const files =
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
source: (await exists(overridden)) ? overridden : path.join(universal, rel),
|
|
66
|
-
};
|
|
67
|
-
});
|
|
95
|
+
const layerFiles = layers.flatMap((layer) => manifest[layer]);
|
|
96
|
+
const files = [...layerFiles, ...STATIC_EXTRAS, ...MAPS].map((rel) => ({
|
|
97
|
+
rel,
|
|
98
|
+
source: path.join(universal, rel),
|
|
99
|
+
}));
|
|
68
100
|
files.push({ rel: SETTINGS, source: null });
|
|
69
101
|
files.push({ rel: CODEX_HOOKS, source: null });
|
|
70
102
|
return files;
|
|
@@ -78,14 +110,12 @@ export async function initManifest() {
|
|
|
78
110
|
* `__PROJECT_NAME__` in `stop-flag.mjs` is a kill switch that silently never
|
|
79
111
|
* fires.
|
|
80
112
|
*/
|
|
81
|
-
export async function initFileContents(repoDir, project) {
|
|
113
|
+
export async function initFileContents(repoDir, project, layers = DEFAULT_LAYERS) {
|
|
82
114
|
const projectName = project?.name ?? projectNameFor(repoDir);
|
|
83
115
|
const ctx = {
|
|
84
116
|
projectName,
|
|
85
|
-
projectScope: project?.scope ?? projectName,
|
|
86
|
-
region: project?.region ?? '',
|
|
87
117
|
};
|
|
88
|
-
const files = await initManifest();
|
|
118
|
+
const files = await initManifest(layers);
|
|
89
119
|
const contents = new Map();
|
|
90
120
|
const sourceFiles = files.filter((file) => file.source !== null);
|
|
91
121
|
const rendered = await mapConcurrent(sourceFiles, 16, async ({ rel, source }) => ({
|
|
@@ -107,13 +137,15 @@ export async function initFileContents(repoDir, project) {
|
|
|
107
137
|
return contents;
|
|
108
138
|
}
|
|
109
139
|
/** The process layer as a set of {@link InstalledFile}s — what `upgrade` reads. */
|
|
110
|
-
export async function initInstallSet(repoDir, project) {
|
|
111
|
-
const files = await initManifest();
|
|
112
|
-
const contents = await initFileContents(repoDir, project);
|
|
140
|
+
export async function initInstallSet(repoDir, project, layers = DEFAULT_LAYERS) {
|
|
141
|
+
const files = await initManifest(layers);
|
|
142
|
+
const contents = await initFileContents(repoDir, project, layers);
|
|
113
143
|
return files.map(({ rel, source }) => ({ rel, source, content: contents.get(rel) ?? '' }));
|
|
114
144
|
}
|
|
115
|
-
export async function planInit(repoDir) {
|
|
116
|
-
const
|
|
145
|
+
export async function planInit(repoDir, options = {}) {
|
|
146
|
+
const previous = await readManifest(repoDir);
|
|
147
|
+
const layers = effectiveLayers(previous, options.withWorkflow === true);
|
|
148
|
+
const files = (await initManifest(layers)).map((f) => f.rel);
|
|
117
149
|
const conflicts = (await mapConcurrent(files, 16, async (rel) => (await exists(path.join(repoDir, rel))) ? rel : null)).filter((rel) => rel !== null);
|
|
118
150
|
return { files: files.map((p) => ({ path: p })), conflicts };
|
|
119
151
|
}
|
|
@@ -123,28 +155,46 @@ export async function initProject(repoDir, options) {
|
|
|
123
155
|
// file from the manifest instead of overriding one refusal wholesale.
|
|
124
156
|
if (options.force)
|
|
125
157
|
throw new InitError(FORCE_DEPRECATED);
|
|
126
|
-
const files = (await initManifest()).map((f) => f.rel);
|
|
127
158
|
const previous = await readManifest(repoDir);
|
|
159
|
+
const layers = effectiveLayers(previous, options.withWorkflow === true);
|
|
160
|
+
const files = (await initManifest(layers)).map((f) => f.rel);
|
|
161
|
+
// Resolve the whole write set before the first edit. A lexical child can
|
|
162
|
+
// still escape through a symlink at the leaf or in any existing parent, and
|
|
163
|
+
// discovering that after another payload file was written would leave a
|
|
164
|
+
// partial install. The manifest is a write too, even on an otherwise-empty
|
|
165
|
+
// re-run, so it belongs in the same preflight.
|
|
166
|
+
const destinations = new Map();
|
|
167
|
+
for (const rel of [...files, MANIFEST_REL]) {
|
|
168
|
+
const dest = await resolveWritableInside(repoDir, rel);
|
|
169
|
+
if (dest === null) {
|
|
170
|
+
throw new InitError(`Refusing to write "${rel}" through a symlink or outside ${repoDir}.`);
|
|
171
|
+
}
|
|
172
|
+
destinations.set(rel, dest);
|
|
173
|
+
}
|
|
128
174
|
// Refuse to clobber an existing CLAUDE.md — init edits someone's working
|
|
129
175
|
// repository (brief §4, non-negotiable).
|
|
130
176
|
for (const map of MAPS) {
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
//
|
|
134
|
-
//
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
sha256(await readFile(
|
|
177
|
+
const dest = destinations.get(map);
|
|
178
|
+
if (dest !== undefined && (await exists(dest))) {
|
|
179
|
+
// A map this rig wrote and that still matches its manifest is safe to
|
|
180
|
+
// skip on an idempotent re-run. An unrecorded or edited map remains the
|
|
181
|
+
// user's guidance and is still refused.
|
|
182
|
+
if (previous?.files[map] !== undefined &&
|
|
183
|
+
sha256(await readFile(dest)) === previous.files[map]) {
|
|
138
184
|
continue;
|
|
139
185
|
}
|
|
140
|
-
|
|
186
|
+
// "AGENTS.md" starts with a vowel SOUND ("a" said as a letter, /eɪ/);
|
|
187
|
+
// "CLAUDE.md" does not — so the article is picked per file rather than
|
|
188
|
+
// hardcoded to "an", which read as "an CLAUDE.md".
|
|
189
|
+
const article = /^[aeiou]/i.test(map) ? 'an' : 'a';
|
|
190
|
+
throw new InitError(`This repo already has ${article} ${map}. Refusing to overwrite it. ` +
|
|
141
191
|
'Merge the agent-os map in by hand, or run create-agent-rig upgrade to refresh a rig.');
|
|
142
192
|
}
|
|
143
193
|
}
|
|
144
|
-
const contents = await initFileContents(repoDir);
|
|
194
|
+
const contents = await initFileContents(repoDir, options.project, layers);
|
|
145
195
|
const plannedCount = files.length;
|
|
146
196
|
const actions = await mapConcurrent(files, 16, async (rel) => {
|
|
147
|
-
const dest =
|
|
197
|
+
const dest = destinations.get(rel);
|
|
148
198
|
if (await exists(dest)) {
|
|
149
199
|
// never overwrite a file init did not write (a user's own copy)
|
|
150
200
|
return { rel, verdict: 'skipped' };
|
|
@@ -152,13 +202,18 @@ export async function initProject(repoDir, options) {
|
|
|
152
202
|
if (options.dryRun)
|
|
153
203
|
return { rel, verdict: 'planned' };
|
|
154
204
|
await mkdir(path.dirname(dest), { recursive: true });
|
|
155
|
-
await
|
|
205
|
+
const checked = await resolveWritableInside(repoDir, rel);
|
|
206
|
+
if (checked === null) {
|
|
207
|
+
throw new InitError(`Refusing to write "${rel}" through a symlink or outside ${repoDir}.`);
|
|
208
|
+
}
|
|
209
|
+
await writeFile(checked, contents.get(rel) ?? '');
|
|
156
210
|
return { rel, verdict: 'written' };
|
|
157
211
|
});
|
|
158
212
|
const written = actions.filter(({ verdict }) => verdict === 'written').map(({ rel }) => rel);
|
|
159
213
|
const skipped = actions.filter(({ verdict }) => verdict === 'skipped').map(({ rel }) => rel);
|
|
160
|
-
if (!options.dryRun)
|
|
161
|
-
await recordInstall(repoDir, written, skipped, contents);
|
|
214
|
+
if (!options.dryRun) {
|
|
215
|
+
await recordInstall(repoDir, written, skipped, contents, layers, options.project);
|
|
216
|
+
}
|
|
162
217
|
return { written, skipped, plannedCount };
|
|
163
218
|
}
|
|
164
219
|
/**
|
|
@@ -172,7 +227,7 @@ async function readRegularFile(abs) {
|
|
|
172
227
|
try {
|
|
173
228
|
if (!(await lstat(abs)).isFile())
|
|
174
229
|
return null;
|
|
175
|
-
return await readFile(abs
|
|
230
|
+
return await readFile(abs);
|
|
176
231
|
}
|
|
177
232
|
catch {
|
|
178
233
|
return null;
|
|
@@ -219,7 +274,7 @@ async function readRegularFile(abs) {
|
|
|
219
274
|
* leaves is a `create` rig whose `CLAUDE.md` was deleted, and this function is
|
|
220
275
|
* what makes that case safe.
|
|
221
276
|
*/
|
|
222
|
-
async function recordInstall(repoDir, written, skipped, contents) {
|
|
277
|
+
async function recordInstall(repoDir, written, skipped, contents, layers, project) {
|
|
223
278
|
const previous = await readManifest(repoDir);
|
|
224
279
|
const name = projectNameFor(repoDir);
|
|
225
280
|
const files = { ...(previous?.files ?? {}) };
|
|
@@ -240,11 +295,17 @@ async function recordInstall(repoDir, written, skipped, contents) {
|
|
|
240
295
|
const manifest = {
|
|
241
296
|
version: await packageVersion(),
|
|
242
297
|
kind: previous?.kind ?? 'init',
|
|
243
|
-
// No manifest:
|
|
244
|
-
//
|
|
298
|
+
// No manifest: prefer the caller's already-validated identity (`create`,
|
|
299
|
+
// RP-177) and only fall back to slugging the directory name when there is
|
|
300
|
+
// none. See the limit above — `upgrade` can do better from the files
|
|
245
301
|
// themselves, and `init` deliberately does not reach for it.
|
|
246
|
-
project: previous?.project ?? { name, scope: name, region: '' },
|
|
302
|
+
project: previous?.project ?? project ?? { name, scope: name, region: '' },
|
|
247
303
|
stacks: previous?.stacks ?? [],
|
|
304
|
+
// `layers` is what THIS run resolved (already unioned with whatever the
|
|
305
|
+
// previous manifest recorded — RP-180's `effectiveLayers`), not
|
|
306
|
+
// re-derived here: a second computation of the same union is exactly the
|
|
307
|
+
// "second copy that goes stale" `invariants.md` warns about.
|
|
308
|
+
layers: [...layers],
|
|
248
309
|
files,
|
|
249
310
|
...(Object.keys(kept).length > 0 ? { kept } : {}),
|
|
250
311
|
};
|