@event4u/agent-config 15.0.0 → 16.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.augment-plugin/marketplace.json +3 -3
- package/.augment-plugin/plugin.json +1 -1
- package/.claude-plugin/marketplace.json +1 -1
- package/CHANGELOG.md +301 -347
- package/CONTRIBUTING.md +9 -0
- package/README.md +2 -2
- package/dist/agent-src/commands/analyze/inbox.md +26 -0
- package/dist/agent-src/commands/analyze/roadmap-repos.md +27 -0
- package/dist/agent-src/commands/challenge-me/closure.md +178 -0
- package/dist/agent-src/commands/challenge-me.md +9 -2
- package/dist/agent-src/commands/council/default.md +25 -5
- package/dist/agent-src/commands/feature/plan.md +28 -1
- package/dist/agent-src/commands/feature/roadmap.md +28 -1
- package/dist/agent-src/commands/implement-ticket.md +27 -0
- package/dist/agent-src/commands/jira-ticket.md +27 -0
- package/dist/agent-src/commands/pr/create.md +29 -0
- package/dist/agent-src/commands/pr/merge.md +60 -9
- package/dist/agent-src/commands/roadmap/ai-council.md +7 -1
- package/dist/agent-src/commands/roadmap/create.md +77 -29
- package/dist/agent-src/commands/roadmap/materialize.md +27 -0
- package/dist/agent-src/commands/roadmap/process-full.md +123 -18
- package/dist/agent-src/commands/team.md +22 -0
- package/dist/agent-src/contexts/authority/scope-growth-ownership.md +80 -0
- package/dist/agent-src/contexts/communication/rules-auto/user-interaction-mechanics.md +97 -0
- package/dist/agent-src/contexts/execution/auto-orchestration-activation.md +44 -3
- package/dist/agent-src/contexts/execution/autonomy-mechanics.md +15 -15
- package/dist/agent-src/contexts/execution/decision-closure-execution.md +93 -0
- package/dist/agent-src/contexts/execution/fix-loop-ladder.md +108 -0
- package/dist/agent-src/contexts/execution/plan-confidence-gate.md +4 -2
- package/dist/agent-src/contexts/execution/roadmap-process-loop.md +75 -6
- package/dist/agent-src/guidelines/agent-infra/active-remediation-mechanics.md +57 -0
- package/dist/agent-src/guidelines/agent-infra/evaluator-independence-mechanics.md +102 -0
- package/dist/agent-src/guidelines/design-fidelity-routing.md +29 -0
- package/dist/agent-src/rules/autonomous-execution.md +15 -8
- package/dist/agent-src/rules/delegation-policy.md +23 -45
- package/dist/agent-src/rules/design-fidelity.md +32 -37
- package/dist/agent-src/rules/evaluator-independence.md +43 -49
- package/dist/agent-src/rules/test-first.md +41 -0
- package/dist/agent-src/rules/user-interaction.md +31 -30
- package/dist/agent-src/skills/accessibility-auditor/data/manifest.json +3 -3
- package/dist/agent-src/skills/ai-council/SKILL.md +11 -3
- package/dist/agent-src/skills/api-design/data/manifest.json +3 -3
- package/dist/agent-src/skills/database/data/manifest.json +4 -4
- package/dist/agent-src/skills/database/data/query-tuning.csv +3 -3
- package/dist/agent-src/skills/design-review/SKILL.md +50 -0
- package/dist/agent-src/skills/error-handling-patterns/SKILL.md +9 -0
- package/dist/agent-src/skills/existing-ui-audit/SKILL.md +14 -4
- package/dist/agent-src/skills/experiment-loop/SKILL.md +31 -1
- package/dist/agent-src/skills/roadmap-writing/SKILL.md +1 -1
- package/dist/agent-src/skills/storybook-workshop/SKILL.md +42 -3
- package/dist/agent-src/skills/threat-modeling/SKILL.md +9 -4
- package/dist/agent-src/skills/threat-modeling/data/manifest.json +4 -4
- package/dist/agent-src/skills/verify-repair-loop/SKILL.md +37 -3
- package/dist/agent-src/templates/agent-settings.md +1 -1
- package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
- package/dist/agent-src/templates/roadmaps.md +188 -0
- package/dist/agent-src/templates/scripts/work_engine/directives/backend/_self_fix.ts +62 -2
- package/dist/agent-src/templates/scripts/work_engine/directives/backend/test.ts +1 -0
- package/dist/agent-src/templates/scripts/work_engine/directives/backend/verify.ts +1 -0
- package/dist/cli-delegate/check_update_banner.js +40 -2
- package/dist/cli-delegate/chunk-4E2W63DA.js +335 -0
- package/dist/cli-delegate/chunk-5R7HOLAF.js +99 -0
- package/dist/cli-delegate/{chunk-IVBPRCQO.js → chunk-6KFEC3G7.js} +1 -1
- package/dist/cli-delegate/{chunk-2TAQ2K4V.js → chunk-6KM6ORRY.js} +55 -386
- package/dist/cli-delegate/{chunk-2XY7ILBT.js → chunk-FC75PGJE.js} +42 -2
- package/dist/cli-delegate/{chunk-GYC3VRYN.js → chunk-FXYUYU4N.js} +57 -13
- package/dist/cli-delegate/{chunk-55ACLDUE.js → chunk-GJCBB2UG.js} +168 -10
- package/dist/cli-delegate/{chunk-AK6HODNQ.js → chunk-HDVVGPQW.js} +873 -539
- package/dist/cli-delegate/chunk-NUHLI2RX.js +80 -0
- package/dist/cli-delegate/{chunk-HZ52BRGG.js → chunk-P6ZHP5W2.js} +15 -90
- package/dist/cli-delegate/{chunk-TYSY33MD.js → chunk-QJWAUMJW.js} +12 -2
- package/dist/cli-delegate/{chunk-57PN4GYJ.js → chunk-RGNIWTEA.js} +1 -1
- package/dist/cli-delegate/chunk-ROYYTEZU.js +39 -0
- package/dist/cli-delegate/{chunk-2KKXJW25.js → chunk-S3VFXMTM.js} +1 -1
- package/dist/cli-delegate/{chunk-3FKR64R5.js → chunk-UNCRJBT3.js} +31 -7
- package/dist/cli-delegate/{chunk-2DK2VJWG.js → chunk-WGXTVKCQ.js} +20 -6
- package/dist/cli-delegate/chunk-YDPILCOL.js +152 -0
- package/dist/cli-delegate/cmd_analyze_session.js +1 -1
- package/dist/cli-delegate/cmd_brand_status.js +1 -1
- package/dist/cli-delegate/cmd_conformance.js +918 -325
- package/dist/cli-delegate/cmd_doctor.js +7 -5
- package/dist/cli-delegate/cmd_explain.js +5 -3
- package/dist/cli-delegate/cmd_export.js +9 -7
- package/dist/cli-delegate/cmd_fleet.js +4 -2
- package/dist/cli-delegate/cmd_handoff.js +6 -6
- package/dist/cli-delegate/cmd_mcp_available.js +1 -1
- package/dist/cli-delegate/cmd_migrate.js +2 -2
- package/dist/cli-delegate/cmd_packs_active.js +3 -2
- package/dist/cli-delegate/cmd_preflight.js +4 -2
- package/dist/cli-delegate/cmd_prune.js +10 -8
- package/dist/cli-delegate/cmd_route_audit.js +2 -2
- package/dist/cli-delegate/cmd_route_explain.js +1 -1
- package/dist/cli-delegate/cmd_session_recycle.js +4 -4
- package/dist/cli-delegate/cmd_settings_get.js +28 -2
- package/dist/cli-delegate/cmd_settings_migrate.js +9 -7
- package/dist/cli-delegate/cmd_settings_set.js +14 -1
- package/dist/cli-delegate/cmd_sync.js +10 -8
- package/dist/cli-delegate/cmd_uninstall.js +16 -13
- package/dist/cli-delegate/cmd_update.js +1 -1
- package/dist/cli-delegate/cmd_upgrade.js +1 -1
- package/dist/cli-delegate/cmd_validate.js +12 -10
- package/dist/cli-delegate/cmd_versions.js +1 -1
- package/dist/discovery/deprecation-report.md +1 -1
- package/dist/discovery/discovery-manifest.json +87 -40
- package/dist/discovery/discovery-manifest.json.sha256 +1 -1
- package/dist/discovery/discovery-manifest.summary.md +4 -4
- package/dist/discovery/dormancy-report.md +1 -1
- package/dist/discovery/orphan-report.md +1 -1
- package/dist/discovery/packs.json +10 -8
- package/dist/discovery/trust-report.md +3 -3
- package/dist/discovery/workspaces.json +8 -6
- package/dist/hooks/dispatch.js +2601 -1073
- package/dist/install/claudeRuleRewrite.js +14 -3
- package/dist/install/conflict.js +60 -10
- package/dist/install/conflictTracker.js +218 -0
- package/dist/install/fsPrimitives.js +54 -0
- package/dist/install/install.mjs +2008 -1481
- package/dist/install/manifestFiles.js +259 -0
- package/dist/install/preflight.js +14 -2
- package/dist/install/preserve.js +157 -0
- package/dist/install/recordedOwnership.js +132 -0
- package/dist/install/txlog.js +11 -2
- package/dist/mcp/registry-manifest.json +3 -3
- package/dist/mcp/server.json +2 -2
- package/dist/mcp/server.mjs +1612 -667
- package/dist/router.json +1 -1
- package/dist/scripts/_lib/agent_settings.js +3 -2
- package/dist/scripts/_lib/fs_atomic.js +167 -0
- package/dist/scripts/_lib/installed_lock.js +1 -1
- package/dist/scripts/_lib/installed_tools.js +460 -0
- package/dist/scripts/_lib/lean_projection_mode.js +3 -2
- package/dist/scripts/_lib/settings_renamed_keys.js +78 -0
- package/dist/server/io/yamlIO.js +50 -0
- package/dist/server/routes/install.js +8 -0
- package/dist/server/routes/wizard.js +9 -3
- package/dist/server/schemas/settings.js +17 -5
- package/dist/shared/missionExecution.js +97 -0
- package/dist/ui/assets/{index-D0jaCRPM.js → index-DH1xc62v.js} +17 -17
- package/dist/ui/index.html +1 -1
- package/docs/MIGRATION.md +103 -0
- package/docs/contracts/settings-classes.md +26 -7
- package/docs/guidelines/agent-infra/active-remediation-mechanics.md +57 -0
- package/docs/guidelines/agent-infra/evaluator-independence-mechanics.md +102 -0
- package/docs/guidelines/design-fidelity-routing.md +29 -0
- package/package.json +1 -1
- package/src/agent-src/templates/scripts/work_engine/directives/backend/_self_fix.ts +62 -2
- package/src/agent-src/templates/scripts/work_engine/directives/backend/test.ts +1 -0
- package/src/agent-src/templates/scripts/work_engine/directives/backend/verify.ts +1 -0
- package/src/config/agent-settings.template.yml +139 -27
- package/src/config/auto-rule-budget.json +16 -0
- package/src/config/ci-local-parity.yml +18 -5
- package/src/config/continuity-surface.json +28 -0
- package/src/config/gate-coverage.yml +146 -13
- package/src/config/gate-violation-baselines.json +6 -6
- package/src/config/hook-token-budget.json +2 -0
- package/src/config/host-injection-effect.json +1 -1
- package/src/config/loop-surfaces.yaml +215 -0
- package/src/config/platform-anchor.json +3 -2
- package/src/config/preamble-payload-budget.json +12 -7
- package/src/config/preamble-payload-exceptions.json +28 -0
- package/src/config/release-gate-locality.yml +11 -0
- package/src/config/routing-coverage-seed.json +18 -4
- package/src/config/rule-enforcement-baseline.json +0 -1
- package/src/install/claudeRuleRewrite.ts +16 -2
- package/src/install/conflict.ts +65 -9
- package/src/install/conflictTracker.ts +299 -0
- package/src/install/fsPrimitives.ts +54 -0
- package/src/install/manifestFiles.ts +312 -0
- package/src/install/preflight.ts +16 -2
- package/src/install/preserve.ts +205 -0
- package/src/install/recordedOwnership.ts +149 -0
- package/src/install/txlog.ts +11 -2
- package/src/install/types.ts +19 -4
- package/src/scripts/_cli/cmd_conformance.ts +88 -15
- package/src/scripts/_cli/cmd_doctor.ts +4 -3
- package/src/scripts/_cli/cmd_route_explain.ts +9 -2
- package/src/scripts/_cli/cmd_settings_get.ts +44 -0
- package/src/scripts/_cli/doctor_execution.ts +90 -0
- package/src/scripts/_dispatch.bash +3 -1
- package/src/scripts/_lib/activation_payload.ts +247 -0
- package/src/scripts/_lib/agent_settings.ts +4 -2
- package/src/scripts/_lib/authority_path.ts +102 -0
- package/src/scripts/_lib/base_ref_payload.ts +315 -0
- package/src/scripts/_lib/cascade_base.ts +94 -0
- package/src/scripts/_lib/changelog_eras.ts +7 -2
- package/src/scripts/_lib/continuation_ladder.ts +149 -2
- package/src/scripts/_lib/council_transport.ts +129 -0
- package/src/scripts/_lib/delivery_ready.ts +112 -0
- package/src/scripts/_lib/dropped_decision.ts +142 -0
- package/src/scripts/_lib/forge_protection.ts +267 -0
- package/src/scripts/_lib/hook_platform_keys.ts +27 -0
- package/src/scripts/_lib/installed_lock.ts +1 -1
- package/src/scripts/_lib/json_python_parity.ts +127 -0
- package/src/scripts/_lib/lean_projection_mode.ts +14 -3
- package/src/scripts/_lib/loop_surfaces.ts +382 -0
- package/src/scripts/_lib/measured_payload_ceiling.ts +424 -0
- package/src/scripts/_lib/mission_record.ts +190 -0
- package/src/scripts/_lib/obligation_frequency.ts +217 -0
- package/src/scripts/_lib/obligations.ts +402 -0
- package/src/scripts/_lib/orchestration_record.ts +11 -20
- package/src/scripts/_lib/payload_catalogue_completeness.ts +211 -0
- package/src/scripts/_lib/release_findings_ingest.ts +324 -0
- package/src/scripts/_lib/release_highlights.ts +199 -10
- package/src/scripts/_lib/release_holds.ts +493 -0
- package/src/scripts/_lib/release_migration_gate.ts +184 -0
- package/src/scripts/_lib/release_tag_dispatch.ts +63 -0
- package/src/scripts/_lib/review_baseline.ts +254 -0
- package/src/scripts/_lib/review_skipped_record.ts +61 -1
- package/src/scripts/_lib/rides_along.ts +102 -0
- package/src/scripts/_lib/settings_renamed_keys.ts +82 -0
- package/src/scripts/_lib/standing_bound_ratchet.ts +216 -103
- package/src/scripts/_lib/test_delta.ts +166 -0
- package/src/scripts/_lib/test_provenance.ts +171 -0
- package/src/scripts/_lib/turn_end_refusals.ts +51 -4
- package/src/scripts/_lib/typed_op_grant.ts +246 -0
- package/src/scripts/_lib/typed_op_watch.ts +185 -0
- package/src/scripts/ai_council/config.ts +8 -11
- package/src/scripts/ai_council/fallback_config.ts +5 -3
- package/src/scripts/ai_council/ownership_classes.ts +118 -0
- package/src/scripts/ask_block_census.ts +285 -15
- package/src/scripts/check_beta_review_markers.ts +35 -4
- package/src/scripts/check_enforcement_matrix.ts +624 -0
- package/src/scripts/check_finding_dispositions.ts +167 -16
- package/src/scripts/check_gate_reachability.ts +173 -10
- package/src/scripts/check_generator_sync.ts +954 -0
- package/src/scripts/check_held_object_arrivals.ts +381 -0
- package/src/scripts/check_preamble_payload_budget.ts +474 -124
- package/src/scripts/check_release_highlights.ts +33 -1
- package/src/scripts/check_release_holds.ts +567 -0
- package/src/scripts/check_release_published.ts +1 -1
- package/src/scripts/check_reply_consistency.ts +86 -17
- package/src/scripts/check_rule_projection_integrity.ts +22 -12
- package/src/scripts/check_test_delta.ts +294 -0
- package/src/scripts/check_test_weakening.ts +299 -0
- package/src/scripts/closure_scan.ts +333 -0
- package/src/scripts/compile_hook_manifest.ts +43 -3
- package/src/scripts/council_record_shape.ts +209 -0
- package/src/scripts/hook_manifest.json +1 -1
- package/src/scripts/hook_manifest.yaml +127 -12
- package/src/scripts/hooks/block_kernel_rule_writes.ts +12 -2
- package/src/scripts/hooks/concern_registry.ts +6 -0
- package/src/scripts/hooks/design_pass_hook.ts +128 -3
- package/src/scripts/hooks/end_review_nudge_hook.ts +101 -21
- package/src/scripts/hooks/evidence_independence.ts +96 -0
- package/src/scripts/hooks/memory_recall_hook.ts +540 -0
- package/src/scripts/hooks/obligation_settle_hook.ts +182 -0
- package/src/scripts/hooks/review_baseline_hook.ts +130 -0
- package/src/scripts/hooks/rule_inject_hook.ts +49 -1
- package/src/scripts/hooks/run_continuation_hook.ts +17 -20
- package/src/scripts/hooks/turn_end_gate_hook.ts +232 -14
- package/src/scripts/hooks_doctor.ts +89 -1
- package/src/scripts/hooks_status.ts +19 -0
- package/src/scripts/install.ts +107 -207
- package/src/scripts/interruption_report.ts +8 -2
- package/src/scripts/janitor.ts +15 -1
- package/src/scripts/lint_decision_classes.ts +464 -0
- package/src/scripts/lint_hook_manifest.ts +11 -0
- package/src/scripts/lint_major_migration_sections.ts +450 -0
- package/src/scripts/lint_plan_risk_register.ts +47 -3
- package/src/scripts/lint_roadmap_blockers.ts +61 -0
- package/src/scripts/lint_roadmap_producers.ts +202 -0
- package/src/scripts/measure_rule_budget.ts +101 -5
- package/src/scripts/measure_turn_end_gate.ts +302 -5
- package/src/scripts/new_roadmap.ts +37 -0
- package/src/scripts/orchestration_record.ts +0 -5
- package/src/scripts/release.ts +66 -162
- package/src/scripts/release_drill.ts +460 -15
- package/src/scripts/release_env.ts +1 -1
- package/src/scripts/release_publication.ts +52 -1
- package/src/scripts/report_enforcement_drift.ts +566 -0
- package/src/scripts/report_held_object_arrivals.ts +456 -0
- package/src/scripts/report_host_injection_effect.ts +3 -11
- package/src/scripts/report_standing_payload_by_host.ts +26 -152
- package/src/scripts/schemas/agent-settings.schema.json +23 -0
- package/src/scripts/schemas/command.schema.json +4 -0
- package/src/scripts/scope_growth.ts +219 -0
- package/src/scripts/sync_agent_settings.ts +140 -18
- package/src/scripts/trigger_eval_grandfather.json +0 -1
- package/src/scripts/ui_conformance_probe.ts +622 -0
- package/src/server/io/yamlIO.ts +48 -0
- package/src/server/schemas/settings.ts +31 -7
- package/src/shared/missionExecution.ts +126 -0
- package/dist/cli-delegate/chunk-523HCFYO.js +0 -90
|
@@ -10,11 +10,13 @@ import {
|
|
|
10
10
|
sessionRefusalFile,
|
|
11
11
|
statePathFor,
|
|
12
12
|
validateAssumption
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-QJWAUMJW.js";
|
|
14
14
|
import {
|
|
15
15
|
readHookStdin
|
|
16
16
|
} from "./chunk-F7DQWYR5.js";
|
|
17
17
|
import {
|
|
18
|
+
DeadScopeError,
|
|
19
|
+
assertScanned,
|
|
18
20
|
reportScanned
|
|
19
21
|
} from "./chunk-I3EIN2YG.js";
|
|
20
22
|
import {
|
|
@@ -34,14 +36,15 @@ import {
|
|
|
34
36
|
frontmatterPaths,
|
|
35
37
|
proseEqual,
|
|
36
38
|
splitFrontmatter
|
|
37
|
-
} from "./chunk-
|
|
39
|
+
} from "./chunk-GJCBB2UG.js";
|
|
38
40
|
import "./chunk-FTAISGDQ.js";
|
|
39
41
|
import "./chunk-M2DPGFZ4.js";
|
|
42
|
+
import "./chunk-ROYYTEZU.js";
|
|
40
43
|
import "./chunk-BTWUYDGN.js";
|
|
41
44
|
import {
|
|
42
45
|
projectStoreSlug,
|
|
43
46
|
resolveSessionRole
|
|
44
|
-
} from "./chunk-
|
|
47
|
+
} from "./chunk-FXYUYU4N.js";
|
|
45
48
|
import {
|
|
46
49
|
atomic_write_json,
|
|
47
50
|
atomic_write_text,
|
|
@@ -52,18 +55,26 @@ import {
|
|
|
52
55
|
prune_stale_session_states,
|
|
53
56
|
session_state_file
|
|
54
57
|
} from "./chunk-E4XIZDIB.js";
|
|
58
|
+
import {
|
|
59
|
+
artefact_roots
|
|
60
|
+
} from "./chunk-NUHLI2RX.js";
|
|
61
|
+
import {
|
|
62
|
+
readRecentEntries
|
|
63
|
+
} from "./chunk-5R7HOLAF.js";
|
|
55
64
|
import {
|
|
56
65
|
detectToolPresence
|
|
57
66
|
} from "./chunk-A4QJ6ENT.js";
|
|
58
67
|
import {
|
|
59
68
|
atomicAppendLine,
|
|
69
|
+
probeHostCapabilities
|
|
70
|
+
} from "./chunk-6KM6ORRY.js";
|
|
71
|
+
import "./chunk-T7L2QK3K.js";
|
|
72
|
+
import "./chunk-DMSZHXZS.js";
|
|
73
|
+
import {
|
|
60
74
|
manifest_path,
|
|
61
|
-
probeHostCapabilities,
|
|
62
75
|
read_manifest
|
|
63
|
-
} from "./chunk-
|
|
76
|
+
} from "./chunk-4E2W63DA.js";
|
|
64
77
|
import "./chunk-MWRD5YOH.js";
|
|
65
|
-
import "./chunk-T7L2QK3K.js";
|
|
66
|
-
import "./chunk-DMSZHXZS.js";
|
|
67
78
|
import {
|
|
68
79
|
require_dist
|
|
69
80
|
} from "./chunk-OY53J6II.js";
|
|
@@ -72,7 +83,7 @@ import {
|
|
|
72
83
|
} from "./chunk-MCJYCQPF.js";
|
|
73
84
|
import {
|
|
74
85
|
load_agent_settings
|
|
75
|
-
} from "./chunk-
|
|
86
|
+
} from "./chunk-FC75PGJE.js";
|
|
76
87
|
import "./chunk-NDJLNC6Q.js";
|
|
77
88
|
import {
|
|
78
89
|
__toESM
|
|
@@ -80,45 +91,12 @@ import {
|
|
|
80
91
|
|
|
81
92
|
// src/scripts/_cli/cmd_conformance.ts
|
|
82
93
|
var YAML = __toESM(require_dist(), 1);
|
|
83
|
-
import * as
|
|
94
|
+
import * as fs15 from "node:fs";
|
|
84
95
|
import * as os7 from "node:os";
|
|
85
|
-
import * as
|
|
96
|
+
import * as path15 from "node:path";
|
|
86
97
|
import process5 from "node:process";
|
|
87
|
-
import { spawnSync as
|
|
88
|
-
import { fileURLToPath as
|
|
89
|
-
|
|
90
|
-
// src/install/txlog.ts
|
|
91
|
-
import { createReadStream, createWriteStream, existsSync, readFileSync, renameSync, statSync, unlinkSync } from "node:fs";
|
|
92
|
-
var ROTATION_MAX_BYTES = 10 * 1024 * 1024;
|
|
93
|
-
var ROTATION_MAX_AGE_MS = 30 * 24 * 60 * 60 * 1e3;
|
|
94
|
-
var RECOVERY_DEPTH_CAP = 500;
|
|
95
|
-
function readRecentEntries(logPath) {
|
|
96
|
-
if (!existsSync(logPath)) {
|
|
97
|
-
return [];
|
|
98
|
-
}
|
|
99
|
-
const raw = readFileSync(logPath, "utf8");
|
|
100
|
-
const lines = raw.split("\n").filter((l) => l.length > 0);
|
|
101
|
-
const tail = lines.slice(-RECOVERY_DEPTH_CAP);
|
|
102
|
-
const out = [];
|
|
103
|
-
for (const line of tail) {
|
|
104
|
-
const parsed = tryParseEntry(line);
|
|
105
|
-
if (parsed !== null) {
|
|
106
|
-
out.push(parsed);
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
return out;
|
|
110
|
-
}
|
|
111
|
-
function tryParseEntry(line) {
|
|
112
|
-
try {
|
|
113
|
-
const obj = JSON.parse(line);
|
|
114
|
-
if (typeof obj.ts !== "string" || typeof obj.kind !== "string" || typeof obj.path !== "string") {
|
|
115
|
-
return null;
|
|
116
|
-
}
|
|
117
|
-
return obj;
|
|
118
|
-
} catch {
|
|
119
|
-
return null;
|
|
120
|
-
}
|
|
121
|
-
}
|
|
98
|
+
import { spawnSync as spawnSync4 } from "node:child_process";
|
|
99
|
+
import { fileURLToPath as fileURLToPath14, pathToFileURL as pathToFileURL14 } from "node:url";
|
|
122
100
|
|
|
123
101
|
// src/scripts/router_target_paths.mjs
|
|
124
102
|
var ROUTE_TARGET_TEMPLATES = Object.freeze({
|
|
@@ -131,10 +109,10 @@ var ROUTE_TARGET_TEMPLATES = Object.freeze({
|
|
|
131
109
|
])
|
|
132
110
|
});
|
|
133
111
|
function parseRouteTarget(target) {
|
|
134
|
-
const
|
|
135
|
-
if (
|
|
136
|
-
const kind = target.slice(0,
|
|
137
|
-
const id = target.slice(
|
|
112
|
+
const sep2 = target.indexOf(":");
|
|
113
|
+
if (sep2 <= 0) return null;
|
|
114
|
+
const kind = target.slice(0, sep2);
|
|
115
|
+
const id = target.slice(sep2 + 1);
|
|
138
116
|
if (!id) return null;
|
|
139
117
|
if (!Object.prototype.hasOwnProperty.call(ROUTE_TARGET_TEMPLATES, kind)) return null;
|
|
140
118
|
return { kind, id };
|
|
@@ -146,18 +124,18 @@ function routeTargetPathsPosix(target) {
|
|
|
146
124
|
}
|
|
147
125
|
|
|
148
126
|
// src/scripts/report_conformance_funnel.ts
|
|
149
|
-
import * as
|
|
127
|
+
import * as fs14 from "node:fs";
|
|
150
128
|
import * as os6 from "node:os";
|
|
151
|
-
import * as
|
|
129
|
+
import * as path14 from "node:path";
|
|
152
130
|
import process4 from "node:process";
|
|
153
|
-
import { fileURLToPath as
|
|
131
|
+
import { fileURLToPath as fileURLToPath13, pathToFileURL as pathToFileURL13 } from "node:url";
|
|
154
132
|
|
|
155
133
|
// src/scripts/conformance_scan.ts
|
|
156
134
|
import { createHash as createHash3 } from "node:crypto";
|
|
157
|
-
import
|
|
135
|
+
import fs10 from "node:fs";
|
|
158
136
|
import os2 from "node:os";
|
|
159
|
-
import
|
|
160
|
-
import { fileURLToPath as
|
|
137
|
+
import path10 from "node:path";
|
|
138
|
+
import { fileURLToPath as fileURLToPath9, pathToFileURL as pathToFileURL9 } from "node:url";
|
|
161
139
|
|
|
162
140
|
// src/scripts/_lib/transcript_entry.ts
|
|
163
141
|
function _isObject(v) {
|
|
@@ -1940,17 +1918,464 @@ var COMMAND_OBJECTS = {
|
|
|
1940
1918
|
};
|
|
1941
1919
|
|
|
1942
1920
|
// src/scripts/hooks/turn_end_gate_hook.ts
|
|
1943
|
-
import * as
|
|
1944
|
-
import * as
|
|
1945
|
-
import { fileURLToPath as
|
|
1921
|
+
import * as fs7 from "node:fs";
|
|
1922
|
+
import * as path7 from "node:path";
|
|
1923
|
+
import { fileURLToPath as fileURLToPath6, pathToFileURL as pathToFileURL6 } from "node:url";
|
|
1946
1924
|
|
|
1947
|
-
// src/scripts/
|
|
1948
|
-
import { spawnSync } from "node:child_process";
|
|
1949
|
-
import * as crypto from "node:crypto";
|
|
1925
|
+
// src/scripts/check_reply_consistency.ts
|
|
1950
1926
|
import * as fs3 from "node:fs";
|
|
1951
|
-
import * as os from "node:os";
|
|
1952
1927
|
import * as path3 from "node:path";
|
|
1953
1928
|
import { fileURLToPath as fileURLToPath3, pathToFileURL as pathToFileURL3 } from "node:url";
|
|
1929
|
+
var _HERE = fileURLToPath3(import.meta.url);
|
|
1930
|
+
var ROOT = path3.resolve(path3.dirname(_HERE), "..", "..");
|
|
1931
|
+
var QUIET = process.argv.slice(2).includes("--quiet");
|
|
1932
|
+
var OPTION_LINE_RE = /^\s*>?\s*(\d+)\.\s+\S/;
|
|
1933
|
+
var REC_LINE_RE = /(?:Recommendation|Empfehlung)\s*:\s*(\d+)\b/i;
|
|
1934
|
+
var TAG_RE = /\((?:recommended|rec|empfohlen)\)/i;
|
|
1935
|
+
var CODESPAN_RE = /`[^`\n]*`/g;
|
|
1936
|
+
var HEADING_RE = /^#{1,6}\s/;
|
|
1937
|
+
var FENCE_RE = /^\s*(```|~~~)/;
|
|
1938
|
+
var REC_ADJACENCY_WINDOW = 2;
|
|
1939
|
+
function _strip_codespans(line) {
|
|
1940
|
+
return line.replace(CODESPAN_RE, "``");
|
|
1941
|
+
}
|
|
1942
|
+
function splitAndMask(text) {
|
|
1943
|
+
return mask_fences(_splitlines(text));
|
|
1944
|
+
}
|
|
1945
|
+
function _splitlines(text) {
|
|
1946
|
+
if (text === "") return [];
|
|
1947
|
+
const parts = text.split(/\r\n|\r|\n/);
|
|
1948
|
+
if (parts.length > 0 && parts[parts.length - 1] === "") {
|
|
1949
|
+
parts.pop();
|
|
1950
|
+
}
|
|
1951
|
+
return parts;
|
|
1952
|
+
}
|
|
1953
|
+
function mask_fences(lines) {
|
|
1954
|
+
const out = [];
|
|
1955
|
+
let fence = null;
|
|
1956
|
+
for (const raw of lines) {
|
|
1957
|
+
const m = FENCE_RE.exec(raw);
|
|
1958
|
+
if (m) {
|
|
1959
|
+
const marker = m[1];
|
|
1960
|
+
if (fence === null) {
|
|
1961
|
+
fence = marker;
|
|
1962
|
+
} else if (fence === marker) {
|
|
1963
|
+
fence = null;
|
|
1964
|
+
}
|
|
1965
|
+
out.push("");
|
|
1966
|
+
continue;
|
|
1967
|
+
}
|
|
1968
|
+
out.push(fence === null ? raw : "");
|
|
1969
|
+
}
|
|
1970
|
+
return out;
|
|
1971
|
+
}
|
|
1972
|
+
function find_option_blocks(text) {
|
|
1973
|
+
const lines = mask_fences(_splitlines(text));
|
|
1974
|
+
const blocks = [];
|
|
1975
|
+
let current = null;
|
|
1976
|
+
for (let idx = 0; idx < lines.length; idx++) {
|
|
1977
|
+
const m = OPTION_LINE_RE.exec(lines[idx]);
|
|
1978
|
+
if (m) {
|
|
1979
|
+
const num = parseInt(m[1], 10);
|
|
1980
|
+
if (current === null) {
|
|
1981
|
+
current = { startLine: idx + 1, endLine: idx + 1, numbers: [num] };
|
|
1982
|
+
} else {
|
|
1983
|
+
current.endLine = idx + 1;
|
|
1984
|
+
current.numbers.push(num);
|
|
1985
|
+
}
|
|
1986
|
+
} else {
|
|
1987
|
+
if (current !== null && current.numbers.length >= 2) {
|
|
1988
|
+
blocks.push(current);
|
|
1989
|
+
}
|
|
1990
|
+
current = null;
|
|
1991
|
+
}
|
|
1992
|
+
}
|
|
1993
|
+
if (current !== null && current.numbers.length >= 2) {
|
|
1994
|
+
blocks.push(current);
|
|
1995
|
+
}
|
|
1996
|
+
return blocks;
|
|
1997
|
+
}
|
|
1998
|
+
function recommendationsUnder(text, block, maskedLines) {
|
|
1999
|
+
const lines = maskedLines ?? mask_fences(_splitlines(text));
|
|
2000
|
+
const recs = [];
|
|
2001
|
+
let inspected = 0;
|
|
2002
|
+
for (let idx = block.endLine; idx < lines.length && inspected < REC_ADJACENCY_WINDOW; idx++) {
|
|
2003
|
+
const line = lines[idx];
|
|
2004
|
+
if (line.trim() === "") {
|
|
2005
|
+
continue;
|
|
2006
|
+
}
|
|
2007
|
+
if (HEADING_RE.test(line) || OPTION_LINE_RE.test(line)) {
|
|
2008
|
+
break;
|
|
2009
|
+
}
|
|
2010
|
+
inspected += 1;
|
|
2011
|
+
const m = REC_LINE_RE.exec(line);
|
|
2012
|
+
if (m) {
|
|
2013
|
+
recs.push({ line: idx + 1, num: parseInt(m[1], 10) });
|
|
2014
|
+
}
|
|
2015
|
+
}
|
|
2016
|
+
return recs;
|
|
2017
|
+
}
|
|
2018
|
+
function check_reply(text) {
|
|
2019
|
+
const rawLines = _splitlines(text);
|
|
2020
|
+
const lines = mask_fences(rawLines);
|
|
2021
|
+
const findings = [];
|
|
2022
|
+
for (let idx = 0; idx < lines.length; idx++) {
|
|
2023
|
+
const stripped = _strip_codespans(lines[idx]);
|
|
2024
|
+
if (OPTION_LINE_RE.test(stripped) && TAG_RE.test(stripped)) {
|
|
2025
|
+
findings.push({
|
|
2026
|
+
line: idx + 1,
|
|
2027
|
+
message: `inline tag on numbered option \u2014 ${rawLines[idx].trim()}`
|
|
2028
|
+
});
|
|
2029
|
+
}
|
|
2030
|
+
}
|
|
2031
|
+
const blocks = find_option_blocks(text);
|
|
2032
|
+
for (const block of blocks) {
|
|
2033
|
+
const recs = recommendationsUnder(text, block);
|
|
2034
|
+
if (recs.length === 0) {
|
|
2035
|
+
findings.push({
|
|
2036
|
+
line: block.startLine,
|
|
2037
|
+
message: "numbered options block without a Recommendation:/Empfehlung: line directly under it"
|
|
2038
|
+
});
|
|
2039
|
+
continue;
|
|
2040
|
+
}
|
|
2041
|
+
if (recs.length > 1) {
|
|
2042
|
+
findings.push({
|
|
2043
|
+
line: recs[1].line,
|
|
2044
|
+
message: `multiple recommendation lines under one options block: [${recs.map((r) => r.num).join(", ")}]`
|
|
2045
|
+
});
|
|
2046
|
+
continue;
|
|
2047
|
+
}
|
|
2048
|
+
const rec = recs[0];
|
|
2049
|
+
if (!block.numbers.includes(rec.num)) {
|
|
2050
|
+
findings.push({
|
|
2051
|
+
line: rec.line,
|
|
2052
|
+
message: `recommendation ${String(rec.num)} not present in the options block above it (options: [${block.numbers.join(", ")}])`
|
|
2053
|
+
});
|
|
2054
|
+
}
|
|
2055
|
+
}
|
|
2056
|
+
findings.sort((a, b) => a.line - b.line);
|
|
2057
|
+
return findings;
|
|
2058
|
+
}
|
|
2059
|
+
function _isDir(p) {
|
|
2060
|
+
try {
|
|
2061
|
+
return fs3.statSync(p).isDirectory();
|
|
2062
|
+
} catch {
|
|
2063
|
+
return false;
|
|
2064
|
+
}
|
|
2065
|
+
}
|
|
2066
|
+
function _rglobMdSorted(dir) {
|
|
2067
|
+
const out = [];
|
|
2068
|
+
const walk = (current) => {
|
|
2069
|
+
let entries;
|
|
2070
|
+
try {
|
|
2071
|
+
entries = fs3.readdirSync(current, { withFileTypes: true });
|
|
2072
|
+
} catch {
|
|
2073
|
+
return;
|
|
2074
|
+
}
|
|
2075
|
+
for (const ent of entries) {
|
|
2076
|
+
const full = path3.join(current, ent.name);
|
|
2077
|
+
if (ent.isDirectory() || ent.isSymbolicLink() && _isDir(full)) {
|
|
2078
|
+
walk(full);
|
|
2079
|
+
} else if (ent.name.endsWith(".md")) {
|
|
2080
|
+
out.push(full);
|
|
2081
|
+
}
|
|
2082
|
+
}
|
|
2083
|
+
};
|
|
2084
|
+
walk(dir);
|
|
2085
|
+
out.sort();
|
|
2086
|
+
return out;
|
|
2087
|
+
}
|
|
2088
|
+
function _relToPosixOrAbs(child, root) {
|
|
2089
|
+
const rel = path3.relative(root, child);
|
|
2090
|
+
if (rel === "" || rel.startsWith("..") || path3.isAbsolute(rel)) {
|
|
2091
|
+
return child.split(path3.sep).join("/");
|
|
2092
|
+
}
|
|
2093
|
+
return rel.split(path3.sep).join("/");
|
|
2094
|
+
}
|
|
2095
|
+
function cmd_scan_dir(root) {
|
|
2096
|
+
let roots;
|
|
2097
|
+
if (!_isDir(root)) {
|
|
2098
|
+
const legacy = path3.join(ROOT, ".agent-src.uncondensed");
|
|
2099
|
+
if (path3.resolve(root) === path3.resolve(legacy)) {
|
|
2100
|
+
roots = artefact_roots();
|
|
2101
|
+
if (roots.length === 0) {
|
|
2102
|
+
process.stderr.write("error: no artefact roots found (legacy or packages/*)\n");
|
|
2103
|
+
return 1;
|
|
2104
|
+
}
|
|
2105
|
+
} else {
|
|
2106
|
+
process.stderr.write(`error: not a directory: ${root}
|
|
2107
|
+
`);
|
|
2108
|
+
return 1;
|
|
2109
|
+
}
|
|
2110
|
+
} else {
|
|
2111
|
+
roots = [root];
|
|
2112
|
+
}
|
|
2113
|
+
const violations = [];
|
|
2114
|
+
let scanned = 0;
|
|
2115
|
+
for (const r of roots) {
|
|
2116
|
+
for (const md of _rglobMdSorted(r)) {
|
|
2117
|
+
scanned += 1;
|
|
2118
|
+
const text = fs3.readFileSync(md, "utf-8");
|
|
2119
|
+
const lines = _splitlines(text);
|
|
2120
|
+
for (let idx = 0; idx < lines.length; idx++) {
|
|
2121
|
+
const raw = lines[idx];
|
|
2122
|
+
const stripped = _strip_codespans(raw);
|
|
2123
|
+
if (OPTION_LINE_RE.test(stripped) && TAG_RE.test(stripped)) {
|
|
2124
|
+
violations.push([md, idx + 1, raw.trim()]);
|
|
2125
|
+
}
|
|
2126
|
+
}
|
|
2127
|
+
}
|
|
2128
|
+
}
|
|
2129
|
+
try {
|
|
2130
|
+
assertScanned({
|
|
2131
|
+
gate: "check_reply_consistency",
|
|
2132
|
+
scanned,
|
|
2133
|
+
units: "markdown file(s)",
|
|
2134
|
+
roots: roots.map((r) => _relToPosixOrAbs(r, ROOT))
|
|
2135
|
+
});
|
|
2136
|
+
} catch (exc) {
|
|
2137
|
+
if (exc instanceof DeadScopeError) {
|
|
2138
|
+
process.stderr.write(`\u274C ${exc.message}
|
|
2139
|
+
`);
|
|
2140
|
+
return 1;
|
|
2141
|
+
}
|
|
2142
|
+
throw exc;
|
|
2143
|
+
}
|
|
2144
|
+
if (violations.length > 0) {
|
|
2145
|
+
for (const [p, line, snippet] of violations) {
|
|
2146
|
+
process.stderr.write(` \u{1F534} ${p}:${String(line)} \u2014 inline-tag \u2014 ${snippet}
|
|
2147
|
+
`);
|
|
2148
|
+
}
|
|
2149
|
+
process.stderr.write(`
|
|
2150
|
+
\u274C ${String(violations.length)} legacy-pattern violation(s)
|
|
2151
|
+
`);
|
|
2152
|
+
return 2;
|
|
2153
|
+
}
|
|
2154
|
+
if (!QUIET) {
|
|
2155
|
+
const scanned2 = roots.map((r) => _relToPosixOrAbs(r, ROOT)).join(", ");
|
|
2156
|
+
process.stdout.write(`\u2705 No legacy (recommended) tags found under ${scanned2}
|
|
2157
|
+
`);
|
|
2158
|
+
}
|
|
2159
|
+
return 0;
|
|
2160
|
+
}
|
|
2161
|
+
var USAGE = "usage: check_reply_consistency [-h] (--stdin | --file FILE | --scan-dir SCAN_DIR)\n [-v] [--quiet]\n";
|
|
2162
|
+
function _usage_error(message) {
|
|
2163
|
+
process.stderr.write(USAGE);
|
|
2164
|
+
process.stderr.write(`check_reply_consistency: error: ${message}
|
|
2165
|
+
`);
|
|
2166
|
+
process.exit(1);
|
|
2167
|
+
}
|
|
2168
|
+
function _readStdin() {
|
|
2169
|
+
try {
|
|
2170
|
+
return fs3.readFileSync(0, "utf-8");
|
|
2171
|
+
} catch {
|
|
2172
|
+
return "";
|
|
2173
|
+
}
|
|
2174
|
+
}
|
|
2175
|
+
function parse_args(argv) {
|
|
2176
|
+
let stdin = false;
|
|
2177
|
+
let file = null;
|
|
2178
|
+
let scan_dir = null;
|
|
2179
|
+
let verbose = false;
|
|
2180
|
+
const groupSeen = [];
|
|
2181
|
+
const need = (i, name) => {
|
|
2182
|
+
const v = argv[i];
|
|
2183
|
+
if (v === void 0) {
|
|
2184
|
+
_usage_error(`argument ${name}: expected one argument`);
|
|
2185
|
+
}
|
|
2186
|
+
return v;
|
|
2187
|
+
};
|
|
2188
|
+
for (let i = 0; i < argv.length; i++) {
|
|
2189
|
+
const arg = argv[i];
|
|
2190
|
+
if (arg === "--stdin") {
|
|
2191
|
+
stdin = true;
|
|
2192
|
+
groupSeen.push("--stdin");
|
|
2193
|
+
} else if (arg === "--file") {
|
|
2194
|
+
file = need(++i, "--file");
|
|
2195
|
+
groupSeen.push("--file");
|
|
2196
|
+
} else if (arg.startsWith("--file=")) {
|
|
2197
|
+
file = arg.slice("--file=".length);
|
|
2198
|
+
groupSeen.push("--file");
|
|
2199
|
+
} else if (arg === "--scan-dir") {
|
|
2200
|
+
scan_dir = need(++i, "--scan-dir");
|
|
2201
|
+
groupSeen.push("--scan-dir");
|
|
2202
|
+
} else if (arg.startsWith("--scan-dir=")) {
|
|
2203
|
+
scan_dir = arg.slice("--scan-dir=".length);
|
|
2204
|
+
groupSeen.push("--scan-dir");
|
|
2205
|
+
} else if (arg === "-v" || arg === "--verbose") {
|
|
2206
|
+
verbose = true;
|
|
2207
|
+
} else if (arg === "--quiet") {
|
|
2208
|
+
} else if (arg === "-h" || arg === "--help") {
|
|
2209
|
+
process.stdout.write(USAGE);
|
|
2210
|
+
process.exit(0);
|
|
2211
|
+
} else {
|
|
2212
|
+
_usage_error(`unrecognized arguments: ${arg}`);
|
|
2213
|
+
}
|
|
2214
|
+
}
|
|
2215
|
+
if (groupSeen.length === 0) {
|
|
2216
|
+
_usage_error("one of the arguments --stdin --file --scan-dir is required");
|
|
2217
|
+
}
|
|
2218
|
+
if (groupSeen.length > 1) {
|
|
2219
|
+
_usage_error(`argument ${groupSeen[1]}: not allowed with argument ${groupSeen[0]}`);
|
|
2220
|
+
}
|
|
2221
|
+
return { stdin, file, scan_dir, verbose };
|
|
2222
|
+
}
|
|
2223
|
+
function main3(argv = process.argv.slice(2)) {
|
|
2224
|
+
const args = parse_args(argv);
|
|
2225
|
+
if (args.scan_dir !== null) {
|
|
2226
|
+
return cmd_scan_dir(args.scan_dir);
|
|
2227
|
+
}
|
|
2228
|
+
let text;
|
|
2229
|
+
try {
|
|
2230
|
+
text = args.stdin ? _readStdin() : fs3.readFileSync(args.file, "utf-8");
|
|
2231
|
+
} catch (e) {
|
|
2232
|
+
process.stderr.write(`error: ${String(e)}
|
|
2233
|
+
`);
|
|
2234
|
+
return 1;
|
|
2235
|
+
}
|
|
2236
|
+
const findings = check_reply(text);
|
|
2237
|
+
if (findings.length === 0) {
|
|
2238
|
+
if (args.verbose && !QUIET) {
|
|
2239
|
+
process.stdout.write("\u2705 reply consistent (every options block carries one adjacent recommendation)\n");
|
|
2240
|
+
}
|
|
2241
|
+
return 0;
|
|
2242
|
+
}
|
|
2243
|
+
for (const f of findings) {
|
|
2244
|
+
process.stderr.write(`\u274C line ${String(f.line)}: ${f.message}
|
|
2245
|
+
`);
|
|
2246
|
+
}
|
|
2247
|
+
return 2;
|
|
2248
|
+
}
|
|
2249
|
+
function _isCliEntry3() {
|
|
2250
|
+
if (true) {
|
|
2251
|
+
return false;
|
|
2252
|
+
}
|
|
2253
|
+
if (process.argv[1] === void 0) {
|
|
2254
|
+
return false;
|
|
2255
|
+
}
|
|
2256
|
+
const argvUrl = pathToFileURL3(path3.resolve(process.argv[1])).href;
|
|
2257
|
+
if (import.meta.url === argvUrl) {
|
|
2258
|
+
return true;
|
|
2259
|
+
}
|
|
2260
|
+
try {
|
|
2261
|
+
const here = fs3.realpathSync(fileURLToPath3(import.meta.url));
|
|
2262
|
+
const argv = fs3.realpathSync(path3.resolve(process.argv[1]));
|
|
2263
|
+
return here === argv;
|
|
2264
|
+
} catch {
|
|
2265
|
+
return false;
|
|
2266
|
+
}
|
|
2267
|
+
}
|
|
2268
|
+
var _IN_BUNDLE = true;
|
|
2269
|
+
if (!_IN_BUNDLE && (_isCliEntry3() || process.argv[1] === _HERE)) {
|
|
2270
|
+
process.exit(main3());
|
|
2271
|
+
}
|
|
2272
|
+
|
|
2273
|
+
// src/scripts/_lib/dropped_decision.ts
|
|
2274
|
+
function detectDroppedDecision(assistantTurnTexts, closingFromPayload = false) {
|
|
2275
|
+
if (assistantTurnTexts.length < 2) return null;
|
|
2276
|
+
const asksIn = (text) => {
|
|
2277
|
+
const blocks = find_option_blocks(text);
|
|
2278
|
+
if (blocks.length === 0) return blocks;
|
|
2279
|
+
const masked = splitAndMask(text);
|
|
2280
|
+
return blocks.filter((b) => recommendationsUnder(text, b, masked).length > 0);
|
|
2281
|
+
};
|
|
2282
|
+
const closing = assistantTurnTexts[assistantTurnTexts.length - 1];
|
|
2283
|
+
if (asksIn(closing).length > 0) return null;
|
|
2284
|
+
for (let i = assistantTurnTexts.length - 2; i >= 0; i -= 1) {
|
|
2285
|
+
const earlier = assistantTurnTexts[i];
|
|
2286
|
+
const blocks = asksIn(earlier);
|
|
2287
|
+
if (blocks.length === 0) continue;
|
|
2288
|
+
const block = blocks[blocks.length - 1];
|
|
2289
|
+
return {
|
|
2290
|
+
detector: "pending-decision",
|
|
2291
|
+
// The option NUMBERS and the line span, never the option text: the
|
|
2292
|
+
// evidence is quoted into a refusal that reaches the transcript, and
|
|
2293
|
+
// an options block can carry anything the reply carried.
|
|
2294
|
+
evidence: `options ${block.numbers.join("/")} at lines ${block.startLine}-${block.endLine} of an earlier reply this turn (closing reply read from ${closingFromPayload ? "the stop payload" : "the transcript"})`,
|
|
2295
|
+
reason: "an earlier reply in THIS turn put numbered options to the user and no user answer followed \u2014 this closing reply carries no options block, so the decision disappeared without being answered, cancelled or superseded. A hook nudge, a reviewer result or a task notification may ADD to a turn; it may not displace a question already asked (user-interaction Iron Law 3: a decision handed to the user outlives the turn). Re-present the block and its recommendation line at the end of this reply"
|
|
2296
|
+
};
|
|
2297
|
+
}
|
|
2298
|
+
return null;
|
|
2299
|
+
}
|
|
2300
|
+
|
|
2301
|
+
// src/scripts/hooks/end_review_nudge_hook.ts
|
|
2302
|
+
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
2303
|
+
import * as crypto from "node:crypto";
|
|
2304
|
+
import * as fs5 from "node:fs";
|
|
2305
|
+
import * as os from "node:os";
|
|
2306
|
+
import * as path5 from "node:path";
|
|
2307
|
+
import { fileURLToPath as fileURLToPath4, pathToFileURL as pathToFileURL4 } from "node:url";
|
|
2308
|
+
|
|
2309
|
+
// src/scripts/_lib/review_baseline.ts
|
|
2310
|
+
import { spawnSync } from "node:child_process";
|
|
2311
|
+
import * as fs4 from "node:fs";
|
|
2312
|
+
import * as path4 from "node:path";
|
|
2313
|
+
function currentHeadSha(cwd) {
|
|
2314
|
+
try {
|
|
2315
|
+
const r = spawnSync("git", ["rev-parse", "HEAD"], { cwd, encoding: "utf8" });
|
|
2316
|
+
if (r.status !== 0) return null;
|
|
2317
|
+
const out = (r.stdout ?? "").trim();
|
|
2318
|
+
return out === "" ? null : out;
|
|
2319
|
+
} catch {
|
|
2320
|
+
return null;
|
|
2321
|
+
}
|
|
2322
|
+
}
|
|
2323
|
+
var BASELINE_STATE_REL = path4.join("agents", "runtime", "state", "review-baseline");
|
|
2324
|
+
function baselineStateDir(workspaceRoot) {
|
|
2325
|
+
return path4.join(workspaceRoot, BASELINE_STATE_REL);
|
|
2326
|
+
}
|
|
2327
|
+
function baselineStateFile(workspaceRoot, sessionKey) {
|
|
2328
|
+
return path4.join(baselineStateDir(workspaceRoot), `${sessionKey}.json`);
|
|
2329
|
+
}
|
|
2330
|
+
function parseBaseline(raw) {
|
|
2331
|
+
let decoded;
|
|
2332
|
+
try {
|
|
2333
|
+
decoded = JSON.parse(raw);
|
|
2334
|
+
} catch {
|
|
2335
|
+
return null;
|
|
2336
|
+
}
|
|
2337
|
+
if (typeof decoded !== "object" || decoded === null || Array.isArray(decoded)) return null;
|
|
2338
|
+
const o = decoded;
|
|
2339
|
+
const lines = o["baseline_lines"];
|
|
2340
|
+
if (typeof lines !== "number" || !Number.isFinite(lines) || lines < 0) return null;
|
|
2341
|
+
const written = o["written_at"];
|
|
2342
|
+
if (typeof written !== "string") return null;
|
|
2343
|
+
const head = o["head_sha"];
|
|
2344
|
+
const measure = o["measure"];
|
|
2345
|
+
return {
|
|
2346
|
+
head_sha: typeof head === "string" && head !== "" ? head : null,
|
|
2347
|
+
baseline_lines: lines,
|
|
2348
|
+
...measure === "exact" || measure === "capped_approximation" ? { measure } : {},
|
|
2349
|
+
written_at: written
|
|
2350
|
+
};
|
|
2351
|
+
}
|
|
2352
|
+
function readBaseline(workspaceRoot, sessionKey) {
|
|
2353
|
+
const file = baselineStateFile(workspaceRoot, sessionKey);
|
|
2354
|
+
let raw;
|
|
2355
|
+
try {
|
|
2356
|
+
raw = fs4.readFileSync(file, "utf-8");
|
|
2357
|
+
} catch (exc) {
|
|
2358
|
+
const code = exc?.code;
|
|
2359
|
+
return code === "ENOENT" ? "absent" : "unreadable";
|
|
2360
|
+
}
|
|
2361
|
+
return parseBaseline(raw) ?? "unreadable";
|
|
2362
|
+
}
|
|
2363
|
+
function applyBaseline(measuredLines, baseline, headSha, measuredMeasure = "exact") {
|
|
2364
|
+
if (baseline === "absent" || baseline === "unreadable") {
|
|
2365
|
+
return { applied: false, fallback: baseline, lines: measuredLines };
|
|
2366
|
+
}
|
|
2367
|
+
if (baseline.measure !== "exact" || measuredMeasure !== "exact") {
|
|
2368
|
+
return { applied: false, fallback: "mixed-measure", lines: measuredLines };
|
|
2369
|
+
}
|
|
2370
|
+
if (baseline.head_sha !== headSha()) {
|
|
2371
|
+
return { applied: false, fallback: "head-moved", lines: measuredLines };
|
|
2372
|
+
}
|
|
2373
|
+
return {
|
|
2374
|
+
applied: true,
|
|
2375
|
+
baseline,
|
|
2376
|
+
lines: Math.max(0, measuredLines - baseline.baseline_lines)
|
|
2377
|
+
};
|
|
2378
|
+
}
|
|
1954
2379
|
|
|
1955
2380
|
// src/scripts/_lib/audit_field_provenance.ts
|
|
1956
2381
|
var MAX_APPLIED_IDS = 32;
|
|
@@ -1966,6 +2391,13 @@ function appliedIds(values) {
|
|
|
1966
2391
|
}
|
|
1967
2392
|
|
|
1968
2393
|
// src/scripts/_lib/review_skipped_record.ts
|
|
2394
|
+
var BASELINE_APPLICATIONS = [
|
|
2395
|
+
"applied",
|
|
2396
|
+
"absent",
|
|
2397
|
+
"unreadable",
|
|
2398
|
+
"head_moved",
|
|
2399
|
+
"mixed_measure"
|
|
2400
|
+
];
|
|
1969
2401
|
var PRODUCER_PRIVACY_CLASS = "ids-only";
|
|
1970
2402
|
function isNonNegInt(n) {
|
|
1971
2403
|
return typeof n === "number" && Number.isFinite(n) && Number.isInteger(n) && n >= 0;
|
|
@@ -1981,6 +2413,9 @@ function buildReviewSkippedLine(input) {
|
|
|
1981
2413
|
}
|
|
1982
2414
|
if (!input.ts) errors.push("ts (ISO-8601 UTC) is required");
|
|
1983
2415
|
if (!input.id) errors.push("id (ULID, UUID, or content hash) is required");
|
|
2416
|
+
if (input.baseline !== void 0 && !BASELINE_APPLICATIONS.includes(input.baseline)) {
|
|
2417
|
+
errors.push(`baseline must be one of ${BASELINE_APPLICATIONS.join(", ")}`);
|
|
2418
|
+
}
|
|
1984
2419
|
if (errors.length) return { line: null, errors };
|
|
1985
2420
|
const line = {
|
|
1986
2421
|
schema_version: 1,
|
|
@@ -2007,7 +2442,14 @@ function buildReviewSkippedLine(input) {
|
|
|
2007
2442
|
persona: null,
|
|
2008
2443
|
input_kind: "prompt",
|
|
2009
2444
|
type: "note",
|
|
2010
|
-
review_skipped: {
|
|
2445
|
+
review_skipped: {
|
|
2446
|
+
diff_lines: input.diff_lines,
|
|
2447
|
+
mutation_measure: input.mutation_measure,
|
|
2448
|
+
// Omitted, not defaulted, when the producer recorded nothing —
|
|
2449
|
+
// audit-log-v1's absent-versus-present split is the same one
|
|
2450
|
+
// `skills_applied` uses above, for the same reason.
|
|
2451
|
+
...input.baseline === void 0 ? {} : { baseline: input.baseline }
|
|
2452
|
+
}
|
|
2011
2453
|
};
|
|
2012
2454
|
return { line, errors: [] };
|
|
2013
2455
|
}
|
|
@@ -2075,13 +2517,13 @@ function isSafeTranscriptPath(rawPath, opts = {}) {
|
|
|
2075
2517
|
const homeDir = opts.homeDir ?? os.homedir();
|
|
2076
2518
|
const maxBytes = opts.maxBytes ?? TRANSCRIPT_SCAN_MAX_BYTES;
|
|
2077
2519
|
try {
|
|
2078
|
-
const realHome =
|
|
2079
|
-
const realPath =
|
|
2080
|
-
const
|
|
2081
|
-
if (
|
|
2520
|
+
const realHome = fs5.realpathSync(homeDir);
|
|
2521
|
+
const realPath = fs5.realpathSync(rawPath);
|
|
2522
|
+
const relative3 = path5.relative(realHome, realPath);
|
|
2523
|
+
if (relative3 === "" || relative3.startsWith("..") || path5.isAbsolute(relative3)) {
|
|
2082
2524
|
return false;
|
|
2083
2525
|
}
|
|
2084
|
-
const { size } =
|
|
2526
|
+
const { size } = fs5.statSync(realPath);
|
|
2085
2527
|
return size <= maxBytes;
|
|
2086
2528
|
} catch {
|
|
2087
2529
|
return false;
|
|
@@ -2112,7 +2554,7 @@ function nonDocMutatedLines(rows) {
|
|
|
2112
2554
|
}
|
|
2113
2555
|
function gitNumstatRows(cwd) {
|
|
2114
2556
|
try {
|
|
2115
|
-
const r =
|
|
2557
|
+
const r = spawnSync2("git", ["diff", "--numstat", "HEAD"], {
|
|
2116
2558
|
cwd,
|
|
2117
2559
|
encoding: "utf8",
|
|
2118
2560
|
maxBuffer: 16 * 1024 * 1024
|
|
@@ -2125,7 +2567,7 @@ function gitNumstatRows(cwd) {
|
|
|
2125
2567
|
}
|
|
2126
2568
|
function untrackedNonDocFiles(cwd) {
|
|
2127
2569
|
try {
|
|
2128
|
-
const r =
|
|
2570
|
+
const r = spawnSync2("git", ["ls-files", "--others", "--exclude-standard"], {
|
|
2129
2571
|
cwd,
|
|
2130
2572
|
encoding: "utf8",
|
|
2131
2573
|
maxBuffer: 16 * 1024 * 1024
|
|
@@ -2140,13 +2582,13 @@ var BINARY_PROBE_BYTES = 8e3;
|
|
|
2140
2582
|
var UNTRACKED_FILE_READ_CAP_BYTES = 8 * 1024 * 1024;
|
|
2141
2583
|
function untrackedFileLineCount(cwd, relPath) {
|
|
2142
2584
|
try {
|
|
2143
|
-
const abs =
|
|
2144
|
-
const size =
|
|
2585
|
+
const abs = path5.resolve(cwd, relPath);
|
|
2586
|
+
const size = fs5.statSync(abs).size;
|
|
2145
2587
|
if (size === 0) return 0;
|
|
2146
2588
|
if (size > UNTRACKED_FILE_READ_CAP_BYTES) {
|
|
2147
2589
|
return MUTATION_LINE_THRESHOLD + 1;
|
|
2148
2590
|
}
|
|
2149
|
-
const buf =
|
|
2591
|
+
const buf = fs5.readFileSync(abs);
|
|
2150
2592
|
if (buf.length === 0) return 0;
|
|
2151
2593
|
const probe = buf.subarray(0, Math.min(buf.length, BINARY_PROBE_BYTES));
|
|
2152
2594
|
if (probe.includes(0)) return 0;
|
|
@@ -2225,30 +2667,31 @@ function scanTranscriptForReviewer(transcriptText) {
|
|
|
2225
2667
|
function buildAdvisoryLine(diffLines) {
|
|
2226
2668
|
return `this session mutated ${diffLines} lines without a neutral review; spawn a cross-model reviewer before claiming done (delegation-policy / verify-budget)`;
|
|
2227
2669
|
}
|
|
2228
|
-
function appendReviewSkippedTelemetry(workspaceRoot, diffLines, mutationMeasure) {
|
|
2670
|
+
function appendReviewSkippedTelemetry(workspaceRoot, diffLines, mutationMeasure, baseline) {
|
|
2229
2671
|
if (is_replay_mode()) return;
|
|
2230
2672
|
const ts = (/* @__PURE__ */ new Date()).toISOString();
|
|
2231
2673
|
const { line, errors } = buildReviewSkippedLine({
|
|
2232
2674
|
diff_lines: diffLines,
|
|
2233
2675
|
mutation_measure: mutationMeasure,
|
|
2234
2676
|
ts,
|
|
2235
|
-
id: crypto.randomUUID()
|
|
2677
|
+
id: crypto.randomUUID(),
|
|
2678
|
+
baseline
|
|
2236
2679
|
});
|
|
2237
2680
|
if (errors.length || line === null) return;
|
|
2238
2681
|
try {
|
|
2239
|
-
const dir =
|
|
2240
|
-
|
|
2241
|
-
const file =
|
|
2242
|
-
|
|
2682
|
+
const dir = path5.join(workspaceRoot, "agents", "runtime", "state", "audit");
|
|
2683
|
+
fs5.mkdirSync(dir, { recursive: true });
|
|
2684
|
+
const file = path5.join(dir, `${ts.slice(0, 7)}.jsonl`);
|
|
2685
|
+
fs5.appendFileSync(file, `${JSON.stringify(line)}
|
|
2243
2686
|
`, "utf8");
|
|
2244
2687
|
} catch {
|
|
2245
2688
|
}
|
|
2246
2689
|
}
|
|
2247
2690
|
function sessionStateDir(workspaceRoot) {
|
|
2248
|
-
return
|
|
2691
|
+
return path5.join(workspaceRoot, "agents", "runtime", "state", "end-review-nudge");
|
|
2249
2692
|
}
|
|
2250
2693
|
function sessionStateFile(workspaceRoot, sessionKey) {
|
|
2251
|
-
return
|
|
2694
|
+
return path5.join(sessionStateDir(workspaceRoot), `${sessionKey}.json`);
|
|
2252
2695
|
}
|
|
2253
2696
|
function deriveSessionKey2(envelope, payload) {
|
|
2254
2697
|
const raw = str(envelope["session_id"]) || str(payload["transcript_path"] ?? payload["transcriptPath"]);
|
|
@@ -2257,7 +2700,7 @@ function deriveSessionKey2(envelope, payload) {
|
|
|
2257
2700
|
}
|
|
2258
2701
|
function hasFiredThisSession(workspaceRoot, sessionKey) {
|
|
2259
2702
|
try {
|
|
2260
|
-
return
|
|
2703
|
+
return fs5.existsSync(sessionStateFile(workspaceRoot, sessionKey));
|
|
2261
2704
|
} catch {
|
|
2262
2705
|
return false;
|
|
2263
2706
|
}
|
|
@@ -2271,26 +2714,45 @@ function markFiredThisSession(workspaceRoot, sessionKey, ts) {
|
|
|
2271
2714
|
function _read_stdin() {
|
|
2272
2715
|
return readHookStdin();
|
|
2273
2716
|
}
|
|
2274
|
-
|
|
2717
|
+
var FALLBACK_TO_TELEMETRY = {
|
|
2718
|
+
absent: "absent",
|
|
2719
|
+
unreadable: "unreadable",
|
|
2720
|
+
"head-moved": "head_moved",
|
|
2721
|
+
"mixed-measure": "mixed_measure"
|
|
2722
|
+
};
|
|
2723
|
+
function main4() {
|
|
2275
2724
|
const [envelope, payload] = unwrap(_read_stdin(), "claude");
|
|
2276
2725
|
const event = String(envelope["event"] ?? "");
|
|
2277
2726
|
if (event !== "" && event !== "stop") {
|
|
2278
2727
|
return 0;
|
|
2279
2728
|
}
|
|
2280
2729
|
const workspace_root = String(envelope["workspace_root"] ?? "").trim() || process.cwd();
|
|
2281
|
-
let
|
|
2730
|
+
let measuredLines;
|
|
2282
2731
|
let mutationMeasure;
|
|
2283
2732
|
try {
|
|
2284
2733
|
const measured = totalNonDocMutatedLinesWithMeasure(workspace_root);
|
|
2285
|
-
|
|
2734
|
+
measuredLines = measured.lines;
|
|
2286
2735
|
mutationMeasure = measured.measure;
|
|
2287
2736
|
} catch {
|
|
2288
2737
|
return 0;
|
|
2289
2738
|
}
|
|
2739
|
+
const sessionKey = deriveSessionKey2(envelope, payload);
|
|
2740
|
+
const baselineOutcome = applyBaseline(
|
|
2741
|
+
measuredLines,
|
|
2742
|
+
readBaseline(workspace_root, sessionKey),
|
|
2743
|
+
// A THUNK, not a value: on the `absent` and `unreadable` branches the
|
|
2744
|
+
// result is discarded, and those two are the steady state on every host
|
|
2745
|
+
// without this nudge and on every session before its first baseline
|
|
2746
|
+
// write. Passing the value eagerly spent an 11-14 ms `git rev-parse` on
|
|
2747
|
+
// each of those stops for nothing.
|
|
2748
|
+
() => currentHeadSha(workspace_root),
|
|
2749
|
+
mutationMeasure
|
|
2750
|
+
);
|
|
2751
|
+
const diffLines = baselineOutcome.lines;
|
|
2752
|
+
const baselineApplication = baselineOutcome.applied ? "applied" : FALLBACK_TO_TELEMETRY[baselineOutcome.fallback];
|
|
2290
2753
|
if (diffLines <= MUTATION_LINE_THRESHOLD) {
|
|
2291
2754
|
return 0;
|
|
2292
2755
|
}
|
|
2293
|
-
const sessionKey = deriveSessionKey2(envelope, payload);
|
|
2294
2756
|
if (hasFiredThisSession(workspace_root, sessionKey)) {
|
|
2295
2757
|
return 0;
|
|
2296
2758
|
}
|
|
@@ -2300,7 +2762,7 @@ function main3() {
|
|
|
2300
2762
|
let reviewerRan = false;
|
|
2301
2763
|
if (transcriptPath && isSafeTranscriptPath(transcriptPath)) {
|
|
2302
2764
|
try {
|
|
2303
|
-
reviewerRan = scanTranscriptForReviewer(
|
|
2765
|
+
reviewerRan = scanTranscriptForReviewer(fs5.readFileSync(transcriptPath, "utf-8"));
|
|
2304
2766
|
} catch {
|
|
2305
2767
|
reviewerRan = false;
|
|
2306
2768
|
}
|
|
@@ -2310,7 +2772,12 @@ function main3() {
|
|
|
2310
2772
|
}
|
|
2311
2773
|
markFiredThisSession(workspace_root, sessionKey, (/* @__PURE__ */ new Date()).toISOString());
|
|
2312
2774
|
try {
|
|
2313
|
-
appendReviewSkippedTelemetry(
|
|
2775
|
+
appendReviewSkippedTelemetry(
|
|
2776
|
+
workspace_root,
|
|
2777
|
+
diffLines,
|
|
2778
|
+
mutationMeasure,
|
|
2779
|
+
baselineApplication
|
|
2780
|
+
);
|
|
2314
2781
|
} catch {
|
|
2315
2782
|
}
|
|
2316
2783
|
process.stdout.write(
|
|
@@ -2323,34 +2790,34 @@ function main3() {
|
|
|
2323
2790
|
);
|
|
2324
2791
|
return EXIT_WARN2;
|
|
2325
2792
|
}
|
|
2326
|
-
function
|
|
2793
|
+
function _isCliEntry4() {
|
|
2327
2794
|
if (true) {
|
|
2328
2795
|
return false;
|
|
2329
2796
|
}
|
|
2330
2797
|
if (process.argv[1] === void 0) {
|
|
2331
2798
|
return false;
|
|
2332
2799
|
}
|
|
2333
|
-
const argvUrl =
|
|
2800
|
+
const argvUrl = pathToFileURL4(path5.resolve(process.argv[1])).href;
|
|
2334
2801
|
if (import.meta.url === argvUrl) {
|
|
2335
2802
|
return true;
|
|
2336
2803
|
}
|
|
2337
2804
|
try {
|
|
2338
|
-
const here =
|
|
2339
|
-
const argv =
|
|
2805
|
+
const here = fs5.realpathSync(fileURLToPath4(import.meta.url));
|
|
2806
|
+
const argv = fs5.realpathSync(path5.resolve(process.argv[1]));
|
|
2340
2807
|
return here === argv;
|
|
2341
2808
|
} catch {
|
|
2342
2809
|
return false;
|
|
2343
2810
|
}
|
|
2344
2811
|
}
|
|
2345
|
-
if (
|
|
2346
|
-
process.exit(
|
|
2812
|
+
if (_isCliEntry4()) {
|
|
2813
|
+
process.exit(main4());
|
|
2347
2814
|
}
|
|
2348
2815
|
|
|
2349
2816
|
// src/scripts/hooks/subagent_ledger_hook.ts
|
|
2350
2817
|
import * as crypto2 from "node:crypto";
|
|
2351
|
-
import * as
|
|
2352
|
-
import * as
|
|
2353
|
-
import { fileURLToPath as
|
|
2818
|
+
import * as fs6 from "node:fs";
|
|
2819
|
+
import * as path6 from "node:path";
|
|
2820
|
+
import { fileURLToPath as fileURLToPath5, pathToFileURL as pathToFileURL5 } from "node:url";
|
|
2354
2821
|
|
|
2355
2822
|
// src/scripts/_lib/subagent_response.ts
|
|
2356
2823
|
var MAX_SUMMARY_CHARS = 2e3;
|
|
@@ -2456,7 +2923,7 @@ var EXIT_ALLOW3 = 0;
|
|
|
2456
2923
|
function isObject2(v) {
|
|
2457
2924
|
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
2458
2925
|
}
|
|
2459
|
-
var LEDGER_DIR =
|
|
2926
|
+
var LEDGER_DIR = path6.join("agents", "runtime", "state", "subagent-ledger");
|
|
2460
2927
|
var OPEN_SUBDIR = "open";
|
|
2461
2928
|
var OPEN_RECORD_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
2462
2929
|
function refFor(agentId) {
|
|
@@ -2546,10 +3013,10 @@ function _jsonObjectCandidates(message) {
|
|
|
2546
3013
|
return out;
|
|
2547
3014
|
}
|
|
2548
3015
|
function openDir(root) {
|
|
2549
|
-
return
|
|
3016
|
+
return path6.join(root, LEDGER_DIR, OPEN_SUBDIR);
|
|
2550
3017
|
}
|
|
2551
3018
|
function openFile(root, ref) {
|
|
2552
|
-
return
|
|
3019
|
+
return path6.join(openDir(root), `${ref}.json`);
|
|
2553
3020
|
}
|
|
2554
3021
|
var DEPTH_BASES = /* @__PURE__ */ new Set(["observed", "asserted-parent", "assumed-root"]);
|
|
2555
3022
|
function _asOpenRecord(value, expectedRef) {
|
|
@@ -2576,7 +3043,7 @@ function readOpenRecords(root) {
|
|
|
2576
3043
|
const out = /* @__PURE__ */ new Map();
|
|
2577
3044
|
let names;
|
|
2578
3045
|
try {
|
|
2579
|
-
names =
|
|
3046
|
+
names = fs6.readdirSync(openDir(root));
|
|
2580
3047
|
} catch {
|
|
2581
3048
|
return out;
|
|
2582
3049
|
}
|
|
@@ -2584,7 +3051,7 @@ function readOpenRecords(root) {
|
|
|
2584
3051
|
if (!name.endsWith(".json")) continue;
|
|
2585
3052
|
const expectedRef = name.slice(0, -".json".length);
|
|
2586
3053
|
try {
|
|
2587
|
-
const raw =
|
|
3054
|
+
const raw = fs6.readFileSync(path6.join(openDir(root), name), "utf8");
|
|
2588
3055
|
const rec = _asOpenRecord(JSON.parse(raw), expectedRef);
|
|
2589
3056
|
if (rec) out.set(rec.ref, rec);
|
|
2590
3057
|
} catch {
|
|
@@ -2599,13 +3066,13 @@ function resolveDepth(parentRef, open) {
|
|
|
2599
3066
|
return { depth: parent.depth + 1, depth_basis: "observed" };
|
|
2600
3067
|
}
|
|
2601
3068
|
function ledgerFileFor2(root, ts) {
|
|
2602
|
-
return
|
|
3069
|
+
return path6.join(root, LEDGER_DIR, `${ts.slice(0, 7)}.jsonl`);
|
|
2603
3070
|
}
|
|
2604
3071
|
function appendLedgerLine(root, ts, line) {
|
|
2605
3072
|
if (is_replay_mode()) return;
|
|
2606
3073
|
const file = ledgerFileFor2(root, ts);
|
|
2607
|
-
|
|
2608
|
-
|
|
3074
|
+
fs6.mkdirSync(path6.dirname(file), { recursive: true });
|
|
3075
|
+
fs6.appendFileSync(file, `${JSON.stringify(line)}
|
|
2609
3076
|
`, "utf8");
|
|
2610
3077
|
}
|
|
2611
3078
|
var WALL_CLOCK_ARMS_MS = [
|
|
@@ -2619,7 +3086,7 @@ function armsExceeded(elapsedMs) {
|
|
|
2619
3086
|
return WALL_CLOCK_ARMS_MS.filter((a) => elapsedMs >= a.ms).map((a) => a.label);
|
|
2620
3087
|
}
|
|
2621
3088
|
function openRecordStats(root, nowMs = Date.now()) {
|
|
2622
|
-
const ledgerPresent =
|
|
3089
|
+
const ledgerPresent = fs6.existsSync(path6.join(root, LEDGER_DIR));
|
|
2623
3090
|
const open = readOpenRecords(root);
|
|
2624
3091
|
let maxDepth = 0;
|
|
2625
3092
|
let counted = 0;
|
|
@@ -2647,13 +3114,13 @@ function writeOpenRecord(root, rec) {
|
|
|
2647
3114
|
function removeOpenRecord(root, ref) {
|
|
2648
3115
|
if (is_replay_mode()) return;
|
|
2649
3116
|
try {
|
|
2650
|
-
|
|
3117
|
+
fs6.unlinkSync(openFile(root, ref));
|
|
2651
3118
|
} catch {
|
|
2652
3119
|
}
|
|
2653
3120
|
}
|
|
2654
3121
|
function countOpen(root) {
|
|
2655
3122
|
try {
|
|
2656
|
-
return
|
|
3123
|
+
return fs6.readdirSync(openDir(root)).filter((n) => n.endsWith(".json")).length;
|
|
2657
3124
|
} catch {
|
|
2658
3125
|
return 0;
|
|
2659
3126
|
}
|
|
@@ -2804,7 +3271,7 @@ function resolveConsumerRoot(envelope) {
|
|
|
2804
3271
|
}
|
|
2805
3272
|
return process.cwd();
|
|
2806
3273
|
}
|
|
2807
|
-
function
|
|
3274
|
+
function main5() {
|
|
2808
3275
|
const raw = readHookStdin();
|
|
2809
3276
|
let envelope = {};
|
|
2810
3277
|
try {
|
|
@@ -2814,20 +3281,20 @@ function main4() {
|
|
|
2814
3281
|
}
|
|
2815
3282
|
return processEnvelope(envelope, resolveConsumerRoot(envelope));
|
|
2816
3283
|
}
|
|
2817
|
-
function
|
|
3284
|
+
function _isCliEntry5() {
|
|
2818
3285
|
if (true) {
|
|
2819
3286
|
return false;
|
|
2820
3287
|
}
|
|
2821
3288
|
if (process.argv[1] === void 0) return false;
|
|
2822
|
-
const argvUrl =
|
|
3289
|
+
const argvUrl = pathToFileURL5(path6.resolve(process.argv[1])).href;
|
|
2823
3290
|
if (import.meta.url === argvUrl) return true;
|
|
2824
3291
|
try {
|
|
2825
|
-
return
|
|
3292
|
+
return fs6.realpathSync(fileURLToPath5(import.meta.url)) === fs6.realpathSync(path6.resolve(process.argv[1]));
|
|
2826
3293
|
} catch {
|
|
2827
3294
|
return false;
|
|
2828
3295
|
}
|
|
2829
3296
|
}
|
|
2830
|
-
if (
|
|
3297
|
+
if (_isCliEntry5()) process.exit(main5());
|
|
2831
3298
|
|
|
2832
3299
|
// src/scripts/hooks/turn_end_gate_hook.ts
|
|
2833
3300
|
var EXIT_BLOCK = 1;
|
|
@@ -2936,7 +3403,7 @@ function detectPromissory(reply) {
|
|
|
2936
3403
|
function readCiSettled(workspaceRoot, session_id) {
|
|
2937
3404
|
if (!hasStableSessionId(session_id)) return { seen: false, settled: false };
|
|
2938
3405
|
try {
|
|
2939
|
-
const raw =
|
|
3406
|
+
const raw = fs7.readFileSync(path7.join(workspaceRoot, statePathFor(session_id)), "utf-8");
|
|
2940
3407
|
const decoded = JSON.parse(raw);
|
|
2941
3408
|
if (!owns_session_state(decoded, session_id)) return { seen: false, settled: false };
|
|
2942
3409
|
if (typeof decoded === "object" && decoded !== null && !Array.isArray(decoded)) {
|
|
@@ -2972,8 +3439,8 @@ function detectCompletionClaim(reply, ci) {
|
|
|
2972
3439
|
function readLanguagePin(workspaceRoot, session_id) {
|
|
2973
3440
|
if (!hasStableSessionId(session_id)) return "und";
|
|
2974
3441
|
try {
|
|
2975
|
-
const raw =
|
|
2976
|
-
|
|
3442
|
+
const raw = fs7.readFileSync(
|
|
3443
|
+
path7.join(workspaceRoot, statePathFor2(session_id)),
|
|
2977
3444
|
"utf-8"
|
|
2978
3445
|
);
|
|
2979
3446
|
const decoded = JSON.parse(raw);
|
|
@@ -3024,12 +3491,37 @@ function detectUnverifiedEdit(toolCalls) {
|
|
|
3024
3491
|
reason: "this turn changed a file and then ran no verification command \u2014 no test, type-check, lint or build call follows the last edit (verify-before-complete: a claim without a fresh run is unverified)"
|
|
3025
3492
|
};
|
|
3026
3493
|
}
|
|
3494
|
+
var _SOURCE_RE = /\.(?:ts|tsx|js|jsx|mjs|cjs|vue|svelte|php|py|rb|go|rs|java|kt|swift|cs|scala|ex|exs)$/i;
|
|
3495
|
+
var _TEST_PATH_RE = /(?:^|\/)(?:tests?|specs?|__tests__|__specs__|e2e|cypress|playwright|features)\//i;
|
|
3496
|
+
var _TEST_FILE_RE = /(?:\.(?:test|spec)\.[a-z]+$)|(?:_test\.[a-z]+$)|(?:(?:^|\/)test_[^/]+$)|(?:Test\.php$)|(?:Spec\.php$)|(?:\.feature$)/i;
|
|
3497
|
+
function _isTestPath(p) {
|
|
3498
|
+
return _TEST_PATH_RE.test(p) || _TEST_FILE_RE.test(p);
|
|
3499
|
+
}
|
|
3500
|
+
function _isProductionSource(p) {
|
|
3501
|
+
return _SOURCE_RE.test(p) && !_isTestPath(p);
|
|
3502
|
+
}
|
|
3503
|
+
function detectUntestedChange(reply, toolCalls) {
|
|
3504
|
+
const edited = toolCalls.filter((c) => _EDIT_TOOLS.has(c.name) && c.path !== void 0).map((c) => c.path);
|
|
3505
|
+
const source = edited.filter(_isProductionSource);
|
|
3506
|
+
if (source.length === 0) return null;
|
|
3507
|
+
if (edited.some(_isTestPath)) return null;
|
|
3508
|
+
const prose = visibleProse(reply);
|
|
3509
|
+
const m = _COMPLETION_RE.exec(prose);
|
|
3510
|
+
if (!m) return null;
|
|
3511
|
+
if (_NEGATED_CLAIM_RE.test(_lineAround(prose, m.index))) return null;
|
|
3512
|
+
const shown = source.slice(0, 3).join(", ");
|
|
3513
|
+
return {
|
|
3514
|
+
detector: "untested",
|
|
3515
|
+
evidence: shown + (source.length > 3 ? ` (+${String(source.length - 3)} more)` : ""),
|
|
3516
|
+
reason: "a completion claim over production code this turn changed, with NO test file touched anywhere in the turn \u2014 running a linter is not evidence the change works. Write the test that would have caught the failure, and enumerate the states the change actually has (every view, every CRUD path, the empty and error states) rather than the happy one. If a test genuinely does not belong here, say which file carries the coverage instead"
|
|
3517
|
+
};
|
|
3518
|
+
}
|
|
3027
3519
|
function sessionStateFile2(workspaceRoot, sessionKey) {
|
|
3028
3520
|
return sessionRefusalFile(workspaceRoot, sessionKey);
|
|
3029
3521
|
}
|
|
3030
3522
|
function alreadyRefusedTurn(workspaceRoot, sessionKey, turnOrdinal) {
|
|
3031
3523
|
try {
|
|
3032
|
-
const raw =
|
|
3524
|
+
const raw = fs7.readFileSync(sessionStateFile2(workspaceRoot, sessionKey), "utf-8");
|
|
3033
3525
|
const decoded = JSON.parse(raw);
|
|
3034
3526
|
if (typeof decoded === "object" && decoded !== null && !Array.isArray(decoded)) {
|
|
3035
3527
|
return decoded["refused_turn"] === turnOrdinal;
|
|
@@ -3038,12 +3530,12 @@ function alreadyRefusedTurn(workspaceRoot, sessionKey, turnOrdinal) {
|
|
|
3038
3530
|
}
|
|
3039
3531
|
return false;
|
|
3040
3532
|
}
|
|
3041
|
-
function markRefusedTurn(workspaceRoot, sessionKey, turnOrdinal, detectors) {
|
|
3533
|
+
function markRefusedTurn(workspaceRoot, sessionKey, turnOrdinal, detectors, promptId) {
|
|
3042
3534
|
if (is_replay_mode()) return;
|
|
3043
3535
|
const file = sessionStateFile2(workspaceRoot, sessionKey);
|
|
3044
3536
|
let prev = null;
|
|
3045
3537
|
try {
|
|
3046
|
-
prev = parseRecord(
|
|
3538
|
+
prev = parseRecord(fs7.readFileSync(file, "utf-8"));
|
|
3047
3539
|
} catch {
|
|
3048
3540
|
}
|
|
3049
3541
|
let version;
|
|
@@ -3059,27 +3551,34 @@ function markRefusedTurn(workspaceRoot, sessionKey, turnOrdinal, detectors) {
|
|
|
3059
3551
|
detectors,
|
|
3060
3552
|
turnOrdinal,
|
|
3061
3553
|
at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3062
|
-
version
|
|
3554
|
+
version,
|
|
3555
|
+
promptId
|
|
3063
3556
|
})
|
|
3064
3557
|
);
|
|
3065
3558
|
} catch {
|
|
3066
3559
|
}
|
|
3067
3560
|
}
|
|
3068
3561
|
function readTranscriptTail(transcriptPath, opts = {}) {
|
|
3069
|
-
const empty = {
|
|
3562
|
+
const empty = {
|
|
3563
|
+
lastAssistant: "",
|
|
3564
|
+
turnOrdinal: 0,
|
|
3565
|
+
toolCalls: [],
|
|
3566
|
+
assistantTurnTexts: []
|
|
3567
|
+
};
|
|
3070
3568
|
if (!transcriptPath || !isSafeTranscriptPath(transcriptPath, opts)) return empty;
|
|
3071
3569
|
let lines;
|
|
3072
3570
|
try {
|
|
3073
|
-
if (opts.maxBytes !== void 0 &&
|
|
3571
|
+
if (opts.maxBytes !== void 0 && fs7.statSync(transcriptPath).size > opts.maxBytes) {
|
|
3074
3572
|
return empty;
|
|
3075
3573
|
}
|
|
3076
|
-
lines =
|
|
3574
|
+
lines = fs7.readFileSync(transcriptPath, "utf-8").split("\n");
|
|
3077
3575
|
} catch {
|
|
3078
3576
|
return empty;
|
|
3079
3577
|
}
|
|
3080
3578
|
let lastAssistant = "";
|
|
3081
3579
|
let turnOrdinal = 0;
|
|
3082
3580
|
let toolCalls = [];
|
|
3581
|
+
let assistantTurnTexts = [];
|
|
3083
3582
|
for (const rawLine of lines) {
|
|
3084
3583
|
const line = rawLine.trim();
|
|
3085
3584
|
if (!line) continue;
|
|
@@ -3098,20 +3597,27 @@ function readTranscriptTail(transcriptPath, opts = {}) {
|
|
|
3098
3597
|
if (typeof msg !== "object" || msg === null || Array.isArray(msg)) continue;
|
|
3099
3598
|
const content = msg["content"];
|
|
3100
3599
|
if (role === "assistant") {
|
|
3101
|
-
toolCalls.push(...
|
|
3600
|
+
toolCalls.push(...extractToolCalls(content));
|
|
3102
3601
|
}
|
|
3103
3602
|
const text = _messageText(content);
|
|
3104
3603
|
if (text === null) continue;
|
|
3105
3604
|
if (role === "assistant") {
|
|
3106
3605
|
lastAssistant = text;
|
|
3606
|
+
assistantTurnTexts.push(text);
|
|
3107
3607
|
} else if (!isSyntheticPrompt(text)) {
|
|
3108
3608
|
turnOrdinal += 1;
|
|
3109
3609
|
toolCalls = [];
|
|
3610
|
+
assistantTurnTexts = [];
|
|
3110
3611
|
}
|
|
3111
3612
|
}
|
|
3112
|
-
return {
|
|
3613
|
+
return {
|
|
3614
|
+
lastAssistant: lastAssistant.trim(),
|
|
3615
|
+
turnOrdinal,
|
|
3616
|
+
toolCalls,
|
|
3617
|
+
assistantTurnTexts
|
|
3618
|
+
};
|
|
3113
3619
|
}
|
|
3114
|
-
function
|
|
3620
|
+
function extractToolCalls(content) {
|
|
3115
3621
|
if (!Array.isArray(content)) return [];
|
|
3116
3622
|
const out = [];
|
|
3117
3623
|
for (const blk of content) {
|
|
@@ -3149,7 +3655,7 @@ function _messageText(content) {
|
|
|
3149
3655
|
function str3(v) {
|
|
3150
3656
|
return typeof v === "string" ? v : "";
|
|
3151
3657
|
}
|
|
3152
|
-
function
|
|
3658
|
+
function main6() {
|
|
3153
3659
|
let envelope;
|
|
3154
3660
|
let payload;
|
|
3155
3661
|
try {
|
|
@@ -3167,10 +3673,19 @@ function main5() {
|
|
|
3167
3673
|
const transcriptPath = str3(
|
|
3168
3674
|
payload["transcript_path"] ?? payload["transcriptPath"]
|
|
3169
3675
|
);
|
|
3170
|
-
const { lastAssistant, turnOrdinal, toolCalls } = readTranscriptTail(
|
|
3171
|
-
|
|
3172
|
-
|
|
3676
|
+
const { lastAssistant, turnOrdinal, toolCalls, assistantTurnTexts } = readTranscriptTail(
|
|
3677
|
+
transcriptPath,
|
|
3678
|
+
{ maxBytes: TRANSCRIPT_READ_MAX_BYTES }
|
|
3679
|
+
);
|
|
3173
3680
|
if (!lastAssistant) return EXIT_ALLOW4;
|
|
3681
|
+
const payloadClosing = str3(
|
|
3682
|
+
payload["last_assistant_message"] ?? payload["lastAssistantMessage"]
|
|
3683
|
+
);
|
|
3684
|
+
const closingFromPayload = payloadClosing !== "" && !assistantTurnTexts.includes(payloadClosing);
|
|
3685
|
+
const turnTexts = closingFromPayload ? [...assistantTurnTexts, payloadClosing] : assistantTurnTexts;
|
|
3686
|
+
const promptId = str3(
|
|
3687
|
+
payload["prompt_id"] ?? payload["promptId"]
|
|
3688
|
+
);
|
|
3174
3689
|
const rawSessionId = str3(envelope["session_id"]) || "";
|
|
3175
3690
|
const sessionKey = deriveSessionKey(rawSessionId || "unknown-session");
|
|
3176
3691
|
if (alreadyRefusedTurn(workspaceRoot, sessionKey, turnOrdinal)) return EXIT_ALLOW4;
|
|
@@ -3192,7 +3707,23 @@ function main5() {
|
|
|
3192
3707
|
// gating is where the comment above says gating belongs — inside the
|
|
3193
3708
|
// detector: no CI observed, or a settled read, or no completion claim
|
|
3194
3709
|
// ⇒ no finding.
|
|
3195
|
-
dispatchOpen ? null : detectCompletionClaim(lastAssistant, readCiSettled(workspaceRoot, rawSessionId))
|
|
3710
|
+
dispatchOpen ? null : detectCompletionClaim(lastAssistant, readCiSettled(workspaceRoot, rawSessionId)),
|
|
3711
|
+
// Detector E is UNCONDITIONAL, and that is the opposite choice from A
|
|
3712
|
+
// and D one line above rather than an oversight. An open dispatch
|
|
3713
|
+
// excuses a promissory closing because the work is genuinely still
|
|
3714
|
+
// running; it excuses nothing about a question the user was already
|
|
3715
|
+
// asked. Worse: a dispatch — or the `end-review-nudge` stop concern
|
|
3716
|
+
// that produced the measured failure — IS the continuation that drops
|
|
3717
|
+
// the decision, so narrowing E the same way would silence it in exactly
|
|
3718
|
+
// the case it exists for.
|
|
3719
|
+
detectDroppedDecision(turnTexts, closingFromPayload),
|
|
3720
|
+
// Detector F takes the OTHER side of that same question, and the two
|
|
3721
|
+
// sitting adjacent is the clearest place to say why. E fires on a
|
|
3722
|
+
// question already asked, which an open dispatch cannot excuse. F fires
|
|
3723
|
+
// on a completion CLAIM, and a turn waiting on a subagent has not
|
|
3724
|
+
// finished — so its closing is not the claim F is about. Same slot,
|
|
3725
|
+
// opposite trigger, opposite treatment of `dispatchOpen`.
|
|
3726
|
+
dispatchOpen ? null : detectUntestedChange(lastAssistant, toolCalls)
|
|
3196
3727
|
]) {
|
|
3197
3728
|
if (f) findings.push(f);
|
|
3198
3729
|
}
|
|
@@ -3201,7 +3732,8 @@ function main5() {
|
|
|
3201
3732
|
workspaceRoot,
|
|
3202
3733
|
sessionKey,
|
|
3203
3734
|
turnOrdinal,
|
|
3204
|
-
findings.map((f) => f.detector)
|
|
3735
|
+
findings.map((f) => f.detector),
|
|
3736
|
+
promptId
|
|
3205
3737
|
);
|
|
3206
3738
|
const lines = findings.map(
|
|
3207
3739
|
(f) => ` \xB7 ${f.detector}: ${f.reason}
|
|
@@ -3210,43 +3742,61 @@ function main5() {
|
|
|
3210
3742
|
process.stderr.write(
|
|
3211
3743
|
`turn-end-gate: REFUSED \u2014 this turn is not finished.
|
|
3212
3744
|
${lines.join("\n")}
|
|
3213
|
-
Do the promised work now, correct the language, run the verification the edit needs,
|
|
3745
|
+
Do the promised work now, correct the language, run the verification the edit needs, read the CI verdict before claiming it, or re-present the options block this turn dropped \u2014 then end the turn.
|
|
3214
3746
|
This turn will not be refused a second time.
|
|
3215
3747
|
`
|
|
3216
3748
|
);
|
|
3217
3749
|
return EXIT_BLOCK;
|
|
3218
3750
|
}
|
|
3219
|
-
function
|
|
3751
|
+
function _isCliEntry6() {
|
|
3220
3752
|
if (true) {
|
|
3221
3753
|
return false;
|
|
3222
3754
|
}
|
|
3223
3755
|
if (process.argv[1] === void 0) {
|
|
3224
3756
|
return false;
|
|
3225
3757
|
}
|
|
3226
|
-
const argvUrl =
|
|
3758
|
+
const argvUrl = pathToFileURL6(path7.resolve(process.argv[1])).href;
|
|
3227
3759
|
if (import.meta.url === argvUrl) {
|
|
3228
3760
|
return true;
|
|
3229
3761
|
}
|
|
3230
3762
|
try {
|
|
3231
|
-
const here =
|
|
3232
|
-
const argv =
|
|
3763
|
+
const here = fs7.realpathSync(fileURLToPath6(import.meta.url));
|
|
3764
|
+
const argv = fs7.realpathSync(path7.resolve(process.argv[1]));
|
|
3233
3765
|
return here === argv;
|
|
3234
3766
|
} catch {
|
|
3235
3767
|
return false;
|
|
3236
3768
|
}
|
|
3237
3769
|
}
|
|
3238
|
-
if (
|
|
3239
|
-
process.exit(
|
|
3770
|
+
if (_isCliEntry6()) {
|
|
3771
|
+
process.exit(main6());
|
|
3240
3772
|
}
|
|
3241
3773
|
|
|
3242
3774
|
// src/scripts/hooks/evidence_independence.ts
|
|
3775
|
+
import { spawnSync as spawnSync3 } from "node:child_process";
|
|
3243
3776
|
import crypto3 from "node:crypto";
|
|
3244
|
-
import
|
|
3245
|
-
import
|
|
3246
|
-
import { fileURLToPath as
|
|
3777
|
+
import fs8 from "node:fs";
|
|
3778
|
+
import path8 from "node:path";
|
|
3779
|
+
import { fileURLToPath as fileURLToPath7, pathToFileURL as pathToFileURL7 } from "node:url";
|
|
3780
|
+
|
|
3781
|
+
// src/scripts/_lib/test_delta.ts
|
|
3782
|
+
function isCodePath(p) {
|
|
3783
|
+
const f = p.replace(/\\/g, "/");
|
|
3784
|
+
if (isTestPath(f)) return false;
|
|
3785
|
+
if (!/\.(ts|tsx|js|mjs|cjs)$/.test(f)) return false;
|
|
3786
|
+
if (f.endsWith(".d.ts")) return false;
|
|
3787
|
+
if (/^(dist|\.augment|\.claude|\.cursor|node_modules)\//.test(f)) return false;
|
|
3788
|
+
return /^(src|scripts)\//.test(f);
|
|
3789
|
+
}
|
|
3790
|
+
function isTestPath(p) {
|
|
3791
|
+
const f = p.replace(/\\/g, "/");
|
|
3792
|
+
if (/^tests\//.test(f)) return true;
|
|
3793
|
+
return /\.(test|spec)\.(ts|tsx|js|mjs|cjs)$/.test(f);
|
|
3794
|
+
}
|
|
3795
|
+
|
|
3796
|
+
// src/scripts/hooks/evidence_independence.ts
|
|
3247
3797
|
var EXIT_ALLOW5 = 0;
|
|
3248
3798
|
var EXIT_BLOCK2 = 1;
|
|
3249
|
-
var STATE_FILE3 =
|
|
3799
|
+
var STATE_FILE3 = path8.join("agents", "state", "evidence-dispatch.json");
|
|
3250
3800
|
function _isObject5(v) {
|
|
3251
3801
|
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
3252
3802
|
}
|
|
@@ -3314,8 +3864,8 @@ function extractDispatch(envelope) {
|
|
|
3314
3864
|
}
|
|
3315
3865
|
function _ledgerStamp(consumer_root) {
|
|
3316
3866
|
try {
|
|
3317
|
-
const raw =
|
|
3318
|
-
|
|
3867
|
+
const raw = fs8.readFileSync(
|
|
3868
|
+
path8.join(consumer_root, "agents", "state", "git-authorization.json"),
|
|
3319
3869
|
"utf8"
|
|
3320
3870
|
);
|
|
3321
3871
|
const d = JSON.parse(raw);
|
|
@@ -3326,7 +3876,7 @@ function _ledgerStamp(consumer_root) {
|
|
|
3326
3876
|
}
|
|
3327
3877
|
function _load(target) {
|
|
3328
3878
|
try {
|
|
3329
|
-
const decoded = JSON.parse(
|
|
3879
|
+
const decoded = JSON.parse(fs8.readFileSync(target, "utf8"));
|
|
3330
3880
|
if (_isObject5(decoded) && Array.isArray(decoded["evaluations"])) {
|
|
3331
3881
|
return decoded;
|
|
3332
3882
|
}
|
|
@@ -3372,6 +3922,32 @@ function decide(tool, prompt, priorEvaluations) {
|
|
|
3372
3922
|
evaluations: priorEvaluations + 1
|
|
3373
3923
|
};
|
|
3374
3924
|
}
|
|
3925
|
+
function sameSessionTestFlag(command) {
|
|
3926
|
+
if (command === null || !/\bgit\b[^|;&]*\bcommit\b/.test(command)) return null;
|
|
3927
|
+
return SAME_SESSION_TEXT;
|
|
3928
|
+
}
|
|
3929
|
+
var SAME_SESSION_TEXT = "This commit stages both a test and code it could cover \u2014 the shape L0 takes in a diff, where the implementer authored the evaluator. This check reads the staged set only: it cannot tell who wrote the test, so it is a prompt to STATE the level, not a finding that you are at L0. L0 is a permitted FALLBACK, not the default: where a second session, a second model or a second provider was available, the test should have come from one of them. Say which in the commit or the PR body \u2014 a diff looks identical either way. See evaluator-independence \xA7 Tests are evaluators.";
|
|
3930
|
+
function touchesTestAndCode(paths) {
|
|
3931
|
+
return paths.some(isTestPath) && paths.some(isCodePath);
|
|
3932
|
+
}
|
|
3933
|
+
function _commandOf(envelope) {
|
|
3934
|
+
const payload = _isObject5(envelope["payload"]) ? envelope["payload"] : envelope;
|
|
3935
|
+
const input = _isObject5(payload["tool_input"]) ? payload["tool_input"] : payload;
|
|
3936
|
+
for (const key of ["command", "cmd", "shell_command"]) {
|
|
3937
|
+
const v = input[key];
|
|
3938
|
+
if (typeof v === "string" && v !== "") return v;
|
|
3939
|
+
}
|
|
3940
|
+
return null;
|
|
3941
|
+
}
|
|
3942
|
+
function _stagedPaths(consumer_root) {
|
|
3943
|
+
const r = spawnSync3("git", ["diff", "--cached", "--name-only"], {
|
|
3944
|
+
cwd: consumer_root,
|
|
3945
|
+
encoding: "utf8"
|
|
3946
|
+
});
|
|
3947
|
+
if (r.status !== 0) return null;
|
|
3948
|
+
const out = r.stdout.split("\n").map((s) => s.trim()).filter((s) => s !== "");
|
|
3949
|
+
return out.length === 0 ? null : out;
|
|
3950
|
+
}
|
|
3375
3951
|
function run3(stdin_text, options) {
|
|
3376
3952
|
let envelope = {};
|
|
3377
3953
|
if (stdin_text.trim()) {
|
|
@@ -3384,7 +3960,7 @@ function run3(stdin_text, options) {
|
|
|
3384
3960
|
return EXIT_ALLOW5;
|
|
3385
3961
|
}
|
|
3386
3962
|
}
|
|
3387
|
-
const target =
|
|
3963
|
+
const target = path8.join(options.consumer_root, STATE_FILE3);
|
|
3388
3964
|
const state = _load(target);
|
|
3389
3965
|
const session_id = typeof envelope["session_id"] === "string" ? envelope["session_id"] : "";
|
|
3390
3966
|
const turnMarker = `${session_id}:${_ledgerStamp(options.consumer_root)}`;
|
|
@@ -3394,6 +3970,15 @@ function run3(stdin_text, options) {
|
|
|
3394
3970
|
state.evaluations = [];
|
|
3395
3971
|
}
|
|
3396
3972
|
const [tool, prompt] = extractDispatch(envelope);
|
|
3973
|
+
const flag = sameSessionTestFlag(_commandOf(envelope));
|
|
3974
|
+
if (flag !== null) {
|
|
3975
|
+
const staged = _stagedPaths(options.consumer_root);
|
|
3976
|
+
if (staged !== null && touchesTestAndCode(staged)) {
|
|
3977
|
+
process.stdout.write(`${JSON.stringify({ decision: "warn", reason: flag })}
|
|
3978
|
+
`);
|
|
3979
|
+
return EXIT_ALLOW5;
|
|
3980
|
+
}
|
|
3981
|
+
}
|
|
3397
3982
|
const decision = decide(tool, prompt, state.evaluations.length);
|
|
3398
3983
|
if (decision.evaluations > state.evaluations.length) {
|
|
3399
3984
|
state.evaluations.push({
|
|
@@ -3422,7 +4007,7 @@ function _errText3(err) {
|
|
|
3422
4007
|
const t = err instanceof Error ? err.message : String(err);
|
|
3423
4008
|
return t.replace(/\s+/g, " ").trim().slice(0, 200);
|
|
3424
4009
|
}
|
|
3425
|
-
function
|
|
4010
|
+
function main7(argv) {
|
|
3426
4011
|
const args = argv ?? process.argv.slice(2);
|
|
3427
4012
|
let consumer_root = process.cwd();
|
|
3428
4013
|
for (let i = 0; i < args.length; i += 1) {
|
|
@@ -3436,33 +4021,33 @@ function main6(argv) {
|
|
|
3436
4021
|
}
|
|
3437
4022
|
return run3(readHookStdin(), { consumer_root });
|
|
3438
4023
|
}
|
|
3439
|
-
function
|
|
4024
|
+
function _isCliEntry7() {
|
|
3440
4025
|
if (true) {
|
|
3441
4026
|
return false;
|
|
3442
4027
|
}
|
|
3443
4028
|
if (process.argv[1] === void 0) {
|
|
3444
4029
|
return false;
|
|
3445
4030
|
}
|
|
3446
|
-
const argvUrl =
|
|
4031
|
+
const argvUrl = pathToFileURL7(path8.resolve(process.argv[1])).href;
|
|
3447
4032
|
if (import.meta.url === argvUrl) {
|
|
3448
4033
|
return true;
|
|
3449
4034
|
}
|
|
3450
4035
|
try {
|
|
3451
|
-
const here =
|
|
3452
|
-
const argv =
|
|
4036
|
+
const here = fs8.realpathSync(fileURLToPath7(import.meta.url));
|
|
4037
|
+
const argv = fs8.realpathSync(path8.resolve(process.argv[1]));
|
|
3453
4038
|
return here === argv;
|
|
3454
4039
|
} catch {
|
|
3455
4040
|
return false;
|
|
3456
4041
|
}
|
|
3457
4042
|
}
|
|
3458
|
-
if (
|
|
3459
|
-
process.exit(
|
|
4043
|
+
if (_isCliEntry7()) {
|
|
4044
|
+
process.exit(main7());
|
|
3460
4045
|
}
|
|
3461
4046
|
|
|
3462
4047
|
// src/scripts/hooks/delegation_nudge_hook.ts
|
|
3463
|
-
import
|
|
3464
|
-
import
|
|
3465
|
-
import { fileURLToPath as
|
|
4048
|
+
import fs9 from "node:fs";
|
|
4049
|
+
import path9 from "node:path";
|
|
4050
|
+
import { fileURLToPath as fileURLToPath8, pathToFileURL as pathToFileURL8 } from "node:url";
|
|
3466
4051
|
|
|
3467
4052
|
// src/scripts/_lib/auto_dispatch.ts
|
|
3468
4053
|
var SIZE_FLOOR = 1;
|
|
@@ -3917,7 +4502,7 @@ function _workspaceRoot(envelope) {
|
|
|
3917
4502
|
}
|
|
3918
4503
|
return process.cwd();
|
|
3919
4504
|
}
|
|
3920
|
-
function
|
|
4505
|
+
function main8() {
|
|
3921
4506
|
let envelope = {};
|
|
3922
4507
|
try {
|
|
3923
4508
|
const raw = readHookStdin();
|
|
@@ -3956,31 +4541,31 @@ function main7() {
|
|
|
3956
4541
|
);
|
|
3957
4542
|
return EXIT_WARN3;
|
|
3958
4543
|
}
|
|
3959
|
-
function
|
|
4544
|
+
function _isCliEntry8() {
|
|
3960
4545
|
if (true) {
|
|
3961
4546
|
return false;
|
|
3962
4547
|
}
|
|
3963
4548
|
if (process.argv[1] === void 0) {
|
|
3964
4549
|
return false;
|
|
3965
4550
|
}
|
|
3966
|
-
const argvUrl =
|
|
4551
|
+
const argvUrl = pathToFileURL8(path9.resolve(process.argv[1])).href;
|
|
3967
4552
|
if (import.meta.url === argvUrl) {
|
|
3968
4553
|
return true;
|
|
3969
4554
|
}
|
|
3970
4555
|
try {
|
|
3971
|
-
const here =
|
|
3972
|
-
const argv =
|
|
4556
|
+
const here = fs9.realpathSync(fileURLToPath8(import.meta.url));
|
|
4557
|
+
const argv = fs9.realpathSync(path9.resolve(process.argv[1]));
|
|
3973
4558
|
return here === argv;
|
|
3974
4559
|
} catch {
|
|
3975
4560
|
return false;
|
|
3976
4561
|
}
|
|
3977
4562
|
}
|
|
3978
|
-
if (
|
|
3979
|
-
process.exit(
|
|
4563
|
+
if (_isCliEntry8()) {
|
|
4564
|
+
process.exit(main8());
|
|
3980
4565
|
}
|
|
3981
4566
|
|
|
3982
4567
|
// src/scripts/conformance_scan.ts
|
|
3983
|
-
var REPO_ROOT =
|
|
4568
|
+
var REPO_ROOT = path10.resolve(path10.dirname(fileURLToPath9(import.meta.url)), "..", "..");
|
|
3984
4569
|
var OBSERVED_BAND = { low: 9.1, high: 39.2 };
|
|
3985
4570
|
var BAND_MIN_TURNS = 1978;
|
|
3986
4571
|
var CARRIER_CHANGES = [
|
|
@@ -4346,7 +4931,7 @@ function scanSession(sessionId, lines) {
|
|
|
4346
4931
|
closeWindow();
|
|
4347
4932
|
return report;
|
|
4348
4933
|
}
|
|
4349
|
-
var DEFAULT_RATE_SERIES =
|
|
4934
|
+
var DEFAULT_RATE_SERIES = path10.join(
|
|
4350
4935
|
REPO_ROOT,
|
|
4351
4936
|
"agents",
|
|
4352
4937
|
"runtime",
|
|
@@ -4355,7 +4940,7 @@ var DEFAULT_RATE_SERIES = path8.join(
|
|
|
4355
4940
|
);
|
|
4356
4941
|
function defaultStore(projectDir) {
|
|
4357
4942
|
const slug = projectStoreSlug(projectDir);
|
|
4358
|
-
return
|
|
4943
|
+
return path10.join(process.env["HOME"] ?? "", ".claude", "projects", slug);
|
|
4359
4944
|
}
|
|
4360
4945
|
function _tokens(chars) {
|
|
4361
4946
|
return Math.round(chars / 4);
|
|
@@ -4366,13 +4951,13 @@ function measureDelivered(projectRulesDir, globalRulesDir) {
|
|
|
4366
4951
|
return {
|
|
4367
4952
|
project: {
|
|
4368
4953
|
dir: projectRulesDir,
|
|
4369
|
-
present:
|
|
4954
|
+
present: fs10.existsSync(projectRulesDir),
|
|
4370
4955
|
files: p.files,
|
|
4371
4956
|
tokens: _tokens(p.chars)
|
|
4372
4957
|
},
|
|
4373
4958
|
global: {
|
|
4374
4959
|
dir: globalRulesDir,
|
|
4375
|
-
present:
|
|
4960
|
+
present: fs10.existsSync(globalRulesDir),
|
|
4376
4961
|
files: g.files,
|
|
4377
4962
|
tokens: _tokens(g.chars)
|
|
4378
4963
|
},
|
|
@@ -4380,13 +4965,13 @@ function measureDelivered(projectRulesDir, globalRulesDir) {
|
|
|
4380
4965
|
};
|
|
4381
4966
|
}
|
|
4382
4967
|
function storeKey(store) {
|
|
4383
|
-
return createHash3("sha256").update(
|
|
4968
|
+
return createHash3("sha256").update(path10.resolve(store)).digest("hex").slice(0, 12);
|
|
4384
4969
|
}
|
|
4385
4970
|
function scanStore(store, limit) {
|
|
4386
|
-
const files =
|
|
4971
|
+
const files = fs10.readdirSync(store).filter((f) => f.endsWith(".jsonl")).map((f) => ({ f, m: fs10.statSync(path10.join(store, f)).mtimeMs })).sort((a, b) => b.m - a.m).slice(0, limit).map((x) => x.f);
|
|
4387
4972
|
const per_session = [];
|
|
4388
4973
|
for (const f of files) {
|
|
4389
|
-
const lines =
|
|
4974
|
+
const lines = fs10.readFileSync(path10.join(store, f), "utf8").split("\n");
|
|
4390
4975
|
const r = scanSession(f.replace(/\.jsonl$/, "").slice(0, 8), lines);
|
|
4391
4976
|
if (r.assistant_turns > 0) {
|
|
4392
4977
|
per_session.push(r);
|
|
@@ -4414,10 +4999,10 @@ function scanStore(store, limit) {
|
|
|
4414
4999
|
const task_completeness_rate_pct = completeness_windows === 0 ? 0 : Number((100 * task_completeness / completeness_windows).toFixed(1));
|
|
4415
5000
|
const era = spansCarrierChange(per_session.map((s) => s.first_at));
|
|
4416
5001
|
const delivered = measureDelivered(
|
|
4417
|
-
|
|
4418
|
-
|
|
5002
|
+
path10.join(REPO_ROOT, ".claude", "rules"),
|
|
5003
|
+
path10.join(process.env["HOME"] ?? os2.homedir(), ".claude", "rules")
|
|
4419
5004
|
);
|
|
4420
|
-
const ownStore =
|
|
5005
|
+
const ownStore = path10.resolve(store) === path10.resolve(defaultStore(REPO_ROOT));
|
|
4421
5006
|
return {
|
|
4422
5007
|
scanned_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4423
5008
|
store,
|
|
@@ -4447,8 +5032,8 @@ function scanStore(store, limit) {
|
|
|
4447
5032
|
};
|
|
4448
5033
|
}
|
|
4449
5034
|
function recordRate(file, scanned_at, rate) {
|
|
4450
|
-
|
|
4451
|
-
|
|
5035
|
+
fs10.mkdirSync(path10.dirname(file), { recursive: true });
|
|
5036
|
+
fs10.appendFileSync(file, `${JSON.stringify({ measured_at: scanned_at, ...rate })}
|
|
4452
5037
|
`, "utf8");
|
|
4453
5038
|
}
|
|
4454
5039
|
function render(report) {
|
|
@@ -4547,7 +5132,7 @@ function render(report) {
|
|
|
4547
5132
|
lines.push(" checkbox batching \u2014 measured NOWHERE. ~5 low-severity findings.");
|
|
4548
5133
|
return lines.join("\n");
|
|
4549
5134
|
}
|
|
4550
|
-
function
|
|
5135
|
+
function main9(argv) {
|
|
4551
5136
|
const args = argv ?? process.argv.slice(2);
|
|
4552
5137
|
let store = null;
|
|
4553
5138
|
let limit = 30;
|
|
@@ -4579,14 +5164,14 @@ function main8(argv) {
|
|
|
4579
5164
|
return 2;
|
|
4580
5165
|
}
|
|
4581
5166
|
const resolved = store ?? defaultStore(process.cwd());
|
|
4582
|
-
if (!
|
|
5167
|
+
if (!fs10.existsSync(resolved)) {
|
|
4583
5168
|
process.stderr.write(`conformance:behavior: no transcript store at ${resolved}
|
|
4584
5169
|
`);
|
|
4585
5170
|
return 1;
|
|
4586
5171
|
}
|
|
4587
5172
|
const report = scanStore(resolved, Number.isFinite(limit) && limit > 0 ? limit : 30);
|
|
4588
5173
|
if (out) {
|
|
4589
|
-
|
|
5174
|
+
fs10.writeFileSync(out, `${JSON.stringify(report, null, 2)}
|
|
4590
5175
|
`, "utf8");
|
|
4591
5176
|
}
|
|
4592
5177
|
if (record) {
|
|
@@ -4594,7 +5179,7 @@ function main8(argv) {
|
|
|
4594
5179
|
}
|
|
4595
5180
|
if (why !== null) {
|
|
4596
5181
|
const id = why;
|
|
4597
|
-
|
|
5182
|
+
fs10.writeSync(
|
|
4598
5183
|
1,
|
|
4599
5184
|
json ? `${JSON.stringify(
|
|
4600
5185
|
{
|
|
@@ -4614,48 +5199,48 @@ function main8(argv) {
|
|
|
4614
5199
|
);
|
|
4615
5200
|
return 0;
|
|
4616
5201
|
}
|
|
4617
|
-
|
|
5202
|
+
fs10.writeSync(1, json ? `${JSON.stringify(report, null, 2)}
|
|
4618
5203
|
` : `${render(report)}
|
|
4619
5204
|
`);
|
|
4620
5205
|
return 0;
|
|
4621
5206
|
}
|
|
4622
|
-
function
|
|
5207
|
+
function _isCliEntry9() {
|
|
4623
5208
|
if (true) {
|
|
4624
5209
|
return false;
|
|
4625
5210
|
}
|
|
4626
5211
|
if (process.argv[1] === void 0) {
|
|
4627
5212
|
return false;
|
|
4628
5213
|
}
|
|
4629
|
-
const argvUrl =
|
|
5214
|
+
const argvUrl = pathToFileURL9(path10.resolve(process.argv[1])).href;
|
|
4630
5215
|
if (import.meta.url === argvUrl) {
|
|
4631
5216
|
return true;
|
|
4632
5217
|
}
|
|
4633
5218
|
try {
|
|
4634
|
-
const here =
|
|
4635
|
-
const argv =
|
|
5219
|
+
const here = fs10.realpathSync(fileURLToPath9(import.meta.url));
|
|
5220
|
+
const argv = fs10.realpathSync(path10.resolve(process.argv[1]));
|
|
4636
5221
|
return here === argv;
|
|
4637
5222
|
} catch {
|
|
4638
5223
|
return false;
|
|
4639
5224
|
}
|
|
4640
5225
|
}
|
|
4641
|
-
if (
|
|
4642
|
-
process.exit(
|
|
5226
|
+
if (_isCliEntry9()) {
|
|
5227
|
+
process.exit(main9());
|
|
4643
5228
|
}
|
|
4644
5229
|
|
|
4645
5230
|
// src/scripts/report_carrier_divergence.ts
|
|
4646
|
-
import * as
|
|
5231
|
+
import * as fs11 from "node:fs";
|
|
4647
5232
|
import * as os3 from "node:os";
|
|
4648
|
-
import * as
|
|
5233
|
+
import * as path11 from "node:path";
|
|
4649
5234
|
import process2 from "node:process";
|
|
4650
|
-
import { fileURLToPath as
|
|
4651
|
-
var
|
|
4652
|
-
var REPO_ROOT2 =
|
|
4653
|
-
var PROJECT_RULES =
|
|
4654
|
-
var PROJECTION_SOURCE =
|
|
4655
|
-
var GLOBAL_RULES =
|
|
5235
|
+
import { fileURLToPath as fileURLToPath10, pathToFileURL as pathToFileURL10 } from "node:url";
|
|
5236
|
+
var _HERE2 = fileURLToPath10(import.meta.url);
|
|
5237
|
+
var REPO_ROOT2 = path11.resolve(path11.dirname(_HERE2), "..", "..");
|
|
5238
|
+
var PROJECT_RULES = path11.join(".claude", "rules");
|
|
5239
|
+
var PROJECTION_SOURCE = path11.join("dist", "agent-src", "rules");
|
|
5240
|
+
var GLOBAL_RULES = path11.join(".claude", "rules");
|
|
4656
5241
|
function _listRules(dir) {
|
|
4657
5242
|
try {
|
|
4658
|
-
return
|
|
5243
|
+
return fs11.readdirSync(dir).filter((f) => f.endsWith(".md")).sort();
|
|
4659
5244
|
} catch {
|
|
4660
5245
|
return [];
|
|
4661
5246
|
}
|
|
@@ -4663,7 +5248,7 @@ function _listRules(dir) {
|
|
|
4663
5248
|
function _ruleType(file) {
|
|
4664
5249
|
let text;
|
|
4665
5250
|
try {
|
|
4666
|
-
text =
|
|
5251
|
+
text = fs11.readFileSync(file, "utf-8");
|
|
4667
5252
|
} catch {
|
|
4668
5253
|
return "";
|
|
4669
5254
|
}
|
|
@@ -4674,8 +5259,8 @@ function compareCarriers(projectDir, globalDir, sourceDir) {
|
|
|
4674
5259
|
const out = {
|
|
4675
5260
|
projectDir,
|
|
4676
5261
|
globalDir,
|
|
4677
|
-
globalPresent:
|
|
4678
|
-
projectPresent:
|
|
5262
|
+
globalPresent: fs11.existsSync(globalDir),
|
|
5263
|
+
projectPresent: fs11.existsSync(projectDir),
|
|
4679
5264
|
shared: 0,
|
|
4680
5265
|
identical: [],
|
|
4681
5266
|
provenanceOnly: [],
|
|
@@ -4698,7 +5283,7 @@ function compareCarriers(projectDir, globalDir, sourceDir) {
|
|
|
4698
5283
|
}
|
|
4699
5284
|
if (!inP && inG) {
|
|
4700
5285
|
out.globalOnly.push(rule);
|
|
4701
|
-
if (sourceDir !== void 0 && _ruleType(
|
|
5286
|
+
if (sourceDir !== void 0 && _ruleType(path11.join(sourceDir, rule)) === "manual") {
|
|
4702
5287
|
out.manualOnlyGlobal.push(rule);
|
|
4703
5288
|
}
|
|
4704
5289
|
continue;
|
|
@@ -4708,8 +5293,8 @@ function compareCarriers(projectDir, globalDir, sourceDir) {
|
|
|
4708
5293
|
let projectCopy;
|
|
4709
5294
|
let globalCopy;
|
|
4710
5295
|
try {
|
|
4711
|
-
projectCopy =
|
|
4712
|
-
globalCopy =
|
|
5296
|
+
projectCopy = fs11.readFileSync(path11.join(projectDir, rule));
|
|
5297
|
+
globalCopy = fs11.readFileSync(path11.join(globalDir, rule));
|
|
4713
5298
|
verdict = comparePair(projectCopy, globalCopy);
|
|
4714
5299
|
} catch {
|
|
4715
5300
|
out.shared -= 1;
|
|
@@ -4854,11 +5439,11 @@ function render2(d) {
|
|
|
4854
5439
|
}
|
|
4855
5440
|
return lines.join("\n");
|
|
4856
5441
|
}
|
|
4857
|
-
function
|
|
5442
|
+
function main10(argv) {
|
|
4858
5443
|
const args = argv ?? process2.argv.slice(2);
|
|
4859
|
-
let projectDir =
|
|
4860
|
-
let globalDir =
|
|
4861
|
-
let sourceDir =
|
|
5444
|
+
let projectDir = path11.join(REPO_ROOT2, PROJECT_RULES);
|
|
5445
|
+
let globalDir = path11.join(os3.homedir(), GLOBAL_RULES);
|
|
5446
|
+
let sourceDir = path11.join(REPO_ROOT2, PROJECTION_SOURCE);
|
|
4862
5447
|
const value = (i) => {
|
|
4863
5448
|
const v = args[i + 1];
|
|
4864
5449
|
return v === void 0 || v.startsWith("-") ? null : v;
|
|
@@ -4872,7 +5457,7 @@ function main9(argv) {
|
|
|
4872
5457
|
`);
|
|
4873
5458
|
return 1;
|
|
4874
5459
|
}
|
|
4875
|
-
const resolved =
|
|
5460
|
+
const resolved = path11.resolve(v);
|
|
4876
5461
|
if (a === "--project") projectDir = resolved;
|
|
4877
5462
|
else if (a === "--global") globalDir = resolved;
|
|
4878
5463
|
else sourceDir = resolved;
|
|
@@ -4892,26 +5477,26 @@ function main9(argv) {
|
|
|
4892
5477
|
`);
|
|
4893
5478
|
return 0;
|
|
4894
5479
|
}
|
|
4895
|
-
function
|
|
5480
|
+
function _isCliEntry10() {
|
|
4896
5481
|
if (process2.argv[1] === void 0) return false;
|
|
4897
|
-
if (import.meta.url ===
|
|
5482
|
+
if (import.meta.url === pathToFileURL10(path11.resolve(process2.argv[1])).href) return true;
|
|
4898
5483
|
try {
|
|
4899
|
-
return
|
|
5484
|
+
return fs11.realpathSync(_HERE2) === fs11.realpathSync(path11.resolve(process2.argv[1]));
|
|
4900
5485
|
} catch {
|
|
4901
5486
|
return false;
|
|
4902
5487
|
}
|
|
4903
5488
|
}
|
|
4904
|
-
if (
|
|
4905
|
-
process2.exit(
|
|
5489
|
+
if (_isCliEntry10()) {
|
|
5490
|
+
process2.exit(main10());
|
|
4906
5491
|
}
|
|
4907
5492
|
|
|
4908
5493
|
// src/scripts/report_skill_activation.ts
|
|
4909
|
-
import * as
|
|
5494
|
+
import * as fs12 from "node:fs";
|
|
4910
5495
|
import * as os4 from "node:os";
|
|
4911
|
-
import * as
|
|
4912
|
-
import { fileURLToPath as
|
|
4913
|
-
var
|
|
4914
|
-
var REPO_ROOT3 =
|
|
5496
|
+
import * as path12 from "node:path";
|
|
5497
|
+
import { fileURLToPath as fileURLToPath11, pathToFileURL as pathToFileURL11 } from "node:url";
|
|
5498
|
+
var _HERE3 = fileURLToPath11(import.meta.url);
|
|
5499
|
+
var REPO_ROOT3 = path12.resolve(path12.dirname(_HERE3), "..", "..");
|
|
4915
5500
|
var SKILLS_ROOT = "src/skills";
|
|
4916
5501
|
var TRIGGER_KEYS = ["triggers:", "trigger_description:", "file_pattern:", "path_prefix:"];
|
|
4917
5502
|
var DETERMINISTIC_RE = /^\s*(?:[-*]\s*)?(?:\*\*)?(MUST|NEVER|ALWAYS)\b/m;
|
|
@@ -4922,25 +5507,25 @@ function censusSkills(root) {
|
|
|
4922
5507
|
withTriggerCorpus: [],
|
|
4923
5508
|
withDeterministicObligation: []
|
|
4924
5509
|
};
|
|
4925
|
-
if (!
|
|
5510
|
+
if (!fs12.existsSync(root)) {
|
|
4926
5511
|
return out;
|
|
4927
5512
|
}
|
|
4928
|
-
for (const entry of
|
|
5513
|
+
for (const entry of fs12.readdirSync(root, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name))) {
|
|
4929
5514
|
if (!entry.isDirectory()) {
|
|
4930
5515
|
continue;
|
|
4931
5516
|
}
|
|
4932
|
-
const file =
|
|
4933
|
-
if (!
|
|
5517
|
+
const file = path12.join(root, entry.name, "SKILL.md");
|
|
5518
|
+
if (!fs12.existsSync(file)) {
|
|
4934
5519
|
continue;
|
|
4935
5520
|
}
|
|
4936
5521
|
out.total += 1;
|
|
4937
|
-
const text =
|
|
5522
|
+
const text = fs12.readFileSync(file, "utf8");
|
|
4938
5523
|
const fmEnd = text.startsWith("---") ? text.indexOf("\n---", 3) : -1;
|
|
4939
5524
|
const fm = fmEnd === -1 ? "" : text.slice(0, fmEnd);
|
|
4940
5525
|
if (TRIGGER_KEYS.some((k) => new RegExp(`^${k}`, "m").test(fm))) {
|
|
4941
5526
|
out.withTriggerKey.push(entry.name);
|
|
4942
5527
|
}
|
|
4943
|
-
if (
|
|
5528
|
+
if (fs12.existsSync(path12.join(root, entry.name, "evals", "triggers.json"))) {
|
|
4944
5529
|
out.withTriggerCorpus.push(entry.name);
|
|
4945
5530
|
}
|
|
4946
5531
|
const body = fmEnd === -1 ? text : text.slice(fmEnd + 4);
|
|
@@ -4951,17 +5536,17 @@ function censusSkills(root) {
|
|
|
4951
5536
|
return out;
|
|
4952
5537
|
}
|
|
4953
5538
|
function defaultStore2(cwd) {
|
|
4954
|
-
return
|
|
5539
|
+
return path12.join(os4.homedir(), ".claude", "projects", projectStoreSlug(cwd));
|
|
4955
5540
|
}
|
|
4956
5541
|
function measureUsage(store, limit) {
|
|
4957
5542
|
const rep = { store, sessions: 0, assistantTurns: 0, invocations: 0, bySkill: {} };
|
|
4958
|
-
if (!
|
|
5543
|
+
if (!fs12.existsSync(store)) {
|
|
4959
5544
|
return rep;
|
|
4960
5545
|
}
|
|
4961
|
-
const files =
|
|
5546
|
+
const files = fs12.readdirSync(store).filter((f) => f.endsWith(".jsonl")).map((f) => path12.join(store, f)).sort((a, b) => fs12.statSync(b).mtimeMs - fs12.statSync(a).mtimeMs).slice(0, limit);
|
|
4962
5547
|
rep.sessions = files.length;
|
|
4963
5548
|
for (const file of files) {
|
|
4964
|
-
for (const line of
|
|
5549
|
+
for (const line of fs12.readFileSync(file, "utf8").split("\n")) {
|
|
4965
5550
|
if (!line.trim()) {
|
|
4966
5551
|
continue;
|
|
4967
5552
|
}
|
|
@@ -5034,15 +5619,15 @@ function buildRecord(census, usage, today) {
|
|
|
5034
5619
|
assistant_turns: usage.reduce((a, u) => a + u.assistantTurns, 0),
|
|
5035
5620
|
invocations: usage.reduce((a, u) => a + u.invocations, 0),
|
|
5036
5621
|
distinct_skills_invoked: distinct.size,
|
|
5037
|
-
stores: usage.map((u) =>
|
|
5622
|
+
stores: usage.map((u) => path12.basename(u.store))
|
|
5038
5623
|
};
|
|
5039
5624
|
}
|
|
5040
5625
|
function readRecord(repoRoot) {
|
|
5041
|
-
const file =
|
|
5042
|
-
if (!
|
|
5626
|
+
const file = path12.join(repoRoot, RECORD_PATH);
|
|
5627
|
+
if (!fs12.existsSync(file)) {
|
|
5043
5628
|
return null;
|
|
5044
5629
|
}
|
|
5045
|
-
return JSON.parse(
|
|
5630
|
+
return JSON.parse(fs12.readFileSync(file, "utf8"));
|
|
5046
5631
|
}
|
|
5047
5632
|
function render3(census, usage, published = null) {
|
|
5048
5633
|
const lines = [];
|
|
@@ -5077,7 +5662,7 @@ function render3(census, usage, published = null) {
|
|
|
5077
5662
|
}
|
|
5078
5663
|
totalInv += u.invocations;
|
|
5079
5664
|
lines.push(
|
|
5080
|
-
` ${
|
|
5665
|
+
` ${path12.basename(u.store).slice(-38).padEnd(38)} sessions=${String(u.sessions).padStart(3)} asst=${String(u.assistantTurns).padStart(6)} Skill calls=${String(u.invocations).padStart(3)}`
|
|
5081
5666
|
);
|
|
5082
5667
|
}
|
|
5083
5668
|
lines.push("");
|
|
@@ -5147,8 +5732,8 @@ function render3(census, usage, published = null) {
|
|
|
5147
5732
|
lines.push(" catalogue once per session, then count descriptions against bare names.");
|
|
5148
5733
|
return lines.join("\n");
|
|
5149
5734
|
}
|
|
5150
|
-
var
|
|
5151
|
-
function
|
|
5735
|
+
var USAGE2 = "usage: report_skill_activation [--root DIR] [--limit N] [--store PATH]... [--emit] [--allow-empty-store]\n";
|
|
5736
|
+
function main11(argv) {
|
|
5152
5737
|
let limit = 30;
|
|
5153
5738
|
let emit = false;
|
|
5154
5739
|
let allowEmpty = false;
|
|
@@ -5170,7 +5755,7 @@ function main10(argv) {
|
|
|
5170
5755
|
} else if (a === "--allow-empty-store") {
|
|
5171
5756
|
allowEmpty = true;
|
|
5172
5757
|
} else if (a === "--help" || a === "-h") {
|
|
5173
|
-
process.stdout.write(
|
|
5758
|
+
process.stdout.write(USAGE2);
|
|
5174
5759
|
return 0;
|
|
5175
5760
|
}
|
|
5176
5761
|
}
|
|
@@ -5181,7 +5766,7 @@ function main10(argv) {
|
|
|
5181
5766
|
if (stores.length === 0) {
|
|
5182
5767
|
stores.push(defaultStore2(REPO_ROOT3));
|
|
5183
5768
|
}
|
|
5184
|
-
const census = censusSkills(
|
|
5769
|
+
const census = censusSkills(path12.join(root, SKILLS_ROOT));
|
|
5185
5770
|
const usage = stores.map((s) => measureUsage(s, limit));
|
|
5186
5771
|
process.stdout.write(`${render3(census, usage, readRecord(root))}
|
|
5187
5772
|
`);
|
|
@@ -5202,27 +5787,27 @@ function main10(argv) {
|
|
|
5202
5787
|
return 1;
|
|
5203
5788
|
}
|
|
5204
5789
|
const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
5205
|
-
const file =
|
|
5206
|
-
|
|
5207
|
-
|
|
5790
|
+
const file = path12.join(root, RECORD_PATH);
|
|
5791
|
+
fs12.mkdirSync(path12.dirname(file), { recursive: true });
|
|
5792
|
+
fs12.writeFileSync(file, `${JSON.stringify(buildRecord(census, usage, today), null, 2)}
|
|
5208
5793
|
`);
|
|
5209
5794
|
process.stdout.write(`
|
|
5210
5795
|
wrote ${RECORD_PATH} (measured ${today})
|
|
5211
5796
|
`);
|
|
5212
5797
|
return 0;
|
|
5213
5798
|
}
|
|
5214
|
-
if (process.argv[1] !== void 0 && import.meta.url ===
|
|
5215
|
-
process.exit(
|
|
5799
|
+
if (process.argv[1] !== void 0 && import.meta.url === pathToFileURL11(path12.resolve(process.argv[1])).href) {
|
|
5800
|
+
process.exit(main11(process.argv.slice(2)));
|
|
5216
5801
|
}
|
|
5217
5802
|
|
|
5218
5803
|
// src/scripts/report_skill_obligation_violations.ts
|
|
5219
|
-
import * as
|
|
5804
|
+
import * as fs13 from "node:fs";
|
|
5220
5805
|
import * as os5 from "node:os";
|
|
5221
|
-
import * as
|
|
5806
|
+
import * as path13 from "node:path";
|
|
5222
5807
|
import process3 from "node:process";
|
|
5223
|
-
import { fileURLToPath as
|
|
5224
|
-
var
|
|
5225
|
-
var REPO_ROOT4 =
|
|
5808
|
+
import { fileURLToPath as fileURLToPath12, pathToFileURL as pathToFileURL12 } from "node:url";
|
|
5809
|
+
var _HERE4 = fileURLToPath12(import.meta.url);
|
|
5810
|
+
var REPO_ROOT4 = path13.resolve(path13.dirname(_HERE4), "..", "..");
|
|
5226
5811
|
var OBLIGATION_LINE_RE = new RegExp(`${DETERMINISTIC_RE.source}.*`, "gm");
|
|
5227
5812
|
var PATH_RE = /`([A-Za-z0-9_./-]*\/[A-Za-z0-9_.-]+\.[a-z]{2,6})`/g;
|
|
5228
5813
|
var CMD_RE = /`([a-z][a-z0-9-]*(?: [a-z][a-z0-9:._-]*){1,3})`/g;
|
|
@@ -5260,7 +5845,7 @@ function _artefacts(line) {
|
|
|
5260
5845
|
return out;
|
|
5261
5846
|
}
|
|
5262
5847
|
function extractObligations(repoRoot) {
|
|
5263
|
-
const skillsRoot =
|
|
5848
|
+
const skillsRoot = path13.join(repoRoot, SKILLS_ROOT);
|
|
5264
5849
|
const census = censusSkills(skillsRoot);
|
|
5265
5850
|
const out = {
|
|
5266
5851
|
skills: census.withDeterministicObligation,
|
|
@@ -5274,7 +5859,7 @@ function extractObligations(repoRoot) {
|
|
|
5274
5859
|
for (const skill of census.withDeterministicObligation) {
|
|
5275
5860
|
let text;
|
|
5276
5861
|
try {
|
|
5277
|
-
text =
|
|
5862
|
+
text = fs13.readFileSync(path13.join(skillsRoot, skill, "SKILL.md"), "utf-8");
|
|
5278
5863
|
} catch {
|
|
5279
5864
|
continue;
|
|
5280
5865
|
}
|
|
@@ -5390,7 +5975,7 @@ function scanSessionForViolations(session, lines, forbidden, parsed) {
|
|
|
5390
5975
|
return flags;
|
|
5391
5976
|
}
|
|
5392
5977
|
function defaultStore3(cwd) {
|
|
5393
|
-
return
|
|
5978
|
+
return path13.join(os5.homedir(), ".claude", "projects", projectStoreSlug(cwd));
|
|
5394
5979
|
}
|
|
5395
5980
|
function scanStore2(repoRoot, store, limit) {
|
|
5396
5981
|
const census = extractObligations(repoRoot);
|
|
@@ -5403,14 +5988,14 @@ function scanStore2(repoRoot, store, limit) {
|
|
|
5403
5988
|
};
|
|
5404
5989
|
let files;
|
|
5405
5990
|
try {
|
|
5406
|
-
files =
|
|
5991
|
+
files = fs13.readdirSync(store).filter((f) => f.endsWith(".jsonl")).map((f) => ({ p: path13.join(store, f), m: fs13.statSync(path13.join(store, f)).mtimeMs })).sort((a, b) => b.m - a.m).slice(0, limit).map((x) => x.p);
|
|
5407
5992
|
} catch {
|
|
5408
5993
|
return report;
|
|
5409
5994
|
}
|
|
5410
5995
|
report.sessions = files.length;
|
|
5411
5996
|
for (const file of files) {
|
|
5412
|
-
const lines =
|
|
5413
|
-
const id =
|
|
5997
|
+
const lines = fs13.readFileSync(file, "utf-8").split("\n");
|
|
5998
|
+
const id = path13.basename(file).replace(/\.jsonl$/, "").slice(0, 8);
|
|
5414
5999
|
const entries = _parseSession(lines);
|
|
5415
6000
|
if (loadedSkillsFrom(entries).size > 0) report.sessionsWithASkill += 1;
|
|
5416
6001
|
report.flags.push(...scanSessionForViolations(id, lines, census.forbidden, entries));
|
|
@@ -5480,7 +6065,7 @@ function render4(r) {
|
|
|
5480
6065
|
lines.push(" ships as detection-only, and this one says so.");
|
|
5481
6066
|
return lines.join("\n");
|
|
5482
6067
|
}
|
|
5483
|
-
function
|
|
6068
|
+
function main12(argv) {
|
|
5484
6069
|
const args = argv ?? process3.argv.slice(2);
|
|
5485
6070
|
let limit = 30;
|
|
5486
6071
|
let json = false;
|
|
@@ -5533,35 +6118,35 @@ function main11(argv) {
|
|
|
5533
6118
|
}
|
|
5534
6119
|
return 0;
|
|
5535
6120
|
}
|
|
5536
|
-
function
|
|
6121
|
+
function _isCliEntry11() {
|
|
5537
6122
|
if (process3.argv[1] === void 0) return false;
|
|
5538
|
-
if (import.meta.url ===
|
|
6123
|
+
if (import.meta.url === pathToFileURL12(path13.resolve(process3.argv[1])).href) return true;
|
|
5539
6124
|
try {
|
|
5540
|
-
return
|
|
6125
|
+
return fs13.realpathSync(_HERE4) === fs13.realpathSync(path13.resolve(process3.argv[1]));
|
|
5541
6126
|
} catch {
|
|
5542
6127
|
return false;
|
|
5543
6128
|
}
|
|
5544
6129
|
}
|
|
5545
|
-
if (
|
|
5546
|
-
process3.exit(
|
|
6130
|
+
if (_isCliEntry11()) {
|
|
6131
|
+
process3.exit(main12());
|
|
5547
6132
|
}
|
|
5548
6133
|
|
|
5549
6134
|
// src/scripts/report_conformance_funnel.ts
|
|
5550
|
-
var
|
|
5551
|
-
var REPO_ROOT5 =
|
|
6135
|
+
var _HERE5 = fileURLToPath13(import.meta.url);
|
|
6136
|
+
var REPO_ROOT5 = path14.resolve(path14.dirname(_HERE5), "..", "..");
|
|
5552
6137
|
function buildFunnel(opts = {}) {
|
|
5553
6138
|
const repoRoot = opts.repoRoot ?? REPO_ROOT5;
|
|
5554
|
-
const projectRulesDir = opts.projectRulesDir ??
|
|
5555
|
-
const globalRulesDir = opts.globalRulesDir ??
|
|
5556
|
-
const sourceDir = opts.sourceDir ??
|
|
6139
|
+
const projectRulesDir = opts.projectRulesDir ?? path14.join(repoRoot, PROJECT_RULES);
|
|
6140
|
+
const globalRulesDir = opts.globalRulesDir ?? path14.join(os6.homedir(), GLOBAL_RULES);
|
|
6141
|
+
const sourceDir = opts.sourceDir ?? path14.join(repoRoot, PROJECTION_SOURCE);
|
|
5557
6142
|
const store = opts.store ?? defaultStore(repoRoot);
|
|
5558
6143
|
const limit = opts.limit ?? 30;
|
|
5559
6144
|
return {
|
|
5560
6145
|
delivered: measureDelivered(projectRulesDir, globalRulesDir),
|
|
5561
6146
|
divergence: compareCarriers(projectRulesDir, globalRulesDir, sourceDir),
|
|
5562
|
-
skills: censusSkills(
|
|
6147
|
+
skills: censusSkills(path14.join(repoRoot, SKILLS_ROOT)),
|
|
5563
6148
|
usage: measureUsage(store, limit),
|
|
5564
|
-
storePresent:
|
|
6149
|
+
storePresent: fs14.existsSync(store),
|
|
5565
6150
|
sk2: scanStore2(repoRoot, store, limit)
|
|
5566
6151
|
};
|
|
5567
6152
|
}
|
|
@@ -5686,7 +6271,7 @@ function render5(r) {
|
|
|
5686
6271
|
lines.push("workflow without a measured false-positive rate first (locked policy).");
|
|
5687
6272
|
return lines.join("\n");
|
|
5688
6273
|
}
|
|
5689
|
-
function
|
|
6274
|
+
function main13(argv) {
|
|
5690
6275
|
const args = argv ?? process4.argv.slice(2);
|
|
5691
6276
|
const opts = {};
|
|
5692
6277
|
const value = (i) => {
|
|
@@ -5702,7 +6287,7 @@ function main12(argv) {
|
|
|
5702
6287
|
`);
|
|
5703
6288
|
return 1;
|
|
5704
6289
|
}
|
|
5705
|
-
const resolved =
|
|
6290
|
+
const resolved = path14.resolve(v);
|
|
5706
6291
|
if (a === "--store") opts.store = resolved;
|
|
5707
6292
|
else if (a === "--project") opts.projectRulesDir = resolved;
|
|
5708
6293
|
else if (a === "--global") opts.globalRulesDir = resolved;
|
|
@@ -5732,21 +6317,21 @@ function main12(argv) {
|
|
|
5732
6317
|
`);
|
|
5733
6318
|
return 0;
|
|
5734
6319
|
}
|
|
5735
|
-
function
|
|
6320
|
+
function _isCliEntry12() {
|
|
5736
6321
|
if (process4.argv[1] === void 0) return false;
|
|
5737
|
-
if (import.meta.url ===
|
|
6322
|
+
if (import.meta.url === pathToFileURL13(path14.resolve(process4.argv[1])).href) return true;
|
|
5738
6323
|
try {
|
|
5739
|
-
return
|
|
6324
|
+
return fs14.realpathSync(_HERE5) === fs14.realpathSync(path14.resolve(process4.argv[1]));
|
|
5740
6325
|
} catch {
|
|
5741
6326
|
return false;
|
|
5742
6327
|
}
|
|
5743
6328
|
}
|
|
5744
|
-
if (
|
|
5745
|
-
process4.exit(
|
|
6329
|
+
if (_isCliEntry12()) {
|
|
6330
|
+
process4.exit(main13());
|
|
5746
6331
|
}
|
|
5747
6332
|
|
|
5748
6333
|
// src/scripts/_cli/cmd_conformance.ts
|
|
5749
|
-
var
|
|
6334
|
+
var _HERE6 = fileURLToPath14(import.meta.url);
|
|
5750
6335
|
var PACKAGE_ROOT = resolvePackageRoot(import.meta.url);
|
|
5751
6336
|
var CONFORMANCE_CHECK_IDS = [
|
|
5752
6337
|
"txlog-clean",
|
|
@@ -5756,6 +6341,10 @@ var CONFORMANCE_CHECK_IDS = [
|
|
|
5756
6341
|
"host-manifest"
|
|
5757
6342
|
];
|
|
5758
6343
|
var THIN_STUB_MARKER = "Routed rule \u2014 load the body on trigger-match";
|
|
6344
|
+
var CONFORMANCE_STATUS_SYMBOLS = {
|
|
6345
|
+
...STATUS_SYMBOLS,
|
|
6346
|
+
unknown: "\u2754"
|
|
6347
|
+
};
|
|
5759
6348
|
function print(s = "") {
|
|
5760
6349
|
process5.stdout.write(`${s}
|
|
5761
6350
|
`);
|
|
@@ -5769,30 +6358,33 @@ function conformanceLogPath() {
|
|
|
5769
6358
|
if (override && override.trim().length > 0) {
|
|
5770
6359
|
return override;
|
|
5771
6360
|
}
|
|
5772
|
-
return
|
|
6361
|
+
return path15.join(os7.homedir(), ".event4u", "agent-config", "conformance-log.jsonl");
|
|
5773
6362
|
}
|
|
5774
6363
|
function installLogPath() {
|
|
5775
6364
|
const override = process5.env["AGENT_CONFIG_INSTALL_LOG"];
|
|
5776
6365
|
if (override && override.trim().length > 0) {
|
|
5777
6366
|
return override;
|
|
5778
6367
|
}
|
|
5779
|
-
return
|
|
6368
|
+
return path15.join(os7.homedir(), ".event4u", "agent-config", "install-log.jsonl");
|
|
5780
6369
|
}
|
|
5781
|
-
function
|
|
5782
|
-
|
|
5783
|
-
|
|
5784
|
-
|
|
5785
|
-
|
|
5786
|
-
message: "no install transaction log \u2014 nothing to recover",
|
|
5787
|
-
remedy: ""
|
|
5788
|
-
};
|
|
5789
|
-
}
|
|
5790
|
-
const entries = readRecentEntries(logPath);
|
|
6370
|
+
function _installLogExpected(projectRoot) {
|
|
6371
|
+
return fs15.existsSync(manifest_path(projectRoot));
|
|
6372
|
+
}
|
|
6373
|
+
function _check_txlog_clean(logPath = installLogPath(), projectRoot = null) {
|
|
6374
|
+
const entries = fs15.existsSync(logPath) ? readRecentEntries(logPath) : [];
|
|
5791
6375
|
if (entries.length === 0) {
|
|
6376
|
+
if (projectRoot !== null && _installLogExpected(projectRoot)) {
|
|
6377
|
+
return {
|
|
6378
|
+
id: "txlog-clean",
|
|
6379
|
+
status: "unknown",
|
|
6380
|
+
message: "install manifest present, no usable install transaction log \u2014 nothing recorded this install, so the last run cannot be confirmed complete",
|
|
6381
|
+
remedy: "no install path writes this log today; run `agent-config doctor` for the drift answer this check cannot give"
|
|
6382
|
+
};
|
|
6383
|
+
}
|
|
5792
6384
|
return {
|
|
5793
6385
|
id: "txlog-clean",
|
|
5794
6386
|
status: "ok",
|
|
5795
|
-
message: "install transaction log
|
|
6387
|
+
message: "no usable install transaction log and no install manifest \u2014 nothing was installed here",
|
|
5796
6388
|
remedy: ""
|
|
5797
6389
|
};
|
|
5798
6390
|
}
|
|
@@ -5802,7 +6394,7 @@ function _check_txlog_clean(logPath = installLogPath()) {
|
|
|
5802
6394
|
id: "txlog-clean",
|
|
5803
6395
|
status: "fail",
|
|
5804
6396
|
message: `install log tail is an abandoned run (abort at ${last.ts}${last.note ? `: ${last.note}` : ""})`,
|
|
5805
|
-
remedy: "re-run `agent-config init`
|
|
6397
|
+
remedy: "re-run `agent-config init` \u2014 it re-applies the plan over the partial tail; the aborted run's writes stay on disk and are replaced only where the plan covers them"
|
|
5806
6398
|
};
|
|
5807
6399
|
}
|
|
5808
6400
|
return {
|
|
@@ -5813,11 +6405,11 @@ function _check_txlog_clean(logPath = installLogPath()) {
|
|
|
5813
6405
|
};
|
|
5814
6406
|
}
|
|
5815
6407
|
function routeTargetPaths(target) {
|
|
5816
|
-
return routeTargetPathsPosix(target).map((rel) =>
|
|
6408
|
+
return routeTargetPathsPosix(target).map((rel) => path15.join(...rel.split("/")));
|
|
5817
6409
|
}
|
|
5818
6410
|
function _check_router_pointers(packageRoot = PACKAGE_ROOT) {
|
|
5819
|
-
const routerPath =
|
|
5820
|
-
if (!
|
|
6411
|
+
const routerPath = path15.join(packageRoot, "dist", "router.json");
|
|
6412
|
+
if (!fs15.existsSync(routerPath)) {
|
|
5821
6413
|
return {
|
|
5822
6414
|
id: "router-pointers",
|
|
5823
6415
|
status: "fail",
|
|
@@ -5827,7 +6419,7 @@ function _check_router_pointers(packageRoot = PACKAGE_ROOT) {
|
|
|
5827
6419
|
}
|
|
5828
6420
|
let router;
|
|
5829
6421
|
try {
|
|
5830
|
-
router = JSON.parse(
|
|
6422
|
+
router = JSON.parse(fs15.readFileSync(routerPath, "utf8"));
|
|
5831
6423
|
} catch (exc) {
|
|
5832
6424
|
return {
|
|
5833
6425
|
id: "router-pointers",
|
|
@@ -5836,13 +6428,13 @@ function _check_router_pointers(packageRoot = PACKAGE_ROOT) {
|
|
|
5836
6428
|
remedy: "reinstall the package \u2014 dist/router.json is corrupt"
|
|
5837
6429
|
};
|
|
5838
6430
|
}
|
|
5839
|
-
const rulesDir =
|
|
6431
|
+
const rulesDir = path15.join(packageRoot, "dist", "agent-src", "rules");
|
|
5840
6432
|
const broken = [];
|
|
5841
6433
|
let ids = 0;
|
|
5842
6434
|
let targets = 0;
|
|
5843
6435
|
for (const kernelId of router["kernel"] ?? []) {
|
|
5844
6436
|
ids += 1;
|
|
5845
|
-
if (!
|
|
6437
|
+
if (!fs15.existsSync(path15.join(rulesDir, `${kernelId}.md`))) {
|
|
5846
6438
|
broken.push(`kernel:${kernelId} \u2192 rules/${kernelId}.md missing`);
|
|
5847
6439
|
}
|
|
5848
6440
|
}
|
|
@@ -5850,7 +6442,7 @@ function _check_router_pointers(packageRoot = PACKAGE_ROOT) {
|
|
|
5850
6442
|
for (const entry of router[tier] ?? []) {
|
|
5851
6443
|
const ruleId = String(entry["id"] ?? "");
|
|
5852
6444
|
ids += 1;
|
|
5853
|
-
if (!
|
|
6445
|
+
if (!fs15.existsSync(path15.join(rulesDir, `${ruleId}.md`))) {
|
|
5854
6446
|
broken.push(`${tier}:${ruleId} \u2192 rules/${ruleId}.md missing`);
|
|
5855
6447
|
}
|
|
5856
6448
|
for (const target of entry["routes_to"] ?? []) {
|
|
@@ -5860,7 +6452,7 @@ function _check_router_pointers(packageRoot = PACKAGE_ROOT) {
|
|
|
5860
6452
|
broken.push(`${ruleId} \u2192 unparseable routes_to ${JSON.stringify(target)}`);
|
|
5861
6453
|
continue;
|
|
5862
6454
|
}
|
|
5863
|
-
if (!candidates.some((rel) =>
|
|
6455
|
+
if (!candidates.some((rel) => fs15.existsSync(path15.join(packageRoot, rel)))) {
|
|
5864
6456
|
broken.push(`${ruleId} \u2192 ${target} (${candidates[0]} missing)`);
|
|
5865
6457
|
}
|
|
5866
6458
|
}
|
|
@@ -5892,9 +6484,9 @@ function detectSmokePlatform(projectRoot) {
|
|
|
5892
6484
|
return "claude";
|
|
5893
6485
|
}
|
|
5894
6486
|
function dispatcherRunner(packageRoot) {
|
|
5895
|
-
const localTsx =
|
|
5896
|
-
const script =
|
|
5897
|
-
if (
|
|
6487
|
+
const localTsx = path15.join(packageRoot, "node_modules", ".bin", "tsx");
|
|
6488
|
+
const script = path15.join(packageRoot, "src", "scripts", "hooks", "dispatch_hook.ts");
|
|
6489
|
+
if (fs15.existsSync(localTsx)) {
|
|
5898
6490
|
return [localTsx, script];
|
|
5899
6491
|
}
|
|
5900
6492
|
return ["npx", "tsx", script];
|
|
@@ -5911,7 +6503,7 @@ function _check_hook_dispatcher(projectRoot, packageRoot = PACKAGE_ROOT, opts =
|
|
|
5911
6503
|
...event === "stop" ? { stop_reason: "conformance-smoke" } : { source: "startup" }
|
|
5912
6504
|
});
|
|
5913
6505
|
const argv = [...runner, "--platform", platform, "--event", event];
|
|
5914
|
-
const proc =
|
|
6506
|
+
const proc = spawnSync4(argv[0], argv.slice(1), {
|
|
5915
6507
|
input: payload,
|
|
5916
6508
|
cwd: projectRoot,
|
|
5917
6509
|
encoding: "utf8",
|
|
@@ -5944,12 +6536,12 @@ function _check_hook_dispatcher(projectRoot, packageRoot = PACKAGE_ROOT, opts =
|
|
|
5944
6536
|
};
|
|
5945
6537
|
}
|
|
5946
6538
|
function readSettingsMode(projectRoot) {
|
|
5947
|
-
const settingsPath =
|
|
5948
|
-
if (!
|
|
6539
|
+
const settingsPath = path15.join(projectRoot, ".agent-settings.yml");
|
|
6540
|
+
if (!fs15.existsSync(settingsPath)) {
|
|
5949
6541
|
return "eager-all";
|
|
5950
6542
|
}
|
|
5951
6543
|
try {
|
|
5952
|
-
const parsed = YAML.parse(
|
|
6544
|
+
const parsed = YAML.parse(fs15.readFileSync(settingsPath, "utf8"));
|
|
5953
6545
|
const lean = parsed?.["lean_projection"] ?? null;
|
|
5954
6546
|
const mode = lean?.["mode"];
|
|
5955
6547
|
return typeof mode === "string" && mode.length > 0 ? mode : "eager-all";
|
|
@@ -5960,7 +6552,7 @@ function readSettingsMode(projectRoot) {
|
|
|
5960
6552
|
function kernelIdsFromRouter(packageRoot) {
|
|
5961
6553
|
try {
|
|
5962
6554
|
const router = JSON.parse(
|
|
5963
|
-
|
|
6555
|
+
fs15.readFileSync(path15.join(packageRoot, "dist", "router.json"), "utf8")
|
|
5964
6556
|
);
|
|
5965
6557
|
return new Set((router["kernel"] ?? []).map(String));
|
|
5966
6558
|
} catch {
|
|
@@ -5977,8 +6569,8 @@ function _check_lean_projection(projectRoot, packageRoot = PACKAGE_ROOT, project
|
|
|
5977
6569
|
remedy: "set lean_projection.mode to 'eager-all' or 'thin' in .agent-settings.yml"
|
|
5978
6570
|
};
|
|
5979
6571
|
}
|
|
5980
|
-
const rulesDir = projectedRulesDir ??
|
|
5981
|
-
if (!
|
|
6572
|
+
const rulesDir = projectedRulesDir ?? path15.join(projectRoot, ".augment", "rules");
|
|
6573
|
+
if (!fs15.existsSync(rulesDir)) {
|
|
5982
6574
|
return {
|
|
5983
6575
|
id: "lean-projection",
|
|
5984
6576
|
status: "skipped",
|
|
@@ -5987,7 +6579,7 @@ function _check_lean_projection(projectRoot, packageRoot = PACKAGE_ROOT, project
|
|
|
5987
6579
|
};
|
|
5988
6580
|
}
|
|
5989
6581
|
const kernel = kernelIdsFromRouter(packageRoot);
|
|
5990
|
-
const files =
|
|
6582
|
+
const files = fs15.readdirSync(rulesDir).filter((f) => f.endsWith(".md") && f !== "INDEX.md").sort();
|
|
5991
6583
|
const nonKernel = files.filter((f) => !kernel.has(f.replace(/\.md$/, "")));
|
|
5992
6584
|
if (nonKernel.length === 0) {
|
|
5993
6585
|
return {
|
|
@@ -6001,7 +6593,7 @@ function _check_lean_projection(projectRoot, packageRoot = PACKAGE_ROOT, project
|
|
|
6001
6593
|
for (const f of nonKernel) {
|
|
6002
6594
|
let text = "";
|
|
6003
6595
|
try {
|
|
6004
|
-
text =
|
|
6596
|
+
text = fs15.readFileSync(path15.join(rulesDir, f), "utf8");
|
|
6005
6597
|
} catch {
|
|
6006
6598
|
continue;
|
|
6007
6599
|
}
|
|
@@ -6032,8 +6624,8 @@ function _check_lean_projection(projectRoot, packageRoot = PACKAGE_ROOT, project
|
|
|
6032
6624
|
function _check_host_manifest(projectRoot) {
|
|
6033
6625
|
const detected = Object.entries(detectToolPresence(projectRoot)).filter(([, v]) => v === true).map(([k]) => k);
|
|
6034
6626
|
const detectedNote = detected.length > 0 ? `detected surfaces: ${detected.join(", ")}` : "no surfaces detected";
|
|
6035
|
-
const settingsPath =
|
|
6036
|
-
if (!
|
|
6627
|
+
const settingsPath = path15.join(projectRoot, ".agent-settings.yml");
|
|
6628
|
+
if (!fs15.existsSync(settingsPath)) {
|
|
6037
6629
|
return {
|
|
6038
6630
|
id: "host-manifest",
|
|
6039
6631
|
status: "ok",
|
|
@@ -6043,7 +6635,7 @@ function _check_host_manifest(projectRoot) {
|
|
|
6043
6635
|
}
|
|
6044
6636
|
let parsed = null;
|
|
6045
6637
|
try {
|
|
6046
|
-
parsed = YAML.parse(
|
|
6638
|
+
parsed = YAML.parse(fs15.readFileSync(settingsPath, "utf8"));
|
|
6047
6639
|
} catch (exc) {
|
|
6048
6640
|
return {
|
|
6049
6641
|
id: "host-manifest",
|
|
@@ -6073,7 +6665,7 @@ function runConformanceChecks(opts = {}) {
|
|
|
6073
6665
|
const projectRoot = opts.projectRoot ?? process5.cwd();
|
|
6074
6666
|
const packageRoot = opts.packageRoot ?? PACKAGE_ROOT;
|
|
6075
6667
|
const checks = [];
|
|
6076
|
-
checks.push(_check_txlog_clean());
|
|
6668
|
+
checks.push(_check_txlog_clean(installLogPath(), projectRoot));
|
|
6077
6669
|
checks.push(_check_router_pointers(packageRoot));
|
|
6078
6670
|
if (opts.skipDispatcher === true) {
|
|
6079
6671
|
checks.push({
|
|
@@ -6104,14 +6696,14 @@ function appendConformanceReport(checks, projectRoot, logPath = conformanceLogPa
|
|
|
6104
6696
|
} catch {
|
|
6105
6697
|
}
|
|
6106
6698
|
}
|
|
6107
|
-
var
|
|
6699
|
+
var USAGE3 = "usage: agent-config conformance [-h] [--project PROJECT] [--json]\n [--skip-dispatcher] [--funnel]\n";
|
|
6108
6700
|
function _parse(argv) {
|
|
6109
6701
|
const opts = { project: null, json: false, skip_dispatcher: false, funnel: false };
|
|
6110
6702
|
let i = 0;
|
|
6111
6703
|
while (i < argv.length) {
|
|
6112
6704
|
const a = argv[i];
|
|
6113
6705
|
if (a === "-h" || a === "--help") {
|
|
6114
|
-
process5.stdout.write(
|
|
6706
|
+
process5.stdout.write(USAGE3);
|
|
6115
6707
|
throw new ArgparseExit(0);
|
|
6116
6708
|
}
|
|
6117
6709
|
if (a === "--json") {
|
|
@@ -6125,7 +6717,7 @@ function _parse(argv) {
|
|
|
6125
6717
|
opts.project = a.slice(a.indexOf("=") + 1);
|
|
6126
6718
|
} else {
|
|
6127
6719
|
if (i + 1 >= argv.length) {
|
|
6128
|
-
process5.stderr.write(
|
|
6720
|
+
process5.stderr.write(USAGE3);
|
|
6129
6721
|
process5.stderr.write("agent-config conformance: error: --project expects a value\n");
|
|
6130
6722
|
throw new ArgparseExit(2);
|
|
6131
6723
|
}
|
|
@@ -6133,7 +6725,7 @@ function _parse(argv) {
|
|
|
6133
6725
|
i += 1;
|
|
6134
6726
|
}
|
|
6135
6727
|
} else {
|
|
6136
|
-
process5.stderr.write(
|
|
6728
|
+
process5.stderr.write(USAGE3);
|
|
6137
6729
|
process5.stderr.write(`agent-config conformance: error: unrecognized argument ${a}
|
|
6138
6730
|
`);
|
|
6139
6731
|
throw new ArgparseExit(2);
|
|
@@ -6142,7 +6734,7 @@ function _parse(argv) {
|
|
|
6142
6734
|
}
|
|
6143
6735
|
return opts;
|
|
6144
6736
|
}
|
|
6145
|
-
function
|
|
6737
|
+
function main14(argv = null) {
|
|
6146
6738
|
const opts = _parse(argv !== null ? Array.from(argv) : process5.argv.slice(2));
|
|
6147
6739
|
if (opts.funnel) {
|
|
6148
6740
|
print(render5(buildFunnel()));
|
|
@@ -6197,7 +6789,7 @@ function main13(argv = null) {
|
|
|
6197
6789
|
print(` \u{1F4CD} project_root: ${project_root}`);
|
|
6198
6790
|
print("conformance:");
|
|
6199
6791
|
for (const c of allChecks) {
|
|
6200
|
-
const sym =
|
|
6792
|
+
const sym = CONFORMANCE_STATUS_SYMBOLS[c["status"]] ?? "?";
|
|
6201
6793
|
print(` ${sym} ${c["id"]}: ${c["message"]}`);
|
|
6202
6794
|
if (c["status"] !== "ok" && c["remedy"]) {
|
|
6203
6795
|
print(` fix: ${c["remedy"]}`);
|
|
@@ -6213,25 +6805,25 @@ function main13(argv = null) {
|
|
|
6213
6805
|
}
|
|
6214
6806
|
return failed ? 1 : 0;
|
|
6215
6807
|
}
|
|
6216
|
-
function
|
|
6808
|
+
function _isCliEntry13() {
|
|
6217
6809
|
if (process5.argv[1] === void 0) {
|
|
6218
6810
|
return false;
|
|
6219
6811
|
}
|
|
6220
|
-
const argvUrl =
|
|
6812
|
+
const argvUrl = pathToFileURL14(path15.resolve(process5.argv[1])).href;
|
|
6221
6813
|
if (import.meta.url === argvUrl) {
|
|
6222
6814
|
return true;
|
|
6223
6815
|
}
|
|
6224
6816
|
try {
|
|
6225
|
-
const here =
|
|
6226
|
-
const argv =
|
|
6817
|
+
const here = fs15.realpathSync(fileURLToPath14(import.meta.url));
|
|
6818
|
+
const argv = fs15.realpathSync(path15.resolve(process5.argv[1]));
|
|
6227
6819
|
return here === argv;
|
|
6228
6820
|
} catch {
|
|
6229
6821
|
return false;
|
|
6230
6822
|
}
|
|
6231
6823
|
}
|
|
6232
|
-
if (
|
|
6824
|
+
if (_isCliEntry13() || process5.argv[1] === _HERE6) {
|
|
6233
6825
|
try {
|
|
6234
|
-
process5.exitCode =
|
|
6826
|
+
process5.exitCode = main14(process5.argv.slice(2));
|
|
6235
6827
|
} catch (e) {
|
|
6236
6828
|
if (e instanceof ArgparseExit) {
|
|
6237
6829
|
process5.exitCode = e.code;
|
|
@@ -6249,12 +6841,13 @@ export {
|
|
|
6249
6841
|
_check_lean_projection,
|
|
6250
6842
|
_check_router_pointers,
|
|
6251
6843
|
_check_txlog_clean,
|
|
6844
|
+
_installLogExpected,
|
|
6252
6845
|
_parse,
|
|
6253
6846
|
appendConformanceReport,
|
|
6254
6847
|
conformanceLogPath,
|
|
6255
6848
|
detectSmokePlatform,
|
|
6256
6849
|
installLogPath,
|
|
6257
|
-
|
|
6850
|
+
main14 as main,
|
|
6258
6851
|
routeTargetPaths,
|
|
6259
6852
|
runConformanceChecks
|
|
6260
6853
|
};
|