@event4u/agent-config 12.0.0 → 12.1.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/.claude-plugin/marketplace.json +1 -1
- package/CHANGELOG.md +122 -0
- package/agents/templates/.ai-council.yml.example +46 -3
- package/dist/agent-src/contexts/model-recommendations.md +6 -4
- package/dist/agent-src/rules/low-impact-corpus-privacy-floor.md +1 -0
- package/dist/agent-src/scripts/roadmap_gates.ts +30 -2
- package/dist/agent-src/scripts/update_roadmap_progress.ts +32 -1
- package/dist/agent-src/skills/roadmap-writing/SKILL.md +7 -7
- package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
- package/dist/agent-src/templates/roadmaps.md +41 -3
- package/dist/cli/registry.js +1 -0
- package/dist/cli/registry.js.map +1 -1
- package/dist/cli-delegate/chunk-K34QTSD5.js +3895 -0
- package/dist/cli-delegate/{chunk-L565YFXH.js → chunk-LKZ5DOYW.js} +557 -297
- package/dist/cli-delegate/{chunk-NN4KW4HZ.js → chunk-O52B4F5S.js} +123 -2338
- package/dist/cli-delegate/cmd_conformance.js +4 -4
- package/dist/cli-delegate/cmd_doctor.js +2 -2
- package/dist/cli-delegate/cmd_export.js +1 -1
- package/dist/cli-delegate/cmd_handoff.js +1 -1
- package/dist/cli-delegate/cmd_prune.js +1 -1
- 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/discovery/deprecation-report.md +1 -1
- package/dist/discovery/discovery-manifest.json +4 -4
- 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 +2574 -1080
- package/dist/install/install.mjs +744 -482
- package/dist/mcp/registry-manifest.json +2 -2
- package/dist/mcp/server.json +2 -2
- package/dist/mcp/server.mjs +113 -10
- package/dist/router.json +1 -1
- package/dist/scripts/_lib/model_tier.js +9 -0
- package/dist/scripts/_lib/model_tier.js.map +1 -1
- package/dist/scripts/condense.js +50 -0
- package/dist/scripts/condense.js.map +1 -1
- package/docs/MIGRATION.md +20 -1
- package/package.json +1 -1
- package/src/agent-src/scripts/roadmap_gates.ts +30 -2
- package/src/agent-src/scripts/update_roadmap_progress.ts +32 -1
- package/src/config/evaluator-budgets.json +4 -4
- package/src/config/gate-coverage.yml +39 -9
- package/src/config/gate-violation-baselines.json +6 -0
- package/src/config/hook-token-budget.json +7 -1
- package/src/config/preamble-payload-budget.json +28 -0
- package/src/scripts/_dispatch.bash +10 -0
- package/src/scripts/_lib/git_common_dir.ts +173 -0
- package/src/scripts/_lib/model_tier.ts +9 -0
- package/src/scripts/_lib/release_highlights.ts +108 -7
- package/src/scripts/_lib/skill_catalogue.ts +862 -0
- package/src/scripts/ai_council/clients.ts +182 -3
- package/src/scripts/ai_council/config.ts +16 -1
- package/src/scripts/ai_council/low_impact.ts +14 -1
- package/src/scripts/ai_council/orchestrator.ts +14 -1
- package/src/scripts/ai_council/transport_resolver.ts +32 -2
- package/src/scripts/capture_skill_catalogue.ts +185 -328
- package/src/scripts/check_branch_freshness.ts +7 -1
- package/src/scripts/check_release_published.ts +6 -2
- package/src/scripts/check_release_trunk_sync.ts +18 -2
- package/src/scripts/condense.ts +50 -1
- package/src/scripts/dispatch_r2_reviewer.ts +15 -5
- package/src/scripts/evidence_report.ts +15 -4
- package/src/scripts/hook_manifest.yaml +47 -13
- package/src/scripts/hooks/concern_registry.ts +2 -0
- package/src/scripts/hooks/orchestration_record_hook.ts +21 -0
- package/src/scripts/hooks/tool_result_bytes_hook.ts +219 -0
- package/src/scripts/hot_context_hook.ts +13 -1
- package/src/scripts/install.ts +129 -0
- package/src/scripts/janitor.ts +77 -2
- package/src/scripts/lint_plan_risk_register.ts +22 -9
- package/src/scripts/lint_roadmap_blockers.ts +109 -6
- package/src/scripts/lint_scheduled_deprecations.ts +738 -0
- package/src/scripts/migration_status.ts +17 -1
- package/src/scripts/probe_review_binding_drift.ts +731 -0
- package/src/scripts/release.ts +95 -1
- package/src/scripts/schemas/command.schema.json +2 -2
- package/src/scripts/schemas/skill.schema.json +2 -1
- package/src/scripts/schemas/subagent.schema.json +2 -2
- package/src/scripts/session_eol_report.ts +81 -0
- package/src/scripts/workspace_doctor.ts +464 -0
- package/src/scripts/worktree_cleanup_check.ts +2 -1
- package/dist/cli-delegate/chunk-AYKQGIBG.js +0 -1594
package/src/scripts/release.ts
CHANGED
|
@@ -536,7 +536,7 @@ function die(msg: string, code = 2): never {
|
|
|
536
536
|
throw new SystemExitError(code);
|
|
537
537
|
}
|
|
538
538
|
|
|
539
|
-
interface RunResult {
|
|
539
|
+
export interface RunResult {
|
|
540
540
|
returncode: number;
|
|
541
541
|
stdout: string;
|
|
542
542
|
stderr: string;
|
|
@@ -1623,6 +1623,93 @@ function set_template_pin(p: string, version: string): void {
|
|
|
1623
1623
|
fs.writeFileSync(p, lines.join('\n'), 'utf-8');
|
|
1624
1624
|
}
|
|
1625
1625
|
|
|
1626
|
+
/**
|
|
1627
|
+
* Refuse a MAJOR cut that carries a scheduled deprecation due at or before it.
|
|
1628
|
+
*
|
|
1629
|
+
* **The trigger is the shape of the TARGET, not a comparison with the current
|
|
1630
|
+
* version.** A major target is `X.0.0` — and that one predicate covers every
|
|
1631
|
+
* path to a major: the `--as major` flag, an explicit `--version 13.0.0`,
|
|
1632
|
+
* auto-detection from a `feat!:` commit, AND `--resume`, where
|
|
1633
|
+
* `_detect_in_flight_target()` returns the already-bumped `package.json`
|
|
1634
|
+
* version so `target === current` and any current-vs-target comparison
|
|
1635
|
+
* silently returns. Resume was the fourth path an earlier version of this
|
|
1636
|
+
* guard missed while its own comment claimed three paths converged.
|
|
1637
|
+
*
|
|
1638
|
+
* Refusing a resumed release can strand a partially-completed one, and that is
|
|
1639
|
+
* the deliberate trade: a stranded release is recoverable by fixing the table
|
|
1640
|
+
* and resuming again, whereas a major shipped over a missed commitment is the
|
|
1641
|
+
* failure this whole surface exists to prevent.
|
|
1642
|
+
*
|
|
1643
|
+
* The target version is PASSED to the gate. Without it the gate falls back to
|
|
1644
|
+
* `package.json`, which at the cut to N still reads N-1 — so a row committed
|
|
1645
|
+
* to N reads as one major early and passes, and only rows already a major late
|
|
1646
|
+
* could ever be refused. That is the lateness being prevented, so measuring
|
|
1647
|
+
* against the shipped version would have made the refusal fire exactly one
|
|
1648
|
+
* major too late, forever.
|
|
1649
|
+
*
|
|
1650
|
+
* Runs under `--dry-run` too, unlike the rest of preflight: this check is one
|
|
1651
|
+
* subprocess reading two files, so the "keep a preview fast" rationale that
|
|
1652
|
+
* excludes the ~15s test-trend collection does not apply — and a preview that
|
|
1653
|
+
* reports green for the single condition that will refuse the real run is the
|
|
1654
|
+
* case an operator runs a preview to discover. It REPORTS there rather than
|
|
1655
|
+
* dying: `--dry-run` exiting 0 before `execute()` and before `preflight()` is a
|
|
1656
|
+
* contract this file's own tests assert, and an earlier revision of this guard
|
|
1657
|
+
* broke it by sitting above the dry-run branch with no preview mode.
|
|
1658
|
+
*
|
|
1659
|
+
* @param runner Seam for the gate invocation. Production passes nothing and
|
|
1660
|
+
* gets the real `run`; tests inject a stub, because the alternative — reaching
|
|
1661
|
+
* this branch only by mutating `docs/MIGRATION.md` — would make the refusal
|
|
1662
|
+
* path testable exclusively through a tracked-file edit.
|
|
1663
|
+
*/
|
|
1664
|
+
export function assert_scheduled_deprecations_clear(
|
|
1665
|
+
target: string,
|
|
1666
|
+
runner: (args: readonly string[]) => RunResult = (args) => run(args, { check: false, capture: true }),
|
|
1667
|
+
opts: { previewOnly?: boolean } = {},
|
|
1668
|
+
): void {
|
|
1669
|
+
const [, minor, patch] = parse_version(target);
|
|
1670
|
+
if (minor !== 0 || patch !== 0) {
|
|
1671
|
+
return;
|
|
1672
|
+
}
|
|
1673
|
+
const res = runner([
|
|
1674
|
+
'./scripts-run',
|
|
1675
|
+
'src/scripts/lint_scheduled_deprecations',
|
|
1676
|
+
'--cutting',
|
|
1677
|
+
target,
|
|
1678
|
+
]);
|
|
1679
|
+
if (res.returncode === 0) {
|
|
1680
|
+
return;
|
|
1681
|
+
}
|
|
1682
|
+
process.stderr.write(res.stdout);
|
|
1683
|
+
process.stderr.write(res.stderr);
|
|
1684
|
+
if (res.returncode !== 1) {
|
|
1685
|
+
// The gate reserves 1 for a finding and 2 for a usage/environment
|
|
1686
|
+
// failure. Diagnosing the latter as "the table has an overdue row"
|
|
1687
|
+
// sends the releaser to edit a file that is not the problem.
|
|
1688
|
+
die(
|
|
1689
|
+
`refusing the ${target} cut: the scheduled-deprecations check could not run ` +
|
|
1690
|
+
`(exit ${String(res.returncode)}). That is an environment or usage failure, not a ` +
|
|
1691
|
+
'finding in docs/MIGRATION.md — fix the invocation or the checkout, then re-run.',
|
|
1692
|
+
);
|
|
1693
|
+
}
|
|
1694
|
+
if (opts.previewOnly === true) {
|
|
1695
|
+
// The preview's job is to SHOW what the real run will refuse. Dying
|
|
1696
|
+
// here would break the `--dry-run exits 0` contract asserted elsewhere
|
|
1697
|
+
// in this file's tests — trading a documented exit code for a message
|
|
1698
|
+
// that has already been printed above.
|
|
1699
|
+
process.stderr.write(
|
|
1700
|
+
`\n(dry-run) the ${target} cut WOULD BE REFUSED for the reason above. ` +
|
|
1701
|
+
'Previewing only; exit code unchanged.\n',
|
|
1702
|
+
);
|
|
1703
|
+
return;
|
|
1704
|
+
}
|
|
1705
|
+
die(
|
|
1706
|
+
`refusing the ${target} cut: the scheduled-deprecations table in docs/MIGRATION.md ` +
|
|
1707
|
+
'has a row due at or before this major, or one that cannot be resolved. Act on ' +
|
|
1708
|
+
"it — perform the removal in its own change, or revise the row's commitment and " +
|
|
1709
|
+
'record why the surface stays — then re-run.',
|
|
1710
|
+
);
|
|
1711
|
+
}
|
|
1712
|
+
|
|
1626
1713
|
// ─── preflight ────────────────────────────────────────────────────────────────
|
|
1627
1714
|
|
|
1628
1715
|
/**
|
|
@@ -2578,6 +2665,13 @@ function main(argv: readonly string[] | null = null): number {
|
|
|
2578
2665
|
}
|
|
2579
2666
|
parse_version(target);
|
|
2580
2667
|
|
|
2668
|
+
// Runs in dry-run too — a preview that hides the one condition which will
|
|
2669
|
+
// refuse the real run is the case previews are for — but REPORTS there
|
|
2670
|
+
// instead of dying: `--dry-run returns 0` is a contract this file's tests
|
|
2671
|
+
// assert, and breaking it to surface a warning would trade a documented
|
|
2672
|
+
// exit code for a message.
|
|
2673
|
+
assert_scheduled_deprecations_clear(target, undefined, { previewOnly: args.dry_run });
|
|
2674
|
+
|
|
2581
2675
|
if (!args.dry_run) {
|
|
2582
2676
|
preflight(target, { resume: args.resume, ci: args.ci });
|
|
2583
2677
|
}
|
|
@@ -158,8 +158,8 @@
|
|
|
158
158
|
},
|
|
159
159
|
"model_tier": {
|
|
160
160
|
"type": "string",
|
|
161
|
-
"enum": ["lite", "medium", "high", "inherit"],
|
|
162
|
-
"description": "Vendor-neutral capability band the command needs (ADR-035). Commands project as Claude skills, so high/medium/lite produce a native Claude `model:`
|
|
161
|
+
"enum": ["lite", "medium", "high", "frontier", "inherit"],
|
|
162
|
+
"description": "Vendor-neutral capability band the command needs (ADR-035, amended by ADR-232). Commands project as Claude skills, so frontier/high/medium/lite produce a native Claude `model:` when model.auto_switch=auto; the generator owns that mapping. inherit keeps the session model. `frontier` is the band above the strongest generally-recommended one - opt-in and expected to stay rare. Non-Claude agents are suggestion-only. No vendor model names here."
|
|
163
163
|
},
|
|
164
164
|
"context": {
|
|
165
165
|
"type": "string",
|
|
@@ -168,9 +168,10 @@
|
|
|
168
168
|
"lite",
|
|
169
169
|
"medium",
|
|
170
170
|
"high",
|
|
171
|
+
"frontier",
|
|
171
172
|
"inherit"
|
|
172
173
|
],
|
|
173
|
-
"description": "Vendor-neutral capability band the skill needs (ADR-035). high/medium/lite project to a native Claude `model:`
|
|
174
|
+
"description": "Vendor-neutral capability band the skill needs (ADR-035, amended by ADR-232). frontier/high/medium/lite project to a native Claude `model:` when model.auto_switch=auto; the generator owns that mapping exclusively. inherit keeps the session model. `frontier` means reasoning capability above the strongest generally-recommended band - opt-in and expected to stay rare, so work that genuinely needs it says so instead of inheriting it silently. Non-Claude agents are suggestion-only - the model-recommendation rule names the tier and the agent resolves its own model. No vendor model names here."
|
|
174
175
|
},
|
|
175
176
|
"context": {
|
|
176
177
|
"type": "string",
|
|
@@ -34,8 +34,8 @@
|
|
|
34
34
|
},
|
|
35
35
|
"model_tier": {
|
|
36
36
|
"type": "string",
|
|
37
|
-
"enum": ["lite", "medium", "high", "inherit"],
|
|
38
|
-
"description": "Vendor-neutral capability band (ADR-034/035). high/medium/lite project to a native Claude `model:`
|
|
37
|
+
"enum": ["lite", "medium", "high", "frontier", "inherit"],
|
|
38
|
+
"description": "Vendor-neutral capability band (ADR-034/035, amended by ADR-232). frontier/high/medium/lite project to a native Claude `model:` via model_tier.ts; `inherit` is a documented passthrough sentinel (→ CC `model: inherit`), not a new mapping. `frontier` is the band above the strongest generally-recommended one - opt-in, expected to stay rare, and never the resolution of `inherit`."
|
|
39
39
|
},
|
|
40
40
|
"effort": {
|
|
41
41
|
"type": "string",
|
|
@@ -61,6 +61,33 @@ export interface EolReport {
|
|
|
61
61
|
compact_summary_records: number;
|
|
62
62
|
marker_drift: boolean;
|
|
63
63
|
};
|
|
64
|
+
/**
|
|
65
|
+
* State-destroyed vs state-captured, as ONE reading
|
|
66
|
+
* (road-to-inbox-harvest-2026-08-d-context-ledger Step 2.2).
|
|
67
|
+
*
|
|
68
|
+
* Before this, a compaction count and an advisory count sat in two places
|
|
69
|
+
* and nobody correlated them, so "how often was state destroyed with no
|
|
70
|
+
* capture in front of it" had no answer at all.
|
|
71
|
+
*
|
|
72
|
+
* HONEST LIMIT, stated in the shape rather than in prose only: the two
|
|
73
|
+
* sides come from different corpora — compactions are scanned out of
|
|
74
|
+
* transcripts, the advisory stamps live in per-session state files under a
|
|
75
|
+
* hashed key — and no field joins a transcript to its state file. So this
|
|
76
|
+
* is an AGGREGATE comparison over the same store, not a per-session join,
|
|
77
|
+
* and `join_basis` says so on every emitted report. A reader may compare
|
|
78
|
+
* the totals; a reader may NOT conclude that a specific compaction lacked
|
|
79
|
+
* a capture.
|
|
80
|
+
*/
|
|
81
|
+
capture: {
|
|
82
|
+
/** Session-eol state files found. `null` ⇒ the directory is absent. */
|
|
83
|
+
state_files: number | null;
|
|
84
|
+
/** State files carrying an `advisory_fired_at` stamp. */
|
|
85
|
+
advisory_fired: number;
|
|
86
|
+
/** State files that additionally recorded "advised, but no envelope". */
|
|
87
|
+
advised_without_envelope: number;
|
|
88
|
+
/** Always `"aggregate"` today. See the doc comment. */
|
|
89
|
+
join_basis: 'aggregate';
|
|
90
|
+
};
|
|
64
91
|
/** Pearson r of file bytes vs final context tokens over the readable set. */
|
|
65
92
|
bytes_tokens_pearson_r: number | null;
|
|
66
93
|
threshold_crossings: Record<string, number>;
|
|
@@ -130,6 +157,47 @@ export function scanSessionFile(file: string): SessionSummary | null {
|
|
|
130
157
|
return { file, bytes, counters, last_ts };
|
|
131
158
|
}
|
|
132
159
|
|
|
160
|
+
/** Where `session_eol_hook` persists its per-session state (gitignored). */
|
|
161
|
+
export const SESSION_EOL_STATE_REL = path.join('agents', 'runtime', 'state', 'session-eol');
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* The capture side of the Step-2.2 reading.
|
|
165
|
+
*
|
|
166
|
+
* `state_files: null` distinguishes "the directory is not there" from "it is
|
|
167
|
+
* there and empty" — an instrument that reports 0 for both cannot tell a quiet
|
|
168
|
+
* estate from one it cannot see, which is the failure the sibling ledger fixed
|
|
169
|
+
* for its own open-record set.
|
|
170
|
+
*/
|
|
171
|
+
export function scanCaptureState(root: string): EolReport['capture'] {
|
|
172
|
+
const dir = path.join(root, SESSION_EOL_STATE_REL);
|
|
173
|
+
let names: string[];
|
|
174
|
+
try {
|
|
175
|
+
names = fs.readdirSync(dir).filter((n) => n.endsWith('.json'));
|
|
176
|
+
} catch {
|
|
177
|
+
return { state_files: null, advisory_fired: 0, advised_without_envelope: 0, join_basis: 'aggregate' };
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
let advisoryFired = 0;
|
|
181
|
+
let advisedWithoutEnvelope = 0;
|
|
182
|
+
for (const name of names) {
|
|
183
|
+
try {
|
|
184
|
+
const parsed: unknown = JSON.parse(fs.readFileSync(path.join(dir, name), 'utf-8'));
|
|
185
|
+
if (typeof parsed !== 'object' || parsed === null) continue;
|
|
186
|
+
const rec = parsed as Record<string, unknown>;
|
|
187
|
+
if (typeof rec['advisory_fired_at'] === 'string') advisoryFired++;
|
|
188
|
+
if (typeof rec['missing_envelope_warned_at'] === 'string') advisedWithoutEnvelope++;
|
|
189
|
+
} catch {
|
|
190
|
+
// A torn or hand-edited state file is data we do not have.
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
return {
|
|
194
|
+
state_files: names.length,
|
|
195
|
+
advisory_fired: advisoryFired,
|
|
196
|
+
advised_without_envelope: advisedWithoutEnvelope,
|
|
197
|
+
join_basis: 'aggregate',
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
|
|
133
201
|
export function buildReport(root: string, now: Date = new Date()): EolReport {
|
|
134
202
|
const files = listTranscriptFiles({ root });
|
|
135
203
|
const sessions: SessionSummary[] = [];
|
|
@@ -176,6 +244,7 @@ export function buildReport(root: string, now: Date = new Date()): EolReport {
|
|
|
176
244
|
compact_summary_records: summaryRecords,
|
|
177
245
|
marker_drift: summaryRecords !== allEvents.length,
|
|
178
246
|
},
|
|
247
|
+
capture: scanCaptureState(root),
|
|
179
248
|
bytes_tokens_pearson_r: pearson(
|
|
180
249
|
withUsage
|
|
181
250
|
.filter((s) => (s.counters.final_context_tokens as number) > 1_000)
|
|
@@ -216,6 +285,18 @@ export function renderText(r: EolReport): string {
|
|
|
216
285
|
` trigger pre-tokens: min=${fmt(c.pre_tokens.min)} median=${fmt(c.pre_tokens.median)} max=${fmt(c.pre_tokens.max)}`,
|
|
217
286
|
);
|
|
218
287
|
}
|
|
288
|
+
// Step 2.2: the capture side, printed directly under the destruction side
|
|
289
|
+
// so the two are read together. `join_basis` is printed every time — a
|
|
290
|
+
// reader must not mistake an aggregate comparison for a per-session join.
|
|
291
|
+
const cap = r.capture;
|
|
292
|
+
if (cap.state_files === null) {
|
|
293
|
+
lines.push(` capture: no session-eol state directory — capture side UNOBSERVED (not zero)`);
|
|
294
|
+
} else {
|
|
295
|
+
lines.push(
|
|
296
|
+
` capture: ${cap.advisory_fired} of ${cap.state_files} state file(s) advised, ` +
|
|
297
|
+
`${cap.advised_without_envelope} advised with no envelope [join: ${cap.join_basis}]`,
|
|
298
|
+
);
|
|
299
|
+
}
|
|
219
300
|
if (c.post_tokens) {
|
|
220
301
|
lines.push(` post-tokens median=${fmt(c.post_tokens.median)}`);
|
|
221
302
|
}
|