session-orchestrator 3.22.0 → 3.24.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/.codex-plugin/plugin.json +1 -1
- package/.cursor/commands/autopilot-multi.md +14 -0
- package/.cursor/commands/autopilot.md +14 -0
- package/.cursor/commands/bootstrap.md +14 -0
- package/.cursor/commands/brainstorm.md +14 -0
- package/.cursor/commands/close.md +13 -0
- package/.cursor/commands/contract-version-bump.md +14 -0
- package/.cursor/commands/debug.md +14 -0
- package/.cursor/commands/discovery.md +14 -0
- package/.cursor/commands/dispatcher.md +14 -0
- package/.cursor/commands/eli5.md +14 -0
- package/.cursor/commands/eval.md +14 -0
- package/.cursor/commands/evolve.md +14 -0
- package/.cursor/commands/go.md +14 -0
- package/.cursor/commands/grill.md +14 -0
- package/.cursor/commands/harness-audit.md +13 -0
- package/.cursor/commands/journey-audit.md +14 -0
- package/.cursor/commands/memory-cleanup.md +14 -0
- package/.cursor/commands/persona-panel.md +14 -0
- package/.cursor/commands/plan.md +14 -0
- package/.cursor/commands/portfolio.md +14 -0
- package/.cursor/commands/reconcile.md +14 -0
- package/.cursor/commands/release.md +14 -0
- package/.cursor/commands/repo-audit.md +13 -0
- package/.cursor/commands/session.md +14 -0
- package/.cursor/commands/spinout.md +14 -0
- package/.cursor/commands/sunset-review.md +14 -0
- package/.cursor/commands/templates-ack.md +14 -0
- package/.cursor/commands/test.md +14 -0
- package/.cursor/hooks.json +60 -0
- package/.cursor/rules/000-session-orchestrator.mdc +8 -0
- package/.cursor/rules/010-session-workflow.mdc +9 -1
- package/.cursor/rules/020-quality-gates.mdc +1 -1
- package/.cursor/rules/030-wave-execution.mdc +1 -1
- package/.cursor/rules/050-plan.mdc +2 -2
- package/.cursor/rules/070-gitlab-ops.mdc +73 -57
- package/.cursor/rules/080-ecosystem-health.mdc +7 -7
- package/.cursor/skills/architecture/SKILL.md +13 -0
- package/.cursor/skills/autopilot/SKILL.md +12 -0
- package/.cursor/skills/bootstrap/SKILL.md +12 -0
- package/.cursor/skills/brainstorm/SKILL.md +13 -0
- package/.cursor/skills/claude-md-drift-check/SKILL.md +13 -0
- package/.cursor/skills/contract-version-bump/SKILL.md +12 -0
- package/.cursor/skills/convergence-monitoring/SKILL.md +12 -0
- package/.cursor/skills/daily/SKILL.md +12 -0
- package/.cursor/skills/debug/SKILL.md +13 -0
- package/.cursor/skills/discovery/SKILL.md +13 -0
- package/.cursor/skills/dispatcher/SKILL.md +13 -0
- package/.cursor/skills/docs-orchestrator/SKILL.md +13 -0
- package/.cursor/skills/domain-model/SKILL.md +13 -0
- package/.cursor/skills/ecosystem-health/SKILL.md +13 -0
- package/.cursor/skills/eli5/SKILL.md +13 -0
- package/.cursor/skills/eval/SKILL.md +12 -0
- package/.cursor/skills/evolve/SKILL.md +13 -0
- package/.cursor/skills/frontmatter-guard/SKILL.md +13 -0
- package/.cursor/skills/gitlab-ops/SKILL.md +13 -0
- package/.cursor/skills/gitlab-portfolio/SKILL.md +13 -0
- package/.cursor/skills/grill/SKILL.md +13 -0
- package/.cursor/skills/hook-development/SKILL.md +13 -0
- package/.cursor/skills/journey-audit/SKILL.md +13 -0
- package/.cursor/skills/mcp-builder/SKILL.md +13 -0
- package/.cursor/skills/memory-cleanup/SKILL.md +12 -0
- package/.cursor/skills/mode-selector/SKILL.md +13 -0
- package/.cursor/skills/npm-publish/SKILL.md +12 -0
- package/.cursor/skills/peekaboo-driver/SKILL.md +13 -0
- package/.cursor/skills/persona-panel/SKILL.md +12 -0
- package/.cursor/skills/plan/SKILL.md +13 -0
- package/.cursor/skills/playwright-driver/SKILL.md +13 -0
- package/.cursor/skills/quality-gates/SKILL.md +13 -0
- package/.cursor/skills/reconcile/SKILL.md +12 -0
- package/.cursor/skills/remote-offload/SKILL.md +13 -0
- package/.cursor/skills/repo-audit/SKILL.md +13 -0
- package/.cursor/skills/session-end/SKILL.md +13 -0
- package/.cursor/skills/session-plan/SKILL.md +13 -0
- package/.cursor/skills/session-start/SKILL.md +13 -0
- package/.cursor/skills/skill-creator/SKILL.md +13 -0
- package/.cursor/skills/spinout/SKILL.md +12 -0
- package/.cursor/skills/sunset-review/SKILL.md +13 -0
- package/.cursor/skills/test-runner/SKILL.md +13 -0
- package/.cursor/skills/tmux-layout/SKILL.md +13 -0
- package/.cursor/skills/ubiquitous-language/SKILL.md +13 -0
- package/.cursor/skills/using-orchestrator/SKILL.md +13 -0
- package/.cursor/skills/vault-mirror/SKILL.md +13 -0
- package/.cursor/skills/vault-sync/SKILL.md +13 -0
- package/.cursor/skills/wave-executor/SKILL.md +13 -0
- package/.cursor/skills/write-executable-plan/SKILL.md +13 -0
- package/.mcp.json +4 -1
- package/CHANGELOG.md +446 -0
- package/README.md +22 -17
- package/agents/AGENTS.md +23 -4
- package/agents/code-implementer.md +2 -1
- package/agents/db-specialist.md +2 -2
- package/agents/docs-writer.md +3 -1
- package/agents/eval-judge.md +1 -1
- package/agents/session-reviewer.md +7 -1
- package/agents/test-writer.md +2 -1
- package/agents/ui-developer.md +2 -1
- package/commands/bootstrap.md +2 -2
- package/commands/close.md +3 -1
- package/commands/go.md +1 -1
- package/commands/journey-audit.md +43 -0
- package/docs/USER-GUIDE.md +2 -2
- package/docs/ci-setup.md +194 -25
- package/docs/codex-setup.md +64 -0
- package/docs/components.md +7 -7
- package/docs/cursor-setup.md +26 -47
- package/docs/events-schema.md +120 -10
- package/docs/github-mirror-protection.md +197 -0
- package/docs/pi-setup.md +2 -0
- package/docs/rule-authoring.md +3 -1
- package/docs/scope-collision-guard.md +49 -2
- package/docs/session-config-reference.md +89 -9
- package/docs/session-config-template.md +38 -7
- package/docs/telemetry/telemetry-claims.md +11 -10
- package/docs/telemetry.md +52 -1
- package/hooks/_lib/atomic-json.mjs +111 -0
- package/hooks/_lib/lock-bootstrap.mjs +8 -4
- package/hooks/_lib/subagent-paths.mjs +143 -0
- package/hooks/_lib/vcs-create-matcher.mjs +397 -38
- package/hooks/cwd-change-restore.mjs +9 -29
- package/hooks/enforce-scope.mjs +93 -0
- package/hooks/hooks-codex.json +1 -1
- package/hooks/hooks-cursor.json +201 -20
- package/hooks/hooks-pi.json +1 -1
- package/hooks/hooks.json +2 -2
- package/hooks/on-session-end.mjs +486 -19
- package/hooks/on-session-start.mjs +263 -12
- package/hooks/on-stop.mjs +392 -24
- package/hooks/post-bash-write-verify.mjs +104 -4
- package/hooks/post-subagent-discovery-validator.mjs +182 -21
- package/hooks/post-tool-batch-wave-signal.mjs +165 -42
- package/hooks/post-tool-failure-corrective-context.mjs +9 -32
- package/hooks/pre-bash-issue-budget.mjs +117 -4
- package/hooks/pre-bash-memory-propose-audit.mjs +13 -7
- package/hooks/pre-bash-sessions-ledger-guard.mjs +159 -0
- package/hooks/pre-bash-staging-fence.mjs +4 -0
- package/hooks/pre-task-scope-disjoint.mjs +368 -35
- package/hooks/skill-invocation-telemetry.mjs +21 -10
- package/hooks/subagent-telemetry.mjs +11 -26
- package/monitors/monitors.json +6 -0
- package/package.json +1 -1
- package/pi/prompts/journey-audit.md +12 -0
- package/rules/_index.md +9 -1
- package/rules/always-on/ask-via-tool.md +62 -0
- package/rules/always-on/bash-harness-pitfalls.md +168 -0
- package/rules/always-on/build-value.md +47 -0
- package/rules/always-on/cross-session-messaging.md +59 -0
- package/rules/always-on/loop-and-monitor.md +221 -0
- package/rules/always-on/parallel-sessions.md +142 -12
- package/rules/always-on/receiving-review.md +108 -0
- package/rules/always-on/test-value.md +40 -0
- package/rules/always-on/verification-before-completion.md +77 -0
- package/scripts/archive-closed-prds.mjs +258 -18
- package/scripts/autopilot.mjs +31 -12
- package/scripts/backfill-abandoned-sessions.mjs +80 -11
- package/scripts/backfill-evidence-digest.mjs +376 -0
- package/scripts/cursor-install.mjs +89 -48
- package/scripts/emit-event.mjs +10 -2
- package/scripts/export-hw-learnings.mjs +143 -2
- package/scripts/express-path.mjs +299 -0
- package/scripts/generate-cursor-adapter.mjs +253 -0
- package/scripts/github-protection-audit.mjs +358 -0
- package/scripts/lib/auq/parse.mjs +5 -29
- package/scripts/lib/auto-dialectic.mjs +68 -0
- package/scripts/lib/autopilot/worktree-pipeline.mjs +318 -18
- package/scripts/lib/build-live-signals.mjs +49 -27
- package/scripts/lib/ci-status-banner.mjs +158 -11
- package/scripts/lib/cold-start-detector.mjs +23 -14
- package/scripts/lib/command-blocker.mjs +70 -0
- package/scripts/lib/config/block-header.mjs +55 -0
- package/scripts/lib/config/discovery-validator.mjs +7 -2
- package/scripts/lib/config/health-endpoints.mjs +383 -0
- package/scripts/lib/config/reconcile.mjs +79 -4
- package/scripts/lib/config/remote-hosts.mjs +233 -0
- package/scripts/lib/config/section-extractor.mjs +235 -36
- package/scripts/lib/config-schema.mjs +9 -1
- package/scripts/lib/config.mjs +87 -8
- package/scripts/lib/convergence-monitor.mjs +13 -2
- package/scripts/lib/cursor-hook-bridge.mjs +443 -0
- package/scripts/lib/dispatcher/cli.mjs +2 -2
- package/scripts/lib/dispatcher/enumerate.mjs +2 -17
- package/scripts/lib/events-schema.mjs +48 -0
- package/scripts/lib/events.mjs +238 -5
- package/scripts/lib/evolve/autonomy-verdict.mjs +9 -4
- package/scripts/lib/evolve/autopilot-effectiveness.mjs +18 -1
- package/scripts/lib/express-path.mjs +327 -0
- package/scripts/lib/file-lock.mjs +22 -4
- package/scripts/lib/gates/gate-full.mjs +81 -8
- package/scripts/lib/gates/gate-helpers.mjs +76 -15
- package/scripts/lib/git-config-drift.mjs +134 -5
- package/scripts/lib/gitlab-portfolio/cli.mjs +3 -15
- package/scripts/lib/harness-audit/categories/category1.mjs +17 -6
- package/scripts/lib/host-identity.mjs +247 -2
- package/scripts/lib/instruction-budget-guard.mjs +31 -1
- package/scripts/lib/issue-budget.mjs +229 -30
- package/scripts/lib/learnings/io.mjs +55 -10
- package/scripts/lib/learnings/schema.mjs +95 -28
- package/scripts/lib/lock-reaper.mjs +7 -1
- package/scripts/lib/locks/staging-fence-lock.mjs +5 -1
- package/scripts/lib/locks/state-md-lock.mjs +8 -1
- package/scripts/lib/memory-banner.mjs +25 -10
- package/scripts/lib/memory-paths.mjs +15 -6
- package/scripts/lib/mode-selector/scoring.mjs +53 -6
- package/scripts/lib/peer-discovery.mjs +20 -2
- package/scripts/lib/platform.mjs +72 -9
- package/scripts/lib/plugin-root.mjs +143 -19
- package/scripts/lib/project-hygiene.mjs +43 -3
- package/scripts/lib/quality-gate.mjs +271 -13
- package/scripts/lib/reconcile/emitter.mjs +87 -19
- package/scripts/lib/reconcile/engine.mjs +517 -18
- package/scripts/lib/reconcile/idempotency.mjs +102 -1
- package/scripts/lib/reconcile/renderer.mjs +148 -3
- package/scripts/lib/reconcile/sanitize.mjs +40 -17
- package/scripts/lib/reconcile/writer.mjs +415 -84
- package/scripts/lib/rule-loader.mjs +37 -2
- package/scripts/lib/rules-sync.mjs +51 -8
- package/scripts/lib/scope-gate.mjs +126 -0
- package/scripts/lib/session-close-backfill.mjs +427 -37
- package/scripts/lib/session-discovery.mjs +69 -5
- package/scripts/lib/session-end/phase-skip.mjs +38 -5
- package/scripts/lib/session-end/worktree-cleanup.mjs +154 -7
- package/scripts/lib/session-id.mjs +30 -14
- package/scripts/lib/session-identity/own-session.mjs +220 -0
- package/scripts/lib/session-lock.mjs +85 -30
- package/scripts/lib/session-schema/normalizer.mjs +70 -3
- package/scripts/lib/session-schema/validator.mjs +40 -0
- package/scripts/lib/session-start-probes.mjs +608 -0
- package/scripts/lib/session-transition.mjs +277 -0
- package/scripts/lib/sessions-canonical.mjs +446 -0
- package/scripts/lib/sessions-staleness-banner.mjs +124 -57
- package/scripts/lib/spiral-carryover.mjs +90 -9
- package/scripts/lib/state-md/frontmatter-mutators.mjs +41 -8
- package/scripts/lib/state-md/mission-status.mjs +350 -52
- package/scripts/lib/state-md/yaml-parser.mjs +145 -16
- package/scripts/lib/state-md.mjs +12 -2
- package/scripts/lib/telemetry/schema.mjs +74 -8
- package/scripts/lib/telemetry/sync.mjs +91 -16
- package/scripts/lib/tmux-layout/telemetry.mjs +14 -2
- package/scripts/lib/validate/check-agents.mjs +66 -0
- package/scripts/lib/validate/check-cursor-adapter.mjs +102 -0
- package/scripts/lib/validate/check-dead-bridge.mjs +24 -2
- package/scripts/lib/validate/check-doc-cli-commands.mjs +25 -65
- package/scripts/lib/validate/check-hooks-emit-event-guard.mjs +370 -0
- package/scripts/lib/validate/check-hooks-symmetry.mjs +29 -63
- package/scripts/lib/validate/check-playwright-mcp-canary.mjs +13 -22
- package/scripts/lib/validate/check-plugin-monitors.mjs +10 -4
- package/scripts/lib/validate/check-skill-script-paths.mjs +436 -0
- package/scripts/lib/validate/check-test-value-bans.mjs +165 -17
- package/scripts/lib/validate/check-untracked-test-deps.mjs +10 -0
- package/scripts/lib/validate/check-unwired-features.mjs +333 -32
- package/scripts/lib/validate/check-validator-registration.mjs +248 -0
- package/scripts/lib/validate/check-vcs-repo-flag.mjs +6 -28
- package/scripts/lib/validate/markdown-fences.mjs +196 -0
- package/scripts/lib/validate/repo-files.mjs +275 -0
- package/scripts/lib/validate-vendored-rules.mjs +229 -7
- package/scripts/lib/vault-mirror/process.mjs +99 -43
- package/scripts/lib/vault-mirror/telemetry.mjs +210 -0
- package/scripts/lib/vault-staleness-banner.mjs +76 -6
- package/scripts/lib/vault-status/board-lock.mjs +185 -0
- package/scripts/lib/vault-status/board-writer.mjs +381 -141
- package/scripts/lib/vault-status/narrative-mirror.mjs +190 -27
- package/scripts/lib/wave-executor/foreign-dispatch.mjs +832 -0
- package/scripts/lib/wave-executor/remote-dispatch.mjs +504 -0
- package/scripts/lib/wave-resource-gate.mjs +127 -7
- package/scripts/lib/wave-transcript-tail.mjs +889 -0
- package/scripts/materialize-wave-scope.mjs +228 -15
- package/scripts/mcp-server.sh +11 -2
- package/scripts/memory-propose.mjs +132 -8
- package/scripts/parse-config.mjs +65 -0
- package/scripts/promote-vault-strict.mjs +4 -15
- package/scripts/site-numbers.mjs +36 -4
- package/scripts/token-audit.sh +9 -2
- package/scripts/validate-plugin.mjs +29 -0
- package/scripts/validate-wave-scope.mjs +67 -0
- package/scripts/vault-consolidate.mjs +3 -11
- package/scripts/vault-integration-watcher.mjs +2 -4
- package/scripts/vault-mirror.mjs +305 -51
- package/skills/_shared/monitor-patterns.md +31 -5
- package/skills/_shared/parallel-aware-auq.md +31 -2
- package/skills/_shared/parallel-aware-preamble.md +19 -4
- package/skills/_shared/platform-tools.md +11 -5
- package/skills/_shared/state-ownership.md +29 -2
- package/skills/autopilot/SKILL.md +5 -1
- package/skills/bootstrap/SKILL.md +3 -3
- package/skills/bootstrap/_shared-template.md +18 -10
- package/skills/bootstrap/deep-template.md +10 -6
- package/skills/bootstrap/fast-template.md +15 -8
- package/skills/bootstrap/standard-template.md +10 -6
- package/skills/claude-md-drift-check/checker.mjs +39 -11
- package/skills/contract-version-bump/SKILL.md +1 -1
- package/skills/dispatcher/SKILL.md +1 -1
- package/skills/ecosystem-health/SKILL.md +4 -1
- package/skills/ecosystem-health/wizard.md +5 -0
- package/skills/evolve/SKILL.md +38 -1
- package/skills/journey-audit/SKILL.md +270 -0
- package/skills/peekaboo-driver/SKILL.md +15 -3
- package/skills/persona-panel/SKILL.md +1 -1
- package/skills/reconcile/SKILL.md +46 -3
- package/skills/remote-offload/SKILL.md +89 -0
- package/skills/session-end/SKILL.md +17 -4
- package/skills/session-end/metrics-collection.md +7 -4
- package/skills/session-end/phase-3-6-tail.md +20 -9
- package/skills/session-end/phase-3-7a-recommendations.md +16 -2
- package/skills/session-plan/SKILL.md +6 -1
- package/skills/session-plan/wave-template.md +1 -0
- package/skills/session-start/SKILL.md +54 -17
- package/skills/session-start/phase-7-5-mode-selector.md +15 -3
- package/skills/session-start/phase-8-5-express-path.md +77 -12
- package/skills/vault-sync/validator.mjs +31 -0
- package/skills/wave-executor/SKILL.md +5 -3
- package/skills/wave-executor/circuit-breaker.md +34 -9
- package/skills/wave-executor/wave-loop.md +143 -22
- package/templates/_shared/journey-manifest.md +110 -0
- package/templates/_shared/rules/parallel-sessions.md +0 -77
|
@@ -23,6 +23,7 @@ import { homedir } from 'node:os';
|
|
|
23
23
|
import { spawnSync } from 'node:child_process';
|
|
24
24
|
import { getCrossRepoProjects, getConfinementRoot } from './lib/config/cross-repo.mjs';
|
|
25
25
|
import { validatePathInsideProject } from './lib/path-utils.mjs';
|
|
26
|
+
import { expandTilde } from './lib/common.mjs';
|
|
26
27
|
|
|
27
28
|
const COMMIT_MSG = 'chore(orchestrator): Promote vault-integration to strict mode — refs #305';
|
|
28
29
|
|
|
@@ -53,18 +54,6 @@ const noBaseline = args.includes('--no-baseline');
|
|
|
53
54
|
const repoIdx = args.indexOf('--repo');
|
|
54
55
|
const singleRepo = repoIdx !== -1 && args[repoIdx + 1] ? args[repoIdx + 1] : null;
|
|
55
56
|
|
|
56
|
-
// ---------------------------------------------------------------------------
|
|
57
|
-
// Path resolution
|
|
58
|
-
// ---------------------------------------------------------------------------
|
|
59
|
-
|
|
60
|
-
/** Expand leading ~ to the user's home directory. */
|
|
61
|
-
function expandHome(p) {
|
|
62
|
-
if (p.startsWith('~/')) {
|
|
63
|
-
return join(homedir(), p.slice(2));
|
|
64
|
-
}
|
|
65
|
-
return p;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
57
|
// ---------------------------------------------------------------------------
|
|
69
58
|
// Vault-integration mode replacement
|
|
70
59
|
// ---------------------------------------------------------------------------
|
|
@@ -424,7 +413,7 @@ async function main() {
|
|
|
424
413
|
|
|
425
414
|
if (singleRepo) {
|
|
426
415
|
// Single-repo mode
|
|
427
|
-
const absRepo =
|
|
416
|
+
const absRepo = expandTilde(singleRepo);
|
|
428
417
|
const singleRoot = getConfinementRoot();
|
|
429
418
|
const singleGuard = validatePathInsideProject(absRepo, singleRoot);
|
|
430
419
|
if (!singleGuard.ok) {
|
|
@@ -449,7 +438,7 @@ async function main() {
|
|
|
449
438
|
|
|
450
439
|
const batchRoot = getConfinementRoot();
|
|
451
440
|
for (const rawPath of eligibleRepos) {
|
|
452
|
-
const absRepo =
|
|
441
|
+
const absRepo = expandTilde(rawPath);
|
|
453
442
|
const guard = validatePathInsideProject(absRepo, batchRoot);
|
|
454
443
|
if (!guard.ok) {
|
|
455
444
|
process.stderr.write(
|
|
@@ -469,7 +458,7 @@ async function main() {
|
|
|
469
458
|
(p) => p === 'projects-baseline' || p.endsWith('/projects-baseline')
|
|
470
459
|
);
|
|
471
460
|
if (baselineEntry) {
|
|
472
|
-
const baselineRepoDir =
|
|
461
|
+
const baselineRepoDir = expandTilde(
|
|
473
462
|
baselineEntry.startsWith('~') || baselineEntry.startsWith('/')
|
|
474
463
|
? baselineEntry
|
|
475
464
|
: `~/Projects/${baselineEntry}`
|
package/scripts/site-numbers.mjs
CHANGED
|
@@ -79,6 +79,7 @@ import { execFileSync } from 'node:child_process';
|
|
|
79
79
|
import { fileURLToPath } from 'node:url';
|
|
80
80
|
|
|
81
81
|
import { writeStdoutLineSync, writeJsonAtomicSync } from './lib/io.mjs';
|
|
82
|
+
import { readCanonicalSessions } from './lib/sessions-canonical.mjs';
|
|
82
83
|
|
|
83
84
|
/** Machine-readable schema tag for the --json envelope. */
|
|
84
85
|
export const SCHEMA = 'site-numbers/1';
|
|
@@ -401,10 +402,31 @@ export const METRIC_DEFS = Object.freeze([
|
|
|
401
402
|
// Gitignored ledger (`.gitignore`: local-only observability data) — absent
|
|
402
403
|
// in every fresh clone, CI checkout and tarball build.
|
|
403
404
|
snapshotFallback: true,
|
|
404
|
-
|
|
405
|
+
// #1186: `grep -c` over-counts — sessions.jsonl is append-only, so the same
|
|
406
|
+
// physical session can carry more than one line (crash-recovery re-appends,
|
|
407
|
+
// #1068 stub/supersede pairs). readCanonicalSessions collapses those to one
|
|
408
|
+
// record per session_id before the count; see scripts/lib/sessions-canonical.mjs
|
|
409
|
+
// for the three collapse rules. `learnings` below stays a raw line count —
|
|
410
|
+
// that ledger has no session_id-shaped identity to dedupe on.
|
|
411
|
+
// Measured on THIS repo's own ledger @ 2ccea0f2: raw line count 289 vs
|
|
412
|
+
// canonical (deduped) count 278 — an over-count of 11 records, which is the
|
|
413
|
+
// bug's magnitude this migration removes.
|
|
414
|
+
source: 'grep -c . .orchestrator/metrics/sessions.jsonl (then deduped per session_id — see readCanonicalSessions, #1186)',
|
|
405
415
|
compute: (root) => {
|
|
406
|
-
const
|
|
407
|
-
|
|
416
|
+
const file = join(root, '.orchestrator', 'metrics', 'sessions.jsonl');
|
|
417
|
+
// Same absent/non-file guard as countJsonlEntries, kept explicit here
|
|
418
|
+
// because readCanonicalSessions returns [] (not null) on a missing ledger
|
|
419
|
+
// — collapsing that into fmtCount(0) would silently defeat the
|
|
420
|
+
// snapshotFallback precedence above (a fresh clone would report "0
|
|
421
|
+
// sessions" instead of falling back to the tracked snapshot).
|
|
422
|
+
if (!existsSync(file) || !statSync(file).isFile()) return null;
|
|
423
|
+
// Same reader every other #1186 consumer uses (autopilot.mjs,
|
|
424
|
+
// build-live-signals.mjs, telemetry/sync.mjs) — a record with no
|
|
425
|
+
// `session_id` is dropped rather than counted, because it cannot be
|
|
426
|
+
// identified for dedup. Measured @ 2ccea0f2 on this repo's own ledger:
|
|
427
|
+
// 0 such rows (raw 289 lines == 289 identified), so the drop is inert
|
|
428
|
+
// here; it only matters for a future malformed/legacy row.
|
|
429
|
+
return fmtCount(readCanonicalSessions({ filePath: file }).length);
|
|
408
430
|
},
|
|
409
431
|
},
|
|
410
432
|
{
|
|
@@ -623,7 +645,17 @@ export function collect(root) {
|
|
|
623
645
|
]) {
|
|
624
646
|
const r = countJsonlEntries(join(root, '.orchestrator', 'metrics', file));
|
|
625
647
|
if (r && r.malformed > 0) {
|
|
626
|
-
|
|
648
|
+
// #1186: the two ledgers now disagree on what a malformed line DOES to
|
|
649
|
+
// the published count. `learnings` is still the raw countJsonlEntries
|
|
650
|
+
// total, which counts a malformed line as an entry regardless of its
|
|
651
|
+
// content. `sessions` is readCanonicalSessions, whose parse loop skips a
|
|
652
|
+
// line it cannot JSON.parse — so a malformed session line is silently
|
|
653
|
+
// ABSENT from the count rather than included in it.
|
|
654
|
+
const consequence =
|
|
655
|
+
name === 'sessions'
|
|
656
|
+
? `they are DROPPED from the sessions count (readCanonicalSessions skips unparseable lines)`
|
|
657
|
+
: `the ${name} count includes them`;
|
|
658
|
+
warnings.push(`${file}: ${r.malformed} non-empty line(s) are not valid JSON — ${consequence}`);
|
|
627
659
|
}
|
|
628
660
|
}
|
|
629
661
|
|
package/scripts/token-audit.sh
CHANGED
|
@@ -141,8 +141,15 @@ if [ -f "$CLAUDE_SETTINGS" ]; then
|
|
|
141
141
|
fi
|
|
142
142
|
fi
|
|
143
143
|
|
|
144
|
-
# Count enabled plugins
|
|
145
|
-
|
|
144
|
+
# Count enabled plugins.
|
|
145
|
+
# `|| true` rather than `|| echo "0"`: grep -c ALREADY prints 0 on no-match and
|
|
146
|
+
# still exits 1, so an echo fallback appends a second line — the capture becomes
|
|
147
|
+
# "0\n0", which every numeric test downstream rejects (bash-harness-pitfalls.md §1).
|
|
148
|
+
plugin_count=$(grep -c ': true' "$CLAUDE_SETTINGS" 2>/dev/null || true)
|
|
149
|
+
# NOTE: after the :-0 default an unreadable file prints the same as "zero
|
|
150
|
+
# plugins" — accepted, the only consumer is the informational echo below.
|
|
151
|
+
# The #1077 fix here is the removed double-"0" line, not a failure sentinel.
|
|
152
|
+
plugin_count=${plugin_count:-0}
|
|
146
153
|
echo " Enabled plugins: $plugin_count"
|
|
147
154
|
fi
|
|
148
155
|
echo ""
|
|
@@ -244,6 +244,9 @@ if (runCheck('check-pi-package.mjs') !== 0) checkFailed = 1;
|
|
|
244
244
|
process.stdout.write('\n');
|
|
245
245
|
if (runCheck('check-pi-prompts.mjs') !== 0) checkFailed = 1;
|
|
246
246
|
|
|
247
|
+
process.stdout.write('\n');
|
|
248
|
+
if (runCheck('check-cursor-adapter.mjs') !== 0) checkFailed = 1;
|
|
249
|
+
|
|
247
250
|
process.stdout.write('\n');
|
|
248
251
|
if (runCheck('check-session-plan-routing.mjs') !== 0) checkFailed = 1;
|
|
249
252
|
|
|
@@ -315,6 +318,16 @@ runCheck('check-vcs-repo-flag.mjs');
|
|
|
315
318
|
process.stdout.write('\n');
|
|
316
319
|
runCheck('check-doc-cli-commands.mjs');
|
|
317
320
|
|
|
321
|
+
// BLOCKING (#1176): a `scripts/**.mjs` path cited in skills/, commands/ or
|
|
322
|
+
// agents/ prose that does not exist. Unlike the WARN-only check above, the
|
|
323
|
+
// oracle is this repository's own filesystem — no version skew of a foreign
|
|
324
|
+
// binary can red an unrelated commit, so a finding is always a real defect.
|
|
325
|
+
// A deliberately absent path is annotated in place:
|
|
326
|
+
// `<!-- path-check: planned #<iid> | historical | example -->`, honoured on the
|
|
327
|
+
// citation's own line or the line immediately above.
|
|
328
|
+
process.stdout.write('\n');
|
|
329
|
+
if (runCheck('check-skill-script-paths.mjs') !== 0) checkFailed = 1;
|
|
330
|
+
|
|
318
331
|
// WARN-only: a state-mutating `git` call in tests/ that names no target resolves
|
|
319
332
|
// its destination from the ambient cwd (or an inherited GIT_DIR) — the 2026-08-19
|
|
320
333
|
// incident, where fixture commits, a fixture remote and a fixture identity landed
|
|
@@ -334,6 +347,22 @@ runCheck('check-doc-cli-commands.mjs');
|
|
|
334
347
|
process.stdout.write('\n');
|
|
335
348
|
runCheck('check-test-git-config-target.mjs');
|
|
336
349
|
|
|
350
|
+
// BLOCKING (#1183): every `emitEvent()` call site under hooks/**/*.mjs must be
|
|
351
|
+
// try/catch-guarded (emitEvent() throws EventValidationError on a malformed
|
|
352
|
+
// record — an unguarded call aborts the hook process). Five pre-existing
|
|
353
|
+
// unguarded sites are baselined inside the checker itself and report WARN,
|
|
354
|
+
// never FAIL, so this can be blocking-by-default without going red on
|
|
355
|
+
// arrival; only a NEW unguarded site fails the build.
|
|
356
|
+
process.stdout.write('\n');
|
|
357
|
+
if (runCheck('check-hooks-emit-event-guard.mjs') !== 0) checkFailed = 1;
|
|
358
|
+
|
|
359
|
+
// BLOCKING (#1184): every scripts/lib/validate/check-*.mjs must be referenced
|
|
360
|
+
// by basename from this file, .husky/pre-commit, or .gitlab-ci.yml — or carry
|
|
361
|
+
// a `// registration: standalone <reason>` header marker declaring itself
|
|
362
|
+
// deliberately CLI-only. A checker nobody runs is built work with no effect.
|
|
363
|
+
process.stdout.write('\n');
|
|
364
|
+
if (runCheck('check-validator-registration.mjs') !== 0) checkFailed = 1;
|
|
365
|
+
|
|
337
366
|
// ---------------------------------------------------------------------------
|
|
338
367
|
// Summary
|
|
339
368
|
// ---------------------------------------------------------------------------
|
|
@@ -252,6 +252,72 @@ function validateRequired(obj, errors) {
|
|
|
252
252
|
}
|
|
253
253
|
}
|
|
254
254
|
|
|
255
|
+
/**
|
|
256
|
+
* Shape-check ONE optional identifier field: present ⇒ a non-empty string.
|
|
257
|
+
*
|
|
258
|
+
* Returns whether the key was PRESENT at all (regardless of validity), so the
|
|
259
|
+
* caller can distinguish "absent" from "present but malformed" — the two need
|
|
260
|
+
* different treatment and only the first is a warning.
|
|
261
|
+
*
|
|
262
|
+
* An EMPTY string is an error rather than a second flavour of absent, for the
|
|
263
|
+
* reason `sessionAttribution()` (scripts/lib/events.mjs) already states about
|
|
264
|
+
* omitting the key: an empty id satisfies a truthiness check while attributing
|
|
265
|
+
* to nothing. A reader comparing `manifest.session === <own session id>` would
|
|
266
|
+
* then treat the manifest as FOREIGN (ignore it) where the writer meant
|
|
267
|
+
* UNBOUND (enforce it) — the two dispositions are opposites, so the ambiguity
|
|
268
|
+
* is not cosmetic. Absence is the only honest encoding of "not session-bound".
|
|
269
|
+
*
|
|
270
|
+
* @param {Record<string, unknown>} obj
|
|
271
|
+
* @param {string} key
|
|
272
|
+
* @param {string[]} errors
|
|
273
|
+
* @returns {boolean} true when the key is present (valid or not)
|
|
274
|
+
*/
|
|
275
|
+
function validateOptionalSessionId(obj, key, errors) {
|
|
276
|
+
if (!(key in obj) || obj[key] === undefined) return false;
|
|
277
|
+
const value = obj[key];
|
|
278
|
+
const t = value === null ? 'null' : typeof value;
|
|
279
|
+
if (t !== 'string') {
|
|
280
|
+
errors.push(`${key} must be a non-empty string, got type: ${t}`);
|
|
281
|
+
return true;
|
|
282
|
+
}
|
|
283
|
+
if (/** @type {string} */ (value).length === 0) {
|
|
284
|
+
errors.push(
|
|
285
|
+
`${key} must be a non-empty string, got: "" — an empty id attributes to nothing; omit the key entirely to declare the manifest unbound`,
|
|
286
|
+
);
|
|
287
|
+
}
|
|
288
|
+
return true;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
/**
|
|
292
|
+
* Validate the OPTIONAL session binding (#1123): `session` (the raw
|
|
293
|
+
* `session_id` of the session that WROTE this manifest) and its human-readable
|
|
294
|
+
* twin `semantic_session`. Both come from one `sessionAttribution(repoRoot)`
|
|
295
|
+
* call — see `skills/wave-executor/wave-loop.md` § Scope Manifest.
|
|
296
|
+
*
|
|
297
|
+
* Deliberately NOT part of {@link validateRequired}, and that is a compatibility
|
|
298
|
+
* constraint rather than a preference: `wave-scope.json` is a shared
|
|
299
|
+
* working-copy artefact, every manifest written before #1123 lacks the field,
|
|
300
|
+
* and the pre-union skeleton of § Scope Manifest 3.3 is fed through this very
|
|
301
|
+
* validator before the union exists. Requiring it would reject manifests the
|
|
302
|
+
* documented procedure itself produces. The absent case therefore WARNS — the
|
|
303
|
+
* flip to an error belongs to a later release, once no legacy writer remains.
|
|
304
|
+
*
|
|
305
|
+
* @param {Record<string, unknown>} obj
|
|
306
|
+
* @param {string[]} errors
|
|
307
|
+
* @param {string[]} warnings
|
|
308
|
+
*/
|
|
309
|
+
function validateSession(obj, errors, warnings) {
|
|
310
|
+
const present = validateOptionalSessionId(obj, 'session', errors);
|
|
311
|
+
validateOptionalSessionId(obj, 'semantic_session', errors);
|
|
312
|
+
if (!present) {
|
|
313
|
+
warnings.push(
|
|
314
|
+
'no session field — manifest is not session-bound (legacy, #1123), so every session sharing this ' +
|
|
315
|
+
'working copy is enforced against it. The writer derives it from sessionAttribution() — see ' +
|
|
316
|
+
'skills/wave-executor/wave-loop.md § Scope Manifest.',
|
|
317
|
+
);
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
255
321
|
/**
|
|
256
322
|
* Literal filesystem-root forms — POSIX "/" and the Windows equivalents "\"
|
|
257
323
|
* and a bare drive root ("C:\", "C:\\", ...). Checked independently of
|
|
@@ -683,6 +749,7 @@ function validate(
|
|
|
683
749
|
const warnings = [];
|
|
684
750
|
|
|
685
751
|
validateRequired(obj, errors);
|
|
752
|
+
validateSession(obj, errors, warnings);
|
|
686
753
|
validateAllowedPaths(obj, errors, warnings);
|
|
687
754
|
validateBlockedCommands(obj, errors);
|
|
688
755
|
validateGates(obj, errors);
|
|
@@ -84,10 +84,9 @@
|
|
|
84
84
|
|
|
85
85
|
import { promises as fs } from 'node:fs';
|
|
86
86
|
import path from 'node:path';
|
|
87
|
-
import os from 'node:os';
|
|
88
87
|
import { pathToFileURL } from 'node:url';
|
|
89
88
|
|
|
90
|
-
import { die, utcTimestamp } from './lib/common.mjs';
|
|
89
|
+
import { die, utcTimestamp, expandTilde } from './lib/common.mjs';
|
|
91
90
|
import { parseColumnFlags, CliFlagError } from './lib/cli-flags.mjs';
|
|
92
91
|
import {
|
|
93
92
|
SCRIPT_NAME,
|
|
@@ -150,13 +149,6 @@ Exit codes:
|
|
|
150
149
|
process.stderr.write(usage);
|
|
151
150
|
}
|
|
152
151
|
|
|
153
|
-
function expandHome(p) {
|
|
154
|
-
if (typeof p !== 'string' || p.length === 0) return p;
|
|
155
|
-
if (p === '~') return os.homedir();
|
|
156
|
-
if (p.startsWith('~/')) return path.join(os.homedir(), p.slice(2));
|
|
157
|
-
return p;
|
|
158
|
-
}
|
|
159
|
-
|
|
160
152
|
async function isDir(p) {
|
|
161
153
|
try {
|
|
162
154
|
const st = await fs.stat(p);
|
|
@@ -222,8 +214,8 @@ async function main() {
|
|
|
222
214
|
const isDryRun = !isApply;
|
|
223
215
|
const isJson = parsed.values.json === true;
|
|
224
216
|
|
|
225
|
-
const sourceRoot = path.resolve(
|
|
226
|
-
const canonicalRoot = path.resolve(
|
|
217
|
+
const sourceRoot = path.resolve(expandTilde(parsed.values.source ?? DEFAULT_SOURCE));
|
|
218
|
+
const canonicalRoot = path.resolve(expandTilde(parsed.values.canonical ?? DEFAULT_CANONICAL));
|
|
227
219
|
|
|
228
220
|
// Parse --resolve flags into a Map<relPath, "src"|"dst"|"skip">
|
|
229
221
|
const resolutions = new Map();
|
|
@@ -31,11 +31,10 @@
|
|
|
31
31
|
*/
|
|
32
32
|
|
|
33
33
|
import { spawnSync } from 'node:child_process';
|
|
34
|
-
import { join } from 'node:path';
|
|
35
|
-
import { homedir } from 'node:os';
|
|
36
34
|
import { getCrossRepoProjects, getConfinementRoot } from './lib/config/cross-repo.mjs';
|
|
37
35
|
import { validatePathInsideProject } from './lib/path-utils.mjs';
|
|
38
36
|
import { resolveRepoSpec, redactUrlCredentials } from './lib/vcs-repo-spec.mjs';
|
|
37
|
+
import { expandTilde } from './lib/common.mjs';
|
|
39
38
|
|
|
40
39
|
// ── Argument parsing ──────────────────────────────────────────────────────────
|
|
41
40
|
|
|
@@ -332,9 +331,8 @@ async function main() {
|
|
|
332
331
|
// Load the config-driven repo list before doing any glab work
|
|
333
332
|
const watcherRoot = getConfinementRoot();
|
|
334
333
|
// Home-expand each entry before confinement, matching sibling scripts (W4-Q2 LOW).
|
|
335
|
-
const expandHome = (p) => (p.startsWith('~/') ? join(homedir(), p.slice(2)) : p);
|
|
336
334
|
const flipRepos = (await getCrossRepoProjects()).filter((r) => {
|
|
337
|
-
const guard = validatePathInsideProject(
|
|
335
|
+
const guard = validatePathInsideProject(expandTilde(r), watcherRoot);
|
|
338
336
|
if (!guard.ok) {
|
|
339
337
|
process.stderr.write(
|
|
340
338
|
`vault-integration-watcher: WARN rejecting confined-path violation for ${JSON.stringify(r)} (reason: ${guard.reason})\n`
|