@event4u/agent-config 14.14.0 → 14.15.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 +63 -0
- package/README.md +1 -1
- package/dist/agent-src/commands/pr/create.md +16 -1
- package/dist/agent-src/contexts/execution/terminal-states.md +25 -4
- package/dist/agent-src/rules/missing-skill-recovery.md +2 -2
- package/dist/agent-src/rules/token-budget-discipline.md +2 -2
- package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
- package/dist/cli/registry.js +1 -0
- package/dist/cli-delegate/{chunk-ILMUPLGW.js → chunk-7RXIKF62.js} +159 -86
- package/dist/cli-delegate/cmd_conformance.js +513 -17
- package/dist/cli-delegate/cmd_doctor.js +1 -1
- package/dist/discovery/deprecation-report.md +1 -1
- package/dist/discovery/discovery-manifest.json +5 -5
- 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 +1043 -390
- package/dist/mcp/registry-manifest.json +2 -2
- package/dist/mcp/server.json +2 -2
- package/dist/mcp/server.mjs +703 -115
- package/package.json +1 -1
- package/src/config/assurance-capability-registry.json +1 -1
- package/src/config/evaluator-budgets.json +4 -4
- package/src/config/gate-coverage.yml +62 -2
- package/src/config/gate-reachability-exemptions.json +1 -0
- package/src/config/gate-violation-baselines.json +4 -3
- package/src/config/rule-enforcement-baseline.json +0 -1
- package/src/config/web-launch-readiness.json +4 -2
- package/src/scripts/_cli/_doctor_emit.ts +71 -0
- package/src/scripts/_cli/_doctor_strict.ts +163 -0
- package/src/scripts/_cli/cmd_doctor.ts +16 -37
- package/src/scripts/_dispatch.bash +11 -0
- package/src/scripts/_lib/branch_convergence.ts +186 -0
- package/src/scripts/_lib/context_observation.ts +132 -0
- package/src/scripts/_lib/continuation_ladder.ts +188 -0
- package/src/scripts/_lib/experiment_binding.ts +95 -0
- package/src/scripts/_lib/ignored_blocker.ts +8 -1
- package/src/scripts/_lib/outcome_envelope.ts +6 -1
- package/src/scripts/_lib/outcome_vocabularies.ts +135 -5
- package/src/scripts/_lib/release_highlights.ts +75 -10
- package/src/scripts/_lib/repeated_failure.ts +19 -2
- package/src/scripts/_lib/runtime_journal.ts +11 -4
- package/src/scripts/check_agent_artifact_location.ts +337 -0
- package/src/scripts/check_artefact_count_messaging.ts +74 -8
- package/src/scripts/check_enforcement_coverage.ts +40 -1
- package/src/scripts/check_release_highlights.ts +17 -1
- package/src/scripts/check_web_launch_readiness.ts +310 -20
- package/src/scripts/evolution_lab.ts +53 -1
- package/src/scripts/generate_capability_matrix.ts +16 -9
- package/src/scripts/git_authorization_hook.ts +476 -6
- package/src/scripts/grade_target_readiness.ts +221 -2
- package/src/scripts/hook_effect_doctor.ts +47 -4
- package/src/scripts/hooks/block_unauthorized_git.ts +238 -9
- package/src/scripts/hooks/merge_impact.ts +207 -0
- package/src/scripts/hooks/run_continuation_hook.ts +78 -88
- package/src/scripts/hooks/session_eol_hook.ts +12 -1
- package/src/scripts/install-hooks.sh +18 -0
- package/src/scripts/lint_code_comments.ts +106 -1
- package/src/scripts/release.ts +5 -17
- package/src/scripts/release_drill.ts +76 -1
- package/src/scripts/release_env.ts +31 -0
- package/src/scripts/release_publication.ts +125 -1
- package/src/scripts/roadmap_context.ts +15 -0
- package/src/scripts/skill_scout.ts +633 -0
- package/src/scripts/sync_pr_branch.ts +521 -42
package/dist/hooks/dispatch.js
CHANGED
|
@@ -112,17 +112,17 @@ var require_visit = __commonJS({
|
|
|
112
112
|
visit.BREAK = BREAK;
|
|
113
113
|
visit.SKIP = SKIP;
|
|
114
114
|
visit.REMOVE = REMOVE;
|
|
115
|
-
function visit_(key, node, visitor,
|
|
116
|
-
const ctrl = callVisitor(key, node, visitor,
|
|
115
|
+
function visit_(key, node, visitor, path106) {
|
|
116
|
+
const ctrl = callVisitor(key, node, visitor, path106);
|
|
117
117
|
if (identity.isNode(ctrl) || identity.isPair(ctrl)) {
|
|
118
|
-
replaceNode(key,
|
|
119
|
-
return visit_(key, ctrl, visitor,
|
|
118
|
+
replaceNode(key, path106, ctrl);
|
|
119
|
+
return visit_(key, ctrl, visitor, path106);
|
|
120
120
|
}
|
|
121
121
|
if (typeof ctrl !== "symbol") {
|
|
122
122
|
if (identity.isCollection(node)) {
|
|
123
|
-
|
|
123
|
+
path106 = Object.freeze(path106.concat(node));
|
|
124
124
|
for (let i = 0; i < node.items.length; ++i) {
|
|
125
|
-
const ci = visit_(i, node.items[i], visitor,
|
|
125
|
+
const ci = visit_(i, node.items[i], visitor, path106);
|
|
126
126
|
if (typeof ci === "number")
|
|
127
127
|
i = ci - 1;
|
|
128
128
|
else if (ci === BREAK)
|
|
@@ -133,13 +133,13 @@ var require_visit = __commonJS({
|
|
|
133
133
|
}
|
|
134
134
|
}
|
|
135
135
|
} else if (identity.isPair(node)) {
|
|
136
|
-
|
|
137
|
-
const ck = visit_("key", node.key, visitor,
|
|
136
|
+
path106 = Object.freeze(path106.concat(node));
|
|
137
|
+
const ck = visit_("key", node.key, visitor, path106);
|
|
138
138
|
if (ck === BREAK)
|
|
139
139
|
return BREAK;
|
|
140
140
|
else if (ck === REMOVE)
|
|
141
141
|
node.key = null;
|
|
142
|
-
const cv = visit_("value", node.value, visitor,
|
|
142
|
+
const cv = visit_("value", node.value, visitor, path106);
|
|
143
143
|
if (cv === BREAK)
|
|
144
144
|
return BREAK;
|
|
145
145
|
else if (cv === REMOVE)
|
|
@@ -160,17 +160,17 @@ var require_visit = __commonJS({
|
|
|
160
160
|
visitAsync.BREAK = BREAK;
|
|
161
161
|
visitAsync.SKIP = SKIP;
|
|
162
162
|
visitAsync.REMOVE = REMOVE;
|
|
163
|
-
async function visitAsync_(key, node, visitor,
|
|
164
|
-
const ctrl = await callVisitor(key, node, visitor,
|
|
163
|
+
async function visitAsync_(key, node, visitor, path106) {
|
|
164
|
+
const ctrl = await callVisitor(key, node, visitor, path106);
|
|
165
165
|
if (identity.isNode(ctrl) || identity.isPair(ctrl)) {
|
|
166
|
-
replaceNode(key,
|
|
167
|
-
return visitAsync_(key, ctrl, visitor,
|
|
166
|
+
replaceNode(key, path106, ctrl);
|
|
167
|
+
return visitAsync_(key, ctrl, visitor, path106);
|
|
168
168
|
}
|
|
169
169
|
if (typeof ctrl !== "symbol") {
|
|
170
170
|
if (identity.isCollection(node)) {
|
|
171
|
-
|
|
171
|
+
path106 = Object.freeze(path106.concat(node));
|
|
172
172
|
for (let i = 0; i < node.items.length; ++i) {
|
|
173
|
-
const ci = await visitAsync_(i, node.items[i], visitor,
|
|
173
|
+
const ci = await visitAsync_(i, node.items[i], visitor, path106);
|
|
174
174
|
if (typeof ci === "number")
|
|
175
175
|
i = ci - 1;
|
|
176
176
|
else if (ci === BREAK)
|
|
@@ -181,13 +181,13 @@ var require_visit = __commonJS({
|
|
|
181
181
|
}
|
|
182
182
|
}
|
|
183
183
|
} else if (identity.isPair(node)) {
|
|
184
|
-
|
|
185
|
-
const ck = await visitAsync_("key", node.key, visitor,
|
|
184
|
+
path106 = Object.freeze(path106.concat(node));
|
|
185
|
+
const ck = await visitAsync_("key", node.key, visitor, path106);
|
|
186
186
|
if (ck === BREAK)
|
|
187
187
|
return BREAK;
|
|
188
188
|
else if (ck === REMOVE)
|
|
189
189
|
node.key = null;
|
|
190
|
-
const cv = await visitAsync_("value", node.value, visitor,
|
|
190
|
+
const cv = await visitAsync_("value", node.value, visitor, path106);
|
|
191
191
|
if (cv === BREAK)
|
|
192
192
|
return BREAK;
|
|
193
193
|
else if (cv === REMOVE)
|
|
@@ -214,23 +214,23 @@ var require_visit = __commonJS({
|
|
|
214
214
|
}
|
|
215
215
|
return visitor;
|
|
216
216
|
}
|
|
217
|
-
function callVisitor(key, node, visitor,
|
|
217
|
+
function callVisitor(key, node, visitor, path106) {
|
|
218
218
|
if (typeof visitor === "function")
|
|
219
|
-
return visitor(key, node,
|
|
219
|
+
return visitor(key, node, path106);
|
|
220
220
|
if (identity.isMap(node))
|
|
221
|
-
return visitor.Map?.(key, node,
|
|
221
|
+
return visitor.Map?.(key, node, path106);
|
|
222
222
|
if (identity.isSeq(node))
|
|
223
|
-
return visitor.Seq?.(key, node,
|
|
223
|
+
return visitor.Seq?.(key, node, path106);
|
|
224
224
|
if (identity.isPair(node))
|
|
225
|
-
return visitor.Pair?.(key, node,
|
|
225
|
+
return visitor.Pair?.(key, node, path106);
|
|
226
226
|
if (identity.isScalar(node))
|
|
227
|
-
return visitor.Scalar?.(key, node,
|
|
227
|
+
return visitor.Scalar?.(key, node, path106);
|
|
228
228
|
if (identity.isAlias(node))
|
|
229
|
-
return visitor.Alias?.(key, node,
|
|
229
|
+
return visitor.Alias?.(key, node, path106);
|
|
230
230
|
return void 0;
|
|
231
231
|
}
|
|
232
|
-
function replaceNode(key,
|
|
233
|
-
const parent =
|
|
232
|
+
function replaceNode(key, path106, node) {
|
|
233
|
+
const parent = path106[path106.length - 1];
|
|
234
234
|
if (identity.isCollection(parent)) {
|
|
235
235
|
parent.items[key] = node;
|
|
236
236
|
} else if (identity.isPair(parent)) {
|
|
@@ -840,10 +840,10 @@ var require_Collection = __commonJS({
|
|
|
840
840
|
var createNode = require_createNode();
|
|
841
841
|
var identity = require_identity();
|
|
842
842
|
var Node = require_Node();
|
|
843
|
-
function collectionFromPath(schema,
|
|
843
|
+
function collectionFromPath(schema, path106, value) {
|
|
844
844
|
let v = value;
|
|
845
|
-
for (let i =
|
|
846
|
-
const k =
|
|
845
|
+
for (let i = path106.length - 1; i >= 0; --i) {
|
|
846
|
+
const k = path106[i];
|
|
847
847
|
if (typeof k === "number" && Number.isInteger(k) && k >= 0) {
|
|
848
848
|
const a = [];
|
|
849
849
|
a[k] = v;
|
|
@@ -862,7 +862,7 @@ var require_Collection = __commonJS({
|
|
|
862
862
|
sourceObjects: /* @__PURE__ */ new Map()
|
|
863
863
|
});
|
|
864
864
|
}
|
|
865
|
-
var isEmptyPath = (
|
|
865
|
+
var isEmptyPath = (path106) => path106 == null || typeof path106 === "object" && !!path106[Symbol.iterator]().next().done;
|
|
866
866
|
var Collection = class extends Node.NodeBase {
|
|
867
867
|
constructor(type, schema) {
|
|
868
868
|
super(type);
|
|
@@ -892,11 +892,11 @@ var require_Collection = __commonJS({
|
|
|
892
892
|
* be a Pair instance or a `{ key, value }` object, which may not have a key
|
|
893
893
|
* that already exists in the map.
|
|
894
894
|
*/
|
|
895
|
-
addIn(
|
|
896
|
-
if (isEmptyPath(
|
|
895
|
+
addIn(path106, value) {
|
|
896
|
+
if (isEmptyPath(path106))
|
|
897
897
|
this.add(value);
|
|
898
898
|
else {
|
|
899
|
-
const [key, ...rest] =
|
|
899
|
+
const [key, ...rest] = path106;
|
|
900
900
|
const node = this.get(key, true);
|
|
901
901
|
if (identity.isCollection(node))
|
|
902
902
|
node.addIn(rest, value);
|
|
@@ -910,8 +910,8 @@ var require_Collection = __commonJS({
|
|
|
910
910
|
* Removes a value from the collection.
|
|
911
911
|
* @returns `true` if the item was found and removed.
|
|
912
912
|
*/
|
|
913
|
-
deleteIn(
|
|
914
|
-
const [key, ...rest] =
|
|
913
|
+
deleteIn(path106) {
|
|
914
|
+
const [key, ...rest] = path106;
|
|
915
915
|
if (rest.length === 0)
|
|
916
916
|
return this.delete(key);
|
|
917
917
|
const node = this.get(key, true);
|
|
@@ -925,8 +925,8 @@ var require_Collection = __commonJS({
|
|
|
925
925
|
* scalar values from their surrounding node; to disable set `keepScalar` to
|
|
926
926
|
* `true` (collections are always returned intact).
|
|
927
927
|
*/
|
|
928
|
-
getIn(
|
|
929
|
-
const [key, ...rest] =
|
|
928
|
+
getIn(path106, keepScalar) {
|
|
929
|
+
const [key, ...rest] = path106;
|
|
930
930
|
const node = this.get(key, true);
|
|
931
931
|
if (rest.length === 0)
|
|
932
932
|
return !keepScalar && identity.isScalar(node) ? node.value : node;
|
|
@@ -944,8 +944,8 @@ var require_Collection = __commonJS({
|
|
|
944
944
|
/**
|
|
945
945
|
* Checks if the collection includes a value with the key `key`.
|
|
946
946
|
*/
|
|
947
|
-
hasIn(
|
|
948
|
-
const [key, ...rest] =
|
|
947
|
+
hasIn(path106) {
|
|
948
|
+
const [key, ...rest] = path106;
|
|
949
949
|
if (rest.length === 0)
|
|
950
950
|
return this.has(key);
|
|
951
951
|
const node = this.get(key, true);
|
|
@@ -955,8 +955,8 @@ var require_Collection = __commonJS({
|
|
|
955
955
|
* Sets a value in this collection. For `!!set`, `value` needs to be a
|
|
956
956
|
* boolean to add/remove the item from the set.
|
|
957
957
|
*/
|
|
958
|
-
setIn(
|
|
959
|
-
const [key, ...rest] =
|
|
958
|
+
setIn(path106, value) {
|
|
959
|
+
const [key, ...rest] = path106;
|
|
960
960
|
if (rest.length === 0) {
|
|
961
961
|
this.set(key, value);
|
|
962
962
|
} else {
|
|
@@ -3471,9 +3471,9 @@ var require_Document = __commonJS({
|
|
|
3471
3471
|
this.contents.add(value);
|
|
3472
3472
|
}
|
|
3473
3473
|
/** Adds a value to the document. */
|
|
3474
|
-
addIn(
|
|
3474
|
+
addIn(path106, value) {
|
|
3475
3475
|
if (assertCollection(this.contents))
|
|
3476
|
-
this.contents.addIn(
|
|
3476
|
+
this.contents.addIn(path106, value);
|
|
3477
3477
|
}
|
|
3478
3478
|
/**
|
|
3479
3479
|
* Create a new `Alias` node, ensuring that the target `node` has the required anchor.
|
|
@@ -3548,14 +3548,14 @@ var require_Document = __commonJS({
|
|
|
3548
3548
|
* Removes a value from the document.
|
|
3549
3549
|
* @returns `true` if the item was found and removed.
|
|
3550
3550
|
*/
|
|
3551
|
-
deleteIn(
|
|
3552
|
-
if (Collection.isEmptyPath(
|
|
3551
|
+
deleteIn(path106) {
|
|
3552
|
+
if (Collection.isEmptyPath(path106)) {
|
|
3553
3553
|
if (this.contents == null)
|
|
3554
3554
|
return false;
|
|
3555
3555
|
this.contents = null;
|
|
3556
3556
|
return true;
|
|
3557
3557
|
}
|
|
3558
|
-
return assertCollection(this.contents) ? this.contents.deleteIn(
|
|
3558
|
+
return assertCollection(this.contents) ? this.contents.deleteIn(path106) : false;
|
|
3559
3559
|
}
|
|
3560
3560
|
/**
|
|
3561
3561
|
* Returns item at `key`, or `undefined` if not found. By default unwraps
|
|
@@ -3570,10 +3570,10 @@ var require_Document = __commonJS({
|
|
|
3570
3570
|
* scalar values from their surrounding node; to disable set `keepScalar` to
|
|
3571
3571
|
* `true` (collections are always returned intact).
|
|
3572
3572
|
*/
|
|
3573
|
-
getIn(
|
|
3574
|
-
if (Collection.isEmptyPath(
|
|
3573
|
+
getIn(path106, keepScalar) {
|
|
3574
|
+
if (Collection.isEmptyPath(path106))
|
|
3575
3575
|
return !keepScalar && identity.isScalar(this.contents) ? this.contents.value : this.contents;
|
|
3576
|
-
return identity.isCollection(this.contents) ? this.contents.getIn(
|
|
3576
|
+
return identity.isCollection(this.contents) ? this.contents.getIn(path106, keepScalar) : void 0;
|
|
3577
3577
|
}
|
|
3578
3578
|
/**
|
|
3579
3579
|
* Checks if the document includes a value with the key `key`.
|
|
@@ -3584,10 +3584,10 @@ var require_Document = __commonJS({
|
|
|
3584
3584
|
/**
|
|
3585
3585
|
* Checks if the document includes a value at `path`.
|
|
3586
3586
|
*/
|
|
3587
|
-
hasIn(
|
|
3588
|
-
if (Collection.isEmptyPath(
|
|
3587
|
+
hasIn(path106) {
|
|
3588
|
+
if (Collection.isEmptyPath(path106))
|
|
3589
3589
|
return this.contents !== void 0;
|
|
3590
|
-
return identity.isCollection(this.contents) ? this.contents.hasIn(
|
|
3590
|
+
return identity.isCollection(this.contents) ? this.contents.hasIn(path106) : false;
|
|
3591
3591
|
}
|
|
3592
3592
|
/**
|
|
3593
3593
|
* Sets a value in this document. For `!!set`, `value` needs to be a
|
|
@@ -3604,13 +3604,13 @@ var require_Document = __commonJS({
|
|
|
3604
3604
|
* Sets a value in this document. For `!!set`, `value` needs to be a
|
|
3605
3605
|
* boolean to add/remove the item from the set.
|
|
3606
3606
|
*/
|
|
3607
|
-
setIn(
|
|
3608
|
-
if (Collection.isEmptyPath(
|
|
3607
|
+
setIn(path106, value) {
|
|
3608
|
+
if (Collection.isEmptyPath(path106)) {
|
|
3609
3609
|
this.contents = value;
|
|
3610
3610
|
} else if (this.contents == null) {
|
|
3611
|
-
this.contents = Collection.collectionFromPath(this.schema, Array.from(
|
|
3611
|
+
this.contents = Collection.collectionFromPath(this.schema, Array.from(path106), value);
|
|
3612
3612
|
} else if (assertCollection(this.contents)) {
|
|
3613
|
-
this.contents.setIn(
|
|
3613
|
+
this.contents.setIn(path106, value);
|
|
3614
3614
|
}
|
|
3615
3615
|
}
|
|
3616
3616
|
/**
|
|
@@ -5570,9 +5570,9 @@ var require_cst_visit = __commonJS({
|
|
|
5570
5570
|
visit.BREAK = BREAK;
|
|
5571
5571
|
visit.SKIP = SKIP;
|
|
5572
5572
|
visit.REMOVE = REMOVE;
|
|
5573
|
-
visit.itemAtPath = (cst,
|
|
5573
|
+
visit.itemAtPath = (cst, path106) => {
|
|
5574
5574
|
let item = cst;
|
|
5575
|
-
for (const [field, index] of
|
|
5575
|
+
for (const [field, index] of path106) {
|
|
5576
5576
|
const tok = item?.[field];
|
|
5577
5577
|
if (tok && "items" in tok) {
|
|
5578
5578
|
item = tok.items[index];
|
|
@@ -5581,23 +5581,23 @@ var require_cst_visit = __commonJS({
|
|
|
5581
5581
|
}
|
|
5582
5582
|
return item;
|
|
5583
5583
|
};
|
|
5584
|
-
visit.parentCollection = (cst,
|
|
5585
|
-
const parent = visit.itemAtPath(cst,
|
|
5586
|
-
const field =
|
|
5584
|
+
visit.parentCollection = (cst, path106) => {
|
|
5585
|
+
const parent = visit.itemAtPath(cst, path106.slice(0, -1));
|
|
5586
|
+
const field = path106[path106.length - 1][0];
|
|
5587
5587
|
const coll = parent?.[field];
|
|
5588
5588
|
if (coll && "items" in coll)
|
|
5589
5589
|
return coll;
|
|
5590
5590
|
throw new Error("Parent collection not found");
|
|
5591
5591
|
};
|
|
5592
|
-
function _visit(
|
|
5593
|
-
let ctrl = visitor(item,
|
|
5592
|
+
function _visit(path106, item, visitor) {
|
|
5593
|
+
let ctrl = visitor(item, path106);
|
|
5594
5594
|
if (typeof ctrl === "symbol")
|
|
5595
5595
|
return ctrl;
|
|
5596
5596
|
for (const field of ["key", "value"]) {
|
|
5597
5597
|
const token = item[field];
|
|
5598
5598
|
if (token && "items" in token) {
|
|
5599
5599
|
for (let i = 0; i < token.items.length; ++i) {
|
|
5600
|
-
const ci = _visit(Object.freeze(
|
|
5600
|
+
const ci = _visit(Object.freeze(path106.concat([[field, i]])), token.items[i], visitor);
|
|
5601
5601
|
if (typeof ci === "number")
|
|
5602
5602
|
i = ci - 1;
|
|
5603
5603
|
else if (ci === BREAK)
|
|
@@ -5608,10 +5608,10 @@ var require_cst_visit = __commonJS({
|
|
|
5608
5608
|
}
|
|
5609
5609
|
}
|
|
5610
5610
|
if (typeof ctrl === "function" && field === "key")
|
|
5611
|
-
ctrl = ctrl(item,
|
|
5611
|
+
ctrl = ctrl(item, path106);
|
|
5612
5612
|
}
|
|
5613
5613
|
}
|
|
5614
|
-
return typeof ctrl === "function" ? ctrl(item,
|
|
5614
|
+
return typeof ctrl === "function" ? ctrl(item, path106) : ctrl;
|
|
5615
5615
|
}
|
|
5616
5616
|
exports.visit = visit;
|
|
5617
5617
|
}
|
|
@@ -6913,14 +6913,14 @@ var require_parser = __commonJS({
|
|
|
6913
6913
|
case "scalar":
|
|
6914
6914
|
case "single-quoted-scalar":
|
|
6915
6915
|
case "double-quoted-scalar": {
|
|
6916
|
-
const
|
|
6916
|
+
const fs103 = this.flowScalar(this.type);
|
|
6917
6917
|
if (atNextItem || it.value) {
|
|
6918
|
-
map.items.push({ start, key:
|
|
6918
|
+
map.items.push({ start, key: fs103, sep: [] });
|
|
6919
6919
|
this.onKeyLine = true;
|
|
6920
6920
|
} else if (it.sep) {
|
|
6921
|
-
this.stack.push(
|
|
6921
|
+
this.stack.push(fs103);
|
|
6922
6922
|
} else {
|
|
6923
|
-
Object.assign(it, { key:
|
|
6923
|
+
Object.assign(it, { key: fs103, sep: [] });
|
|
6924
6924
|
this.onKeyLine = true;
|
|
6925
6925
|
}
|
|
6926
6926
|
return;
|
|
@@ -7048,13 +7048,13 @@ var require_parser = __commonJS({
|
|
|
7048
7048
|
case "scalar":
|
|
7049
7049
|
case "single-quoted-scalar":
|
|
7050
7050
|
case "double-quoted-scalar": {
|
|
7051
|
-
const
|
|
7051
|
+
const fs103 = this.flowScalar(this.type);
|
|
7052
7052
|
if (!it || it.value)
|
|
7053
|
-
fc.items.push({ start: [], key:
|
|
7053
|
+
fc.items.push({ start: [], key: fs103, sep: [] });
|
|
7054
7054
|
else if (it.sep)
|
|
7055
|
-
this.stack.push(
|
|
7055
|
+
this.stack.push(fs103);
|
|
7056
7056
|
else
|
|
7057
|
-
Object.assign(it, { key:
|
|
7057
|
+
Object.assign(it, { key: fs103, sep: [] });
|
|
7058
7058
|
return;
|
|
7059
7059
|
}
|
|
7060
7060
|
case "flow-map-end":
|
|
@@ -7363,14 +7363,14 @@ var require_dist = __commonJS({
|
|
|
7363
7363
|
});
|
|
7364
7364
|
|
|
7365
7365
|
// src/scripts/hooks/dispatch_entry.ts
|
|
7366
|
-
import * as
|
|
7366
|
+
import * as path105 from "node:path";
|
|
7367
7367
|
import { fileURLToPath as fileURLToPath67 } from "node:url";
|
|
7368
7368
|
|
|
7369
7369
|
// src/scripts/hooks/dispatch_hook.ts
|
|
7370
7370
|
var import_yaml6 = __toESM(require_dist(), 1);
|
|
7371
7371
|
import { spawnSync as spawnSync10 } from "node:child_process";
|
|
7372
|
-
import
|
|
7373
|
-
import
|
|
7372
|
+
import fs102 from "node:fs";
|
|
7373
|
+
import path104 from "node:path";
|
|
7374
7374
|
import * as tty2 from "node:tty";
|
|
7375
7375
|
import { fileURLToPath as fileURLToPath66, pathToFileURL as pathToFileURL59 } from "node:url";
|
|
7376
7376
|
|
|
@@ -24686,8 +24686,8 @@ function lockfile_path(env) {
|
|
|
24686
24686
|
}
|
|
24687
24687
|
return write_target("installed.lock", { env: env ?? null });
|
|
24688
24688
|
}
|
|
24689
|
-
function read_lockfile(
|
|
24690
|
-
const target =
|
|
24689
|
+
function read_lockfile(path106) {
|
|
24690
|
+
const target = path106 ?? lockfile_path();
|
|
24691
24691
|
let text;
|
|
24692
24692
|
try {
|
|
24693
24693
|
text = fs51.readFileSync(target, { encoding: "utf-8" });
|
|
@@ -25850,12 +25850,39 @@ var ALL_OPS = [
|
|
|
25850
25850
|
"pr-merge-auto",
|
|
25851
25851
|
"tag",
|
|
25852
25852
|
"release",
|
|
25853
|
-
"publish"
|
|
25853
|
+
"publish",
|
|
25854
|
+
"unpublish",
|
|
25855
|
+
"deprecate",
|
|
25856
|
+
"release-asset",
|
|
25857
|
+
"protection",
|
|
25858
|
+
"workflow-toggle",
|
|
25859
|
+
"repo-lifecycle",
|
|
25860
|
+
"review-approve",
|
|
25861
|
+
"force-push",
|
|
25862
|
+
"worktree-remove",
|
|
25863
|
+
"clean-ignored",
|
|
25864
|
+
"tag-force",
|
|
25865
|
+
"rebase",
|
|
25866
|
+
"reset-hard",
|
|
25867
|
+
"clean",
|
|
25868
|
+
"stash-drop",
|
|
25869
|
+
"branch-delete",
|
|
25870
|
+
"close"
|
|
25854
25871
|
];
|
|
25855
25872
|
var PHRASES = [
|
|
25856
25873
|
{ op: "commit", re: /\b(commit(e|et|te|ten)?|committe|einchecken)\b/i },
|
|
25857
25874
|
{ op: "push", re: /\b(push(e|en|t)?|hochladen|hochschieben|raufschieben)\b/i },
|
|
25858
|
-
|
|
25875
|
+
// A CREATION VERB IS REQUIRED, as for `pr-create` above and for the same
|
|
25876
|
+
// reason. The bare noun could not tell an authorization from a mention, and
|
|
25877
|
+
// the mention is the dangerous half: "den branch nicht löschen" names the
|
|
25878
|
+
// object precisely in order to forbid acting on it, yet authorized branch
|
|
25879
|
+
// creation — the negation trails a bare-noun match, so neither the
|
|
25880
|
+
// look-behind nor the span check in `negatedBefore` can reach it. Widened
|
|
25881
|
+
// 2026-09-03 alongside the destructive-coverage work that measured it.
|
|
25882
|
+
{
|
|
25883
|
+
op: "branch",
|
|
25884
|
+
re: /\b(erstell(e|en)?|mach(e|en)?|leg(e|en)?\s+an|anleg(e|en)?|(er|be)?(ö|oe)ffne|open|create|new|neuer?|starte?|checkout|wechsl?e|switch)\b[^.\n]{0,30}\b(branch|feature-branch|zweig)\b|\b(branch|feature-branch|zweig)\b[^.\n]{0,25}\b(erstellen|anlegen|aufmachen|(ö|oe)ffnen|starten)\b/i
|
|
25885
|
+
},
|
|
25859
25886
|
// A creation verb is required — "schau dir den PR an" is not "open a PR".
|
|
25860
25887
|
{
|
|
25861
25888
|
op: "pr-create",
|
|
@@ -25892,7 +25919,111 @@ var PHRASES = [
|
|
|
25892
25919
|
op: "release",
|
|
25893
25920
|
re: /\b(releasen?|ver(ö|oe)ffentlich(e|en))\b(?!\s*[- ]?(notes?|branch|candidate|pr\b|datum|date|zweig))/i
|
|
25894
25921
|
},
|
|
25895
|
-
{ op: "publish", re: /\b(publish(e|en)?|publiziere[n]?)\b/i }
|
|
25922
|
+
{ op: "publish", re: /\b(publish(e|en)?|publiziere[n]?)\b/i },
|
|
25923
|
+
// ── Authorization vocabulary for the ops added 2026-09-03.
|
|
25924
|
+
//
|
|
25925
|
+
// NON-NEGOTIABLE, and the reason it ships in the same change as the new BLOCK
|
|
25926
|
+
// ops: a blocked operation with no phrase that authorizes it is a dead end.
|
|
25927
|
+
// The guard refuses, the user says "doch, mach das", the classifier records
|
|
25928
|
+
// nothing, and the refusal repeats forever. Every op the guard can block must
|
|
25929
|
+
// have a sentence that unblocks it, or the user's override is a claim rather
|
|
25930
|
+
// than a mechanism.
|
|
25931
|
+
//
|
|
25932
|
+
// Tight on purpose. Under-matching costs one confirmation; over-matching
|
|
25933
|
+
// authorizes something the user did not ask for, so each pattern demands the
|
|
25934
|
+
// object noun rather than a bare verb wherever the verb is ordinary German.
|
|
25935
|
+
//
|
|
25936
|
+
// `unpublish` before nothing in particular — `\bpublish\b` does not match
|
|
25937
|
+
// inside "unpublish" (no word boundary between `n` and `p`), so the two never
|
|
25938
|
+
// collide.
|
|
25939
|
+
// TWO SHAPES EVERY GERMAN PATTERN BELOW MUST CARRY, both learned from tests
|
|
25940
|
+
// that went red rather than from inspection:
|
|
25941
|
+
//
|
|
25942
|
+
// 1. THE IMPERATIVE DROPS ITS `-e`. "entfern die worktree", "archivier das
|
|
25943
|
+
// repo", "deaktivier den workflow" are what people type; `entfern(e|en)`
|
|
25944
|
+
// matches none of them. Every verb ending is therefore `(e|en)?`.
|
|
25945
|
+
// 2. WORD ORDER GOES BOTH WAYS. "archivier das repo" and "das repo
|
|
25946
|
+
// archivieren" are one instruction, and a pattern anchored on the noun
|
|
25947
|
+
// first sees only the second.
|
|
25948
|
+
//
|
|
25949
|
+
// The object noun stays REQUIRED in every pattern that has one. That is what
|
|
25950
|
+
// keeps the loosened verb endings from over-authorizing: "lösch" alone
|
|
25951
|
+
// authorizes nothing, "lösch den branch" authorizes a branch deletion.
|
|
25952
|
+
{ op: "unpublish", re: /\bunpublish(e|en)?\b/i },
|
|
25953
|
+
{
|
|
25954
|
+
op: "deprecate",
|
|
25955
|
+
re: /\bdeprecate(d|n)?\b|\bals\s+veraltet\s+markier(e|en)?\b/i
|
|
25956
|
+
},
|
|
25957
|
+
{
|
|
25958
|
+
op: "release-asset",
|
|
25959
|
+
re: /\brelease[-\s]?asset\b|\b(clobber|(ü|ue)berschreib(e|en)?|ersetz(e|en)?|replace|austausch(e|en)?)\b[^.\n]{0,25}\b(asset|artefakt|artifact|tarball|binary)\b|\b(asset|artefakt|artifact)\b[^.\n]{0,25}\b((ü|ue)berschreiben|ersetzen|austauschen|replace)\b/i
|
|
25960
|
+
},
|
|
25961
|
+
// A VERB IS REQUIRED, like `tag` and `release` above and for the same reason.
|
|
25962
|
+
// A bare noun cannot tell an authorization from a mention, and here the
|
|
25963
|
+
// mention is the dangerous half: "die branch-protection nicht anfassen" names
|
|
25964
|
+
// the object precisely in order to forbid touching it. Measured — this was the
|
|
25965
|
+
// one row of the negation corpus that neither the look-behind nor the
|
|
25966
|
+
// span check could reach, because the negation trails a bare-noun match.
|
|
25967
|
+
{
|
|
25968
|
+
op: "protection",
|
|
25969
|
+
re: /\b(entfern(e|en)?|l(ö|oe)sch(e|en)?|deaktivier(e|en)?|nimm|weg|remove|delete|disable|drop|lift)\b[^.\n]{0,30}\b(branch[-\s]?protection|protection[-\s]?rule|schutzregel|ruleset)\b|\b(branch[-\s]?protection|protection[-\s]?rule|schutzregel|ruleset)\b[^.\n]{0,30}\b(entfernen|l(ö|oe)schen|deaktivieren|abschalten|remove|delete|disable|drop|lift|weg)\b/i
|
|
25970
|
+
},
|
|
25971
|
+
{
|
|
25972
|
+
op: "workflow-toggle",
|
|
25973
|
+
re: /\bworkflow\b[^.\n]{0,25}\b(deaktivier(e|en)?|aktivier(e|en)?|disable|enable|abschalt(e|en)?|ausschalt(e|en)?)\b|\b(deaktivier(e|en)?|aktivier(e|en)?|disable|enable|abschalt(e|en)?|ausschalt(e|en)?)\b[^.\n]{0,25}\bworkflow\b/i
|
|
25974
|
+
},
|
|
25975
|
+
{
|
|
25976
|
+
op: "repo-lifecycle",
|
|
25977
|
+
re: /\b(repo|repository)\b[^.\n]{0,30}\b(archivier(e|en)?|archive|l(ö|oe)sch(e|en)?|delete)\b|\b(archivier(e|en)?|archive|l(ö|oe)sch(e|en)?|delete)\b[^.\n]{0,25}\b(repo|repository)\b|\b(repo|repository)\b[^.\n]{0,30}\bauf\s+(privat|public|öffentlich|private)\b/i
|
|
25978
|
+
},
|
|
25979
|
+
{
|
|
25980
|
+
op: "review-approve",
|
|
25981
|
+
re: /\b(approve|genehmig(e|en)?|freigeb(e|en)?|abnehm(e|en)?)\b[^.\n]{0,30}\b(review|pr|pull[-\s]request)\b|\b(review|pr|pull[-\s]request)\b[^.\n]{0,20}\b(approve|approven|genehmigen|freigeben)\b/i
|
|
25982
|
+
},
|
|
25983
|
+
{
|
|
25984
|
+
op: "force-push",
|
|
25985
|
+
re: /\bforce[-\s]?push(e|en|st)?\b|--force(-with-lease)?\b|\bmit\s+gewalt\s+push(e|en)?\b/i
|
|
25986
|
+
},
|
|
25987
|
+
{
|
|
25988
|
+
op: "worktree-remove",
|
|
25989
|
+
re: /\bworktree\b[^.\n]{0,25}\b(entfern(e|en)?|l(ö|oe)sch(e|en)?|remove|delete|weg(werfen|r(ä|ae)umen))\b|\b(entfern(e|en)?|l(ö|oe)sch(e|en)?|remove|delete)\b[^.\n]{0,25}\bworktree\b/i
|
|
25990
|
+
},
|
|
25991
|
+
// The `-x` flag is the whole distinction: without it `git clean` spares
|
|
25992
|
+
// ignored files, with it `.env` and local certificates go too.
|
|
25993
|
+
{
|
|
25994
|
+
op: "clean-ignored",
|
|
25995
|
+
re: /\bgit\s+clean\b[^.\n]{0,20}-[A-Za-z]*x|\b(ignorierte|ignored)\b[^.\n]{0,25}\b(dateien|files)\b[^.\n]{0,25}\b(l(ö|oe)sch(e|en)?|entfern(e|en)?|remove|delete)\b/i
|
|
25996
|
+
},
|
|
25997
|
+
{
|
|
25998
|
+
op: "tag-force",
|
|
25999
|
+
re: /\btag\b[^.\n]{0,25}\b(verschieb(e|en)?|(ü|ue)berschreib(e|en)?|umh(ä|ae)ng(e|en)?|force|move)\b|\b(verschieb(e|en)?|(ü|ue)berschreib(e|en)?)\b[^.\n]{0,20}\btag\b/i
|
|
26000
|
+
},
|
|
26001
|
+
{ op: "rebase", re: /\brebase(n|st|d)?\b/i },
|
|
26002
|
+
{
|
|
26003
|
+
op: "reset-hard",
|
|
26004
|
+
re: /\breset\s+--hard\b|\bhard\s+reset\b|\bhart\s+zur(ü|ue)cksetz(e|en)?\b/i
|
|
26005
|
+
},
|
|
26006
|
+
{ op: "clean", re: /\bgit\s+clean\b/i },
|
|
26007
|
+
{
|
|
26008
|
+
op: "stash-drop",
|
|
26009
|
+
re: /\bstash\b[^.\n]{0,25}\b(drop|clear|verwerf(e|en)?|l(ö|oe)sch(e|en)?)\b|\b(verwerf(e|en)?|l(ö|oe)sch(e|en)?|drop)\b[^.\n]{0,20}\bstash\b/i
|
|
26010
|
+
},
|
|
26011
|
+
{
|
|
26012
|
+
op: "branch-delete",
|
|
26013
|
+
re: /\b(l(ö|oe)sch(e|en)?|entfern(e|en)?|delete|remove)\b[^.\n]{0,25}\b(branch|branches|zweig)\b|\b(branch|branches|zweig)\b[^.\n]{0,25}\b(l(ö|oe)schen|entfernen|delete|remove)\b/i
|
|
26014
|
+
},
|
|
26015
|
+
{
|
|
26016
|
+
op: "close",
|
|
26017
|
+
re: /\b(schlie(ß|ss)(e|en)?|close)\b[^.\n]{0,30}\b(pr|pull[-\s]request|issue|ticket)\b|\b(pr|pull[-\s]request|issue|ticket)\b[^.\n]{0,20}\b(schlie(ß|ss)en|close)\b/i
|
|
26018
|
+
},
|
|
26019
|
+
// Enabling auto-merge is its own op on the guard side, so it needs its own
|
|
26020
|
+
// sentence. Without one it is the dead end this block exists to prevent: the
|
|
26021
|
+
// plain merge phrase authorizes `pr-merge` and never `pr-merge-auto`, so the
|
|
26022
|
+
// refusal would have repeated forever.
|
|
26023
|
+
{
|
|
26024
|
+
op: "pr-merge-auto",
|
|
26025
|
+
re: /\bauto[-\s]?merge\b|\bmerge\b[^.\n]{0,20}\bautomatisch\b|\bautomatisch\b[^.\n]{0,20}\bmerg(e|en)\b/i
|
|
26026
|
+
}
|
|
25896
26027
|
];
|
|
25897
26028
|
var OUTPUT_LINE = /^\s*(To\s+\S+|remote:|error:|fatal:|hint:|warning:|!\s|\?\?\s|\s*\^|[-+]{3}\s|@@\s|\$\s|>\s|\d+\s+(pass|fail)|npm ERR!|Error:|Traceback|at\s+\S+:\d+)/i;
|
|
25898
26029
|
function isInterrogative(prose) {
|
|
@@ -25953,6 +26084,67 @@ function splitFences(prompt) {
|
|
|
25953
26084
|
function _commandLines(fence) {
|
|
25954
26085
|
return fence.split("\n").map((l) => l.trim()).filter((l) => l.length > 0).filter((l) => !/^(remote:|error:|hint:|fatal:|warning:|To |!\s|\s*\^)/i.test(l)).map((l) => l.replace(/^[$>#]\s*/, "")).filter((l) => /^(git|gh|npm|pnpm|yarn|task)\b/.test(l));
|
|
25955
26086
|
}
|
|
26087
|
+
function extractMergeTargets(prompt) {
|
|
26088
|
+
const out = /* @__PURE__ */ new Set();
|
|
26089
|
+
const re = /(?:#|\bpr[- ]?|\bpull[- ]request\s+#?)(\d{1,7})\b/giu;
|
|
26090
|
+
let m;
|
|
26091
|
+
while ((m = re.exec(prompt)) !== null) {
|
|
26092
|
+
const n = Number.parseInt(m[1], 10);
|
|
26093
|
+
if (Number.isSafeInteger(n) && n > 0) {
|
|
26094
|
+
out.add(n);
|
|
26095
|
+
}
|
|
26096
|
+
}
|
|
26097
|
+
return [...out].sort((a, b) => a - b);
|
|
26098
|
+
}
|
|
26099
|
+
var REVOKE_RE = /\b(stop|stopp|halt|abbrechen|abbruch|cancel|revoke|widerruf(en)?|zur(ü|ue)ck(nehmen|ziehen)|hold\s+(everything|on|the\s+merge)|warte|wait)\b|(?:\b(nicht|kein(e|en)?|no|not|dont|don't|never|niemals|nie)\b[^.!?\n]{0,30}\b(merg(e|en|ing)|zusammenf(ü|ue)hren)\b)/iu;
|
|
26100
|
+
function isRevocation(prompt) {
|
|
26101
|
+
return REVOKE_RE.test(prompt);
|
|
26102
|
+
}
|
|
26103
|
+
function _grantId(session_id, at, targets) {
|
|
26104
|
+
return `${sessionSlug(session_id) || "nosession"}:${at}:${targets.join(",")}`;
|
|
26105
|
+
}
|
|
26106
|
+
function foldGrants(prior, prompt, authorized, session_id, now) {
|
|
26107
|
+
if (isRevocation(prompt)) {
|
|
26108
|
+
return [];
|
|
26109
|
+
}
|
|
26110
|
+
const carried = prior.filter((g) => g.consumed.length < g.targets.length);
|
|
26111
|
+
if (!authorized.includes("pr-merge")) {
|
|
26112
|
+
return carried;
|
|
26113
|
+
}
|
|
26114
|
+
const targets = extractMergeTargets(prompt);
|
|
26115
|
+
if (targets.length === 0) {
|
|
26116
|
+
return carried;
|
|
26117
|
+
}
|
|
26118
|
+
const at = now.toISOString();
|
|
26119
|
+
const already = new Set(carried.flatMap((g) => g.targets));
|
|
26120
|
+
const fresh = targets.filter((t) => !already.has(t));
|
|
26121
|
+
if (fresh.length === 0) {
|
|
26122
|
+
return carried;
|
|
26123
|
+
}
|
|
26124
|
+
return [
|
|
26125
|
+
...carried,
|
|
26126
|
+
{
|
|
26127
|
+
id: _grantId(session_id, at, fresh),
|
|
26128
|
+
op: "pr-merge",
|
|
26129
|
+
targets: fresh,
|
|
26130
|
+
consumed: [],
|
|
26131
|
+
granted_at: at,
|
|
26132
|
+
evidence: prompt.trim().slice(0, 120)
|
|
26133
|
+
}
|
|
26134
|
+
];
|
|
26135
|
+
}
|
|
26136
|
+
var NEGATION_WORD = /\b(nicht|nichts|kein(e|en|em|er|es)?|niemals|nie|no|not|dont|don't|never|without|ohne)\b/i;
|
|
26137
|
+
function negatedBefore(text, index, matched = "") {
|
|
26138
|
+
let start = 0;
|
|
26139
|
+
for (const mark of [".", "!", "?", "\n"]) {
|
|
26140
|
+
const at = text.lastIndexOf(mark, index - 1);
|
|
26141
|
+
if (at + 1 > start) {
|
|
26142
|
+
start = at + 1;
|
|
26143
|
+
}
|
|
26144
|
+
}
|
|
26145
|
+
const before = text.slice(Math.max(start, index - 30), index);
|
|
26146
|
+
return NEGATION_WORD.test(before) || NEGATION_WORD.test(matched);
|
|
26147
|
+
}
|
|
25956
26148
|
function classifyAuthorization(prompt) {
|
|
25957
26149
|
const { prose, fences } = splitFences(prompt);
|
|
25958
26150
|
const authorized = /* @__PURE__ */ new Set();
|
|
@@ -25960,7 +26152,7 @@ function classifyAuthorization(prompt) {
|
|
|
25960
26152
|
const instruction = prose.split("\n").filter((l) => !OUTPUT_LINE.test(l)).join("\n");
|
|
25961
26153
|
for (const { op, re } of isInterrogative(instruction) ? [] : PHRASES) {
|
|
25962
26154
|
const m = re.exec(instruction);
|
|
25963
|
-
if (m) {
|
|
26155
|
+
if (m && !negatedBefore(instruction, m.index, m[0])) {
|
|
25964
26156
|
authorized.add(op);
|
|
25965
26157
|
evidence[op] = `prose: "${m[0]}"`;
|
|
25966
26158
|
}
|
|
@@ -25982,6 +26174,68 @@ function classifyAuthorization(prompt) {
|
|
|
25982
26174
|
}
|
|
25983
26175
|
return { authorized: [...authorized], evidence };
|
|
25984
26176
|
}
|
|
26177
|
+
function readGrants(consumer_root, session_id) {
|
|
26178
|
+
try {
|
|
26179
|
+
const raw = fs55.readFileSync(path55.join(consumer_root, ledgerFileFor(session_id)), "utf8");
|
|
26180
|
+
const decoded = JSON.parse(raw);
|
|
26181
|
+
if (!_isObject8(decoded) || !Array.isArray(decoded["grants"])) {
|
|
26182
|
+
return [];
|
|
26183
|
+
}
|
|
26184
|
+
const owner = typeof decoded["session_id"] === "string" ? decoded["session_id"] : "";
|
|
26185
|
+
if (session_id && owner && owner !== session_id) {
|
|
26186
|
+
return [];
|
|
26187
|
+
}
|
|
26188
|
+
return decoded["grants"].flatMap((g) => {
|
|
26189
|
+
if (!_isObject8(g)) return [];
|
|
26190
|
+
const op = g["op"];
|
|
26191
|
+
if (typeof op !== "string" || !ALL_OPS.includes(op)) return [];
|
|
26192
|
+
const targets = Array.isArray(g["targets"]) ? g["targets"] : [];
|
|
26193
|
+
const consumed = Array.isArray(g["consumed"]) ? g["consumed"] : [];
|
|
26194
|
+
return [
|
|
26195
|
+
{
|
|
26196
|
+
id: String(g["id"] ?? ""),
|
|
26197
|
+
op,
|
|
26198
|
+
targets: targets.filter((t) => typeof t === "number"),
|
|
26199
|
+
consumed: consumed.filter((t) => typeof t === "number"),
|
|
26200
|
+
granted_at: String(g["granted_at"] ?? ""),
|
|
26201
|
+
evidence: String(g["evidence"] ?? "")
|
|
26202
|
+
}
|
|
26203
|
+
];
|
|
26204
|
+
});
|
|
26205
|
+
} catch {
|
|
26206
|
+
return [];
|
|
26207
|
+
}
|
|
26208
|
+
}
|
|
26209
|
+
function consumeGrantTarget(consumer_root, session_id, target) {
|
|
26210
|
+
const file = path55.join(consumer_root, ledgerFileFor(session_id));
|
|
26211
|
+
let decoded;
|
|
26212
|
+
try {
|
|
26213
|
+
decoded = JSON.parse(fs55.readFileSync(file, "utf8"));
|
|
26214
|
+
} catch {
|
|
26215
|
+
return;
|
|
26216
|
+
}
|
|
26217
|
+
if (!_isObject8(decoded) || !Array.isArray(decoded["grants"])) {
|
|
26218
|
+
return;
|
|
26219
|
+
}
|
|
26220
|
+
let touched = false;
|
|
26221
|
+
for (const g of decoded["grants"]) {
|
|
26222
|
+
if (!_isObject8(g) || !Array.isArray(g["targets"]) || !Array.isArray(g["consumed"])) {
|
|
26223
|
+
continue;
|
|
26224
|
+
}
|
|
26225
|
+
const targets = g["targets"];
|
|
26226
|
+
const consumed = g["consumed"];
|
|
26227
|
+
if (targets.includes(target) && !consumed.includes(target)) {
|
|
26228
|
+
consumed.push(target);
|
|
26229
|
+
touched = true;
|
|
26230
|
+
}
|
|
26231
|
+
}
|
|
26232
|
+
if (touched) {
|
|
26233
|
+
try {
|
|
26234
|
+
atomic_write_json(file, decoded);
|
|
26235
|
+
} catch {
|
|
26236
|
+
}
|
|
26237
|
+
}
|
|
26238
|
+
}
|
|
25985
26239
|
function takePending(consumer_root, session_id, now) {
|
|
25986
26240
|
const file = path55.join(consumer_root, pendingFileFor(session_id));
|
|
25987
26241
|
let raw;
|
|
@@ -26050,12 +26304,24 @@ function run10(stdin_text, options) {
|
|
|
26050
26304
|
authorized.push(pending.op);
|
|
26051
26305
|
evidence[pending.op] = `confirmation of the refused \`${pending.op}\` (refused ${pending.refused_at}): "${prompt.trim().slice(0, 40)}"`;
|
|
26052
26306
|
}
|
|
26307
|
+
const now = /* @__PURE__ */ new Date();
|
|
26053
26308
|
const ledger = {
|
|
26054
26309
|
session_id: typeof envelope["session_id"] === "string" ? envelope["session_id"] : "",
|
|
26055
|
-
detected_at:
|
|
26310
|
+
detected_at: now.toISOString(),
|
|
26056
26311
|
authorized,
|
|
26057
26312
|
evidence,
|
|
26058
|
-
prompt_chars: prompt.length
|
|
26313
|
+
prompt_chars: prompt.length,
|
|
26314
|
+
// Grants survive this write; `authorized` does not. That asymmetry IS the
|
|
26315
|
+
// decision. A bare operation name stays one-shot exactly as `commit-policy`
|
|
26316
|
+
// requires, and only an authorization that also froze its objects earns a
|
|
26317
|
+
// life longer than the turn. See ADR-252.
|
|
26318
|
+
grants: foldGrants(
|
|
26319
|
+
readGrants(options.consumer_root, session),
|
|
26320
|
+
prompt,
|
|
26321
|
+
authorized,
|
|
26322
|
+
session,
|
|
26323
|
+
now
|
|
26324
|
+
)
|
|
26059
26325
|
};
|
|
26060
26326
|
try {
|
|
26061
26327
|
atomic_write_json(path55.join(options.consumer_root, ledgerFileFor(session)), ledger);
|
|
@@ -26104,6 +26370,95 @@ if (_isCliEntry24()) {
|
|
|
26104
26370
|
import fs56 from "node:fs";
|
|
26105
26371
|
import path56 from "node:path";
|
|
26106
26372
|
import { fileURLToPath as fileURLToPath34, pathToFileURL as pathToFileURL27 } from "node:url";
|
|
26373
|
+
|
|
26374
|
+
// src/scripts/hooks/merge_impact.ts
|
|
26375
|
+
import { execFileSync as execFileSync3 } from "node:child_process";
|
|
26376
|
+
var DESTRUCTIVE_MARKERS = [
|
|
26377
|
+
// Schema removal. Matched on ADDED lines only — a migration that *removes* a
|
|
26378
|
+
// dropColumn call is the opposite of destructive, and matching the raw patch
|
|
26379
|
+
// would score it the same way.
|
|
26380
|
+
{ label: "migration drops a column or table", re: /^\+.*\b(dropColumn|dropTable|dropIfExists|removeColumn|drop_column|drop_table)\b/im },
|
|
26381
|
+
{ label: "raw DROP or TRUNCATE in a migration", re: /^\+.*\b(DROP\s+(TABLE|COLUMN|INDEX|CONSTRAINT)|TRUNCATE\s+TABLE)\b/im },
|
|
26382
|
+
// The author said so themselves. Conventional Commits marks a breaking change
|
|
26383
|
+
// with a `!` before the colon or a body trailer.
|
|
26384
|
+
{ label: "author marked a BREAKING CHANGE", re: /^\+.*BREAKING[ -]CHANGE/m },
|
|
26385
|
+
// A removed export is the shape most likely to break an importer.
|
|
26386
|
+
{ label: "an exported symbol was removed", re: /^-\s*export\s+(default\s+|const\s+|function\s+|class\s+|interface\s+|type\s+|async\s+)/m },
|
|
26387
|
+
{ label: "a public PHP or Python symbol was removed", re: /^-\s*(public\s+function|def\s+[a-z_]+\s*\()/m },
|
|
26388
|
+
// Route removal breaks callers that never imported anything.
|
|
26389
|
+
{ label: "a route or endpoint was removed", re: /^-.*\b(Route::(get|post|put|patch|delete)|@(Get|Post|Put|Patch|Delete)Mapping|app\.(get|post|put|patch|delete)\s*\()/m },
|
|
26390
|
+
{ label: "a whole file was deleted", re: /^deleted file mode /m }
|
|
26391
|
+
];
|
|
26392
|
+
var MAJOR_BUMP = /^-\s*"version"\s*:\s*"(\d+)\.[^"]*"[\s\S]{0,200}?^\+\s*"version"\s*:\s*"(\d+)\./m;
|
|
26393
|
+
function classifyDiff(patch) {
|
|
26394
|
+
if (patch.trim() === "") {
|
|
26395
|
+
return { verdict: "undecidable", markers: [], reason: "empty diff" };
|
|
26396
|
+
}
|
|
26397
|
+
const markers = [];
|
|
26398
|
+
for (const { label, re } of DESTRUCTIVE_MARKERS) {
|
|
26399
|
+
if (re.test(patch)) {
|
|
26400
|
+
markers.push(label);
|
|
26401
|
+
}
|
|
26402
|
+
}
|
|
26403
|
+
const bump = MAJOR_BUMP.exec(patch);
|
|
26404
|
+
if (bump && bump[1] !== bump[2]) {
|
|
26405
|
+
markers.push(`major version bump ${bump[1]}.x to ${bump[2]}.x`);
|
|
26406
|
+
}
|
|
26407
|
+
const filesChanged = (patch.match(/^diff --git /gm) ?? []).length;
|
|
26408
|
+
if (markers.length > 0) {
|
|
26409
|
+
return { verdict: "destructive", markers, filesChanged };
|
|
26410
|
+
}
|
|
26411
|
+
return { verdict: "additive", markers: [], filesChanged };
|
|
26412
|
+
}
|
|
26413
|
+
function fetchPatch(pr, opts = {}) {
|
|
26414
|
+
const run13 = opts.exec ?? execFileSync3;
|
|
26415
|
+
const cwd = opts.cwd ?? process.cwd();
|
|
26416
|
+
const capture = (file, args) => run13(file, args, { cwd, encoding: "utf-8", stdio: ["ignore", "pipe", "ignore"], timeout: 15e3 });
|
|
26417
|
+
for (const ref of [`refs/pull/${pr}/head`, `pull/${pr}/head`]) {
|
|
26418
|
+
try {
|
|
26419
|
+
const base = capture("git", ["merge-base", "HEAD", ref]).trim();
|
|
26420
|
+
if (base) {
|
|
26421
|
+
const patch = capture("git", ["diff", `${base}...${ref}`]);
|
|
26422
|
+
if (patch.trim() !== "") {
|
|
26423
|
+
return { patch, source: "local" };
|
|
26424
|
+
}
|
|
26425
|
+
}
|
|
26426
|
+
} catch {
|
|
26427
|
+
}
|
|
26428
|
+
}
|
|
26429
|
+
if (opts.allowNetwork === false) {
|
|
26430
|
+
return { patch: "", source: "none", reason: "no local ref and network reads disabled" };
|
|
26431
|
+
}
|
|
26432
|
+
try {
|
|
26433
|
+
const patch = capture("gh", ["pr", "diff", String(pr), "--patch"]);
|
|
26434
|
+
if (patch.trim() !== "") {
|
|
26435
|
+
return { patch, source: "gh" };
|
|
26436
|
+
}
|
|
26437
|
+
return { patch: "", source: "none", reason: "gh returned an empty diff" };
|
|
26438
|
+
} catch {
|
|
26439
|
+
return { patch: "", source: "none", reason: "no local ref, and gh pr diff failed" };
|
|
26440
|
+
}
|
|
26441
|
+
}
|
|
26442
|
+
function analyseMergeImpact(pr, opts = {}) {
|
|
26443
|
+
const got = fetchPatch(pr, opts);
|
|
26444
|
+
if (got.source === "none") {
|
|
26445
|
+
return { verdict: "undecidable", markers: [], ...got.reason ? { reason: got.reason } : {} };
|
|
26446
|
+
}
|
|
26447
|
+
return classifyDiff(got.patch);
|
|
26448
|
+
}
|
|
26449
|
+
function describeImpact(pr, impact) {
|
|
26450
|
+
const say = `Say "merge #${pr}" to authorize it.`;
|
|
26451
|
+
switch (impact.verdict) {
|
|
26452
|
+
case "additive":
|
|
26453
|
+
return `Impact scan: PR #${pr} touches ${impact.filesChanged ?? 0} file(s) and trips no destructive marker \u2014 no schema drop, no removed export or route, no major bump, no BREAKING CHANGE. Additive as far as the diff can show, which is not the same as safe to merge: the base has moved since review and merging may trigger a deploy. ${say}`;
|
|
26454
|
+
case "destructive":
|
|
26455
|
+
return `Impact scan: PR #${pr} is NOT additive \u2014 ${impact.markers.join("; ")}. Read the diff before authorizing. ${say}`;
|
|
26456
|
+
default:
|
|
26457
|
+
return `Impact scan: could not read the diff for PR #${pr} (${impact.reason ?? "unknown"}), so nothing is known about what it changes. ${say}`;
|
|
26458
|
+
}
|
|
26459
|
+
}
|
|
26460
|
+
|
|
26461
|
+
// src/scripts/hooks/block_unauthorized_git.ts
|
|
26107
26462
|
var EXIT_ALLOW11 = 0;
|
|
26108
26463
|
var EXIT_BLOCK = 1;
|
|
26109
26464
|
function _isObject9(v) {
|
|
@@ -26116,13 +26471,52 @@ var BLOCK_OPS = /* @__PURE__ */ new Set([
|
|
|
26116
26471
|
"pr-merge",
|
|
26117
26472
|
// Enabling auto-merge commits the outcome to a condition the agent does not
|
|
26118
26473
|
// control, so it is blocked on the same terms as the merge it schedules.
|
|
26119
|
-
"pr-merge-auto"
|
|
26474
|
+
"pr-merge-auto",
|
|
26475
|
+
// ── Added 2026-09-03. Every one is already never-autonomous in the
|
|
26476
|
+
// `non-destructive-by-default` prose; the measurement that drove it is in the
|
|
26477
|
+
// `GitOp` union's own note — 17 of 25 borderline operations classified as
|
|
26478
|
+
// NOTHING, including three worse than anything the guard already caught.
|
|
26479
|
+
/** The undo that is more destructive than the act: lockfiles break. */
|
|
26480
|
+
"unpublish",
|
|
26481
|
+
/** Metadata only, and every install on earth starts warning. */
|
|
26482
|
+
"deprecate",
|
|
26483
|
+
/** Replaces bytes consumers already hold a checksum for. */
|
|
26484
|
+
"release-asset",
|
|
26485
|
+
/** Deletes the guard rather than the data — everything after is unguarded. */
|
|
26486
|
+
"protection",
|
|
26487
|
+
/** No data lost; the gate that protects everything downstream is off. */
|
|
26488
|
+
"workflow-toggle",
|
|
26489
|
+
/** Reach outside the repository, and mostly one-way. */
|
|
26490
|
+
"repo-lifecycle",
|
|
26491
|
+
/** No code moves, and an armed auto-merge is released. */
|
|
26492
|
+
"review-approve",
|
|
26493
|
+
/** Discards commits that landed after the last fetch, on a shared ref. */
|
|
26494
|
+
"force-push",
|
|
26495
|
+
/** Destroys uncommitted work belonging to a session this one cannot see. */
|
|
26496
|
+
"worktree-remove",
|
|
26497
|
+
/** `-x` is the flag that takes `.env` and local certificates. */
|
|
26498
|
+
"clean-ignored"
|
|
26120
26499
|
]);
|
|
26121
26500
|
var WARN_OPS = /* @__PURE__ */ new Set([
|
|
26122
26501
|
"commit",
|
|
26123
26502
|
"push",
|
|
26124
26503
|
"pr-create",
|
|
26125
|
-
"branch"
|
|
26504
|
+
"branch",
|
|
26505
|
+
// ── Added 2026-09-03, deliberately at warn rather than block.
|
|
26506
|
+
//
|
|
26507
|
+
// Each is destructive in some reading, and each is also routine enough that
|
|
26508
|
+
// blocking it would be the friction that gets the whole guard routed around —
|
|
26509
|
+
// the failure mode this estate has already recorded twice. `reset-hard` is the
|
|
26510
|
+
// sharpest case and stays here for a decidable reason: the Hard Floor's
|
|
26511
|
+
// qualifier is "past unpushed work", and the command text cannot say whether
|
|
26512
|
+
// the work was pushed.
|
|
26513
|
+
"tag-force",
|
|
26514
|
+
"rebase",
|
|
26515
|
+
"reset-hard",
|
|
26516
|
+
"clean",
|
|
26517
|
+
"stash-drop",
|
|
26518
|
+
"branch-delete",
|
|
26519
|
+
"close"
|
|
26126
26520
|
]);
|
|
26127
26521
|
var G = "(?:-[A-Za-z-]+(?:=\\S+)?(?:\\s+\\S+)?\\s+)*";
|
|
26128
26522
|
var P = "^(?:\\S*\\/)?";
|
|
@@ -26168,6 +26562,72 @@ var COMMAND_OPS = [
|
|
|
26168
26562
|
op: "pr-create",
|
|
26169
26563
|
re: new RegExp(`${P}gh\\s+pr\\s+create\\b|${ghApiWrite("\\/pulls\\b").source}`, "i")
|
|
26170
26564
|
},
|
|
26565
|
+
// ── Added 2026-09-03. Placement inside this table is as load-bearing as the
|
|
26566
|
+
// patterns: the loop takes the MOST SEVERE match per segment, but within one
|
|
26567
|
+
// op the first pattern wins, so anything more specific than a plain `git push`
|
|
26568
|
+
// has to sit above it.
|
|
26569
|
+
// `npm unpublish` is NOT reached by the publish pattern — `\bpublish\b` needs
|
|
26570
|
+
// a word boundary that `unpublish` does not provide between `n` and `p`. That
|
|
26571
|
+
// is why it classified as nothing for as long as it did.
|
|
26572
|
+
{ op: "unpublish", re: new RegExp(`${P}(npm|pnpm|yarn)\\s+${G}unpublish\\b`, "i") },
|
|
26573
|
+
{ op: "deprecate", re: new RegExp(`${P}(npm|pnpm|yarn)\\s+${G}deprecate\\b`, "i") },
|
|
26574
|
+
{
|
|
26575
|
+
op: "release-asset",
|
|
26576
|
+
re: new RegExp(`${P}gh\\s+release\\s+(upload|edit|delete)\\b`, "i")
|
|
26577
|
+
},
|
|
26578
|
+
{
|
|
26579
|
+
op: "protection",
|
|
26580
|
+
re: new RegExp(
|
|
26581
|
+
`${P}gh\\s+api\\b(?=[^\\n]*(?:protection|rulesets?)\\b)(?=[^\\n]*(?:-X|--method)\\s+(?:DELETE|PUT|PATCH|POST)\\b)|${P}gh\\s+ruleset\\s+delete\\b`,
|
|
26582
|
+
"i"
|
|
26583
|
+
)
|
|
26584
|
+
},
|
|
26585
|
+
{
|
|
26586
|
+
op: "workflow-toggle",
|
|
26587
|
+
re: new RegExp(`${P}gh\\s+workflow\\s+(disable|enable)\\b`, "i")
|
|
26588
|
+
},
|
|
26589
|
+
{
|
|
26590
|
+
op: "repo-lifecycle",
|
|
26591
|
+
re: new RegExp(
|
|
26592
|
+
`${P}gh\\s+repo\\s+(archive|delete|unarchive)\\b|${P}gh\\s+repo\\s+edit\\b(?=[^\\n]*--visibility\\b)`,
|
|
26593
|
+
"i"
|
|
26594
|
+
)
|
|
26595
|
+
},
|
|
26596
|
+
{
|
|
26597
|
+
op: "review-approve",
|
|
26598
|
+
re: new RegExp(`${P}gh\\s+pr\\s+review\\b(?=[^\\n]*--approve\\b)`, "i")
|
|
26599
|
+
},
|
|
26600
|
+
// Above `push`, and both spellings: `--force` and `--force-with-lease`. The
|
|
26601
|
+
// "safe force" is in the same class here because what it is safe against is a
|
|
26602
|
+
// stale local view, not a collaborator who pushed after your fetch.
|
|
26603
|
+
{
|
|
26604
|
+
op: "force-push",
|
|
26605
|
+
re: new RegExp(`${P}git\\s+${G}push\\b[^\\n;|&]*(--force\\b|--force-with-lease\\b|\\s-f\\b)`, "i")
|
|
26606
|
+
},
|
|
26607
|
+
{
|
|
26608
|
+
op: "worktree-remove",
|
|
26609
|
+
re: new RegExp(`${P}git\\s+worktree\\s+remove\\b[^\\n;|&]*(--force\\b|\\s-f\\b)`, "i")
|
|
26610
|
+
},
|
|
26611
|
+
// `-x` (or `-X`) anywhere in the flag cluster is what reaches ignored files.
|
|
26612
|
+
{
|
|
26613
|
+
op: "clean-ignored",
|
|
26614
|
+
re: new RegExp(`${P}git\\s+clean\\b[^\\n;|&]*-[A-Za-z]*x`, "i")
|
|
26615
|
+
},
|
|
26616
|
+
{ op: "tag-force", re: new RegExp(`${P}git\\s+tag\\b[^\\n;|&]*(-f\\b|--force\\b)`, "i") },
|
|
26617
|
+
{ op: "rebase", re: new RegExp(`${P}git\\s+${G}rebase\\b`, "i") },
|
|
26618
|
+
{ op: "reset-hard", re: new RegExp(`${P}git\\s+${G}reset\\b[^\\n;|&]*--hard\\b`, "i") },
|
|
26619
|
+
{ op: "clean", re: new RegExp(`${P}git\\s+clean\\b`, "i") },
|
|
26620
|
+
{ op: "stash-drop", re: new RegExp(`${P}git\\s+stash\\s+(drop|clear)\\b`, "i") },
|
|
26621
|
+
// Remote deletion and the local `-D` are one op: both remove a ref, and the
|
|
26622
|
+
// remote form additionally closes any open PR pointing at it.
|
|
26623
|
+
{
|
|
26624
|
+
op: "branch-delete",
|
|
26625
|
+
re: new RegExp(
|
|
26626
|
+
`${P}git\\s+branch\\b[^\\n;|&]*(-D\\b|--delete\\b)|${P}git\\s+${G}push\\b[^\\n;|&]*(--delete\\b|\\s:\\S)`,
|
|
26627
|
+
"i"
|
|
26628
|
+
)
|
|
26629
|
+
},
|
|
26630
|
+
{ op: "close", re: new RegExp(`${P}gh\\s+(pr|issue)\\s+close\\b`, "i") },
|
|
26171
26631
|
{ op: "push", re: new RegExp(`${P}git\\s+${G}push\\b`, "i") },
|
|
26172
26632
|
{ op: "commit", re: new RegExp(`${P}git\\s+${G}commit\\b`, "i") },
|
|
26173
26633
|
{ op: "branch", re: new RegExp(`${P}git\\s+${G}(checkout\\s+-b|switch\\s+-c)\\b`, "i") }
|
|
@@ -26360,8 +26820,25 @@ function commandOp(command) {
|
|
|
26360
26820
|
}
|
|
26361
26821
|
return found;
|
|
26362
26822
|
}
|
|
26823
|
+
function mergeTargetOf(command) {
|
|
26824
|
+
const gh = /\bgh\s+pr\s+merge\s+(?:-{1,2}\S+\s+)*?(\d{1,7})\b/i.exec(command);
|
|
26825
|
+
if (gh) {
|
|
26826
|
+
return Number.parseInt(gh[1], 10);
|
|
26827
|
+
}
|
|
26828
|
+
const api = /\/pulls\/(\d{1,7})\/merge\b/i.exec(command);
|
|
26829
|
+
return api ? Number.parseInt(api[1], 10) : null;
|
|
26830
|
+
}
|
|
26831
|
+
function grantCovers(grants, op, target) {
|
|
26832
|
+
if (op !== "pr-merge" || target === null) {
|
|
26833
|
+
return null;
|
|
26834
|
+
}
|
|
26835
|
+
return grants.find(
|
|
26836
|
+
(g) => g.op === "pr-merge" && g.targets.includes(target) && !g.consumed.includes(target)
|
|
26837
|
+
) ?? null;
|
|
26838
|
+
}
|
|
26363
26839
|
var LEDGER_MAX_AGE_MS = 30 * 60 * 1e3;
|
|
26364
26840
|
function _loadLedger(consumer_root, session_id, now) {
|
|
26841
|
+
const grants = readGrants(consumer_root, session_id);
|
|
26365
26842
|
const candidates = [ledgerFileFor(session_id)];
|
|
26366
26843
|
if (!candidates.includes(STATE_FILE7)) {
|
|
26367
26844
|
candidates.push(STATE_FILE7);
|
|
@@ -26369,10 +26846,10 @@ function _loadLedger(consumer_root, session_id, now) {
|
|
|
26369
26846
|
for (const rel of candidates) {
|
|
26370
26847
|
const found = _readLedgerFile(path56.join(consumer_root, rel), session_id, now);
|
|
26371
26848
|
if (found !== null) {
|
|
26372
|
-
return found;
|
|
26849
|
+
return { ...found, grants };
|
|
26373
26850
|
}
|
|
26374
26851
|
}
|
|
26375
|
-
return { authorized: /* @__PURE__ */ new Set(), present: false };
|
|
26852
|
+
return { authorized: /* @__PURE__ */ new Set(), present: false, grants };
|
|
26376
26853
|
}
|
|
26377
26854
|
function _readLedgerFile(file, session_id, now) {
|
|
26378
26855
|
try {
|
|
@@ -26396,7 +26873,7 @@ function _readLedgerFile(file, session_id, now) {
|
|
|
26396
26873
|
}
|
|
26397
26874
|
return null;
|
|
26398
26875
|
}
|
|
26399
|
-
function decide(command, ledger) {
|
|
26876
|
+
function decide(command, ledger, impact) {
|
|
26400
26877
|
if (command === null) {
|
|
26401
26878
|
return { exit: EXIT_ALLOW11, stdout: "", stderr: "" };
|
|
26402
26879
|
}
|
|
@@ -26404,9 +26881,14 @@ function decide(command, ledger) {
|
|
|
26404
26881
|
if (op === null || ledger.authorized.has(op)) {
|
|
26405
26882
|
return { exit: EXIT_ALLOW11, stdout: "", stderr: "" };
|
|
26406
26883
|
}
|
|
26884
|
+
const target = mergeTargetOf(command);
|
|
26885
|
+
if (grantCovers(ledger.grants ?? [], op, target) && target !== null) {
|
|
26886
|
+
return { exit: EXIT_ALLOW11, stdout: "", stderr: "", consumedTarget: target };
|
|
26887
|
+
}
|
|
26407
26888
|
const shown = command.length > 120 ? `${command.slice(0, 117)}\u2026` : command;
|
|
26408
26889
|
if (BLOCK_OPS.has(op)) {
|
|
26409
|
-
const
|
|
26890
|
+
const scan = op === "pr-merge" && target !== null && impact ? ` ${impact}` : "";
|
|
26891
|
+
const reason = `Blocked: \`${op}\` with no authorization in this turn's prompt. This operation is irreversible and non-destructive-by-default already declares it never-autonomous. Command: ${shown}.${scan} Ask the user, in one numbered-options block, and run it only after they answer this turn.`;
|
|
26410
26892
|
return { exit: EXIT_BLOCK, stdout: "", stderr: `${reason}
|
|
26411
26893
|
`, blockedOp: op };
|
|
26412
26894
|
}
|
|
@@ -26434,10 +26916,24 @@ function run11(stdin_text, options) {
|
|
|
26434
26916
|
}
|
|
26435
26917
|
}
|
|
26436
26918
|
const session_id = typeof envelope["session_id"] === "string" ? envelope["session_id"] : "";
|
|
26437
|
-
const
|
|
26438
|
-
|
|
26439
|
-
|
|
26440
|
-
);
|
|
26919
|
+
const command = extractCommand(envelope);
|
|
26920
|
+
const ledger = _loadLedger(options.consumer_root, session_id, Date.now());
|
|
26921
|
+
let impact;
|
|
26922
|
+
const stage1 = command === null ? null : commandOp(command);
|
|
26923
|
+
const stage2Target = command === null ? null : mergeTargetOf(command);
|
|
26924
|
+
if (stage1 === "pr-merge" && stage2Target !== null && !ledger.authorized.has("pr-merge") && !grantCovers(ledger.grants ?? [], "pr-merge", stage2Target)) {
|
|
26925
|
+
try {
|
|
26926
|
+
impact = describeImpact(
|
|
26927
|
+
stage2Target,
|
|
26928
|
+
analyseMergeImpact(stage2Target, { cwd: options.consumer_root })
|
|
26929
|
+
);
|
|
26930
|
+
} catch {
|
|
26931
|
+
}
|
|
26932
|
+
}
|
|
26933
|
+
const decision = decide(command, ledger, impact);
|
|
26934
|
+
if (decision.consumedTarget !== void 0) {
|
|
26935
|
+
consumeGrantTarget(options.consumer_root, session_id, decision.consumedTarget);
|
|
26936
|
+
}
|
|
26441
26937
|
if (decision.blockedOp) {
|
|
26442
26938
|
try {
|
|
26443
26939
|
atomic_write_json(path56.join(options.consumer_root, pendingFileFor(session_id)), {
|
|
@@ -29177,7 +29673,7 @@ import path67 from "node:path";
|
|
|
29177
29673
|
import { fileURLToPath as fileURLToPath43, pathToFileURL as pathToFileURL36 } from "node:url";
|
|
29178
29674
|
|
|
29179
29675
|
// src/scripts/code_graph/detect.ts
|
|
29180
|
-
import { execFileSync as
|
|
29676
|
+
import { execFileSync as execFileSync4 } from "node:child_process";
|
|
29181
29677
|
import * as fs66 from "node:fs";
|
|
29182
29678
|
import * as path66 from "node:path";
|
|
29183
29679
|
|
|
@@ -29228,7 +29724,7 @@ function validateGraph(g) {
|
|
|
29228
29724
|
var CONSUMER_CANDIDATES = ["graph.json", "code-graph.json", ".code-graph/graph.json"];
|
|
29229
29725
|
function gitLastCommitEpoch(root) {
|
|
29230
29726
|
try {
|
|
29231
|
-
const out =
|
|
29727
|
+
const out = execFileSync4("git", ["-C", root, "log", "-1", "--format=%ct"], {
|
|
29232
29728
|
env: hardenedSpawnEnv(),
|
|
29233
29729
|
encoding: "utf-8",
|
|
29234
29730
|
stdio: ["ignore", "pipe", "ignore"]
|
|
@@ -29241,7 +29737,7 @@ function gitLastCommitEpoch(root) {
|
|
|
29241
29737
|
}
|
|
29242
29738
|
function commitsBehind(root, sha) {
|
|
29243
29739
|
try {
|
|
29244
|
-
const out =
|
|
29740
|
+
const out = execFileSync4("git", ["-C", root, "rev-list", "--count", `${sha}..HEAD`], {
|
|
29245
29741
|
env: hardenedSpawnEnv(),
|
|
29246
29742
|
encoding: "utf-8",
|
|
29247
29743
|
stdio: ["ignore", "pipe", "ignore"]
|
|
@@ -33893,6 +34389,61 @@ function changedFiles(root, base) {
|
|
|
33893
34389
|
const dirty = m.status === 0 ? m.stdout.split("\n") : [];
|
|
33894
34390
|
return [.../* @__PURE__ */ new Set([...tracked, ...untracked, ...dirty])].filter((f) => f.trim().length > 0);
|
|
33895
34391
|
}
|
|
34392
|
+
function addedLineMap(root, base) {
|
|
34393
|
+
const out = /* @__PURE__ */ new Map();
|
|
34394
|
+
const u = spawnSync9("git", ["ls-files", "--others", "--exclude-standard"], {
|
|
34395
|
+
cwd: root,
|
|
34396
|
+
encoding: "utf-8"
|
|
34397
|
+
});
|
|
34398
|
+
if (u.status === 0) {
|
|
34399
|
+
for (const f of u.stdout.split("\n")) {
|
|
34400
|
+
if (f.trim()) out.set(f.trim(), "all");
|
|
34401
|
+
}
|
|
34402
|
+
}
|
|
34403
|
+
for (const argv of [
|
|
34404
|
+
["diff", "--unified=0", "--diff-filter=ACMR", `${base}...HEAD`],
|
|
34405
|
+
["diff", "--unified=0", "--diff-filter=ACMR"]
|
|
34406
|
+
]) {
|
|
34407
|
+
const r = spawnSync9("git", argv, { cwd: root, encoding: "utf-8" });
|
|
34408
|
+
if (r.status !== 0) continue;
|
|
34409
|
+
mergeAddedLines(out, parseAddedLines(r.stdout));
|
|
34410
|
+
}
|
|
34411
|
+
return out;
|
|
34412
|
+
}
|
|
34413
|
+
function parseAddedLines(diffText) {
|
|
34414
|
+
const out = /* @__PURE__ */ new Map();
|
|
34415
|
+
let file = null;
|
|
34416
|
+
for (const line of diffText.split("\n")) {
|
|
34417
|
+
if (line.startsWith("+++ ")) {
|
|
34418
|
+
const p = line.slice(4).trim();
|
|
34419
|
+
file = p === "/dev/null" ? null : p.replace(/^b\//, "");
|
|
34420
|
+
continue;
|
|
34421
|
+
}
|
|
34422
|
+
if (!file || !line.startsWith("@@")) continue;
|
|
34423
|
+
const m = /^@@ -\d+(?:,\d+)? \+(\d+)(?:,(\d+))? @@/.exec(line);
|
|
34424
|
+
if (!m) continue;
|
|
34425
|
+
const start = Number.parseInt(m[1], 10);
|
|
34426
|
+
const count = m[2] === void 0 ? 1 : Number.parseInt(m[2], 10);
|
|
34427
|
+
const set = out.get(file) ?? /* @__PURE__ */ new Set();
|
|
34428
|
+
for (let n = start; n < start + count; n += 1) set.add(n);
|
|
34429
|
+
out.set(file, set);
|
|
34430
|
+
}
|
|
34431
|
+
return out;
|
|
34432
|
+
}
|
|
34433
|
+
function mergeAddedLines(into, from) {
|
|
34434
|
+
for (const [file, lines] of from) {
|
|
34435
|
+
const prev = into.get(file);
|
|
34436
|
+
if (prev === "all") continue;
|
|
34437
|
+
const set = prev ?? /* @__PURE__ */ new Set();
|
|
34438
|
+
for (const n of lines) set.add(n);
|
|
34439
|
+
into.set(file, set);
|
|
34440
|
+
}
|
|
34441
|
+
}
|
|
34442
|
+
function findingsOnAddedLines(findings, lines) {
|
|
34443
|
+
if (lines === void 0) return [];
|
|
34444
|
+
if (lines === "all") return [...findings];
|
|
34445
|
+
return findings.filter((f) => lines.has(f.line));
|
|
34446
|
+
}
|
|
33896
34447
|
var COMMENT_CASES = [
|
|
33897
34448
|
{
|
|
33898
34449
|
name: "a block-comment continuation carrying no leading star is flagged",
|
|
@@ -34070,6 +34621,7 @@ ${HELP}`);
|
|
|
34070
34621
|
return 1;
|
|
34071
34622
|
}
|
|
34072
34623
|
const candidates = (explicit.length > 0 ? explicit : changedFiles(root, base)).filter(isScannable);
|
|
34624
|
+
const added = explicit.length > 0 ? null : addedLineMap(root, base);
|
|
34073
34625
|
const findings = [];
|
|
34074
34626
|
for (const rel of candidates) {
|
|
34075
34627
|
const abs = path85.isAbsolute(rel) ? rel : path85.join(root, rel);
|
|
@@ -34079,7 +34631,8 @@ ${HELP}`);
|
|
|
34079
34631
|
} catch {
|
|
34080
34632
|
continue;
|
|
34081
34633
|
}
|
|
34082
|
-
|
|
34634
|
+
const all = scanText2(rel, text);
|
|
34635
|
+
findings.push(...added ? findingsOnAddedLines(all, added.get(rel)) : all);
|
|
34083
34636
|
}
|
|
34084
34637
|
try {
|
|
34085
34638
|
reportScanned({
|
|
@@ -34386,8 +34939,8 @@ if (_isCliEntry44()) {
|
|
|
34386
34939
|
}
|
|
34387
34940
|
|
|
34388
34941
|
// src/scripts/hooks/session_eol_hook.ts
|
|
34389
|
-
import * as
|
|
34390
|
-
import * as
|
|
34942
|
+
import * as fs91 from "node:fs";
|
|
34943
|
+
import * as path93 from "node:path";
|
|
34391
34944
|
import process15 from "node:process";
|
|
34392
34945
|
import { fileURLToPath as fileURLToPath59, pathToFileURL as pathToFileURL52 } from "node:url";
|
|
34393
34946
|
|
|
@@ -34561,9 +35114,112 @@ function readNewCompleteLines(filePath, fromByte) {
|
|
|
34561
35114
|
}
|
|
34562
35115
|
}
|
|
34563
35116
|
|
|
34564
|
-
// src/scripts/_lib/
|
|
35117
|
+
// src/scripts/_lib/context_observation.ts
|
|
35118
|
+
import * as fs89 from "node:fs";
|
|
35119
|
+
import * as path91 from "node:path";
|
|
35120
|
+
|
|
35121
|
+
// src/scripts/_lib/loop_guards.ts
|
|
34565
35122
|
import * as fs88 from "node:fs";
|
|
34566
35123
|
import * as path90 from "node:path";
|
|
35124
|
+
function atomicWriteJson(file, value) {
|
|
35125
|
+
const tmp = `${file}.${String(process.pid)}.tmp`;
|
|
35126
|
+
try {
|
|
35127
|
+
fs88.mkdirSync(path90.dirname(file), { recursive: true });
|
|
35128
|
+
fs88.writeFileSync(tmp, `${JSON.stringify(value)}
|
|
35129
|
+
`, "utf8");
|
|
35130
|
+
fs88.renameSync(tmp, file);
|
|
35131
|
+
return true;
|
|
35132
|
+
} catch {
|
|
35133
|
+
try {
|
|
35134
|
+
fs88.unlinkSync(tmp);
|
|
35135
|
+
} catch {
|
|
35136
|
+
}
|
|
35137
|
+
return false;
|
|
35138
|
+
}
|
|
35139
|
+
}
|
|
35140
|
+
var DEPENDENCY_PATTERNS = [
|
|
35141
|
+
{ kind: "binary", re: /\b(?:command not found|is not recognized as an internal or external command)\b/i },
|
|
35142
|
+
{ kind: "credential", re: /\b(?:not (?:authenticated|logged in)|authentication (?:failed|required)|no credentials found)\b/i },
|
|
35143
|
+
{ kind: "credential", re: /\b(?:missing|unset|not set)\b[^\n]{0,40}\b(?:credential|token|api[_ -]?key|secret)\b/i },
|
|
35144
|
+
{ kind: "permission", re: /\b(?:permission denied|forbidden|403 forbidden)\b/i },
|
|
35145
|
+
{ kind: "quota", re: /\b(?:rate limit(?:ed| exceeded| reached)?|quota exceeded|429 too many requests|spend (?:cap|limit) reached)\b/i },
|
|
35146
|
+
{ kind: "service", re: /\b(?:5\d\d (?:internal )?server error|service unavailable|connection refused)\b/i }
|
|
35147
|
+
];
|
|
35148
|
+
var DEPENDENCY_SCAN_BYTES = 64 * 1024;
|
|
35149
|
+
function detectUnavailableDependency(transcriptTail, tailLines = 200) {
|
|
35150
|
+
const lines = transcriptTail.split("\n");
|
|
35151
|
+
const window = lines.slice(Math.max(0, lines.length - tailLines));
|
|
35152
|
+
for (const line of window) {
|
|
35153
|
+
for (const { kind, re } of DEPENDENCY_PATTERNS) {
|
|
35154
|
+
if (re.test(line)) {
|
|
35155
|
+
return { kind, evidence: line.trim().slice(0, 200) };
|
|
35156
|
+
}
|
|
35157
|
+
}
|
|
35158
|
+
}
|
|
35159
|
+
return null;
|
|
35160
|
+
}
|
|
35161
|
+
function stallSignal(history, window = 3) {
|
|
35162
|
+
if (history.length === 0) {
|
|
35163
|
+
return { level: "flat", flatRun: 0, minimum: null, newMinimum: false };
|
|
35164
|
+
}
|
|
35165
|
+
const last = history[history.length - 1];
|
|
35166
|
+
const minimum = Math.min(...history);
|
|
35167
|
+
const earlier = history.slice(0, -1);
|
|
35168
|
+
const newMinimum = earlier.length > 0 && last < Math.min(...earlier);
|
|
35169
|
+
let flatRun = 1;
|
|
35170
|
+
for (let i = history.length - 2; i >= 0; i -= 1) {
|
|
35171
|
+
if (history[i] !== last) break;
|
|
35172
|
+
flatRun += 1;
|
|
35173
|
+
}
|
|
35174
|
+
if (newMinimum) return { level: "progressing", flatRun, minimum, newMinimum };
|
|
35175
|
+
if (flatRun >= window) return { level: "stalled", flatRun, minimum, newMinimum };
|
|
35176
|
+
return { level: "flat", flatRun, minimum, newMinimum };
|
|
35177
|
+
}
|
|
35178
|
+
function readUnavailableDependency(transcriptPath) {
|
|
35179
|
+
try {
|
|
35180
|
+
const raw = fs88.readFileSync(transcriptPath, "utf8");
|
|
35181
|
+
return detectUnavailableDependency(raw.slice(-DEPENDENCY_SCAN_BYTES));
|
|
35182
|
+
} catch {
|
|
35183
|
+
return null;
|
|
35184
|
+
}
|
|
35185
|
+
}
|
|
35186
|
+
|
|
35187
|
+
// src/scripts/_lib/context_observation.ts
|
|
35188
|
+
var CONTEXT_OBSERVATION_REL = path91.join(
|
|
35189
|
+
"agents",
|
|
35190
|
+
"runtime",
|
|
35191
|
+
"state",
|
|
35192
|
+
"context-observation.json"
|
|
35193
|
+
);
|
|
35194
|
+
function observationFile(repoRoot) {
|
|
35195
|
+
return path91.join(repoRoot, CONTEXT_OBSERVATION_REL);
|
|
35196
|
+
}
|
|
35197
|
+
function readContextObservation(repoRoot) {
|
|
35198
|
+
try {
|
|
35199
|
+
const parsed = JSON.parse(fs89.readFileSync(observationFile(repoRoot), "utf-8"));
|
|
35200
|
+
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) return null;
|
|
35201
|
+
const o = parsed;
|
|
35202
|
+
if (typeof o["fingerprint"] !== "string" || o["fingerprint"] === "") return null;
|
|
35203
|
+
if (typeof o["at"] !== "string") return null;
|
|
35204
|
+
return {
|
|
35205
|
+
schema_version: 1,
|
|
35206
|
+
roadmap: typeof o["roadmap"] === "string" ? o["roadmap"] : "",
|
|
35207
|
+
fingerprint: o["fingerprint"],
|
|
35208
|
+
at: o["at"]
|
|
35209
|
+
};
|
|
35210
|
+
} catch {
|
|
35211
|
+
return null;
|
|
35212
|
+
}
|
|
35213
|
+
}
|
|
35214
|
+
function premiseMoved(claimed, observed) {
|
|
35215
|
+
if (claimed === null || claimed === void 0 || claimed === "") return false;
|
|
35216
|
+
if (observed === null || observed === void 0 || observed === "") return false;
|
|
35217
|
+
return claimed !== observed;
|
|
35218
|
+
}
|
|
35219
|
+
|
|
35220
|
+
// src/scripts/_lib/run_checkpoint.ts
|
|
35221
|
+
import * as fs90 from "node:fs";
|
|
35222
|
+
import * as path92 from "node:path";
|
|
34567
35223
|
|
|
34568
35224
|
// src/scripts/_lib/roadmap_checkboxes.ts
|
|
34569
35225
|
var CHECKBOX_LINE = /^[ \t]*[-*][ \t]+\[([ xX~-])\][ \t]+(.*)$/;
|
|
@@ -34593,7 +35249,7 @@ function phaseLines(text) {
|
|
|
34593
35249
|
}
|
|
34594
35250
|
|
|
34595
35251
|
// src/scripts/_lib/run_checkpoint.ts
|
|
34596
|
-
var CHECKPOINT_DIR_REL =
|
|
35252
|
+
var CHECKPOINT_DIR_REL = path92.join("agents", "runtime", "state", "checkpoints");
|
|
34597
35253
|
function countRoadmap(text) {
|
|
34598
35254
|
const counts = { open: 0, done: 0, parked: 0, next: null };
|
|
34599
35255
|
for (const raw of phaseLines(text)) {
|
|
@@ -34614,34 +35270,34 @@ function countRoadmap(text) {
|
|
|
34614
35270
|
return counts;
|
|
34615
35271
|
}
|
|
34616
35272
|
function checkpointFile(repoRoot, runId) {
|
|
34617
|
-
return
|
|
35273
|
+
return path92.join(repoRoot, CHECKPOINT_DIR_REL, `${runId.replace(/[^A-Za-z0-9_-]/g, "_")}.json`);
|
|
34618
35274
|
}
|
|
34619
35275
|
function roadmapPath(repoRoot, slug) {
|
|
34620
|
-
return
|
|
35276
|
+
return path92.join(repoRoot, "agents", "roadmaps", `${slug}.md`);
|
|
34621
35277
|
}
|
|
34622
35278
|
function readHead(repoRoot) {
|
|
34623
35279
|
try {
|
|
34624
|
-
let gitDir =
|
|
34625
|
-
if (
|
|
34626
|
-
const m = /^gitdir:\s*(.+)$/m.exec(
|
|
35280
|
+
let gitDir = path92.join(repoRoot, ".git");
|
|
35281
|
+
if (fs90.statSync(gitDir).isFile()) {
|
|
35282
|
+
const m = /^gitdir:\s*(.+)$/m.exec(fs90.readFileSync(gitDir, "utf-8").trim());
|
|
34627
35283
|
if (m === null) return null;
|
|
34628
|
-
gitDir =
|
|
35284
|
+
gitDir = path92.resolve(repoRoot, m[1]);
|
|
34629
35285
|
}
|
|
34630
35286
|
let refRoot = gitDir;
|
|
34631
35287
|
try {
|
|
34632
|
-
const common =
|
|
34633
|
-
if (common !== "") refRoot =
|
|
35288
|
+
const common = fs90.readFileSync(path92.join(gitDir, "commondir"), "utf-8").trim();
|
|
35289
|
+
if (common !== "") refRoot = path92.resolve(gitDir, common);
|
|
34634
35290
|
} catch {
|
|
34635
35291
|
}
|
|
34636
|
-
const head =
|
|
35292
|
+
const head = fs90.readFileSync(path92.join(gitDir, "HEAD"), "utf-8").trim();
|
|
34637
35293
|
if (/^[0-9a-f]{40}$/.test(head)) return head;
|
|
34638
35294
|
const ref = /^ref:\s*(.+)$/.exec(head);
|
|
34639
35295
|
if (ref === null) return null;
|
|
34640
35296
|
const refName = ref[1];
|
|
34641
35297
|
try {
|
|
34642
|
-
return
|
|
35298
|
+
return fs90.readFileSync(path92.join(refRoot, refName), "utf-8").trim() || null;
|
|
34643
35299
|
} catch {
|
|
34644
|
-
const packed =
|
|
35300
|
+
const packed = fs90.readFileSync(path92.join(refRoot, "packed-refs"), "utf-8");
|
|
34645
35301
|
for (const line of packed.split("\n")) {
|
|
34646
35302
|
const pm = /^([0-9a-f]{40})\s+(.+)$/.exec(line.trim());
|
|
34647
35303
|
if (pm !== null && pm[2] === refName) return pm[1];
|
|
@@ -34655,7 +35311,7 @@ function readHead(repoRoot) {
|
|
|
34655
35311
|
function buildCheckpoint(repoRoot, runId, slug, opts = {}) {
|
|
34656
35312
|
let text;
|
|
34657
35313
|
try {
|
|
34658
|
-
text =
|
|
35314
|
+
text = fs90.readFileSync(roadmapPath(repoRoot, slug), "utf-8");
|
|
34659
35315
|
} catch {
|
|
34660
35316
|
return null;
|
|
34661
35317
|
}
|
|
@@ -34679,8 +35335,8 @@ function buildCheckpoint(repoRoot, runId, slug, opts = {}) {
|
|
|
34679
35335
|
function writeCheckpoint(repoRoot, cp) {
|
|
34680
35336
|
const file = checkpointFile(repoRoot, cp.run_id);
|
|
34681
35337
|
try {
|
|
34682
|
-
|
|
34683
|
-
|
|
35338
|
+
fs90.mkdirSync(path92.dirname(file), { recursive: true });
|
|
35339
|
+
fs90.writeFileSync(file, `${JSON.stringify(cp, null, 2)}
|
|
34684
35340
|
`, "utf-8");
|
|
34685
35341
|
return file;
|
|
34686
35342
|
} catch {
|
|
@@ -34691,7 +35347,7 @@ function writeCheckpoint(repoRoot, cp) {
|
|
|
34691
35347
|
// src/scripts/hooks/session_eol_hook.ts
|
|
34692
35348
|
var EXIT_WARN17 = 2;
|
|
34693
35349
|
var THRESHOLD_OVERRIDE_ENV = "AGENT_RECYCLE_THRESHOLD_TOKENS";
|
|
34694
|
-
var CONTEXT_FILL_REL =
|
|
35350
|
+
var CONTEXT_FILL_REL = path93.join("agents", "runtime", "state", "context-fill.json");
|
|
34695
35351
|
function str12(value) {
|
|
34696
35352
|
return typeof value === "string" ? value : "";
|
|
34697
35353
|
}
|
|
@@ -34706,7 +35362,7 @@ function payloadSessionId(payload, envelope) {
|
|
|
34706
35362
|
}
|
|
34707
35363
|
function readState4(file) {
|
|
34708
35364
|
try {
|
|
34709
|
-
const parsed = JSON.parse(
|
|
35365
|
+
const parsed = JSON.parse(fs91.readFileSync(file, "utf-8"));
|
|
34710
35366
|
if (parsed && typeof parsed === "object" && parsed.schema_version === 1 && parsed.counters && typeof parsed.counters.scanned_bytes === "number") {
|
|
34711
35367
|
return {
|
|
34712
35368
|
schema_version: 1,
|
|
@@ -34727,10 +35383,10 @@ function readState4(file) {
|
|
|
34727
35383
|
};
|
|
34728
35384
|
}
|
|
34729
35385
|
function envelopeExists(workspaceRoot3, since = null) {
|
|
34730
|
-
const target =
|
|
35386
|
+
const target = path93.join(workspaceRoot3, RECYCLE_ENVELOPE_REL);
|
|
34731
35387
|
let raw;
|
|
34732
35388
|
try {
|
|
34733
|
-
raw =
|
|
35389
|
+
raw = fs91.readFileSync(target, "utf-8");
|
|
34734
35390
|
} catch (exc) {
|
|
34735
35391
|
return exc?.code !== "ENOENT";
|
|
34736
35392
|
}
|
|
@@ -34744,7 +35400,7 @@ function envelopeExists(workspaceRoot3, since = null) {
|
|
|
34744
35400
|
}
|
|
34745
35401
|
}
|
|
34746
35402
|
function buildMissingEnvelopeLine(workspaceRoot3) {
|
|
34747
|
-
return `recycle advised earlier, but no envelope exists at ${
|
|
35403
|
+
return `recycle advised earlier, but no envelope exists at ${path93.join(workspaceRoot3, RECYCLE_ENVELOPE_REL)} \u2014 /clear now starts the successor from nothing. Re-run \`agent-config session:recycle\` and check that it prints the absolute path it wrote before clearing.`;
|
|
34748
35404
|
}
|
|
34749
35405
|
function readThresholdTokens() {
|
|
34750
35406
|
const override = process15.env[THRESHOLD_OVERRIDE_ENV];
|
|
@@ -34760,7 +35416,7 @@ function buildAdvisoryLine4(tokens, threshold) {
|
|
|
34760
35416
|
}
|
|
34761
35417
|
function writeContextFill(workspaceRoot3, tokens, threshold, ts) {
|
|
34762
35418
|
try {
|
|
34763
|
-
atomic_write_json(
|
|
35419
|
+
atomic_write_json(path93.join(workspaceRoot3, CONTEXT_FILL_REL), {
|
|
34764
35420
|
schema_version: 1,
|
|
34765
35421
|
final_context_tokens: tokens,
|
|
34766
35422
|
recycle_threshold_tokens: threshold,
|
|
@@ -34823,7 +35479,10 @@ function main58() {
|
|
|
34823
35479
|
try {
|
|
34824
35480
|
const slug = read_claimed_slug(workspaceRoot3, checkpointRunId);
|
|
34825
35481
|
if (slug !== null) {
|
|
34826
|
-
const
|
|
35482
|
+
const observed = readContextObservation(workspaceRoot3)?.fingerprint ?? null;
|
|
35483
|
+
const cp = buildCheckpoint(workspaceRoot3, eolSessionKey(checkpointRunId), slug, {
|
|
35484
|
+
...observed !== null ? { contextFingerprint: observed } : {}
|
|
35485
|
+
});
|
|
34827
35486
|
if (cp !== null) writeCheckpoint(workspaceRoot3, cp);
|
|
34828
35487
|
}
|
|
34829
35488
|
} catch {
|
|
@@ -34860,13 +35519,13 @@ function _isCliEntry45() {
|
|
|
34860
35519
|
if (process15.argv[1] === void 0) {
|
|
34861
35520
|
return false;
|
|
34862
35521
|
}
|
|
34863
|
-
const argvUrl = pathToFileURL52(
|
|
35522
|
+
const argvUrl = pathToFileURL52(path93.resolve(process15.argv[1])).href;
|
|
34864
35523
|
if (import.meta.url === argvUrl) {
|
|
34865
35524
|
return true;
|
|
34866
35525
|
}
|
|
34867
35526
|
try {
|
|
34868
|
-
const here =
|
|
34869
|
-
const argv =
|
|
35527
|
+
const here = fs91.realpathSync(fileURLToPath59(import.meta.url));
|
|
35528
|
+
const argv = fs91.realpathSync(path93.resolve(process15.argv[1]));
|
|
34870
35529
|
return here === argv;
|
|
34871
35530
|
} catch {
|
|
34872
35531
|
return false;
|
|
@@ -34877,14 +35536,14 @@ if (_isCliEntry45()) {
|
|
|
34877
35536
|
}
|
|
34878
35537
|
|
|
34879
35538
|
// src/scripts/hooks/tool_result_bytes_hook.ts
|
|
34880
|
-
import * as
|
|
34881
|
-
import * as
|
|
35539
|
+
import * as fs92 from "node:fs";
|
|
35540
|
+
import * as path94 from "node:path";
|
|
34882
35541
|
import { fileURLToPath as fileURLToPath60, pathToFileURL as pathToFileURL53 } from "node:url";
|
|
34883
35542
|
var EXIT_ALLOW30 = 0;
|
|
34884
35543
|
function isObject15(v) {
|
|
34885
35544
|
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
34886
35545
|
}
|
|
34887
|
-
var CENSUS_FILE =
|
|
35546
|
+
var CENSUS_FILE = path94.join("agents", "runtime", "state", "tool-result-census.jsonl");
|
|
34888
35547
|
var RESULT_KEYS = ["tool_response", "toolResponse", "tool_result", "toolUseResult"];
|
|
34889
35548
|
function _resultBytes(payload) {
|
|
34890
35549
|
for (const key of RESULT_KEYS) {
|
|
@@ -34919,13 +35578,13 @@ function unwrapPayload4(envelope) {
|
|
|
34919
35578
|
return isObject15(inner) ? inner : envelope;
|
|
34920
35579
|
}
|
|
34921
35580
|
function censusFile(consumerRoot) {
|
|
34922
|
-
return
|
|
35581
|
+
return path94.join(consumerRoot, CENSUS_FILE);
|
|
34923
35582
|
}
|
|
34924
35583
|
function _appendCensusLine(consumerRoot, line) {
|
|
34925
35584
|
if (is_replay_mode()) return;
|
|
34926
35585
|
const file = censusFile(consumerRoot);
|
|
34927
|
-
|
|
34928
|
-
|
|
35586
|
+
fs92.mkdirSync(path94.dirname(file), { recursive: true });
|
|
35587
|
+
fs92.appendFileSync(file, `${JSON.stringify(line)}
|
|
34929
35588
|
`, "utf8");
|
|
34930
35589
|
}
|
|
34931
35590
|
function processEnvelope4(envelope, consumerRoot) {
|
|
@@ -34971,10 +35630,10 @@ function _isCliEntry46() {
|
|
|
34971
35630
|
return false;
|
|
34972
35631
|
}
|
|
34973
35632
|
if (process.argv[1] === void 0) return false;
|
|
34974
|
-
const argvUrl = pathToFileURL53(
|
|
35633
|
+
const argvUrl = pathToFileURL53(path94.resolve(process.argv[1])).href;
|
|
34975
35634
|
if (import.meta.url === argvUrl) return true;
|
|
34976
35635
|
try {
|
|
34977
|
-
return
|
|
35636
|
+
return fs92.realpathSync(fileURLToPath60(import.meta.url)) === fs92.realpathSync(path94.resolve(process.argv[1]));
|
|
34978
35637
|
} catch {
|
|
34979
35638
|
return false;
|
|
34980
35639
|
}
|
|
@@ -34982,8 +35641,8 @@ function _isCliEntry46() {
|
|
|
34982
35641
|
if (_isCliEntry46()) process.exit(main59());
|
|
34983
35642
|
|
|
34984
35643
|
// src/scripts/hooks/spawn_guard_shadow_hook.ts
|
|
34985
|
-
import * as
|
|
34986
|
-
import * as
|
|
35644
|
+
import * as fs93 from "node:fs";
|
|
35645
|
+
import * as path95 from "node:path";
|
|
34987
35646
|
import { fileURLToPath as fileURLToPath61, pathToFileURL as pathToFileURL54 } from "node:url";
|
|
34988
35647
|
var EXIT_ALLOW31 = 0;
|
|
34989
35648
|
function isObject16(v) {
|
|
@@ -35061,10 +35720,10 @@ function main60() {
|
|
|
35061
35720
|
function _isCliEntry47() {
|
|
35062
35721
|
if (true) return false;
|
|
35063
35722
|
if (process.argv[1] === void 0) return false;
|
|
35064
|
-
const argvUrl = pathToFileURL54(
|
|
35723
|
+
const argvUrl = pathToFileURL54(path95.resolve(process.argv[1])).href;
|
|
35065
35724
|
if (import.meta.url === argvUrl) return true;
|
|
35066
35725
|
try {
|
|
35067
|
-
return
|
|
35726
|
+
return fs93.realpathSync(fileURLToPath61(import.meta.url)) === fs93.realpathSync(path95.resolve(process.argv[1]));
|
|
35068
35727
|
} catch {
|
|
35069
35728
|
return false;
|
|
35070
35729
|
}
|
|
@@ -35072,13 +35731,13 @@ function _isCliEntry47() {
|
|
|
35072
35731
|
if (_isCliEntry47()) process.exit(main60());
|
|
35073
35732
|
|
|
35074
35733
|
// src/scripts/hooks/source_first_gate_hook.ts
|
|
35075
|
-
import * as
|
|
35076
|
-
import * as
|
|
35734
|
+
import * as fs94 from "node:fs";
|
|
35735
|
+
import * as path96 from "node:path";
|
|
35077
35736
|
import { fileURLToPath as fileURLToPath62, pathToFileURL as pathToFileURL55 } from "node:url";
|
|
35078
35737
|
var EXIT_ALLOW32 = 0;
|
|
35079
35738
|
var MAX_SHADOW_WARNS = 2;
|
|
35080
|
-
var SHADOW_LOG =
|
|
35081
|
-
var STATE_FILE9 =
|
|
35739
|
+
var SHADOW_LOG = path96.join("agents", "runtime", "state", "source-first-gate.jsonl");
|
|
35740
|
+
var STATE_FILE9 = path96.join("agents", "runtime", "state", "source-first-gate.json");
|
|
35082
35741
|
function isObject17(v) {
|
|
35083
35742
|
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
35084
35743
|
}
|
|
@@ -35152,7 +35811,7 @@ var EMPTY_STATE = { handoverSeen: false, sourceRead: false, wouldWarn: 0 };
|
|
|
35152
35811
|
var MAX_SESSIONS2 = 50;
|
|
35153
35812
|
function readState5(root, session) {
|
|
35154
35813
|
try {
|
|
35155
|
-
const all = JSON.parse(
|
|
35814
|
+
const all = JSON.parse(fs94.readFileSync(path96.join(root, STATE_FILE9), "utf-8"));
|
|
35156
35815
|
const entry = all[session];
|
|
35157
35816
|
if (entry && typeof entry.handoverSeen === "boolean" && typeof entry.sourceRead === "boolean" && typeof entry.wouldWarn === "number") {
|
|
35158
35817
|
return entry;
|
|
@@ -35164,10 +35823,10 @@ function readState5(root, session) {
|
|
|
35164
35823
|
function writeState4(root, session, state) {
|
|
35165
35824
|
if (is_replay_mode()) return;
|
|
35166
35825
|
try {
|
|
35167
|
-
const file =
|
|
35826
|
+
const file = path96.join(root, STATE_FILE9);
|
|
35168
35827
|
let all = {};
|
|
35169
35828
|
try {
|
|
35170
|
-
all = JSON.parse(
|
|
35829
|
+
all = JSON.parse(fs94.readFileSync(file, "utf-8"));
|
|
35171
35830
|
} catch {
|
|
35172
35831
|
}
|
|
35173
35832
|
if (!isObject17(all)) all = {};
|
|
@@ -35178,8 +35837,8 @@ function writeState4(root, session, state) {
|
|
|
35178
35837
|
for (const key of keys.slice(keys.length - MAX_SESSIONS2)) pruned[key] = all[key];
|
|
35179
35838
|
all = pruned;
|
|
35180
35839
|
}
|
|
35181
|
-
|
|
35182
|
-
|
|
35840
|
+
fs94.mkdirSync(path96.dirname(file), { recursive: true });
|
|
35841
|
+
fs94.writeFileSync(file, JSON.stringify(all));
|
|
35183
35842
|
} catch {
|
|
35184
35843
|
}
|
|
35185
35844
|
}
|
|
@@ -35200,7 +35859,7 @@ function evaluateCandidates2(handoverSeen, handoverOnDisk, sourceRead) {
|
|
|
35200
35859
|
}
|
|
35201
35860
|
function handoverPresentOnDisk(root) {
|
|
35202
35861
|
try {
|
|
35203
|
-
return
|
|
35862
|
+
return fs94.statSync(path96.join(root, ".claude", "design-system")).isDirectory();
|
|
35204
35863
|
} catch {
|
|
35205
35864
|
return false;
|
|
35206
35865
|
}
|
|
@@ -35208,9 +35867,9 @@ function handoverPresentOnDisk(root) {
|
|
|
35208
35867
|
function appendShadowLine(root, line) {
|
|
35209
35868
|
if (is_replay_mode()) return;
|
|
35210
35869
|
try {
|
|
35211
|
-
const file =
|
|
35212
|
-
|
|
35213
|
-
|
|
35870
|
+
const file = path96.join(root, SHADOW_LOG);
|
|
35871
|
+
fs94.mkdirSync(path96.dirname(file), { recursive: true });
|
|
35872
|
+
fs94.appendFileSync(file, `${JSON.stringify(line)}
|
|
35214
35873
|
`, "utf8");
|
|
35215
35874
|
} catch {
|
|
35216
35875
|
}
|
|
@@ -35286,10 +35945,10 @@ function main61() {
|
|
|
35286
35945
|
function _isCliEntry48() {
|
|
35287
35946
|
if (true) return false;
|
|
35288
35947
|
if (process.argv[1] === void 0) return false;
|
|
35289
|
-
const argvUrl = pathToFileURL55(
|
|
35948
|
+
const argvUrl = pathToFileURL55(path96.resolve(process.argv[1])).href;
|
|
35290
35949
|
if (import.meta.url === argvUrl) return true;
|
|
35291
35950
|
try {
|
|
35292
|
-
return
|
|
35951
|
+
return fs94.realpathSync(fileURLToPath62(import.meta.url)) === fs94.realpathSync(path96.resolve(process.argv[1]));
|
|
35293
35952
|
} catch {
|
|
35294
35953
|
return false;
|
|
35295
35954
|
}
|
|
@@ -35297,12 +35956,12 @@ function _isCliEntry48() {
|
|
|
35297
35956
|
if (_isCliEntry48()) process.exit(main61());
|
|
35298
35957
|
|
|
35299
35958
|
// src/scripts/hooks/interruption_ledger_hook.ts
|
|
35300
|
-
import * as
|
|
35301
|
-
import * as
|
|
35959
|
+
import * as fs95 from "node:fs";
|
|
35960
|
+
import * as path97 from "node:path";
|
|
35302
35961
|
import { fileURLToPath as fileURLToPath63, pathToFileURL as pathToFileURL56 } from "node:url";
|
|
35303
35962
|
var EXIT_OK2 = 0;
|
|
35304
35963
|
var TRANSCRIPT_READ_MAX_BYTES2 = 2 * 1024 * 1024;
|
|
35305
|
-
var LEDGER_RELPATH =
|
|
35964
|
+
var LEDGER_RELPATH = path97.join("agents", "runtime", "state", "interruptions.jsonl");
|
|
35306
35965
|
function hasNumberedOptions(reply) {
|
|
35307
35966
|
let count = 0;
|
|
35308
35967
|
for (const line of reply.split("\n")) {
|
|
@@ -35326,14 +35985,14 @@ function classifyReply(reply) {
|
|
|
35326
35985
|
function readClaimedRoadmap(workspaceRoot3, sessionId2) {
|
|
35327
35986
|
if (!sessionId2) return null;
|
|
35328
35987
|
try {
|
|
35329
|
-
const file =
|
|
35988
|
+
const file = path97.join(
|
|
35330
35989
|
workspaceRoot3,
|
|
35331
35990
|
"agents",
|
|
35332
35991
|
"runtime",
|
|
35333
35992
|
"state",
|
|
35334
35993
|
`roadmap-claim-${sessionId2}.json`
|
|
35335
35994
|
);
|
|
35336
|
-
const parsed = JSON.parse(
|
|
35995
|
+
const parsed = JSON.parse(fs95.readFileSync(file, "utf8"));
|
|
35337
35996
|
if (parsed === null || typeof parsed !== "object") return null;
|
|
35338
35997
|
const slug = parsed["slug"];
|
|
35339
35998
|
return typeof slug === "string" && slug.length > 0 ? slug : null;
|
|
@@ -35344,7 +36003,7 @@ function readClaimedRoadmap(workspaceRoot3, sessionId2) {
|
|
|
35344
36003
|
function alreadyRecorded(ledgerPath, runId, turn) {
|
|
35345
36004
|
let raw;
|
|
35346
36005
|
try {
|
|
35347
|
-
raw =
|
|
36006
|
+
raw = fs95.readFileSync(ledgerPath, "utf8");
|
|
35348
36007
|
} catch {
|
|
35349
36008
|
return false;
|
|
35350
36009
|
}
|
|
@@ -35388,7 +36047,7 @@ function main62() {
|
|
|
35388
36047
|
if (!lastAssistant) return EXIT_OK2;
|
|
35389
36048
|
const sessionId2 = str14(payload["session_id"]) || str14(envelope["session_id"]);
|
|
35390
36049
|
const runId = sessionId2 ? derive_session_tag(sessionId2) : "unknown";
|
|
35391
|
-
const ledgerPath =
|
|
36050
|
+
const ledgerPath = path97.join(workspaceRoot3, LEDGER_RELPATH);
|
|
35392
36051
|
if (alreadyRecorded(ledgerPath, runId, turnOrdinal)) return EXIT_OK2;
|
|
35393
36052
|
const verdict = classifyReply(lastAssistant);
|
|
35394
36053
|
const record = {
|
|
@@ -35400,8 +36059,8 @@ function main62() {
|
|
|
35400
36059
|
at: (/* @__PURE__ */ new Date()).toISOString()
|
|
35401
36060
|
};
|
|
35402
36061
|
try {
|
|
35403
|
-
|
|
35404
|
-
|
|
36062
|
+
fs95.mkdirSync(path97.dirname(ledgerPath), { recursive: true });
|
|
36063
|
+
fs95.appendFileSync(ledgerPath, `${JSON.stringify(record)}
|
|
35405
36064
|
`, "utf8");
|
|
35406
36065
|
} catch {
|
|
35407
36066
|
}
|
|
@@ -35411,13 +36070,13 @@ function _isCliEntry49() {
|
|
|
35411
36070
|
if (process.argv[1] === void 0) {
|
|
35412
36071
|
return false;
|
|
35413
36072
|
}
|
|
35414
|
-
const argvUrl = pathToFileURL56(
|
|
36073
|
+
const argvUrl = pathToFileURL56(path97.resolve(process.argv[1])).href;
|
|
35415
36074
|
if (import.meta.url === argvUrl) {
|
|
35416
36075
|
return true;
|
|
35417
36076
|
}
|
|
35418
36077
|
try {
|
|
35419
|
-
const here =
|
|
35420
|
-
const argv =
|
|
36078
|
+
const here = fs95.realpathSync(fileURLToPath63(import.meta.url));
|
|
36079
|
+
const argv = fs95.realpathSync(path97.resolve(process.argv[1]));
|
|
35421
36080
|
return here === argv;
|
|
35422
36081
|
} catch {
|
|
35423
36082
|
return false;
|
|
@@ -35428,15 +36087,15 @@ if (_isCliEntry49()) {
|
|
|
35428
36087
|
}
|
|
35429
36088
|
|
|
35430
36089
|
// src/scripts/hooks/run_continuation_hook.ts
|
|
35431
|
-
import * as
|
|
36090
|
+
import * as fs97 from "node:fs";
|
|
35432
36091
|
|
|
35433
36092
|
// src/scripts/_lib/billing_grant.ts
|
|
35434
|
-
import * as
|
|
35435
|
-
import * as
|
|
35436
|
-
var BILLING_GRANT_DIR_REL =
|
|
36093
|
+
import * as fs96 from "node:fs";
|
|
36094
|
+
import * as path98 from "node:path";
|
|
36095
|
+
var BILLING_GRANT_DIR_REL = path98.join("agents", "runtime", "billing-grants");
|
|
35437
36096
|
var BILLING_GRANT_MAX_AGE_MS = 24 * 60 * 60 * 1e3;
|
|
35438
36097
|
function grantFile(repoRoot, runId) {
|
|
35439
|
-
return
|
|
36098
|
+
return path98.join(
|
|
35440
36099
|
repoRoot,
|
|
35441
36100
|
BILLING_GRANT_DIR_REL,
|
|
35442
36101
|
`${runId.replace(/[^A-Za-z0-9_-]/g, "_")}.json`
|
|
@@ -35444,79 +36103,96 @@ function grantFile(repoRoot, runId) {
|
|
|
35444
36103
|
}
|
|
35445
36104
|
function revokeBillingGrant(repoRoot, runId) {
|
|
35446
36105
|
try {
|
|
35447
|
-
|
|
36106
|
+
fs96.unlinkSync(grantFile(repoRoot, runId));
|
|
35448
36107
|
} catch {
|
|
35449
36108
|
}
|
|
35450
36109
|
}
|
|
35451
36110
|
|
|
35452
36111
|
// src/scripts/hooks/run_continuation_hook.ts
|
|
35453
|
-
import * as
|
|
36112
|
+
import * as path99 from "node:path";
|
|
35454
36113
|
import { fileURLToPath as fileURLToPath64, pathToFileURL as pathToFileURL57 } from "node:url";
|
|
35455
36114
|
|
|
35456
|
-
// src/scripts/_lib/
|
|
35457
|
-
|
|
35458
|
-
|
|
35459
|
-
|
|
35460
|
-
|
|
35461
|
-
|
|
35462
|
-
|
|
35463
|
-
|
|
35464
|
-
|
|
35465
|
-
|
|
35466
|
-
|
|
35467
|
-
|
|
35468
|
-
|
|
35469
|
-
|
|
35470
|
-
|
|
35471
|
-
|
|
35472
|
-
|
|
35473
|
-
|
|
35474
|
-
|
|
35475
|
-
|
|
35476
|
-
|
|
35477
|
-
|
|
35478
|
-
{ kind: "credential", re: /\b(?:missing|unset|not set)\b[^\n]{0,40}\b(?:credential|token|api[_ -]?key|secret)\b/i },
|
|
35479
|
-
{ kind: "permission", re: /\b(?:permission denied|forbidden|403 forbidden)\b/i },
|
|
35480
|
-
{ kind: "quota", re: /\b(?:rate limit(?:ed| exceeded| reached)?|quota exceeded|429 too many requests|spend (?:cap|limit) reached)\b/i },
|
|
35481
|
-
{ kind: "service", re: /\b(?:5\d\d (?:internal )?server error|service unavailable|connection refused)\b/i }
|
|
36115
|
+
// src/scripts/_lib/outcome_vocabularies.ts
|
|
36116
|
+
var RUN_TERMINAL_STATES = [
|
|
36117
|
+
"success",
|
|
36118
|
+
"clean-no-op",
|
|
36119
|
+
"blocked",
|
|
36120
|
+
"approval-required",
|
|
36121
|
+
"exhausted",
|
|
36122
|
+
"stagnated",
|
|
36123
|
+
/**
|
|
36124
|
+
* The plan premise this run was built on no longer holds — the situational
|
|
36125
|
+
* -awareness fingerprint the run engaged under (`origin/main` plus every open
|
|
36126
|
+
* PR head) was re-observed and differs.
|
|
36127
|
+
*
|
|
36128
|
+
* Added by `road-to-wired-instruments` Phase 2 under the AI-council decision
|
|
36129
|
+
* of 2026-09-03 (option (a), unanimous). It is NOT `blocked` with a reason
|
|
36130
|
+
* field: premise invalidation is operationally distinct from a missing
|
|
36131
|
+
* precondition and from an exhausted budget, and folding it into either loses
|
|
36132
|
+
* both aggregation by state and type-enforced exhaustive handling. The
|
|
36133
|
+
* remedy differs too — re-probe and re-plan, where `blocked` says obtain the
|
|
36134
|
+
* missing thing and `exhausted` says the budget was too small.
|
|
36135
|
+
*/
|
|
36136
|
+
"premise-invalidated"
|
|
35482
36137
|
];
|
|
35483
|
-
var
|
|
35484
|
-
|
|
35485
|
-
|
|
35486
|
-
|
|
35487
|
-
|
|
35488
|
-
|
|
35489
|
-
|
|
35490
|
-
|
|
35491
|
-
|
|
35492
|
-
|
|
35493
|
-
|
|
35494
|
-
|
|
36138
|
+
var RUN_TERMINAL_VOCABULARY_VERSION = 2;
|
|
36139
|
+
|
|
36140
|
+
// src/scripts/_lib/continuation_ladder.ts
|
|
36141
|
+
var MAX_ITERATIONS = 25;
|
|
36142
|
+
var WALL_CLOCK_CAP_MS = 4 * 60 * 60 * 1e3;
|
|
36143
|
+
var STALL_WINDOW = 3;
|
|
36144
|
+
var HALT_ACTIONS = [
|
|
36145
|
+
"halt-max-iterations",
|
|
36146
|
+
"halt-wall-clock",
|
|
36147
|
+
"halt-stall",
|
|
36148
|
+
// Phase 5.4. Checked BEFORE the counter rungs: a dependency the run cannot
|
|
36149
|
+
// obtain is not something more iterations close, so consuming the budget
|
|
36150
|
+
// against it is the waste the rung exists to stop.
|
|
36151
|
+
"halt-dependency-unavailable",
|
|
36152
|
+
// `road-to-wired-instruments` 2.2, and BEFORE the counter rungs for the same
|
|
36153
|
+
// reason: a run whose plan premise moved does not become correct by running
|
|
36154
|
+
// more iterations against the stale plan, and letting it cap out reports
|
|
36155
|
+
// `exhausted` — a budget problem, whose remedy is a bigger budget — for what
|
|
36156
|
+
// is actually a staleness problem, whose remedy is a re-probe.
|
|
36157
|
+
"halt-premise-invalidated"
|
|
36158
|
+
];
|
|
36159
|
+
var TERMINAL_STATE_BY_ACTION = {
|
|
36160
|
+
engage: null,
|
|
36161
|
+
complete: "success",
|
|
36162
|
+
blocked: "blocked",
|
|
36163
|
+
"halt-max-iterations": "exhausted",
|
|
36164
|
+
"halt-wall-clock": "exhausted",
|
|
36165
|
+
"halt-stall": "stagnated",
|
|
36166
|
+
"halt-dependency-unavailable": "blocked",
|
|
36167
|
+
"halt-premise-invalidated": "premise-invalidated"
|
|
36168
|
+
};
|
|
36169
|
+
function terminalStateFor(action) {
|
|
36170
|
+
return TERMINAL_STATE_BY_ACTION[action] ?? null;
|
|
35495
36171
|
}
|
|
35496
|
-
function
|
|
35497
|
-
|
|
35498
|
-
|
|
36172
|
+
function ladder(state, openCount, nowMs, blockedCount, caps = {
|
|
36173
|
+
maxIterations: MAX_ITERATIONS,
|
|
36174
|
+
wallClockMs: WALL_CLOCK_CAP_MS,
|
|
36175
|
+
stallWindow: STALL_WINDOW
|
|
36176
|
+
}, unavailable = null, premiseInvalidated = false) {
|
|
36177
|
+
if (state.halted) return state.halted;
|
|
36178
|
+
if (openCount === 0) return blockedCount > 0 ? "blocked" : "complete";
|
|
36179
|
+
if (unavailable !== null) return "halt-dependency-unavailable";
|
|
36180
|
+
if (premiseInvalidated) return "halt-premise-invalidated";
|
|
36181
|
+
if (state.iterations >= caps.maxIterations) return "halt-max-iterations";
|
|
36182
|
+
const started = Date.parse(state.started_at);
|
|
36183
|
+
if (Number.isFinite(started) && nowMs - started >= caps.wallClockMs) {
|
|
36184
|
+
return "halt-wall-clock";
|
|
35499
36185
|
}
|
|
35500
|
-
const
|
|
35501
|
-
|
|
35502
|
-
|
|
35503
|
-
const newMinimum = earlier.length > 0 && last < Math.min(...earlier);
|
|
35504
|
-
let flatRun = 1;
|
|
35505
|
-
for (let i = history.length - 2; i >= 0; i -= 1) {
|
|
35506
|
-
if (history[i] !== last) break;
|
|
35507
|
-
flatRun += 1;
|
|
36186
|
+
const tail = state.history.slice(-caps.stallWindow);
|
|
36187
|
+
if (tail.length >= caps.stallWindow && tail.every((n) => n === openCount)) {
|
|
36188
|
+
return "halt-stall";
|
|
35508
36189
|
}
|
|
35509
|
-
|
|
35510
|
-
if (flatRun >= window) return { level: "stalled", flatRun, minimum, newMinimum };
|
|
35511
|
-
return { level: "flat", flatRun, minimum, newMinimum };
|
|
36190
|
+
return "engage";
|
|
35512
36191
|
}
|
|
35513
|
-
function
|
|
35514
|
-
|
|
35515
|
-
|
|
35516
|
-
|
|
35517
|
-
} catch {
|
|
35518
|
-
return null;
|
|
35519
|
-
}
|
|
36192
|
+
function parseHaltStamp(v) {
|
|
36193
|
+
if (typeof v !== "string") return null;
|
|
36194
|
+
if (HALT_ACTIONS.includes(v)) return v;
|
|
36195
|
+
return v.startsWith("halt-") ? v : null;
|
|
35520
36196
|
}
|
|
35521
36197
|
|
|
35522
36198
|
// src/scripts/hooks/run_continuation_hook.ts
|
|
@@ -35524,16 +36200,13 @@ var EXIT_ALLOW33 = 0;
|
|
|
35524
36200
|
var EXIT_BLOCK5 = 1;
|
|
35525
36201
|
var BLOCKED_BY_MARKER = /<!--\s*blocked-by:\s*\S[^>]*-->/;
|
|
35526
36202
|
var LEDGER_TAIL_MAX_BYTES = 512 * 1024;
|
|
35527
|
-
var EVENTS_RELPATH =
|
|
36203
|
+
var EVENTS_RELPATH = path99.join(
|
|
35528
36204
|
"agents",
|
|
35529
36205
|
"runtime",
|
|
35530
36206
|
"state",
|
|
35531
36207
|
"run-continuation.jsonl"
|
|
35532
36208
|
);
|
|
35533
|
-
var STATE_DIR_REL =
|
|
35534
|
-
var MAX_ITERATIONS = 25;
|
|
35535
|
-
var WALL_CLOCK_CAP_MS = 4 * 60 * 60 * 1e3;
|
|
35536
|
-
var STALL_WINDOW = 3;
|
|
36209
|
+
var STATE_DIR_REL = path99.join("agents", "runtime", "state");
|
|
35537
36210
|
var ABSENT_CONFIRM_FIRES = 2;
|
|
35538
36211
|
var DUPLICATE_WINDOW_MS = 60 * 1e3;
|
|
35539
36212
|
function isDuplicateFire(state, turnOrdinal, openCount, nowMs, roadmapSource) {
|
|
@@ -35548,15 +36221,6 @@ function isDuplicateFire(state, turnOrdinal, openCount, nowMs, roadmapSource) {
|
|
|
35548
36221
|
const at = Date.parse(state.last_engaged_at ?? "");
|
|
35549
36222
|
return Number.isFinite(at) && nowMs - at < DUPLICATE_WINDOW_MS;
|
|
35550
36223
|
}
|
|
35551
|
-
var HALT_ACTIONS = [
|
|
35552
|
-
"halt-max-iterations",
|
|
35553
|
-
"halt-wall-clock",
|
|
35554
|
-
"halt-stall",
|
|
35555
|
-
// Phase 5.4. Checked BEFORE the counter rungs: a dependency the run cannot
|
|
35556
|
-
// obtain is not something more iterations close, so consuming the budget
|
|
35557
|
-
// against it is the waste the rung exists to stop.
|
|
35558
|
-
"halt-dependency-unavailable"
|
|
35559
|
-
];
|
|
35560
36224
|
function parseExecutionMode(text) {
|
|
35561
36225
|
if (!text.startsWith("---")) return null;
|
|
35562
36226
|
const end = text.indexOf("\n---", 3);
|
|
@@ -35611,42 +36275,23 @@ function extractVerify(stepText) {
|
|
|
35611
36275
|
if (backticked !== null) return backticked[1].trim() || null;
|
|
35612
36276
|
return null;
|
|
35613
36277
|
}
|
|
35614
|
-
function ladder(state, openCount, nowMs, blockedCount, caps = {
|
|
35615
|
-
maxIterations: MAX_ITERATIONS,
|
|
35616
|
-
wallClockMs: WALL_CLOCK_CAP_MS,
|
|
35617
|
-
stallWindow: STALL_WINDOW
|
|
35618
|
-
}, unavailable = null) {
|
|
35619
|
-
if (state.halted) return state.halted;
|
|
35620
|
-
if (openCount === 0) return blockedCount > 0 ? "blocked" : "complete";
|
|
35621
|
-
if (unavailable !== null) return "halt-dependency-unavailable";
|
|
35622
|
-
if (state.iterations >= caps.maxIterations) return "halt-max-iterations";
|
|
35623
|
-
const started = Date.parse(state.started_at);
|
|
35624
|
-
if (Number.isFinite(started) && nowMs - started >= caps.wallClockMs) {
|
|
35625
|
-
return "halt-wall-clock";
|
|
35626
|
-
}
|
|
35627
|
-
const tail = state.history.slice(-caps.stallWindow);
|
|
35628
|
-
if (tail.length >= caps.stallWindow && tail.every((n) => n === openCount)) {
|
|
35629
|
-
return "halt-stall";
|
|
35630
|
-
}
|
|
35631
|
-
return "engage";
|
|
35632
|
-
}
|
|
35633
36278
|
function stateRelPath(runId, slug) {
|
|
35634
36279
|
const safeRun = runId.replace(/[^A-Za-z0-9_-]/g, "_");
|
|
35635
36280
|
const safeSlug = slug.replace(/[^A-Za-z0-9_-]/g, "_");
|
|
35636
|
-
return
|
|
36281
|
+
return path99.join(STATE_DIR_REL, `run-continuation-${safeRun}-${safeSlug}.json`);
|
|
35637
36282
|
}
|
|
35638
36283
|
function legacyStateRelPath(runId) {
|
|
35639
36284
|
const safe = runId.replace(/[^A-Za-z0-9_-]/g, "_");
|
|
35640
|
-
return
|
|
36285
|
+
return path99.join(STATE_DIR_REL, `run-continuation-${safe}.json`);
|
|
35641
36286
|
}
|
|
35642
36287
|
function readRunState(workspaceRoot3, runId, slug) {
|
|
35643
|
-
const keyedFile =
|
|
36288
|
+
const keyedFile = path99.join(workspaceRoot3, stateRelPath(runId, slug));
|
|
35644
36289
|
const keyed = readState6(keyedFile);
|
|
35645
36290
|
if (keyed !== null) return { state: keyed, from: "keyed", keyedFile };
|
|
35646
36291
|
if (fileExists(keyedFile)) {
|
|
35647
36292
|
return { state: null, from: "keyed", keyedFile };
|
|
35648
36293
|
}
|
|
35649
|
-
const legacy = readState6(
|
|
36294
|
+
const legacy = readState6(path99.join(workspaceRoot3, legacyStateRelPath(runId)));
|
|
35650
36295
|
if (legacy === null) return { state: null, from: "none", keyedFile };
|
|
35651
36296
|
if (legacy.roadmap !== void 0 && legacy.roadmap !== slug) {
|
|
35652
36297
|
return { state: null, from: "none", keyedFile };
|
|
@@ -35659,25 +36304,25 @@ function writeState5(file, state) {
|
|
|
35659
36304
|
function clearRunState(workspaceRoot3, runId, keyedFile, adoptedLegacy) {
|
|
35660
36305
|
revokeBillingGrant(workspaceRoot3, runId);
|
|
35661
36306
|
try {
|
|
35662
|
-
|
|
36307
|
+
fs97.rmSync(keyedFile, { force: true });
|
|
35663
36308
|
} catch {
|
|
35664
36309
|
}
|
|
35665
36310
|
if (!adoptedLegacy) return;
|
|
35666
36311
|
try {
|
|
35667
|
-
|
|
36312
|
+
fs97.rmSync(path99.join(workspaceRoot3, legacyStateRelPath(runId)), { force: true });
|
|
35668
36313
|
} catch {
|
|
35669
36314
|
}
|
|
35670
36315
|
}
|
|
35671
36316
|
function fileExists(p) {
|
|
35672
36317
|
try {
|
|
35673
|
-
return
|
|
36318
|
+
return fs97.statSync(p).isFile();
|
|
35674
36319
|
} catch {
|
|
35675
36320
|
return false;
|
|
35676
36321
|
}
|
|
35677
36322
|
}
|
|
35678
36323
|
function readState6(file) {
|
|
35679
36324
|
try {
|
|
35680
|
-
const parsed = JSON.parse(
|
|
36325
|
+
const parsed = JSON.parse(fs97.readFileSync(file, "utf8"));
|
|
35681
36326
|
if (parsed === null || typeof parsed !== "object") return null;
|
|
35682
36327
|
const o = parsed;
|
|
35683
36328
|
if (typeof o["started_at"] !== "string") return null;
|
|
@@ -35707,26 +36352,27 @@ function readState6(file) {
|
|
|
35707
36352
|
if (o["inert_reported"] === true) {
|
|
35708
36353
|
rec.inert_reported = true;
|
|
35709
36354
|
}
|
|
35710
|
-
|
|
35711
|
-
|
|
35712
|
-
rec.halted = halted;
|
|
36355
|
+
if (typeof o["context_fingerprint"] === "string" && o["context_fingerprint"] !== "") {
|
|
36356
|
+
rec.context_fingerprint = o["context_fingerprint"];
|
|
35713
36357
|
}
|
|
36358
|
+
const halted = parseHaltStamp(o["halted"]);
|
|
36359
|
+
if (halted !== null) rec.halted = halted;
|
|
35714
36360
|
return rec;
|
|
35715
36361
|
} catch {
|
|
35716
36362
|
return null;
|
|
35717
36363
|
}
|
|
35718
36364
|
}
|
|
35719
36365
|
function normalizeDir(p) {
|
|
35720
|
-
const abs =
|
|
36366
|
+
const abs = path99.resolve(p);
|
|
35721
36367
|
try {
|
|
35722
|
-
return
|
|
36368
|
+
return fs97.realpathSync(abs);
|
|
35723
36369
|
} catch {
|
|
35724
36370
|
return abs;
|
|
35725
36371
|
}
|
|
35726
36372
|
}
|
|
35727
36373
|
function normalizeFile(p) {
|
|
35728
|
-
const abs =
|
|
35729
|
-
return
|
|
36374
|
+
const abs = path99.resolve(p);
|
|
36375
|
+
return path99.join(normalizeDir(path99.dirname(abs)), path99.basename(abs));
|
|
35730
36376
|
}
|
|
35731
36377
|
function provenance(workspaceRoot3, claimPath, sessionRoot, sessionCwd) {
|
|
35732
36378
|
const reader = normalizeDir(workspaceRoot3);
|
|
@@ -35753,36 +36399,36 @@ function provenance(workspaceRoot3, claimPath, sessionRoot, sessionCwd) {
|
|
|
35753
36399
|
};
|
|
35754
36400
|
}
|
|
35755
36401
|
function resolveRoadmap(sessionRoot, workspaceRoot3, slug) {
|
|
35756
|
-
const dirRel =
|
|
36402
|
+
const dirRel = path99.join("agents", "roadmaps");
|
|
35757
36403
|
const stem = slug.trim().replace(/\.md$/, "");
|
|
35758
|
-
const rel =
|
|
35759
|
-
const norm =
|
|
35760
|
-
if (
|
|
35761
|
-
if (sessionRoot !== workspaceRoot3 && isDirectory(
|
|
35762
|
-
return
|
|
36404
|
+
const rel = path99.join(dirRel, `${stem}.md`);
|
|
36405
|
+
const norm = path99.normalize(rel);
|
|
36406
|
+
if (path99.dirname(norm) !== dirRel) return null;
|
|
36407
|
+
if (sessionRoot !== workspaceRoot3 && isDirectory(path99.join(sessionRoot, dirRel))) {
|
|
36408
|
+
return path99.join(sessionRoot, norm);
|
|
35763
36409
|
}
|
|
35764
|
-
return
|
|
36410
|
+
return path99.join(normalizeDir(workspaceRoot3), norm);
|
|
35765
36411
|
}
|
|
35766
36412
|
function isDirectory(p) {
|
|
35767
36413
|
try {
|
|
35768
|
-
return
|
|
36414
|
+
return fs97.statSync(p).isDirectory();
|
|
35769
36415
|
} catch {
|
|
35770
36416
|
return false;
|
|
35771
36417
|
}
|
|
35772
36418
|
}
|
|
35773
36419
|
function eventAlreadyLogged(workspaceRoot3, runId, slug, event) {
|
|
35774
36420
|
try {
|
|
35775
|
-
const file =
|
|
35776
|
-
const size =
|
|
36421
|
+
const file = path99.join(workspaceRoot3, EVENTS_RELPATH);
|
|
36422
|
+
const size = fs97.statSync(file).size;
|
|
35777
36423
|
const start = Math.max(0, size - LEDGER_TAIL_MAX_BYTES);
|
|
35778
|
-
const fd =
|
|
36424
|
+
const fd = fs97.openSync(file, "r");
|
|
35779
36425
|
let text;
|
|
35780
36426
|
try {
|
|
35781
36427
|
const buf = Buffer.alloc(size - start);
|
|
35782
|
-
const read =
|
|
36428
|
+
const read = fs97.readSync(fd, buf, 0, buf.length, start);
|
|
35783
36429
|
text = buf.subarray(0, read).toString("utf8");
|
|
35784
36430
|
} finally {
|
|
35785
|
-
|
|
36431
|
+
fs97.closeSync(fd);
|
|
35786
36432
|
}
|
|
35787
36433
|
for (const line of text.split("\n")) {
|
|
35788
36434
|
if (line === "") continue;
|
|
@@ -35805,9 +36451,9 @@ function eventAlreadyLogged(workspaceRoot3, runId, slug, event) {
|
|
|
35805
36451
|
}
|
|
35806
36452
|
function appendEvent2(workspaceRoot3, record) {
|
|
35807
36453
|
try {
|
|
35808
|
-
const file =
|
|
35809
|
-
|
|
35810
|
-
|
|
36454
|
+
const file = path99.join(workspaceRoot3, EVENTS_RELPATH);
|
|
36455
|
+
fs97.mkdirSync(path99.dirname(file), { recursive: true });
|
|
36456
|
+
fs97.appendFileSync(file, `${JSON.stringify(record)}
|
|
35811
36457
|
`, "utf8");
|
|
35812
36458
|
} catch {
|
|
35813
36459
|
}
|
|
@@ -35815,7 +36461,7 @@ function appendEvent2(workspaceRoot3, record) {
|
|
|
35815
36461
|
function refusedThisTurn(workspaceRoot3, sessionId2, turnOrdinal) {
|
|
35816
36462
|
try {
|
|
35817
36463
|
const file = sessionRefusalFile(workspaceRoot3, deriveSessionKey(sessionId2 || "unknown-session"));
|
|
35818
|
-
const rec = parseRecord(
|
|
36464
|
+
const rec = parseRecord(fs97.readFileSync(file, "utf-8"));
|
|
35819
36465
|
return rec !== null && rec.refused_turn === turnOrdinal;
|
|
35820
36466
|
} catch {
|
|
35821
36467
|
return false;
|
|
@@ -35849,7 +36495,7 @@ function main63() {
|
|
|
35849
36495
|
let roadmapText = null;
|
|
35850
36496
|
if (roadmapPath2 !== null) {
|
|
35851
36497
|
try {
|
|
35852
|
-
roadmapText =
|
|
36498
|
+
roadmapText = fs97.readFileSync(roadmapPath2, "utf8");
|
|
35853
36499
|
roadmapFile = roadmapPath2;
|
|
35854
36500
|
} catch {
|
|
35855
36501
|
roadmapText = null;
|
|
@@ -35898,7 +36544,7 @@ function main63() {
|
|
|
35898
36544
|
);
|
|
35899
36545
|
if (!transcriptPath) return EXIT_ALLOW33;
|
|
35900
36546
|
try {
|
|
35901
|
-
if (
|
|
36547
|
+
if (fs97.statSync(transcriptPath).size > TRANSCRIPT_READ_MAX_BYTES) {
|
|
35902
36548
|
const inert = readRunState(workspaceRoot3, runId, slug);
|
|
35903
36549
|
if (inert.state !== null && inert.state.inert_reported !== true) {
|
|
35904
36550
|
const inertRoots = provenance(
|
|
@@ -35973,7 +36619,17 @@ function main63() {
|
|
|
35973
36619
|
}
|
|
35974
36620
|
const unavailable = readUnavailableDependency(transcriptPath);
|
|
35975
36621
|
state.stall = stallSignal(state.history, STALL_WINDOW).level;
|
|
35976
|
-
const
|
|
36622
|
+
const observed = readContextObservation(workspaceRoot3)?.fingerprint ?? null;
|
|
36623
|
+
const premiseInvalidated = premiseMoved(state.context_fingerprint, observed);
|
|
36624
|
+
const action = ladder(
|
|
36625
|
+
state,
|
|
36626
|
+
scan.open,
|
|
36627
|
+
Date.now(),
|
|
36628
|
+
scan.blocked,
|
|
36629
|
+
void 0,
|
|
36630
|
+
unavailable,
|
|
36631
|
+
premiseInvalidated
|
|
36632
|
+
);
|
|
35977
36633
|
if (action !== "engage") {
|
|
35978
36634
|
const alreadyStamped = prev?.halted !== void 0;
|
|
35979
36635
|
const alreadyBlocked = action === "blocked" && eventAlreadyLogged(workspaceRoot3, runId, slug, "blocked");
|
|
@@ -35986,6 +36642,12 @@ function main63() {
|
|
|
35986
36642
|
iterations: state.iterations,
|
|
35987
36643
|
open: scan.open,
|
|
35988
36644
|
blocked: scan.blocked,
|
|
36645
|
+
// A ledger line is a persisted shape carrying a `RunTerminalState`,
|
|
36646
|
+
// so it names the vocabulary version it was written against: a
|
|
36647
|
+
// reader meeting an unknown value can then tell a newer writer
|
|
36648
|
+
// from a corrupt row.
|
|
36649
|
+
terminal_state: terminalStateFor(action),
|
|
36650
|
+
terminal_vocabulary_version: RUN_TERMINAL_VOCABULARY_VERSION,
|
|
35989
36651
|
at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
35990
36652
|
...roots
|
|
35991
36653
|
});
|
|
@@ -36006,6 +36668,9 @@ function main63() {
|
|
|
36006
36668
|
}
|
|
36007
36669
|
state.iterations += 1;
|
|
36008
36670
|
state.last_turn = turnOrdinal;
|
|
36671
|
+
if (state.context_fingerprint === void 0 && observed !== null) {
|
|
36672
|
+
state.context_fingerprint = observed;
|
|
36673
|
+
}
|
|
36009
36674
|
state.history.push(scan.open);
|
|
36010
36675
|
state.last_engaged_at = (/* @__PURE__ */ new Date()).toISOString();
|
|
36011
36676
|
if (!writeState5(stateFile4, state)) {
|
|
@@ -36038,11 +36703,11 @@ function _isCliEntry50() {
|
|
|
36038
36703
|
return false;
|
|
36039
36704
|
}
|
|
36040
36705
|
if (process.argv[1] === void 0) return false;
|
|
36041
|
-
const argvUrl = pathToFileURL57(
|
|
36706
|
+
const argvUrl = pathToFileURL57(path99.resolve(process.argv[1])).href;
|
|
36042
36707
|
if (import.meta.url === argvUrl) return true;
|
|
36043
36708
|
try {
|
|
36044
|
-
const here =
|
|
36045
|
-
const argv =
|
|
36709
|
+
const here = fs97.realpathSync(fileURLToPath64(import.meta.url));
|
|
36710
|
+
const argv = fs97.realpathSync(path99.resolve(process.argv[1]));
|
|
36046
36711
|
return here === argv;
|
|
36047
36712
|
} catch {
|
|
36048
36713
|
return false;
|
|
@@ -36053,26 +36718,14 @@ if (_isCliEntry50()) {
|
|
|
36053
36718
|
}
|
|
36054
36719
|
|
|
36055
36720
|
// src/scripts/hooks/journal_record_hook.ts
|
|
36056
|
-
import * as
|
|
36057
|
-
import * as
|
|
36721
|
+
import * as fs99 from "node:fs";
|
|
36722
|
+
import * as path101 from "node:path";
|
|
36058
36723
|
import { fileURLToPath as fileURLToPath65, pathToFileURL as pathToFileURL58 } from "node:url";
|
|
36059
36724
|
|
|
36060
36725
|
// src/scripts/_lib/runtime_journal.ts
|
|
36061
36726
|
import * as crypto14 from "node:crypto";
|
|
36062
|
-
import * as
|
|
36063
|
-
import * as
|
|
36064
|
-
|
|
36065
|
-
// src/scripts/_lib/outcome_vocabularies.ts
|
|
36066
|
-
var RUN_TERMINAL_STATES = [
|
|
36067
|
-
"success",
|
|
36068
|
-
"clean-no-op",
|
|
36069
|
-
"blocked",
|
|
36070
|
-
"approval-required",
|
|
36071
|
-
"exhausted",
|
|
36072
|
-
"stagnated"
|
|
36073
|
-
];
|
|
36074
|
-
|
|
36075
|
-
// src/scripts/_lib/runtime_journal.ts
|
|
36727
|
+
import * as fs98 from "node:fs";
|
|
36728
|
+
import * as path100 from "node:path";
|
|
36076
36729
|
var JOURNAL_SCHEMA_VERSION = 3;
|
|
36077
36730
|
var BOUNDARY_RULE_VERSION = 1;
|
|
36078
36731
|
var RETENTION_TTL_DAYS = 30;
|
|
@@ -36163,7 +36816,7 @@ function requireId(name, id, optional) {
|
|
|
36163
36816
|
}
|
|
36164
36817
|
var JOURNAL_DIR_NAME = "agent-journal";
|
|
36165
36818
|
var JOURNAL_FILE_NAME = "journal.sqlite";
|
|
36166
|
-
var JOURNAL_FALLBACK_REL =
|
|
36819
|
+
var JOURNAL_FALLBACK_REL = path100.join("agents", "runtime", "state", JOURNAL_FILE_NAME);
|
|
36167
36820
|
function digest(domain, input) {
|
|
36168
36821
|
return crypto14.createHash("sha256").update(`${domain}\0${input}`).digest("hex").slice(0, 12);
|
|
36169
36822
|
}
|
|
@@ -36174,20 +36827,20 @@ function resolveJournal(root) {
|
|
|
36174
36827
|
if (common !== null) {
|
|
36175
36828
|
const own = git_dir(root) ?? common;
|
|
36176
36829
|
return {
|
|
36177
|
-
path:
|
|
36830
|
+
path: path100.join(common, JOURNAL_DIR_NAME, JOURNAL_FILE_NAME),
|
|
36178
36831
|
scope: "repo-shared",
|
|
36179
36832
|
reason: "common git dir resolved \u2014 every worktree of this repo writes one database",
|
|
36180
36833
|
repository_id: digest(REPO_DOMAIN, common),
|
|
36181
36834
|
worktree_id: digest(WORKTREE_DOMAIN, own)
|
|
36182
36835
|
};
|
|
36183
36836
|
}
|
|
36184
|
-
let real =
|
|
36837
|
+
let real = path100.resolve(root);
|
|
36185
36838
|
try {
|
|
36186
|
-
real =
|
|
36839
|
+
real = fs98.realpathSync(real);
|
|
36187
36840
|
} catch {
|
|
36188
36841
|
}
|
|
36189
36842
|
return {
|
|
36190
|
-
path:
|
|
36843
|
+
path: path100.join(real, JOURNAL_FALLBACK_REL),
|
|
36191
36844
|
scope: "worktree-local",
|
|
36192
36845
|
reason: "no common git dir \u2014 not inside a git repository; falling back to the tree-local path",
|
|
36193
36846
|
repository_id: digest(REPO_DOMAIN, real),
|
|
@@ -36273,7 +36926,7 @@ function ensureWal(db) {
|
|
|
36273
36926
|
function discard(dbPath) {
|
|
36274
36927
|
for (const p of [dbPath, `${dbPath}-wal`, `${dbPath}-shm`]) {
|
|
36275
36928
|
try {
|
|
36276
|
-
|
|
36929
|
+
fs98.rmSync(p, { force: true });
|
|
36277
36930
|
} catch {
|
|
36278
36931
|
}
|
|
36279
36932
|
}
|
|
@@ -36285,9 +36938,9 @@ function openJournal(root) {
|
|
|
36285
36938
|
);
|
|
36286
36939
|
}
|
|
36287
36940
|
const location = resolveJournal(root);
|
|
36288
|
-
|
|
36941
|
+
fs98.mkdirSync(path100.dirname(location.path), { recursive: true });
|
|
36289
36942
|
const { DatabaseSync } = loadSqliteSync("runtime_journal");
|
|
36290
|
-
if (
|
|
36943
|
+
if (fs98.existsSync(location.path)) {
|
|
36291
36944
|
let drift = false;
|
|
36292
36945
|
let probe = null;
|
|
36293
36946
|
try {
|
|
@@ -36369,7 +37022,7 @@ function recordEvent(h, input) {
|
|
|
36369
37022
|
const explicit = requireId("episode_id", input.episode_id, true);
|
|
36370
37023
|
if (input.terminal_state !== null && input.terminal_state !== void 0 && !TERMINAL_STATES.includes(input.terminal_state)) {
|
|
36371
37024
|
throw new JournalContractError(
|
|
36372
|
-
`terminal_state ${JSON.stringify(input.terminal_state)} is not
|
|
37025
|
+
`terminal_state ${JSON.stringify(input.terminal_state)} is not in the run vocabulary.`
|
|
36373
37026
|
);
|
|
36374
37027
|
}
|
|
36375
37028
|
if (input.consumption !== null && input.consumption !== void 0 && !CONSUMPTION_STATES.includes(input.consumption)) {
|
|
@@ -36530,10 +37183,10 @@ function _isCliEntry51() {
|
|
|
36530
37183
|
return false;
|
|
36531
37184
|
}
|
|
36532
37185
|
if (process.argv[1] === void 0) return false;
|
|
36533
|
-
const argvUrl = pathToFileURL58(
|
|
37186
|
+
const argvUrl = pathToFileURL58(path101.resolve(process.argv[1])).href;
|
|
36534
37187
|
if (import.meta.url === argvUrl) return true;
|
|
36535
37188
|
try {
|
|
36536
|
-
return
|
|
37189
|
+
return fs99.realpathSync(fileURLToPath65(import.meta.url)) === fs99.realpathSync(path101.resolve(process.argv[1]));
|
|
36537
37190
|
} catch {
|
|
36538
37191
|
return false;
|
|
36539
37192
|
}
|
|
@@ -36696,8 +37349,8 @@ function _py_json_dumps2(value, indent) {
|
|
|
36696
37349
|
|
|
36697
37350
|
// src/scripts/_lib/collector_denominator.ts
|
|
36698
37351
|
import crypto15 from "node:crypto";
|
|
36699
|
-
import
|
|
36700
|
-
import
|
|
37352
|
+
import fs101 from "node:fs";
|
|
37353
|
+
import path103 from "node:path";
|
|
36701
37354
|
|
|
36702
37355
|
// src/scripts/_lib/collector_record.ts
|
|
36703
37356
|
var COLLECTOR_EVENTS = [
|
|
@@ -36774,30 +37427,30 @@ var FIELD_PURPOSE = {
|
|
|
36774
37427
|
var ALLOWED_FIELDS = new Set(Object.keys(FIELD_PURPOSE));
|
|
36775
37428
|
|
|
36776
37429
|
// src/scripts/_lib/collector_store.ts
|
|
36777
|
-
import * as
|
|
37430
|
+
import * as fs100 from "node:fs";
|
|
36778
37431
|
import * as os12 from "node:os";
|
|
36779
|
-
import * as
|
|
37432
|
+
import * as path102 from "node:path";
|
|
36780
37433
|
var COLLECTOR_DIR_NAME = "agent-collector";
|
|
36781
37434
|
var COLLECTOR_FILE_NAME = "collector.sqlite";
|
|
36782
37435
|
var OPT_OUT_MARKER_NAME = "OPT-OUT";
|
|
36783
37436
|
var MIGRATION_MARKER_NAME = "MIGRATION-IN-FLIGHT";
|
|
36784
37437
|
var QUARANTINE_DIR_NAME = "quarantine";
|
|
36785
37438
|
function defaultUserRoot() {
|
|
36786
|
-
return
|
|
37439
|
+
return path102.join(os12.homedir(), ".event4u", "agent-config");
|
|
36787
37440
|
}
|
|
36788
37441
|
function resolveCollectorStore(userRoot = defaultUserRoot()) {
|
|
36789
|
-
const dir =
|
|
37442
|
+
const dir = path102.join(userRoot, COLLECTOR_DIR_NAME);
|
|
36790
37443
|
return {
|
|
36791
37444
|
userRoot,
|
|
36792
37445
|
root: dir,
|
|
36793
|
-
path:
|
|
36794
|
-
optOutMarker:
|
|
36795
|
-
migrationMarker:
|
|
36796
|
-
quarantineDir:
|
|
37446
|
+
path: path102.join(dir, COLLECTOR_FILE_NAME),
|
|
37447
|
+
optOutMarker: path102.join(dir, OPT_OUT_MARKER_NAME),
|
|
37448
|
+
migrationMarker: path102.join(dir, MIGRATION_MARKER_NAME),
|
|
37449
|
+
quarantineDir: path102.join(dir, QUARANTINE_DIR_NAME)
|
|
36797
37450
|
};
|
|
36798
37451
|
}
|
|
36799
37452
|
function isOptedOut(userRoot = defaultUserRoot()) {
|
|
36800
|
-
return
|
|
37453
|
+
return fs100.existsSync(resolveCollectorStore(userRoot).optOutMarker);
|
|
36801
37454
|
}
|
|
36802
37455
|
var MIGRATIONS = Object.freeze({
|
|
36803
37456
|
// 0 → 1. No DDL: `user_version` 0 is the default SQLite assigns, and a
|
|
@@ -36814,24 +37467,24 @@ var SPOOL_DIR_NAME = "spool";
|
|
|
36814
37467
|
var SPOOL_PENDING_NAME = "pending.jsonl";
|
|
36815
37468
|
var ENABLED_MARKER_NAME = "ENABLED";
|
|
36816
37469
|
function denominatorPath(userRoot) {
|
|
36817
|
-
return
|
|
37470
|
+
return path103.join(resolveCollectorStore(userRoot).root, DENOMINATOR_FILE_NAME);
|
|
36818
37471
|
}
|
|
36819
37472
|
function spoolDir(userRoot) {
|
|
36820
|
-
return
|
|
37473
|
+
return path103.join(resolveCollectorStore(userRoot).root, SPOOL_DIR_NAME);
|
|
36821
37474
|
}
|
|
36822
37475
|
function spoolPendingPath(userRoot) {
|
|
36823
|
-
return
|
|
37476
|
+
return path103.join(spoolDir(userRoot), SPOOL_PENDING_NAME);
|
|
36824
37477
|
}
|
|
36825
37478
|
function enabledMarkerPath(userRoot) {
|
|
36826
|
-
return
|
|
37479
|
+
return path103.join(resolveCollectorStore(userRoot).root, ENABLED_MARKER_NAME);
|
|
36827
37480
|
}
|
|
36828
37481
|
function isCollectorEnabled(userRoot) {
|
|
36829
37482
|
if (isOptedOut(userRoot)) return false;
|
|
36830
|
-
if (
|
|
36831
|
-
return
|
|
37483
|
+
if (fs101.existsSync(killSwitchPathLocal(userRoot))) return false;
|
|
37484
|
+
return fs101.existsSync(enabledMarkerPath(userRoot));
|
|
36832
37485
|
}
|
|
36833
37486
|
function killSwitchPathLocal(userRoot) {
|
|
36834
|
-
return
|
|
37487
|
+
return path103.join(resolveCollectorStore(userRoot).root, "STOP");
|
|
36835
37488
|
}
|
|
36836
37489
|
function utcDate(at = Date.now()) {
|
|
36837
37490
|
return new Date(at).toISOString().slice(0, 10);
|
|
@@ -36843,8 +37496,8 @@ function recordOpportunity(event, platform, userRoot, at = Date.now(), opts = {}
|
|
|
36843
37496
|
if (!COLLECTOR_EVENTS.includes(event)) return false;
|
|
36844
37497
|
if (!COLLECTOR_PLATFORMS.includes(platform)) return false;
|
|
36845
37498
|
const target = denominatorPath(userRoot);
|
|
36846
|
-
|
|
36847
|
-
|
|
37499
|
+
fs101.mkdirSync(path103.dirname(target), { recursive: true });
|
|
37500
|
+
fs101.appendFileSync(target, `${utcDate(at)} ${event} ${platform}
|
|
36848
37501
|
`);
|
|
36849
37502
|
return true;
|
|
36850
37503
|
} catch {
|
|
@@ -36858,19 +37511,19 @@ var MACHINE_ID_NAME = "machine-id";
|
|
|
36858
37511
|
var EPISODE_DIR_NAME = "episodes";
|
|
36859
37512
|
var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
36860
37513
|
function machineIdPath(userRoot) {
|
|
36861
|
-
return
|
|
37514
|
+
return path103.join(resolveCollectorStore(userRoot).root, MACHINE_ID_NAME);
|
|
36862
37515
|
}
|
|
36863
37516
|
function machineId(userRoot) {
|
|
36864
37517
|
const target = machineIdPath(userRoot);
|
|
36865
37518
|
try {
|
|
36866
|
-
const existing =
|
|
37519
|
+
const existing = fs101.readFileSync(target, "utf8").trim();
|
|
36867
37520
|
if (UUID_RE.test(existing)) return existing;
|
|
36868
37521
|
} catch {
|
|
36869
37522
|
}
|
|
36870
37523
|
try {
|
|
36871
37524
|
const minted = crypto15.randomUUID();
|
|
36872
|
-
|
|
36873
|
-
|
|
37525
|
+
fs101.mkdirSync(path103.dirname(target), { recursive: true });
|
|
37526
|
+
fs101.writeFileSync(target, `${minted}
|
|
36874
37527
|
`);
|
|
36875
37528
|
return minted;
|
|
36876
37529
|
} catch {
|
|
@@ -36894,17 +37547,17 @@ function episodeId(env = process.env) {
|
|
|
36894
37547
|
].join("-");
|
|
36895
37548
|
}
|
|
36896
37549
|
function nextSequence(episode, userRoot) {
|
|
36897
|
-
const dir =
|
|
36898
|
-
const target =
|
|
37550
|
+
const dir = path103.join(resolveCollectorStore(userRoot).root, EPISODE_DIR_NAME);
|
|
37551
|
+
const target = path103.join(dir, `${episode}.seq`);
|
|
36899
37552
|
try {
|
|
36900
|
-
|
|
37553
|
+
fs101.mkdirSync(dir, { recursive: true });
|
|
36901
37554
|
let current = 0;
|
|
36902
37555
|
try {
|
|
36903
|
-
const raw = Number.parseInt(
|
|
37556
|
+
const raw = Number.parseInt(fs101.readFileSync(target, "utf8").trim(), 10);
|
|
36904
37557
|
if (Number.isInteger(raw) && raw >= 0) current = raw + 1;
|
|
36905
37558
|
} catch {
|
|
36906
37559
|
}
|
|
36907
|
-
|
|
37560
|
+
fs101.writeFileSync(target, `${current}
|
|
36908
37561
|
`);
|
|
36909
37562
|
return current;
|
|
36910
37563
|
} catch {
|
|
@@ -36943,12 +37596,12 @@ function spoolRecord(record, userRoot) {
|
|
|
36943
37596
|
try {
|
|
36944
37597
|
if (!isCollectorEnabled(userRoot)) return false;
|
|
36945
37598
|
const target = spoolPendingPath(userRoot);
|
|
36946
|
-
|
|
37599
|
+
fs101.mkdirSync(path103.dirname(target), { recursive: true });
|
|
36947
37600
|
try {
|
|
36948
|
-
if (
|
|
37601
|
+
if (fs101.statSync(target).size >= SPOOL_MAX_BYTES) return false;
|
|
36949
37602
|
} catch {
|
|
36950
37603
|
}
|
|
36951
|
-
|
|
37604
|
+
fs101.appendFileSync(target, `${JSON.stringify(record)}
|
|
36952
37605
|
`);
|
|
36953
37606
|
return true;
|
|
36954
37607
|
} catch {
|
|
@@ -36958,11 +37611,11 @@ function spoolRecord(record, userRoot) {
|
|
|
36958
37611
|
|
|
36959
37612
|
// src/scripts/hooks/dispatch_hook.ts
|
|
36960
37613
|
var _IN_BUNDLE = true;
|
|
36961
|
-
var REPO_ROOT =
|
|
36962
|
-
|
|
37614
|
+
var REPO_ROOT = path104.resolve(
|
|
37615
|
+
path104.dirname(fileURLToPath66(import.meta.url)),
|
|
36963
37616
|
..._IN_BUNDLE ? ["..", ".."] : ["..", "..", ".."]
|
|
36964
37617
|
);
|
|
36965
|
-
var MANIFEST_PATH =
|
|
37618
|
+
var MANIFEST_PATH = path104.join(REPO_ROOT, "src", "scripts", "hook_manifest.yaml");
|
|
36966
37619
|
var EXIT_ALLOW35 = 0;
|
|
36967
37620
|
var EXIT_BLOCK6 = 1;
|
|
36968
37621
|
var EXIT_WARN18 = 2;
|
|
@@ -37024,11 +37677,11 @@ function _manifest_fingerprint(text) {
|
|
|
37024
37677
|
return `${h.toString(16)}:${String(text.length)}`;
|
|
37025
37678
|
}
|
|
37026
37679
|
function _load_yaml3(p) {
|
|
37027
|
-
const text =
|
|
37680
|
+
const text = fs102.readFileSync(p, "utf-8");
|
|
37028
37681
|
const compiled = p.replace(/\.ya?ml$/u, ".json");
|
|
37029
37682
|
if (compiled !== p) {
|
|
37030
37683
|
try {
|
|
37031
|
-
const raw = JSON.parse(
|
|
37684
|
+
const raw = JSON.parse(fs102.readFileSync(compiled, "utf-8"));
|
|
37032
37685
|
if (_isObject17(raw) && raw["fingerprint"] === _manifest_fingerprint(text) && _isObject17(raw["manifest"])) {
|
|
37033
37686
|
return raw["manifest"];
|
|
37034
37687
|
}
|
|
@@ -37134,7 +37787,7 @@ function _maybe_capture_payload(args, payload_text) {
|
|
|
37134
37787
|
}
|
|
37135
37788
|
try {
|
|
37136
37789
|
const target = _expanduser3(capture_dir);
|
|
37137
|
-
|
|
37790
|
+
fs102.mkdirSync(target, { recursive: true });
|
|
37138
37791
|
let payload;
|
|
37139
37792
|
try {
|
|
37140
37793
|
payload = payload_text.trim() ? JSON.parse(payload_text) : {};
|
|
@@ -37151,8 +37804,8 @@ function _maybe_capture_payload(args, payload_text) {
|
|
|
37151
37804
|
const ts = Date.now();
|
|
37152
37805
|
const native = (args.native_event || args.event).replace(/\//g, "_");
|
|
37153
37806
|
const fname = `${args.platform}__${native}__${ts}__${process.pid}.json`;
|
|
37154
|
-
|
|
37155
|
-
|
|
37807
|
+
fs102.writeFileSync(
|
|
37808
|
+
path104.join(target, fname),
|
|
37156
37809
|
_py_json_dumps2(record, 2) + "\n",
|
|
37157
37810
|
{ encoding: "utf-8" }
|
|
37158
37811
|
);
|
|
@@ -37163,7 +37816,7 @@ function _maybe_capture_payload(args, payload_text) {
|
|
|
37163
37816
|
function _expanduser3(p) {
|
|
37164
37817
|
if (p === "~" || p.startsWith("~/")) {
|
|
37165
37818
|
const home = process.env["HOME"] || process.env["USERPROFILE"] || "";
|
|
37166
|
-
return
|
|
37819
|
+
return path104.join(home, p.slice(1));
|
|
37167
37820
|
}
|
|
37168
37821
|
return p;
|
|
37169
37822
|
}
|
|
@@ -37195,25 +37848,25 @@ function _resolve_tsx_invocation2(scriptPath, scriptArgs) {
|
|
|
37195
37848
|
const walkUp = (start) => {
|
|
37196
37849
|
let dir = start;
|
|
37197
37850
|
for (; ; ) {
|
|
37198
|
-
const candidate =
|
|
37851
|
+
const candidate = path104.join(dir, "node_modules", ".bin", binName);
|
|
37199
37852
|
if (_isFile8(candidate)) {
|
|
37200
37853
|
return candidate;
|
|
37201
37854
|
}
|
|
37202
|
-
const parent =
|
|
37855
|
+
const parent = path104.dirname(dir);
|
|
37203
37856
|
if (parent === dir) {
|
|
37204
37857
|
return null;
|
|
37205
37858
|
}
|
|
37206
37859
|
dir = parent;
|
|
37207
37860
|
}
|
|
37208
37861
|
};
|
|
37209
|
-
const tsx = walkUp(
|
|
37862
|
+
const tsx = walkUp(path104.dirname(scriptPath)) ?? walkUp(path104.dirname(fileURLToPath66(import.meta.url)));
|
|
37210
37863
|
if (tsx !== null) {
|
|
37211
37864
|
return { command: tsx, args: [scriptPath, ...scriptArgs] };
|
|
37212
37865
|
}
|
|
37213
37866
|
return { command: "npx", args: ["tsx", scriptPath, ...scriptArgs] };
|
|
37214
37867
|
}
|
|
37215
37868
|
function _run_concern_inproc(main_fn, concern, envelope) {
|
|
37216
|
-
const scriptAbs =
|
|
37869
|
+
const scriptAbs = path104.join(REPO_ROOT, String(concern["script"]));
|
|
37217
37870
|
const argsList = Array.isArray(concern["args"]) ? concern["args"].map((a) => String(a)) : [];
|
|
37218
37871
|
argsList.push("--platform", String(envelope["platform"] || "generic"));
|
|
37219
37872
|
const workspace = String(envelope["workspace_root"] || process.cwd());
|
|
@@ -37290,7 +37943,7 @@ function _run_concern(concern, envelope) {
|
|
|
37290
37943
|
return _run_concern_inproc(inproc, concern, envelope);
|
|
37291
37944
|
}
|
|
37292
37945
|
}
|
|
37293
|
-
const script =
|
|
37946
|
+
const script = path104.join(REPO_ROOT, String(concern["script"]));
|
|
37294
37947
|
const argsList = Array.isArray(concern["args"]) ? concern["args"].map((a) => String(a)) : [];
|
|
37295
37948
|
const cmd = [script, ...argsList];
|
|
37296
37949
|
cmd.push("--platform", String(envelope["platform"] || "generic"));
|
|
@@ -37347,7 +38000,7 @@ function _run_concern(concern, envelope) {
|
|
|
37347
38000
|
}
|
|
37348
38001
|
function _isFile8(p) {
|
|
37349
38002
|
try {
|
|
37350
|
-
return
|
|
38003
|
+
return fs102.statSync(p).isFile();
|
|
37351
38004
|
} catch {
|
|
37352
38005
|
return false;
|
|
37353
38006
|
}
|
|
@@ -37369,10 +38022,10 @@ function _write_feedback(envelope, session_id, entries, final_rc, started_at) {
|
|
|
37369
38022
|
return;
|
|
37370
38023
|
}
|
|
37371
38024
|
const workspace = String(envelope["workspace_root"] || process.cwd());
|
|
37372
|
-
const state_root =
|
|
38025
|
+
const state_root = path104.join(workspace, "agents", "runtime", "state");
|
|
37373
38026
|
const fb_dir = feedback_dir(state_root, session_id);
|
|
37374
38027
|
try {
|
|
37375
|
-
|
|
38028
|
+
fs102.mkdirSync(fb_dir, { recursive: true });
|
|
37376
38029
|
} catch (exc) {
|
|
37377
38030
|
const msg = exc instanceof Error ? exc.message : String(exc);
|
|
37378
38031
|
process.stderr.write(`dispatch_hook: feedback dir unavailable: ${msg}
|
|
@@ -37380,7 +38033,7 @@ function _write_feedback(envelope, session_id, entries, final_rc, started_at) {
|
|
|
37380
38033
|
return;
|
|
37381
38034
|
}
|
|
37382
38035
|
for (const entry of entries) {
|
|
37383
|
-
const target =
|
|
38036
|
+
const target = path104.join(fb_dir, `${entry["concern"]}.json`);
|
|
37384
38037
|
try {
|
|
37385
38038
|
atomic_write_json(target, entry);
|
|
37386
38039
|
} catch (exc) {
|
|
@@ -37429,7 +38082,7 @@ function _write_feedback(envelope, session_id, entries, final_rc, started_at) {
|
|
|
37429
38082
|
};
|
|
37430
38083
|
try {
|
|
37431
38084
|
const invocation = `${String(process.pid)}-${process.hrtime.bigint().toString()}`;
|
|
37432
|
-
update_json_under_lock(
|
|
38085
|
+
update_json_under_lock(path104.join(fb_dir, "summary.json"), (loaded) => {
|
|
37433
38086
|
const priorRaw = loaded["invocations"];
|
|
37434
38087
|
const prior = Array.isArray(priorRaw) ? priorRaw : [];
|
|
37435
38088
|
const next = [...prior, { invocation, ...summary }];
|
|
@@ -37456,8 +38109,8 @@ function _record_rule_trips(envelope, entries) {
|
|
|
37456
38109
|
if (tripped.length === 0) return;
|
|
37457
38110
|
try {
|
|
37458
38111
|
const workspace = String(envelope["workspace_root"] || process.cwd());
|
|
37459
|
-
const state_dir =
|
|
37460
|
-
const target =
|
|
38112
|
+
const state_dir = path104.join(workspace, "agents", "runtime", "state");
|
|
38113
|
+
const target = path104.join(state_dir, "rule-trips.json");
|
|
37461
38114
|
const today = _now_iso3().slice(0, 10);
|
|
37462
38115
|
update_json_under_lock(target, (loaded) => {
|
|
37463
38116
|
const doc = { schema_version: 1, concerns: {}, ...loaded };
|
|
@@ -37599,7 +38252,7 @@ function main65(argv) {
|
|
|
37599
38252
|
recordOpportunity(args.event, args.platform);
|
|
37600
38253
|
recordCapture(args.event, args.platform);
|
|
37601
38254
|
const manifest_path = args.manifest;
|
|
37602
|
-
if (!
|
|
38255
|
+
if (!fs102.existsSync(manifest_path)) {
|
|
37603
38256
|
process.stderr.write(`dispatch_hook: manifest missing at ${manifest_path}
|
|
37604
38257
|
`);
|
|
37605
38258
|
return EXIT_ALLOW35;
|
|
@@ -37766,7 +38419,7 @@ function main65(argv) {
|
|
|
37766
38419
|
}
|
|
37767
38420
|
function _isDir4(p) {
|
|
37768
38421
|
try {
|
|
37769
|
-
return
|
|
38422
|
+
return fs102.statSync(p).isDirectory();
|
|
37770
38423
|
} catch {
|
|
37771
38424
|
return false;
|
|
37772
38425
|
}
|
|
@@ -37783,13 +38436,13 @@ function _isCliEntry52() {
|
|
|
37783
38436
|
if (process.argv[1] === void 0) {
|
|
37784
38437
|
return false;
|
|
37785
38438
|
}
|
|
37786
|
-
const argvUrl = pathToFileURL59(
|
|
38439
|
+
const argvUrl = pathToFileURL59(path104.resolve(process.argv[1])).href;
|
|
37787
38440
|
if (import.meta.url === argvUrl) {
|
|
37788
38441
|
return true;
|
|
37789
38442
|
}
|
|
37790
38443
|
try {
|
|
37791
|
-
const here =
|
|
37792
|
-
const argv =
|
|
38444
|
+
const here = fs102.realpathSync(fileURLToPath66(import.meta.url));
|
|
38445
|
+
const argv = fs102.realpathSync(path104.resolve(process.argv[1]));
|
|
37793
38446
|
return here === argv;
|
|
37794
38447
|
} catch {
|
|
37795
38448
|
return false;
|
|
@@ -37802,7 +38455,7 @@ if (isCliEntry14) {
|
|
|
37802
38455
|
|
|
37803
38456
|
// src/scripts/hooks/dispatch_entry.ts
|
|
37804
38457
|
var _selfPath = fileURLToPath67(import.meta.url);
|
|
37805
|
-
var _invokedDirectly2 = globalThis.__AC_HOOKS_BUNDLE_DIRECT === true || process.argv[1] !== void 0 &&
|
|
38458
|
+
var _invokedDirectly2 = globalThis.__AC_HOOKS_BUNDLE_DIRECT === true || process.argv[1] !== void 0 && path105.resolve(process.argv[1]) === path105.resolve(_selfPath);
|
|
37806
38459
|
if (_invokedDirectly2) {
|
|
37807
38460
|
process.exitCode = main65(process.argv.slice(2));
|
|
37808
38461
|
}
|