ctxr-cli 0.4.0 → 0.5.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/dist/adapters/harness/claude-code.d.ts +0 -6
- package/dist/adapters/harness/claude-code.d.ts.map +1 -1
- package/dist/adapters/harness/claude-code.js +44 -25
- package/dist/adapters/harness/claude-code.js.map +1 -1
- package/dist/adapters/types.d.ts +28 -9
- package/dist/adapters/types.d.ts.map +1 -1
- package/dist/commands/adapters-generate.d.ts.map +1 -1
- package/dist/commands/adapters-generate.js +15 -3
- package/dist/commands/adapters-generate.js.map +1 -1
- package/dist/commands/adapters-write-gate.d.ts +20 -0
- package/dist/commands/adapters-write-gate.d.ts.map +1 -0
- package/dist/commands/adapters-write-gate.js +77 -0
- package/dist/commands/adapters-write-gate.js.map +1 -0
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +57 -9
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/rollup-write.d.ts.map +1 -1
- package/dist/commands/rollup-write.js +8 -0
- package/dist/commands/rollup-write.js.map +1 -1
- package/dist/commands/session-land.d.ts.map +1 -1
- package/dist/commands/session-land.js +55 -24
- package/dist/commands/session-land.js.map +1 -1
- package/dist/commands/verify.d.ts +9 -2
- package/dist/commands/verify.d.ts.map +1 -1
- package/dist/commands/verify.js +50 -27
- package/dist/commands/verify.js.map +1 -1
- package/dist/config/defaults.d.ts +20 -4
- package/dist/config/defaults.d.ts.map +1 -1
- package/dist/config/defaults.js +20 -4
- package/dist/config/defaults.js.map +1 -1
- package/dist/config/schema.d.ts +29 -5
- package/dist/config/schema.d.ts.map +1 -1
- package/dist/config/schema.js +73 -5
- package/dist/config/schema.js.map +1 -1
- package/dist/core/agents-doc.d.ts +71 -16
- package/dist/core/agents-doc.d.ts.map +1 -1
- package/dist/core/agents-doc.js +220 -139
- package/dist/core/agents-doc.js.map +1 -1
- package/dist/core/checks/harness-portability-checks.d.ts +12 -0
- package/dist/core/checks/harness-portability-checks.d.ts.map +1 -0
- package/dist/core/checks/harness-portability-checks.js +39 -0
- package/dist/core/checks/harness-portability-checks.js.map +1 -0
- package/dist/core/checks/integrity-checks.d.ts +25 -1
- package/dist/core/checks/integrity-checks.d.ts.map +1 -1
- package/dist/core/checks/integrity-checks.js +136 -3
- package/dist/core/checks/integrity-checks.js.map +1 -1
- package/dist/core/checks/manifest.d.ts.map +1 -1
- package/dist/core/checks/manifest.js +2 -0
- package/dist/core/checks/manifest.js.map +1 -1
- package/dist/core/checks/organize-checks.d.ts +12 -0
- package/dist/core/checks/organize-checks.d.ts.map +1 -1
- package/dist/core/checks/organize-checks.js +51 -1
- package/dist/core/checks/organize-checks.js.map +1 -1
- package/dist/core/convention-doc.d.ts +33 -0
- package/dist/core/convention-doc.d.ts.map +1 -0
- package/dist/core/convention-doc.js +110 -0
- package/dist/core/convention-doc.js.map +1 -0
- package/dist/core/conventions.d.ts +25 -5
- package/dist/core/conventions.d.ts.map +1 -1
- package/dist/core/conventions.js +65 -3
- package/dist/core/conventions.js.map +1 -1
- package/dist/core/errors.d.ts.map +1 -1
- package/dist/core/errors.js +2 -1
- package/dist/core/errors.js.map +1 -1
- package/dist/core/fs/fenced-region.d.ts +38 -0
- package/dist/core/fs/fenced-region.d.ts.map +1 -1
- package/dist/core/fs/fenced-region.js +88 -2
- package/dist/core/fs/fenced-region.js.map +1 -1
- package/dist/core/git/repo.d.ts +10 -0
- package/dist/core/git/repo.d.ts.map +1 -1
- package/dist/core/git/repo.js +28 -0
- package/dist/core/git/repo.js.map +1 -1
- package/dist/core/git/worktree.d.ts +8 -0
- package/dist/core/git/worktree.d.ts.map +1 -1
- package/dist/core/git/worktree.js +11 -0
- package/dist/core/git/worktree.js.map +1 -1
- package/dist/core/hooks.d.ts +10 -0
- package/dist/core/hooks.d.ts.map +1 -1
- package/dist/core/hooks.js +37 -10
- package/dist/core/hooks.js.map +1 -1
- package/dist/core/json-config-merge.d.ts +26 -2
- package/dist/core/json-config-merge.d.ts.map +1 -1
- package/dist/core/json-config-merge.js +61 -7
- package/dist/core/json-config-merge.js.map +1 -1
- package/dist/core/migrations/registry.d.ts.map +1 -1
- package/dist/core/migrations/registry.js +7 -1
- package/dist/core/migrations/registry.js.map +1 -1
- package/dist/core/migrations/rename-conventions-path.d.ts +26 -0
- package/dist/core/migrations/rename-conventions-path.d.ts.map +1 -0
- package/dist/core/migrations/rename-conventions-path.js +86 -0
- package/dist/core/migrations/rename-conventions-path.js.map +1 -0
- package/dist/core/migrations/rename-procedures-path.d.ts +17 -0
- package/dist/core/migrations/rename-procedures-path.d.ts.map +1 -0
- package/dist/core/migrations/rename-procedures-path.js +45 -0
- package/dist/core/migrations/rename-procedures-path.js.map +1 -0
- package/dist/core/notes/list.js +5 -5
- package/dist/core/notes/list.js.map +1 -1
- package/dist/core/reconcile.d.ts.map +1 -1
- package/dist/core/reconcile.js +32 -5
- package/dist/core/reconcile.js.map +1 -1
- package/dist/core/rollup.d.ts +2 -2
- package/dist/core/rollup.d.ts.map +1 -1
- package/dist/core/rollup.js +24 -3
- package/dist/core/rollup.js.map +1 -1
- package/dist/core/{procedures.d.ts → skills.d.ts} +12 -12
- package/dist/core/skills.d.ts.map +1 -0
- package/dist/core/{procedures.js → skills.js} +25 -41
- package/dist/core/skills.js.map +1 -0
- package/dist/core/templates.d.ts +20 -0
- package/dist/core/templates.d.ts.map +1 -0
- package/dist/core/templates.js +68 -0
- package/dist/core/templates.js.map +1 -0
- package/dist/core/write-lifecycle/path-gate.d.ts +28 -0
- package/dist/core/write-lifecycle/path-gate.d.ts.map +1 -1
- package/dist/core/write-lifecycle/path-gate.js +78 -22
- package/dist/core/write-lifecycle/path-gate.js.map +1 -1
- package/dist/run.d.ts.map +1 -1
- package/dist/run.js +12 -1
- package/dist/run.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
- package/templates/agents/canonical.md +20 -0
- package/templates/agents/capture-and-ingest.md +17 -0
- package/templates/agents/conventions.md +5 -0
- package/templates/agents/mission.md +5 -0
- package/templates/agents/placement-no-layers.md +5 -0
- package/templates/agents/placement.md +7 -0
- package/templates/agents/retrieval-leg-routing.md +14 -0
- package/templates/conventions/baseline-convention.md +60 -0
- package/templates/conventions/custom-convention-seed.md +21 -0
- package/templates/hooks/claude-code-write-gate.sh +15 -0
- package/templates/skills/ctxr-connection-finding.md +1 -1
- package/templates/skills/ctxr-ingest-orchestration.md +1 -1
- package/templates/skills/ctxr-land.md +11 -6
- package/dist/core/procedures.d.ts.map +0 -1
- package/dist/core/procedures.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/config/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;;GAIG;AACH
|
|
1
|
+
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/config/schema.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import type { StoreConfig } from '../config/schema.js';
|
|
2
2
|
import { type ScannedDoc } from './conventions.js';
|
|
3
|
+
export declare function agentsMdPath(root: string): string;
|
|
3
4
|
/**
|
|
4
5
|
* context-retrieval spec (task 4.5): the leg-routing rule that tells an
|
|
5
6
|
* agent which of its two retrieval legs to use for a given question — the
|
|
6
7
|
* catalog/graph (contexture-built-and-maintained) or its own direct content
|
|
7
8
|
* matching (grep, scoped by the store's declared exclusion paths). This is
|
|
8
9
|
* one fenced region within AGENTS.md; Phase 8 adds the canonical template's
|
|
9
|
-
* other sections (root-resolution, frontmatter schema, write-path,
|
|
10
|
+
* other sections (root-resolution, frontmatter schema, write-path, skill
|
|
10
11
|
* index) as sibling regions in the same file, never touching this one.
|
|
11
12
|
*/
|
|
12
13
|
export declare const AGENTS_MD_LEG_ROUTING_FENCE: import("./markers.js").Fence;
|
|
13
|
-
export declare function agentsMdPath(root: string): string;
|
|
14
14
|
export declare function renderLegRoutingSection(config: StoreConfig): string[];
|
|
15
15
|
/** Idempotently reconciles AGENTS.md's leg-routing section from current config — called at init and on re-init. */
|
|
16
16
|
export declare function buildAgentsLegRoutingSection(root: string, config: StoreConfig): Promise<{
|
|
@@ -30,12 +30,14 @@ export declare function buildAgentsCaptureSection(root: string, config: StoreCon
|
|
|
30
30
|
changed: boolean;
|
|
31
31
|
}>;
|
|
32
32
|
/**
|
|
33
|
-
* context-organize spec (task 7.1): the placement
|
|
34
|
-
*
|
|
35
|
-
* hardcoded layout —
|
|
33
|
+
* context-organize spec (task 7.1): the placement skill's documentation is
|
|
34
|
+
* driven entirely by the configured taxonomy, never a
|
|
35
|
+
* hardcoded layout — the layer list is generated purely from
|
|
36
36
|
* `config.taxonomy.layers`, so it reads correctly under PARA, Zettelkasten,
|
|
37
37
|
* Diátaxis, or any custom taxonomy without a single layer name appearing in
|
|
38
|
-
* this file's own source.
|
|
38
|
+
* this file's own source. A store with no declared layers gets its own
|
|
39
|
+
* template rather than a swapped-out middle, so both variants read as
|
|
40
|
+
* complete documents.
|
|
39
41
|
*/
|
|
40
42
|
export declare const AGENTS_MD_PLACEMENT_FENCE: import("./markers.js").Fence;
|
|
41
43
|
export declare function renderPlacementSection(config: StoreConfig): string[];
|
|
@@ -43,26 +45,79 @@ export declare function buildAgentsPlacementSection(root: string, config: StoreC
|
|
|
43
45
|
changed: boolean;
|
|
44
46
|
}>;
|
|
45
47
|
/**
|
|
46
|
-
* harness-portability spec (
|
|
47
|
-
* required pieces — root-resolution rule, frontmatter schema
|
|
48
|
-
* write-path rule, and
|
|
49
|
-
* this file, with no harness-specific context, has
|
|
50
|
-
* (the spec's own "Reading only AGENTS.md is
|
|
48
|
+
* harness-portability spec (inline-conventions-and-mission): the canonical
|
|
49
|
+
* template's required pieces — root-resolution rule, frontmatter schema
|
|
50
|
+
* pointer, write-path rule, and the harness/store identity boundary — so an
|
|
51
|
+
* agent that has read only this file, with no harness-specific context, has
|
|
52
|
+
* everything it needs (the spec's own "Reading only AGENTS.md is
|
|
53
|
+
* sufficient" scenario). The skill index this section used to carry is gone
|
|
54
|
+
* (see the REMOVED "The skill index reflects the files on disk" requirement)
|
|
55
|
+
* — on a harness with native skill auto-discovery it duplicated content
|
|
56
|
+
* already in context; a harness without one still reaches every skill by
|
|
57
|
+
* path at the configured skills path.
|
|
51
58
|
*/
|
|
52
59
|
export declare const AGENTS_MD_CANONICAL_FENCE: import("./markers.js").Fence;
|
|
53
|
-
export declare function renderCanonicalSection(config: StoreConfig
|
|
60
|
+
export declare function renderCanonicalSection(config: StoreConfig): string[];
|
|
54
61
|
export declare function buildAgentsCanonicalSection(root: string, config: StoreConfig): Promise<{
|
|
55
62
|
changed: boolean;
|
|
56
63
|
}>;
|
|
57
64
|
/**
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
*
|
|
61
|
-
*
|
|
65
|
+
* inline-conventions-and-mission: the store's current mission, inlined as
|
|
66
|
+
* its own fenced section — replacing the pointer-only rendering this used to
|
|
67
|
+
* get. `missionRaw` is the mission note's raw file content, read by the
|
|
68
|
+
* caller (`buildAgentsMissionSection`) so this stays a pure, synchronous
|
|
69
|
+
* renderer like every other section in this file; `null` means unconfigured
|
|
70
|
+
* or the note doesn't exist, either of which renders nothing at all.
|
|
71
|
+
*/
|
|
72
|
+
export declare const AGENTS_MD_MISSION_FENCE: import("./markers.js").Fence;
|
|
73
|
+
export declare function renderMissionSection(config: StoreConfig, missionRaw: string | null): string[];
|
|
74
|
+
export declare function buildAgentsMissionSection(root: string, config: StoreConfig): Promise<{
|
|
75
|
+
changed: boolean;
|
|
76
|
+
}>;
|
|
77
|
+
/**
|
|
78
|
+
* harness-portability spec (inline-conventions-and-mission, folded into one
|
|
79
|
+
* template by compose-store-guidance-documents): operator conventions
|
|
80
|
+
* inlined in full. What's on disk at the configured conventions path is
|
|
81
|
+
* inlined body-and-all — heading-demoted under a heading naming its title,
|
|
82
|
+
* with a provenance line naming its source path — never referenced by a
|
|
83
|
+
* link alone; contexture ships no seeds here — conventions are
|
|
84
|
+
* definitionally operator-authored, so an empty store gets an explanation of
|
|
85
|
+
* the mechanism instead. One template (`conventions.md`) carries both: the
|
|
86
|
+
* empty-vs-populated difference is entirely in the lines `renderConventionsSection`
|
|
87
|
+
* computes for its one `__CONVENTION_BODY__` slot, so the surrounding frame
|
|
88
|
+
* (heading, harness-specific-note paragraph) exists in exactly one place and
|
|
89
|
+
* cannot drift between two copies the way it could when it shipped as two
|
|
90
|
+
* separate template files.
|
|
62
91
|
*/
|
|
63
92
|
export declare const AGENTS_MD_CONVENTIONS_FENCE: import("./markers.js").Fence;
|
|
93
|
+
/** Exported so doctor/verify can check a specific convention file's inlined block for drift without re-deriving the format. */
|
|
94
|
+
export declare function renderConventionBlock(doc: ScannedDoc): string[];
|
|
64
95
|
export declare function renderConventionsSection(config: StoreConfig, conventions: readonly ScannedDoc[]): string[];
|
|
65
96
|
export declare function buildAgentsConventionsSection(root: string, config: StoreConfig): Promise<{
|
|
66
97
|
changed: boolean;
|
|
67
98
|
}>;
|
|
99
|
+
/**
|
|
100
|
+
* harness-portability spec: "Generated sections render in a fixed order" —
|
|
101
|
+
* hard rules and current state first, operating mechanics next, the long
|
|
102
|
+
* operator reference last. `reconcileStore` passes this straight to
|
|
103
|
+
* `reorderFencedRegionsInFile`; a mission-less store simply never has the
|
|
104
|
+
* mission fence present, which the reorder primitive already treats as
|
|
105
|
+
* "skip it," not an error.
|
|
106
|
+
*/
|
|
107
|
+
export declare const AGENTS_MD_SECTION_ORDER: import("./markers.js").Fence[];
|
|
108
|
+
export interface AgentsMdDrift {
|
|
109
|
+
/** Store-relative paths of convention files whose inlined block no longer matches the source. */
|
|
110
|
+
driftedConventions: string[];
|
|
111
|
+
/** The configured mission path, when its inlined section no longer matches the source; null otherwise. */
|
|
112
|
+
driftedMission: string | null;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* harness-portability spec: "The entry document's inlined content matches
|
|
116
|
+
* its sources" — shared by `ctxr doctor` (reports every drifted file) and
|
|
117
|
+
* `ctxr verify --portable` (stops at the first one), per design.md's
|
|
118
|
+
* "Drift detection reuses render, not a hash": re-runs the same renderers
|
|
119
|
+
* `buildAgents*Section` uses and diffs against what is currently inside each
|
|
120
|
+
* fence, rather than storing a separate content hash anywhere.
|
|
121
|
+
*/
|
|
122
|
+
export declare function checkAgentsMdDrift(root: string, config: StoreConfig): Promise<AgentsMdDrift>;
|
|
68
123
|
//# sourceMappingURL=agents-doc.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agents-doc.d.ts","sourceRoot":"","sources":["../../src/core/agents-doc.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"agents-doc.d.ts","sourceRoot":"","sources":["../../src/core/agents-doc.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAIvD,OAAO,EAAsD,KAAK,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAgBvG,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEjD;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,2BAA2B,8BAA4C,CAAC;AAgCrF,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,EAAE,CAOrE;AAED,mHAAmH;AACnH,wBAAsB,4BAA4B,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAA;CAAE,CAAC,CAEnH;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,uBAAuB,8BAAyC,CAAC;AAE9E,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,EAAE,CAElE;AAED,wBAAsB,yBAAyB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAA;CAAE,CAAC,CAEhH;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,yBAAyB,8BAAgC,CAAC;AAEvE,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,EAAE,CAapE;AAED,wBAAsB,2BAA2B,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAA;CAAE,CAAC,CAElH;AAED;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,yBAAyB,8BAAgC,CAAC;AAuBvE,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,EAAE,CAUpE;AAED,wBAAsB,2BAA2B,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAA;CAAE,CAAC,CAElH;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,uBAAuB,8BAA8B,CAAC;AAEnE,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,EAAE,CAS7F;AAED,wBAAsB,yBAAyB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAA;CAAE,CAAC,CAoBhH;AAED;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,2BAA2B,8BAAkC,CAAC;AAE3E,+HAA+H;AAC/H,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,UAAU,GAAG,MAAM,EAAE,CAE/D;AAeD,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,WAAW,EAAE,WAAW,EAAE,SAAS,UAAU,EAAE,GAAG,MAAM,EAAE,CAE1G;AAED,wBAAsB,6BAA6B,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAA;CAAE,CAAC,CAGpH;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,uBAAuB,gCAOnC,CAAC;AAEF,MAAM,WAAW,aAAa;IAC5B,iGAAiG;IACjG,kBAAkB,EAAE,MAAM,EAAE,CAAC;IAC7B,0GAA0G;IAC1G,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B;AAED;;;;;;;GAOG;AACH,wBAAsB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,aAAa,CAAC,CAoClG"}
|
package/dist/core/agents-doc.js
CHANGED
|
@@ -1,42 +1,67 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
1
2
|
import path from 'node:path';
|
|
2
3
|
import { GRAPH_DOCUMENT_RELATIVE_PATH } from './graph/persist.js';
|
|
3
4
|
import { CONFIG_FILE_NAME } from './root.js';
|
|
4
5
|
import { excludedPrefixesFor } from './notes/list.js';
|
|
5
|
-
import { scanConventions } from './conventions.js';
|
|
6
|
-
import {
|
|
7
|
-
import { upsertFencedRegionInFile } from './fs/fenced-region.js';
|
|
6
|
+
import { extractDocMetadata, inlineDocBody, scanConventions } from './conventions.js';
|
|
7
|
+
import { readFencedRegionFromFile, removeFencedRegionFromFile, upsertFencedRegionInFile } from './fs/fenced-region.js';
|
|
8
8
|
import { htmlCommentFence } from './markers.js';
|
|
9
|
+
import { packagedTemplate, substituteBlock } from './templates.js';
|
|
10
|
+
/**
|
|
11
|
+
* extract-agents-doc-templates: each generated AGENTS.md section's prose
|
|
12
|
+
* lives in `templates/agents/<fence-slug>.md`, named for the fence it lands
|
|
13
|
+
* in, so the file a reviewer opens and the region it writes share a name.
|
|
14
|
+
* Only genuinely per-store data — the exclusion list, the taxonomy layers,
|
|
15
|
+
* the scanned indexes — is computed here and substituted in.
|
|
16
|
+
*/
|
|
17
|
+
function agentsTemplate(name) {
|
|
18
|
+
return packagedTemplate('agents', name);
|
|
19
|
+
}
|
|
20
|
+
export function agentsMdPath(root) {
|
|
21
|
+
return path.join(root, 'AGENTS.md');
|
|
22
|
+
}
|
|
9
23
|
/**
|
|
10
24
|
* context-retrieval spec (task 4.5): the leg-routing rule that tells an
|
|
11
25
|
* agent which of its two retrieval legs to use for a given question — the
|
|
12
26
|
* catalog/graph (contexture-built-and-maintained) or its own direct content
|
|
13
27
|
* matching (grep, scoped by the store's declared exclusion paths). This is
|
|
14
28
|
* one fenced region within AGENTS.md; Phase 8 adds the canonical template's
|
|
15
|
-
* other sections (root-resolution, frontmatter schema, write-path,
|
|
29
|
+
* other sections (root-resolution, frontmatter schema, write-path, skill
|
|
16
30
|
* index) as sibling regions in the same file, never touching this one.
|
|
17
31
|
*/
|
|
18
32
|
export const AGENTS_MD_LEG_ROUTING_FENCE = htmlCommentFence('retrieval-leg-routing');
|
|
19
|
-
|
|
20
|
-
return
|
|
33
|
+
function trimTrailingSlash(prefix) {
|
|
34
|
+
return prefix.replace(/\/+$/, '');
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* inline-conventions-and-mission: `excludedPrefixesFor` deliberately includes
|
|
38
|
+
* both a parent path (e.g. `.contexture/`) and paths nested under it (e.g.
|
|
39
|
+
* `.contexture/cache/`) — each has its own reason to be there, and the note
|
|
40
|
+
* walker (`notes/list.ts`) needs the full, unfiltered set to skip directories
|
|
41
|
+
* early rather than descend and filter every file. Rendering that list
|
|
42
|
+
* verbatim produces a dozen-plus redundant bullets, so this collapses any
|
|
43
|
+
* prefix already covered by an ancestor prefix for display only — the
|
|
44
|
+
* exclusion logic itself is untouched.
|
|
45
|
+
*/
|
|
46
|
+
function collapseNestedPrefixes(prefixes) {
|
|
47
|
+
// Original (possibly trailing-slash) form preserved per trimmed key, since
|
|
48
|
+
// this list mixes directory prefixes and bare file exclusions (AGENTS.md,
|
|
49
|
+
// log.md) — the collapse test itself compares on the trimmed form only.
|
|
50
|
+
const originalByTrimmed = new Map();
|
|
51
|
+
for (const prefix of prefixes) {
|
|
52
|
+
const trimmed = trimTrailingSlash(prefix);
|
|
53
|
+
if (!originalByTrimmed.has(trimmed))
|
|
54
|
+
originalByTrimmed.set(trimmed, prefix);
|
|
55
|
+
}
|
|
56
|
+
const trimmed = [...originalByTrimmed.keys()];
|
|
57
|
+
return trimmed
|
|
58
|
+
.filter((path) => !trimmed.some((other) => other !== path && path.startsWith(`${other}/`)))
|
|
59
|
+
.sort()
|
|
60
|
+
.map((path) => originalByTrimmed.get(path));
|
|
21
61
|
}
|
|
22
62
|
export function renderLegRoutingSection(config) {
|
|
23
|
-
const exclusions =
|
|
24
|
-
return [
|
|
25
|
-
'## Retrieval: which leg to use',
|
|
26
|
-
'',
|
|
27
|
-
'contexture builds and maintains two retrieval tools ahead of time — consult them first:',
|
|
28
|
-
'',
|
|
29
|
-
'- **Catalog** (`ctxr catalog show --section <id>`): a curated, coverage-guaranteed index of every retrievable note, one section per taxonomy layer.',
|
|
30
|
-
'- **Graph** (`ctxr graph query ...`): the wikilink graph between notes — neighbors, shortest path, hubs, orphans, clusters, bridges; `--type <relation>` follows one configured relation.',
|
|
31
|
-
`- **Graph document** (\`${GRAPH_DOCUMENT_RELATIVE_PATH}\`, rebuilt by \`ctxr graph build\`): hub notes by cluster, cross-cluster bridges, and orphans — read it for cluster context before writing.`,
|
|
32
|
-
'',
|
|
33
|
-
'For a literal or entity question the catalog and graph do not answer (a specific string, an exact identifier, a phrase),',
|
|
34
|
-
'use your own direct content-matching tool (e.g. grep/ripgrep) against the store, scoped to exclude:',
|
|
35
|
-
'',
|
|
36
|
-
...exclusions.map((prefix) => `- \`${prefix}\``),
|
|
37
|
-
'',
|
|
38
|
-
'There is no `ctxr search` command. Ranked or semantic search is deferred to a future version — do not look for one.',
|
|
39
|
-
];
|
|
63
|
+
const exclusions = collapseNestedPrefixes(excludedPrefixesFor(config));
|
|
64
|
+
return substituteBlock(agentsTemplate('retrieval-leg-routing').replaceAll('__GRAPH_DOCUMENT_PATH__', GRAPH_DOCUMENT_RELATIVE_PATH), '__EXCLUSION_PATHS__', [exclusions.map((prefix) => `\`${prefix}\``).join(', ')]).split('\n');
|
|
40
65
|
}
|
|
41
66
|
/** Idempotently reconciles AGENTS.md's leg-routing section from current config — called at init and on re-init. */
|
|
42
67
|
export async function buildAgentsLegRoutingSection(root, config) {
|
|
@@ -52,81 +77,57 @@ export async function buildAgentsLegRoutingSection(root, config) {
|
|
|
52
77
|
*/
|
|
53
78
|
export const AGENTS_MD_CAPTURE_FENCE = htmlCommentFence('capture-and-ingest');
|
|
54
79
|
export function renderCaptureSection(config) {
|
|
55
|
-
return
|
|
56
|
-
'## Capturing and ingesting new material',
|
|
57
|
-
'',
|
|
58
|
-
`To capture something new, write a plain markdown file directly into \`${config.ingest.inbox_path}\` —`,
|
|
59
|
-
'no CLI command wraps this. That file MUST NOT contain any of these frontmatter fields; contexture assigns',
|
|
60
|
-
'them once, at ingest, and never before:',
|
|
61
|
-
'',
|
|
62
|
-
'- `source_type`',
|
|
63
|
-
'- `source_id`',
|
|
64
|
-
'- `source_hash`',
|
|
65
|
-
'- `ingested`',
|
|
66
|
-
'',
|
|
67
|
-
'Before ingesting, run `ctxr source check <path> --source-id <id>` to get one of four verdicts:',
|
|
68
|
-
'`new`, `already_ingested`, `alternate_source_match`, or `multiple_matches` — the last one means stop and',
|
|
69
|
-
'resolve the ambiguity yourself rather than guessing which existing note it is.',
|
|
70
|
-
'',
|
|
71
|
-
'To ingest, run `ctxr ingest <path> --source-type <type> --source-id <id>`. It stamps the four fields',
|
|
72
|
-
'above onto the file in place and rebuilds the catalog, so the result already has a catalog entry.',
|
|
73
|
-
];
|
|
80
|
+
return agentsTemplate('capture-and-ingest').replaceAll('__INBOX_PATH__', config.ingest.inbox_path).split('\n');
|
|
74
81
|
}
|
|
75
82
|
export async function buildAgentsCaptureSection(root, config) {
|
|
76
83
|
return upsertFencedRegionInFile(agentsMdPath(root), AGENTS_MD_CAPTURE_FENCE, renderCaptureSection(config));
|
|
77
84
|
}
|
|
78
85
|
/**
|
|
79
|
-
* context-organize spec (task 7.1): the placement
|
|
80
|
-
*
|
|
81
|
-
* hardcoded layout —
|
|
86
|
+
* context-organize spec (task 7.1): the placement skill's documentation is
|
|
87
|
+
* driven entirely by the configured taxonomy, never a
|
|
88
|
+
* hardcoded layout — the layer list is generated purely from
|
|
82
89
|
* `config.taxonomy.layers`, so it reads correctly under PARA, Zettelkasten,
|
|
83
90
|
* Diátaxis, or any custom taxonomy without a single layer name appearing in
|
|
84
|
-
* this file's own source.
|
|
91
|
+
* this file's own source. A store with no declared layers gets its own
|
|
92
|
+
* template rather than a swapped-out middle, so both variants read as
|
|
93
|
+
* complete documents.
|
|
85
94
|
*/
|
|
86
95
|
export const AGENTS_MD_PLACEMENT_FENCE = htmlCommentFence('placement');
|
|
87
96
|
export function renderPlacementSection(config) {
|
|
88
97
|
const { layers } = config.taxonomy;
|
|
89
|
-
if (layers.length === 0)
|
|
90
|
-
return
|
|
91
|
-
|
|
92
|
-
'',
|
|
93
|
-
'This store\'s taxonomy declares no top-level layers — place new notes directly at the store root (or',
|
|
94
|
-
'wherever related notes already live) and rely on wikilinks and `ctxr graph` for organization,',
|
|
95
|
-
'rather than a folder hierarchy.',
|
|
96
|
-
];
|
|
97
|
-
}
|
|
98
|
-
const lines = [
|
|
99
|
-
'## Placing a new note',
|
|
100
|
-
'',
|
|
101
|
-
'This store\'s taxonomy declares these layers — choose the one whose description best matches the note:',
|
|
102
|
-
'',
|
|
103
|
-
];
|
|
104
|
-
for (const layer of layers) {
|
|
98
|
+
if (layers.length === 0)
|
|
99
|
+
return agentsTemplate('placement-no-layers').split('\n');
|
|
100
|
+
const layerLines = layers.map((layer) => {
|
|
105
101
|
const directoryDefault = Object.entries(config.visibility.directory_defaults).find(([prefix]) => prefix === layer.path || prefix === `${layer.path}/`)?.[1];
|
|
106
|
-
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
return lines;
|
|
102
|
+
return `- **${layer.name}** (\`${layer.path}/\`): ${layer.description}${directoryDefault ? ` Notes here default to visibility "${directoryDefault}" unless given an explicit value.` : ''}`;
|
|
103
|
+
});
|
|
104
|
+
return substituteBlock(agentsTemplate('placement'), '__LAYER_LIST__', layerLines).split('\n');
|
|
110
105
|
}
|
|
111
106
|
export async function buildAgentsPlacementSection(root, config) {
|
|
112
107
|
return upsertFencedRegionInFile(agentsMdPath(root), AGENTS_MD_PLACEMENT_FENCE, renderPlacementSection(config));
|
|
113
108
|
}
|
|
114
109
|
/**
|
|
115
|
-
* harness-portability spec (
|
|
116
|
-
* required pieces — root-resolution rule, frontmatter schema
|
|
117
|
-
* write-path rule, and
|
|
118
|
-
* this file, with no harness-specific context, has
|
|
119
|
-
* (the spec's own "Reading only AGENTS.md is
|
|
110
|
+
* harness-portability spec (inline-conventions-and-mission): the canonical
|
|
111
|
+
* template's required pieces — root-resolution rule, frontmatter schema
|
|
112
|
+
* pointer, write-path rule, and the harness/store identity boundary — so an
|
|
113
|
+
* agent that has read only this file, with no harness-specific context, has
|
|
114
|
+
* everything it needs (the spec's own "Reading only AGENTS.md is
|
|
115
|
+
* sufficient" scenario). The skill index this section used to carry is gone
|
|
116
|
+
* (see the REMOVED "The skill index reflects the files on disk" requirement)
|
|
117
|
+
* — on a harness with native skill auto-discovery it duplicated content
|
|
118
|
+
* already in context; a harness without one still reaches every skill by
|
|
119
|
+
* path at the configured skills path.
|
|
120
120
|
*/
|
|
121
121
|
export const AGENTS_MD_CANONICAL_FENCE = htmlCommentFence('canonical');
|
|
122
122
|
/**
|
|
123
|
-
* context-organize spec
|
|
124
|
-
*
|
|
125
|
-
*
|
|
126
|
-
*
|
|
127
|
-
*
|
|
128
|
-
*
|
|
129
|
-
*
|
|
123
|
+
* context-organize spec, kept through inline-conventions-and-mission's
|
|
124
|
+
* design decision "the identity/mission pointer coexists with the inlined
|
|
125
|
+
* Mission section": when `organize.mission_path` is configured, the
|
|
126
|
+
* canonical section still names it as a document to load at session start,
|
|
127
|
+
* immediately followed (as its own fenced section — see
|
|
128
|
+
* `renderMissionSection` below) by that document's full inlined body.
|
|
129
|
+
* Nothing is rendered when unset: the `__MISSION_POINTER__` template line
|
|
130
|
+
* disappears entirely (via `substituteBlock`'s empty-list case), not a
|
|
130
131
|
* placeholder.
|
|
131
132
|
*/
|
|
132
133
|
function renderMissionPointer(config) {
|
|
@@ -136,79 +137,159 @@ function renderMissionPointer(config) {
|
|
|
136
137
|
return [
|
|
137
138
|
'',
|
|
138
139
|
`Load \`${missionPath}\` at the start of every session — this store's standing current-state document, ` +
|
|
139
|
-
'kept current by the mission skill
|
|
140
|
+
'kept current by the mission skill and written through `ctxr rollup write`; its full content follows in the "Mission" section below.',
|
|
140
141
|
];
|
|
141
142
|
}
|
|
142
|
-
export function renderCanonicalSection(config
|
|
143
|
-
|
|
144
|
-
'
|
|
145
|
-
'',
|
|
146
|
-
'
|
|
147
|
-
'',
|
|
148
|
-
`Every contexture command resolves the store root in this order: an explicit ` +
|
|
149
|
-
'`--root <path>` flag; the `CONTEXTURE_ROOT` environment variable; walking up from the current directory ' +
|
|
150
|
-
`looking for \`${CONFIG_FILE_NAME}\`. No other flag or environment variable selects the root.`,
|
|
151
|
-
'',
|
|
152
|
-
'### Frontmatter schema',
|
|
153
|
-
'',
|
|
154
|
-
`- Visibility field: \`${config.fields.visibility}:\` — resolves explicit value, then directory default, then the ` +
|
|
155
|
-
`configured fail-closed default (\`${config.visibility.default_context}\`). See \`ctxr note resolve <path>\`.`,
|
|
156
|
-
'- Source-identity fields (assigned only by `ctxr ingest`, never hand-written): `source_type`, `source_id`, `source_hash`, `ingested`.',
|
|
157
|
-
'- Disclosure audience tags (optional, hand-written): `audience: [<name>, ...]`.',
|
|
158
|
-
'',
|
|
159
|
-
'### Write path',
|
|
160
|
-
'',
|
|
161
|
-
'Every write to this store happens inside a session worktree, never directly on the default branch: `ctxr ' +
|
|
162
|
-
'session start` creates one, then `ctxr session submit` validates, commits, pushes, and opens (or ' +
|
|
163
|
-
'reports how to open) a pull request. Do not edit files in the store root directly.',
|
|
164
|
-
'',
|
|
165
|
-
'### Identity and memory',
|
|
166
|
-
'',
|
|
167
|
-
'Identity, persona, and durable cross-session memory for the agent working this store belong to its harness, ' +
|
|
168
|
-
'not to this store — the store holds knowledge and procedures, documented as portable markdown under ' +
|
|
169
|
-
`\`${config.harness.procedures_path}\` (see the procedure index below), never a persona or memory file of its own.`,
|
|
170
|
-
...renderMissionPointer(config),
|
|
171
|
-
'',
|
|
172
|
-
'### Procedure index',
|
|
173
|
-
'',
|
|
174
|
-
'Judgment-driven operations, documented as portable markdown under ' +
|
|
175
|
-
`\`${config.harness.procedures_path}\` — read one directly, no harness-specific discovery required:`,
|
|
176
|
-
'',
|
|
177
|
-
];
|
|
178
|
-
for (const procedure of procedures) {
|
|
179
|
-
lines.push(`- [${procedure.title}](${procedure.path})${procedure.description ? ` — ${procedure.description}` : ''}`);
|
|
180
|
-
}
|
|
181
|
-
return lines;
|
|
143
|
+
export function renderCanonicalSection(config) {
|
|
144
|
+
return substituteBlock(agentsTemplate('canonical')
|
|
145
|
+
.replaceAll('__CONFIG_FILE_NAME__', CONFIG_FILE_NAME)
|
|
146
|
+
.replaceAll('__VISIBILITY_FIELD__', config.fields.visibility)
|
|
147
|
+
.replaceAll('__DEFAULT_CONTEXT__', config.visibility.default_context)
|
|
148
|
+
.replaceAll('__SKILLS_PATH__', config.harness.skills_path), '__MISSION_POINTER__', renderMissionPointer(config)).split('\n');
|
|
182
149
|
}
|
|
183
150
|
export async function buildAgentsCanonicalSection(root, config) {
|
|
184
|
-
|
|
185
|
-
return upsertFencedRegionInFile(agentsMdPath(root), AGENTS_MD_CANONICAL_FENCE, renderCanonicalSection(config, procedures));
|
|
151
|
+
return upsertFencedRegionInFile(agentsMdPath(root), AGENTS_MD_CANONICAL_FENCE, renderCanonicalSection(config));
|
|
186
152
|
}
|
|
187
153
|
/**
|
|
188
|
-
*
|
|
189
|
-
*
|
|
190
|
-
*
|
|
191
|
-
*
|
|
154
|
+
* inline-conventions-and-mission: the store's current mission, inlined as
|
|
155
|
+
* its own fenced section — replacing the pointer-only rendering this used to
|
|
156
|
+
* get. `missionRaw` is the mission note's raw file content, read by the
|
|
157
|
+
* caller (`buildAgentsMissionSection`) so this stays a pure, synchronous
|
|
158
|
+
* renderer like every other section in this file; `null` means unconfigured
|
|
159
|
+
* or the note doesn't exist, either of which renders nothing at all.
|
|
192
160
|
*/
|
|
193
|
-
export const
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
const
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
161
|
+
export const AGENTS_MD_MISSION_FENCE = htmlCommentFence('mission');
|
|
162
|
+
export function renderMissionSection(config, missionRaw) {
|
|
163
|
+
const { mission_path: missionPath } = config.organize;
|
|
164
|
+
if (!missionPath || missionRaw === null)
|
|
165
|
+
return [];
|
|
166
|
+
const doc = extractDocMetadata(missionRaw, missionPath);
|
|
167
|
+
return substituteBlock(agentsTemplate('mission').replaceAll('__MISSION_PATH__', missionPath), '__MISSION_BODY__', inlineDocBody(doc, 1)).split('\n');
|
|
168
|
+
}
|
|
169
|
+
export async function buildAgentsMissionSection(root, config) {
|
|
170
|
+
const { mission_path: missionPath } = config.organize;
|
|
171
|
+
let missionRaw = null;
|
|
172
|
+
if (missionPath) {
|
|
173
|
+
try {
|
|
174
|
+
missionRaw = await readFile(path.join(root, missionPath), 'utf8');
|
|
175
|
+
}
|
|
176
|
+
catch (err) {
|
|
177
|
+
if (err.code !== 'ENOENT')
|
|
178
|
+
throw err;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
const body = renderMissionSection(config, missionRaw);
|
|
182
|
+
// `upsertFencedRegionInFile` appends a fence pair unconditionally when it's
|
|
183
|
+
// absent, even with an empty body — wrong here, where "unconfigured" must
|
|
184
|
+
// mean the section is absent entirely, never an empty fence pair. Removal
|
|
185
|
+
// is idempotent (a no-op when the fence isn't there), so this also cleans
|
|
186
|
+
// up correctly if a store had a mission configured and then unset it.
|
|
187
|
+
if (body.length === 0) {
|
|
188
|
+
return removeFencedRegionFromFile(agentsMdPath(root), AGENTS_MD_MISSION_FENCE);
|
|
202
189
|
}
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
190
|
+
return upsertFencedRegionInFile(agentsMdPath(root), AGENTS_MD_MISSION_FENCE, body);
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* harness-portability spec (inline-conventions-and-mission, folded into one
|
|
194
|
+
* template by compose-store-guidance-documents): operator conventions
|
|
195
|
+
* inlined in full. What's on disk at the configured conventions path is
|
|
196
|
+
* inlined body-and-all — heading-demoted under a heading naming its title,
|
|
197
|
+
* with a provenance line naming its source path — never referenced by a
|
|
198
|
+
* link alone; contexture ships no seeds here — conventions are
|
|
199
|
+
* definitionally operator-authored, so an empty store gets an explanation of
|
|
200
|
+
* the mechanism instead. One template (`conventions.md`) carries both: the
|
|
201
|
+
* empty-vs-populated difference is entirely in the lines `renderConventionsSection`
|
|
202
|
+
* computes for its one `__CONVENTION_BODY__` slot, so the surrounding frame
|
|
203
|
+
* (heading, harness-specific-note paragraph) exists in exactly one place and
|
|
204
|
+
* cannot drift between two copies the way it could when it shipped as two
|
|
205
|
+
* separate template files.
|
|
206
|
+
*/
|
|
207
|
+
export const AGENTS_MD_CONVENTIONS_FENCE = htmlCommentFence('conventions');
|
|
208
|
+
/** Exported so doctor/verify can check a specific convention file's inlined block for drift without re-deriving the format. */
|
|
209
|
+
export function renderConventionBlock(doc) {
|
|
210
|
+
return [`### ${doc.title}`, '', ...inlineDocBody(doc, 2), '', `_Source: ${doc.path}_`];
|
|
211
|
+
}
|
|
212
|
+
function conventionsBody(config, conventions) {
|
|
213
|
+
if (conventions.length === 0) {
|
|
214
|
+
return [
|
|
215
|
+
'This store declares no convention documents yet. Operator-authored conventions (content style, field',
|
|
216
|
+
`semantics, house rules) belong as markdown files under \`${config.harness.guidance_path}\` — each is`,
|
|
217
|
+
'inlined here in full on regeneration.',
|
|
218
|
+
];
|
|
206
219
|
}
|
|
207
|
-
|
|
208
|
-
|
|
220
|
+
const blocks = conventions.map(renderConventionBlock);
|
|
221
|
+
const bodies = blocks.flatMap((block, i) => (i === blocks.length - 1 ? block : [...block, '']));
|
|
222
|
+
return ['Operator-authored conventions for this store, inlined in full:', '', ...bodies];
|
|
223
|
+
}
|
|
224
|
+
export function renderConventionsSection(config, conventions) {
|
|
225
|
+
return substituteBlock(agentsTemplate('conventions'), '__CONVENTION_BODY__', conventionsBody(config, conventions)).split('\n');
|
|
209
226
|
}
|
|
210
227
|
export async function buildAgentsConventionsSection(root, config) {
|
|
211
228
|
const conventions = await scanConventions(root, config);
|
|
212
229
|
return upsertFencedRegionInFile(agentsMdPath(root), AGENTS_MD_CONVENTIONS_FENCE, renderConventionsSection(config, conventions));
|
|
213
230
|
}
|
|
231
|
+
/**
|
|
232
|
+
* harness-portability spec: "Generated sections render in a fixed order" —
|
|
233
|
+
* hard rules and current state first, operating mechanics next, the long
|
|
234
|
+
* operator reference last. `reconcileStore` passes this straight to
|
|
235
|
+
* `reorderFencedRegionsInFile`; a mission-less store simply never has the
|
|
236
|
+
* mission fence present, which the reorder primitive already treats as
|
|
237
|
+
* "skip it," not an error.
|
|
238
|
+
*/
|
|
239
|
+
export const AGENTS_MD_SECTION_ORDER = [
|
|
240
|
+
AGENTS_MD_CANONICAL_FENCE,
|
|
241
|
+
AGENTS_MD_MISSION_FENCE,
|
|
242
|
+
AGENTS_MD_LEG_ROUTING_FENCE,
|
|
243
|
+
AGENTS_MD_CAPTURE_FENCE,
|
|
244
|
+
AGENTS_MD_PLACEMENT_FENCE,
|
|
245
|
+
AGENTS_MD_CONVENTIONS_FENCE,
|
|
246
|
+
];
|
|
247
|
+
/**
|
|
248
|
+
* harness-portability spec: "The entry document's inlined content matches
|
|
249
|
+
* its sources" — shared by `ctxr doctor` (reports every drifted file) and
|
|
250
|
+
* `ctxr verify --portable` (stops at the first one), per design.md's
|
|
251
|
+
* "Drift detection reuses render, not a hash": re-runs the same renderers
|
|
252
|
+
* `buildAgents*Section` uses and diffs against what is currently inside each
|
|
253
|
+
* fence, rather than storing a separate content hash anywhere.
|
|
254
|
+
*/
|
|
255
|
+
export async function checkAgentsMdDrift(root, config) {
|
|
256
|
+
const filePath = agentsMdPath(root);
|
|
257
|
+
const conventions = await scanConventions(root, config);
|
|
258
|
+
const conventionsRegion = (await readFencedRegionFromFile(filePath, AGENTS_MD_CONVENTIONS_FENCE)).join('\n');
|
|
259
|
+
const freshConventionsSection = renderConventionsSection(config, conventions).join('\n');
|
|
260
|
+
const driftedConventions = [];
|
|
261
|
+
if (freshConventionsSection !== conventionsRegion) {
|
|
262
|
+
if (conventions.length === 0) {
|
|
263
|
+
driftedConventions.push(config.harness.guidance_path);
|
|
264
|
+
}
|
|
265
|
+
else {
|
|
266
|
+
for (const doc of conventions) {
|
|
267
|
+
if (!conventionsRegion.includes(renderConventionBlock(doc).join('\n')))
|
|
268
|
+
driftedConventions.push(doc.path);
|
|
269
|
+
}
|
|
270
|
+
// Every individual block present, yet the whole section still differs
|
|
271
|
+
// (a reordering, an added/removed file, a template change): still real
|
|
272
|
+
// drift, just not attributable to one file — report the whole set.
|
|
273
|
+
if (driftedConventions.length === 0)
|
|
274
|
+
driftedConventions.push(...conventions.map((doc) => doc.path));
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
let driftedMission = null;
|
|
278
|
+
const missionPath = config.organize.mission_path;
|
|
279
|
+
if (missionPath) {
|
|
280
|
+
let missionRaw = null;
|
|
281
|
+
try {
|
|
282
|
+
missionRaw = await readFile(path.join(root, missionPath), 'utf8');
|
|
283
|
+
}
|
|
284
|
+
catch (err) {
|
|
285
|
+
if (err.code !== 'ENOENT')
|
|
286
|
+
throw err;
|
|
287
|
+
}
|
|
288
|
+
const missionRegion = (await readFencedRegionFromFile(filePath, AGENTS_MD_MISSION_FENCE)).join('\n');
|
|
289
|
+
const freshMissionSection = renderMissionSection(config, missionRaw).join('\n');
|
|
290
|
+
if (freshMissionSection !== missionRegion)
|
|
291
|
+
driftedMission = missionPath;
|
|
292
|
+
}
|
|
293
|
+
return { driftedConventions, driftedMission };
|
|
294
|
+
}
|
|
214
295
|
//# sourceMappingURL=agents-doc.js.map
|