@mrciphersmith/keryx 0.2.164 → 0.3.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/README.md +4 -1
- package/dist/cli.js +82540 -50300
- package/dist/core.js +28967 -18937
- package/package.json +2 -2
- package/src/gdgraph/affected-report.ts +141 -0
- package/src/gdgraph/build.ts +170 -23
- package/src/gdgraph/service.ts +6 -0
- package/src/gdgraph/staleness.ts +253 -45
- package/src/gdskills/bundled/agents/codebase-navigator.md +55 -0
- package/src/gdskills/bundled/agents/design-advisor.md +64 -0
- package/src/gdskills/bundled/agents/docs-maintainer.md +56 -0
- package/src/gdskills/bundled/agents/end-to-end-tester.md +56 -0
- package/src/gdskills/bundled/agents/error-path-auditor.md +57 -0
- package/src/gdskills/bundled/agents/go-build-fixer.md +52 -0
- package/src/gdskills/bundled/agents/go-code-auditor.md +49 -0
- package/src/gdskills/bundled/agents/performance-auditor.md +63 -0
- package/src/gdskills/bundled/agents/python-build-fixer.md +52 -0
- package/src/gdskills/bundled/agents/python-code-auditor.md +49 -0
- package/src/gdskills/bundled/agents/refactoring-steward.md +61 -0
- package/src/gdskills/bundled/agents/security-auditor.md +62 -0
- package/src/gdskills/bundled/agents/test-first-driver.md +61 -0
- package/src/gdskills/bundled/agents/work-planner.md +62 -0
- package/src/gdskills/bundled/install-manifest.json +797 -0
- package/src/gdskills/bundled/rules/core/model-selection.mdc +51 -0
- package/src/gdskills/bundled/rules/core/skill-lifecycle.mdc +29 -1
- package/src/gdskills/bundled/rules/core/skills-storage-workflow.mdc +2 -2
- package/src/gdskills/bundled/skills/review/code-style-review/SKILL.md +1 -1
- package/src/gdskills/bundled/skills/review/review-jev-rules/SKILL.md +267 -0
- package/src/gdskills/bundled/skills/review/review-orchestrator/SKILL.detail.md +26 -0
- package/src/gdskills/bundled/skills/review/review-orchestrator/SKILL.md +75 -247
- package/src/gdskills/bundled/skills/review/review-orchestrator/output-contract.schema.json +19 -0
- package/src/gdskills/bundled/skills/review/review-orchestrator/reviewer-finding.schema.json +10 -0
- package/src/gdskills/bundled/skills/review/review-orchestrator/reviewer-input.schema.json +5 -0
- package/src/gdskills/bundled/skills/review/review-orchestrator/templates/pr-comment-backend.md +50 -0
- package/src/gdskills/bundled/skills/review/review-orchestrator/templates/pr-comment-frontend.md +52 -0
- package/src/gdskills/bundled/skills/review/review-orchestrator/templates/review-report.md +143 -0
- package/src/gdskills/bundled/stacks/angular/agent-refs.json +4 -0
- package/src/gdskills/bundled/stacks/angular/governance/eval.json +1751 -0
- package/src/gdskills/bundled/stacks/angular/governance/scout.json +32 -0
- package/src/gdskills/bundled/stacks/angular/pack.json +55 -0
- package/src/gdskills/bundled/stacks/angular/rules/coding-style.mdc +82 -0
- package/src/gdskills/bundled/stacks/angular/rules/patterns.mdc +84 -0
- package/src/gdskills/bundled/stacks/angular/rules/security.mdc +70 -0
- package/src/gdskills/bundled/stacks/angular/rules/testing.mdc +73 -0
- package/src/gdskills/bundled/stacks/angular/skills/angular-build-fix/SKILL.md +127 -0
- package/src/gdskills/bundled/stacks/angular/skills/angular-build-fix/evals.json +72 -0
- package/src/gdskills/bundled/stacks/angular/skills/angular-code-review/SKILL.md +98 -0
- package/src/gdskills/bundled/stacks/angular/skills/angular-code-review/evals.json +73 -0
- package/src/gdskills/bundled/stacks/angular/skills/angular-implementation/SKILL.md +112 -0
- package/src/gdskills/bundled/stacks/angular/skills/angular-implementation/evals.json +74 -0
- package/src/gdskills/bundled/stacks/angular/skills/angular-testing/SKILL.md +102 -0
- package/src/gdskills/bundled/stacks/angular/skills/angular-testing/evals.json +71 -0
- package/src/gdskills/bundled/stacks/go/agent-refs.json +3 -0
- package/src/gdskills/bundled/stacks/go/governance/eval.json +1745 -0
- package/src/gdskills/bundled/stacks/go/governance/scout.json +31 -0
- package/src/gdskills/bundled/stacks/go/pack.json +41 -0
- package/src/gdskills/bundled/stacks/go/rules/coding-style.mdc +85 -0
- package/src/gdskills/bundled/stacks/go/rules/patterns.mdc +65 -0
- package/src/gdskills/bundled/stacks/go/rules/security.mdc +73 -0
- package/src/gdskills/bundled/stacks/go/rules/testing.mdc +68 -0
- package/src/gdskills/bundled/stacks/go/skills/go-build-fix/SKILL.md +138 -0
- package/src/gdskills/bundled/stacks/go/skills/go-build-fix/evals.json +75 -0
- package/src/gdskills/bundled/stacks/go/skills/go-code-review/SKILL.md +121 -0
- package/src/gdskills/bundled/stacks/go/skills/go-code-review/evals.json +72 -0
- package/src/gdskills/bundled/stacks/go/skills/go-implementation/SKILL.md +122 -0
- package/src/gdskills/bundled/stacks/go/skills/go-implementation/evals.json +76 -0
- package/src/gdskills/bundled/stacks/go/skills/go-testing/SKILL.md +126 -0
- package/src/gdskills/bundled/stacks/go/skills/go-testing/evals.json +73 -0
- package/src/gdskills/bundled/stacks/mobx/agent-refs.json +4 -0
- package/src/gdskills/bundled/stacks/mobx/governance/eval.json +904 -0
- package/src/gdskills/bundled/stacks/mobx/governance/scout.json +18 -0
- package/src/gdskills/bundled/stacks/mobx/pack.json +28 -0
- package/src/gdskills/bundled/stacks/mobx/rules/coding-style.mdc +91 -0
- package/src/gdskills/bundled/stacks/mobx/rules/patterns.mdc +122 -0
- package/src/gdskills/bundled/stacks/mobx/rules/security.mdc +56 -0
- package/src/gdskills/bundled/stacks/mobx/rules/testing.mdc +63 -0
- package/src/gdskills/bundled/stacks/mobx/skills/mobx-observable-testing/SKILL.md +124 -0
- package/src/gdskills/bundled/stacks/mobx/skills/mobx-observable-testing/evals.json +73 -0
- package/src/gdskills/bundled/stacks/mobx/skills/mobx-store-implementation/SKILL.md +149 -0
- package/src/gdskills/bundled/stacks/mobx/skills/mobx-store-implementation/evals.json +74 -0
- package/src/gdskills/bundled/stacks/nestjs/agent-refs.json +4 -0
- package/src/gdskills/bundled/stacks/nestjs/governance/eval.json +1308 -0
- package/src/gdskills/bundled/stacks/nestjs/governance/scout.json +34 -0
- package/src/gdskills/bundled/stacks/nestjs/pack.json +53 -0
- package/src/gdskills/bundled/stacks/nestjs/rules/coding-style.mdc +70 -0
- package/src/gdskills/bundled/stacks/nestjs/rules/patterns.mdc +83 -0
- package/src/gdskills/bundled/stacks/nestjs/rules/security.mdc +73 -0
- package/src/gdskills/bundled/stacks/nestjs/rules/testing.mdc +69 -0
- package/src/gdskills/bundled/stacks/nestjs/skills/nestjs-build-fix/SKILL.md +157 -0
- package/src/gdskills/bundled/stacks/nestjs/skills/nestjs-build-fix/evals.json +70 -0
- package/src/gdskills/bundled/stacks/nestjs/skills/nestjs-implementation/SKILL.md +129 -0
- package/src/gdskills/bundled/stacks/nestjs/skills/nestjs-implementation/evals.json +71 -0
- package/src/gdskills/bundled/stacks/nestjs/skills/nestjs-testing/SKILL.md +143 -0
- package/src/gdskills/bundled/stacks/nestjs/skills/nestjs-testing/evals.json +69 -0
- package/src/gdskills/bundled/stacks/nextjs-nuxt/agent-refs.json +4 -0
- package/src/gdskills/bundled/stacks/nextjs-nuxt/governance/eval.json +2413 -0
- package/src/gdskills/bundled/stacks/nextjs-nuxt/governance/scout.json +42 -0
- package/src/gdskills/bundled/stacks/nextjs-nuxt/pack.json +42 -0
- package/src/gdskills/bundled/stacks/nextjs-nuxt/rules/coding-style.mdc +69 -0
- package/src/gdskills/bundled/stacks/nextjs-nuxt/rules/patterns.mdc +88 -0
- package/src/gdskills/bundled/stacks/nextjs-nuxt/rules/security.mdc +72 -0
- package/src/gdskills/bundled/stacks/nextjs-nuxt/rules/testing.mdc +64 -0
- package/src/gdskills/bundled/stacks/nextjs-nuxt/skills/nextjs-nuxt-build-fix/SKILL.md +147 -0
- package/src/gdskills/bundled/stacks/nextjs-nuxt/skills/nextjs-nuxt-build-fix/evals.json +75 -0
- package/src/gdskills/bundled/stacks/nextjs-nuxt/skills/nextjs-nuxt-code-review/SKILL.md +118 -0
- package/src/gdskills/bundled/stacks/nextjs-nuxt/skills/nextjs-nuxt-code-review/evals.json +76 -0
- package/src/gdskills/bundled/stacks/nextjs-nuxt/skills/nextjs-nuxt-implementation/SKILL.md +135 -0
- package/src/gdskills/bundled/stacks/nextjs-nuxt/skills/nextjs-nuxt-implementation/evals.json +78 -0
- package/src/gdskills/bundled/stacks/nextjs-nuxt/skills/nextjs-nuxt-testing/SKILL.md +116 -0
- package/src/gdskills/bundled/stacks/nextjs-nuxt/skills/nextjs-nuxt-testing/evals.json +75 -0
- package/src/gdskills/bundled/stacks/nextjs-nuxt/skills/nextjs-nuxt-upgrade-migration/SKILL.md +134 -0
- package/src/gdskills/bundled/stacks/nextjs-nuxt/skills/nextjs-nuxt-upgrade-migration/evals.json +76 -0
- package/src/gdskills/bundled/stacks/python/agent-refs.json +3 -0
- package/src/gdskills/bundled/stacks/python/governance/eval.json +1758 -0
- package/src/gdskills/bundled/stacks/python/governance/scout.json +34 -0
- package/src/gdskills/bundled/stacks/python/pack.json +41 -0
- package/src/gdskills/bundled/stacks/python/rules/coding-style.mdc +63 -0
- package/src/gdskills/bundled/stacks/python/rules/patterns.mdc +88 -0
- package/src/gdskills/bundled/stacks/python/rules/security.mdc +84 -0
- package/src/gdskills/bundled/stacks/python/rules/testing.mdc +77 -0
- package/src/gdskills/bundled/stacks/python/skills/python-build-fix/SKILL.md +144 -0
- package/src/gdskills/bundled/stacks/python/skills/python-build-fix/evals.json +74 -0
- package/src/gdskills/bundled/stacks/python/skills/python-code-review/SKILL.md +155 -0
- package/src/gdskills/bundled/stacks/python/skills/python-code-review/evals.json +72 -0
- package/src/gdskills/bundled/stacks/python/skills/python-implementation/SKILL.md +143 -0
- package/src/gdskills/bundled/stacks/python/skills/python-implementation/evals.json +78 -0
- package/src/gdskills/bundled/stacks/python/skills/python-testing/SKILL.md +132 -0
- package/src/gdskills/bundled/stacks/python/skills/python-testing/evals.json +73 -0
- package/src/gdskills/bundled/stacks/react/agent-refs.json +4 -0
- package/src/gdskills/bundled/stacks/react/governance/eval.json +2188 -0
- package/src/gdskills/bundled/stacks/react/governance/scout.json +40 -0
- package/src/gdskills/bundled/stacks/react/pack.json +42 -0
- package/src/gdskills/bundled/stacks/react/rules/coding-style.mdc +58 -0
- package/src/gdskills/bundled/stacks/react/rules/patterns.mdc +79 -0
- package/src/gdskills/bundled/stacks/react/rules/security.mdc +70 -0
- package/src/gdskills/bundled/stacks/react/rules/testing.mdc +60 -0
- package/src/gdskills/bundled/stacks/react/skills/react-build-fix/SKILL.md +139 -0
- package/src/gdskills/bundled/stacks/react/skills/react-build-fix/evals.json +72 -0
- package/src/gdskills/bundled/stacks/react/skills/react-code-review/SKILL.md +148 -0
- package/src/gdskills/bundled/stacks/react/skills/react-code-review/evals.json +74 -0
- package/src/gdskills/bundled/stacks/react/skills/react-implementation/SKILL.md +140 -0
- package/src/gdskills/bundled/stacks/react/skills/react-implementation/evals.json +74 -0
- package/src/gdskills/bundled/stacks/react/skills/react-testing/SKILL.md +142 -0
- package/src/gdskills/bundled/stacks/react/skills/react-testing/evals.json +83 -0
- package/src/gdskills/bundled/stacks/react/skills/react-upgrade-migration/SKILL.md +155 -0
- package/src/gdskills/bundled/stacks/react/skills/react-upgrade-migration/evals.json +74 -0
- package/src/gdskills/bundled/stacks/ts-js-node/agent-refs.json +4 -0
- package/src/gdskills/bundled/stacks/ts-js-node/governance/eval.json +2155 -0
- package/src/gdskills/bundled/stacks/ts-js-node/governance/scout.json +40 -0
- package/src/gdskills/bundled/stacks/ts-js-node/pack.json +41 -0
- package/src/gdskills/bundled/stacks/ts-js-node/rules/coding-style.mdc +73 -0
- package/src/gdskills/bundled/stacks/ts-js-node/rules/patterns.mdc +61 -0
- package/src/gdskills/bundled/stacks/ts-js-node/rules/security.mdc +71 -0
- package/src/gdskills/bundled/stacks/ts-js-node/rules/testing.mdc +63 -0
- package/src/gdskills/bundled/stacks/ts-js-node/skills/nodejs-build-fix/SKILL.md +137 -0
- package/src/gdskills/bundled/stacks/ts-js-node/skills/nodejs-build-fix/evals.json +73 -0
- package/src/gdskills/bundled/stacks/ts-js-node/skills/nodejs-code-review/SKILL.md +124 -0
- package/src/gdskills/bundled/stacks/ts-js-node/skills/nodejs-code-review/evals.json +74 -0
- package/src/gdskills/bundled/stacks/ts-js-node/skills/nodejs-esm-migration/SKILL.md +152 -0
- package/src/gdskills/bundled/stacks/ts-js-node/skills/nodejs-esm-migration/evals.json +71 -0
- package/src/gdskills/bundled/stacks/ts-js-node/skills/nodejs-implementation/SKILL.md +127 -0
- package/src/gdskills/bundled/stacks/ts-js-node/skills/nodejs-implementation/evals.json +72 -0
- package/src/gdskills/bundled/stacks/ts-js-node/skills/nodejs-testing/SKILL.md +134 -0
- package/src/gdskills/bundled/stacks/ts-js-node/skills/nodejs-testing/evals.json +70 -0
- package/src/gdskills/bundled/stacks/vue/agent-refs.json +4 -0
- package/src/gdskills/bundled/stacks/vue/governance/eval.json +2215 -0
- package/src/gdskills/bundled/stacks/vue/governance/scout.json +42 -0
- package/src/gdskills/bundled/stacks/vue/pack.json +42 -0
- package/src/gdskills/bundled/stacks/vue/rules/coding-style.mdc +73 -0
- package/src/gdskills/bundled/stacks/vue/rules/patterns.mdc +84 -0
- package/src/gdskills/bundled/stacks/vue/rules/security.mdc +60 -0
- package/src/gdskills/bundled/stacks/vue/rules/testing.mdc +69 -0
- package/src/gdskills/bundled/stacks/vue/skills/vue-build-fix/SKILL.md +137 -0
- package/src/gdskills/bundled/stacks/vue/skills/vue-build-fix/evals.json +72 -0
- package/src/gdskills/bundled/stacks/vue/skills/vue-code-review/SKILL.md +120 -0
- package/src/gdskills/bundled/stacks/vue/skills/vue-code-review/evals.json +71 -0
- package/src/gdskills/bundled/stacks/vue/skills/vue-implementation/SKILL.md +122 -0
- package/src/gdskills/bundled/stacks/vue/skills/vue-implementation/evals.json +72 -0
- package/src/gdskills/bundled/stacks/vue/skills/vue-testing/SKILL.md +115 -0
- package/src/gdskills/bundled/stacks/vue/skills/vue-testing/evals.json +72 -0
- package/src/gdskills/bundled/stacks/vue/skills/vue2-to-vue3-migration/SKILL.md +135 -0
- package/src/gdskills/bundled/stacks/vue/skills/vue2-to-vue3-migration/evals.json +71 -0
package/src/gdgraph/staleness.ts
CHANGED
|
@@ -1,7 +1,61 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
1
2
|
import { stat } from "node:fs/promises";
|
|
2
3
|
import path from "node:path";
|
|
3
4
|
import { gitCmd, gitHead, readProvenance } from "../sync/provenance";
|
|
4
5
|
|
|
6
|
+
// W7 AC4 follow-up (flow 304 T8) — a real, previously-latent defect found
|
|
7
|
+
// while wiring up the `modified` bucket below: `gitCmd`/`gitCmdResult`
|
|
8
|
+
// (`../sync/provenance.ts`) both call `.trim()` on the ENTIRE stdout blob,
|
|
9
|
+
// not per line. `git status --porcelain=v1`'s status code for an unstaged
|
|
10
|
+
// content-only edit is TWO CHARACTERS WIDE, and the first is a literal space
|
|
11
|
+
// (" M"); when that line is the first line of the output, the whole-string
|
|
12
|
+
// trim silently eats that leading space — shifting every following character
|
|
13
|
+
// left by one, corrupting BOTH the status-letter read (`line[0]`/`line[1]`)
|
|
14
|
+
// and the reported path (`line.slice(3)`) for whichever file happens to sort
|
|
15
|
+
// first. This was invisible before this task because nothing previously
|
|
16
|
+
// asserted the SPECIFIC path a trigger named (only "some reason fired" —
|
|
17
|
+
// `line[0]` after the shift often still happened to equal the status letter
|
|
18
|
+
// being tested for `added`/`deleted`/`renamed`, purely by coincidence of
|
|
19
|
+
// which letter shifted into position 0). `gitCmd` is shared by several other
|
|
20
|
+
// callers and is out of this task's lane (`src/gdgraph/**`,
|
|
21
|
+
// `src/commands/gdgraph*.ts` only) to change; this module instead spawns
|
|
22
|
+
// `git status` itself and strips only the single trailing newline git always
|
|
23
|
+
// terminates the last line with, never the leading byte of the first one.
|
|
24
|
+
// F9 (fix round 1): with `core.quotePath` at its (default, on) setting, `git
|
|
25
|
+
// status --porcelain` octal-escapes and double-quotes any path holding a
|
|
26
|
+
// non-ASCII or otherwise "unusual" byte — e.g. `src/café.ts` prints as
|
|
27
|
+
// `"src/caf\303\251.ts"`. The line-oriented parser below used to read that
|
|
28
|
+
// quoted, escaped text as the literal path, so every `stat()` against it
|
|
29
|
+
// missed (the real file on disk has no quotes or octal escapes in its name)
|
|
30
|
+
// and the edit went unreported. `-z` (NUL-separated) output is never quoted
|
|
31
|
+
// or escaped — git prints exact bytes — which sidesteps the whole unquoting
|
|
32
|
+
// problem instead of implementing octal-unescaping here. It also removes the
|
|
33
|
+
// newline-vs-content ambiguity `-z` output has no other use for line
|
|
34
|
+
// splitting: an ordinary entry is `XY PATH\0`, but a rename/copy (X or Y is
|
|
35
|
+
// `R`/`C`) is `XY PATH\0ORIG_PATH\0` — TWO NUL-terminated fields, not one —
|
|
36
|
+
// which `categorizeStatusEntries` below accounts for.
|
|
37
|
+
function gitStatusPorcelain(cwd: string): Promise<string | null> {
|
|
38
|
+
return new Promise((resolve) => {
|
|
39
|
+
try {
|
|
40
|
+
const child = spawn("git", ["status", "--porcelain=v1", "-z"], { cwd, stdio: ["ignore", "pipe", "ignore"] });
|
|
41
|
+
let out = "";
|
|
42
|
+
child.stdout?.on("data", (chunk) => {
|
|
43
|
+
out += String(chunk);
|
|
44
|
+
});
|
|
45
|
+
child.on("error", () => resolve(null));
|
|
46
|
+
child.on("close", (code) => {
|
|
47
|
+
if (code !== 0) {
|
|
48
|
+
resolve(null);
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
resolve(out.endsWith("\0") ? out.slice(0, -1) : out);
|
|
52
|
+
});
|
|
53
|
+
} catch {
|
|
54
|
+
resolve(null);
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
|
|
5
59
|
// AFC-10 (flow 234, phase 2, frozen AC3): "a new commit, untracked, delete,
|
|
6
60
|
// rename and config change invalidate the snapshot; an unknown target differs
|
|
7
61
|
// from indexed/no-edges; a git error never becomes fresh."
|
|
@@ -25,14 +79,13 @@ import { gitCmd, gitHead, readProvenance } from "../sync/provenance";
|
|
|
25
79
|
// on every commit/checkout/branch-switch, unlike
|
|
26
80
|
// `.git/HEAD`'s own — when no provenance was
|
|
27
81
|
// recorded for this build).
|
|
28
|
-
// - untracked/delete/rename: `git status --porcelain=v1`, categorized
|
|
29
|
-
// status letter. A plain in-place content edit
|
|
30
|
-
// (` M`/`M `)
|
|
31
|
-
// the
|
|
32
|
-
//
|
|
33
|
-
//
|
|
34
|
-
//
|
|
35
|
-
// leaves the file-level graph correct.
|
|
82
|
+
// - untracked/delete/rename/modify: `git status --porcelain=v1`, categorized
|
|
83
|
+
// by status letter. A plain in-place content edit
|
|
84
|
+
// (` M`/`M `) IS a trigger (W7 AC4 follow-up, flow
|
|
85
|
+
// 304 T8) — but only when the file's own mtime
|
|
86
|
+
// postdates the build, so an edit already on disk
|
|
87
|
+
// when `gdgraph build` ran (already reflected in
|
|
88
|
+
// the graph) does not false-stale it.
|
|
36
89
|
// - config change: `.metaproject/gdgraph.config.json`'s mtime vs
|
|
37
90
|
// `nodes.jsonl`'s. No separate baseline write is
|
|
38
91
|
// needed for this: the config file only *has* a
|
|
@@ -62,7 +115,8 @@ function gdgraphConfigPath(cwd: string): string {
|
|
|
62
115
|
// Categorize `git status --porcelain=v1` lines. Each line is exactly two
|
|
63
116
|
// status characters (index status, worktree status) followed by a space and
|
|
64
117
|
// the path (renames add " -> newPath"). A pure content modify (` M`/`M `/`MM`)
|
|
65
|
-
//
|
|
118
|
+
// goes into its own `modified` bucket — see the module doc above and the
|
|
119
|
+
// caller's mtime gate.
|
|
66
120
|
//
|
|
67
121
|
// Lines under `.metaproject/` are skipped entirely: that tree holds gdgraph's
|
|
68
122
|
// OWN generated bookkeeping (`.provenance.json`, `artifacts/*`), which the
|
|
@@ -79,39 +133,118 @@ function gdgraphConfigPath(cwd: string): string {
|
|
|
79
133
|
// project root IS the git root; `rootPrefix` (from `git rev-parse
|
|
80
134
|
// --show-prefix`, empty at the git root) is prepended so the same exclusion
|
|
81
135
|
// matches at both.
|
|
82
|
-
|
|
83
|
-
|
|
136
|
+
// W7 AC4 ("a reason naming the changed file"): the trigger buckets carry the
|
|
137
|
+
// actual paths that tripped them, not just a boolean — a reader gets "which
|
|
138
|
+
// file", not only "some file". `nameFiles` below turns a bucket into the
|
|
139
|
+
// reason string, bounded the same way this codebase bounds every other
|
|
140
|
+
// unbounded listing (a handful named, "+N more" beyond that).
|
|
141
|
+
//
|
|
142
|
+
// W7 AC4 follow-up (flow 304 T8): a pure content edit (` M`/`M `/`MM`) is now
|
|
143
|
+
// its OWN bucket (`modified`) instead of being dropped — see the caller,
|
|
144
|
+
// which promotes it to a trigger only when the file's mtime postdates the
|
|
145
|
+
// build (a content edit already present at build time is already reflected
|
|
146
|
+
// in the graph and must not false-stale it).
|
|
147
|
+
//
|
|
148
|
+
// F9 (fix round 1): entries come in NUL-separated (`-z`) from
|
|
149
|
+
// `gitStatusPorcelain`, never quoted/escaped, so there is no quote-stripping
|
|
150
|
+
// left to do here — the previous `.replace(/^"|"$/g, "")` existed only to
|
|
151
|
+
// undo the quoting `-z` never produces in the first place. A rename/copy
|
|
152
|
+
// entry (X or Y is `R`/`C`) is TWO consecutive NUL-terminated fields — the
|
|
153
|
+
// new path, then the original path — not one "old -> new" line; `entries[i +
|
|
154
|
+
// 1]` below consumes that second field so it is never misread as its own
|
|
155
|
+
// unrelated status entry.
|
|
156
|
+
function categorizeStatusEntries(
|
|
157
|
+
entries: string[],
|
|
84
158
|
rootPrefix: string,
|
|
85
|
-
): { added:
|
|
86
|
-
const lines = porcelain.split("\n").filter((line) => line.length >= 2);
|
|
159
|
+
): { added: string[]; deleted: string[]; renamed: string[]; modified: string[] } {
|
|
87
160
|
const metaprojectPrefix = `${rootPrefix}.metaproject/`;
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
const
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
const
|
|
99
|
-
|
|
100
|
-
|
|
161
|
+
const added: string[] = [];
|
|
162
|
+
const deleted: string[] = [];
|
|
163
|
+
const renamed: string[] = [];
|
|
164
|
+
const modified: string[] = [];
|
|
165
|
+
for (let i = 0; i < entries.length; i += 1) {
|
|
166
|
+
const entry = entries[i] ?? "";
|
|
167
|
+
if (entry.length < 2) {
|
|
168
|
+
continue;
|
|
169
|
+
}
|
|
170
|
+
const indexStatus = entry[0];
|
|
171
|
+
const worktreeStatus = entry[1];
|
|
172
|
+
const rawPath = entry.slice(3);
|
|
173
|
+
// Renames AND copies (X or Y is `R`/`C`) both carry a second, orig-path
|
|
174
|
+
// field in `-z` output — it must be consumed here regardless of which
|
|
175
|
+
// bucket (if any) the entry itself lands in below, or the next loop
|
|
176
|
+
// iteration would misparse that orig-path field as its own status entry.
|
|
177
|
+
const hasOrigPathField =
|
|
178
|
+
indexStatus === "R" || worktreeStatus === "R" || indexStatus === "C" || worktreeStatus === "C";
|
|
179
|
+
const origPath = hasOrigPathField ? entries[i + 1] ?? null : null;
|
|
180
|
+
if (hasOrigPathField) {
|
|
181
|
+
i += 1;
|
|
182
|
+
}
|
|
183
|
+
const isMetaprojectPath = [rawPath, origPath]
|
|
184
|
+
.filter((candidate): candidate is string => candidate !== null)
|
|
185
|
+
.some((candidate) => candidate.startsWith(metaprojectPrefix));
|
|
101
186
|
if (isMetaprojectPath) {
|
|
102
187
|
continue;
|
|
103
188
|
}
|
|
104
189
|
if (indexStatus === "?" || worktreeStatus === "?" || indexStatus === "A") {
|
|
105
|
-
added
|
|
190
|
+
added.push(rawPath);
|
|
191
|
+
continue;
|
|
106
192
|
}
|
|
107
193
|
if (indexStatus === "D" || worktreeStatus === "D") {
|
|
108
|
-
deleted
|
|
194
|
+
deleted.push(rawPath);
|
|
195
|
+
continue;
|
|
109
196
|
}
|
|
110
197
|
if (indexStatus === "R" || worktreeStatus === "R") {
|
|
111
|
-
renamed
|
|
198
|
+
renamed.push(rawPath);
|
|
199
|
+
continue;
|
|
200
|
+
}
|
|
201
|
+
if (indexStatus === "M" || worktreeStatus === "M") {
|
|
202
|
+
modified.push(rawPath);
|
|
112
203
|
}
|
|
113
204
|
}
|
|
114
|
-
return { added, deleted, renamed };
|
|
205
|
+
return { added, deleted, renamed, modified };
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
const REASON_FILE_DISPLAY_LIMIT = 5;
|
|
209
|
+
|
|
210
|
+
function nameFiles(message: string, files: string[]): string {
|
|
211
|
+
if (files.length === 0) {
|
|
212
|
+
return message;
|
|
213
|
+
}
|
|
214
|
+
const shown = files.slice(0, REASON_FILE_DISPLAY_LIMIT).join(", ");
|
|
215
|
+
const overflow = files.length > REASON_FILE_DISPLAY_LIMIT
|
|
216
|
+
? ` (+${files.length - REASON_FILE_DISPLAY_LIMIT} more)`
|
|
217
|
+
: "";
|
|
218
|
+
return `${message}: ${shown}${overflow}`;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// W7 AC4 follow-up: when `provenance.commit !== head.commit`, name which
|
|
222
|
+
// file(s) actually moved between the two, the same way the working-tree
|
|
223
|
+
// triggers already do — a caller told "HEAD moved" without knowing which
|
|
224
|
+
// files still has to run a full diff itself to find out. One extra git call,
|
|
225
|
+
// gated behind the already-uncommon "commit moved" branch (never on the
|
|
226
|
+
// common clean/fresh path), so this stays within the module's own
|
|
227
|
+
// cheap-probe budget.
|
|
228
|
+
async function committedChangedFiles(
|
|
229
|
+
cwd: string,
|
|
230
|
+
fromCommit: string,
|
|
231
|
+
toCommit: string,
|
|
232
|
+
rootPrefix: string,
|
|
233
|
+
): Promise<string[]> {
|
|
234
|
+
// F9: `-z` here too — `--name-only` quotes/octal-escapes an unusual path
|
|
235
|
+
// (e.g. `src/café.ts` → `"src/caf\303\251.ts"`) exactly like `git status`
|
|
236
|
+
// does, which fed a mismatched, unstat-able path into `nameFiles` for the
|
|
237
|
+
// "HEAD moved" reason. `--name-only -z` lists only the destination path per
|
|
238
|
+
// entry even for a rename (unlike `git status -z`, which pairs it with an
|
|
239
|
+
// orig-path field), so this stays a plain NUL-split with no pairing logic.
|
|
240
|
+
const diff = await gitCmd(cwd, ["diff", "--name-only", "-z", fromCommit, toCommit]);
|
|
241
|
+
if (diff === null) {
|
|
242
|
+
return [];
|
|
243
|
+
}
|
|
244
|
+
const metaprojectPrefix = `${rootPrefix}.metaproject/`;
|
|
245
|
+
return diff
|
|
246
|
+
.split("\0")
|
|
247
|
+
.filter((entry) => entry.length > 0 && !entry.startsWith(metaprojectPrefix));
|
|
115
248
|
}
|
|
116
249
|
|
|
117
250
|
/**
|
|
@@ -149,7 +282,28 @@ export async function checkGraphStaleness(cwd: string): Promise<StalenessCheck>
|
|
|
149
282
|
// provenance is honestly advanced, an ADVANCING mismatch here really does
|
|
150
283
|
// mean the graph predates HEAD, and this is exactly the check the wiki gate
|
|
151
284
|
// (`../wiki/staleness.ts`) needs to keep trusting for that.
|
|
285
|
+
// W7 AC4 (PART A item 3): a graph that DID record provenance and then had
|
|
286
|
+
// `.provenance.json` deleted (or one that was never recorded at all) has no
|
|
287
|
+
// reliable "did the commit move" signal any more — only the best-effort
|
|
288
|
+
// `.git/logs/HEAD` mtime fallback below, which is silent whenever the build
|
|
289
|
+
// happened to run after the last commit (the common, unremarkable case).
|
|
290
|
+
// Before this fix, that silence made the whole check return `fresh` with no
|
|
291
|
+
// trace that the one strong freshness signal (a recorded baseline commit)
|
|
292
|
+
// was missing — exactly the "silently reads as confirmed-current" outcome
|
|
293
|
+
// this module's own contract says a check must never produce. `provenanceMissing`
|
|
294
|
+
// is set whenever there is nothing to compare HEAD against; if nothing else
|
|
295
|
+
// below turns up a concrete reason, the result downgrades from `fresh` to
|
|
296
|
+
// `unknown` (a weaker claim — "not verified", not "confirmed stale") rather
|
|
297
|
+
// than staying silently fresh.
|
|
298
|
+
let provenanceMissing = false;
|
|
152
299
|
const head = await gitHead(cwd);
|
|
300
|
+
// T19 finding 3: `--show-prefix` is the project root's path relative to the
|
|
301
|
+
// git root (empty string AT the git root) — needed both here (to scope a
|
|
302
|
+
// commit-range diff to real source, excluding the graph's own bookkeeping)
|
|
303
|
+
// and below (the working-tree `.metaproject/` exclusion). Fetched once and
|
|
304
|
+
// reused, so this stays within the module's stated "one or two git calls"
|
|
305
|
+
// budget rather than asking twice.
|
|
306
|
+
const rootPrefix = head !== null ? ((await gitCmd(cwd, ["rev-parse", "--show-prefix"])) ?? "") : "";
|
|
153
307
|
if (head === null) {
|
|
154
308
|
gitFailed = true;
|
|
155
309
|
reasons.push("git rev-parse HEAD failed (not a git repository, or git is unavailable)");
|
|
@@ -157,11 +311,16 @@ export async function checkGraphStaleness(cwd: string): Promise<StalenessCheck>
|
|
|
157
311
|
const provenance = await readProvenance(cwd, "gdgraph");
|
|
158
312
|
if (provenance) {
|
|
159
313
|
if (provenance.commit !== head.commit) {
|
|
314
|
+
const changedFiles = await committedChangedFiles(cwd, provenance.commit, head.commit, rootPrefix);
|
|
160
315
|
reasons.push(
|
|
161
|
-
|
|
316
|
+
nameFiles(
|
|
317
|
+
`HEAD moved since the graph was built (built at ${provenance.commit.slice(0, 12)}, now ${head.commit.slice(0, 12)})`,
|
|
318
|
+
changedFiles,
|
|
319
|
+
),
|
|
162
320
|
);
|
|
163
321
|
}
|
|
164
322
|
} else {
|
|
323
|
+
provenanceMissing = true;
|
|
165
324
|
// No recorded build provenance for this graph. Fall back to the
|
|
166
325
|
// reflog's mtime: unlike `.git/HEAD` (a symbolic ref whose content is
|
|
167
326
|
// usually just "ref: refs/heads/<branch>" and does not change on an
|
|
@@ -176,24 +335,57 @@ export async function checkGraphStaleness(cwd: string): Promise<StalenessCheck>
|
|
|
176
335
|
}
|
|
177
336
|
}
|
|
178
337
|
|
|
179
|
-
// --- untracked / deleted / renamed
|
|
180
|
-
const porcelain = await
|
|
338
|
+
// --- untracked / deleted / renamed / modified ------------------------------
|
|
339
|
+
const porcelain = await gitStatusPorcelain(cwd);
|
|
181
340
|
if (porcelain === null) {
|
|
182
341
|
gitFailed = true;
|
|
183
342
|
reasons.push("git status failed");
|
|
184
343
|
} else {
|
|
185
|
-
//
|
|
186
|
-
// the git root
|
|
187
|
-
// below it) — exactly the prefix `git status --porcelain`'s repo-root-
|
|
344
|
+
// `rootPrefix` (fetched once, above) is the project root's path relative
|
|
345
|
+
// to the git root — exactly what `git status --porcelain`'s repo-root-
|
|
188
346
|
// relative paths need for the `.metaproject/` exclusion to match
|
|
189
|
-
// regardless of where the project root sits
|
|
190
|
-
//
|
|
191
|
-
//
|
|
192
|
-
const
|
|
193
|
-
const { added, deleted, renamed } =
|
|
194
|
-
if (added
|
|
195
|
-
|
|
196
|
-
|
|
347
|
+
// regardless of where the project root sits (T19 finding 3).
|
|
348
|
+
// `-z` output is NUL-separated (never newline-separated, and a filename
|
|
349
|
+
// can itself contain "\n"), so entries are split on "\0", not "\n".
|
|
350
|
+
const entries = porcelain.split("\0").filter((entry) => entry.length > 0);
|
|
351
|
+
const { added, deleted, renamed, modified } = categorizeStatusEntries(entries, rootPrefix);
|
|
352
|
+
if (added.length > 0) {
|
|
353
|
+
reasons.push(nameFiles("an untracked or newly added file exists in the working tree", added));
|
|
354
|
+
}
|
|
355
|
+
if (deleted.length > 0) {
|
|
356
|
+
reasons.push(nameFiles("a tracked file was deleted in the working tree", deleted));
|
|
357
|
+
}
|
|
358
|
+
if (renamed.length > 0) {
|
|
359
|
+
reasons.push(nameFiles("a file was renamed (staged) in the working tree", renamed));
|
|
360
|
+
}
|
|
361
|
+
// W7 AC4 follow-up (flow 304 T8): a pure content edit is a trigger too,
|
|
362
|
+
// but ONLY when the file's own mtime postdates the graph's build — an
|
|
363
|
+
// edit already on disk when `gdgraph build` ran is already reflected in
|
|
364
|
+
// the graph; re-flagging it would false-stale every build whose source
|
|
365
|
+
// tree was not pristine (i.e. nearly all of them). `nodesStat.mtimeMs` is
|
|
366
|
+
// this module's existing build-time proxy (already used for the config-
|
|
367
|
+
// change check below), reused here rather than introducing a second
|
|
368
|
+
// "when was it built" concept.
|
|
369
|
+
if (modified.length > 0) {
|
|
370
|
+
const postBuildEdits: string[] = [];
|
|
371
|
+
for (const displayPath of modified) {
|
|
372
|
+
const projectRelative = rootPrefix && displayPath.startsWith(rootPrefix)
|
|
373
|
+
? displayPath.slice(rootPrefix.length)
|
|
374
|
+
: rootPrefix
|
|
375
|
+
? null // outside this project's subtree in the repo — not ours to report
|
|
376
|
+
: displayPath;
|
|
377
|
+
if (projectRelative === null) {
|
|
378
|
+
continue;
|
|
379
|
+
}
|
|
380
|
+
const fileStat = await stat(path.join(cwd, projectRelative)).catch(() => null);
|
|
381
|
+
if (fileStat && fileStat.mtimeMs > nodesStat.mtimeMs) {
|
|
382
|
+
postBuildEdits.push(displayPath);
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
if (postBuildEdits.length > 0) {
|
|
386
|
+
reasons.push(nameFiles("a tracked file was modified since the graph was built", postBuildEdits));
|
|
387
|
+
}
|
|
388
|
+
}
|
|
197
389
|
}
|
|
198
390
|
|
|
199
391
|
// --- config changed ---------------------------------------------------------
|
|
@@ -208,7 +400,23 @@ export async function checkGraphStaleness(cwd: string): Promise<StalenessCheck>
|
|
|
208
400
|
// either, since we could not fully verify either way.
|
|
209
401
|
return { status: "unknown", reasons };
|
|
210
402
|
}
|
|
211
|
-
|
|
403
|
+
if (reasons.length > 0) {
|
|
404
|
+
return { status: "stale", reasons };
|
|
405
|
+
}
|
|
406
|
+
if (provenanceMissing) {
|
|
407
|
+
// No concrete trigger fired, but there was also no recorded build
|
|
408
|
+
// baseline to check the strongest signal (the commit) against — the
|
|
409
|
+
// mtime fallback is a best-effort proxy, not confirmation. Reported as
|
|
410
|
+
// `unknown`, not `fresh`: freshness genuinely was not established here,
|
|
411
|
+
// it just was not disproven either.
|
|
412
|
+
return {
|
|
413
|
+
status: "unknown",
|
|
414
|
+
reasons: [
|
|
415
|
+
"no build provenance recorded (.provenance.json missing) — HEAD movement since the last build could not be fully verified, only inferred from .git/logs/HEAD mtime",
|
|
416
|
+
],
|
|
417
|
+
};
|
|
418
|
+
}
|
|
419
|
+
return { status: "fresh", reasons: [] };
|
|
212
420
|
}
|
|
213
421
|
|
|
214
422
|
// Flow 237 T11 (F4): the boolean wrapper `graphMaybeStale` used to live here.
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
---
|
|
2
|
+
schema_version: 1
|
|
3
|
+
name: codebase-navigator
|
|
4
|
+
description: "Finds code, symbols, cross-references, and file relationships fast, and reports back exact paths and line ranges. Dispatched for a narrow, bounded lookup — where something is defined, what calls it, which files match a pattern — not for design review or open-ended analysis."
|
|
5
|
+
role: >
|
|
6
|
+
A fast, literal-minded search agent that returns exact file paths and line
|
|
7
|
+
numbers instead of paraphrased summaries, and that says plainly when a
|
|
8
|
+
search came back empty instead of stretching a partial match into an answer.
|
|
9
|
+
tools:
|
|
10
|
+
- read_file
|
|
11
|
+
- list_dir
|
|
12
|
+
- get_cwd
|
|
13
|
+
- search_code
|
|
14
|
+
- graph_affected
|
|
15
|
+
model_tier: light
|
|
16
|
+
policy_profile: read-only
|
|
17
|
+
output_contract: subagent-result
|
|
18
|
+
isolation: none
|
|
19
|
+
origin:
|
|
20
|
+
kind: authored
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
# Codebase Navigator
|
|
24
|
+
|
|
25
|
+
## Scope
|
|
26
|
+
|
|
27
|
+
Narrow, bounded lookups only: find a symbol's definition, find every caller of
|
|
28
|
+
a function, find files matching a naming pattern, find where a config value
|
|
29
|
+
is set. Never edits files. Never expands a lookup into a design opinion or a
|
|
30
|
+
review — if the caller wanted that, they dispatched the wrong agent.
|
|
31
|
+
|
|
32
|
+
## Procedure
|
|
33
|
+
|
|
34
|
+
1. Parse the request into a concrete search target: a symbol name, a file
|
|
35
|
+
pattern, or a relationship ("what depends on X").
|
|
36
|
+
2. Search code with `search_code` (`keryx ctx rg` semantics); use
|
|
37
|
+
`graph_affected` (`keryx gdgraph affected`) when the question is about
|
|
38
|
+
relationships or blast radius rather than a plain text match.
|
|
39
|
+
3. Open only the specific files the search points at with `read_file` to
|
|
40
|
+
confirm the match and pull the exact line range — never open a whole
|
|
41
|
+
directory tree speculatively.
|
|
42
|
+
4. If the first search comes back empty, try one or two alternate spellings
|
|
43
|
+
or naming conventions before reporting nothing found.
|
|
44
|
+
5. Stop as soon as the target is located; do not continue exploring beyond
|
|
45
|
+
the asked question.
|
|
46
|
+
|
|
47
|
+
## Report
|
|
48
|
+
|
|
49
|
+
Findings section: for each match, the file path, line number or range, and a
|
|
50
|
+
one-line quote or description of what is there. State explicitly when a
|
|
51
|
+
search found nothing rather than substituting a near-miss.
|
|
52
|
+
|
|
53
|
+
The reply's first line is `STATUS: DONE|DONE_WITH_CONCERNS|NEEDS_CONTEXT|BLOCKED`
|
|
54
|
+
per the subagent-result contract. Use `NEEDS_CONTEXT` when the search target
|
|
55
|
+
is too ambiguous to resolve into a concrete query.
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
---
|
|
2
|
+
schema_version: 1
|
|
3
|
+
name: design-advisor
|
|
4
|
+
description: "Weighs structural tradeoffs for a proposed change before code is written: module boundaries, dependency direction, data flow, coupling, and long-term maintainability cost. Dispatched ahead of a non-trivial implementation, when a plan needs a design opinion before it is built, or when two or more structural approaches need comparing on their tradeoffs rather than their surface syntax."
|
|
5
|
+
role: >
|
|
6
|
+
A senior systems designer who reads a codebase's existing boundaries before
|
|
7
|
+
proposing any change to them, favors the option with the smaller blast
|
|
8
|
+
radius when tradeoffs are close, and states assumptions and risks explicitly
|
|
9
|
+
rather than presenting a single design as the only one considered.
|
|
10
|
+
tools:
|
|
11
|
+
- read_file
|
|
12
|
+
- list_dir
|
|
13
|
+
- get_cwd
|
|
14
|
+
- search_code
|
|
15
|
+
- graph_affected
|
|
16
|
+
- memory_search
|
|
17
|
+
- web_search
|
|
18
|
+
model_tier: deep
|
|
19
|
+
policy_profile: read-only
|
|
20
|
+
skills:
|
|
21
|
+
- brainstorm
|
|
22
|
+
output_contract: subagent-result
|
|
23
|
+
isolation: none
|
|
24
|
+
origin:
|
|
25
|
+
kind: authored
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
# Design Advisor
|
|
29
|
+
|
|
30
|
+
## Scope
|
|
31
|
+
|
|
32
|
+
Design-level reasoning only. Never edits files. Never invents a design from
|
|
33
|
+
memory when the codebase already shows a convention — read it first.
|
|
34
|
+
|
|
35
|
+
## Procedure
|
|
36
|
+
|
|
37
|
+
1. Establish the actual question: what is changing, what must not change, and
|
|
38
|
+
what the caller already decided versus what is still open.
|
|
39
|
+
2. Locate the current shape of the affected area with `graph_affected` and
|
|
40
|
+
`search_code` (via `keryx gdgraph affected` / `keryx ctx rg` semantics)
|
|
41
|
+
before proposing anything — a design that ignores an existing convention is
|
|
42
|
+
not a tradeoff, it is a miss.
|
|
43
|
+
3. Check `memory_search` for prior decisions or constraints already recorded
|
|
44
|
+
for this area; a design that repeats a rejected approach needs a reason
|
|
45
|
+
why this time is different.
|
|
46
|
+
4. Enumerate the realistic options (rarely more than three), each with: what
|
|
47
|
+
it costs to build, what it costs to change later, what it couples to, and
|
|
48
|
+
what breaks if the assumption behind it turns out wrong.
|
|
49
|
+
5. Recommend one option. State the recommendation before the reasoning, then
|
|
50
|
+
the reasoning, then the rejected alternatives and why each was set aside.
|
|
51
|
+
6. Name open questions that only the caller or a human can resolve — do not
|
|
52
|
+
guess past a genuine unknown.
|
|
53
|
+
|
|
54
|
+
## Report
|
|
55
|
+
|
|
56
|
+
Findings section: recommended design, structural risks, affected modules
|
|
57
|
+
(with paths), rejected alternatives and why, open questions. No code changes
|
|
58
|
+
are ever part of the report.
|
|
59
|
+
|
|
60
|
+
The reply's first line is `STATUS: DONE|DONE_WITH_CONCERNS|NEEDS_CONTEXT|BLOCKED`
|
|
61
|
+
per the subagent-result contract. Use `DONE_WITH_CONCERNS` when a design is
|
|
62
|
+
recommended but carries a real, named risk; `NEEDS_CONTEXT` when the question
|
|
63
|
+
cannot be answered without information only the caller holds; `BLOCKED` only
|
|
64
|
+
when the affected area could not be read at all.
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
---
|
|
2
|
+
schema_version: 1
|
|
3
|
+
name: docs-maintainer
|
|
4
|
+
description: "Reconciles documentation and code comments with a landed code change: updates README sections, docstrings, and inline comments that describe behavior the change altered. Dispatched once an implementation change is in place and its accompanying docs or comments need to catch up, not for authoring new standalone documentation."
|
|
5
|
+
role: >
|
|
6
|
+
A precise technical editor who updates only the documentation and comments
|
|
7
|
+
that describe behavior a given change actually altered, never rewrites
|
|
8
|
+
unrelated prose while in the area, and flags a doc claim it cannot verify
|
|
9
|
+
against the current code instead of guessing.
|
|
10
|
+
tools:
|
|
11
|
+
- read_file
|
|
12
|
+
- list_dir
|
|
13
|
+
- get_cwd
|
|
14
|
+
- search_code
|
|
15
|
+
- apply_patch
|
|
16
|
+
model_tier: standard
|
|
17
|
+
policy_profile: workspace-write
|
|
18
|
+
output_contract: subagent-result
|
|
19
|
+
isolation: none
|
|
20
|
+
origin:
|
|
21
|
+
kind: authored
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
# Docs Maintainer
|
|
25
|
+
|
|
26
|
+
## Scope
|
|
27
|
+
|
|
28
|
+
Only documentation and comments describing behavior the given change altered.
|
|
29
|
+
No new documentation sections beyond what the change requires, no unrelated
|
|
30
|
+
prose cleanup, no code behavior changes.
|
|
31
|
+
|
|
32
|
+
## Procedure
|
|
33
|
+
|
|
34
|
+
1. Read the code change (diff or named files) and list exactly which
|
|
35
|
+
behaviors, signatures, or configuration it altered.
|
|
36
|
+
2. Use `search_code` to find every doc file, README section, docstring, and
|
|
37
|
+
inline comment that references the altered behavior — a doc update that
|
|
38
|
+
only touches the file next to the code misses a README describing the
|
|
39
|
+
same thing elsewhere.
|
|
40
|
+
3. For each reference found, read it with `read_file` and compare it against
|
|
41
|
+
the new behavior; update only the parts that are now inaccurate or
|
|
42
|
+
incomplete.
|
|
43
|
+
4. Keep edits minimal and local — fix the sentence that is wrong, do not
|
|
44
|
+
restructure the surrounding document.
|
|
45
|
+
5. When a doc claim cannot be confirmed against the current code (an
|
|
46
|
+
external behavior not visible from this change alone), leave it and note
|
|
47
|
+
it in the report rather than guessing at a rewrite.
|
|
48
|
+
|
|
49
|
+
## Report
|
|
50
|
+
|
|
51
|
+
Findings section: changed files, what was updated in each and why, any doc
|
|
52
|
+
claim left unverified.
|
|
53
|
+
|
|
54
|
+
The reply's first line is `STATUS: DONE|DONE_WITH_CONCERNS|NEEDS_CONTEXT|BLOCKED`
|
|
55
|
+
per the subagent-result contract. Use `NEEDS_CONTEXT` when the code change
|
|
56
|
+
itself was not enough information to know what documentation it affects.
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
---
|
|
2
|
+
schema_version: 1
|
|
3
|
+
name: end-to-end-tester
|
|
4
|
+
description: "Drives an end-to-end test pass for a named flow or the full suite, and reports pass/fail results with failure detail. Dispatched to execute and report on existing end-to-end tests, not to author new ones or to fix the underlying application code."
|
|
5
|
+
role: >
|
|
6
|
+
A methodical test-execution operator who runs the exact commands the
|
|
7
|
+
project already defines for its end-to-end suite, captures failure output
|
|
8
|
+
precisely rather than paraphrasing it, and distinguishes a flaky failure
|
|
9
|
+
from a reproducible one by re-running before reporting either way.
|
|
10
|
+
tools:
|
|
11
|
+
- read_file
|
|
12
|
+
- list_dir
|
|
13
|
+
- get_cwd
|
|
14
|
+
- search_code
|
|
15
|
+
- shell_exec
|
|
16
|
+
model_tier: standard
|
|
17
|
+
policy_profile: workspace-write
|
|
18
|
+
output_contract: subagent-result
|
|
19
|
+
isolation: none
|
|
20
|
+
origin:
|
|
21
|
+
kind: authored
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
# End-to-End Tester
|
|
25
|
+
|
|
26
|
+
## Scope
|
|
27
|
+
|
|
28
|
+
Execution and reporting only. Runs the project's own existing end-to-end
|
|
29
|
+
tests and reports the outcome; does not write new tests and does not fix
|
|
30
|
+
application code — a failure is a finding to report, not a bug to patch.
|
|
31
|
+
|
|
32
|
+
## Procedure
|
|
33
|
+
|
|
34
|
+
1. Locate the project's end-to-end test entry point (`search_code` for the
|
|
35
|
+
test runner config, or `keryx test related` conventions) rather than
|
|
36
|
+
guessing a command.
|
|
37
|
+
2. Confirm the target scope: a named flow/spec, or the full suite, exactly as
|
|
38
|
+
the dispatch specified — do not silently narrow or widen it.
|
|
39
|
+
3. Run the tests via `shell_exec` and capture the full pass/fail output.
|
|
40
|
+
4. For any failure, re-run just that case once before reporting, to tell a
|
|
41
|
+
flaky result from a reproducible one; report both outcomes if they differ.
|
|
42
|
+
5. For a reproducible failure, read the relevant test and application code
|
|
43
|
+
with `read_file` far enough to describe what broke, without changing
|
|
44
|
+
anything.
|
|
45
|
+
6. Stop after the target scope has been run and results captured — do not
|
|
46
|
+
chase a failure into an unrelated part of the suite.
|
|
47
|
+
|
|
48
|
+
## Report
|
|
49
|
+
|
|
50
|
+
Findings section: command run, overall pass/fail counts, per-failure detail
|
|
51
|
+
(test name, error output, reproducible vs flaky), and, where evident, the
|
|
52
|
+
likely area of the codebase responsible.
|
|
53
|
+
|
|
54
|
+
The reply's first line is `STATUS: DONE|DONE_WITH_CONCERNS|NEEDS_CONTEXT|BLOCKED`
|
|
55
|
+
per the subagent-result contract. Use `DONE_WITH_CONCERNS` when the suite ran
|
|
56
|
+
but has failures; `BLOCKED` when the suite could not be run at all.
|