@event4u/agent-config 14.21.0 → 14.22.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/.augment-plugin/marketplace.json +3 -3
- package/.augment-plugin/plugin.json +1 -1
- package/.claude-plugin/marketplace.json +1 -1
- package/CHANGELOG.md +198 -0
- package/CREDITS.md +37 -0
- package/dist/agent-src/commands/analyze/inbox.md +380 -5
- package/dist/agent-src/commands/analyze/repo.md +4 -2
- package/dist/agent-src/contexts/communication/rules-auto/token-efficiency-mechanics.md +69 -0
- package/dist/agent-src/contexts/execution/auto-dispatch-classification.md +5 -5
- package/dist/agent-src/rules/external-code-graph-interop.md +19 -14
- package/dist/agent-src/rules/token-efficiency.md +26 -3
- package/dist/agent-src/scripts/_cli_entry.ts +51 -0
- package/dist/agent-src/scripts/archive_completed_roadmaps.ts +14 -23
- package/dist/agent-src/scripts/roadmap_gates.ts +4 -20
- package/dist/agent-src/scripts/roadmap_set_step.ts +5 -2
- package/dist/agent-src/scripts/stubs_due.ts +4 -18
- package/dist/agent-src/scripts/update_roadmap_progress.ts +7 -24
- package/dist/agent-src/skills/code-intelligence/SKILL.md +25 -0
- package/dist/agent-src/skills/roadmap-writing/SKILL.md +17 -0
- package/dist/agent-src/templates/agent-settings.md +0 -1
- package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
- package/dist/cli-delegate/_cli_entry.js +8 -0
- package/dist/cli-delegate/_lib/pin_resolver.js +170 -0
- package/dist/cli-delegate/archival_sweep.js +8 -0
- package/dist/cli-delegate/archive_completed_roadmaps.js +494 -0
- package/dist/cli-delegate/check_update_banner.js +923 -0
- package/dist/cli-delegate/chunk-5EK5WQN6.js +28 -0
- package/dist/cli-delegate/chunk-7XGD2OEU.js +96 -0
- package/dist/cli-delegate/{chunk-643Z7FIC.js → chunk-BIXEDQPZ.js} +6 -0
- package/dist/cli-delegate/chunk-DBH4AHDK.js +155 -0
- package/dist/cli-delegate/chunk-JO25G5H7.js +20 -0
- package/dist/cli-delegate/chunk-LTYVIY76.js +7961 -0
- package/dist/cli-delegate/chunk-QAJS5YWY.js +999 -0
- package/dist/cli-delegate/{chunk-ZVBOHSVF.js → chunk-TGIPZBCW.js} +1 -1
- package/dist/cli-delegate/{chunk-YS6XTLEK.js → chunk-TYSY33MD.js} +56 -6
- package/dist/cli-delegate/chunk-ULET4BYS.js +328 -0
- package/dist/cli-delegate/chunk-YDQSHTD7.js +187 -0
- package/dist/cli-delegate/chunk-YWVXLR44.js +48 -0
- package/dist/cli-delegate/chunk-ZZQBUHFK.js +273 -0
- package/dist/cli-delegate/cmd_conformance.js +2 -2
- package/dist/cli-delegate/cmd_export.js +1 -1
- package/dist/cli-delegate/cmd_handoff.js +26 -2
- package/dist/cli-delegate/cmd_prune.js +1 -1
- package/dist/cli-delegate/cmd_session_recycle.js +2 -2
- package/dist/cli-delegate/cmd_settings_migrate.js +1 -1
- package/dist/cli-delegate/cmd_sync.js +1 -1
- package/dist/cli-delegate/cmd_uninstall.js +1 -1
- package/dist/cli-delegate/cmd_validate.js +1 -1
- package/dist/cli-delegate/dashboard_mode.js +16 -0
- package/dist/cli-delegate/gate_budget.js +24 -0
- package/dist/cli-delegate/gate_execute.js +25 -0
- package/dist/cli-delegate/guarded_baseline.js +18 -0
- package/dist/cli-delegate/resume_probe.js +22 -0
- package/dist/cli-delegate/roadmap_gates.js +638 -0
- package/dist/cli-delegate/roadmap_set_step.js +173 -0
- package/dist/cli-delegate/stub_queue.js +47 -0
- package/dist/cli-delegate/stubs_due.js +38 -0
- package/dist/cli-delegate/ticket_bundles.js +59 -0
- package/dist/cli-delegate/update_roadmap_progress.js +60 -0
- package/dist/discovery/deprecation-report.md +1 -1
- package/dist/discovery/discovery-manifest.json +8 -8
- package/dist/discovery/discovery-manifest.json.sha256 +1 -1
- package/dist/discovery/discovery-manifest.summary.md +1 -1
- package/dist/discovery/dormancy-report.md +1 -1
- package/dist/discovery/orphan-report.md +1 -1
- package/dist/discovery/packs.json +2 -2
- package/dist/discovery/trust-report.md +1 -1
- package/dist/discovery/workspaces.json +2 -2
- package/dist/hooks/dispatch.js +1193 -917
- package/dist/install/claudeLayerCarriage.js +237 -0
- package/dist/install/claudePathsPlan.js +79 -0
- package/dist/install/hostLayerFingerprint.js +1 -1
- package/dist/install/install.mjs +6 -0
- package/dist/install/partitionEligibility.js +231 -117
- package/dist/install/ruleLayerPartition.js +10 -7
- package/dist/mcp/registry-manifest.json +2 -2
- package/dist/mcp/server.json +2 -2
- package/dist/mcp/server.mjs +39219 -38995
- package/dist/scripts/condense.js +32 -25
- package/docs/MIGRATION.md +49 -1
- package/docs/contracts/settings-classes.md +1 -1
- package/docs/guidelines/agent-infra/minimal-safe-diff-mechanics.md +73 -0
- package/package.json +7 -4
- package/src/agent-src/scripts/_cli_entry.ts +51 -0
- package/src/agent-src/scripts/archive_completed_roadmaps.ts +14 -23
- package/src/agent-src/scripts/roadmap_gates.ts +4 -20
- package/src/agent-src/scripts/roadmap_set_step.ts +5 -2
- package/src/agent-src/scripts/stubs_due.ts +4 -18
- package/src/agent-src/scripts/update_roadmap_progress.ts +7 -24
- package/src/config/continuity-surface.json +509 -0
- package/src/config/estate-count-budget.json +1 -1
- package/src/config/gate-coverage.yml +29 -8
- package/src/config/gate-violation-baselines.json +8 -8
- package/src/config/gitignore-block.txt +19 -0
- package/src/config/host-injection-effect.json +73 -0
- package/src/config/packed-binary-manifest.json +33 -0
- package/src/config/preamble-payload-budget.json +112 -105
- package/src/config/publish-surface.json +4 -2
- package/src/install/claudeLayerCarriage.ts +273 -0
- package/src/install/claudePathsPlan.ts +76 -0
- package/src/install/hostLayerFingerprint.ts +1 -1
- package/src/install/partitionEligibility.ts +261 -127
- package/src/install/ruleLayerPartition.ts +19 -23
- package/src/scripts/_dispatch.bash +77 -27
- package/src/scripts/_lib/auto_dispatch.ts +2 -2
- package/src/scripts/_lib/catalogue_layer_parity.ts +146 -0
- package/src/scripts/_lib/continuity_surface.ts +296 -0
- package/src/scripts/_lib/corpus_manifest.ts +26 -9
- package/src/scripts/_lib/hook_settings.ts +1 -1
- package/src/scripts/_lib/injection_effect.ts +151 -0
- package/src/scripts/_lib/layer_overlap_notice.ts +50 -6
- package/src/scripts/_lib/packed_binary_predicate.ts +225 -0
- package/src/scripts/_lib/pin_resolver.ts +13 -0
- package/src/scripts/_lib/regression_neighbourhood.ts +1 -1
- package/src/scripts/_lib/retired_status.ts +74 -0
- package/src/scripts/_lib/skill_catalogue.ts +156 -21
- package/src/scripts/_lib/subagent_capsule.ts +117 -8
- package/src/scripts/ai_council/api_transport.ts +5 -0
- package/src/scripts/ai_council/deliberation_metrics.ts +353 -0
- package/src/scripts/ai_council/prompts.ts +9 -0
- package/src/scripts/ai_council/synthesis_disagreement.ts +206 -0
- package/src/scripts/capture_skill_catalogue.ts +24 -11
- package/src/scripts/check_candidate_lines.ts +499 -0
- package/src/scripts/check_continuity_surface.ts +475 -0
- package/src/scripts/check_dependency_floors.ts +13 -6
- package/src/scripts/check_estate_count.ts +40 -79
- package/src/scripts/check_pack_size.ts +262 -23
- package/src/scripts/check_roadmap_trackable.ts +19 -16
- package/src/scripts/check_rule_layer_partition.ts +54 -34
- package/src/scripts/check_single_delivery.ts +97 -31
- package/src/scripts/check_update_banner.ts +13 -0
- package/src/scripts/code_graph/build.ts +138 -15
- package/src/scripts/code_graph/cli.ts +76 -8
- package/src/scripts/code_graph/extract.ts +11 -0
- package/src/scripts/code_graph/grammar_probe.ts +43 -0
- package/src/scripts/code_graph/loader.ts +88 -14
- package/src/scripts/code_graph/query.ts +121 -11
- package/src/scripts/code_graph/resolution_tiers.ts +238 -0
- package/src/scripts/code_graph/sqlite_store.ts +247 -6
- package/src/scripts/code_graph/types.ts +66 -1
- package/src/scripts/code_graph/validate.ts +23 -0
- package/src/scripts/condense.ts +34 -22
- package/src/scripts/corpus_manifest.ts +5 -5
- package/src/scripts/council_cli.ts +11 -12
- package/src/scripts/count_intent_disagreement.ts +426 -0
- package/src/scripts/handoff_context_hook.ts +79 -0
- package/src/scripts/hook_effect_doctor.ts +82 -1
- package/src/scripts/hook_manifest.json +1 -1
- package/src/scripts/hook_manifest.yaml +64 -12
- package/src/scripts/hooks/chain_nudge_hook.ts +282 -0
- package/src/scripts/hooks/code_graph_context_hook.ts +212 -0
- package/src/scripts/hooks/concern_registry.ts +4 -2
- package/src/scripts/hooks/host_semantics.ts +1 -1
- package/src/scripts/hooks/orchestration_record_hook.ts +2 -2
- package/src/scripts/hooks/rule_inject_hook.ts +1 -1
- package/src/scripts/hooks/skill_route_hook.ts +11 -4
- package/src/scripts/inbox_source_census.ts +322 -0
- package/src/scripts/install-hooks.sh +82 -0
- package/src/scripts/{lint_carrier_integrity.ts → lint_deferral_integrity.ts} +60 -214
- package/src/scripts/lint_plan_risk_register.ts +13 -17
- package/src/scripts/mcp_server/suggest_skill.ts +72 -0
- package/src/scripts/mcp_server/tools.ts +2 -56
- package/src/scripts/media/lib/adapter-contract.md +7 -2
- package/src/scripts/media/lib/fixtures/flux/asset-0001.png +0 -0
- package/src/scripts/media/lib/fixtures/gemini-image/asset-0001.png +0 -0
- package/src/scripts/media/lib/fixtures/ideogram/asset-0001.png +0 -0
- package/src/scripts/rdp_candidates_delta.ts +276 -0
- package/src/scripts/rdp_quality_eval.ts +217 -19
- package/src/scripts/release_mix_taxonomy.json +3 -2
- package/src/scripts/report_host_injection_effect.ts +189 -0
- package/src/scripts/report_layer_overlap.ts +41 -0
- package/src/scripts/report_skill_menu_census.ts +341 -0
- package/src/scripts/skill_tools/score_skill_relevance.ts +70 -6
- package/src/scripts/skill_tools/suggest_skill_for_task.ts +37 -3
- package/src/vendor/grammars/README.md +61 -0
- package/src/vendor/grammars/tree-sitter-javascript.wasm +0 -0
- package/src/vendor/grammars/tree-sitter-php.wasm +0 -0
- package/src/vendor/grammars/tree-sitter-typescript.wasm +0 -0
- package/src/scripts/_lib/carrier_status.ts +0 -118
- package/src/scripts/_lib/estate_carrier_cases.ts +0 -72
- package/src/scripts/hooks/code_graph_nudge_hook.ts +0 -191
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The single-delivery partition predicate — one artefact, one layer.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* **What it decides.**
|
|
5
5
|
*
|
|
6
6
|
* Two layers deliver agent artefacts: a machine-local project layer at
|
|
7
7
|
* `<repo>/.claude/` (gitignored, 0 tracked files, rewritten by every
|
|
@@ -11,16 +11,23 @@
|
|
|
11
11
|
* 203,873 tokens against a 110,000 cap (185.3 %).
|
|
12
12
|
*
|
|
13
13
|
* ADR-236 partitions them: an artefact that exists ONLY for this package stays
|
|
14
|
-
* in the project layer; everything else is delivered only globally.
|
|
15
|
-
* `<repo>/.claude/` from 111 rules and 338 skills to **16 rules and zero
|
|
16
|
-
* skills**.
|
|
14
|
+
* in the project layer; everything else is delivered only globally.
|
|
17
15
|
*
|
|
18
|
-
*
|
|
16
|
+
* The figure this note carried — "16 rules and zero skills" — was the 2026-08-19
|
|
17
|
+
* projection of the design. Measured 2026-09-07 on the amended implementation:
|
|
18
|
+
* **13 rules** (15 package-only, 2 of them byte-identically deduped at user
|
|
19
|
+
* scope) and **zero skills**, plus 49 flat-command wrappers, which are a
|
|
20
|
+
* different family and are withheld per name like everything else.
|
|
21
|
+
*
|
|
22
|
+
* **Why the predicate is fail-safe and never fails the build.**
|
|
19
23
|
*
|
|
20
24
|
* The partition is a removal, so the build loses its repair path: it can no
|
|
21
25
|
* longer heal a stale global layer by regenerating, because it stops writing
|
|
22
|
-
* those files.
|
|
23
|
-
*
|
|
26
|
+
* those files. **How that fail-safe is expressed changed on 2026-09-07** and the
|
|
27
|
+
* sentence below is the OLD form, kept because the constraint it records still
|
|
28
|
+
* binds: uncertainty used to resolve to a repo-wide `standalone/full`, a mode
|
|
29
|
+
* this file no longer has. It now resolves PER ARTEFACT — an unreadable host
|
|
30
|
+
* layer withholds nothing — and still never to a refusal:
|
|
24
31
|
*
|
|
25
32
|
* `.github/workflows/consistency.yml:169` runs `task generate-tools` on a fresh
|
|
26
33
|
* checkout where, by that workflow's own comment at `:172-174`, the host rule
|
|
@@ -30,51 +37,101 @@
|
|
|
30
37
|
* exists to prevent; breaking the Consistency pipeline is the other. Full
|
|
31
38
|
* projection is the only branch that does neither.
|
|
32
39
|
*
|
|
33
|
-
*
|
|
40
|
+
* **Why content and not a version number.**
|
|
34
41
|
*
|
|
35
42
|
* Rationale and the 153-skill measurement that decided it: see
|
|
36
43
|
* `hostLayerFingerprint.ts`. Version equality is checked too, but as a cheap
|
|
37
44
|
* pre-filter — it is necessary, never sufficient.
|
|
38
45
|
*
|
|
39
|
-
*
|
|
46
|
+
* **Contract.**
|
|
40
47
|
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
48
|
+
* `verifyHostLayer` itself is side-effect-free and takes its facts from the
|
|
49
|
+
* caller. The MODULE is not: `resolveHostLayerVerdict` reads the filesystem and
|
|
50
|
+
* the lockfile, and since 2026-09-07 it re-exports `keepInProjectLayer` /
|
|
51
|
+
* `claudeLayerHolds`, which read directories. The earlier blanket "no I/O of its
|
|
52
|
+
* own" was true of the pure predicate and false of the file. No CLI entry, no
|
|
53
|
+
* `process.exit`. Ships inside the consumer installer bundle, same
|
|
43
54
|
* constraint as `ruleInScope.ts`.
|
|
44
55
|
*/
|
|
45
56
|
import * as fs from 'node:fs';
|
|
46
57
|
import * as os from 'node:os';
|
|
58
|
+
import { claudeLayerHolds, keepInProjectLayer } from './claudeLayerCarriage.js';
|
|
59
|
+
/**
|
|
60
|
+
* **`emittedWrapperSlugs` — why the skill sweep's protected set narrowed.**
|
|
61
|
+
*
|
|
62
|
+
* `generate_claude_skills` sweeps `.claude/skills/` of anything absent from the
|
|
63
|
+
* set it is about to write, and it spares command-wrapper slugs so the command
|
|
64
|
+
* emitter — which runs afterwards into the same directory — does not lose
|
|
65
|
+
* entries it is about to create. That protected set used to be EVERY command
|
|
66
|
+
* slug, which was safe only while skills were projected in full: a slug that is
|
|
67
|
+
* also a skill name was protected twice over.
|
|
68
|
+
*
|
|
69
|
+
* Once `~/.claude/skills` began withholding by name (2026-09-07) the
|
|
70
|
+
* over-protection became a leak — precisely the one
|
|
71
|
+
* `tests/scripts/single_delivery_emission.test.ts` exists for. A command-named
|
|
72
|
+
* skill survives in `.claude/skills/` while both counters read zero, because the
|
|
73
|
+
* skill sweep spares it and the command prune skips symlinks.
|
|
74
|
+
*
|
|
75
|
+
* So the set mirrors the emitter's own skips — **all of them**, which a neutral
|
|
76
|
+
* review found it did not on 2026-09-07: the note said "two" and named two while
|
|
77
|
+
* the emitter had three, so up to 8 builtin-reserved slugs (`bug`, `review`,
|
|
78
|
+
* `worktree`, `agents`, `context`, `cost`, `memory`, `skills`) were protected
|
|
79
|
+
* from a sweep that should reach them. Benign in the shipped pipeline order,
|
|
80
|
+
* because the command emitter's own stale-dir sweep cleans them afterwards — but
|
|
81
|
+
* the invariant the note asserted did not hold, and it reopens for any run that
|
|
82
|
+
* calls `generate_claude_skills` without `generate_claude_commands`.
|
|
83
|
+
*
|
|
84
|
+
* The four skips: a slug that is also a skill name · every CLUSTERED command
|
|
85
|
+
* (those reach the host as `/cluster:sub` and need no wrapper) · a Claude Code
|
|
86
|
+
* built-in name · a slug `~/.claude/skills` already carries.
|
|
87
|
+
* `condense.ts::_emitted_wrapper_slugs` is that set.
|
|
88
|
+
*
|
|
89
|
+
* **The re-export below.**
|
|
90
|
+
*
|
|
91
|
+
* `keepInProjectLayer` is re-exported so `condense.ts` reaches both halves of
|
|
92
|
+
* the partition through ONE import line. Not stylistic: that file sits ~1,200 lines past the 1,500-line
|
|
93
|
+
* source ceiling, where `check_source_size_budget` counts every added line as
|
|
94
|
+
* one unit of excess and its test asserts `baseline == live` — so a second
|
|
95
|
+
* import statement there is a blocking gate failure, while the same line here
|
|
96
|
+
* (535 lines, under the cap) costs nothing.
|
|
97
|
+
*/
|
|
98
|
+
export { claudeLayerHolds, keepInProjectLayer } from './claudeLayerCarriage.js';
|
|
47
99
|
import { parseFrontmatter } from './ruleInScope.js';
|
|
48
100
|
import { fingerprintLayers, hostLayerInputs } from './hostLayerFingerprint.js';
|
|
49
101
|
import { current_package_version, read_lockfile, write_lockfile, } from '../scripts/_lib/installed_lock.js';
|
|
50
102
|
/** The workspace id that marks an artefact as existing only for this package. */
|
|
51
103
|
export const MAINTAINER_WORKSPACE = 'agent-config-maintainer';
|
|
52
104
|
/**
|
|
53
|
-
*
|
|
54
|
-
* throws, never refuses.
|
|
105
|
+
* Verify the host layer against the install record. Total function: always
|
|
106
|
+
* returns a verdict, never throws, never refuses.
|
|
55
107
|
*
|
|
56
|
-
* The order of the guards is
|
|
57
|
-
*
|
|
58
|
-
*
|
|
108
|
+
* The order of the guards is cheapest-and-most-decisive first, so the
|
|
109
|
+
* fingerprint is computed only when everything else already agrees.
|
|
110
|
+
*
|
|
111
|
+
* **A `false` no longer changes what gets written.** It changes what the run
|
|
112
|
+
* SAYS — see `reportHostLayerVerdict`, whose warning names the remedy. The
|
|
113
|
+
* withhold decision moved to per-artefact evidence, where an unverified install
|
|
114
|
+
* that nonetheless carries an artefact is not a reason to deliver that artefact
|
|
115
|
+
* twice.
|
|
59
116
|
*/
|
|
60
|
-
export function
|
|
117
|
+
export function verifyHostLayer(inputs) {
|
|
61
118
|
if (!inputs.hostLayerPresent) {
|
|
62
119
|
return {
|
|
63
|
-
|
|
120
|
+
verified: false,
|
|
64
121
|
reason: 'no host-global layer on this machine',
|
|
65
122
|
};
|
|
66
123
|
}
|
|
67
124
|
const lock = inputs.lockfile;
|
|
68
125
|
if (lock === null) {
|
|
69
126
|
return {
|
|
70
|
-
|
|
127
|
+
verified: false,
|
|
71
128
|
reason: 'host layer present but no install record (installed.lock absent)',
|
|
72
129
|
};
|
|
73
130
|
}
|
|
74
131
|
const recorded = lock.agent_config_version;
|
|
75
132
|
if (!recorded) {
|
|
76
133
|
return {
|
|
77
|
-
|
|
134
|
+
verified: false,
|
|
78
135
|
reason: 'install record carries no version',
|
|
79
136
|
};
|
|
80
137
|
}
|
|
@@ -83,15 +140,15 @@ export function partitionVerdict(inputs) {
|
|
|
83
140
|
// checkout still expects, and ordering does not establish substitutability.
|
|
84
141
|
if (recorded !== inputs.projectVersion) {
|
|
85
142
|
return {
|
|
86
|
-
|
|
143
|
+
verified: false,
|
|
87
144
|
reason: `version mismatch (installed ${recorded}, building ${inputs.projectVersion})`,
|
|
88
145
|
};
|
|
89
146
|
}
|
|
90
147
|
const installedFp = lock.host_layer_fingerprint;
|
|
91
148
|
if (!installedFp) {
|
|
92
149
|
return {
|
|
93
|
-
|
|
94
|
-
reason: 'install predates host-layer fingerprinting — re-run `agent-config install` to
|
|
150
|
+
verified: false,
|
|
151
|
+
reason: 'install predates host-layer fingerprinting — re-run `agent-config install` to record one',
|
|
95
152
|
};
|
|
96
153
|
}
|
|
97
154
|
let expected;
|
|
@@ -100,18 +157,18 @@ export function partitionVerdict(inputs) {
|
|
|
100
157
|
}
|
|
101
158
|
catch {
|
|
102
159
|
return {
|
|
103
|
-
|
|
160
|
+
verified: false,
|
|
104
161
|
reason: 'could not compute the expected host-layer fingerprint',
|
|
105
162
|
};
|
|
106
163
|
}
|
|
107
164
|
if (installedFp !== expected) {
|
|
108
165
|
return {
|
|
109
|
-
|
|
166
|
+
verified: false,
|
|
110
167
|
reason: 'host-layer content differs from this checkout — re-run `agent-config install`',
|
|
111
168
|
};
|
|
112
169
|
}
|
|
113
170
|
return {
|
|
114
|
-
|
|
171
|
+
verified: true,
|
|
115
172
|
reason: `host layer verified at ${recorded} (fingerprint ${installedFp.slice(0, 12)})`,
|
|
116
173
|
};
|
|
117
174
|
}
|
|
@@ -129,7 +186,7 @@ export function partitionVerdict(inputs) {
|
|
|
129
186
|
* the project layer. Both defaults resolve toward "the artefact is generally
|
|
130
187
|
* useful"; only one of them is about withholding.
|
|
131
188
|
*
|
|
132
|
-
*
|
|
189
|
+
* **The state space, MEASURED rather than enumerated defensively (2026-08-21).**
|
|
133
190
|
*
|
|
134
191
|
* Three of this function's branches — unreadable file, absent `workspaces:`,
|
|
135
192
|
* empty list — all resolve to `false`, and the closure review asked whether one
|
|
@@ -171,61 +228,69 @@ export function isExclusivelyPackageOnly(source_path) {
|
|
|
171
228
|
let _memo = null;
|
|
172
229
|
let _announce = (m) => process.stdout.write(`${m}\n`);
|
|
173
230
|
/**
|
|
174
|
-
* Install the emitter used for the
|
|
175
|
-
* their DEFAULT output level — the first implementation used one that
|
|
176
|
-
* at `verbose`, which withheld ~100 rules while saying nothing in a
|
|
231
|
+
* Install the emitter used for the projection line. Callers pass a function
|
|
232
|
+
* visible at their DEFAULT output level — the first implementation used one that
|
|
233
|
+
* prints only at `verbose`, which withheld ~100 rules while saying nothing in a
|
|
234
|
+
* normal run.
|
|
177
235
|
*/
|
|
178
236
|
export function setPartitionAnnounce(fn) {
|
|
179
237
|
_announce = fn;
|
|
180
238
|
}
|
|
181
|
-
/** Test seam — drop the memo so one process can exercise both
|
|
182
|
-
export function
|
|
239
|
+
/** Test seam — drop the memo so one process can exercise both verdicts. */
|
|
240
|
+
export function _resetHostLayerVerdictForTest() {
|
|
183
241
|
_memo = null;
|
|
184
242
|
}
|
|
185
243
|
/**
|
|
186
|
-
*
|
|
187
|
-
*
|
|
188
|
-
*
|
|
189
|
-
*
|
|
190
|
-
*
|
|
191
|
-
*
|
|
192
|
-
*
|
|
193
|
-
*
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
*
|
|
200
|
-
*
|
|
201
|
-
*
|
|
202
|
-
*
|
|
203
|
-
*
|
|
204
|
-
*
|
|
205
|
-
*
|
|
206
|
-
*
|
|
207
|
-
*
|
|
208
|
-
*
|
|
209
|
-
*
|
|
210
|
-
*
|
|
211
|
-
*
|
|
212
|
-
*
|
|
213
|
-
*
|
|
214
|
-
*
|
|
244
|
+
* Verify the host layer once per generation, and say so once.
|
|
245
|
+
*
|
|
246
|
+
* **What this no longer does.**
|
|
247
|
+
*
|
|
248
|
+
* It used to answer `partitionActive(projectRoot)`, and every generator gated its
|
|
249
|
+
* withhold on that one boolean. **That entry point is deleted** (owner decision,
|
|
250
|
+
* 2026-09-07). The project layer's contents are now decided per artefact, on the
|
|
251
|
+
* host layer's own contents, by `claudeLayerCarriage.keepInProjectLayer` and
|
|
252
|
+
* `globalRuleLayers.hostLayerCarries`. A version number is not evidence about an
|
|
253
|
+
* artefact, and using it as one delivered 261 skills and 29 personas twice per
|
|
254
|
+
* session for as long as an install lagged a release.
|
|
255
|
+
*
|
|
256
|
+
* So what survives is the DIAGNOSTIC. **Both council seats (2026-08-20, 2/2)
|
|
257
|
+
* required that generation print the mode it selected** rather than partition
|
|
258
|
+
* silently, and that requirement is still live — but this function is no longer
|
|
259
|
+
* where it is met, and the first version of this note claimed otherwise.
|
|
260
|
+
*
|
|
261
|
+
* **Corrected 2026-09-07 after a neutral review.** The note read "it still
|
|
262
|
+
* prints". It did not: removing `partitionActive` removed `condense.ts`'s only
|
|
263
|
+
* call into this resolver, so the emitter that file installed became dead and
|
|
264
|
+
* `task generate-tools` withheld ~299 skills and 29 personas while printing
|
|
265
|
+
* nothing about the layer it withheld against. The line is now emitted by
|
|
266
|
+
* `report_layer_overlap`, the step that already runs immediately after the
|
|
267
|
+
* generator in the same chain — see the comment there for why it lives in that
|
|
268
|
+
* file rather than in the 2,700-line generator.
|
|
269
|
+
*
|
|
270
|
+
* **What that line does and does not carry**, since a second review asked: it
|
|
271
|
+
* reports the VERIFICATION state of the layer being withheld against, not a
|
|
272
|
+
* withhold count, and this verdict decides nothing. The counts are the
|
|
273
|
+
* generator's own summary one line above (`skills=N`,
|
|
274
|
+
* `command_skills=N (M withheld …)`). So the council requirement is met by the
|
|
275
|
+
* pair of lines rather than by this one — stated that way instead of claiming
|
|
276
|
+
* the line alone honours it.
|
|
277
|
+
*
|
|
278
|
+
* The caller still supplies `announce`, and the level still matters — the first
|
|
279
|
+
* implementation used an `info()` that prints only at `verbose`. Residual,
|
|
280
|
+
* stated: at an explicitly silent output level the line is dropped.
|
|
215
281
|
*
|
|
216
282
|
* The fingerprint compares the host layer against **what the installer recorded
|
|
217
|
-
* when it wrote that layer**, not against a re-derivation from source
|
|
218
|
-
*
|
|
219
|
-
* make the partition permanently unreachable rather than merely inactive — and it
|
|
220
|
-
* is the property the partition needs: the omitted artefacts are still present,
|
|
221
|
-
* in the form this version's installer left them.
|
|
283
|
+
* when it wrote that layer**, not against a re-derivation from source — the
|
|
284
|
+
* property that keeps a mismatch informative rather than permanent.
|
|
222
285
|
*
|
|
223
286
|
* **Known residual:** an installer that crashes mid-write and still reaches the
|
|
224
287
|
* lockfile would fingerprint its own partial layer, and that fingerprint then
|
|
225
288
|
* verifies. Ordering narrows the window (the lockfile is written last) without
|
|
226
|
-
* closing it
|
|
289
|
+
* closing it. It now costs less than it did: the withhold no longer trusts this
|
|
290
|
+
* verdict, so a wrongly-verified layer misreports a line rather than authorising
|
|
291
|
+
* a removal.
|
|
227
292
|
*/
|
|
228
|
-
export function
|
|
293
|
+
export function resolveHostLayerVerdict(projectRoot) {
|
|
229
294
|
if (_memo !== null) {
|
|
230
295
|
return _memo;
|
|
231
296
|
}
|
|
@@ -243,15 +308,17 @@ export function resolvePartitionVerdict(projectRoot) {
|
|
|
243
308
|
lock = read_lockfile();
|
|
244
309
|
}
|
|
245
310
|
catch {
|
|
246
|
-
lock = null; // unreadable record →
|
|
311
|
+
lock = null; // unreadable record → report it as unverified
|
|
247
312
|
}
|
|
248
|
-
_memo =
|
|
313
|
+
_memo = verifyHostLayer({
|
|
249
314
|
projectVersion: current_package_version(projectRoot),
|
|
250
315
|
lockfile: lock,
|
|
251
316
|
hostLayerPresent: present,
|
|
252
317
|
expectedFingerprint: () => fingerprintLayers(layers),
|
|
253
318
|
});
|
|
254
|
-
_announce(
|
|
319
|
+
_announce(_memo.verified
|
|
320
|
+
? `projection: project layer carries only what ~/.claude lacks — ${_memo.reason}`
|
|
321
|
+
: `projection: project layer carries only what ~/.claude lacks · ⚠️ host layer UNVERIFIED — ${_memo.reason}`);
|
|
255
322
|
return _memo;
|
|
256
323
|
}
|
|
257
324
|
/**
|
|
@@ -272,7 +339,7 @@ export function resolvePartitionVerdict(projectRoot) {
|
|
|
272
339
|
* errors are not symmetric and this must never prefer the second.
|
|
273
340
|
*
|
|
274
341
|
* Lives here rather than inline in `install.ts` for the same reason
|
|
275
|
-
* {@link
|
|
342
|
+
* {@link resolveHostLayerVerdict} does: it belongs beside the predicate it
|
|
276
343
|
* serves, and `install.ts` is 5,000+ lines where the source-size ratchet counts
|
|
277
344
|
* every added line.
|
|
278
345
|
*
|
|
@@ -309,53 +376,58 @@ skip, report) {
|
|
|
309
376
|
* names**, and neither `check_single_delivery` nor `_lib/layer_overlap_notice`
|
|
310
377
|
* looked, because `personas` was in neither's `TYPES`.
|
|
311
378
|
*
|
|
312
|
-
*
|
|
379
|
+
* **Three properties the caller depends on.**
|
|
313
380
|
*
|
|
314
|
-
* **Scoped to `.claude/` only.**
|
|
315
|
-
*
|
|
316
|
-
*
|
|
317
|
-
*
|
|
318
|
-
*
|
|
381
|
+
* **Scoped to `.claude/` only.** The evidence is `~/.claude/personas`. It says
|
|
382
|
+
* nothing about `~/.cursor`, so withholding a cursor persona on the strength of
|
|
383
|
+
* a claude directory listing would deliver it nowhere — the one failure the
|
|
384
|
+
* fail-safe design exists to prevent. Every other tool directory keeps the full
|
|
385
|
+
* projection.
|
|
319
386
|
*
|
|
320
|
-
* **
|
|
387
|
+
* **Withheld PER NAME, on that directory's own contents** (owner decision,
|
|
388
|
+
* 2026-09-07). This used to gate on `partitionActive` — a version and fingerprint
|
|
389
|
+
* check against `installed.lock` — which meant an install one release behind
|
|
390
|
+
* delivered all 29 personas twice. A persona `~/.claude/personas` actually holds
|
|
391
|
+
* is withheld whatever the lockfile says; one it lacks stays, on its own, without
|
|
392
|
+
* keeping the other 28 duplicates alive with it.
|
|
393
|
+
*
|
|
394
|
+
* **Reconciliation is the shorter list, not a second code path.** The caller's
|
|
321
395
|
* stale-symlink sweep removes any link whose name is absent from the list it was
|
|
322
|
-
* given for that directory, so
|
|
323
|
-
*
|
|
396
|
+
* given for that directory, so a shorter list empties what an earlier version
|
|
397
|
+
* populated. A gate that only declined to WRITE would leave the existing
|
|
324
398
|
* duplicate standing — a partition that stops new duplication and keeps the old
|
|
325
399
|
* is not a partition.
|
|
326
|
-
*
|
|
327
|
-
* Verified before shipping: every one of the 29 project personas is present in
|
|
328
|
-
* the global layer (32 there, a strict superset). The partition is a removal and
|
|
329
|
-
* has no repair path, so withholding is only safe once the surviving layer is
|
|
330
|
-
* known to carry what is withheld.
|
|
331
400
|
*/
|
|
332
|
-
export function personaPartition(
|
|
333
|
-
const
|
|
401
|
+
export function personaPartition(all, home) {
|
|
402
|
+
const claudeList = keepInProjectLayer('personas', all, home);
|
|
403
|
+
const withheld = all.length - claudeList.length;
|
|
334
404
|
return {
|
|
335
405
|
all,
|
|
336
|
-
listFor: (toolDir) => (
|
|
337
|
-
note:
|
|
338
|
-
|
|
406
|
+
listFor: (toolDir) => personaListFor(toolDir, all, claudeList),
|
|
407
|
+
note: withheld > 0
|
|
408
|
+
? ` — .claude/ withheld ${String(withheld)}: ADR-236, those personas arrive from ~/.claude`
|
|
409
|
+
: '',
|
|
410
|
+
countFor: (toolDir) => personaListFor(toolDir, all, claudeList).length,
|
|
339
411
|
};
|
|
340
412
|
}
|
|
341
413
|
/**
|
|
342
|
-
* The pure half of {@link personaPartition}:
|
|
343
|
-
*
|
|
344
|
-
*
|
|
345
|
-
* Split out so the decision is testable in BOTH directions
|
|
346
|
-
*
|
|
347
|
-
*
|
|
348
|
-
*
|
|
349
|
-
*
|
|
350
|
-
*
|
|
414
|
+
* The pure half of {@link personaPartition}: a Claude tool directory gets the
|
|
415
|
+
* narrowed list, every other directory gets the full one.
|
|
416
|
+
*
|
|
417
|
+
* Split out so the decision is testable in BOTH directions without reading this
|
|
418
|
+
* machine's `~/.claude`. A test over the un-injected path can only assert
|
|
419
|
+
* whatever the machine happens to be — a test that passes either way and
|
|
420
|
+
* therefore proves nothing. The two properties worth pinning are exactly the two
|
|
421
|
+
* this signature exposes: `.claude/` gets the narrowed list, and NOTHING else
|
|
422
|
+
* ever does.
|
|
351
423
|
*/
|
|
352
|
-
export function
|
|
353
|
-
return
|
|
424
|
+
export function personaListFor(toolDir, all, claudeList) {
|
|
425
|
+
return toolDir.startsWith('.claude/') ? claudeList : all;
|
|
354
426
|
}
|
|
355
427
|
/**
|
|
356
428
|
* Does the project layer withhold the colon-form `/cluster:sub` commands?
|
|
357
429
|
*
|
|
358
|
-
*
|
|
430
|
+
* **The claim this replaces, and the measurement that revised it.**
|
|
359
431
|
*
|
|
360
432
|
* `generate_claude_project_commands` was written on the reasoning that "Claude
|
|
361
433
|
* Code dedupes project and user scope by name, so the two copies of
|
|
@@ -377,16 +449,24 @@ export function personaWithheldFor(toolDir, active) {
|
|
|
377
449
|
* exists, those 40 symlinks are written, deduped away, and LOSE. They are dead
|
|
378
450
|
* weight there — not a second listing, and not a reachability guarantee either.
|
|
379
451
|
*
|
|
380
|
-
*
|
|
452
|
+
* **Why the predicate is the DIRECTORY, not `installed.lock`.**
|
|
381
453
|
*
|
|
382
|
-
*
|
|
383
|
-
* `installed.lock
|
|
384
|
-
*
|
|
385
|
-
*
|
|
386
|
-
*
|
|
387
|
-
*
|
|
454
|
+
* This used to be `partitionActive` — true only when a global layer was present
|
|
455
|
+
* AND verified against `installed.lock` by version and fingerprint. That gets
|
|
456
|
+
* the measurement above backwards in the one case that matters: the project copy
|
|
457
|
+
* loses whenever the global copy EXISTS, and whether the recorded version is a
|
|
458
|
+
* release behind has no bearing on whether it exists. An install one release old
|
|
459
|
+
* therefore kept writing 40 symlinks the host deduped away — dead weight, chosen
|
|
460
|
+
* on a fact about a version number.
|
|
388
461
|
*
|
|
389
|
-
*
|
|
462
|
+
* So the evidence is the host directory itself, asked per name (owner decision,
|
|
463
|
+
* 2026-09-07): `~/.claude/commands/<cluster>/<sub>.md` for a clustered command,
|
|
464
|
+
* `~/.claude/commands/<slug>.md` for a flat one. Present → the project copy loses
|
|
465
|
+
* and is withheld. Absent → the project copy is the only reachable one and stays.
|
|
466
|
+
* Unreadable layer → nothing is withheld. The fail-safe direction is unchanged;
|
|
467
|
+
* it is now per artefact rather than per repository.
|
|
468
|
+
*
|
|
469
|
+
* **Honest limits.**
|
|
390
470
|
*
|
|
391
471
|
* Self-report, n=1 per condition, one host version, one machine. What is NOT
|
|
392
472
|
* claimed: that older or newer hosts dedupe the same way, or that precedence is
|
|
@@ -398,21 +478,55 @@ export function personaWithheldFor(toolDir, active) {
|
|
|
398
478
|
* It cannot. When this predicate returns true the project copy is never written,
|
|
399
479
|
* so there is no second copy for the host to double-list or for the gate to
|
|
400
480
|
* count — it would report zero overlap while the assumption underneath had
|
|
401
|
-
* failed.
|
|
402
|
-
*
|
|
403
|
-
*
|
|
481
|
+
* failed. The 2026-09-07 change does not repair that: reading the directory is
|
|
482
|
+
* evidence about PRESENCE, never about how the host resolves two copies of a
|
|
483
|
+
* name, so a host that stopped deduping is still undetected here.
|
|
404
484
|
*
|
|
405
485
|
* What actually holds: reachability survives a dedup change either way, because
|
|
406
486
|
* the global copy is delivered regardless. What is lost is only the project
|
|
407
487
|
* copy's redundancy, and nothing detects that. A real detector would have to
|
|
408
488
|
* pin the host version this measurement was taken against and re-probe when it
|
|
409
489
|
* moves — not built here, and named as absent rather than implied away.
|
|
490
|
+
*
|
|
491
|
+
* **Flat wrappers ARE withheld — corrected 2026-09-07 after a neutral review.**
|
|
492
|
+
*
|
|
493
|
+
* A CLUSTERED command reaches Claude Code as `/cluster:sub` from a `.md` under
|
|
494
|
+
* `commands/`, and `~/.claude/commands/` carries 41 such cluster directories — so
|
|
495
|
+
* the project copy has somewhere to lose to, and this predicate withholds it.
|
|
496
|
+
*
|
|
497
|
+
* A FLAT command reaches the host as a hyphen-named wrapper under `skills/`,
|
|
498
|
+
* because the host does not register flat command FILES (probed ≤ 2.1.204).
|
|
499
|
+
*
|
|
500
|
+
* **The first version of this note then claimed `~/.claude/skills` carries NONE
|
|
501
|
+
* of those wrappers, that "nothing else delivers them", and left
|
|
502
|
+
* `generate_claude_commands` ungated on that basis. All three were wrong.**
|
|
503
|
+
* `install.ts::_apply_claude_flat_command_wrappers`, wired for every
|
|
504
|
+
* `claude-code` deploy, writes `~/.claude/skills/<slug>/SKILL.md` for every
|
|
505
|
+
* VISIBLE flat command and deletes the flat file. The claim was a snapshot of one
|
|
506
|
+
* machine whose last install had not run that pass — 53 flat `.md` files still
|
|
507
|
+
* sat in `~/.claude/commands` — presented as a property of the installer.
|
|
508
|
+
*
|
|
509
|
+
* What it would have cost: the next `agent-config install` writes ~17 wrappers
|
|
510
|
+
* globally while the generator keeps writing all 49 project wrappers, so 17 flat
|
|
511
|
+
* commands arrive TWICE per session — the duplication class ADR-236 exists to
|
|
512
|
+
* remove — and `check_single_delivery` reports a `skills` overlap the same note
|
|
513
|
+
* said could not happen.
|
|
514
|
+
*
|
|
515
|
+
* So the wrapper emitter now applies the same per-name rule as everything else:
|
|
516
|
+
* `claudeLayerHolds('skills', slug)` withholds a wrapper the host layer carries,
|
|
517
|
+
* and keeps one it does not. Fail-safe per artefact, no repo-wide switch.
|
|
518
|
+
*
|
|
519
|
+
* A number in that note was wrong too, and is corrected here rather than left to
|
|
520
|
+
* be quoted: the project layer carries **49** wrappers, not 153. `153` was
|
|
521
|
+
* transplanted from the 153-skill measurement in `hostLayerFingerprint.ts`.
|
|
522
|
+
*
|
|
523
|
+
* @param globalName the host-side name — `<cluster>/<sub>.md` or `<slug>.md`.
|
|
410
524
|
*/
|
|
411
|
-
export function
|
|
412
|
-
return
|
|
525
|
+
export function commandWithheld(globalName, home) {
|
|
526
|
+
return claudeLayerHolds('commands', globalName, home);
|
|
413
527
|
}
|
|
414
528
|
/**
|
|
415
|
-
*
|
|
529
|
+
* **The caller's early return, flagged by review and kept.**
|
|
416
530
|
*
|
|
417
531
|
* `generate_claude_project_commands` applies this predicate and then returns
|
|
418
532
|
* early when `src/domains/` is absent — BEFORE its stale-link sweep. So a tree
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* ## Why the decision moved from per-run to per-directory
|
|
6
6
|
*
|
|
7
7
|
* The filter used to sit in `condense.ts::_scoped_rule_basenames()`, which runs
|
|
8
|
-
* once per generation, so `partitionActive` — a claude-only fingerprint against
|
|
8
|
+
* once per generation, so the then-current `partitionActive` — a claude-only fingerprint against
|
|
9
9
|
* `installed.lock` — decided for every host at once. That contradicted
|
|
10
10
|
* `partitionEligibility.ts`'s own fail-safe reasoning, which refuses to withhold a
|
|
11
11
|
* cursor artefact on claude's evidence because it "would deliver it nowhere", and
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
* Four call sites consume it — the symlink emit plan, the cursor `.mdc` emitter,
|
|
33
33
|
* the windsurf emitter, the augment projector — and four sites deciding this
|
|
34
34
|
* separately is exactly how three of them came to disagree. It is in `src/install/`
|
|
35
|
-
* beside {@link
|
|
35
|
+
* beside {@link hostLayerCarries}, the predicate
|
|
36
36
|
* it composes, rather than in the 2,700-line generator that calls it.
|
|
37
37
|
*
|
|
38
38
|
* ## The classification source is the PROJECTION, not the authored tree
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
import * as fs from 'node:fs';
|
|
47
47
|
import * as os from 'node:os';
|
|
48
48
|
import * as path from 'node:path';
|
|
49
|
-
import { isExclusivelyPackageOnly
|
|
49
|
+
import { isExclusivelyPackageOnly } from './partitionEligibility.js';
|
|
50
50
|
import { hostLayerCarries, toolIdForProjectRuleDir } from './globalRuleLayers.js';
|
|
51
51
|
/**
|
|
52
52
|
* Narrow one directory's rule list to the package-only set — but only when THIS
|
|
@@ -58,10 +58,13 @@ import { hostLayerCarries, toolIdForProjectRuleDir } from './globalRuleLayers.js
|
|
|
58
58
|
*/
|
|
59
59
|
export function partitionRulesForDir(opts) {
|
|
60
60
|
const { toolDir, rules, projectRoot, rulesSource } = opts;
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
61
|
+
void projectRoot;
|
|
62
|
+
// There is no repo-wide gate above this any more (owner decision, 2026-09-07).
|
|
63
|
+
// `partitionActive` used to run first and veto every directory on one
|
|
64
|
+
// claude-only version-and-fingerprint check against `installed.lock` — the
|
|
65
|
+
// exact borrowed-evidence extrapolation this module's own header refuses. The
|
|
66
|
+
// per-directory evidence below was always the stronger test; it is now the
|
|
67
|
+
// only one.
|
|
65
68
|
const toolId = toolIdForProjectRuleDir(toolDir);
|
|
66
69
|
if (toolId === null) {
|
|
67
70
|
// An unmapped directory has no global layer this code can point at, so
|
|
@@ -3,13 +3,13 @@
|
|
|
3
3
|
"artefact_count": 625,
|
|
4
4
|
"scanner_version": "de0a22b4ac4c"
|
|
5
5
|
},
|
|
6
|
-
"generated_at": "2026-09-
|
|
6
|
+
"generated_at": "2026-09-08",
|
|
7
7
|
"package": {
|
|
8
8
|
"description": "Governed skills, rules and commands for AI coding tools (Claude Code, Cursor, Windsurf, Copilot) \u2014 every claim machine-checked, including the counts in these badges.",
|
|
9
9
|
"homepage": "https://event4u-app.github.io/agent-config",
|
|
10
10
|
"name": "@event4u/agent-config",
|
|
11
11
|
"repository": "https://github.com/event4u-app/agent-config",
|
|
12
|
-
"version": "14.
|
|
12
|
+
"version": "14.22.0"
|
|
13
13
|
},
|
|
14
14
|
"registries": [
|
|
15
15
|
{
|
package/dist/mcp/server.json
CHANGED
|
@@ -9,12 +9,12 @@
|
|
|
9
9
|
"transport": {
|
|
10
10
|
"type": "stdio"
|
|
11
11
|
},
|
|
12
|
-
"version": "14.
|
|
12
|
+
"version": "14.22.0"
|
|
13
13
|
}
|
|
14
14
|
],
|
|
15
15
|
"repository": {
|
|
16
16
|
"source": "github",
|
|
17
17
|
"url": "https://github.com/event4u-app/agent-config"
|
|
18
18
|
},
|
|
19
|
-
"version": "14.
|
|
19
|
+
"version": "14.22.0"
|
|
20
20
|
}
|