create-agent-rig 0.4.0 → 0.6.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.
Files changed (118) hide show
  1. package/CHANGELOG.md +316 -11
  2. package/README.md +58 -19
  3. package/package.json +2 -1
  4. package/packages/cli/dist/commands/create.js +8 -3
  5. package/packages/cli/dist/commands/init.js +85 -34
  6. package/packages/cli/dist/commands/upgrade.js +112 -30
  7. package/packages/cli/dist/index.js +81 -19
  8. package/packages/cli/dist/lib/copy-tree.js +35 -6
  9. package/packages/cli/dist/lib/init-settings.js +12 -0
  10. package/packages/cli/dist/lib/install-set.js +6 -8
  11. package/packages/cli/dist/lib/manifest.js +31 -9
  12. package/packages/cli/dist/lib/safe-path.js +30 -0
  13. package/scripts/prepare.mjs +1 -1
  14. package/templates/agent-os/init/AGENTS.md +199 -0
  15. package/templates/agent-os/init/CLAUDE.md +69 -9
  16. package/templates/agent-os/stack/aws-cdk/.agents/skills/post-deploy-verify/SKILL.md +105 -0
  17. package/templates/agent-os/stack/aws-cdk/.agents/skills/ro-debug/SKILL.md +117 -0
  18. package/templates/agent-os/stack/aws-cdk/.claude/agents/cdk-diff-reviewer.md +41 -3
  19. package/templates/agent-os/stack/aws-cdk/.claude/rules/aws-cdk.md +1 -1
  20. package/templates/agent-os/stack/aws-cdk/.claude/skills/post-deploy-verify/SKILL.md +41 -0
  21. package/templates/agent-os/stack/aws-cdk/.codex/agents/cdk-diff-reviewer.toml +4 -0
  22. package/templates/agent-os/stack/node-ts/.claude/rules/node-ts.md +29 -0
  23. package/templates/agent-os/universal/.agents/skills/check-premises/SKILL.md +236 -0
  24. package/templates/agent-os/universal/.agents/skills/loop/SKILL.md +958 -0
  25. package/templates/agent-os/universal/.agents/skills/new-invariant/SKILL.md +102 -0
  26. package/templates/agent-os/universal/.agents/skills/new-invariant/guard-invariant.example.mjs +78 -0
  27. package/templates/agent-os/universal/.agents/skills/new-invariant/guard-invariant.example.test.mjs +89 -0
  28. package/templates/agent-os/universal/.agents/skills/pr-ship/SKILL.md +396 -0
  29. package/templates/agent-os/universal/.agents/skills/worktree-task/SKILL.md +73 -0
  30. package/templates/agent-os/universal/.claude/agents/code-reviewer.md +40 -1
  31. package/templates/agent-os/universal/.claude/agents/prose-reviewer.md +71 -1
  32. package/templates/agent-os/universal/.claude/agents/security-scanner.md +40 -0
  33. package/templates/agent-os/universal/.claude/hooks/gate-stop-dod.mjs +301 -26
  34. package/templates/agent-os/universal/.claude/hooks/guard-bash.mjs +43 -5
  35. package/templates/agent-os/universal/.claude/hooks/guard-core-purity.mjs +25 -11
  36. package/templates/agent-os/universal/.claude/hooks/guard-rulebook.mjs +127 -0
  37. package/templates/agent-os/universal/.claude/hooks/guard-secret-file.mjs +180 -0
  38. package/templates/agent-os/universal/.claude/hooks/guard-web-boundary.mjs +32 -13
  39. package/templates/agent-os/universal/.claude/hooks/inject-rules.mjs +175 -7
  40. package/templates/agent-os/universal/.claude/hooks/lib/edit-input.mjs +503 -0
  41. package/templates/agent-os/universal/.claude/rules/autonomy.md +69 -1
  42. package/templates/agent-os/universal/.claude/rules/invariants.md +104 -19
  43. package/templates/agent-os/universal/.claude/rules/workflow.md +55 -5
  44. package/templates/agent-os/universal/.claude/scripts/decision-router.mjs +1260 -0
  45. package/templates/agent-os/universal/.claude/scripts/detect-missed-gate.mjs +65 -2
  46. package/templates/agent-os/universal/.claude/scripts/doctor.mjs +351 -0
  47. package/templates/agent-os/universal/.claude/scripts/git-env.mjs +49 -0
  48. package/templates/agent-os/universal/.claude/scripts/lib/gate-coverage.mjs +306 -0
  49. package/templates/agent-os/universal/.claude/scripts/lib/revalidation-points.mjs +28 -0
  50. package/templates/agent-os/universal/.claude/scripts/lib/secrets.mjs +490 -0
  51. package/templates/agent-os/universal/.claude/scripts/lib/verdict.mjs +462 -0
  52. package/templates/agent-os/universal/.claude/scripts/preflight.mjs +33 -17
  53. package/templates/agent-os/universal/.claude/scripts/queue/as-of.mjs +51 -0
  54. package/templates/agent-os/universal/.claude/scripts/queue/checkout.mjs +149 -0
  55. package/templates/agent-os/universal/.claude/scripts/queue/core.mjs +809 -28
  56. package/templates/agent-os/universal/.claude/scripts/queue/gate-rounds.mjs +160 -0
  57. package/templates/agent-os/universal/.claude/scripts/queue/github-issues.mjs +95 -16
  58. package/templates/agent-os/universal/.claude/scripts/queue/index.mjs +543 -15
  59. package/templates/agent-os/universal/.claude/scripts/queue/jira.mjs +457 -47
  60. package/templates/agent-os/universal/.claude/scripts/queue/plan-md.mjs +289 -25
  61. package/templates/agent-os/universal/.claude/scripts/queue/state.mjs +197 -0
  62. package/templates/agent-os/universal/.claude/scripts/revalidate.mjs +316 -0
  63. package/templates/agent-os/universal/.claude/scripts/revalidation-report.mjs +180 -0
  64. package/templates/agent-os/universal/.claude/scripts/run-journal.mjs +435 -0
  65. package/templates/agent-os/universal/.claude/scripts/run-state.mjs +539 -0
  66. package/templates/agent-os/universal/.claude/scripts/stop-flag.mjs +15 -8
  67. package/templates/agent-os/universal/.claude/scripts/unattended-flag.mjs +239 -0
  68. package/templates/agent-os/universal/.claude/scripts/verdict.mjs +198 -0
  69. package/templates/agent-os/universal/.claude/settings.json +11 -2
  70. package/templates/agent-os/universal/.claude/skills/check-premises/SKILL.md +118 -7
  71. package/templates/agent-os/universal/.claude/skills/loop/SKILL.md +667 -38
  72. package/templates/agent-os/universal/.claude/skills/pr-ship/SKILL.md +359 -26
  73. package/templates/agent-os/universal/.codex/agents/code-reviewer.toml +4 -0
  74. package/templates/agent-os/universal/.codex/agents/prose-reviewer.toml +4 -0
  75. package/templates/agent-os/universal/.codex/agents/security-scanner.toml +4 -0
  76. package/templates/agent-os/universal/.codex/agents/test-writer.toml +4 -0
  77. package/templates/agent-os/universal/.codex/hooks.json +70 -0
  78. package/templates/agent-os/universal/AGENTS.md +166 -0
  79. package/templates/agent-os/universal/CLAUDE.md +49 -14
  80. package/templates/agent-os/universal/PLAN.md +7 -40
  81. package/templates/agent-os/universal/docs/decisions/closing-a-task.md +98 -0
  82. package/templates/agent-os/universal/docs/decisions/codex-adapter.md +108 -0
  83. package/templates/agent-os/universal/docs/decisions/fail-open-guards.md +43 -0
  84. package/templates/agent-os/universal/docs/decisions/gate-coverage.md +83 -0
  85. package/templates/agent-os/universal/docs/decisions/review-lanes.md +72 -0
  86. package/templates/agent-os/universal/docs/decisions/run-directory.md +44 -0
  87. package/templates/agent-os/universal/docs/decisions/spacing-rations-mechanisms.md +125 -0
  88. package/templates/agent-os/universal/docs/decisions/stop-conditions-in-a-file.md +46 -0
  89. package/templates/agent-os/universal/docs/decisions/two-empty-endings.md +74 -0
  90. package/templates/agent-os/universal/journal/README.md +101 -0
  91. package/templates/agent-os/universal/layers.json +45 -2
  92. package/templates/hash-history.json +310 -49
  93. package/templates/release-ledger.json +9 -0
  94. package/templates/skeleton/aws-serverless/.github/workflows/deploy.yml +34 -1
  95. package/templates/skeleton/aws-serverless/README.md +91 -9
  96. package/templates/skeleton/aws-serverless/apps/web/src/lib/api.ts +9 -2
  97. package/templates/skeleton/aws-serverless/gitignore +37 -0
  98. package/templates/skeleton/aws-serverless/infra/bin/app.ts +73 -13
  99. package/templates/skeleton/aws-serverless/infra/lib/app-stack.ts +136 -4
  100. package/templates/skeleton/aws-serverless/infra/lib/web-stack.ts +14 -1
  101. package/templates/skeleton/aws-serverless/infra/test/allowed-origins.test.ts +301 -0
  102. package/templates/skeleton/aws-serverless/infra/test/app-composition.test.ts +137 -0
  103. package/templates/skeleton/aws-serverless/infra/test/app-stack.test.ts +36 -20
  104. package/templates/skeleton/aws-serverless/infra/test/web-stack.test.ts +15 -12
  105. package/templates/skeleton/aws-serverless/services/api/src/handlers/create-note.ts +33 -6
  106. package/templates/skeleton/aws-serverless/services/api/src/handlers/list-notes.ts +18 -5
  107. package/templates/skeleton/aws-serverless/services/api/src/usecases/create-note.ts +11 -0
  108. package/templates/skeleton/aws-serverless/services/api/test/create-note.handler.test.ts +120 -1
  109. package/templates/skeleton/aws-serverless/services/api/test/list-notes.test.ts +72 -1
  110. package/templates/skeleton/node-service/README.md +11 -1
  111. package/templates/skeleton/node-service/gitignore +34 -0
  112. package/templates/skeleton/node-service/packages/db/src/note-store.ts +47 -10
  113. package/templates/skeleton/node-service/packages/db/test/note-store.test.ts +20 -0
  114. package/templates/skeleton/node-service/services/api/src/main.ts +2 -9
  115. package/templates/skeleton/node-service/services/api/src/server.ts +93 -10
  116. package/templates/skeleton/node-service/services/api/src/static-dir.ts +20 -0
  117. package/templates/skeleton/node-service/services/api/test/server.test.ts +98 -13
  118. package/templates/skeleton/node-service/services/api/test/static-dir.test.ts +28 -0
