@event4u/agent-config 14.21.0 → 14.23.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 +164 -187
- package/CREDITS.md +37 -0
- package/README.md +1 -1
- package/dist/agent-src/commands/analyze/inbox.md +380 -5
- package/dist/agent-src/commands/analyze/repo.md +4 -2
- package/dist/agent-src/commands/pr/merge.md +47 -38
- package/dist/agent-src/commands/roadmap/next.md +8 -0
- package/dist/agent-src/contexts/communication/rules-auto/token-efficiency-mechanics.md +69 -0
- package/dist/agent-src/contexts/execution/auto-dispatch-classification.md +5 -5
- package/dist/agent-src/contexts/execution/autonomy-mechanics.md +12 -0
- package/dist/agent-src/rules/external-code-graph-interop.md +19 -14
- package/dist/agent-src/rules/notes-first-reasoning.md +36 -25
- package/dist/agent-src/rules/token-efficiency.md +26 -3
- package/dist/agent-src/scripts/_cli_entry.ts +51 -0
- package/dist/agent-src/scripts/archive_completed_roadmaps.ts +120 -27
- package/dist/agent-src/scripts/roadmap_gates.ts +4 -20
- package/dist/agent-src/scripts/roadmap_set_step.ts +5 -2
- package/dist/agent-src/scripts/stubs_due.ts +4 -18
- package/dist/agent-src/scripts/update_roadmap_progress.ts +7 -24
- package/dist/agent-src/skills/code-intelligence/SKILL.md +82 -1
- package/dist/agent-src/skills/git-workflow/references/push-closes-its-loop.md +9 -0
- package/dist/agent-src/skills/roadmap-writing/SKILL.md +17 -0
- package/dist/agent-src/skills/tailwind-engineer/SKILL.md +52 -2
- package/dist/agent-src/templates/agent-settings.md +0 -1
- package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
- package/dist/cli/registry.js +1 -1
- package/dist/cli-delegate/_cli_entry.js +8 -0
- package/dist/cli-delegate/_lib/pin_resolver.js +170 -0
- package/dist/cli-delegate/archival_sweep.js +8 -0
- package/dist/cli-delegate/archive_completed_roadmaps.js +542 -0
- package/dist/cli-delegate/check_update_banner.js +923 -0
- package/dist/cli-delegate/{chunk-ZVBOHSVF.js → chunk-2KKXJW25.js} +23 -9
- package/dist/cli-delegate/chunk-5EK5WQN6.js +28 -0
- package/dist/cli-delegate/chunk-7XGD2OEU.js +96 -0
- package/dist/cli-delegate/chunk-DBH4AHDK.js +155 -0
- package/dist/cli-delegate/{chunk-4FS4WRXP.js → chunk-IAI3XL43.js} +15 -3
- package/dist/cli-delegate/chunk-JO25G5H7.js +20 -0
- package/dist/cli-delegate/{chunk-643Z7FIC.js → chunk-KCNTUSPI.js} +7 -1
- package/dist/cli-delegate/chunk-LTYVIY76.js +7961 -0
- package/dist/cli-delegate/chunk-QAJS5YWY.js +999 -0
- package/dist/cli-delegate/{chunk-YS6XTLEK.js → chunk-TYSY33MD.js} +56 -6
- package/dist/cli-delegate/chunk-ULET4BYS.js +328 -0
- package/dist/cli-delegate/chunk-YDQSHTD7.js +187 -0
- package/dist/cli-delegate/chunk-YWVXLR44.js +48 -0
- package/dist/cli-delegate/chunk-ZZQBUHFK.js +273 -0
- package/dist/cli-delegate/cmd_conformance.js +2 -2
- package/dist/cli-delegate/cmd_export.js +2 -2
- package/dist/cli-delegate/cmd_handoff.js +45 -13
- package/dist/cli-delegate/cmd_prune.js +2 -2
- package/dist/cli-delegate/cmd_session_recycle.js +4 -14
- package/dist/cli-delegate/cmd_settings_migrate.js +2 -2
- package/dist/cli-delegate/cmd_settings_set.js +1 -1
- package/dist/cli-delegate/cmd_sync.js +2 -2
- package/dist/cli-delegate/cmd_uninstall.js +2 -2
- package/dist/cli-delegate/cmd_validate.js +2 -2
- package/dist/cli-delegate/dashboard_mode.js +16 -0
- package/dist/cli-delegate/gate_budget.js +24 -0
- package/dist/cli-delegate/gate_execute.js +25 -0
- package/dist/cli-delegate/guarded_baseline.js +18 -0
- package/dist/cli-delegate/resume_probe.js +22 -0
- package/dist/cli-delegate/roadmap_gates.js +638 -0
- package/dist/cli-delegate/roadmap_set_step.js +173 -0
- package/dist/cli-delegate/stub_queue.js +47 -0
- package/dist/cli-delegate/stubs_due.js +38 -0
- package/dist/cli-delegate/ticket_bundles.js +59 -0
- package/dist/cli-delegate/update_roadmap_progress.js +60 -0
- package/dist/discovery/deprecation-report.md +1 -1
- package/dist/discovery/discovery-manifest.json +13 -13
- package/dist/discovery/discovery-manifest.json.sha256 +1 -1
- package/dist/discovery/discovery-manifest.summary.md +1 -1
- package/dist/discovery/dormancy-report.md +1 -1
- package/dist/discovery/orphan-report.md +1 -1
- package/dist/discovery/packs.json +2 -2
- package/dist/discovery/trust-report.md +1 -1
- package/dist/discovery/workspaces.json +2 -2
- package/dist/hooks/dispatch.js +1813 -946
- package/dist/install/claudeLayerCarriage.js +237 -0
- package/dist/install/claudePathsPlan.js +79 -0
- package/dist/install/hostLayerFingerprint.js +1 -1
- package/dist/install/install.mjs +21 -3
- package/dist/install/partitionEligibility.js +231 -117
- package/dist/install/ruleLayerPartition.js +10 -7
- package/dist/mcp/registry-manifest.json +2 -2
- package/dist/mcp/server.json +2 -2
- package/dist/mcp/server.mjs +10870 -7641
- package/dist/scripts/_lib/lean_projection_mode.js +108 -0
- package/dist/scripts/_lib/router_match.js +243 -0
- package/dist/scripts/_lib/rule_injection.js +216 -0
- package/dist/scripts/condense.js +52 -45
- package/dist/scripts/project_thin_rules.js +139 -19
- package/dist/server/schemas/settings.js +16 -3
- package/docs/MIGRATION.md +105 -1
- package/docs/contracts/settings-classes.md +40 -8
- package/docs/guidelines/agent-infra/minimal-safe-diff-mechanics.md +73 -0
- package/docs/guidelines/agent-infra/notes-horizon-mechanics.md +90 -0
- package/llms.txt +1 -1
- package/package.json +7 -4
- package/src/agent-src/scripts/_cli_entry.ts +51 -0
- package/src/agent-src/scripts/archive_completed_roadmaps.ts +120 -27
- package/src/agent-src/scripts/roadmap_gates.ts +4 -20
- package/src/agent-src/scripts/roadmap_set_step.ts +5 -2
- package/src/agent-src/scripts/stubs_due.ts +4 -18
- package/src/agent-src/scripts/update_roadmap_progress.ts +7 -24
- package/src/config/agent-settings.template.yml +47 -1
- package/src/config/continuity-surface.json +516 -0
- package/src/config/estate-count-budget.json +1 -1
- package/src/config/evaluator-budgets.json +4 -4
- package/src/config/gate-coverage.yml +29 -8
- package/src/config/gate-violation-baselines.json +8 -8
- package/src/config/gitignore-block.txt +19 -0
- package/src/config/hook-token-budget.json +7 -6
- package/src/config/host-injection-effect.json +73 -0
- package/src/config/packed-binary-manifest.json +33 -0
- package/src/config/preamble-payload-budget.json +112 -105
- package/src/config/publish-surface.json +4 -2
- package/src/config/routing-coverage-seed.json +9 -2
- package/src/install/claudeLayerCarriage.ts +273 -0
- package/src/install/claudePathsPlan.ts +76 -0
- package/src/install/hostLayerFingerprint.ts +1 -1
- package/src/install/partitionEligibility.ts +261 -127
- package/src/install/ruleLayerPartition.ts +19 -23
- package/src/scripts/_cli/cmd_session_recycle.ts +2 -25
- package/src/scripts/_cli/handoff_sessions.ts +14 -44
- package/src/scripts/_dispatch.bash +77 -27
- package/src/scripts/_lib/auto_dispatch.ts +2 -2
- package/src/scripts/_lib/catalogue_layer_parity.ts +146 -0
- package/src/scripts/_lib/continuity_slot.ts +295 -0
- package/src/scripts/_lib/continuity_surface.ts +296 -0
- package/src/scripts/_lib/continuity_writer.ts +253 -0
- package/src/scripts/_lib/corpus_manifest.ts +26 -9
- package/src/scripts/_lib/hook_settings.ts +86 -1
- package/src/scripts/_lib/injection_effect.ts +151 -0
- package/src/scripts/_lib/layer_overlap_notice.ts +50 -6
- package/src/scripts/_lib/lean_projection_mode.ts +127 -0
- package/src/scripts/_lib/packed_binary_predicate.ts +262 -0
- package/src/scripts/_lib/pin_resolver.ts +13 -0
- package/src/scripts/_lib/recycle_envelope_paths.ts +109 -21
- package/src/scripts/_lib/regression_neighbourhood.ts +159 -22
- package/src/scripts/_lib/retired_status.ts +74 -0
- package/src/scripts/_lib/session_eol.ts +44 -0
- package/src/scripts/_lib/session_index_trust.ts +346 -0
- package/src/scripts/_lib/skill_catalogue.ts +156 -21
- package/src/scripts/_lib/standing_bound_ratchet.ts +154 -0
- package/src/scripts/_lib/subagent_capsule.ts +117 -8
- package/src/scripts/_lib/vendored_grammar_upstream.ts +280 -0
- package/src/scripts/ai_council/api_transport.ts +5 -0
- package/src/scripts/ai_council/deliberation_metrics.ts +353 -0
- package/src/scripts/ai_council/prompts.ts +9 -0
- package/src/scripts/ai_council/synthesis_disagreement.ts +206 -0
- package/src/scripts/audit_mcp_tools.ts +69 -25
- package/src/scripts/build_mcp_catalog.ts +24 -1
- package/src/scripts/capture_skill_catalogue.ts +24 -11
- package/src/scripts/check_candidate_lines.ts +499 -0
- package/src/scripts/check_continuity_surface.ts +475 -0
- package/src/scripts/check_dependency_floors.ts +13 -6
- package/src/scripts/check_estate_count.ts +40 -79
- package/src/scripts/check_host_tree_parity.ts +291 -0
- package/src/scripts/check_pack_size.ts +262 -23
- package/src/scripts/check_preamble_payload_budget.ts +136 -7
- package/src/scripts/check_roadmap_trackable.ts +19 -16
- package/src/scripts/check_rule_layer_partition.ts +54 -34
- package/src/scripts/check_rule_projection_integrity.ts +102 -2
- package/src/scripts/check_single_delivery.ts +97 -31
- package/src/scripts/check_update_banner.ts +13 -0
- package/src/scripts/ci_settle.ts +205 -5
- package/src/scripts/code_graph/build.ts +217 -15
- package/src/scripts/code_graph/cli.ts +334 -15
- package/src/scripts/code_graph/detect.ts +38 -0
- package/src/scripts/code_graph/extract.ts +11 -0
- package/src/scripts/code_graph/grammar_probe.ts +43 -0
- package/src/scripts/code_graph/loader.ts +88 -14
- package/src/scripts/code_graph/query.ts +144 -11
- package/src/scripts/code_graph/resolution_tiers.ts +238 -0
- package/src/scripts/code_graph/sqlite_store.ts +262 -6
- package/src/scripts/code_graph/types.ts +117 -3
- package/src/scripts/code_graph/validate.ts +26 -1
- package/src/scripts/code_graph/verbs.ts +590 -0
- package/src/scripts/condense.ts +54 -42
- package/src/scripts/corpus_manifest.ts +5 -5
- package/src/scripts/council_cli.ts +11 -12
- package/src/scripts/count_intent_disagreement.ts +426 -0
- package/src/scripts/handoff_context_hook.ts +118 -1
- package/src/scripts/hook_effect_doctor.ts +82 -1
- package/src/scripts/hook_manifest.json +1 -1
- package/src/scripts/hook_manifest.yaml +87 -12
- package/src/scripts/hooks/block_speaking_inbox_dir.ts +182 -16
- package/src/scripts/hooks/chain_nudge_hook.ts +282 -0
- package/src/scripts/hooks/code_graph_context_hook.ts +201 -0
- package/src/scripts/hooks/concern_registry.ts +4 -2
- package/src/scripts/hooks/host_semantics.ts +1 -1
- package/src/scripts/hooks/orchestration_record_hook.ts +2 -2
- package/src/scripts/hooks/push_settle_hook.ts +3 -2
- package/src/scripts/hooks/rule_inject_hook.ts +108 -21
- package/src/scripts/hooks/session_eol_hook.ts +120 -2
- package/src/scripts/hooks/skill_route_hook.ts +11 -4
- package/src/scripts/hot_context_hook.ts +62 -7
- package/src/scripts/inbox_source_census.ts +322 -0
- package/src/scripts/install-hooks.sh +82 -0
- package/src/scripts/{lint_carrier_integrity.ts → lint_deferral_integrity.ts} +60 -214
- package/src/scripts/lint_plan_risk_register.ts +13 -17
- package/src/scripts/lint_roadmap_blockers.ts +164 -1
- package/src/scripts/mcp_server/consumer_tool_catalog.json +152 -2
- package/src/scripts/mcp_server/graph_tools.ts +294 -0
- package/src/scripts/mcp_server/path_util.ts +31 -0
- package/src/scripts/mcp_server/suggest_skill.ts +72 -0
- package/src/scripts/mcp_server/tool_catalog_source.ts +7 -1
- package/src/scripts/mcp_server/tools.ts +5 -69
- package/src/scripts/media/lib/adapter-contract.md +7 -2
- package/src/scripts/media/lib/fixtures/flux/asset-0001.png +0 -0
- package/src/scripts/media/lib/fixtures/gemini-image/asset-0001.png +0 -0
- package/src/scripts/media/lib/fixtures/ideogram/asset-0001.png +0 -0
- package/src/scripts/model_rule_injection.ts +61 -4
- package/src/scripts/project_thin_rules.ts +149 -16
- package/src/scripts/rdp_candidates_delta.ts +276 -0
- package/src/scripts/rdp_quality_eval.ts +217 -19
- package/src/scripts/release_mix_taxonomy.json +3 -2
- package/src/scripts/report_host_injection_effect.ts +189 -0
- package/src/scripts/report_layer_overlap.ts +41 -0
- package/src/scripts/report_skill_menu_census.ts +341 -0
- package/src/scripts/report_standing_payload_by_host.ts +650 -0
- package/src/scripts/schemas/agent-settings.schema.json +7 -1
- package/src/scripts/session_memory_index.ts +81 -8
- package/src/scripts/skill_tools/score_skill_relevance.ts +70 -6
- package/src/scripts/skill_tools/suggest_skill_for_task.ts +37 -3
- package/src/server/schemas/settings.ts +23 -4
- package/src/vendor/grammars/README.md +86 -0
- package/src/vendor/grammars/tree-sitter-javascript.wasm +0 -0
- package/src/vendor/grammars/tree-sitter-php.wasm +0 -0
- package/src/vendor/grammars/tree-sitter-typescript.wasm +0 -0
- package/src/scripts/_lib/carrier_status.ts +0 -118
- package/src/scripts/_lib/estate_carrier_cases.ts +0 -72
- package/src/scripts/hooks/code_graph_nudge_hook.ts +0 -191
|
@@ -224,6 +224,31 @@ var MAX_LINE_CHARS = 240;
|
|
|
224
224
|
var MAX_ENTRIES = 40;
|
|
225
225
|
var CAPSULE_SCHEMA_VERSION = 4;
|
|
226
226
|
var ACCEPTED_CAPSULE_VERSIONS = [3, 4];
|
|
227
|
+
var CAPSULE_VARIANTS = ["worker", "main_session", "continuity_record"];
|
|
228
|
+
var CONTINUITY_RECORD_FORBIDDEN_KEYS = /* @__PURE__ */ new Set([
|
|
229
|
+
"decisions",
|
|
230
|
+
"constraints",
|
|
231
|
+
"do_not_touch",
|
|
232
|
+
"assumptions",
|
|
233
|
+
"failed_approaches",
|
|
234
|
+
"successful_approaches",
|
|
235
|
+
"open_questions",
|
|
236
|
+
"not_carried_forward",
|
|
237
|
+
"status_summary",
|
|
238
|
+
"suggested_skills",
|
|
239
|
+
"open_worker_envelopes"
|
|
240
|
+
]);
|
|
241
|
+
var CONTINUITY_RECORD_REQUIRED_KEYS = [
|
|
242
|
+
"capsule_version",
|
|
243
|
+
"variant",
|
|
244
|
+
"summary",
|
|
245
|
+
"task",
|
|
246
|
+
"workspace",
|
|
247
|
+
"written_at",
|
|
248
|
+
"acceptance_criteria",
|
|
249
|
+
"remaining",
|
|
250
|
+
"predecessor"
|
|
251
|
+
];
|
|
227
252
|
function isShortLine(value, max) {
|
|
228
253
|
return typeof value === "string" && value.length > 0 && value.length <= max && !value.includes("\n");
|
|
229
254
|
}
|
|
@@ -406,13 +431,38 @@ function validateRecycleEnvelope(input) {
|
|
|
406
431
|
);
|
|
407
432
|
}
|
|
408
433
|
}
|
|
434
|
+
const variant = e["variant"];
|
|
435
|
+
if (typeof variant !== "string" || !CAPSULE_VARIANTS.includes(variant)) {
|
|
436
|
+
return [
|
|
437
|
+
`unknown variant ${JSON.stringify(variant)} \u2014 this reader knows ${CAPSULE_VARIANTS.join(" | ")}. A reader that does not know a variant must not guess at its required fields, so no further field checks were run.`
|
|
438
|
+
];
|
|
439
|
+
}
|
|
440
|
+
if (variant === "worker") {
|
|
441
|
+
return [
|
|
442
|
+
"variant 'worker' is a subagent generation handover and is validated by the worker path, not by the main-session recycle validator \u2014 routing it here would apply the wrong required set to a well-formed record."
|
|
443
|
+
];
|
|
444
|
+
}
|
|
445
|
+
const isDerived = variant === "continuity_record";
|
|
409
446
|
const version = e["capsule_version"];
|
|
410
447
|
if (typeof version !== "number" || !ACCEPTED_CAPSULE_VERSIONS.includes(version)) {
|
|
411
448
|
errors.push(`capsule_version must be one of ${ACCEPTED_CAPSULE_VERSIONS.join(" | ")}`);
|
|
412
449
|
}
|
|
413
|
-
const atV4 = version === 4;
|
|
414
|
-
if (
|
|
415
|
-
|
|
450
|
+
const atV4 = version === 4 && !isDerived;
|
|
451
|
+
if (isDerived) {
|
|
452
|
+
for (const key of Object.keys(e)) {
|
|
453
|
+
if (CONTINUITY_RECORD_FORBIDDEN_KEYS.has(key)) {
|
|
454
|
+
errors.push(
|
|
455
|
+
`field "${key}" is forbidden on variant 'continuity_record' \u2014 it carries a model judgement, and a record written without model spend cannot have made one. Use variant 'main_session' for a judged record.`
|
|
456
|
+
);
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
for (const key of CONTINUITY_RECORD_REQUIRED_KEYS) {
|
|
460
|
+
if (e[key] === void 0) {
|
|
461
|
+
errors.push(
|
|
462
|
+
`field "${key}" is required on variant 'continuity_record' \u2014 it is computable from on-disk state, so its absence is a writer defect rather than an unavailable judgement.`
|
|
463
|
+
);
|
|
464
|
+
}
|
|
465
|
+
}
|
|
416
466
|
}
|
|
417
467
|
if (!isShortLine(e["summary"], MAX_LINE_CHARS)) {
|
|
418
468
|
errors.push(`summary must be a single line of 1\u2013${MAX_LINE_CHARS} chars`);
|
|
@@ -432,7 +482,7 @@ function validateRecycleEnvelope(input) {
|
|
|
432
482
|
errors.push('acceptance_criteria must carry at least one entry \u2014 the successor cannot know "done" without it');
|
|
433
483
|
}
|
|
434
484
|
checkList(errors, "remaining", e["remaining"], MAX_LINE_CHARS, true);
|
|
435
|
-
checkList(errors, "not_carried_forward", e["not_carried_forward"], MAX_LINE_CHARS,
|
|
485
|
+
checkList(errors, "not_carried_forward", e["not_carried_forward"], MAX_LINE_CHARS, !isDerived);
|
|
436
486
|
checkList(errors, "decisions", e["decisions"], MAX_LINE_CHARS, false);
|
|
437
487
|
errors.push(...decisionTagErrors(e["decisions"]));
|
|
438
488
|
checkList(errors, "constraints", e["constraints"], MAX_LINE_CHARS, false);
|
|
@@ -443,7 +493,7 @@ function validateRecycleEnvelope(input) {
|
|
|
443
493
|
if (e["next_task"] !== void 0 && !isShortLine(e["next_task"], MAX_LINE_CHARS)) {
|
|
444
494
|
errors.push(`next_task must be a single line of 1\u2013${MAX_LINE_CHARS} chars`);
|
|
445
495
|
}
|
|
446
|
-
checkList(errors, "failed_approaches", e["failed_approaches"], MAX_LINE_CHARS,
|
|
496
|
+
checkList(errors, "failed_approaches", e["failed_approaches"], MAX_LINE_CHARS, !isDerived);
|
|
447
497
|
if (Array.isArray(e["failed_approaches"]) && e["failed_approaches"].length === 0) {
|
|
448
498
|
errors.push(
|
|
449
499
|
'failed_approaches must carry at least one entry \u2014 write "none" explicitly, so silence and "nothing was abandoned" stay distinguishable'
|
|
@@ -458,7 +508,7 @@ function validateRecycleEnvelope(input) {
|
|
|
458
508
|
checkList(errors, "open_questions", e["open_questions"], MAX_LINE_CHARS, false);
|
|
459
509
|
const predecessor = e["predecessor"];
|
|
460
510
|
if (predecessor === void 0) {
|
|
461
|
-
if (atV4) {
|
|
511
|
+
if (atV4 || isDerived) {
|
|
462
512
|
errors.push(
|
|
463
513
|
'predecessor is required \u2014 name the session this one continues, or write "none" explicitly for the first session in a workspace'
|
|
464
514
|
);
|
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
import { createRequire as __acCreateRequire } from 'node:module'; const require = globalThis.require ?? __acCreateRequire(import.meta.url);
|
|
2
|
+
import {
|
|
3
|
+
isCliEntry
|
|
4
|
+
} from "./chunk-5EK5WQN6.js";
|
|
5
|
+
|
|
6
|
+
// src/agent-src/scripts/stubs_due.ts
|
|
7
|
+
import * as fs from "node:fs";
|
|
8
|
+
import * as path from "node:path";
|
|
9
|
+
import { fileURLToPath } from "node:url";
|
|
10
|
+
var STUB_DIR = path.join("agents", "roadmaps", "stubs");
|
|
11
|
+
var CADENCE_DAYS = { transfer: 30, orgmode: 120 };
|
|
12
|
+
var TRANSFER_MARKER = "drain-run transfer";
|
|
13
|
+
var _HERE = path.resolve(fileURLToPath(import.meta.url));
|
|
14
|
+
var BLOCKED_QUICKWIN_FIELDS = ["design_validated", "capability_gap", "blocker_class"];
|
|
15
|
+
var QUICKWIN_BLOCKER_CLASSES = ["estate", "budget"];
|
|
16
|
+
function is_blocked_quickwin(design_validated, capability_gap, blocker_class) {
|
|
17
|
+
if (design_validated === null || design_validated === "") return false;
|
|
18
|
+
if (capability_gap !== "none") return false;
|
|
19
|
+
return QUICKWIN_BLOCKER_CLASSES.includes(blocker_class ?? "");
|
|
20
|
+
}
|
|
21
|
+
function _isDir(p) {
|
|
22
|
+
try {
|
|
23
|
+
return fs.statSync(p).isDirectory();
|
|
24
|
+
} catch {
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
function repo_root(start) {
|
|
29
|
+
let cur = start ?? process.cwd();
|
|
30
|
+
const chain = [cur];
|
|
31
|
+
for (; ; ) {
|
|
32
|
+
const parent = path.dirname(cur);
|
|
33
|
+
if (parent === cur) break;
|
|
34
|
+
chain.push(parent);
|
|
35
|
+
cur = parent;
|
|
36
|
+
}
|
|
37
|
+
for (const candidate of chain) {
|
|
38
|
+
if (_isDir(path.join(candidate, STUB_DIR))) {
|
|
39
|
+
return candidate;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return start ?? process.cwd();
|
|
43
|
+
}
|
|
44
|
+
function _frontmatter(text) {
|
|
45
|
+
const lines = text.split("\n");
|
|
46
|
+
if (lines[0]?.trim() !== "---") {
|
|
47
|
+
return [];
|
|
48
|
+
}
|
|
49
|
+
const out = [];
|
|
50
|
+
for (const line of lines.slice(1)) {
|
|
51
|
+
if (line.trim() === "---") {
|
|
52
|
+
return out;
|
|
53
|
+
}
|
|
54
|
+
out.push(line);
|
|
55
|
+
}
|
|
56
|
+
return [];
|
|
57
|
+
}
|
|
58
|
+
function _scalar(front, key) {
|
|
59
|
+
const prefix = `${key}:`;
|
|
60
|
+
for (const line of front) {
|
|
61
|
+
if (line.startsWith(prefix)) {
|
|
62
|
+
return line.slice(prefix.length).trim().replace(/^["']|["']$/g, "");
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
function count_owner_decisions(text) {
|
|
68
|
+
const lines = text.split("\n");
|
|
69
|
+
let n = 0;
|
|
70
|
+
for (const line of lines) {
|
|
71
|
+
if (/^#{2,4}\s+Unresolved decision\b/.test(line)) {
|
|
72
|
+
n += 1;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
let inBlocker = false;
|
|
76
|
+
let ownerIsMaintainer = false;
|
|
77
|
+
let statusOpen = false;
|
|
78
|
+
const flush = () => {
|
|
79
|
+
if (inBlocker && ownerIsMaintainer && statusOpen) {
|
|
80
|
+
n += 1;
|
|
81
|
+
}
|
|
82
|
+
inBlocker = false;
|
|
83
|
+
ownerIsMaintainer = false;
|
|
84
|
+
statusOpen = false;
|
|
85
|
+
};
|
|
86
|
+
for (const line of lines) {
|
|
87
|
+
if (/^#{2,4}\s+(blocker:|b-)/.test(line.trim()) || /^#{2,4}\s+\S+ — /.test(line)) {
|
|
88
|
+
if (/blocker:/.test(line) || /^#{2,4}\s+b-/.test(line.trim())) {
|
|
89
|
+
flush();
|
|
90
|
+
inBlocker = true;
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
if (!inBlocker) continue;
|
|
95
|
+
if (/^#{1,4}\s/.test(line)) {
|
|
96
|
+
flush();
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
if (/^-\s+\*\*Owner:\*\*\s*maintainer\b/i.test(line)) ownerIsMaintainer = true;
|
|
100
|
+
if (/^-\s+\*\*Status:\*\*\s*open\b/i.test(line)) statusOpen = true;
|
|
101
|
+
}
|
|
102
|
+
flush();
|
|
103
|
+
return n;
|
|
104
|
+
}
|
|
105
|
+
function _addDays(from, days) {
|
|
106
|
+
const d = new Date(from.getTime() + days * 864e5);
|
|
107
|
+
return d.toISOString().slice(0, 10);
|
|
108
|
+
}
|
|
109
|
+
function _parseIso(s) {
|
|
110
|
+
if (!/^\d{4}-\d{2}-\d{2}$/.test(s)) return null;
|
|
111
|
+
const d = /* @__PURE__ */ new Date(`${s}T00:00:00Z`);
|
|
112
|
+
return Number.isNaN(d.getTime()) ? null : d;
|
|
113
|
+
}
|
|
114
|
+
function scan(root, today) {
|
|
115
|
+
return scan_dir(path.join(root, STUB_DIR), today, release_dates(root));
|
|
116
|
+
}
|
|
117
|
+
var CHANGELOG_ERAS = ["CHANGELOG.md", "docs/archive/CHANGELOG-pre-14.12.0.md"];
|
|
118
|
+
var RELEASE_HEADING = /^## \[\d+\.\d+\.\d+\][^\n]*\((\d{4}-\d{2}-\d{2})\)\s*$/gm;
|
|
119
|
+
function release_dates(root) {
|
|
120
|
+
const out = [];
|
|
121
|
+
for (const rel of CHANGELOG_ERAS) {
|
|
122
|
+
let text;
|
|
123
|
+
try {
|
|
124
|
+
text = fs.readFileSync(path.join(root, rel), "utf8");
|
|
125
|
+
} catch {
|
|
126
|
+
continue;
|
|
127
|
+
}
|
|
128
|
+
for (const m of text.matchAll(RELEASE_HEADING)) {
|
|
129
|
+
if (m[1] !== void 0) out.push(m[1]);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
return out;
|
|
133
|
+
}
|
|
134
|
+
function releases_since(opened, dates) {
|
|
135
|
+
return dates.filter((d) => d > opened).length;
|
|
136
|
+
}
|
|
137
|
+
function scan_dir(base, today, releaseDates = []) {
|
|
138
|
+
if (!_isDir(base)) return [];
|
|
139
|
+
const now = _parseIso(today);
|
|
140
|
+
const out = [];
|
|
141
|
+
let names;
|
|
142
|
+
try {
|
|
143
|
+
names = fs.readdirSync(base).filter((n) => n.endsWith(".md") && n !== "README.md").sort();
|
|
144
|
+
} catch {
|
|
145
|
+
return [];
|
|
146
|
+
}
|
|
147
|
+
for (const name of names) {
|
|
148
|
+
let text;
|
|
149
|
+
try {
|
|
150
|
+
text = fs.readFileSync(path.join(base, name), "utf8");
|
|
151
|
+
} catch {
|
|
152
|
+
continue;
|
|
153
|
+
}
|
|
154
|
+
const front = _frontmatter(text);
|
|
155
|
+
const review_by = _scalar(front, "review_by");
|
|
156
|
+
const reviewed_at = _scalar(front, "reviewed_at");
|
|
157
|
+
const probeVal = _scalar(front, "probe");
|
|
158
|
+
const design_validated = _scalar(front, "design_validated");
|
|
159
|
+
const capability_gap = _scalar(front, "capability_gap");
|
|
160
|
+
const blocker_class = _scalar(front, "blocker_class");
|
|
161
|
+
const blocker_opened = _scalar(front, "blocker_opened");
|
|
162
|
+
const shape = text.includes(TRANSFER_MARKER) ? "transfer" : "orgmode";
|
|
163
|
+
let overdue = false;
|
|
164
|
+
let days_overdue = null;
|
|
165
|
+
if (review_by !== null && now !== null) {
|
|
166
|
+
const due = _parseIso(review_by);
|
|
167
|
+
if (due !== null && due.getTime() < now.getTime()) {
|
|
168
|
+
overdue = true;
|
|
169
|
+
days_overdue = Math.round((now.getTime() - due.getTime()) / 864e5);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
out.push({
|
|
173
|
+
file: `${STUB_DIR}/${name}`,
|
|
174
|
+
shape,
|
|
175
|
+
review_by,
|
|
176
|
+
reviewed_at,
|
|
177
|
+
probe_none: probeVal === "none",
|
|
178
|
+
has_probe_heading: /^#{1,4} *(Probe|Promotion)/m.test(text),
|
|
179
|
+
owner_decisions: count_owner_decisions(text),
|
|
180
|
+
overdue,
|
|
181
|
+
days_overdue,
|
|
182
|
+
design_validated,
|
|
183
|
+
capability_gap,
|
|
184
|
+
blocker_class,
|
|
185
|
+
blocker_opened,
|
|
186
|
+
releases_since_blocked: blocker_opened === null ? null : releases_since(blocker_opened, releaseDates),
|
|
187
|
+
blocked_quickwin: is_blocked_quickwin(design_validated, capability_gap, blocker_class)
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
return out;
|
|
191
|
+
}
|
|
192
|
+
function counts(records) {
|
|
193
|
+
return {
|
|
194
|
+
overdue: records.filter((r) => r.overdue).length,
|
|
195
|
+
owner_decisions: records.reduce((s, r) => s + r.owner_decisions, 0),
|
|
196
|
+
missing_review_by: records.filter((r) => r.review_by === null).length,
|
|
197
|
+
blocked_quickwin: records.filter((r) => r.blocked_quickwin).length,
|
|
198
|
+
total: records.length
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
function due_date(shape, from) {
|
|
202
|
+
const d = _parseIso(from) ?? /* @__PURE__ */ new Date();
|
|
203
|
+
return _addDays(d, CADENCE_DAYS[shape]);
|
|
204
|
+
}
|
|
205
|
+
function main(argv = process.argv.slice(2)) {
|
|
206
|
+
const asJson = argv.includes("--json");
|
|
207
|
+
const countsOnly = argv.includes("--counts");
|
|
208
|
+
const todayIdx = argv.indexOf("--today");
|
|
209
|
+
const today = todayIdx >= 0 && argv[todayIdx + 1] !== void 0 ? argv[todayIdx + 1] : (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
210
|
+
const root = repo_root();
|
|
211
|
+
const records = scan(root, today);
|
|
212
|
+
const c = counts(records);
|
|
213
|
+
if (countsOnly) {
|
|
214
|
+
process.stdout.write(`${c.overdue} ${c.owner_decisions}
|
|
215
|
+
`);
|
|
216
|
+
return 0;
|
|
217
|
+
}
|
|
218
|
+
if (asJson) {
|
|
219
|
+
process.stdout.write(`${JSON.stringify({ today, counts: c, stubs: records }, null, 2)}
|
|
220
|
+
`);
|
|
221
|
+
return 0;
|
|
222
|
+
}
|
|
223
|
+
process.stdout.write(`stubs:due \xB7 ${today} \xB7 ${c.total} stub(s) under ${STUB_DIR}/
|
|
224
|
+
|
|
225
|
+
`);
|
|
226
|
+
const overdue = records.filter((r) => r.overdue).sort((a, b) => (b.days_overdue ?? 0) - (a.days_overdue ?? 0));
|
|
227
|
+
if (overdue.length === 0) {
|
|
228
|
+
process.stdout.write(" \u2705 no stub is past its review date.\n");
|
|
229
|
+
} else {
|
|
230
|
+
process.stdout.write(` \u26A0\uFE0F ${overdue.length} overdue:
|
|
231
|
+
`);
|
|
232
|
+
for (const r of overdue) {
|
|
233
|
+
process.stdout.write(
|
|
234
|
+
` ${r.file} (${r.shape}, due ${r.review_by}, ${r.days_overdue}d late)
|
|
235
|
+
`
|
|
236
|
+
);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
if (c.missing_review_by > 0) {
|
|
240
|
+
process.stdout.write(
|
|
241
|
+
`
|
|
242
|
+
\u26A0\uFE0F ${c.missing_review_by} stub(s) carry no \`review_by:\` \u2014 see ${STUB_DIR}/README.md \xA7 Frontmatter contract:
|
|
243
|
+
`
|
|
244
|
+
);
|
|
245
|
+
for (const r of records.filter((x) => x.review_by === null)) {
|
|
246
|
+
process.stdout.write(
|
|
247
|
+
` ${r.file} (${r.shape}, suggested ${due_date(r.shape, today)})
|
|
248
|
+
`
|
|
249
|
+
);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
const withDecisions = records.filter((r) => r.owner_decisions > 0);
|
|
253
|
+
process.stdout.write(`
|
|
254
|
+
${c.owner_decisions} decision(s) routed to the owner`);
|
|
255
|
+
if (withDecisions.length === 0) {
|
|
256
|
+
process.stdout.write(".\n");
|
|
257
|
+
} else {
|
|
258
|
+
process.stdout.write(":\n");
|
|
259
|
+
for (const r of withDecisions) {
|
|
260
|
+
process.stdout.write(` ${r.file} (${r.owner_decisions})
|
|
261
|
+
`);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
const quickwins = records.filter((r) => r.blocked_quickwin);
|
|
265
|
+
if (quickwins.length > 0) {
|
|
266
|
+
process.stdout.write(
|
|
267
|
+
`
|
|
268
|
+
\u{1F513} ${quickwins.length} BLOCKED QUICK-WIN(S) \u2014 design validated, no capability gap,
|
|
269
|
+
held by an estate or budget decision rather than a product one:
|
|
270
|
+
`
|
|
271
|
+
);
|
|
272
|
+
for (const r of quickwins) {
|
|
273
|
+
const since = r.releases_since_blocked === null ? "no `blocker_opened:`" : `${String(r.releases_since_blocked)} release(s) since ${r.blocker_opened}`;
|
|
274
|
+
process.stdout.write(` ${r.file} (${r.blocker_class}, ${since})
|
|
275
|
+
`);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
const noProbe = records.filter((r) => !r.probe_none && !r.has_probe_heading);
|
|
279
|
+
if (noProbe.length > 0) {
|
|
280
|
+
process.stdout.write(
|
|
281
|
+
`
|
|
282
|
+
\u26A0\uFE0F ${noProbe.length} stub(s) name no promoting probe and do not say \`probe: none\`:
|
|
283
|
+
`
|
|
284
|
+
);
|
|
285
|
+
for (const r of noProbe) {
|
|
286
|
+
process.stdout.write(` ${r.file}
|
|
287
|
+
`);
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
process.stdout.write("\n Read-only. This command writes nothing.\n");
|
|
291
|
+
return 0;
|
|
292
|
+
}
|
|
293
|
+
if (isCliEntry(import.meta.url, "stubs_due")) {
|
|
294
|
+
process.exitCode = main();
|
|
295
|
+
}
|
|
296
|
+
function headerFragment(stubsDir, today) {
|
|
297
|
+
let overdue = 0;
|
|
298
|
+
let decisions = 0;
|
|
299
|
+
try {
|
|
300
|
+
const c = counts(scan_dir(stubsDir, today ?? (/* @__PURE__ */ new Date()).toISOString().slice(0, 10)));
|
|
301
|
+
overdue = c.overdue;
|
|
302
|
+
decisions = c.owner_decisions;
|
|
303
|
+
} catch {
|
|
304
|
+
return "";
|
|
305
|
+
}
|
|
306
|
+
if (overdue === 0 && decisions === 0) {
|
|
307
|
+
return "";
|
|
308
|
+
}
|
|
309
|
+
return ` \xB7 **${overdue}** overdue stub${overdue !== 1 ? "s" : ""}, **${decisions}** owner decision${decisions !== 1 ? "s" : ""} \u2192 \`agent-config stubs:due\``;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
export {
|
|
313
|
+
CADENCE_DAYS,
|
|
314
|
+
BLOCKED_QUICKWIN_FIELDS,
|
|
315
|
+
QUICKWIN_BLOCKER_CLASSES,
|
|
316
|
+
is_blocked_quickwin,
|
|
317
|
+
repo_root,
|
|
318
|
+
count_owner_decisions,
|
|
319
|
+
scan,
|
|
320
|
+
CHANGELOG_ERAS,
|
|
321
|
+
release_dates,
|
|
322
|
+
releases_since,
|
|
323
|
+
scan_dir,
|
|
324
|
+
counts,
|
|
325
|
+
due_date,
|
|
326
|
+
main,
|
|
327
|
+
headerFragment
|
|
328
|
+
};
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import { createRequire as __acCreateRequire } from 'node:module'; const require = globalThis.require ?? __acCreateRequire(import.meta.url);
|
|
2
|
+
|
|
3
|
+
// src/agent-src/scripts/guarded_baseline.ts
|
|
4
|
+
import * as fs from "node:fs";
|
|
5
|
+
import * as path from "node:path";
|
|
6
|
+
var GUARDED_BASELINE_RE = /<!--[ \t]*roadmap-status:[ \t]*guarded-baseline[ \t]*-->/;
|
|
7
|
+
var GUARDED_CATEGORIES = ["future-mechanism", "absence-assertion"];
|
|
8
|
+
var ANY_CHECKBOX_RE = /^[ \t]*[-*][ \t]+\[([ xX~-])\]/;
|
|
9
|
+
var SPAN_END_RE = /^[ \t]*[-*][ \t]+\[[ xX~-]\]|^#{1,6}[ \t]/;
|
|
10
|
+
var BLOCK_START_RE = /^[ \t]*guarded_baseline:[ \t]*$/;
|
|
11
|
+
var FIELD_RE = /^[ \t]*([a-z_]+):[ \t]*(.*)$/;
|
|
12
|
+
var FENCE_RE = /^[ \t]*(?:```|~~~)/;
|
|
13
|
+
var LIST_ITEM_RE = /^[ \t]*[-*][ \t]+/;
|
|
14
|
+
var INLINE_CODE_RE = /`[^`]*`/g;
|
|
15
|
+
function _label(annotatedLine, lines, i) {
|
|
16
|
+
const own = annotatedLine.replace(ANY_CHECKBOX_RE, "").replace(GUARDED_BASELINE_RE, "").replace(/\*\*/g, "").trim();
|
|
17
|
+
if (own !== "") {
|
|
18
|
+
return own;
|
|
19
|
+
}
|
|
20
|
+
for (let j = i + 1; j < lines.length; j++) {
|
|
21
|
+
const next = lines[j].trim();
|
|
22
|
+
if (next === "") {
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
if (SPAN_END_RE.test(lines[j])) {
|
|
26
|
+
break;
|
|
27
|
+
}
|
|
28
|
+
return next.replace(/\*\*/g, "").trim();
|
|
29
|
+
}
|
|
30
|
+
return "(unlabelled)";
|
|
31
|
+
}
|
|
32
|
+
function parseGuardedBaselines(text) {
|
|
33
|
+
const lines = text.split("\n");
|
|
34
|
+
const out = [];
|
|
35
|
+
let inFence = false;
|
|
36
|
+
for (let i = 0; i < lines.length; i++) {
|
|
37
|
+
const raw = lines[i];
|
|
38
|
+
if (FENCE_RE.test(raw)) {
|
|
39
|
+
inFence = !inFence;
|
|
40
|
+
}
|
|
41
|
+
if (inFence || !LIST_ITEM_RE.test(raw)) {
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
if (!GUARDED_BASELINE_RE.test(raw.replace(INLINE_CODE_RE, ""))) {
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
const box = ANY_CHECKBOX_RE.exec(raw);
|
|
48
|
+
const fields = {};
|
|
49
|
+
let hasBlock = false;
|
|
50
|
+
for (let j = i + 1; j < lines.length; j++) {
|
|
51
|
+
const line = lines[j];
|
|
52
|
+
if (SPAN_END_RE.test(line)) {
|
|
53
|
+
break;
|
|
54
|
+
}
|
|
55
|
+
if (FENCE_RE.test(line)) {
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
if (!hasBlock) {
|
|
59
|
+
hasBlock = BLOCK_START_RE.test(line);
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
const f = FIELD_RE.exec(line);
|
|
63
|
+
if (f) {
|
|
64
|
+
fields[f[1]] = f[2].trim();
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
out.push({
|
|
68
|
+
line: i + 1,
|
|
69
|
+
label: _label(raw, lines, i),
|
|
70
|
+
glyph: box ? box[1] : null,
|
|
71
|
+
hasBlock,
|
|
72
|
+
fields
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
return out;
|
|
76
|
+
}
|
|
77
|
+
function guardedBaselineProblems(items) {
|
|
78
|
+
const problems = [];
|
|
79
|
+
for (const it of items) {
|
|
80
|
+
const at = `line ${it.line} (${it.label})`;
|
|
81
|
+
if (it.glyph === null) {
|
|
82
|
+
problems.push(
|
|
83
|
+
`${at}: the guarded-baseline annotation is not on a checkbox step \u2014 it is only legal on an unchecked \`- [ ]\` line`
|
|
84
|
+
);
|
|
85
|
+
} else if (it.glyph !== " ") {
|
|
86
|
+
problems.push(
|
|
87
|
+
`${at}: the guarded-baseline annotation sits on \`[${it.glyph}]\` \u2014 the canonical checkbox stays UNCHECKED; only verification against the real mechanism permits \`[x]\``
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
if (!it.hasBlock) {
|
|
91
|
+
problems.push(`${at}: carries no adjacent \`guarded_baseline:\` evidence block`);
|
|
92
|
+
}
|
|
93
|
+
if ((it.fields["red_proof"] ?? "") === "") {
|
|
94
|
+
problems.push(
|
|
95
|
+
`${at}: records no \`red_proof\` \u2014 a baseline that has not demonstrably gone RED is an ordinary open item, not a guarded one`
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
const category = it.fields["category"] ?? "";
|
|
99
|
+
if (category === "") {
|
|
100
|
+
problems.push(
|
|
101
|
+
`${at}: records no \`category\` \u2014 one of ${GUARDED_CATEGORIES.join(", ")} is required, and absence is not defaulted`
|
|
102
|
+
);
|
|
103
|
+
} else if (!GUARDED_CATEGORIES.includes(category)) {
|
|
104
|
+
problems.push(
|
|
105
|
+
`${at}: records category \`${category}\`, which is not one of ` + GUARDED_CATEGORIES.join(", ")
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return problems;
|
|
110
|
+
}
|
|
111
|
+
function guardedBaselineStaleness(items, repo_root) {
|
|
112
|
+
const stale = [];
|
|
113
|
+
const unverifiable = [];
|
|
114
|
+
for (const it of items) {
|
|
115
|
+
const trigger = it.fields["recheck_when"] ?? "";
|
|
116
|
+
if (trigger === "") {
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
119
|
+
const tokens = trigger.split(/[\s,]+/).filter((t) => t !== "");
|
|
120
|
+
const paths = tokens.filter((t) => t.includes("/"));
|
|
121
|
+
for (const token of paths) {
|
|
122
|
+
if (fs.existsSync(path.join(repo_root, token))) {
|
|
123
|
+
stale.push(
|
|
124
|
+
`line ${it.line} (${it.label}): recheck_when \`${token}\` now exists \u2014 re-verify against the real mechanism`
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
if (paths.length > 0) {
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
for (const token of tokens) {
|
|
132
|
+
unverifiable.push(`line ${it.line} (${it.label}): recheck_when \`${token}\``);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
return { stale, unverifiable };
|
|
136
|
+
}
|
|
137
|
+
function reportGuardedBaselines(roadmaps, repo_root, write = (s) => process.stderr.write(s)) {
|
|
138
|
+
const rows = [];
|
|
139
|
+
let problems = 0;
|
|
140
|
+
for (const r of roadmaps) {
|
|
141
|
+
let items;
|
|
142
|
+
try {
|
|
143
|
+
items = parseGuardedBaselines(fs.readFileSync(r.path, { encoding: "utf-8" }));
|
|
144
|
+
} catch {
|
|
145
|
+
continue;
|
|
146
|
+
}
|
|
147
|
+
if (items.length === 0) {
|
|
148
|
+
continue;
|
|
149
|
+
}
|
|
150
|
+
const bad = guardedBaselineProblems(items);
|
|
151
|
+
const { stale, unverifiable } = guardedBaselineStaleness(items, repo_root);
|
|
152
|
+
problems += bad.length;
|
|
153
|
+
rows.push(
|
|
154
|
+
`| [${r.rel}](roadmaps/${r.rel}) | ${items.length} | ${stale.length} | ${bad.length} |`
|
|
155
|
+
);
|
|
156
|
+
write(
|
|
157
|
+
`\u{1F6E1}\uFE0F ${r.rel}: ${items.length} guarded-baseline step(s) \u2014 RED-proven, NOT complete, and blocking archival:
|
|
158
|
+
`
|
|
159
|
+
);
|
|
160
|
+
for (const it of items) {
|
|
161
|
+
write(` - ${it.label} (category ${it.fields["category"] ?? "\u2014"})
|
|
162
|
+
`);
|
|
163
|
+
}
|
|
164
|
+
for (const p of bad) write(` \u274C ${p}
|
|
165
|
+
`);
|
|
166
|
+
for (const s of stale) write(` \u26A0\uFE0F ${s}
|
|
167
|
+
`);
|
|
168
|
+
for (const u of unverifiable) write(` \xB7 not machine-checkable: ${u}
|
|
169
|
+
`);
|
|
170
|
+
}
|
|
171
|
+
if (rows.length === 0) {
|
|
172
|
+
return { section: "", problems };
|
|
173
|
+
}
|
|
174
|
+
return {
|
|
175
|
+
section: "\n## \u{1F6E1}\uFE0F Guarded baselines \u2014 RED-proven, not complete\n\nThese steps carry `<!-- roadmap-status: guarded-baseline -->`: an executable guard exists and has been shown to go RED under a named sabotage, but the acceptance criterion names a mechanism that does not exist yet. They are **not** done, they are **not** counted as done, and they **block archival** until the real mechanism is verified (council 2026-08-31, 2/2 convergent).\n\n| Roadmap | Guarded | Stale | Rejected |\n|---|---:|---:|---:|\n" + rows.join("\n") + "\n",
|
|
176
|
+
problems
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
export {
|
|
181
|
+
GUARDED_BASELINE_RE,
|
|
182
|
+
GUARDED_CATEGORIES,
|
|
183
|
+
parseGuardedBaselines,
|
|
184
|
+
guardedBaselineProblems,
|
|
185
|
+
guardedBaselineStaleness,
|
|
186
|
+
reportGuardedBaselines
|
|
187
|
+
};
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { createRequire as __acCreateRequire } from 'node:module'; const require = globalThis.require ?? __acCreateRequire(import.meta.url);
|
|
2
|
+
|
|
3
|
+
// src/agent-src/scripts/archival_sweep.ts
|
|
4
|
+
import { spawnSync } from "node:child_process";
|
|
5
|
+
import * as fs from "node:fs";
|
|
6
|
+
import * as path from "node:path";
|
|
7
|
+
import { fileURLToPath } from "node:url";
|
|
8
|
+
var _HERE = fileURLToPath(import.meta.url);
|
|
9
|
+
function _isFile(p) {
|
|
10
|
+
try {
|
|
11
|
+
return fs.statSync(p).isFile();
|
|
12
|
+
} catch {
|
|
13
|
+
return false;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
function run_archival_sweep(root) {
|
|
17
|
+
const script = path.join(path.dirname(_HERE), "archive_completed_roadmaps.ts");
|
|
18
|
+
if (!_isFile(script)) {
|
|
19
|
+
return { ran: false, ok: true, stdout: "", stderr: "" };
|
|
20
|
+
}
|
|
21
|
+
const argv = [script, "--all", "--repo-root", root];
|
|
22
|
+
const binName = process.platform === "win32" ? "tsx.cmd" : "tsx";
|
|
23
|
+
let dir = path.dirname(_HERE);
|
|
24
|
+
for (; ; ) {
|
|
25
|
+
const candidate = path.join(dir, "node_modules", ".bin", binName);
|
|
26
|
+
if (fs.existsSync(candidate)) {
|
|
27
|
+
return _sweepResult(spawnSync(candidate, argv, { cwd: root, encoding: "utf-8" }));
|
|
28
|
+
}
|
|
29
|
+
const parent = path.dirname(dir);
|
|
30
|
+
if (parent === dir) {
|
|
31
|
+
break;
|
|
32
|
+
}
|
|
33
|
+
dir = parent;
|
|
34
|
+
}
|
|
35
|
+
return _sweepResult(spawnSync("npx", ["tsx", ...argv], { cwd: root, encoding: "utf-8" }));
|
|
36
|
+
}
|
|
37
|
+
function _sweepResult(r) {
|
|
38
|
+
return {
|
|
39
|
+
ran: true,
|
|
40
|
+
ok: r.status === 0,
|
|
41
|
+
stdout: String(r.stdout ?? ""),
|
|
42
|
+
stderr: String(r.stderr ?? "")
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export {
|
|
47
|
+
run_archival_sweep
|
|
48
|
+
};
|