@event4u/agent-config 14.19.0 → 14.20.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 +108 -156
- package/dist/agent-src/commands/agent-handoff.md +42 -41
- package/dist/agent-src/contexts/execution/host-capability-manifest.md +7 -1
- package/dist/agent-src/rules/untrusted-input-defense.md +0 -2
- package/dist/agent-src/skills/evaluate-llm-feature/SKILL.md +1 -1
- package/dist/agent-src/skills/markitdown/SKILL.md +1 -1
- package/dist/agent-src/skills/skill-improvement-pipeline/SKILL.md +28 -6
- package/dist/agent-src/skills/test-driven-development/SKILL.md +1 -3
- package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
- package/dist/agent-src/templates/roadmaps.md +14 -1
- package/dist/agent-src/templates/scripts/telemetry/mcp_lite.ts +213 -0
- package/dist/agent-src/templates/scripts/telemetry/report_renderer.ts +16 -0
- package/dist/agent-src/templates/scripts/telemetry_report.ts +22 -2
- package/dist/cli/mcp/dispatch.js +10 -0
- package/dist/cli/mcp/stdio.js +33 -2
- package/dist/cli/mcp/telemetry.js +227 -0
- package/dist/cli-delegate/{chunk-GZTMRYCN.js → chunk-C6IPZRDA.js} +79 -12
- package/dist/cli-delegate/{chunk-CYH5SP6M.js → chunk-I6RHFQEG.js} +151 -16
- package/dist/cli-delegate/{chunk-IDHUQIXP.js → chunk-NUMQHLS5.js} +21 -4
- package/dist/cli-delegate/{chunk-PMEKGDED.js → chunk-PI2GU3DP.js} +163 -1
- package/dist/cli-delegate/{chunk-7PRE6ZV2.js → chunk-YS6XTLEK.js} +199 -4
- package/dist/cli-delegate/chunk-ZVBOHSVF.js +1109 -0
- package/dist/cli-delegate/cmd_conformance.js +73 -109
- package/dist/cli-delegate/cmd_doctor.js +2 -2
- package/dist/cli-delegate/cmd_export.js +2 -2
- package/dist/cli-delegate/cmd_handoff.js +41 -11
- package/dist/cli-delegate/cmd_memory_get.js +1 -1
- package/dist/cli-delegate/cmd_prune.js +2 -2
- package/dist/cli-delegate/cmd_route_audit.js +1 -1
- package/dist/cli-delegate/cmd_session_recycle.js +59 -902
- package/dist/cli-delegate/cmd_settings_migrate.js +2 -2
- package/dist/cli-delegate/cmd_sync.js +2 -2
- package/dist/cli-delegate/cmd_uninstall.js +2 -2
- package/dist/cli-delegate/cmd_validate.js +2 -2
- package/dist/discovery/deprecation-report.md +1 -1
- package/dist/discovery/discovery-manifest.json +9 -9
- 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 +7257 -6497
- package/dist/install/install.mjs +393 -168
- package/dist/mcp/registry-manifest.json +2 -2
- package/dist/mcp/server.json +2 -2
- package/dist/mcp/server.mjs +497 -118
- package/dist/scripts/mcp_server/telemetry.js +148 -0
- package/docs/guidelines/agent-infra/naming.md +1 -1
- package/docs/guidelines/agent-infra/security-lint-containment.md +46 -6
- package/docs/guidelines/agent-infra/self-improvement-pipeline.md +4 -4
- package/docs/guidelines/agent-infra/untrusted-input-spotlighting.md +1 -1
- package/docs/guidelines/redundancy-taxonomy.md +28 -0
- package/package.json +1 -1
- package/src/agent-src/templates/scripts/telemetry/mcp_lite.ts +213 -0
- package/src/agent-src/templates/scripts/telemetry/report_renderer.ts +16 -0
- package/src/agent-src/templates/scripts/telemetry_report.ts +22 -2
- package/src/config/assurance-capability-registry.json +9 -0
- package/src/config/gate-coverage.yml +55 -0
- package/src/config/gate-violation-baselines.json +15 -3
- package/src/scripts/_cli/cmd_session_recycle.ts +51 -3
- package/src/scripts/_lib/audit_field_provenance.ts +44 -3
- package/src/scripts/_lib/host_capability.ts +38 -0
- package/src/scripts/_lib/install_reach_checks.ts +33 -1
- package/src/scripts/_lib/mcp_bridge.ts +222 -10
- package/src/scripts/_lib/mcp_consent_residual.ts +173 -0
- package/src/scripts/_lib/orchestration_record.ts +23 -1
- package/src/scripts/_lib/recycle_envelope_paths.ts +190 -0
- package/src/scripts/_lib/release_position.ts +96 -0
- package/src/scripts/_lib/review_skipped_record.ts +17 -1
- package/src/scripts/_lib/security_lint.ts +179 -7
- package/src/scripts/_lib/self_repair.ts +141 -6
- package/src/scripts/_lib/self_repair_store.ts +273 -7
- package/src/scripts/_lib/subagent_capsule.ts +155 -3
- package/src/scripts/build_rule_trigger_matrix.ts +5 -0
- package/src/scripts/check_mcp_doc_drift.ts +217 -0
- package/src/scripts/check_pack_size.ts +321 -3
- package/src/scripts/handoff_context_hook.ts +54 -7
- package/src/scripts/hooks/session_eol_hook.ts +18 -7
- package/src/scripts/install.ts +4 -4
- package/src/scripts/lint_agent_security.ts +316 -25
- package/src/scripts/lint_confusables.ts +42 -6
- package/src/scripts/lint_handoffs.ts +0 -132
- package/src/scripts/lint_hidden_unicode.ts +49 -7
- package/src/scripts/lint_instruction_smuggling.ts +42 -6
- package/src/scripts/lint_mcp_config_security.ts +42 -6
- package/src/scripts/lint_roadmap_later_disposition.ts +217 -27
- package/src/scripts/lint_skill_frontmatter_safety.ts +43 -7
- package/src/scripts/mcp_server/resources.ts +41 -0
- package/src/scripts/mcp_server/telemetry.ts +19 -4
- package/src/scripts/orchestration_record.ts +12 -1
- package/src/scripts/release.ts +24 -24
- package/src/scripts/release_publication.ts +6 -2
- package/src/scripts/self_repair_cli.ts +31 -1
- package/src/scripts/skill_scout.ts +69 -0
- package/dist/cli-delegate/chunk-2GNWGMAL.js +0 -172
- package/dist/cli-delegate/chunk-LPPWO5CE.js +0 -161
|
@@ -731,8 +731,12 @@ export function guard_release_curation(version: string, prMerged = false): void
|
|
|
731
731
|
marked.join('\n')
|
|
732
732
|
: '') +
|
|
733
733
|
'\n Stopped BEFORE committing — no release commit, no branch on ' +
|
|
734
|
-
`${REMOTE}, no pull request, no tag.
|
|
735
|
-
|
|
734
|
+
`${REMOTE}, no pull request, no tag. HEAD is on the LOCAL ` +
|
|
735
|
+
`\`release/${version}\` branch and the generated section is in the working ` +
|
|
736
|
+
'tree: curate the `### Release highlights` head in `CHANGELOG.md` there, then ' +
|
|
737
|
+
're-run `task release`. That re-run works from this position — `preflightPosition` ' +
|
|
738
|
+
'accepts the release branch with the uncommitted step-2 output, which it did not ' +
|
|
739
|
+
'until 2026-09-07 (both spellings of the re-run were refused before step 1).',
|
|
736
740
|
);
|
|
737
741
|
}
|
|
738
742
|
|
|
@@ -48,6 +48,7 @@ import {
|
|
|
48
48
|
attachReleaseErrors,
|
|
49
49
|
listRecords,
|
|
50
50
|
markReleased,
|
|
51
|
+
writeTargetIndex,
|
|
51
52
|
openRecords,
|
|
52
53
|
readOverflow,
|
|
53
54
|
readRecord,
|
|
@@ -503,6 +504,30 @@ function releaseCmd(root: string, argv: string[]): number {
|
|
|
503
504
|
return EXIT_OK;
|
|
504
505
|
}
|
|
505
506
|
|
|
507
|
+
/**
|
|
508
|
+
* Rebuild the per-target occurrence index and print it.
|
|
509
|
+
*
|
|
510
|
+
* A DERIVED read: the record files are the source, the index is regenerable
|
|
511
|
+
* and gitignored with the rest of `agents/runtime/`. It exists because
|
|
512
|
+
* `occurrences` counts a fingerprint (class + normalised evidence shape), so a
|
|
513
|
+
* rule's weakness showing up in three different shapes was three records with
|
|
514
|
+
* one occurrence each — and the third-recurrence escalation had nothing that
|
|
515
|
+
* could ever establish its own precondition.
|
|
516
|
+
*/
|
|
517
|
+
function targetsCmd(root: string): number {
|
|
518
|
+
const counts = writeTargetIndex(root);
|
|
519
|
+
if (counts.length === 0) {
|
|
520
|
+
process.stdout.write('self-repair: no record carries a resolved target yet.\n');
|
|
521
|
+
return EXIT_OK;
|
|
522
|
+
}
|
|
523
|
+
for (const c of counts) {
|
|
524
|
+
process.stdout.write(
|
|
525
|
+
` ${c.target} ${c.occurrences} occurrence(s) across ${c.records.length} record(s)\n`,
|
|
526
|
+
);
|
|
527
|
+
}
|
|
528
|
+
return EXIT_OK;
|
|
529
|
+
}
|
|
530
|
+
|
|
506
531
|
export function main(argv: readonly string[]): number {
|
|
507
532
|
const root = process.cwd();
|
|
508
533
|
const sub = argv[0] ?? 'status';
|
|
@@ -512,7 +537,12 @@ export function main(argv: readonly string[]): number {
|
|
|
512
537
|
if (sub === 'release') {
|
|
513
538
|
return releaseCmd(root, [...argv.slice(1)]);
|
|
514
539
|
}
|
|
515
|
-
|
|
540
|
+
if (sub === 'targets') {
|
|
541
|
+
return targetsCmd(root);
|
|
542
|
+
}
|
|
543
|
+
process.stderr.write(
|
|
544
|
+
`self-repair: unknown subcommand '${sub}' (status | release | targets).\n`,
|
|
545
|
+
);
|
|
516
546
|
return EXIT_FAIL;
|
|
517
547
|
}
|
|
518
548
|
|
|
@@ -48,6 +48,12 @@ import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
|
48
48
|
|
|
49
49
|
import { collect, _keyword_vector, _cosine } from './audit_skill_overlap.js';
|
|
50
50
|
import { reportScanned, DeadScopeError } from './_lib/scan_scope.js';
|
|
51
|
+
import * as sl from './_lib/security_lint.js';
|
|
52
|
+
import { _scan as _scanHiddenUnicode } from './lint_hidden_unicode.js';
|
|
53
|
+
import { _scan as _scanConfusables } from './lint_confusables.js';
|
|
54
|
+
import { _scan as _scanInstructionSmuggling } from './lint_instruction_smuggling.js';
|
|
55
|
+
import { _scan as _scanMcpConfigSecurity } from './lint_mcp_config_security.js';
|
|
56
|
+
import { _scan as _scanFrontmatterSafety } from './lint_skill_frontmatter_safety.js';
|
|
51
57
|
|
|
52
58
|
const _HERE = fileURLToPath(import.meta.url);
|
|
53
59
|
const _DEFAULT_ROOT = path.resolve(path.dirname(_HERE), '..', '..');
|
|
@@ -262,6 +268,60 @@ export function resolveCandidateDir(
|
|
|
262
268
|
return { dir, refusal: null };
|
|
263
269
|
}
|
|
264
270
|
|
|
271
|
+
/**
|
|
272
|
+
* The five content linters, by the check id each one reports under.
|
|
273
|
+
*
|
|
274
|
+
* The SAME functions the `lint_agent_security` umbrella spawns as processes.
|
|
275
|
+
* Called in-process here rather than shelled out: five `tsx` cold starts per
|
|
276
|
+
* candidate is a cost with no benefit, and the thing that must be identical is
|
|
277
|
+
* the DETECTION, which is these functions.
|
|
278
|
+
*/
|
|
279
|
+
const CONTENT_LINTERS: ReadonlyArray<readonly [string, (sf: sl.ScannedFile) => sl.Finding[]]> = [
|
|
280
|
+
['hidden-unicode', _scanHiddenUnicode],
|
|
281
|
+
['mixed-script-confusable', _scanConfusables],
|
|
282
|
+
['instruction-smuggling', _scanInstructionSmuggling],
|
|
283
|
+
['mcp-config-security', _scanMcpConfigSecurity],
|
|
284
|
+
['dangerous-frontmatter', _scanFrontmatterSafety],
|
|
285
|
+
];
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* Read what a quarantined candidate SAYS, and refuse on a payload.
|
|
289
|
+
*
|
|
290
|
+
* `intake`'s other checks are properties of the file — symlink, extension, exec
|
|
291
|
+
* bit, size. Every one of them can be true of a file whose text tells an agent
|
|
292
|
+
* to hide its output from the user. "Inert" was a claim about the container that
|
|
293
|
+
* the gate read as a claim about the contents.
|
|
294
|
+
*
|
|
295
|
+
* TWO DELIBERATE DIFFERENCES FROM HOW THESE LINTERS RUN OVER THIS PACKAGE:
|
|
296
|
+
*
|
|
297
|
+
* 1. **Any HIGH refuses, whatever its weight.** The 0.25 confidence weighting is
|
|
298
|
+
* a false-positive containment device for THIS repository's own corpus, where
|
|
299
|
+
* a path containing `docs` or `examples` really is documentation somebody
|
|
300
|
+
* here wrote. A quarantined third-party candidate carries no such provenance,
|
|
301
|
+
* and a directory named `examples/` in it is an attacker's word for it. A
|
|
302
|
+
* refusal is also cheaper than a false pass in exactly this direction: the
|
|
303
|
+
* candidate is rejected and a human reads it.
|
|
304
|
+
* 2. **Every text extension is scanned, not just `.md`.** The candidate
|
|
305
|
+
* allow-list already bounds what may be present; a payload in the `.yml` a
|
|
306
|
+
* candidate ships is a payload.
|
|
307
|
+
*
|
|
308
|
+
* The refusal NAMES the linter, because "the content scan refused this" sends a
|
|
309
|
+
* reader to five detectors.
|
|
310
|
+
*/
|
|
311
|
+
export function scanCandidateContent(candidateDir: string): string[] {
|
|
312
|
+
const out: string[] = [];
|
|
313
|
+
for (const sf of sl.iter_corpus(['.'], [...ALLOWED_EXT], candidateDir)) {
|
|
314
|
+
for (const [check, scan] of CONTENT_LINTERS) {
|
|
315
|
+
for (const finding of scan(sf)) {
|
|
316
|
+
if (finding.severity !== 'HIGH') continue;
|
|
317
|
+
const loc = finding.line ? `${sf.rel}:${String(finding.line)}` : sf.rel;
|
|
318
|
+
out.push(`${loc}: flagged by ${check} — ${finding.message}`);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
return out;
|
|
323
|
+
}
|
|
324
|
+
|
|
265
325
|
/**
|
|
266
326
|
* Refuse a candidate that is not inert.
|
|
267
327
|
*
|
|
@@ -296,6 +356,15 @@ export function intake(candidateDir: string): IntakeResult {
|
|
|
296
356
|
if (files.length === 0) {
|
|
297
357
|
refusals.push('candidate directory is empty');
|
|
298
358
|
}
|
|
359
|
+
// Content, after the file properties. Ordering is not cosmetic: a candidate
|
|
360
|
+
// that fails an inertness check may not be safe to READ (a symlink out of
|
|
361
|
+
// quarantine is the case the read-time re-check exists for), so the bytes
|
|
362
|
+
// are only opened once the container has been judged.
|
|
363
|
+
if (refusals.length === 0) {
|
|
364
|
+
for (const flagged of scanCandidateContent(candidateDir)) {
|
|
365
|
+
refusals.push(flagged);
|
|
366
|
+
}
|
|
367
|
+
}
|
|
299
368
|
return { accepted: refusals.length === 0, refusals, files_seen: files.length };
|
|
300
369
|
}
|
|
301
370
|
|
|
@@ -1,172 +0,0 @@
|
|
|
1
|
-
import { createRequire as __acCreateRequire } from 'node:module'; const require = globalThis.require ?? __acCreateRequire(import.meta.url);
|
|
2
|
-
import {
|
|
3
|
-
read_lockfile
|
|
4
|
-
} from "./chunk-T7L2QK3K.js";
|
|
5
|
-
|
|
6
|
-
// src/scripts/_lib/turn_end_refusals.ts
|
|
7
|
-
import * as crypto from "node:crypto";
|
|
8
|
-
import * as fs from "node:fs";
|
|
9
|
-
import * as path from "node:path";
|
|
10
|
-
var DETECTOR_IDS = [
|
|
11
|
-
"promissory",
|
|
12
|
-
"language",
|
|
13
|
-
"verification",
|
|
14
|
-
"completion"
|
|
15
|
-
];
|
|
16
|
-
var REFUSAL_STATE_REL = path.join("agents", "runtime", "state", "turn-end-gate");
|
|
17
|
-
function refusalStateDir(workspaceRoot) {
|
|
18
|
-
return path.join(workspaceRoot, REFUSAL_STATE_REL);
|
|
19
|
-
}
|
|
20
|
-
function deriveSessionKey(sessionId) {
|
|
21
|
-
return crypto.createHash("sha256").update(sessionId).digest("hex").slice(0, 32);
|
|
22
|
-
}
|
|
23
|
-
function sessionRefusalFile(workspaceRoot, sessionKey) {
|
|
24
|
-
return path.join(refusalStateDir(workspaceRoot), `${sessionKey}.json`);
|
|
25
|
-
}
|
|
26
|
-
function readSessionCounts(workspaceRoot, sessionId) {
|
|
27
|
-
try {
|
|
28
|
-
const raw = fs.readFileSync(
|
|
29
|
-
sessionRefusalFile(workspaceRoot, deriveSessionKey(sessionId)),
|
|
30
|
-
"utf-8"
|
|
31
|
-
);
|
|
32
|
-
const rec = parseRecord(raw);
|
|
33
|
-
return rec === null ? null : countsOf(rec);
|
|
34
|
-
} catch {
|
|
35
|
-
return null;
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
function emptyCounts() {
|
|
39
|
-
return { promissory: 0, language: 0, verification: 0, completion: 0 };
|
|
40
|
-
}
|
|
41
|
-
function isDetector(v) {
|
|
42
|
-
return typeof v === "string" && DETECTOR_IDS.includes(v);
|
|
43
|
-
}
|
|
44
|
-
function parseRecord(raw) {
|
|
45
|
-
let decoded;
|
|
46
|
-
try {
|
|
47
|
-
decoded = JSON.parse(raw);
|
|
48
|
-
} catch {
|
|
49
|
-
return null;
|
|
50
|
-
}
|
|
51
|
-
if (typeof decoded !== "object" || decoded === null || Array.isArray(decoded)) return null;
|
|
52
|
-
const o = decoded;
|
|
53
|
-
if (typeof o["refused_at"] !== "string") return null;
|
|
54
|
-
if (typeof o["refused_turn"] !== "number") return null;
|
|
55
|
-
if (!isDetector(o["detector"])) return null;
|
|
56
|
-
const rec = {
|
|
57
|
-
refused_at: o["refused_at"],
|
|
58
|
-
refused_turn: o["refused_turn"],
|
|
59
|
-
detector: o["detector"]
|
|
60
|
-
};
|
|
61
|
-
if (typeof o["first_refused_at"] === "string") rec.first_refused_at = o["first_refused_at"];
|
|
62
|
-
if (typeof o["agent_config_version"] === "string") {
|
|
63
|
-
rec.agent_config_version = o["agent_config_version"];
|
|
64
|
-
}
|
|
65
|
-
const counts = o["counts"];
|
|
66
|
-
if (typeof counts === "object" && counts !== null && !Array.isArray(counts)) {
|
|
67
|
-
const parsed = {};
|
|
68
|
-
for (const id of DETECTOR_IDS) {
|
|
69
|
-
const n = counts[id];
|
|
70
|
-
if (typeof n === "number" && Number.isFinite(n) && n >= 0) parsed[id] = n;
|
|
71
|
-
}
|
|
72
|
-
rec.counts = parsed;
|
|
73
|
-
}
|
|
74
|
-
return rec;
|
|
75
|
-
}
|
|
76
|
-
function countsOf(rec) {
|
|
77
|
-
const out = emptyCounts();
|
|
78
|
-
if (rec.counts === void 0) {
|
|
79
|
-
out[rec.detector] = 1;
|
|
80
|
-
return out;
|
|
81
|
-
}
|
|
82
|
-
let any = false;
|
|
83
|
-
for (const id of DETECTOR_IDS) {
|
|
84
|
-
const n = rec.counts[id];
|
|
85
|
-
if (typeof n === "number" && n > 0) {
|
|
86
|
-
out[id] = n;
|
|
87
|
-
any = true;
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
if (!any) out[rec.detector] = 1;
|
|
91
|
-
return out;
|
|
92
|
-
}
|
|
93
|
-
function foldRefusal(prev, input) {
|
|
94
|
-
const counts = prev === null ? emptyCounts() : countsOf(prev);
|
|
95
|
-
for (const d of input.detectors) counts[d] += 1;
|
|
96
|
-
const primary = input.detectors[0] ?? prev?.detector ?? "verification";
|
|
97
|
-
const rec = {
|
|
98
|
-
refused_at: input.at,
|
|
99
|
-
refused_turn: input.turnOrdinal,
|
|
100
|
-
detector: primary,
|
|
101
|
-
first_refused_at: prev?.first_refused_at ?? prev?.refused_at ?? input.at,
|
|
102
|
-
counts
|
|
103
|
-
};
|
|
104
|
-
if (input.version !== void 0) rec.agent_config_version = input.version;
|
|
105
|
-
else if (prev?.agent_config_version !== void 0) {
|
|
106
|
-
rec.agent_config_version = prev.agent_config_version;
|
|
107
|
-
}
|
|
108
|
-
return rec;
|
|
109
|
-
}
|
|
110
|
-
function readInstallBoundary() {
|
|
111
|
-
try {
|
|
112
|
-
const lock = read_lockfile();
|
|
113
|
-
if (lock === null) return { version: null, installed_at: null };
|
|
114
|
-
return {
|
|
115
|
-
version: lock.agent_config_version ?? null,
|
|
116
|
-
installed_at: lock.installed_at ?? null
|
|
117
|
-
};
|
|
118
|
-
} catch {
|
|
119
|
-
return { version: null, installed_at: null };
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
var REFUSAL_STATE_MAX_AGE_DAYS = 90;
|
|
123
|
-
function pruneAgedRefusalState(workspaceRoot, opts = {}) {
|
|
124
|
-
const maxAgeDays = opts.maxAgeDays ?? REFUSAL_STATE_MAX_AGE_DAYS;
|
|
125
|
-
const now = opts.now ?? /* @__PURE__ */ new Date();
|
|
126
|
-
const dir = refusalStateDir(workspaceRoot);
|
|
127
|
-
const result = { scanned: 0, pruned: 0, kept: 0 };
|
|
128
|
-
let entries;
|
|
129
|
-
try {
|
|
130
|
-
entries = fs.readdirSync(dir);
|
|
131
|
-
} catch {
|
|
132
|
-
return result;
|
|
133
|
-
}
|
|
134
|
-
const cutoffMs = now.getTime() - maxAgeDays * 24 * 60 * 60 * 1e3;
|
|
135
|
-
for (const name of entries) {
|
|
136
|
-
if (!name.endsWith(".json")) continue;
|
|
137
|
-
result.scanned += 1;
|
|
138
|
-
const file = path.join(dir, name);
|
|
139
|
-
let rec = null;
|
|
140
|
-
try {
|
|
141
|
-
rec = parseRecord(fs.readFileSync(file, "utf-8"));
|
|
142
|
-
} catch {
|
|
143
|
-
rec = null;
|
|
144
|
-
}
|
|
145
|
-
if (rec === null) {
|
|
146
|
-
result.kept += 1;
|
|
147
|
-
continue;
|
|
148
|
-
}
|
|
149
|
-
const at = Date.parse(rec.refused_at);
|
|
150
|
-
if (!Number.isFinite(at) || at >= cutoffMs) {
|
|
151
|
-
result.kept += 1;
|
|
152
|
-
continue;
|
|
153
|
-
}
|
|
154
|
-
try {
|
|
155
|
-
fs.unlinkSync(file);
|
|
156
|
-
result.pruned += 1;
|
|
157
|
-
} catch {
|
|
158
|
-
result.kept += 1;
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
return result;
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
export {
|
|
165
|
-
deriveSessionKey,
|
|
166
|
-
sessionRefusalFile,
|
|
167
|
-
readSessionCounts,
|
|
168
|
-
parseRecord,
|
|
169
|
-
foldRefusal,
|
|
170
|
-
readInstallBoundary,
|
|
171
|
-
pruneAgedRefusalState
|
|
172
|
-
};
|
|
@@ -1,161 +0,0 @@
|
|
|
1
|
-
import { createRequire as __acCreateRequire } from 'node:module'; const require = globalThis.require ?? __acCreateRequire(import.meta.url);
|
|
2
|
-
import {
|
|
3
|
-
statePathFor
|
|
4
|
-
} from "./chunk-7PRE6ZV2.js";
|
|
5
|
-
import {
|
|
6
|
-
git_common_dir
|
|
7
|
-
} from "./chunk-E4XIZDIB.js";
|
|
8
|
-
|
|
9
|
-
// src/scripts/_lib/envelope_grounding.ts
|
|
10
|
-
import { execFileSync } from "node:child_process";
|
|
11
|
-
import * as fs from "node:fs";
|
|
12
|
-
import * as path from "node:path";
|
|
13
|
-
|
|
14
|
-
// src/scripts/_lib/git_env.ts
|
|
15
|
-
var GIT_DISCOVERY_VARS = [
|
|
16
|
-
"GIT_DIR",
|
|
17
|
-
"GIT_WORK_TREE",
|
|
18
|
-
"GIT_INDEX_FILE",
|
|
19
|
-
"GIT_OBJECT_DIRECTORY",
|
|
20
|
-
"GIT_ALTERNATE_OBJECT_DIRECTORIES",
|
|
21
|
-
"GIT_COMMON_DIR",
|
|
22
|
-
"GIT_NAMESPACE",
|
|
23
|
-
"GIT_PREFIX"
|
|
24
|
-
];
|
|
25
|
-
function gitEnv(base = process.env) {
|
|
26
|
-
const env = { ...base };
|
|
27
|
-
for (const key of GIT_DISCOVERY_VARS) {
|
|
28
|
-
delete env[key];
|
|
29
|
-
}
|
|
30
|
-
return env;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
// src/scripts/_lib/envelope_grounding.ts
|
|
34
|
-
var MAX_FIELD_CHARS = 200;
|
|
35
|
-
var MAX_PATHS = 40;
|
|
36
|
-
function git(root, args) {
|
|
37
|
-
try {
|
|
38
|
-
return execFileSync("git", args, {
|
|
39
|
-
cwd: root,
|
|
40
|
-
env: gitEnv(),
|
|
41
|
-
encoding: "utf-8",
|
|
42
|
-
stdio: ["ignore", "pipe", "ignore"]
|
|
43
|
-
}).trim();
|
|
44
|
-
} catch {
|
|
45
|
-
return null;
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
function canonicalizeRepoIdentity(raw) {
|
|
49
|
-
let s = raw.trim();
|
|
50
|
-
s = s.replace(/^[a-z][a-z0-9+.-]*:\/\//i, "");
|
|
51
|
-
s = s.replace(/^[^/@]+@/, "");
|
|
52
|
-
s = s.replace(/^([^/:]+):(?!\/)/, "$1/");
|
|
53
|
-
s = s.replace(/\/+$/, "");
|
|
54
|
-
s = s.replace(/\.git$/i, "");
|
|
55
|
-
const slash = s.indexOf("/");
|
|
56
|
-
if (slash > 0) {
|
|
57
|
-
s = s.slice(0, slash).toLowerCase() + s.slice(slash);
|
|
58
|
-
} else {
|
|
59
|
-
s = s.toLowerCase();
|
|
60
|
-
}
|
|
61
|
-
return s;
|
|
62
|
-
}
|
|
63
|
-
function collectRepoAnchor(root) {
|
|
64
|
-
const remote = git(root, ["config", "--get", "remote.origin.url"]);
|
|
65
|
-
let identity = null;
|
|
66
|
-
if (remote) {
|
|
67
|
-
identity = canonicalizeRepoIdentity(remote);
|
|
68
|
-
} else {
|
|
69
|
-
const common = git_common_dir(root);
|
|
70
|
-
if (common !== null) {
|
|
71
|
-
try {
|
|
72
|
-
identity = fs.realpathSync(common);
|
|
73
|
-
} catch {
|
|
74
|
-
identity = common;
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
return {
|
|
79
|
-
repo_identity: identity ? identity.slice(0, MAX_FIELD_CHARS) : null,
|
|
80
|
-
branch: git(root, ["rev-parse", "--abbrev-ref", "HEAD"]),
|
|
81
|
-
head: git(root, ["rev-parse", "HEAD"])
|
|
82
|
-
};
|
|
83
|
-
}
|
|
84
|
-
function readLastVerify(root, session_id) {
|
|
85
|
-
if (typeof session_id !== "string" || session_id.trim() === "") return null;
|
|
86
|
-
try {
|
|
87
|
-
const raw = fs.readFileSync(path.join(root, statePathFor(session_id)), "utf-8");
|
|
88
|
-
const state = JSON.parse(raw);
|
|
89
|
-
const lv = state["last_verification"];
|
|
90
|
-
if (typeof lv !== "object" || lv === null || Array.isArray(lv)) return null;
|
|
91
|
-
const rec = lv;
|
|
92
|
-
const command = typeof rec["command"] === "string" ? rec["command"] : null;
|
|
93
|
-
if (!command) return null;
|
|
94
|
-
const at = typeof rec["at"] === "string" ? rec["at"] : "unknown time";
|
|
95
|
-
const flat = `${command} @ ${at} (no exit status is recorded anywhere)`.replace(/\s+/g, " ").trim();
|
|
96
|
-
return flat.slice(0, MAX_FIELD_CHARS);
|
|
97
|
-
} catch {
|
|
98
|
-
return null;
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
function collectGrounding(root, session_id) {
|
|
102
|
-
const anchor = collectRepoAnchor(root);
|
|
103
|
-
const porcelain = git(root, ["status", "--porcelain"]);
|
|
104
|
-
if (porcelain === null) {
|
|
105
|
-
return { ...anchor, uncommitted_paths: [], status_summary: null, last_verify: readLastVerify(root, session_id) };
|
|
106
|
-
}
|
|
107
|
-
const lines = porcelain.split("\n").filter((l) => l.trim().length > 0);
|
|
108
|
-
const paths = lines.map((l) => l.slice(3).trim()).filter((p) => p.length > 0 && p.length <= MAX_FIELD_CHARS).slice(0, MAX_PATHS);
|
|
109
|
-
return {
|
|
110
|
-
...anchor,
|
|
111
|
-
uncommitted_paths: paths,
|
|
112
|
-
status_summary: lines.length === 0 ? "clean working tree" : `${lines.length} uncommitted path(s)${lines.length > MAX_PATHS ? `, first ${MAX_PATHS} listed` : ""}`,
|
|
113
|
-
last_verify: readLastVerify(root, session_id)
|
|
114
|
-
};
|
|
115
|
-
}
|
|
116
|
-
function describeDrift(envelope, actual) {
|
|
117
|
-
if (typeof envelope !== "object" || envelope === null || Array.isArray(envelope)) return [];
|
|
118
|
-
const e = envelope;
|
|
119
|
-
const drift = [];
|
|
120
|
-
const recordedIdentity = typeof e["repo_identity"] === "string" ? e["repo_identity"] : null;
|
|
121
|
-
if (recordedIdentity && actual.repo_identity && recordedIdentity !== actual.repo_identity) {
|
|
122
|
-
drift.push(
|
|
123
|
-
`IDENTITY DRIFT: this envelope was written in "${recordedIdentity}", you are in "${actual.repo_identity}". Re-verify every path before acting \u2014 same branch name does not mean same working tree.`
|
|
124
|
-
);
|
|
125
|
-
}
|
|
126
|
-
const recordedBranch = typeof e["branch"] === "string" ? e["branch"] : null;
|
|
127
|
-
if (recordedBranch && actual.branch && recordedBranch !== actual.branch) {
|
|
128
|
-
drift.push(
|
|
129
|
-
`BRANCH DRIFT: envelope written on "${recordedBranch}", checkout is on "${actual.branch}".`
|
|
130
|
-
);
|
|
131
|
-
}
|
|
132
|
-
const recordedHead = typeof e["head"] === "string" ? e["head"] : null;
|
|
133
|
-
if (recordedHead && actual.head && recordedHead !== actual.head) {
|
|
134
|
-
drift.push(
|
|
135
|
-
`COMMIT DRIFT: envelope written at ${recordedHead.slice(0, 12)}, HEAD is now ${actual.head.slice(0, 12)} \u2014 re-read anything the envelope quotes.`
|
|
136
|
-
);
|
|
137
|
-
}
|
|
138
|
-
return drift;
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
// src/scripts/_lib/recycle_envelope_paths.ts
|
|
142
|
-
import * as path2 from "node:path";
|
|
143
|
-
var RECYCLE_ENVELOPE_REL = path2.join("agents", "runtime", "state", "recycle-envelope.json");
|
|
144
|
-
var RECYCLE_CONSUMED_REL = path2.join(
|
|
145
|
-
"agents",
|
|
146
|
-
"runtime",
|
|
147
|
-
"state",
|
|
148
|
-
"recycle-envelope.consumed.json"
|
|
149
|
-
);
|
|
150
|
-
var RECYCLE_MAX_AGE_HOURS = 48;
|
|
151
|
-
var RECYCLE_ENVELOPE_MAX_BYTES = 6144;
|
|
152
|
-
|
|
153
|
-
export {
|
|
154
|
-
collectRepoAnchor,
|
|
155
|
-
collectGrounding,
|
|
156
|
-
describeDrift,
|
|
157
|
-
RECYCLE_ENVELOPE_REL,
|
|
158
|
-
RECYCLE_CONSUMED_REL,
|
|
159
|
-
RECYCLE_MAX_AGE_HOURS,
|
|
160
|
-
RECYCLE_ENVELOPE_MAX_BYTES
|
|
161
|
-
};
|