@event4u/agent-config 9.33.0 → 9.35.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 +154 -145
- package/CONTRIBUTING.md +23 -14
- package/dist/agent-src/commands/agent-handoff.md +15 -3
- package/dist/agent-src/commands/roadmap/next.md +37 -5
- package/dist/agent-src/scripts/archive_completed_roadmaps.ts +35 -1
- package/dist/agent-src/scripts/roadmap_gates.ts +119 -4
- package/dist/agent-src/skills/corpus-grounding/SKILL.md +21 -12
- package/dist/agent-src/skills/design-tokens/SKILL.md +15 -0
- package/dist/agent-src/skills/react-shadcn-ui/SKILL.md +24 -0
- package/dist/agent-src/skills/rule-writing/SKILL.md +23 -0
- package/dist/agent-src/skills/skill-writing/SKILL.md +80 -2
- package/dist/agent-src/skills/systematic-debugging/SKILL.md +5 -3
- package/dist/agent-src/skills/tailwind-engineer/SKILL.md +24 -0
- package/dist/agent-src/skills/testing-anti-patterns/SKILL.md +25 -0
- package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
- package/dist/agent-src/templates/scripts/memory_lookup.ts +1 -2
- package/dist/agent-src/templates/scripts/memory_signal.ts +2 -4
- package/dist/agent-src/templates/scripts/work_engine/hooks/builtin/decision_gate.ts +35 -5
- package/dist/agent-src/templates/scripts/work_engine/hooks/builtin/staged_confirmation.ts +252 -0
- package/dist/agent-src/templates/scripts/work_engine/hooks/builtin/staged_confirmation_store.ts +307 -0
- package/dist/cli/registry.js +2 -2
- package/dist/cli/registry.js.map +1 -1
- package/dist/cli-delegate/{chunk-PMQ6Z3T3.js → chunk-2TGMGLBL.js} +11 -4
- package/dist/cli-delegate/{chunk-YPAWXXXR.js → chunk-55RI5UXK.js} +17 -0
- package/dist/cli-delegate/{chunk-MA4GFWDY.js → chunk-H6F2CQFI.js} +1 -1
- package/dist/cli-delegate/{chunk-2WELHO3P.js → chunk-I5EAFRII.js} +35 -0
- package/dist/cli-delegate/{chunk-3EWYC3YK.js → chunk-UEZ7D35A.js} +4 -3
- package/dist/cli-delegate/{chunk-UVKNIJH2.js → chunk-ZAXH3ZWU.js} +3 -0
- package/dist/cli-delegate/cmd_conformance.js +2 -2
- package/dist/cli-delegate/cmd_doctor.js +2 -2
- package/dist/cli-delegate/cmd_export.js +2 -2
- package/dist/cli-delegate/cmd_handoff.js +3 -3
- package/dist/cli-delegate/cmd_memory_get.js +1 -1
- package/dist/cli-delegate/cmd_prune.js +2 -2
- package/dist/cli-delegate/cmd_route_audit.js +1 -1
- package/dist/cli-delegate/cmd_session_recycle.js +7 -2
- package/dist/cli-delegate/cmd_settings_migrate.js +2 -2
- package/dist/cli-delegate/cmd_settings_set.js +1 -1
- package/dist/cli-delegate/cmd_sync.js +2 -2
- package/dist/cli-delegate/cmd_uninstall.js +2 -2
- package/dist/cli-delegate/cmd_validate.js +2 -2
- package/dist/discovery/deprecation-report.md +1 -1
- package/dist/discovery/discovery-manifest.json +13 -13
- package/dist/discovery/discovery-manifest.json.sha256 +1 -1
- package/dist/discovery/discovery-manifest.summary.md +2 -2
- package/dist/discovery/dormancy-report.md +17 -0
- package/dist/discovery/orphan-report.md +1 -1
- package/dist/discovery/packs.json +3 -3
- package/dist/discovery/trust-report.md +1 -1
- package/dist/discovery/workspaces.json +3 -3
- package/dist/hooks/dispatch.js +355 -85
- package/dist/install/install.mjs +3 -0
- package/dist/mcp/registry-manifest.json +3 -3
- package/dist/mcp/server.json +2 -2
- package/dist/mcp/server.mjs +192 -12
- package/dist/server/schemas/settings.js +1 -0
- package/dist/server/schemas/settings.js.map +1 -1
- package/docs/contracts/settings-classes.md +3 -2
- package/docs/guidelines/agent-infra/failure-signatures.md +47 -12
- package/package.json +2 -2
- package/src/agent-src/scripts/archive_completed_roadmaps.ts +35 -1
- package/src/agent-src/scripts/roadmap_gates.ts +119 -4
- package/src/agent-src/templates/scripts/memory_lookup.ts +1 -2
- package/src/agent-src/templates/scripts/memory_signal.ts +2 -4
- package/src/agent-src/templates/scripts/work_engine/hooks/builtin/decision_gate.ts +35 -5
- package/src/agent-src/templates/scripts/work_engine/hooks/builtin/staged_confirmation.ts +252 -0
- package/src/agent-src/templates/scripts/work_engine/hooks/builtin/staged_confirmation_store.ts +307 -0
- package/src/config/agent-settings.template.yml +11 -2
- package/src/config/quorum-attendance-budget.json +11 -3
- package/src/scripts/_cli/cmd_session_recycle.ts +6 -1
- package/src/scripts/_dispatch.bash +6 -2
- package/src/scripts/_lib/env_kill_switch.ts +37 -0
- package/src/scripts/_lib/security_lint.ts +18 -4
- package/src/scripts/_lib/self_repair.ts +60 -0
- package/src/scripts/_lib/self_repair_store.ts +65 -5
- package/src/scripts/_lib/session_register.ts +67 -1
- package/src/scripts/_lib/subagent_capsule.ts +78 -1
- package/src/scripts/ai_council/config.ts +60 -0
- package/src/scripts/ai_council/events_log.ts +105 -6
- package/src/scripts/ai_council/orchestrator.ts +38 -0
- package/src/scripts/ai_council/prompts.ts +165 -3
- package/src/scripts/ai_council/quorum.ts +87 -0
- package/src/scripts/ai_team/review_gate.ts +2 -2
- package/src/scripts/build_discovery_manifest.ts +165 -0
- package/src/scripts/check_claims.ts +51 -2
- package/src/scripts/ci_time_ratio.ts +3 -1
- package/src/scripts/council_cli.ts +36 -1
- package/src/scripts/discovery_graph.ts +201 -27
- package/src/scripts/dispatch_r2_reviewer.ts +102 -1
- package/src/scripts/hooks/turn_end_gate_hook.ts +172 -11
- package/src/scripts/lint_framework_leakage.ts +195 -28
- package/src/scripts/lint_framework_leakage_allowlist.json +94 -86
- package/src/scripts/lint_handoffs.ts +92 -2
- package/src/scripts/lint_hedge_words.ts +317 -0
- package/src/scripts/lint_mcp_config_security.ts +1 -1
- package/src/scripts/lint_skill_frontmatter_safety.ts +1 -1
- package/src/scripts/memory_lookup.ts +1 -2
- package/src/scripts/schemas/command.schema.json +4 -0
- package/src/scripts/schemas/skill.schema.json +4 -0
- package/src/scripts/self_repair_cli.ts +26 -1
- package/src/scripts/session_register_hook.ts +238 -18
- package/src/scripts/sessions_cli.ts +377 -12
- package/src/scripts/skill_linter.ts +58 -2
- package/src/server/schemas/settings.ts +3 -0
package/dist/hooks/dispatch.js
CHANGED
|
@@ -3996,10 +3996,10 @@ var require_resolve_block_map = __commonJS({
|
|
|
3996
3996
|
let offset = bm.offset;
|
|
3997
3997
|
let commentEnd = null;
|
|
3998
3998
|
for (const collItem of bm.items) {
|
|
3999
|
-
const { start, key, sep:
|
|
3999
|
+
const { start, key, sep: sep7, value } = collItem;
|
|
4000
4000
|
const keyProps = resolveProps.resolveProps(start, {
|
|
4001
4001
|
indicator: "explicit-key-ind",
|
|
4002
|
-
next: key ??
|
|
4002
|
+
next: key ?? sep7?.[0],
|
|
4003
4003
|
offset,
|
|
4004
4004
|
onError,
|
|
4005
4005
|
parentIndent: bm.indent,
|
|
@@ -4013,7 +4013,7 @@ var require_resolve_block_map = __commonJS({
|
|
|
4013
4013
|
else if ("indent" in key && key.indent !== bm.indent)
|
|
4014
4014
|
onError(offset, "BAD_INDENT", startColMsg);
|
|
4015
4015
|
}
|
|
4016
|
-
if (!keyProps.anchor && !keyProps.tag && !
|
|
4016
|
+
if (!keyProps.anchor && !keyProps.tag && !sep7) {
|
|
4017
4017
|
commentEnd = keyProps.end;
|
|
4018
4018
|
if (keyProps.comment) {
|
|
4019
4019
|
if (map.comment)
|
|
@@ -4037,7 +4037,7 @@ var require_resolve_block_map = __commonJS({
|
|
|
4037
4037
|
ctx.atKey = false;
|
|
4038
4038
|
if (utilMapIncludes.mapIncludes(ctx, map.items, keyNode))
|
|
4039
4039
|
onError(keyStart, "DUPLICATE_KEY", "Map keys must be unique");
|
|
4040
|
-
const valueProps = resolveProps.resolveProps(
|
|
4040
|
+
const valueProps = resolveProps.resolveProps(sep7 ?? [], {
|
|
4041
4041
|
indicator: "map-value-ind",
|
|
4042
4042
|
next: value,
|
|
4043
4043
|
offset: keyNode.range[2],
|
|
@@ -4053,7 +4053,7 @@ var require_resolve_block_map = __commonJS({
|
|
|
4053
4053
|
if (ctx.options.strict && keyProps.start < valueProps.found.offset - 1024)
|
|
4054
4054
|
onError(keyNode.range, "KEY_OVER_1024_CHARS", "The : indicator must be at most 1024 chars after the start of an implicit block mapping key");
|
|
4055
4055
|
}
|
|
4056
|
-
const valueNode = value ? composeNode(ctx, value, valueProps, onError) : composeEmptyNode(ctx, offset,
|
|
4056
|
+
const valueNode = value ? composeNode(ctx, value, valueProps, onError) : composeEmptyNode(ctx, offset, sep7, null, valueProps, onError);
|
|
4057
4057
|
if (ctx.schema.compat)
|
|
4058
4058
|
utilFlowIndentCheck.flowIndentCheck(bm.indent, value, onError);
|
|
4059
4059
|
offset = valueNode.range[2];
|
|
@@ -4144,7 +4144,7 @@ var require_resolve_end = __commonJS({
|
|
|
4144
4144
|
let comment = "";
|
|
4145
4145
|
if (end) {
|
|
4146
4146
|
let hasSpace = false;
|
|
4147
|
-
let
|
|
4147
|
+
let sep7 = "";
|
|
4148
4148
|
for (const token of end) {
|
|
4149
4149
|
const { source, type } = token;
|
|
4150
4150
|
switch (type) {
|
|
@@ -4158,13 +4158,13 @@ var require_resolve_end = __commonJS({
|
|
|
4158
4158
|
if (!comment)
|
|
4159
4159
|
comment = cb;
|
|
4160
4160
|
else
|
|
4161
|
-
comment +=
|
|
4162
|
-
|
|
4161
|
+
comment += sep7 + cb;
|
|
4162
|
+
sep7 = "";
|
|
4163
4163
|
break;
|
|
4164
4164
|
}
|
|
4165
4165
|
case "newline":
|
|
4166
4166
|
if (comment)
|
|
4167
|
-
|
|
4167
|
+
sep7 += source;
|
|
4168
4168
|
hasSpace = true;
|
|
4169
4169
|
break;
|
|
4170
4170
|
default:
|
|
@@ -4207,18 +4207,18 @@ var require_resolve_flow_collection = __commonJS({
|
|
|
4207
4207
|
let offset = fc.offset + fc.start.source.length;
|
|
4208
4208
|
for (let i = 0; i < fc.items.length; ++i) {
|
|
4209
4209
|
const collItem = fc.items[i];
|
|
4210
|
-
const { start, key, sep:
|
|
4210
|
+
const { start, key, sep: sep7, value } = collItem;
|
|
4211
4211
|
const props = resolveProps.resolveProps(start, {
|
|
4212
4212
|
flow: fcName,
|
|
4213
4213
|
indicator: "explicit-key-ind",
|
|
4214
|
-
next: key ??
|
|
4214
|
+
next: key ?? sep7?.[0],
|
|
4215
4215
|
offset,
|
|
4216
4216
|
onError,
|
|
4217
4217
|
parentIndent: fc.indent,
|
|
4218
4218
|
startOnNewline: false
|
|
4219
4219
|
});
|
|
4220
4220
|
if (!props.found) {
|
|
4221
|
-
if (!props.anchor && !props.tag && !
|
|
4221
|
+
if (!props.anchor && !props.tag && !sep7 && !value) {
|
|
4222
4222
|
if (i === 0 && props.comma)
|
|
4223
4223
|
onError(props.comma, "UNEXPECTED_TOKEN", `Unexpected , in ${fcName}`);
|
|
4224
4224
|
else if (i < fc.items.length - 1)
|
|
@@ -4272,8 +4272,8 @@ var require_resolve_flow_collection = __commonJS({
|
|
|
4272
4272
|
}
|
|
4273
4273
|
}
|
|
4274
4274
|
}
|
|
4275
|
-
if (!isMap && !
|
|
4276
|
-
const valueNode = value ? composeNode(ctx, value, props, onError) : composeEmptyNode(ctx, props.end,
|
|
4275
|
+
if (!isMap && !sep7 && !props.found) {
|
|
4276
|
+
const valueNode = value ? composeNode(ctx, value, props, onError) : composeEmptyNode(ctx, props.end, sep7, null, props, onError);
|
|
4277
4277
|
coll.items.push(valueNode);
|
|
4278
4278
|
offset = valueNode.range[2];
|
|
4279
4279
|
if (isBlock(value))
|
|
@@ -4285,7 +4285,7 @@ var require_resolve_flow_collection = __commonJS({
|
|
|
4285
4285
|
if (isBlock(key))
|
|
4286
4286
|
onError(keyNode.range, "BLOCK_IN_FLOW", blockMsg);
|
|
4287
4287
|
ctx.atKey = false;
|
|
4288
|
-
const valueProps = resolveProps.resolveProps(
|
|
4288
|
+
const valueProps = resolveProps.resolveProps(sep7 ?? [], {
|
|
4289
4289
|
flow: fcName,
|
|
4290
4290
|
indicator: "map-value-ind",
|
|
4291
4291
|
next: value,
|
|
@@ -4296,8 +4296,8 @@ var require_resolve_flow_collection = __commonJS({
|
|
|
4296
4296
|
});
|
|
4297
4297
|
if (valueProps.found) {
|
|
4298
4298
|
if (!isMap && !props.found && ctx.options.strict) {
|
|
4299
|
-
if (
|
|
4300
|
-
for (const st of
|
|
4299
|
+
if (sep7)
|
|
4300
|
+
for (const st of sep7) {
|
|
4301
4301
|
if (st === valueProps.found)
|
|
4302
4302
|
break;
|
|
4303
4303
|
if (st.type === "newline") {
|
|
@@ -4314,7 +4314,7 @@ var require_resolve_flow_collection = __commonJS({
|
|
|
4314
4314
|
else
|
|
4315
4315
|
onError(valueProps.start, "MISSING_CHAR", `Missing , or : between ${fcName} items`);
|
|
4316
4316
|
}
|
|
4317
|
-
const valueNode = value ? composeNode(ctx, value, valueProps, onError) : valueProps.found ? composeEmptyNode(ctx, valueProps.end,
|
|
4317
|
+
const valueNode = value ? composeNode(ctx, value, valueProps, onError) : valueProps.found ? composeEmptyNode(ctx, valueProps.end, sep7, null, valueProps, onError) : null;
|
|
4318
4318
|
if (valueNode) {
|
|
4319
4319
|
if (isBlock(value))
|
|
4320
4320
|
onError(valueNode.range, "BLOCK_IN_FLOW", blockMsg);
|
|
@@ -4494,7 +4494,7 @@ var require_resolve_block_scalar = __commonJS({
|
|
|
4494
4494
|
chompStart = i + 1;
|
|
4495
4495
|
}
|
|
4496
4496
|
let value = "";
|
|
4497
|
-
let
|
|
4497
|
+
let sep7 = "";
|
|
4498
4498
|
let prevMoreIndented = false;
|
|
4499
4499
|
for (let i = 0; i < contentStart; ++i)
|
|
4500
4500
|
value += lines[i][0].slice(trimIndent) + "\n";
|
|
@@ -4511,24 +4511,24 @@ var require_resolve_block_scalar = __commonJS({
|
|
|
4511
4511
|
indent = "";
|
|
4512
4512
|
}
|
|
4513
4513
|
if (type === Scalar.Scalar.BLOCK_LITERAL) {
|
|
4514
|
-
value +=
|
|
4515
|
-
|
|
4514
|
+
value += sep7 + indent.slice(trimIndent) + content;
|
|
4515
|
+
sep7 = "\n";
|
|
4516
4516
|
} else if (indent.length > trimIndent || content[0] === " ") {
|
|
4517
|
-
if (
|
|
4518
|
-
|
|
4519
|
-
else if (!prevMoreIndented &&
|
|
4520
|
-
|
|
4521
|
-
value +=
|
|
4522
|
-
|
|
4517
|
+
if (sep7 === " ")
|
|
4518
|
+
sep7 = "\n";
|
|
4519
|
+
else if (!prevMoreIndented && sep7 === "\n")
|
|
4520
|
+
sep7 = "\n\n";
|
|
4521
|
+
value += sep7 + indent.slice(trimIndent) + content;
|
|
4522
|
+
sep7 = "\n";
|
|
4523
4523
|
prevMoreIndented = true;
|
|
4524
4524
|
} else if (content === "") {
|
|
4525
|
-
if (
|
|
4525
|
+
if (sep7 === "\n")
|
|
4526
4526
|
value += "\n";
|
|
4527
4527
|
else
|
|
4528
|
-
|
|
4528
|
+
sep7 = "\n";
|
|
4529
4529
|
} else {
|
|
4530
|
-
value +=
|
|
4531
|
-
|
|
4530
|
+
value += sep7 + content;
|
|
4531
|
+
sep7 = " ";
|
|
4532
4532
|
prevMoreIndented = false;
|
|
4533
4533
|
}
|
|
4534
4534
|
}
|
|
@@ -4710,25 +4710,25 @@ var require_resolve_flow_scalar = __commonJS({
|
|
|
4710
4710
|
if (!match)
|
|
4711
4711
|
return source;
|
|
4712
4712
|
let res = match[1];
|
|
4713
|
-
let
|
|
4713
|
+
let sep7 = " ";
|
|
4714
4714
|
let pos = first.lastIndex;
|
|
4715
4715
|
line.lastIndex = pos;
|
|
4716
4716
|
while (match = line.exec(source)) {
|
|
4717
4717
|
if (match[1] === "") {
|
|
4718
|
-
if (
|
|
4719
|
-
res +=
|
|
4718
|
+
if (sep7 === "\n")
|
|
4719
|
+
res += sep7;
|
|
4720
4720
|
else
|
|
4721
|
-
|
|
4721
|
+
sep7 = "\n";
|
|
4722
4722
|
} else {
|
|
4723
|
-
res +=
|
|
4724
|
-
|
|
4723
|
+
res += sep7 + match[1];
|
|
4724
|
+
sep7 = " ";
|
|
4725
4725
|
}
|
|
4726
4726
|
pos = line.lastIndex;
|
|
4727
4727
|
}
|
|
4728
4728
|
const last = /[ \t]*(.*)/sy;
|
|
4729
4729
|
last.lastIndex = pos;
|
|
4730
4730
|
match = last.exec(source);
|
|
4731
|
-
return res +
|
|
4731
|
+
return res + sep7 + (match?.[1] ?? "");
|
|
4732
4732
|
}
|
|
4733
4733
|
function doubleQuotedValue(source, onError) {
|
|
4734
4734
|
let res = "";
|
|
@@ -5538,14 +5538,14 @@ var require_cst_stringify = __commonJS({
|
|
|
5538
5538
|
}
|
|
5539
5539
|
}
|
|
5540
5540
|
}
|
|
5541
|
-
function stringifyItem({ start, key, sep:
|
|
5541
|
+
function stringifyItem({ start, key, sep: sep7, value }) {
|
|
5542
5542
|
let res = "";
|
|
5543
5543
|
for (const st of start)
|
|
5544
5544
|
res += st.source;
|
|
5545
5545
|
if (key)
|
|
5546
5546
|
res += stringifyToken(key);
|
|
5547
|
-
if (
|
|
5548
|
-
for (const st of
|
|
5547
|
+
if (sep7)
|
|
5548
|
+
for (const st of sep7)
|
|
5549
5549
|
res += st.source;
|
|
5550
5550
|
if (value)
|
|
5551
5551
|
res += stringifyToken(value);
|
|
@@ -6712,18 +6712,18 @@ var require_parser = __commonJS({
|
|
|
6712
6712
|
if (this.type === "map-value-ind") {
|
|
6713
6713
|
const prev = getPrevProps(this.peek(2));
|
|
6714
6714
|
const start = getFirstKeyStartProps(prev);
|
|
6715
|
-
let
|
|
6715
|
+
let sep7;
|
|
6716
6716
|
if (scalar.end) {
|
|
6717
|
-
|
|
6718
|
-
|
|
6717
|
+
sep7 = scalar.end;
|
|
6718
|
+
sep7.push(this.sourceToken);
|
|
6719
6719
|
delete scalar.end;
|
|
6720
6720
|
} else
|
|
6721
|
-
|
|
6721
|
+
sep7 = [this.sourceToken];
|
|
6722
6722
|
const map = {
|
|
6723
6723
|
type: "block-map",
|
|
6724
6724
|
offset: scalar.offset,
|
|
6725
6725
|
indent: scalar.indent,
|
|
6726
|
-
items: [{ start, key: scalar, sep:
|
|
6726
|
+
items: [{ start, key: scalar, sep: sep7 }]
|
|
6727
6727
|
};
|
|
6728
6728
|
this.onKeyLine = true;
|
|
6729
6729
|
this.stack[this.stack.length - 1] = map;
|
|
@@ -6876,15 +6876,15 @@ var require_parser = __commonJS({
|
|
|
6876
6876
|
} else if (isFlowToken(it.key) && !includesToken(it.sep, "newline")) {
|
|
6877
6877
|
const start2 = getFirstKeyStartProps(it.start);
|
|
6878
6878
|
const key = it.key;
|
|
6879
|
-
const
|
|
6880
|
-
|
|
6879
|
+
const sep7 = it.sep;
|
|
6880
|
+
sep7.push(this.sourceToken);
|
|
6881
6881
|
delete it.key;
|
|
6882
6882
|
delete it.sep;
|
|
6883
6883
|
this.stack.push({
|
|
6884
6884
|
type: "block-map",
|
|
6885
6885
|
offset: this.offset,
|
|
6886
6886
|
indent: this.indent,
|
|
6887
|
-
items: [{ start: start2, key, sep:
|
|
6887
|
+
items: [{ start: start2, key, sep: sep7 }]
|
|
6888
6888
|
});
|
|
6889
6889
|
} else if (start.length > 0) {
|
|
6890
6890
|
it.sep = it.sep.concat(start, this.sourceToken);
|
|
@@ -7078,13 +7078,13 @@ var require_parser = __commonJS({
|
|
|
7078
7078
|
const prev = getPrevProps(parent);
|
|
7079
7079
|
const start = getFirstKeyStartProps(prev);
|
|
7080
7080
|
fixFlowSeqItems(fc);
|
|
7081
|
-
const
|
|
7082
|
-
|
|
7081
|
+
const sep7 = fc.end.splice(1, fc.end.length);
|
|
7082
|
+
sep7.push(this.sourceToken);
|
|
7083
7083
|
const map = {
|
|
7084
7084
|
type: "block-map",
|
|
7085
7085
|
offset: fc.offset,
|
|
7086
7086
|
indent: fc.indent,
|
|
7087
|
-
items: [{ start, key: fc, sep:
|
|
7087
|
+
items: [{ start, key: fc, sep: sep7 }]
|
|
7088
7088
|
};
|
|
7089
7089
|
this.onKeyLine = true;
|
|
7090
7090
|
this.stack[this.stack.length - 1] = map;
|
|
@@ -7993,7 +7993,7 @@ function* iter_corpus(roots = DEFAULT_SCAN_ROOTS, exts = [".md"]) {
|
|
|
7993
7993
|
function report(findings, opts) {
|
|
7994
7994
|
const check_label = opts.check_label;
|
|
7995
7995
|
if (findings.length === 0) {
|
|
7996
|
-
process.stdout.write(`\u2705 ${check_label}: clean (${_corpus_note()}).
|
|
7996
|
+
process.stdout.write(`\u2705 ${check_label}: clean (${_corpus_note(opts.scanned_roots)}).
|
|
7997
7997
|
`);
|
|
7998
7998
|
return 0;
|
|
7999
7999
|
}
|
|
@@ -8033,8 +8033,9 @@ function _pyG(n) {
|
|
|
8033
8033
|
}
|
|
8034
8034
|
return s;
|
|
8035
8035
|
}
|
|
8036
|
-
function _corpus_note() {
|
|
8037
|
-
|
|
8036
|
+
function _corpus_note(scanned_roots) {
|
|
8037
|
+
const roots = scanned_roots && scanned_roots.length > 0 ? scanned_roots : DEFAULT_SCAN_ROOTS;
|
|
8038
|
+
return "scanned " + roots.join(", ");
|
|
8038
8039
|
}
|
|
8039
8040
|
var PyFloat = class {
|
|
8040
8041
|
constructor(value) {
|
|
@@ -14035,6 +14036,11 @@ var import_yaml3 = __toESM(require_dist(), 1);
|
|
|
14035
14036
|
import * as fs14 from "node:fs";
|
|
14036
14037
|
import * as os2 from "node:os";
|
|
14037
14038
|
import * as path13 from "node:path";
|
|
14039
|
+
|
|
14040
|
+
// src/scripts/ai_council/quorum.ts
|
|
14041
|
+
var SOLO_FLOOR_MIN_PRESENT = 2;
|
|
14042
|
+
|
|
14043
|
+
// src/scripts/ai_council/config.ts
|
|
14038
14044
|
var _VALID_PROVIDERS = /* @__PURE__ */ new Set([
|
|
14039
14045
|
"anthropic",
|
|
14040
14046
|
"openai",
|
|
@@ -14341,6 +14347,9 @@ function _build_config(raw, source_path) {
|
|
|
14341
14347
|
_asDict(_getOr(raw, "cli_call_budget", {}))
|
|
14342
14348
|
);
|
|
14343
14349
|
const quorum = _build_quorum(_get(raw, "quorum", "majority"));
|
|
14350
|
+
const quorum_min_present = _build_quorum_min_present(
|
|
14351
|
+
_get(raw, "quorum_min_present", SOLO_FLOOR_MIN_PRESENT)
|
|
14352
|
+
);
|
|
14344
14353
|
const necessity_classifier = _build_necessity_classifier(
|
|
14345
14354
|
_asDict(_getOr(raw, "necessity_classifier", {}))
|
|
14346
14355
|
);
|
|
@@ -14389,6 +14398,7 @@ function _build_config(raw, source_path) {
|
|
|
14389
14398
|
consensus_scoring: consensus,
|
|
14390
14399
|
cli_call_budget,
|
|
14391
14400
|
quorum,
|
|
14401
|
+
quorum_min_present,
|
|
14392
14402
|
necessity_classifier,
|
|
14393
14403
|
model_downgrade,
|
|
14394
14404
|
debate,
|
|
@@ -15216,6 +15226,14 @@ function _build_quorum(raw) {
|
|
|
15216
15226
|
`\`quorum\`=${_pyRepr3(raw)} must be 'majority' or an integer >= 1 (got ${_pyTypeName(raw)}).`
|
|
15217
15227
|
);
|
|
15218
15228
|
}
|
|
15229
|
+
function _build_quorum_min_present(raw) {
|
|
15230
|
+
if (_isInt(raw) && raw >= 1) {
|
|
15231
|
+
return raw;
|
|
15232
|
+
}
|
|
15233
|
+
throw new CouncilConfigError(
|
|
15234
|
+
`\`quorum_min_present\`=${_pyRepr3(raw)} must be an integer >= 1 (got ${_pyTypeName(raw)}).`
|
|
15235
|
+
);
|
|
15236
|
+
}
|
|
15219
15237
|
function _build_advisor(name, cfg) {
|
|
15220
15238
|
if (!_isDict(cfg)) {
|
|
15221
15239
|
throw new CouncilConfigError(`advisors.${name}: must be a mapping.`);
|
|
@@ -16205,6 +16223,38 @@ function hasBoundaryMarker(block) {
|
|
|
16205
16223
|
// outside the datamarking while still riding in the same block.
|
|
16206
16224
|
block.trimEnd().endsWith(ENVELOPE_BOUNDARY_CLOSE);
|
|
16207
16225
|
}
|
|
16226
|
+
var DECISION_REVERSIBILITY_TAGS = ["reversible", "irreversible"];
|
|
16227
|
+
function decisionTagErrors(decisions) {
|
|
16228
|
+
if (!Array.isArray(decisions)) {
|
|
16229
|
+
return [];
|
|
16230
|
+
}
|
|
16231
|
+
const errors = [];
|
|
16232
|
+
for (const line of decisions) {
|
|
16233
|
+
if (typeof line !== "string") {
|
|
16234
|
+
continue;
|
|
16235
|
+
}
|
|
16236
|
+
const m = /\[([^\]]*)\]\s*$/.exec(line.trimEnd());
|
|
16237
|
+
if (m === null) {
|
|
16238
|
+
continue;
|
|
16239
|
+
}
|
|
16240
|
+
const inner = (m[1] ?? "").trim();
|
|
16241
|
+
const lowered = inner.toLowerCase();
|
|
16242
|
+
if (DECISION_REVERSIBILITY_TAGS.includes(lowered)) {
|
|
16243
|
+
if (inner !== lowered) {
|
|
16244
|
+
errors.push(
|
|
16245
|
+
`decisions: reversibility tag must be lower-case \u2014 got \`[${inner}]\`, expected \`[${lowered}]\``
|
|
16246
|
+
);
|
|
16247
|
+
}
|
|
16248
|
+
continue;
|
|
16249
|
+
}
|
|
16250
|
+
if (/^i?rr?ever[a-z]*[^a-z]*$/i.test(lowered)) {
|
|
16251
|
+
errors.push(
|
|
16252
|
+
`decisions: \`[${inner}]\` is not a reversibility tag \u2014 use exactly ` + DECISION_REVERSIBILITY_TAGS.map((t) => `\`[${t}]\``).join(" or ") + ", or drop the bracket"
|
|
16253
|
+
);
|
|
16254
|
+
}
|
|
16255
|
+
}
|
|
16256
|
+
return errors;
|
|
16257
|
+
}
|
|
16208
16258
|
var RECYCLE_ENVELOPE_KEYS = /* @__PURE__ */ new Set([
|
|
16209
16259
|
"capsule_version",
|
|
16210
16260
|
"variant",
|
|
@@ -16217,6 +16267,7 @@ var RECYCLE_ENVELOPE_KEYS = /* @__PURE__ */ new Set([
|
|
|
16217
16267
|
"not_carried_forward",
|
|
16218
16268
|
"decisions",
|
|
16219
16269
|
"constraints",
|
|
16270
|
+
"do_not_touch",
|
|
16220
16271
|
"open_worker_envelopes",
|
|
16221
16272
|
"artifact_paths",
|
|
16222
16273
|
"assumptions",
|
|
@@ -16269,7 +16320,9 @@ function validateRecycleEnvelope(input) {
|
|
|
16269
16320
|
checkList(errors, "remaining", e["remaining"], MAX_LINE_CHARS, true);
|
|
16270
16321
|
checkList(errors, "not_carried_forward", e["not_carried_forward"], MAX_LINE_CHARS, true);
|
|
16271
16322
|
checkList(errors, "decisions", e["decisions"], MAX_LINE_CHARS, false);
|
|
16323
|
+
errors.push(...decisionTagErrors(e["decisions"]));
|
|
16272
16324
|
checkList(errors, "constraints", e["constraints"], MAX_LINE_CHARS, false);
|
|
16325
|
+
checkList(errors, "do_not_touch", e["do_not_touch"], MAX_REF_CHARS, false);
|
|
16273
16326
|
checkList(errors, "open_worker_envelopes", e["open_worker_envelopes"], MAX_REF_CHARS, false);
|
|
16274
16327
|
checkList(errors, "artifact_paths", e["artifact_paths"], MAX_REF_CHARS, false);
|
|
16275
16328
|
checkList(errors, "suggested_skills", e["suggested_skills"], MAX_REF_CHARS, false);
|
|
@@ -18839,6 +18892,12 @@ function claude_config_dir() {
|
|
|
18839
18892
|
return env !== "" ? env : path32.join(os4.homedir(), ".claude");
|
|
18840
18893
|
}
|
|
18841
18894
|
|
|
18895
|
+
// src/scripts/_lib/env_kill_switch.ts
|
|
18896
|
+
var _OFF_VALUES = /* @__PURE__ */ new Set(["", "0", "false", "False"]);
|
|
18897
|
+
function isEnvKillSwitchActive(name) {
|
|
18898
|
+
return !_OFF_VALUES.has(process.env[name] ?? "");
|
|
18899
|
+
}
|
|
18900
|
+
|
|
18842
18901
|
// src/scripts/ai_team/config.ts
|
|
18843
18902
|
var TeamConfigError = class extends Error {
|
|
18844
18903
|
constructor(message) {
|
|
@@ -19048,8 +19107,7 @@ function circuit_breaker_notice(bound) {
|
|
|
19048
19107
|
return `\u26A0\uFE0F team review-gate circuit breaker: ${bound} consecutive BLOCK verdict(s) this session (bound: \`ai_team.review_gate.max_consecutive_blocks\`). The managed gate stops re-blocking now \u2014 you decide: review the last BLOCK reason via \`/team:status\`, fix what is real, ignore what is not. An ALLOW verdict resets the counter.`;
|
|
19049
19108
|
}
|
|
19050
19109
|
function _kill_switch_active() {
|
|
19051
|
-
|
|
19052
|
-
return !(value === "" || value === "0" || value === "false" || value === "False");
|
|
19110
|
+
return isEnvKillSwitchActive(_KILL_SWITCH_ENV);
|
|
19053
19111
|
}
|
|
19054
19112
|
function _iso_seconds_z(d) {
|
|
19055
19113
|
const pad = (n, w = 2) => String(n).padStart(w, "0");
|
|
@@ -19930,6 +19988,28 @@ function fingerprint2(defect_class, evidence) {
|
|
|
19930
19988
|
const shape = evidence.toLowerCase().replace(/\d+/g, "#").replace(/[`"'‚'„"»«]/g, "").replace(/[^a-zà-ÿ#\s]/g, " ").replace(/\s+/g, " ").trim();
|
|
19931
19989
|
return createHash4("sha256").update(`${defect_class}|${shape}`).digest("hex").slice(0, 16);
|
|
19932
19990
|
}
|
|
19991
|
+
var NEW_RECORDS_PER_SOURCE_PER_WINDOW = 20;
|
|
19992
|
+
var CREATION_WINDOW_MS = 24 * 60 * 60 * 1e3;
|
|
19993
|
+
function recentCreations(existing, source, now) {
|
|
19994
|
+
const end = Date.parse(now);
|
|
19995
|
+
if (Number.isNaN(end)) {
|
|
19996
|
+
return 0;
|
|
19997
|
+
}
|
|
19998
|
+
return existing.filter((r) => {
|
|
19999
|
+
if (r.source !== source) {
|
|
20000
|
+
return false;
|
|
20001
|
+
}
|
|
20002
|
+
const t = Date.parse(r.first_seen);
|
|
20003
|
+
return Number.isNaN(t) || end - t < CREATION_WINDOW_MS && end - t >= 0;
|
|
20004
|
+
}).length;
|
|
20005
|
+
}
|
|
20006
|
+
function creationCapReached(existing, finding, now) {
|
|
20007
|
+
const fp = fingerprint2(finding.defect_class, finding.evidence);
|
|
20008
|
+
if (existing.some((r) => r.fingerprint === fp)) {
|
|
20009
|
+
return false;
|
|
20010
|
+
}
|
|
20011
|
+
return recentCreations(existing, finding.source, now) >= NEW_RECORDS_PER_SOURCE_PER_WINDOW;
|
|
20012
|
+
}
|
|
19933
20013
|
function mergeRecord(existing, finding, now) {
|
|
19934
20014
|
const fp = fingerprint2(finding.defect_class, finding.evidence);
|
|
19935
20015
|
if (existing !== null && existing.fingerprint === fp) {
|
|
@@ -19995,7 +20075,7 @@ function listRecords(root) {
|
|
|
19995
20075
|
}
|
|
19996
20076
|
const out = [];
|
|
19997
20077
|
for (const n of names.sort()) {
|
|
19998
|
-
if (!n.endsWith(".json")) {
|
|
20078
|
+
if (!n.endsWith(".json") || n === OVERFLOW_FILE) {
|
|
19999
20079
|
continue;
|
|
20000
20080
|
}
|
|
20001
20081
|
const rec = readRecord(root, n.slice(0, -".json".length));
|
|
@@ -20009,9 +20089,35 @@ function listRecords(root) {
|
|
|
20009
20089
|
function openRecords(root) {
|
|
20010
20090
|
return listRecords(root).filter((r) => r.status === "open");
|
|
20011
20091
|
}
|
|
20092
|
+
var OVERFLOW_FILE = "_overflow.json";
|
|
20093
|
+
function overflowPath(root) {
|
|
20094
|
+
return path38.join(storeDir(root), OVERFLOW_FILE);
|
|
20095
|
+
}
|
|
20096
|
+
function readOverflow(root) {
|
|
20097
|
+
try {
|
|
20098
|
+
const parsed = JSON.parse(fs37.readFileSync(overflowPath(root), "utf-8"));
|
|
20099
|
+
return typeof parsed === "object" && parsed !== null ? parsed : {};
|
|
20100
|
+
} catch {
|
|
20101
|
+
return {};
|
|
20102
|
+
}
|
|
20103
|
+
}
|
|
20104
|
+
function bumpOverflow(root, source, now) {
|
|
20105
|
+
const counts = readOverflow(root);
|
|
20106
|
+
const prev = counts[source]?.dropped ?? 0;
|
|
20107
|
+
counts[source] = { dropped: prev + 1, last_seen: now };
|
|
20108
|
+
const dir = storeDir(root);
|
|
20109
|
+
fs37.mkdirSync(dir, { recursive: true });
|
|
20110
|
+
fs37.writeFileSync(overflowPath(root), `${JSON.stringify(counts, null, 2)}
|
|
20111
|
+
`, "utf-8");
|
|
20112
|
+
}
|
|
20012
20113
|
function upsertFinding(root, finding, now) {
|
|
20013
20114
|
const fp = fingerprint2(finding.defect_class, finding.evidence);
|
|
20014
|
-
const
|
|
20115
|
+
const existing = readRecord(root, fp);
|
|
20116
|
+
if (existing === null && creationCapReached(listRecords(root), finding, now)) {
|
|
20117
|
+
bumpOverflow(root, finding.source, now);
|
|
20118
|
+
return null;
|
|
20119
|
+
}
|
|
20120
|
+
const merged = mergeRecord(existing, finding, now);
|
|
20015
20121
|
writeRecord(root, merged);
|
|
20016
20122
|
return merged;
|
|
20017
20123
|
}
|
|
@@ -20405,35 +20511,109 @@ function foreign_live_records(dir, session_id, options = {}) {
|
|
|
20405
20511
|
const own = safe_stem(session_id);
|
|
20406
20512
|
return read_live_records(dir, options).filter((r) => safe_stem(r.session_id) !== own);
|
|
20407
20513
|
}
|
|
20514
|
+
function classify_collisions(others, here) {
|
|
20515
|
+
const out = [];
|
|
20516
|
+
for (const r of others) {
|
|
20517
|
+
if (here.roadmap_slug !== null && r.roadmap_slug !== null && r.roadmap_slug === here.roadmap_slug) {
|
|
20518
|
+
out.push({ kind: "roadmap", record: r });
|
|
20519
|
+
}
|
|
20520
|
+
}
|
|
20521
|
+
for (const r of others) {
|
|
20522
|
+
if (here.branch !== null && r.branch === here.branch) {
|
|
20523
|
+
out.push({ kind: "branch", record: r });
|
|
20524
|
+
}
|
|
20525
|
+
}
|
|
20526
|
+
return out;
|
|
20527
|
+
}
|
|
20408
20528
|
|
|
20409
20529
|
// src/scripts/session_register_hook.ts
|
|
20410
20530
|
var REPLAY_ENV_VAR6 = "AGENT_CONFIG_REPLAY";
|
|
20411
|
-
var
|
|
20531
|
+
var _STATE_REL = path42.join("agents", "runtime", "state");
|
|
20532
|
+
var ROADMAP_CLAIM_REL = path42.join(_STATE_REL, "roadmap-claim.json");
|
|
20533
|
+
function roadmap_claim_rel(session_id) {
|
|
20534
|
+
const id = String(session_id ?? "").trim();
|
|
20535
|
+
if (id === "") {
|
|
20536
|
+
return ROADMAP_CLAIM_REL;
|
|
20537
|
+
}
|
|
20538
|
+
const rel = path42.join(_STATE_REL, `roadmap-claim-${safe_stem(id)}.json`);
|
|
20539
|
+
const norm = path42.normalize(rel);
|
|
20540
|
+
if (!norm.startsWith(`${_STATE_REL}${path42.sep}`) || norm.includes("..")) {
|
|
20541
|
+
return ROADMAP_CLAIM_REL;
|
|
20542
|
+
}
|
|
20543
|
+
return norm;
|
|
20544
|
+
}
|
|
20412
20545
|
function _is_replay_mode4() {
|
|
20413
20546
|
return String(process9.env[REPLAY_ENV_VAR6] ?? "").trim() !== "";
|
|
20414
20547
|
}
|
|
20415
|
-
function
|
|
20548
|
+
function _read_claim_file(file) {
|
|
20416
20549
|
try {
|
|
20417
|
-
const
|
|
20418
|
-
|
|
20419
|
-
|
|
20420
|
-
const slug = parsed["slug"];
|
|
20421
|
-
if (typeof slug === "string" && slug.trim().length > 0) {
|
|
20422
|
-
return slug.trim();
|
|
20423
|
-
}
|
|
20550
|
+
const parsed = JSON.parse(fs41.readFileSync(file, "utf-8"));
|
|
20551
|
+
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
20552
|
+
return null;
|
|
20424
20553
|
}
|
|
20425
|
-
|
|
20554
|
+
const rec = parsed;
|
|
20555
|
+
const slug = rec["slug"];
|
|
20556
|
+
if (typeof slug !== "string" || slug.trim().length === 0) {
|
|
20557
|
+
return null;
|
|
20558
|
+
}
|
|
20559
|
+
const sid = rec["session_id"];
|
|
20560
|
+
return {
|
|
20561
|
+
slug: slug.trim(),
|
|
20562
|
+
...typeof sid === "string" && sid.trim() !== "" ? { session_id: sid.trim() } : {}
|
|
20563
|
+
};
|
|
20426
20564
|
} catch {
|
|
20427
20565
|
return null;
|
|
20428
20566
|
}
|
|
20429
20567
|
}
|
|
20568
|
+
function read_claimed_slug(workspace_root, session_id) {
|
|
20569
|
+
const own = roadmap_claim_rel(session_id);
|
|
20570
|
+
if (own !== ROADMAP_CLAIM_REL) {
|
|
20571
|
+
const mine = _read_claim_file(path42.join(workspace_root, own));
|
|
20572
|
+
if (mine !== null) {
|
|
20573
|
+
return mine.slug;
|
|
20574
|
+
}
|
|
20575
|
+
}
|
|
20576
|
+
const legacy = _read_claim_file(path42.join(workspace_root, ROADMAP_CLAIM_REL));
|
|
20577
|
+
if (legacy === null) {
|
|
20578
|
+
return null;
|
|
20579
|
+
}
|
|
20580
|
+
const id = String(session_id ?? "").trim();
|
|
20581
|
+
if (id !== "") {
|
|
20582
|
+
return null;
|
|
20583
|
+
}
|
|
20584
|
+
return legacy.slug;
|
|
20585
|
+
}
|
|
20586
|
+
function claim_is_stale(workspace_root, slug, peer_worktree) {
|
|
20587
|
+
if (slug === null || slug.trim() === "") {
|
|
20588
|
+
return false;
|
|
20589
|
+
}
|
|
20590
|
+
const base = slug.trim().replace(/\.md$/, "");
|
|
20591
|
+
const rel = path42.normalize(path42.join("agents", "roadmaps", `${base}.md`));
|
|
20592
|
+
const inside = rel.startsWith(`agents${path42.sep}roadmaps${path42.sep}`) && !rel.includes("..");
|
|
20593
|
+
if (!inside || path42.isAbsolute(base)) {
|
|
20594
|
+
return true;
|
|
20595
|
+
}
|
|
20596
|
+
const roots = [peer_worktree, workspace_root].filter(
|
|
20597
|
+
(r) => typeof r === "string" && r.trim() !== ""
|
|
20598
|
+
);
|
|
20599
|
+
for (const root of roots) {
|
|
20600
|
+
try {
|
|
20601
|
+
if (fs41.existsSync(path42.join(root, rel))) {
|
|
20602
|
+
return false;
|
|
20603
|
+
}
|
|
20604
|
+
} catch {
|
|
20605
|
+
return false;
|
|
20606
|
+
}
|
|
20607
|
+
}
|
|
20608
|
+
return true;
|
|
20609
|
+
}
|
|
20430
20610
|
function build_record(workspace_root, session_id, platform, started_at, now = /* @__PURE__ */ new Date()) {
|
|
20431
20611
|
return {
|
|
20432
20612
|
session_id,
|
|
20433
20613
|
platform,
|
|
20434
20614
|
worktree: workspace_root,
|
|
20435
20615
|
branch: current_branch(workspace_root),
|
|
20436
|
-
roadmap_slug: read_claimed_slug(workspace_root),
|
|
20616
|
+
roadmap_slug: read_claimed_slug(workspace_root, session_id),
|
|
20437
20617
|
started_at,
|
|
20438
20618
|
last_seen: iso_now(now)
|
|
20439
20619
|
};
|
|
@@ -20451,20 +20631,26 @@ function foreign_sessions_block(workspace_root, session_id, now = /* @__PURE__ *
|
|
|
20451
20631
|
const others = foreign_live_records(dir, session_id, { prune: true, now });
|
|
20452
20632
|
if (others.length === 0) return null;
|
|
20453
20633
|
const here = current_branch(workspace_root);
|
|
20634
|
+
const my_slug = read_claimed_slug(workspace_root, session_id);
|
|
20454
20635
|
const lines = [];
|
|
20455
|
-
|
|
20636
|
+
const live_others = [];
|
|
20456
20637
|
for (const r of others) {
|
|
20457
20638
|
const age_min = Math.max(0, Math.round((now.getTime() - Date.parse(r.last_seen)) / 6e4));
|
|
20458
|
-
const
|
|
20639
|
+
const stale = claim_is_stale(workspace_root, r.roadmap_slug, r.worktree);
|
|
20640
|
+
const slug = r.roadmap_slug === null ? "no roadmap claimed" : stale ? `roadmap: ${r.roadmap_slug} (STALE \u2014 no such open roadmap; treat as no claim)` : `roadmap: ${r.roadmap_slug}`;
|
|
20459
20641
|
const ttl_note = ttl_is_measured(r.platform) ? "" : ` \xB7 unmeasured host, TTL falls back to ${Math.round(ttl_seconds_for(r.platform) / 3600)}h`;
|
|
20460
20642
|
lines.push(
|
|
20461
20643
|
`- ${r.platform} \xB7 branch \`${r.branch ?? "detached"}\` \xB7 ${slug} \xB7 last seen ${age_min} min ago${ttl_note}
|
|
20462
20644
|
worktree: ${r.worktree}`
|
|
20463
20645
|
);
|
|
20464
|
-
|
|
20465
|
-
collision = r;
|
|
20466
|
-
}
|
|
20646
|
+
live_others.push(stale ? { ...r, roadmap_slug: null } : r);
|
|
20467
20647
|
}
|
|
20648
|
+
const collisions = classify_collisions(live_others, {
|
|
20649
|
+
branch: here,
|
|
20650
|
+
roadmap_slug: claim_is_stale(workspace_root, my_slug) ? null : my_slug
|
|
20651
|
+
});
|
|
20652
|
+
const roadmap_hits = collisions.filter((c) => c.kind === "roadmap");
|
|
20653
|
+
const branch_hit = collisions.find((c) => c.kind === "branch") ?? null;
|
|
20468
20654
|
const parts = [
|
|
20469
20655
|
"<session-register>",
|
|
20470
20656
|
"The following OTHER agent sessions are live on this repository right now.",
|
|
@@ -20472,7 +20658,23 @@ function foreign_sessions_block(workspace_root, session_id, now = /* @__PURE__ *
|
|
|
20472
20658
|
"",
|
|
20473
20659
|
...lines
|
|
20474
20660
|
];
|
|
20475
|
-
if (
|
|
20661
|
+
if (roadmap_hits.length > 0) {
|
|
20662
|
+
parts.push(
|
|
20663
|
+
"",
|
|
20664
|
+
`DUPLICATE WORK: ${roadmap_hits.length} other live session(s) claim the SAME roadmap \`${my_slug}\`.`,
|
|
20665
|
+
...roadmap_hits.map(
|
|
20666
|
+
(h) => ` \xB7 branch \`${h.record.branch ?? "detached"}\` in ${h.record.worktree}`
|
|
20667
|
+
),
|
|
20668
|
+
"A different branch name does NOT make this a different task \u2014 measured twice,",
|
|
20669
|
+
"two sessions built one roadmap phase under two branch names and one PR was wasted.",
|
|
20670
|
+
"STOP before writing code. Ask the user ONCE, as numbered options:",
|
|
20671
|
+
" 1. Take a different roadmap (`agent-config sessions:list` shows what is held)",
|
|
20672
|
+
" 2. Split the roadmap explicitly \u2014 name which phases are yours",
|
|
20673
|
+
" 3. Continue anyway, accepting that one of the two results is discarded",
|
|
20674
|
+
"Never decide silently, in either direction."
|
|
20675
|
+
);
|
|
20676
|
+
}
|
|
20677
|
+
if (branch_hit !== null) {
|
|
20476
20678
|
parts.push(
|
|
20477
20679
|
"",
|
|
20478
20680
|
`COLLISION: another live session already holds branch \`${here}\`.`,
|
|
@@ -20513,6 +20715,10 @@ function main25() {
|
|
|
20513
20715
|
if (event === "session_end" || event === "stop" && stop_means_session_end(platform)) {
|
|
20514
20716
|
const dir = register_dir(root);
|
|
20515
20717
|
if (dir !== null) delete_record(dir, session_id);
|
|
20718
|
+
try {
|
|
20719
|
+
fs41.unlinkSync(path42.join(root, roadmap_claim_rel(session_id)));
|
|
20720
|
+
} catch {
|
|
20721
|
+
}
|
|
20516
20722
|
return 0;
|
|
20517
20723
|
}
|
|
20518
20724
|
if (event === "session_start" || event === "user_prompt_submit" || event === "stop") {
|
|
@@ -22439,7 +22645,7 @@ import { fileURLToPath as fileURLToPath36, pathToFileURL as pathToFileURL29 } fr
|
|
|
22439
22645
|
|
|
22440
22646
|
// src/install/rtkDetection.ts
|
|
22441
22647
|
import { spawnSync as spawnSync4 } from "node:child_process";
|
|
22442
|
-
import { existsSync as
|
|
22648
|
+
import { existsSync as existsSync9, statSync as statSync9, readFileSync as readFileSync19, writeFileSync as writeFileSync8, mkdirSync as mkdirSync9 } from "node:fs";
|
|
22443
22649
|
import { homedir as homedir4 } from "node:os";
|
|
22444
22650
|
import { delimiter, join as join19, dirname as dirname9 } from "node:path";
|
|
22445
22651
|
var TOKEN_KILLER_GAIN_SIGNATURE = /RTK Token Savings/;
|
|
@@ -22452,7 +22658,7 @@ function resolveBinaryOnPath(name, pathEnv) {
|
|
|
22452
22658
|
if (dir.length === 0) continue;
|
|
22453
22659
|
for (const suffix of suffixes) {
|
|
22454
22660
|
const candidate = join19(dir, `${name}${suffix}`);
|
|
22455
|
-
if (
|
|
22661
|
+
if (existsSync9(candidate)) return candidate;
|
|
22456
22662
|
}
|
|
22457
22663
|
}
|
|
22458
22664
|
return null;
|
|
@@ -25266,6 +25472,32 @@ function detectLanguage(reply, pinned) {
|
|
|
25266
25472
|
reason: `the pinned reply language is "${pinned}" but the reply classifies as "${verdict.language}" (${verdict.de_markers} de / ${verdict.en_markers} en markers; code, quotes, tables, URLs and paths excluded, then scored lead-first by the same classifier that sets the pin)`
|
|
25267
25473
|
};
|
|
25268
25474
|
}
|
|
25475
|
+
var _EDIT_TOOLS = /* @__PURE__ */ new Set(["Edit", "Write", "MultiEdit", "NotebookEdit"]);
|
|
25476
|
+
var _VERIFY_RE = /\b(test|tests|vitest|jest|pytest|phpunit|pest|tsc|eslint|ruff|mypy|pyright|clippy|typecheck|lint|build|ci|preflight|smoke[-_:a-z]*|check[-_:a-z]*|validate[-_:a-z]*)\b|\b(task|npm|pnpm|yarn|composer|cargo|go|make|php artisan|bun)\s+(run\s+)?\S*(test|check|lint|build|ci|typecheck)/i;
|
|
25477
|
+
function isVerificationCommand(command) {
|
|
25478
|
+
return _VERIFY_RE.test(command);
|
|
25479
|
+
}
|
|
25480
|
+
function detectUnverifiedEdit(toolCalls) {
|
|
25481
|
+
let lastEdit = -1;
|
|
25482
|
+
for (let i = 0; i < toolCalls.length; i += 1) {
|
|
25483
|
+
if (_EDIT_TOOLS.has(toolCalls[i].name)) lastEdit = i;
|
|
25484
|
+
}
|
|
25485
|
+
if (lastEdit === -1) return null;
|
|
25486
|
+
for (let i = lastEdit + 1; i < toolCalls.length; i += 1) {
|
|
25487
|
+
const c = toolCalls[i];
|
|
25488
|
+
if (c.name === "Bash" && c.command !== void 0 && isVerificationCommand(c.command)) {
|
|
25489
|
+
return null;
|
|
25490
|
+
}
|
|
25491
|
+
}
|
|
25492
|
+
const edited = toolCalls[lastEdit].path;
|
|
25493
|
+
return {
|
|
25494
|
+
detector: "verification",
|
|
25495
|
+
// The path, never the diff: the evidence span is quoted into a refusal,
|
|
25496
|
+
// and `ToolCall` is shaped so a file body cannot reach it.
|
|
25497
|
+
evidence: edited ?? toolCalls[lastEdit].name,
|
|
25498
|
+
reason: "this turn changed a file and then ran no verification command \u2014 no test, type-check, lint or build call follows the last edit (verify-before-complete: a claim without a fresh run is unverified)"
|
|
25499
|
+
};
|
|
25500
|
+
}
|
|
25269
25501
|
function stateDir(workspaceRoot2) {
|
|
25270
25502
|
return path59.join(workspaceRoot2, "agents", "runtime", "state", "turn-end-gate");
|
|
25271
25503
|
}
|
|
@@ -25298,7 +25530,7 @@ function markRefusedTurn(workspaceRoot2, sessionKey, turnOrdinal, detector) {
|
|
|
25298
25530
|
}
|
|
25299
25531
|
}
|
|
25300
25532
|
function readTranscriptTail(transcriptPath, opts = {}) {
|
|
25301
|
-
const empty = { lastAssistant: "", turnOrdinal: 0 };
|
|
25533
|
+
const empty = { lastAssistant: "", turnOrdinal: 0, toolCalls: [] };
|
|
25302
25534
|
if (!transcriptPath || !isSafeTranscriptPath(transcriptPath, opts)) return empty;
|
|
25303
25535
|
let lines;
|
|
25304
25536
|
try {
|
|
@@ -25311,6 +25543,7 @@ function readTranscriptTail(transcriptPath, opts = {}) {
|
|
|
25311
25543
|
}
|
|
25312
25544
|
let lastAssistant = "";
|
|
25313
25545
|
let turnOrdinal = 0;
|
|
25546
|
+
let toolCalls = [];
|
|
25314
25547
|
for (const rawLine of lines) {
|
|
25315
25548
|
const line = rawLine.trim();
|
|
25316
25549
|
if (!line) continue;
|
|
@@ -25327,15 +25560,42 @@ function readTranscriptTail(transcriptPath, opts = {}) {
|
|
|
25327
25560
|
if (role !== "assistant" && role !== "user") continue;
|
|
25328
25561
|
const msg = entry["message"];
|
|
25329
25562
|
if (typeof msg !== "object" || msg === null || Array.isArray(msg)) continue;
|
|
25330
|
-
const
|
|
25563
|
+
const content = msg["content"];
|
|
25564
|
+
if (role === "assistant") {
|
|
25565
|
+
toolCalls.push(..._toolCalls(content));
|
|
25566
|
+
}
|
|
25567
|
+
const text = _messageText(content);
|
|
25331
25568
|
if (text === null) continue;
|
|
25332
25569
|
if (role === "assistant") {
|
|
25333
25570
|
lastAssistant = text;
|
|
25334
25571
|
} else if (!isSyntheticPrompt(text)) {
|
|
25335
25572
|
turnOrdinal += 1;
|
|
25573
|
+
toolCalls = [];
|
|
25336
25574
|
}
|
|
25337
25575
|
}
|
|
25338
|
-
return { lastAssistant: lastAssistant.trim(), turnOrdinal };
|
|
25576
|
+
return { lastAssistant: lastAssistant.trim(), turnOrdinal, toolCalls };
|
|
25577
|
+
}
|
|
25578
|
+
function _toolCalls(content) {
|
|
25579
|
+
if (!Array.isArray(content)) return [];
|
|
25580
|
+
const out = [];
|
|
25581
|
+
for (const blk of content) {
|
|
25582
|
+
if (typeof blk !== "object" || blk === null || Array.isArray(blk)) continue;
|
|
25583
|
+
const b = blk;
|
|
25584
|
+
if (b["type"] !== "tool_use") continue;
|
|
25585
|
+
const name = b["name"];
|
|
25586
|
+
if (typeof name !== "string") continue;
|
|
25587
|
+
const input = b["input"];
|
|
25588
|
+
const call = { name };
|
|
25589
|
+
if (typeof input === "object" && input !== null && !Array.isArray(input)) {
|
|
25590
|
+
const inp = input;
|
|
25591
|
+
const cmd = inp["command"];
|
|
25592
|
+
if (typeof cmd === "string") call.command = cmd;
|
|
25593
|
+
const p = inp["file_path"] ?? inp["path"] ?? inp["notebook_path"];
|
|
25594
|
+
if (typeof p === "string") call.path = p;
|
|
25595
|
+
}
|
|
25596
|
+
out.push(call);
|
|
25597
|
+
}
|
|
25598
|
+
return out;
|
|
25339
25599
|
}
|
|
25340
25600
|
function _messageText(content) {
|
|
25341
25601
|
if (typeof content === "string") return content;
|
|
@@ -25359,7 +25619,12 @@ function _isOn(v) {
|
|
|
25359
25619
|
return null;
|
|
25360
25620
|
}
|
|
25361
25621
|
function readGateSettings(workspaceRoot2) {
|
|
25362
|
-
const off = {
|
|
25622
|
+
const off = {
|
|
25623
|
+
enabled: false,
|
|
25624
|
+
promissory: true,
|
|
25625
|
+
language: true,
|
|
25626
|
+
verification: true
|
|
25627
|
+
};
|
|
25363
25628
|
let settings;
|
|
25364
25629
|
try {
|
|
25365
25630
|
settings = load_agent_settings({ cwd: workspaceRoot2 });
|
|
@@ -25378,7 +25643,8 @@ function readGateSettings(workspaceRoot2) {
|
|
|
25378
25643
|
return {
|
|
25379
25644
|
enabled: flag("enabled", false),
|
|
25380
25645
|
promissory: flag("promissory", true),
|
|
25381
|
-
language: flag("language", true)
|
|
25646
|
+
language: flag("language", true),
|
|
25647
|
+
verification: flag("verification", true)
|
|
25382
25648
|
};
|
|
25383
25649
|
}
|
|
25384
25650
|
function str4(v) {
|
|
@@ -25399,7 +25665,7 @@ function main41() {
|
|
|
25399
25665
|
const transcriptPath = str4(
|
|
25400
25666
|
payload["transcript_path"] ?? payload["transcriptPath"]
|
|
25401
25667
|
);
|
|
25402
|
-
const { lastAssistant, turnOrdinal } = readTranscriptTail(transcriptPath, {
|
|
25668
|
+
const { lastAssistant, turnOrdinal, toolCalls } = readTranscriptTail(transcriptPath, {
|
|
25403
25669
|
maxBytes: TRANSCRIPT_READ_MAX_BYTES
|
|
25404
25670
|
});
|
|
25405
25671
|
if (!lastAssistant) return EXIT_ALLOW17;
|
|
@@ -25416,6 +25682,10 @@ function main41() {
|
|
|
25416
25682
|
const f = detectLanguage(lastAssistant, readLanguagePin(workspaceRoot2));
|
|
25417
25683
|
if (f) findings.push(f);
|
|
25418
25684
|
}
|
|
25685
|
+
if (settings.verification) {
|
|
25686
|
+
const f = detectUnverifiedEdit(toolCalls);
|
|
25687
|
+
if (f) findings.push(f);
|
|
25688
|
+
}
|
|
25419
25689
|
if (findings.length === 0) return EXIT_ALLOW17;
|
|
25420
25690
|
markRefusedTurn(workspaceRoot2, sessionKey, turnOrdinal, findings[0].detector);
|
|
25421
25691
|
const lines = findings.map(
|
|
@@ -25425,7 +25695,7 @@ function main41() {
|
|
|
25425
25695
|
process.stderr.write(
|
|
25426
25696
|
`turn-end-gate: REFUSED \u2014 this turn is not finished.
|
|
25427
25697
|
${lines.join("\n")}
|
|
25428
|
-
Do the promised work now,
|
|
25698
|
+
Do the promised work now, correct the language, or run the verification the edit needs, then end the turn.
|
|
25429
25699
|
This turn will not be refused a second time.
|
|
25430
25700
|
Disable: hooks.turn_end_gate.enabled: false in .agent-settings.yml
|
|
25431
25701
|
`
|