session-orchestrator 5.3.0 → 5.5.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/.agents/skills/claude-md-drift-check/SKILL.md +1 -1
- package/.agents/skills/test-audit/SKILL.md +21 -0
- package/.agents/skills/test-audit/agents/openai.yaml +5 -0
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/.codex-plugin/plugin.json +1 -1
- package/.codex-plugin/skills/claude-md-drift-check/SKILL.md +1 -1
- package/.codex-plugin/skills/test-audit/SKILL.md +21 -0
- package/.codex-plugin/skills/test-audit/agents/openai.yaml +5 -0
- package/.cursor/commands/test-audit.md +14 -0
- package/.cursor/rules/060-evolve.mdc +28 -13
- package/.cursor/skills/claude-md-drift-check/SKILL.md +1 -1
- package/.cursor/skills/test-audit/SKILL.md +12 -0
- package/.cursor-plugin/plugin.json +1 -1
- package/.orchestrator/policy/blocked-commands.json +1 -1
- package/AGENTS.md +9 -31
- package/CHANGELOG.md +162 -0
- package/README.md +14 -10
- package/docs/agent-authoring.md +2 -2
- package/docs/baseline.md +10 -1
- package/docs/ci-setup.md +154 -4
- package/docs/components.md +11 -11
- package/docs/events-schema.md +25 -19
- package/docs/install.md +14 -2
- package/docs/migration-v4.md +24 -17
- package/docs/persona-panel.md +5 -4
- package/docs/plugin-architecture-v3.md +1 -1
- package/docs/rule-authoring.md +27 -12
- package/docs/scope-collision-guard.md +40 -16
- package/docs/session-config-reference.md +61 -12
- package/docs/session-config-template.md +11 -2
- package/docs/vault-docs-architecture.md +8 -4
- package/hooks/_lib/hook-import-set.json +42 -29
- package/hooks/_lib/lock-bootstrap.mjs +118 -26
- package/hooks/config-protection.mjs +1 -1
- package/hooks/enforce-commands.mjs +28 -13
- package/hooks/enforce-scope.mjs +201 -23
- package/hooks/hooks-codex.json +1 -1
- package/hooks/hooks-cursor.json +5 -0
- package/hooks/hooks-pi.json +5 -0
- package/hooks/hooks.json +6 -1
- package/hooks/on-session-start.mjs +57 -2
- package/hooks/on-stop.mjs +70 -168
- package/hooks/post-bash-write-verify.mjs +98 -17
- package/hooks/post-edit-validate.mjs +15 -5
- package/hooks/post-tool-batch-wave-signal.mjs +32 -152
- package/hooks/pre-bash-memory-propose-audit.mjs +71 -10
- package/hooks/pre-bash-sessions-ledger-guard.mjs +28 -2
- package/hooks/pre-bash-staging-fence.mjs +29 -8
- package/hooks/pre-edit-sessions-ledger-guard.mjs +162 -0
- package/hooks/pre-task-scope-disjoint.mjs +1143 -279
- package/hooks/subagent-telemetry.mjs +96 -19
- package/hooks/wave-scope-commit-guard.mjs +168 -72
- package/package.json +2 -6
- package/pi/prompts/test-audit.md +12 -0
- package/rules/README.md +6 -1
- package/rules/_index.md +3 -3
- package/rules/always-on/bash-harness-pitfalls.md +7 -1
- package/rules/opt-in-domain/prompt-caching.md +5 -1
- package/rules/opt-in-stack/backend-data.md +9 -1
- package/rules/opt-in-stack/backend.md +7 -1
- package/rules/opt-in-stack/frontend.md +6 -1
- package/rules/opt-in-stack/security-web.md +7 -1
- package/rules/opt-in-stack/swift.md +5 -1
- package/scripts/apply-session-learnings.mjs +513 -0
- package/scripts/archive-closed-prds.mjs +40 -12
- package/scripts/autopilot.mjs +57 -54
- package/scripts/backfill-abandoned-sessions.mjs +81 -6
- package/scripts/backfill-learnings-from-vault.mjs +49 -22
- package/scripts/baseline-archetypes.mjs +1 -1
- package/scripts/check-package-manager.mjs +62 -5
- package/scripts/codex-install.mjs +3 -0
- package/scripts/cursor-install.mjs +47 -6
- package/scripts/emit-session.mjs +298 -2
- package/scripts/export-hw-learnings.mjs +40 -10
- package/scripts/fleet-checkin.mjs +170 -0
- package/scripts/lib/agent-frontmatter.mjs +3 -3
- package/scripts/lib/auto-dream.mjs +7 -6
- package/scripts/lib/autopilot/flags.mjs +6 -1
- package/scripts/lib/autopilot/loop.mjs +32 -13
- package/scripts/lib/autopilot/stall-sampler.mjs +13 -9
- package/scripts/lib/baseline-archetypes.mjs +41 -22
- package/scripts/lib/blocked-commands-policy.mjs +40 -0
- package/scripts/lib/common.mjs +41 -0
- package/scripts/lib/config/host-paths.mjs +79 -0
- package/scripts/lib/config/persona-gate-wave.mjs +3 -3
- package/scripts/lib/config/reaper.mjs +7 -6
- package/scripts/lib/config/vault-integration.mjs +151 -16
- package/scripts/lib/config-schema.mjs +13 -0
- package/scripts/lib/config.mjs +75 -10
- package/scripts/lib/eval/engine.mjs +13 -0
- package/scripts/lib/events-retention-banner.mjs +393 -0
- package/scripts/lib/events-rotation.mjs +21 -6
- package/scripts/lib/events.mjs +72 -5
- package/scripts/lib/fleet-protocol.mjs +288 -0
- package/scripts/lib/gates/gate-baseline.mjs +13 -3
- package/scripts/lib/gates/gate-full.mjs +7 -2
- package/scripts/lib/gates/gate-helpers.mjs +93 -2
- package/scripts/lib/gates/gate-incremental.mjs +23 -22
- package/scripts/lib/gates/gate-per-file.mjs +16 -7
- package/scripts/lib/hardening.mjs +1 -0
- package/scripts/lib/harness-audit/categories/category4.mjs +8 -6
- package/scripts/lib/instruction-budget-guard.mjs +77 -11
- package/scripts/lib/learnings/expiry-sweep.mjs +420 -22
- package/scripts/lib/learnings/io.mjs +274 -37
- package/scripts/lib/learnings/schema.mjs +163 -15
- package/scripts/lib/learnings/sizing-subject.mjs +2 -2
- package/scripts/lib/lock-reaper.mjs +38 -14
- package/scripts/lib/maintenance-due-banner.mjs +23 -8
- package/scripts/lib/memory-proposals/schema.mjs +11 -5
- package/scripts/lib/named-baseline-resolver.mjs +53 -28
- package/scripts/lib/named-vault-resolver.mjs +147 -5
- package/scripts/lib/orphan-reaper/defaults.mjs +41 -0
- package/scripts/lib/orphan-reaper/no-follow-append.mjs +87 -0
- package/scripts/lib/orphan-reaper/ps-snapshot.mjs +181 -0
- package/scripts/lib/orphan-reaper/reaper-audit.mjs +323 -0
- package/scripts/lib/orphan-reaper/reaper-decide.mjs +395 -0
- package/scripts/lib/orphan-reaper/scan-throttle.mjs +144 -0
- package/scripts/lib/orphan-reaper/scan.mjs +510 -0
- package/scripts/lib/orphan-reaper/trigger.mjs +173 -0
- package/scripts/lib/orphan-reaper.mjs +47 -1315
- package/scripts/lib/owner-yaml.mjs +104 -6
- package/scripts/lib/persona-panel/catalog-loader.mjs +1 -1
- package/scripts/lib/platform.mjs +206 -2
- package/scripts/lib/plugin-update-banner.mjs +3 -1
- package/scripts/lib/process-group.mjs +134 -22
- package/scripts/lib/project-hygiene.mjs +21 -1
- package/scripts/lib/quality-gate.mjs +45 -5
- package/scripts/lib/resource-probe.mjs +1 -1
- package/scripts/lib/rule-loader.mjs +100 -62
- package/scripts/lib/rules-sync.mjs +27 -12
- package/scripts/lib/scope-baseline.mjs +119 -29
- package/scripts/lib/scope-echo.mjs +7 -0
- package/scripts/lib/scope-gate.mjs +194 -27
- package/scripts/lib/session-close-backfill.mjs +129 -4
- package/scripts/lib/session-end/tail-runner.mjs +10 -5
- package/scripts/lib/session-lock-shape.mjs +6 -3
- package/scripts/lib/session-lock.mjs +320 -67
- package/scripts/lib/session-record-repair.mjs +183 -26
- package/scripts/lib/session-registry.mjs +67 -17
- package/scripts/lib/session-schema/constants.mjs +30 -4
- package/scripts/lib/session-schema/validator.mjs +28 -1
- package/scripts/lib/session-start-probes.mjs +242 -68
- package/scripts/lib/session-token-rollup.mjs +252 -54
- package/scripts/lib/sessions-canonical.mjs +100 -9
- package/scripts/lib/sessions-staleness-banner.mjs +3 -1
- package/scripts/lib/sh-quote.mjs +29 -0
- package/scripts/lib/subagents-schema.mjs +30 -3
- package/scripts/lib/tail-window.mjs +27 -3
- package/scripts/lib/telemetry/pricing.mjs +121 -71
- package/scripts/lib/telemetry/sync.mjs +17 -0
- package/scripts/lib/tests-src-ratio.mjs +215 -23
- package/scripts/lib/tmux-layout/layouts.mjs +1 -11
- package/scripts/lib/tmux-layout/telemetry-stats.mjs +12 -0
- package/scripts/lib/tmux-layout/tmux-shell.mjs +2 -11
- package/scripts/lib/ux-grill/reconcile.mjs +1 -1
- package/scripts/lib/validate/check-agents.mjs +1 -1
- package/scripts/lib/validate/check-hooks-symmetry.mjs +5 -0
- package/scripts/lib/validate/check-learnings-shell-writes.mjs +214 -0
- package/scripts/lib/validate/check-test-value-bans.mjs +388 -27
- package/scripts/lib/validate/check-unicode-safety.mjs +1 -0
- package/scripts/lib/validate/check-unwired-features.mjs +1 -1
- package/scripts/lib/validate/check-vcs-repo-flag.mjs +1 -1
- package/scripts/lib/validate-vendored-rules.mjs +206 -81
- package/scripts/lib/vault-mirror/auto-commit.mjs +5 -3
- package/scripts/lib/vault-mirror/namespace.mjs +47 -26
- package/scripts/lib/vault-mirror/process.mjs +350 -62
- package/scripts/lib/vault-mirror/pseudonym-map.mjs +14 -5
- package/scripts/lib/vault-mirror/render-learnings.mjs +66 -3
- package/scripts/lib/vault-mirror/render-sessions.mjs +28 -4
- package/scripts/lib/vault-mirror/telemetry.mjs +25 -11
- package/scripts/lib/vault-status/board-writer.mjs +53 -12
- package/scripts/lib/vault-status/narrative-mirror.mjs +40 -9
- package/scripts/lib/vcs-repo-spec.mjs +8 -0
- package/scripts/lib/wave-executor/dispatch-common.mjs +10 -18
- package/scripts/lib/wave-executor/foreign-dispatch.mjs +1 -1
- package/scripts/lib/wave-executor/remote-dispatch.mjs +1 -1
- package/scripts/lib/wave-resource-gate.mjs +34 -8
- package/scripts/materialize-wave-scope.mjs +7 -4
- package/scripts/memory-propose.mjs +18 -5
- package/scripts/release-session-lock.mjs +2 -1
- package/scripts/release.mjs +11 -3
- package/scripts/repair-invalid-sessions.mjs +37 -4
- package/scripts/run-migrate-v2-cross-repo.mjs +171 -31
- package/scripts/run-quality-gate.mjs +331 -307
- package/scripts/self-update.mjs +229 -0
- package/scripts/site-numbers.mjs +163 -5
- package/scripts/sweep-expired-learnings.mjs +603 -20
- package/scripts/sweep-expired-rules.mjs +2 -1
- package/scripts/validate-plugin.mjs +7 -0
- package/scripts/validate-wave-scope.mjs +21 -2
- package/scripts/vault-backfill.mjs +50 -37
- package/scripts/vault-integration-watcher.mjs +2 -1
- package/scripts/vault-mirror.mjs +238 -75
- package/scripts/wave-scope-binding.mjs +2 -1
- package/skills/_shared/config-reading.md +3 -3
- package/skills/_shared/fleet-protocol.md +134 -0
- package/skills/_shared/state-ownership.md +41 -12
- package/skills/autopilot/SKILL.md +25 -11
- package/skills/bootstrap/SKILL.md +6 -4
- package/skills/bootstrap/_shared-template.md +97 -2
- package/skills/bootstrap/fast-template.md +4 -1
- package/skills/bootstrap/private-contract.md +2 -1
- package/skills/bootstrap/public-fallback.md +6 -3
- package/skills/bootstrap/references/bootstrap-refresh-lock-flow.md +5 -3
- package/skills/bootstrap/references/bootstrap-retroactive-flow.md +2 -1
- package/skills/bootstrap/standard-template.md +2 -0
- package/skills/claude-md-drift-check/SKILL.md +10 -10
- package/skills/claude-md-drift-check/checker.mjs +26 -18
- package/skills/discovery/probes/ssot-code-diff.mjs +12 -6
- package/skills/discovery/probes/vault-narrative-staleness.mjs +6 -2
- package/skills/discovery/probes/vault-staleness.mjs +9 -3
- package/skills/docs-orchestrator/SKILL.md +12 -5
- package/skills/docs-orchestrator/audience-mapping.md +5 -3
- package/skills/evolve/SKILL.md +13 -4
- package/skills/evolve/references/evolve-analyze-mode.md +42 -18
- package/skills/memory-cleanup/SKILL.md +1 -1
- package/skills/persona-panel/SKILL.md +2 -2
- package/skills/persona-panel/persona-format.md +2 -2
- package/skills/persona-panel/presets/designer-lens.md +1 -1
- package/skills/persona-panel/presets/engineer-lens.md +1 -1
- package/skills/persona-panel/presets/pm-lens.md +1 -1
- package/skills/plan/mode-retro.md +19 -4
- package/skills/quality-gates/SKILL.md +6 -4
- package/skills/remote-offload/SKILL.md +4 -2
- package/skills/session-end/learning-patterns.md +23 -13
- package/skills/session-end/metrics-collection.md +6 -7
- package/skills/session-end/phase-3-2-docs-verification.md +7 -6
- package/skills/session-end/plan-verification.md +25 -9
- package/skills/session-end/references/phase-3-documentation-updates.md +13 -3
- package/skills/session-end/references/phase-4a-worktree-cleanup.md +2 -0
- package/skills/session-end/references/session-summary-template.md +1 -1
- package/skills/session-end/session-metrics-write.md +65 -68
- package/skills/session-plan/SKILL.md +0 -3
- package/skills/session-start/SKILL.md +8 -2
- package/skills/session-start/references/operations-contract.md +6 -0
- package/skills/session-start/references/phase-1-2-session-lock.md +32 -7
- package/skills/session-start/references/phase-1-7-vault-status-board.md +1 -1
- package/skills/session-start/references/phase-4-ssot-environment-check.md +10 -3
- package/skills/test-audit/SKILL.md +152 -0
- package/skills/test-audit/references/campaign.md +111 -0
- package/skills/test-audit/references/mutate.sh +50 -0
- package/skills/vault-mirror/SKILL.md +21 -11
- package/skills/wave-executor/SKILL.md +2 -2
- package/skills/wave-executor/circuit-breaker.md +1 -1
- package/skills/wave-executor/references/wave-executor-state-init.md +3 -0
- package/skills/wave-executor/references/wave-loop-dispatch.md +11 -1
- package/skills/wave-executor/references/wave-loop-review.md +4 -6
- package/skills/wave-executor/references/wave-loop-scope-manifest.md +13 -5
- package/templates/personas/README.md +5 -5
- package/templates/personas/accounting-compliance.v1.md +1 -1
- package/templates/personas/accounting-tax-advisor.v1.md +1 -1
- package/templates/personas/buyer-p1-cto.v1.md +1 -1
- package/templates/personas/buyer-p2-kanzlei.v1.md +1 -1
- package/templates/personas/buyer-p3-build.v1.md +1 -1
- package/templates/personas/buyer-p4-tech-veto.v1.md +1 -1
- package/templates/personas/buyer-p5-solo.v1.md +1 -1
- package/templates/personas/buyer-p6-ld.v1.md +1 -1
- package/templates/personas/klima-ai-expert.v1.md +1 -1
- package/templates/personas/klima-physicist.v1.md +1 -1
|
@@ -29,6 +29,7 @@
|
|
|
29
29
|
* per-file error on the `--apply` path)
|
|
30
30
|
*/
|
|
31
31
|
|
|
32
|
+
import path from 'node:path';
|
|
32
33
|
import { emitEvent } from './lib/events.mjs';
|
|
33
34
|
import { isMainModule } from './lib/is-main-module.mjs';
|
|
34
35
|
import {
|
|
@@ -100,7 +101,7 @@ export function parseArgs(argv) {
|
|
|
100
101
|
} else if (a === '--repo-root') {
|
|
101
102
|
const raw = argv[++i];
|
|
102
103
|
if (typeof raw !== 'string' || raw.length === 0) usageError('--repo-root requires a path');
|
|
103
|
-
args.repoRoot = raw;
|
|
104
|
+
args.repoRoot = path.resolve(raw);
|
|
104
105
|
} else if (a === '--learnings') {
|
|
105
106
|
const raw = argv[++i];
|
|
106
107
|
if (typeof raw !== 'string' || raw.length === 0) usageError('--learnings requires a path');
|
|
@@ -513,6 +513,13 @@ runStrictShAdvisory();
|
|
|
513
513
|
// session-end tail phases from their dispatcher.
|
|
514
514
|
if (runCheck('check-skill-links.mjs') !== 0) checkFailed = 1;
|
|
515
515
|
|
|
516
|
+
// BLOCKING (#1446 / GH#69): instruction prose that tells an agent to write
|
|
517
|
+
// `learnings.jsonl` with a shell `>` / `>>`. The store is gitignored, so a bad
|
|
518
|
+
// write has no VCS restore; the sanctioned writers (`apply-session-learnings.mjs`,
|
|
519
|
+
// `sweep-expired-learnings.mjs --prune`) validate, snapshot `.bak` and archive.
|
|
520
|
+
process.stdout.write('\n');
|
|
521
|
+
if (runCheck('check-learnings-shell-writes.mjs') !== 0) checkFailed = 1;
|
|
522
|
+
|
|
516
523
|
// WARN-only: a state-mutating `git` call in tests/ that names no target resolves
|
|
517
524
|
// its destination from the ambient cwd (or an inherited GIT_DIR) — the 2026-08-19
|
|
518
525
|
// incident, where fixture commits, a fixture remote and a fixture identity landed
|
|
@@ -35,6 +35,9 @@
|
|
|
35
35
|
* `git ls-files` — spawned HERE, in the CLI layer,
|
|
36
36
|
* because scripts/lib/scope-gate.mjs is hook-safe and
|
|
37
37
|
* must not spawn a process (see its module header).
|
|
38
|
+
* Runs even when the manifest fails schema validation
|
|
39
|
+
* (#1026.4): it reads only the sidecar, so schema
|
|
40
|
+
* errors and collisions are reported together (exit 1).
|
|
38
41
|
* --union <path> #1020. QUERY MODE. Read the same sidecar, compute
|
|
39
42
|
* `expandTestSiblings(unionFileScopes(scopes), {role})`
|
|
40
43
|
* using the MANIFEST'S OWN `role`, and print the
|
|
@@ -638,11 +641,24 @@ function knownRepoFiles() {
|
|
|
638
641
|
* @param {string} sidecarPath
|
|
639
642
|
*/
|
|
640
643
|
function assertDisjointOrDie(sidecarPath) {
|
|
644
|
+
if (!reportScopeCollisions(sidecarPath)) process.exit(1);
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
/**
|
|
648
|
+
* Run the #1020 collision check and write one stderr line per finding.
|
|
649
|
+
* Reads ONLY the sidecar, never the manifest — which is why {@link validate}
|
|
650
|
+
* can still run it when the manifest fails schema validation (#1026.4).
|
|
651
|
+
* Sidecar I/O and shape defects exit via {@link readAgentScopesOrDie}.
|
|
652
|
+
*
|
|
653
|
+
* @param {string} sidecarPath
|
|
654
|
+
* @returns {boolean} true when the wave is disjoint
|
|
655
|
+
*/
|
|
656
|
+
function reportScopeCollisions(sidecarPath) {
|
|
641
657
|
const agentScopes = readAgentScopesOrDie(sidecarPath, '--assert-disjoint');
|
|
642
658
|
const { ok, collisions, duplicateIds } = findScopeCollisions(agentScopes, {
|
|
643
659
|
knownFiles: knownRepoFiles(),
|
|
644
660
|
});
|
|
645
|
-
if (ok) return;
|
|
661
|
+
if (ok) return true;
|
|
646
662
|
|
|
647
663
|
// Duplicate ids FIRST: they are a malformed plan, and a reader who fixes them
|
|
648
664
|
// may well change which collisions remain.
|
|
@@ -659,7 +675,7 @@ function assertDisjointOrDie(sidecarPath) {
|
|
|
659
675
|
process.stderr.write(
|
|
660
676
|
`ERROR: ${collisions.length} scope collision(s), ${duplicateIds.length} duplicate id(s) — every file must belong to exactly ONE agent per wave (#1020; .claude/rules/parallel-sessions.md § Decision Tree)\n`,
|
|
661
677
|
);
|
|
662
|
-
|
|
678
|
+
return false;
|
|
663
679
|
}
|
|
664
680
|
|
|
665
681
|
/**
|
|
@@ -709,6 +725,9 @@ function validate(
|
|
|
709
725
|
for (const e of errors) {
|
|
710
726
|
process.stderr.write(`ERROR: ${e}\n`);
|
|
711
727
|
}
|
|
728
|
+
// #1026.4 — the collision check reads only the sidecar, so a schema error
|
|
729
|
+
// must not hide its findings: report both, exit 1 either way.
|
|
730
|
+
if (assertDisjointPath) reportScopeCollisions(assertDisjointPath);
|
|
712
731
|
process.exit(1);
|
|
713
732
|
}
|
|
714
733
|
|
|
@@ -38,6 +38,10 @@ import {
|
|
|
38
38
|
} from './lib/vault-backfill/template.mjs';
|
|
39
39
|
|
|
40
40
|
import { validateManifest, SLUG_RE } from './lib/vault-backfill/manifest.mjs';
|
|
41
|
+
import { _parseVaultIntegration } from './lib/config/vault-integration.mjs';
|
|
42
|
+
import { loadHostPaths, resolveVaultIntegrationHost } from './lib/config/host-paths.mjs';
|
|
43
|
+
import { resolveVaultDir } from './lib/config.mjs';
|
|
44
|
+
import { expandTilde } from './lib/common.mjs';
|
|
41
45
|
|
|
42
46
|
// ── CLI argument parsing ──────────────────────────────────────────────────────
|
|
43
47
|
|
|
@@ -85,9 +89,29 @@ let hadWriteError = false;
|
|
|
85
89
|
|
|
86
90
|
if (flagVerbose) setGlabVerbose(true);
|
|
87
91
|
|
|
88
|
-
// ── Session Config reader
|
|
92
|
+
// ── Session Config reader ─────────────────────────────────────────────────────
|
|
89
93
|
|
|
90
|
-
/**
|
|
94
|
+
/**
|
|
95
|
+
* Read vault-integration.{gitlab-groups,vault-dir} from CLAUDE.md / AGENTS.md in
|
|
96
|
+
* CWD through the canonical Session Config parser (#1094), so every form it
|
|
97
|
+
* accepts (block, inline object, dash/bold bullet) reaches this CLI too.
|
|
98
|
+
*
|
|
99
|
+
* `vault-dir` resolves HOST-LOCALLY like every other vault writer:
|
|
100
|
+
* SO_VAULT_DIR > owner.yaml `vault-dirs:` cwd match > owner.yaml
|
|
101
|
+
* `paths.vault-dir` > the committed value (`resolveVaultDir`). The committed
|
|
102
|
+
* value alone would put `--apply` stubs into whatever vault the committed file
|
|
103
|
+
* names, even on a host whose owner.yaml points elsewhere. Not
|
|
104
|
+
* `parseSessionConfig`: it throws on an invalid value in any unrelated block.
|
|
105
|
+
*
|
|
106
|
+
* `enabled` is the switch the other vault writers obey (board-writer,
|
|
107
|
+
* narrative-mirror: `enabled !== true` → skip), after the same host-local
|
|
108
|
+
* lowering `parseSessionConfig` applies — env `SO_VAULT_INTEGRATION` >
|
|
109
|
+
* owner.yaml `vault-integration:` > committed (#1496: stubs were created with
|
|
110
|
+
* the integration off, from an owner.yaml `paths.vault-dir` alone).
|
|
111
|
+
*
|
|
112
|
+
* @returns {{'gitlab-groups': string[]|null, 'vault-dir': string|null, enabled: boolean,
|
|
113
|
+
* 'host-override': string|null}}
|
|
114
|
+
*/
|
|
91
115
|
function readVaultIntegrationConfig() {
|
|
92
116
|
const candidates = [join(process.cwd(), 'CLAUDE.md'), join(process.cwd(), 'AGENTS.md')];
|
|
93
117
|
|
|
@@ -98,45 +122,24 @@ function readVaultIntegrationConfig() {
|
|
|
98
122
|
}
|
|
99
123
|
}
|
|
100
124
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
if (!inBlock && /^vault-integration:\s*$/.test(line)) { inBlock = true; continue; }
|
|
111
|
-
if (inBlock) {
|
|
112
|
-
if (line.length > 0 && !/^\s/.test(line)) break;
|
|
113
|
-
|
|
114
|
-
const m = line.match(/^\s+([a-zA-Z_-]+):\s*(.*)/);
|
|
115
|
-
if (!m) continue;
|
|
116
|
-
|
|
117
|
-
const k = m[1].trim();
|
|
118
|
-
let v = m[2].trim().replace(/\s*#.*$/, '').trim();
|
|
119
|
-
if ((v.startsWith('"') && v.endsWith('"')) || (v.startsWith("'") && v.endsWith("'"))) {
|
|
120
|
-
v = v.slice(1, -1);
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
if (k === 'gitlab-groups' && v) {
|
|
124
|
-
gitlabGroups = v.replace(/^\[/, '').replace(/\]$/, '').trim() || null;
|
|
125
|
-
}
|
|
126
|
-
if (k === 'vault-dir' && v && v !== 'none' && v !== 'null') {
|
|
127
|
-
vaultDir = v;
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
return { 'gitlab-groups': gitlabGroups, 'vault-dir': vaultDir };
|
|
125
|
+
const hostCtx = loadHostPaths();
|
|
126
|
+
const vi = resolveVaultIntegrationHost(_parseVaultIntegration(content ?? ''), hostCtx);
|
|
127
|
+
const vaultDir = resolveVaultDir(vi['vault-dir'], hostCtx).value ?? null;
|
|
128
|
+
return {
|
|
129
|
+
'gitlab-groups': vi['gitlab-groups'],
|
|
130
|
+
'vault-dir': vaultDir,
|
|
131
|
+
enabled: vi.enabled === true,
|
|
132
|
+
'host-override': vi['host-override'],
|
|
133
|
+
};
|
|
133
134
|
}
|
|
134
135
|
|
|
135
136
|
// ── Vault-dir folder stub ─────────────────────────────────────────────────────
|
|
136
137
|
|
|
137
138
|
function createVaultFolderStub(vaultDir, slug) {
|
|
138
139
|
if (!vaultDir) return;
|
|
139
|
-
|
|
140
|
+
// `~/…` is the documented vault-dir shape; resolve() alone does not expand it
|
|
141
|
+
// and would put the stub under `<cwd>/~/…`.
|
|
142
|
+
const stubDir = join(resolve(expandTilde(vaultDir)), '01-projects', slug);
|
|
140
143
|
try {
|
|
141
144
|
if (!existsSync(stubDir)) {
|
|
142
145
|
if (applyWrites) {
|
|
@@ -399,10 +402,20 @@ async function main() {
|
|
|
399
402
|
if (flagGroups) {
|
|
400
403
|
groups = flagGroups.split(',').map((g) => g.trim()).filter(Boolean);
|
|
401
404
|
} else if (cfgConfig['gitlab-groups']) {
|
|
402
|
-
groups = cfgConfig['gitlab-groups']
|
|
405
|
+
groups = cfgConfig['gitlab-groups'];
|
|
403
406
|
}
|
|
404
407
|
|
|
405
|
-
|
|
408
|
+
// The configured vault-dir counts only while vault-integration is on; an
|
|
409
|
+
// explicit --vault-dir is this run's own request and still wins.
|
|
410
|
+
let vaultDir = flagVaultDir ?? null;
|
|
411
|
+
if (vaultDir === null && cfgConfig['vault-dir'] !== null) {
|
|
412
|
+
if (cfgConfig.enabled) {
|
|
413
|
+
vaultDir = cfgConfig['vault-dir'];
|
|
414
|
+
} else {
|
|
415
|
+
const why = cfgConfig['host-override'] ? `switched off by ${cfgConfig['host-override']}` : 'not enabled';
|
|
416
|
+
log(`vault-integration is ${why} — no vault folder stubs (pass --vault-dir to create them anyway)`);
|
|
417
|
+
}
|
|
418
|
+
}
|
|
406
419
|
|
|
407
420
|
if (!flagYes && (!groups || groups.length === 0)) {
|
|
408
421
|
die(1, 'no GitLab groups specified — pass --groups <CSV> or set vault-integration.gitlab-groups in CLAUDE.md');
|
|
@@ -35,6 +35,7 @@ import { getCrossRepoProjects, getConfinementRoot } from './lib/config/cross-rep
|
|
|
35
35
|
import { validatePathInsideProject } from './lib/path-utils.mjs';
|
|
36
36
|
import { resolveRepoSpec, redactUrlCredentials } from './lib/vcs-repo-spec.mjs';
|
|
37
37
|
import { expandTilde } from './lib/common.mjs';
|
|
38
|
+
import { shellQuote } from './lib/sh-quote.mjs';
|
|
38
39
|
|
|
39
40
|
// ── Argument parsing ──────────────────────────────────────────────────────────
|
|
40
41
|
|
|
@@ -285,7 +286,7 @@ function buildTickBody(issueMap, depIds, verdict, streak, date) {
|
|
|
285
286
|
function buildFlipBody(repos) {
|
|
286
287
|
// Defense-in-depth: regex+confinement upstream already filter, but shell-quote here
|
|
287
288
|
// makes the embedded bash safe under any future bypass.
|
|
288
|
-
const repoList = repos.map(
|
|
289
|
+
const repoList = repos.map(shellQuote).join(' ');
|
|
289
290
|
// The sed/add/commit one-liner targets the project-instruction file. Most
|
|
290
291
|
// ecosystem repos use CLAUDE.md, but Codex-CLI repos use AGENTS.md as a
|
|
291
292
|
// transparent alias — see skills/_shared/instruction-file-resolution.md.
|