@@ -0,0 +1,149 @@
1
+ /**
2
+ * Which checkout are we in?
3
+ *
4
+ * Its own module on purpose, and the reason is a defect this seam already had:
5
+ * the writer resolved its file from `process.cwd()` while the reader resolved
6
+ * from the script's own location, so a close run inside `.claude/worktrees/<slug>/`
7
+ * wrote a tier the next selection could not see — and `worktree-task` then
8
+ * deleted the directory it had written to. Two answers to "which checkout" is
9
+ * one answer too many, so both sides import this.
10
+ *
11
+ * It sits apart from `state.mjs` because the CLI needs only this much. Pulling
12
+ * the whole tier computation (and `detect-missed-gate.mjs` behind it) into the
13
+ * read path would make selection depend on a module it never calls.
14
+ */
15
+
16
+ import { execFileSync } from 'node:child_process';
17
+ import { dirname, resolve } from 'node:path';
18
+
19
+ // The sanitiser is IMPORTED, never re-derived. This repo had already ruled on
20
+ // which git variables to strip, exported the answer with its stated limit, and
21
+ // built a sweep for call sites that forget it — and this file still shipped a
22
+ // third copy, wider and wrong, which is the "two files enforcing one invariant"
23
+ // `invariants.md` names by rule. It comes from the small shared module rather
24
+ // than from `preflight.mjs`, because a CLI script has no business on the queue's
25
+ // read path: importing one there broke every fixture that copies only `queue/`.
26
+ import { withoutGitLocation } from '../git-env.mjs';
27
+
28
+ /**
29
+ * The root of the MAIN checkout, from anywhere — main, a linked worktree, or a
30
+ * subdirectory of either.
31
+ *
32
+ * `--git-common-dir` is what makes this a lookup rather than a guess: inside a
33
+ * linked worktree it points at the main repository's `.git`, not the worktree's
34
+ * own gitdir.
35
+ *
36
+ * 🔴 **The probe runs under `LC_ALL: 'C'`, because the catch CLASSIFIES git's
37
+ * stderr and git translates it.** Under `fr_FR` the "no repository here" message
38
+ * is *"ni ceci ni aucun de ses répertoires parents n'est un dépôt git"*; the
39
+ * regex misses, and the legitimate fallback turns into a hard refusal from the
40
+ * queue CLI — in a non-git directory, for anyone whose shell is not English. CI
41
+ * runs under `C`, so CI can never see it. Note this SETS a variable rather than
42
+ * stripping one: `GIT_CONFIG_*` is untouched.
43
+ *
44
+ * **Two failures fall back to `startDir`, and only those two:** there is no
45
+ * repository above it, or git is not installed. A queue works fine in a plain
46
+ * directory, and refusing there would break every non-git use to protect
47
+ * nothing. **Every other failure is raised.** A bare catch here would turn
48
+ * *dubious ownership*, a git too old for `--path-format`, or a broken binary
49
+ * into the permissive answer — silently, with git's own explanation discarded.
50
+ * That is the shape this whole module exists to remove, and swallowing it one
51
+ * level up would just move it.
52
+ *
53
+ * 🔴 **The child's environment is sanitised through the SHARED list.** A git
54
+ * hook exports `GIT_DIR` and `GIT_INDEX_FILE`; inherited here, they make this
55
+ * function answer confidently about a checkout the caller is not in. A hook in
56
+ * a linked worktree exports them **absolute**, so changing `cwd` does not save
57
+ * you — see `git-env.mjs` for the measurements. This repository has the scar:
58
+ * NOTES.md's `GIT_DIR` incident, 19 junk commits across two branches.
59
+ *
60
+ * ⚠ **Only *location* is stripped, deliberately.** A `GIT_*` prefix sweep would
61
+ * also take `GIT_CONFIG_GLOBAL`/`GIT_CONFIG_COUNT`, which is how containers and
62
+ * CI inject `safe.directory` for a checkout owned by another uid — remove those
63
+ * and git exits 128 on *dubious ownership*, which under the old bare catch came
64
+ * back as the pre-fix behaviour with nothing printed.
65
+ */
66
+ export const mainCheckoutRoot = (startDir) => {
67
+ try {
68
+ const gitDir = execFileSync(
69
+ 'git',
70
+ ['rev-parse', '--path-format=absolute', '--git-common-dir'],
71
+ {
72
+ cwd: startDir,
73
+ encoding: 'utf8',
74
+ stdio: ['ignore', 'pipe', 'pipe'],
75
+ // `LC_ALL: 'C'` — see the note on classifying stderr, above.
76
+ env: { ...withoutGitLocation(), LC_ALL: 'C', LANGUAGE: '' },
77
+ },
78
+ ).trim();
79
+ // `resolve`, because git answers with forward slashes on Windows
80
+ // (`C:/Users/...`) and every caller compares against a native path.
81
+ return gitDir ? resolve(dirname(gitDir)) : startDir;
82
+ } catch (error) {
83
+ if (error?.code === 'ENOENT') return startDir; // git is not installed
84
+ const stderr = String(error?.stderr ?? '');
85
+ if (/not a git repository|not a work tree/i.test(stderr)) return startDir;
86
+ throw new Error(
87
+ `could not determine the main checkout for ${startDir}: ${stderr.trim() || error?.message}`,
88
+ { cause: error },
89
+ );
90
+ }
91
+ };
92
+
93
+ /**
94
+ * Is this checkout in a state a gate round may be counted against (AR-141)?
95
+ *
96
+ * A round is counted per branch and the fan-out's verdicts name a head. On one
97
+ * branch two rounds were counted before a commit that pre-commit then refused,
98
+ * so the counter and the records named a head that never shipped. The three
99
+ * states that make a head unshippable are decidable from git alone: a dirty
100
+ * working tree (tracked or untracked), a branch with no upstream, and commits
101
+ * the upstream has not seen. `{ ok: true }` otherwise; a git that cannot answer
102
+ * is reported as such, never as clean.
103
+ *
104
+ * Bounded: two git calls, each with a timeout, and the porcelain output is
105
+ * read only for emptiness. The upstream question has one catch for three
106
+ * states — a detached HEAD, a branch with no upstream, an upstream that is
107
+ * gone — and names none of them apart; the refusal is right for all three.
108
+ */
109
+ export const checkoutIsShippable = (root) => {
110
+ const git = (args) =>
111
+ execFileSync('git', args, {
112
+ cwd: root,
113
+ encoding: 'utf8',
114
+ stdio: ['ignore', 'pipe', 'ignore'],
115
+ env: withoutGitLocation(),
116
+ timeout: 30_000,
117
+ }).trim();
118
+ let status;
119
+ try {
120
+ status = git(['status', '--porcelain']);
121
+ } catch (error) {
122
+ return { ok: false, why: `git could not read the working tree at ${root}: ${error.message}` };
123
+ }
124
+ if (status !== '') {
125
+ return {
126
+ ok: false,
127
+ why: 'the working tree is dirty — a round counted now would name a head that has not ' +
128
+ 'been committed; commit (and push) first',
129
+ };
130
+ }
131
+ let ahead;
132
+ try {
133
+ ahead = git(['rev-list', '--count', '@{upstream}..HEAD']);
134
+ } catch {
135
+ return {
136
+ ok: false,
137
+ why: 'HEAD has no upstream — push the branch first, so the round names a head the ' +
138
+ 'reviewers and CI can see',
139
+ };
140
+ }
141
+ if (ahead !== '0') {
142
+ return {
143
+ ok: false,
144
+ why: `HEAD is ${ahead} commit(s) ahead of its upstream — push first, so the round names ` +
145
+ 'the head that ships',
146
+ };
147
+ }
148
+ return { ok: true };
149
+ };