create-agent-rig 0.9.1 → 0.10.1
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 +462 -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 +508 -101
- package/packages/cli/dist/index.js +658 -47
- 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 +45 -12
- 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/gate-stop-dod.mjs +4 -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 +59 -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 +45 -12
- 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 +112 -40
- package/templates/release-ledger.json +3 -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
package/package.json
CHANGED
|
@@ -1,19 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-agent-rig",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.10.1",
|
|
4
|
+
"description": "Configure an agent operating system (rules, gates, hooks) for Claude Code and Codex in a new or existing repository — no application scaffolding",
|
|
5
5
|
"keywords": [
|
|
6
|
-
"create",
|
|
7
|
-
"scaffold",
|
|
8
|
-
"generator",
|
|
9
|
-
"starter",
|
|
10
|
-
"template",
|
|
11
6
|
"agent",
|
|
12
7
|
"claude-code",
|
|
13
8
|
"codex",
|
|
14
9
|
"agent-os",
|
|
15
|
-
"
|
|
16
|
-
"
|
|
10
|
+
"rules",
|
|
11
|
+
"hooks",
|
|
12
|
+
"governance"
|
|
17
13
|
],
|
|
18
14
|
"license": "MIT",
|
|
19
15
|
"repository": {
|
|
@@ -38,16 +34,14 @@
|
|
|
38
34
|
"packageManager": "pnpm@11.16.0",
|
|
39
35
|
"scripts": {
|
|
40
36
|
"prepare": "node scripts/prepare.mjs",
|
|
41
|
-
"build": "
|
|
37
|
+
"build": "node scripts/prepare.mjs --build-only",
|
|
42
38
|
"lint": "eslint . && prettier --check .",
|
|
43
39
|
"format": "prettier --write .",
|
|
44
40
|
"typecheck": "tsc -p packages/cli/tsconfig.json && tsc -p tsconfig.json",
|
|
45
41
|
"test": "pnpm build && vitest run",
|
|
46
|
-
"test:unit": "vitest run --project unit --project template
|
|
42
|
+
"test:unit": "vitest run --project unit --project template",
|
|
47
43
|
"test:smoke": "vitest run --project unit",
|
|
48
|
-
"test:e2e": "pnpm build && vitest run --project e2e"
|
|
49
|
-
"template:install": "pnpm --dir templates/skeleton/aws-serverless install",
|
|
50
|
-
"template:check": "pnpm --dir templates/skeleton/aws-serverless run check"
|
|
44
|
+
"test:e2e": "pnpm build && vitest run --project e2e"
|
|
51
45
|
},
|
|
52
46
|
"devDependencies": {
|
|
53
47
|
"@eslint/js": "^10.0.1",
|
|
@@ -1,121 +1,89 @@
|
|
|
1
1
|
import { execFile } from 'node:child_process';
|
|
2
|
-
import { mkdir,
|
|
2
|
+
import { mkdir, readdir, stat } from 'node:fs/promises';
|
|
3
3
|
import path from 'node:path';
|
|
4
4
|
import { promisify } from 'node:util';
|
|
5
|
-
import { copyTree, listTree, mapConcurrent } from '../lib/copy-tree.js';
|
|
6
|
-
import { ALLOWED_OVERWRITES, detectCollisions } from '../lib/composition.js';
|
|
7
|
-
import { agentOsLayerDirs } from '../lib/install-set.js';
|
|
8
|
-
import { sha256, writeManifest } from '../lib/manifest.js';
|
|
9
|
-
import { substituteContent, substituteFileName } from '../lib/substitute.js';
|
|
10
5
|
import { gitEnv } from '../lib/git-env.js';
|
|
11
|
-
import {
|
|
12
|
-
import { skeletonDir } from '../templates.js';
|
|
13
|
-
import { packageVersion } from '../lib/version.js';
|
|
6
|
+
import { initProject } from './init.js';
|
|
14
7
|
/** A user-facing failure: message is printed as-is, no stack trace. */
|
|
15
8
|
export class CreateError extends Error {
|
|
16
9
|
}
|
|
17
|
-
/**
|
|
18
|
-
|
|
10
|
+
/**
|
|
11
|
+
* A safe, predictable project name — also what ends up in a filename (the
|
|
12
|
+
* kill switch, `~/.claude/<name>-loop-STOP`) and inside a single-quoted string
|
|
13
|
+
* literal in a generated script (`stop-flag.mjs`), so it is validated
|
|
14
|
+
* up front rather than silently slugged. There is no npm scope to validate
|
|
15
|
+
* for any more (RP-177 retired the application skeleton this pattern used to
|
|
16
|
+
* double as): the shape survives only because it is still the right shape for
|
|
17
|
+
* a directory/kill-switch name, not because anything downstream reads it as a
|
|
18
|
+
* package identifier.
|
|
19
|
+
*
|
|
20
|
+
* No trailing `-` or `.`: `projectNameFor` (the name `init` would derive from
|
|
21
|
+
* this same directory with no identity supplied) strips both, and a name this
|
|
22
|
+
* pattern accepted but that function would rewrite is exactly the mismatch
|
|
23
|
+
* that once made a freshly created rig fail to match its own installed files
|
|
24
|
+
* on the very next `upgrade`.
|
|
25
|
+
*/
|
|
26
|
+
const NAME_PATTERN = /^[a-z0-9](?:[a-z0-9._-]*[a-z0-9])?$/;
|
|
27
|
+
/**
|
|
28
|
+
* `create <dir>` — a thin convenience wrapper (RP-177): make the directory,
|
|
29
|
+
* initialize Git, run the same install `init` runs inside it, then commit the
|
|
30
|
+
* pristine baseline. There is only one payload flavour; this command's entire
|
|
31
|
+
* value is not having to `mkdir`, `git init`, `cd` and run `init` by hand.
|
|
32
|
+
*/
|
|
19
33
|
export async function createProject(dirArg, options) {
|
|
20
34
|
const projectDir = path.resolve(options.cwd, dirArg);
|
|
21
35
|
const projectName = path.basename(projectDir);
|
|
22
36
|
if (!NAME_PATTERN.test(projectName)) {
|
|
23
|
-
throw new CreateError(`Invalid project name "${projectName}": use lowercase letters, digits, ".", "_" and "-" ` +
|
|
24
|
-
'
|
|
37
|
+
throw new CreateError(`Invalid project name "${projectName}": use lowercase letters, digits, ".", "_" and "-", ` +
|
|
38
|
+
'starting and ending with a letter or digit.');
|
|
25
39
|
}
|
|
26
40
|
await ensureEmptyOrAbsent(projectDir);
|
|
27
|
-
const targetName = options.target ?? DEFAULT_TARGET;
|
|
28
|
-
const target = TARGETS[targetName];
|
|
29
|
-
if (!target) {
|
|
30
|
-
throw new CreateError(`Unknown target "${targetName}". Known targets: ${TARGET_NAMES.join(', ')}.`);
|
|
31
|
-
}
|
|
32
|
-
const ctx = {
|
|
33
|
-
projectName,
|
|
34
|
-
projectScope: projectName,
|
|
35
|
-
region: target.defaultRegion ?? '',
|
|
36
|
-
};
|
|
37
|
-
const transforms = {
|
|
38
|
-
transformContent: (content) => substituteContent(content, ctx),
|
|
39
|
-
transformName: (name) => substituteFileName(name, ctx),
|
|
40
|
-
};
|
|
41
|
-
// Layer 2 (the skeleton) + layer 1 (agent-os: universal + stack overlays).
|
|
42
|
-
const agentOsLayers = agentOsLayerDirs(target.stacks);
|
|
43
|
-
const layers = [
|
|
44
|
-
{ name: `skeleton/${target.skeletonDir}`, dir: skeletonDir(target.skeletonDir) },
|
|
45
|
-
...agentOsLayers,
|
|
46
|
-
];
|
|
47
|
-
// Composition safety: layers must claim disjoint paths. Checked before any
|
|
48
|
-
// copy — a collision is a template bug and must never be resolved by order.
|
|
49
|
-
const claimed = [];
|
|
50
|
-
for (const layer of layers) {
|
|
51
|
-
claimed.push({ name: layer.name, files: await listTree(layer.dir, transforms) });
|
|
52
|
-
}
|
|
53
|
-
const collisions = detectCollisions(claimed, ALLOWED_OVERWRITES);
|
|
54
|
-
if (collisions.length > 0) {
|
|
55
|
-
const detail = collisions
|
|
56
|
-
.map((c) => ` ${c.path} — claimed by ${c.layers.join(' and ')}`)
|
|
57
|
-
.join('\n');
|
|
58
|
-
throw new CreateError(`Template layers collide (fix the templates, not the order):\n${detail}`);
|
|
59
|
-
}
|
|
60
41
|
await mkdir(projectDir, { recursive: true });
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
42
|
+
const gitReady = options.git !== false && (await initGitRepository(projectDir));
|
|
43
|
+
await initProject(projectDir, {
|
|
44
|
+
project: { name: projectName, scope: projectName, region: '' },
|
|
45
|
+
withWorkflow: options.withWorkflow,
|
|
46
|
+
});
|
|
47
|
+
if (gitReady) {
|
|
48
|
+
await commitGitBaseline(projectDir);
|
|
67
49
|
}
|
|
68
50
|
return { projectDir, projectName };
|
|
69
51
|
}
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
for (const layer of agentOsLayers) {
|
|
85
|
-
const paths = await listTree(layer.dir, transforms);
|
|
86
|
-
const hashes = await mapConcurrent(paths, 16, async (rel) => ({
|
|
87
|
-
rel,
|
|
88
|
-
hash: sha256(await readFile(path.join(projectDir, ...rel.split('/')), 'utf8')),
|
|
89
|
-
}));
|
|
90
|
-
for (const { rel, hash } of hashes) {
|
|
91
|
-
files[rel] = hash;
|
|
92
|
-
}
|
|
52
|
+
const run = promisify(execFile);
|
|
53
|
+
const gitInvocation = (projectDir) => ({
|
|
54
|
+
quiet: ['-c', 'gc.auto=0', '-c', 'maintenance.auto=false'],
|
|
55
|
+
where: { cwd: projectDir, env: gitEnv() },
|
|
56
|
+
});
|
|
57
|
+
async function initGitRepository(projectDir) {
|
|
58
|
+
const { quiet, where } = gitInvocation(projectDir);
|
|
59
|
+
try {
|
|
60
|
+
await run('git', [...quiet, 'init', '--quiet'], where);
|
|
61
|
+
return true;
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
// git missing or unusable — generation never fails on this.
|
|
65
|
+
return false;
|
|
93
66
|
}
|
|
94
|
-
await writeManifest(projectDir, {
|
|
95
|
-
version: await packageVersion(),
|
|
96
|
-
kind: 'create',
|
|
97
|
-
project: { name: ctx.projectName, scope: ctx.projectScope, region: ctx.region },
|
|
98
|
-
stacks: [...(TARGETS[target]?.stacks ?? [])],
|
|
99
|
-
files,
|
|
100
|
-
});
|
|
101
67
|
}
|
|
102
|
-
|
|
103
|
-
async function initGitBaseline(projectDir) {
|
|
68
|
+
async function commitGitBaseline(projectDir) {
|
|
104
69
|
// Disable git's background maintenance for these one-shot commands: a commit
|
|
105
70
|
// can otherwise fork an auto-gc / maintenance process that keeps writing to
|
|
106
71
|
// .git/objects/pack after we return — a non-deterministic tail that races any
|
|
107
72
|
// caller cleaning up the directory, and pointless work on a one-commit repo.
|
|
108
|
-
const quiet
|
|
109
|
-
|
|
73
|
+
const { quiet, where } = gitInvocation(projectDir);
|
|
74
|
+
// Pin both repository locations even though cwd is already the child. If a
|
|
75
|
+
// later refactor calls this without a successful `git init`, Git must fail
|
|
76
|
+
// here rather than discover and mutate a parent repository.
|
|
77
|
+
const repository = [`--git-dir=${path.join(projectDir, '.git')}`, `--work-tree=${projectDir}`];
|
|
110
78
|
try {
|
|
111
|
-
await run('git', [...quiet, '
|
|
112
|
-
await run('git', [...quiet, 'add', '-A'], where);
|
|
79
|
+
await run('git', [...quiet, ...repository, 'add', '-A'], where);
|
|
113
80
|
// Explicit identity: the baseline must commit even where git has no
|
|
114
81
|
// global user configured (fresh machines, CI). --no-verify here shields
|
|
115
82
|
// the baseline from the USER'S global hooks only — the generated
|
|
116
83
|
// project's own gates do not exist yet, so nothing is being bypassed.
|
|
117
84
|
await run('git', [
|
|
118
85
|
...quiet,
|
|
86
|
+
...repository,
|
|
119
87
|
'-c',
|
|
120
88
|
'user.name=create-agent-rig',
|
|
121
89
|
'-c',
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
import { parseArgs } from 'node:util';
|
|
2
|
+
import { MANIFEST_REL, parseManifest, sha256 } from '../lib/manifest.js';
|
|
3
|
+
import { readBounded, verifyIntegrations } from '../integrations/verify.js';
|
|
4
|
+
import { DECLARATION_REL, MAX_DECLARATION_BYTES, parseDeclaration, } from '../integrations/declaration.js';
|
|
5
|
+
import { REGISTRY } from '../integrations/registry.js';
|
|
6
|
+
import { inspectSpecKit, SPEC_KIT_VERSION, } from '../integrations/spec-kit.js';
|
|
7
|
+
import { inspectMemory } from '../integrations/memory-doctor.js';
|
|
8
|
+
import { inspectGuards } from '../integrations/doctor-guards.js';
|
|
9
|
+
import { inspectWorkflow } from '../integrations/doctor-workflow.js';
|
|
10
|
+
function text(bytes) {
|
|
11
|
+
try {
|
|
12
|
+
return new TextDecoder('utf-8', { fatal: true, ignoreBOM: true }).decode(bytes);
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
return undefined;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
async function rigChecks(root, codexHash) {
|
|
19
|
+
const source = await readBounded(root, MANIFEST_REL, 1024 * 1024);
|
|
20
|
+
if (source.status === 'absent')
|
|
21
|
+
return [{ id: 'rig-manifest', status: 'warn', reason: 'not-installed' }];
|
|
22
|
+
const decoded = source.status === 'ok' ? text(source.bytes) : undefined;
|
|
23
|
+
const manifest = decoded === undefined ? null : parseManifest(decoded);
|
|
24
|
+
if (manifest === null || Object.keys(manifest.files).length > 4096)
|
|
25
|
+
return [{ id: 'rig-manifest', status: 'fail', reason: 'unreadable-manifest' }];
|
|
26
|
+
const checks = [{ id: 'rig-manifest', status: 'pass', reason: 'valid' }];
|
|
27
|
+
let contentDrift = false;
|
|
28
|
+
let lineDrift = false;
|
|
29
|
+
let absent = false;
|
|
30
|
+
let unreadable = false;
|
|
31
|
+
for (const [rel, recorded] of Object.entries(manifest.files)) {
|
|
32
|
+
const expected = rel === '.codex/config.toml' ? (codexHash ?? recorded) : recorded;
|
|
33
|
+
const file = await readBounded(root, rel, 1024 * 1024);
|
|
34
|
+
if (file.status === 'absent') {
|
|
35
|
+
absent = true;
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
if (file.status !== 'ok') {
|
|
39
|
+
unreadable = true;
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
if (sha256(file.bytes) === expected)
|
|
43
|
+
continue;
|
|
44
|
+
const decodedFile = text(file.bytes);
|
|
45
|
+
if (decodedFile !== undefined &&
|
|
46
|
+
(sha256(decodedFile.replace(/\r\n/g, '\n')) === expected ||
|
|
47
|
+
sha256(decodedFile.replace(/\r\n/g, '\n').replace(/\n/g, '\r\n')) === expected))
|
|
48
|
+
lineDrift = true;
|
|
49
|
+
else
|
|
50
|
+
contentDrift = true;
|
|
51
|
+
}
|
|
52
|
+
checks.push({
|
|
53
|
+
id: 'rig-owned-files',
|
|
54
|
+
status: unreadable ? 'fail' : absent || contentDrift || lineDrift ? 'warn' : 'pass',
|
|
55
|
+
reason: unreadable
|
|
56
|
+
? 'unreadable-owned-file'
|
|
57
|
+
: absent
|
|
58
|
+
? 'absent-owned-file'
|
|
59
|
+
: contentDrift
|
|
60
|
+
? 'content-drift'
|
|
61
|
+
: lineDrift
|
|
62
|
+
? 'line-ending-drift'
|
|
63
|
+
: 'pristine',
|
|
64
|
+
});
|
|
65
|
+
return checks;
|
|
66
|
+
}
|
|
67
|
+
/** Read-only diagnosis. Runtime observations are returned, never persisted. */
|
|
68
|
+
export async function runDoctor(options) {
|
|
69
|
+
let json;
|
|
70
|
+
try {
|
|
71
|
+
const parsed = parseArgs({
|
|
72
|
+
args: options.args,
|
|
73
|
+
allowPositionals: false,
|
|
74
|
+
options: { json: { type: 'boolean' } },
|
|
75
|
+
});
|
|
76
|
+
json = parsed.values.json === true;
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
return { exitCode: 2, stdout: '', stderr: 'doctor accepts only --json\n' };
|
|
80
|
+
}
|
|
81
|
+
const source = await readBounded(options.cwd, DECLARATION_REL, MAX_DECLARATION_BYTES);
|
|
82
|
+
const declaration = source.status === 'ok' ? parseDeclaration(text(source.bytes) ?? '', REGISTRY) : undefined;
|
|
83
|
+
const intent = declaration?.status === 'ok' && declaration.rejected.length === 0 ? declaration : undefined;
|
|
84
|
+
const checks = await rigChecks(options.cwd, intent?.targets?.codex?.fileHash);
|
|
85
|
+
if (checks.some((check) => check.id === 'rig-manifest' && check.status === 'pass')) {
|
|
86
|
+
const [guards, workflow] = await Promise.all([
|
|
87
|
+
inspectGuards({ repoDir: options.cwd }),
|
|
88
|
+
inspectWorkflow({ repoDir: options.cwd }),
|
|
89
|
+
]);
|
|
90
|
+
checks.push({ id: 'guards', ...guards }, { id: 'workflow', ...workflow });
|
|
91
|
+
}
|
|
92
|
+
const memory = await inspectMemory({ repoDir: options.cwd, env: options.env ?? process.env });
|
|
93
|
+
checks.push({ id: 'custom-memory', status: memory.status, reason: memory.reason });
|
|
94
|
+
let specKit;
|
|
95
|
+
const wiring = await verifyIntegrations({ repoDir: options.cwd, env: options.env });
|
|
96
|
+
const invalid = wiring.issues.some((issue) => issue.status !== 'missing');
|
|
97
|
+
const pendingHarness = wiring.integrations.some((entry) => Object.keys(entry.harnesses).length === 0);
|
|
98
|
+
checks.push({
|
|
99
|
+
id: 'integrations',
|
|
100
|
+
status: invalid ? 'fail' : pendingHarness ? 'warn' : 'pass',
|
|
101
|
+
reason: invalid
|
|
102
|
+
? 'invalid-declaration'
|
|
103
|
+
: pendingHarness
|
|
104
|
+
? 'harness-selection-pending'
|
|
105
|
+
: wiring.integrations.length
|
|
106
|
+
? 'declared'
|
|
107
|
+
: 'not-selected',
|
|
108
|
+
});
|
|
109
|
+
for (const entry of wiring.integrations) {
|
|
110
|
+
if (Object.keys(entry.harnesses).length === 0) {
|
|
111
|
+
checks.push({
|
|
112
|
+
id: `${entry.id}:harness-selection`,
|
|
113
|
+
status: 'warn',
|
|
114
|
+
reason: 'harness-selection-pending',
|
|
115
|
+
});
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
if (entry.id === 'spec-kit') {
|
|
119
|
+
const selected = intent?.entries.find((candidate) => candidate.id === 'spec-kit');
|
|
120
|
+
if (selected?.version !== SPEC_KIT_VERSION) {
|
|
121
|
+
checks.push({ id: 'spec-kit', status: 'fail', reason: 'unsupported-requested-version' });
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
const inspection = await inspectSpecKit({
|
|
125
|
+
repoDir: options.cwd,
|
|
126
|
+
harnesses: selected.harnesses ?? [],
|
|
127
|
+
env: options.env,
|
|
128
|
+
});
|
|
129
|
+
specKit = inspection;
|
|
130
|
+
checks.push({ id: 'spec-kit', status: inspection.status, reason: inspection.reason });
|
|
131
|
+
}
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
134
|
+
for (const [harness, state] of Object.entries(entry.harnesses)) {
|
|
135
|
+
checks.push({
|
|
136
|
+
id: `${entry.id}:${harness}`,
|
|
137
|
+
status: state.wiring === 'unreadable'
|
|
138
|
+
? 'fail'
|
|
139
|
+
: state.wiring === 'healthy'
|
|
140
|
+
? state.launcher === 'missing'
|
|
141
|
+
? 'warn'
|
|
142
|
+
: 'pass'
|
|
143
|
+
: 'warn',
|
|
144
|
+
reason: state.wiring === 'healthy'
|
|
145
|
+
? state.launcher === 'missing'
|
|
146
|
+
? 'launcher-missing'
|
|
147
|
+
: 'wired'
|
|
148
|
+
: state.wiring,
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
const status = checks.some((check) => check.status === 'fail')
|
|
153
|
+
? 'fail'
|
|
154
|
+
: checks.some((check) => check.status === 'warn')
|
|
155
|
+
? 'warn'
|
|
156
|
+
: 'pass';
|
|
157
|
+
const wiringNames = {
|
|
158
|
+
healthy: 'wired',
|
|
159
|
+
missing: 'absent',
|
|
160
|
+
drift: 'drifted',
|
|
161
|
+
unowned: 'foreign',
|
|
162
|
+
unreadable: 'unreadable',
|
|
163
|
+
};
|
|
164
|
+
const integrations = wiring.integrations
|
|
165
|
+
.filter((entry) => entry.id !== 'spec-kit')
|
|
166
|
+
.map((entry) => ({
|
|
167
|
+
id: entry.id,
|
|
168
|
+
harnesses: Object.fromEntries(Object.entries(entry.harnesses).map(([harness, state]) => [
|
|
169
|
+
harness,
|
|
170
|
+
{ ...state, wiring: wiringNames[state.wiring] },
|
|
171
|
+
])),
|
|
172
|
+
}));
|
|
173
|
+
const report = {
|
|
174
|
+
schemaVersion: 1,
|
|
175
|
+
status: status === 'pass' ? 'ok' : status,
|
|
176
|
+
checks: checks.map((check) => ({
|
|
177
|
+
...check,
|
|
178
|
+
status: check.status === 'pass' ? 'ok' : check.status,
|
|
179
|
+
detail: check.reason === 'workflow-verified'
|
|
180
|
+
? 'Workflow and frozen revalidation scripts match this package; the RP-26 decision is not observed.'
|
|
181
|
+
: check.reason.replaceAll('-', ' '),
|
|
182
|
+
fix: check.status === 'pass'
|
|
183
|
+
? ''
|
|
184
|
+
: check.id.startsWith('rig-') || check.id === 'guards' || check.id === 'workflow'
|
|
185
|
+
? 'Review the installation with create-agent-rig upgrade before accepting changes.'
|
|
186
|
+
: check.id === 'custom-memory'
|
|
187
|
+
? 'Check the machine-scoped Memory installation and its compatible version.'
|
|
188
|
+
: check.id === 'spec-kit'
|
|
189
|
+
? 'Check the pinned Spec Kit launcher and authoritative integration status.'
|
|
190
|
+
: 'Review create-agent-rig setup list and the intended provider wiring.',
|
|
191
|
+
})),
|
|
192
|
+
integrations,
|
|
193
|
+
memory: { ...memory, status: memory.status === 'pass' ? 'ok' : memory.status },
|
|
194
|
+
...(specKit
|
|
195
|
+
? {
|
|
196
|
+
specKit: {
|
|
197
|
+
version: SPEC_KIT_VERSION,
|
|
198
|
+
...specKit,
|
|
199
|
+
status: specKit.status === 'pass' ? 'ok' : specKit.status,
|
|
200
|
+
connectivity: 'not-observed',
|
|
201
|
+
trust: 'not-observed',
|
|
202
|
+
},
|
|
203
|
+
}
|
|
204
|
+
: {}),
|
|
205
|
+
};
|
|
206
|
+
return {
|
|
207
|
+
exitCode: status === 'fail' ? 1 : 0,
|
|
208
|
+
stdout: json
|
|
209
|
+
? `${JSON.stringify(report)}\n`
|
|
210
|
+
: `${report.checks.map((check) => `${check.status}: ${check.id}: ${check.detail}${check.fix ? ` — ${check.fix}` : ''}`).join('\n')}\n`,
|
|
211
|
+
stderr: '',
|
|
212
|
+
};
|
|
213
|
+
}
|