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.
- package/CHANGELOG.md +316 -11
- package/README.md +58 -19
- package/package.json +2 -1
- package/packages/cli/dist/commands/create.js +8 -3
- package/packages/cli/dist/commands/init.js +85 -34
- package/packages/cli/dist/commands/upgrade.js +112 -30
- package/packages/cli/dist/index.js +81 -19
- package/packages/cli/dist/lib/copy-tree.js +35 -6
- package/packages/cli/dist/lib/init-settings.js +12 -0
- package/packages/cli/dist/lib/install-set.js +6 -8
- package/packages/cli/dist/lib/manifest.js +31 -9
- package/packages/cli/dist/lib/safe-path.js +30 -0
- package/scripts/prepare.mjs +1 -1
- package/templates/agent-os/init/AGENTS.md +199 -0
- package/templates/agent-os/init/CLAUDE.md +69 -9
- package/templates/agent-os/stack/aws-cdk/.agents/skills/post-deploy-verify/SKILL.md +105 -0
- package/templates/agent-os/stack/aws-cdk/.agents/skills/ro-debug/SKILL.md +117 -0
- package/templates/agent-os/stack/aws-cdk/.claude/agents/cdk-diff-reviewer.md +41 -3
- package/templates/agent-os/stack/aws-cdk/.claude/rules/aws-cdk.md +1 -1
- package/templates/agent-os/stack/aws-cdk/.claude/skills/post-deploy-verify/SKILL.md +41 -0
- package/templates/agent-os/stack/aws-cdk/.codex/agents/cdk-diff-reviewer.toml +4 -0
- package/templates/agent-os/stack/node-ts/.claude/rules/node-ts.md +29 -0
- package/templates/agent-os/universal/.agents/skills/check-premises/SKILL.md +236 -0
- package/templates/agent-os/universal/.agents/skills/loop/SKILL.md +958 -0
- package/templates/agent-os/universal/.agents/skills/new-invariant/SKILL.md +102 -0
- package/templates/agent-os/universal/.agents/skills/new-invariant/guard-invariant.example.mjs +78 -0
- package/templates/agent-os/universal/.agents/skills/new-invariant/guard-invariant.example.test.mjs +89 -0
- package/templates/agent-os/universal/.agents/skills/pr-ship/SKILL.md +396 -0
- package/templates/agent-os/universal/.agents/skills/worktree-task/SKILL.md +73 -0
- package/templates/agent-os/universal/.claude/agents/code-reviewer.md +40 -1
- package/templates/agent-os/universal/.claude/agents/prose-reviewer.md +71 -1
- package/templates/agent-os/universal/.claude/agents/security-scanner.md +40 -0
- package/templates/agent-os/universal/.claude/hooks/gate-stop-dod.mjs +301 -26
- package/templates/agent-os/universal/.claude/hooks/guard-bash.mjs +43 -5
- package/templates/agent-os/universal/.claude/hooks/guard-core-purity.mjs +25 -11
- package/templates/agent-os/universal/.claude/hooks/guard-rulebook.mjs +127 -0
- package/templates/agent-os/universal/.claude/hooks/guard-secret-file.mjs +180 -0
- package/templates/agent-os/universal/.claude/hooks/guard-web-boundary.mjs +32 -13
- package/templates/agent-os/universal/.claude/hooks/inject-rules.mjs +175 -7
- package/templates/agent-os/universal/.claude/hooks/lib/edit-input.mjs +503 -0
- package/templates/agent-os/universal/.claude/rules/autonomy.md +69 -1
- package/templates/agent-os/universal/.claude/rules/invariants.md +104 -19
- package/templates/agent-os/universal/.claude/rules/workflow.md +55 -5
- package/templates/agent-os/universal/.claude/scripts/decision-router.mjs +1260 -0
- package/templates/agent-os/universal/.claude/scripts/detect-missed-gate.mjs +65 -2
- package/templates/agent-os/universal/.claude/scripts/doctor.mjs +351 -0
- package/templates/agent-os/universal/.claude/scripts/git-env.mjs +49 -0
- package/templates/agent-os/universal/.claude/scripts/lib/gate-coverage.mjs +306 -0
- package/templates/agent-os/universal/.claude/scripts/lib/revalidation-points.mjs +28 -0
- package/templates/agent-os/universal/.claude/scripts/lib/secrets.mjs +490 -0
- package/templates/agent-os/universal/.claude/scripts/lib/verdict.mjs +462 -0
- package/templates/agent-os/universal/.claude/scripts/preflight.mjs +33 -17
- package/templates/agent-os/universal/.claude/scripts/queue/as-of.mjs +51 -0
- package/templates/agent-os/universal/.claude/scripts/queue/checkout.mjs +149 -0
- package/templates/agent-os/universal/.claude/scripts/queue/core.mjs +809 -28
- package/templates/agent-os/universal/.claude/scripts/queue/gate-rounds.mjs +160 -0
- package/templates/agent-os/universal/.claude/scripts/queue/github-issues.mjs +95 -16
- package/templates/agent-os/universal/.claude/scripts/queue/index.mjs +543 -15
- package/templates/agent-os/universal/.claude/scripts/queue/jira.mjs +457 -47
- package/templates/agent-os/universal/.claude/scripts/queue/plan-md.mjs +289 -25
- package/templates/agent-os/universal/.claude/scripts/queue/state.mjs +197 -0
- package/templates/agent-os/universal/.claude/scripts/revalidate.mjs +316 -0
- package/templates/agent-os/universal/.claude/scripts/revalidation-report.mjs +180 -0
- package/templates/agent-os/universal/.claude/scripts/run-journal.mjs +435 -0
- package/templates/agent-os/universal/.claude/scripts/run-state.mjs +539 -0
- package/templates/agent-os/universal/.claude/scripts/stop-flag.mjs +15 -8
- package/templates/agent-os/universal/.claude/scripts/unattended-flag.mjs +239 -0
- package/templates/agent-os/universal/.claude/scripts/verdict.mjs +198 -0
- package/templates/agent-os/universal/.claude/settings.json +11 -2
- package/templates/agent-os/universal/.claude/skills/check-premises/SKILL.md +118 -7
- package/templates/agent-os/universal/.claude/skills/loop/SKILL.md +667 -38
- package/templates/agent-os/universal/.claude/skills/pr-ship/SKILL.md +359 -26
- package/templates/agent-os/universal/.codex/agents/code-reviewer.toml +4 -0
- package/templates/agent-os/universal/.codex/agents/prose-reviewer.toml +4 -0
- package/templates/agent-os/universal/.codex/agents/security-scanner.toml +4 -0
- package/templates/agent-os/universal/.codex/agents/test-writer.toml +4 -0
- package/templates/agent-os/universal/.codex/hooks.json +70 -0
- package/templates/agent-os/universal/AGENTS.md +166 -0
- package/templates/agent-os/universal/CLAUDE.md +49 -14
- package/templates/agent-os/universal/PLAN.md +7 -40
- package/templates/agent-os/universal/docs/decisions/closing-a-task.md +98 -0
- package/templates/agent-os/universal/docs/decisions/codex-adapter.md +108 -0
- package/templates/agent-os/universal/docs/decisions/fail-open-guards.md +43 -0
- package/templates/agent-os/universal/docs/decisions/gate-coverage.md +83 -0
- package/templates/agent-os/universal/docs/decisions/review-lanes.md +72 -0
- package/templates/agent-os/universal/docs/decisions/run-directory.md +44 -0
- package/templates/agent-os/universal/docs/decisions/spacing-rations-mechanisms.md +125 -0
- package/templates/agent-os/universal/docs/decisions/stop-conditions-in-a-file.md +46 -0
- package/templates/agent-os/universal/docs/decisions/two-empty-endings.md +74 -0
- package/templates/agent-os/universal/journal/README.md +101 -0
- package/templates/agent-os/universal/layers.json +45 -2
- package/templates/hash-history.json +310 -49
- package/templates/release-ledger.json +9 -0
- package/templates/skeleton/aws-serverless/.github/workflows/deploy.yml +34 -1
- package/templates/skeleton/aws-serverless/README.md +91 -9
- package/templates/skeleton/aws-serverless/apps/web/src/lib/api.ts +9 -2
- package/templates/skeleton/aws-serverless/gitignore +37 -0
- package/templates/skeleton/aws-serverless/infra/bin/app.ts +73 -13
- package/templates/skeleton/aws-serverless/infra/lib/app-stack.ts +136 -4
- package/templates/skeleton/aws-serverless/infra/lib/web-stack.ts +14 -1
- package/templates/skeleton/aws-serverless/infra/test/allowed-origins.test.ts +301 -0
- package/templates/skeleton/aws-serverless/infra/test/app-composition.test.ts +137 -0
- package/templates/skeleton/aws-serverless/infra/test/app-stack.test.ts +36 -20
- package/templates/skeleton/aws-serverless/infra/test/web-stack.test.ts +15 -12
- package/templates/skeleton/aws-serverless/services/api/src/handlers/create-note.ts +33 -6
- package/templates/skeleton/aws-serverless/services/api/src/handlers/list-notes.ts +18 -5
- package/templates/skeleton/aws-serverless/services/api/src/usecases/create-note.ts +11 -0
- package/templates/skeleton/aws-serverless/services/api/test/create-note.handler.test.ts +120 -1
- package/templates/skeleton/aws-serverless/services/api/test/list-notes.test.ts +72 -1
- package/templates/skeleton/node-service/README.md +11 -1
- package/templates/skeleton/node-service/gitignore +34 -0
- package/templates/skeleton/node-service/packages/db/src/note-store.ts +47 -10
- package/templates/skeleton/node-service/packages/db/test/note-store.test.ts +20 -0
- package/templates/skeleton/node-service/services/api/src/main.ts +2 -9
- package/templates/skeleton/node-service/services/api/src/server.ts +93 -10
- package/templates/skeleton/node-service/services/api/src/static-dir.ts +20 -0
- package/templates/skeleton/node-service/services/api/test/server.test.ts +98 -13
- 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
|
+
};
|