session-orchestrator 4.1.0 → 5.0.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/session-plan/SKILL.md +1 -1
- package/.agents/skills/session-start/SKILL.md +1 -1
- package/.agents/skills/ux-grill/SKILL.md +22 -0
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +3 -2
- package/.codex-plugin/plugin.json +1 -1
- package/.codex-plugin/skills/session-plan/SKILL.md +1 -1
- package/.codex-plugin/skills/session-start/SKILL.md +1 -1
- package/.codex-plugin/skills/ux-grill/SKILL.md +21 -0
- package/.codex-plugin/skills/ux-grill/agents/openai.yaml +5 -0
- package/.cursor/commands/ux-grill.md +14 -0
- package/.cursor/skills/session-plan/SKILL.md +1 -1
- package/.cursor/skills/session-start/SKILL.md +1 -1
- package/.cursor/skills/ux-grill/SKILL.md +13 -0
- package/.cursor-plugin/plugin.json +1 -1
- package/AGENTS.md +2 -1
- package/CHANGELOG.md +128 -1
- package/README.md +98 -86
- package/agents/dialectic-deriver.md +11 -0
- package/agents/ux-evaluator.md +1 -1
- package/commands/close.md +3 -3
- package/commands/go.md +2 -0
- package/commands/memory-cleanup.md +4 -3
- package/commands/persona-panel.md +1 -1
- package/commands/session.md +3 -2
- package/commands/ux-grill.md +51 -0
- package/docs/README.md +4 -4
- package/docs/USER-GUIDE.md +117 -50
- package/docs/agent-authoring.md +2 -2
- package/docs/baseline.md +55 -1
- package/docs/ci-setup.md +1 -1
- package/docs/codex-setup.md +9 -0
- package/docs/components.md +9 -9
- package/docs/cursor-setup.md +1 -0
- package/docs/events-schema.md +13 -6
- package/docs/github-mirror-protection.md +61 -20
- package/docs/instruction-delivery.md +1 -1
- package/docs/memory-proposal-flow.md +3 -3
- package/docs/migration-v4.md +2 -2
- package/docs/migration-v5.md +62 -0
- package/docs/owner-config-schema.md +74 -90
- package/docs/persona-panel.md +4 -4
- package/docs/pi-setup.md +1 -0
- package/docs/rule-authoring.md +13 -6
- package/docs/scope-collision-guard.md +16 -0
- package/docs/session-config-reference.md +55 -22
- package/docs/session-config-template.md +9 -5
- package/docs/vault-docs-architecture.md +4 -2
- package/hooks/_lib/hook-import-set.json +70 -3
- package/hooks/_lib/lock-bootstrap.mjs +84 -1
- package/hooks/_lib/vcs-create-matcher.mjs +401 -16
- package/hooks/enforce-scope.mjs +201 -0
- package/hooks/hooks-codex.json +1 -1
- package/hooks/hooks-cursor.json +5 -0
- package/hooks/hooks.json +7 -2
- package/hooks/on-session-start.mjs +171 -49
- package/hooks/post-bash-issue-budget-refund.mjs +375 -0
- package/hooks/pre-auq-clarity.mjs +70 -18
- package/hooks/pre-bash-issue-budget.mjs +170 -26
- package/hooks/subagent-telemetry.mjs +106 -20
- package/package.json +5 -4
- package/pi/prompts/ux-grill.md +12 -0
- package/scripts/baseline-archetypes.mjs +28 -0
- package/scripts/ci/assert-vitest-green.mjs +4 -2
- package/scripts/dialectic-deriver.mjs +32 -8
- package/scripts/emit-session.mjs +72 -1
- package/scripts/lib/agent-status.mjs +441 -9
- package/scripts/lib/auq/schema.mjs +10 -3
- package/scripts/lib/auto-dialectic.mjs +0 -68
- package/scripts/lib/baseline-archetypes.mjs +439 -0
- package/scripts/lib/build-live-signals.mjs +5 -6
- package/scripts/lib/ci-status-banner.mjs +29 -6
- package/scripts/lib/claude-md-budget-lint.mjs +52 -2
- package/scripts/lib/config/issue-budget.mjs +68 -8
- package/scripts/lib/config/private-config-dir.mjs +3 -2
- package/scripts/lib/config/remote-hosts.mjs +2 -2
- package/scripts/lib/config-schema.mjs +79 -0
- package/scripts/lib/config.mjs +12 -1
- package/scripts/lib/eval/engine.mjs +7 -1
- package/scripts/lib/file-lock.mjs +151 -8
- package/scripts/lib/git-porcelain.mjs +113 -0
- package/scripts/lib/instruction-budget-guard.mjs +415 -47
- package/scripts/lib/io.mjs +29 -4
- package/scripts/lib/issue-budget-reconcile.mjs +392 -0
- package/scripts/lib/issue-budget.mjs +412 -9
- package/scripts/lib/learnings/evolve-telemetry.mjs +1 -2
- package/scripts/lib/learnings/sizing-subject.mjs +44 -0
- package/scripts/lib/locks/staging-fence-lock.mjs +19 -38
- package/scripts/lib/locks/state-md-lock.mjs +19 -41
- package/scripts/lib/maintenance-due-banner.mjs +450 -0
- package/scripts/lib/owner-config.example.yaml +29 -46
- package/scripts/lib/owner-yaml.mjs +14 -13
- package/scripts/lib/peer-cards/merger.mjs +143 -0
- package/scripts/lib/pre-dispatch-check.mjs +20 -14
- package/scripts/lib/project-hygiene.mjs +81 -30
- package/scripts/lib/quality-gate.mjs +27 -71
- package/scripts/lib/reconcile/engine.mjs +19 -1
- package/scripts/lib/reconcile/writer.mjs +278 -11
- package/scripts/lib/resource-probe/evaluate.mjs +19 -21
- package/scripts/lib/rules-sync.mjs +34 -4
- package/scripts/lib/scope-echo.mjs +346 -0
- package/scripts/lib/session-close-backfill.mjs +182 -40
- package/scripts/lib/session-end/phase-skip.mjs +85 -86
- package/scripts/lib/session-end/tail-runner.mjs +178 -0
- package/scripts/lib/session-lock.mjs +62 -2
- package/scripts/lib/session-record-repair.mjs +91 -0
- package/scripts/lib/session-schema/constants.mjs +6 -0
- package/scripts/lib/session-schema/filters.mjs +26 -1
- package/scripts/lib/session-schema/validator.mjs +20 -0
- package/scripts/lib/session-shape.mjs +558 -0
- package/scripts/lib/session-start-probes.mjs +429 -56
- package/scripts/lib/session-token-rollup.mjs +95 -10
- package/scripts/lib/state-md/frontmatter-mutators.mjs +22 -34
- package/scripts/lib/state-md.mjs +1 -0
- package/scripts/lib/subagents-schema.mjs +77 -9
- package/scripts/lib/telemetry/pricing.mjs +197 -0
- package/scripts/lib/telemetry/sync.mjs +50 -1
- package/scripts/lib/test-runner/artifact-paths.mjs +30 -5
- package/scripts/lib/test-runner/issue-reconcile.mjs +45 -8
- package/scripts/lib/tmux-layout/layouts.mjs +62 -4
- package/scripts/lib/ux-grill/collect.mjs +1163 -0
- package/scripts/lib/ux-grill/compare.mjs +285 -0
- package/scripts/lib/ux-grill/manifest.mjs +618 -0
- package/scripts/lib/ux-grill/measures.mjs +431 -0
- package/scripts/lib/ux-grill/paths.mjs +224 -0
- package/scripts/lib/ux-grill/pencil-coverage.mjs +284 -0
- package/scripts/lib/ux-grill/reconcile.mjs +344 -0
- package/scripts/lib/ux-grill/run-record.mjs +316 -0
- package/scripts/lib/ux-grill/schema.mjs +321 -0
- package/scripts/lib/validate/check-skill-script-paths.mjs +33 -10
- package/scripts/lib/validate/check-untracked-test-deps.mjs +33 -19
- package/scripts/lib/validate/check-unwired-features.mjs +56 -27
- package/scripts/lib/vault-mirror/process.mjs +2 -1
- package/scripts/lib/vault-status/board-lock.mjs +18 -0
- package/scripts/lib/vault-status/board-writer.mjs +8 -0
- package/scripts/lib/vault-status/narrative-mirror.mjs +4 -4
- package/scripts/lib/wave-resource-gate.mjs +23 -27
- package/scripts/lib/wave-sizing.mjs +10 -3
- package/scripts/materialize-wave-scope.mjs +68 -14
- package/scripts/mcp-server.sh +16 -1
- package/scripts/print-applicable-rules.mjs +7 -6
- package/scripts/print-learnings-index.mjs +3 -2
- package/scripts/release.mjs +7 -2
- package/scripts/session-shape.mjs +266 -0
- package/skills/_shared/config-reading.md +15 -9
- package/skills/_shared/private-capability-context.md +89 -0
- package/skills/bootstrap/SKILL.md +60 -209
- package/skills/bootstrap/_shared-template.md +99 -14
- package/skills/bootstrap/deep-template.md +36 -26
- package/skills/bootstrap/fast-template.md +44 -8
- package/skills/bootstrap/intensity-heuristic.md +10 -4
- package/skills/bootstrap/private-contract.md +119 -0
- package/skills/bootstrap/public-fallback.md +30 -18
- package/skills/bootstrap/references/bootstrap-ecosystem-health-flow.md +48 -0
- package/skills/bootstrap/references/bootstrap-refresh-lock-flow.md +37 -0
- package/skills/bootstrap/references/bootstrap-retroactive-flow.md +108 -0
- package/skills/bootstrap/references/bootstrap-rules-fetch-bridge.md +64 -0
- package/skills/bootstrap/standard-template.md +39 -24
- package/skills/claude-md-drift-check/SKILL.md +9 -2
- package/skills/claude-md-drift-check/checker.mjs +213 -21
- package/skills/discovery/SKILL.md +6 -173
- package/skills/discovery/probes/vault-staleness.mjs +35 -5
- package/skills/discovery/probes-docs.md +8 -4
- package/skills/discovery/probes-supply-chain.md +4 -2
- package/skills/discovery/probes-ui.md +8 -4
- package/skills/discovery/probes-vault.md +12 -4
- package/skills/discovery/references/discovery-interactive-triage.md +139 -0
- package/skills/discovery/references/discovery-triage-state.md +54 -0
- package/skills/docs-orchestrator/audience-mapping.md +1 -1
- package/skills/eval/rubric-v1.md +13 -0
- package/skills/evolve/SKILL.md +2 -458
- package/skills/evolve/references/evolve-analyze-mode.md +360 -0
- package/skills/evolve/references/evolve-dialectic-mode.md +139 -0
- package/skills/gitlab-ops/SKILL.md +3 -3
- package/skills/grill/SKILL.md +1 -1
- package/skills/memory-cleanup/SKILL.md +2 -2
- package/skills/plan/mode-new.md +9 -0
- package/skills/plan/mode-retro.md +4 -3
- package/skills/reconcile/SKILL.md +11 -1
- package/skills/session-end/SKILL.md +3 -2
- package/skills/session-end/drift-operations.md +20 -5
- package/skills/session-end/metrics-collection.md +1 -0
- package/skills/session-end/phase-3-2-docs-verification.md +1 -1
- package/skills/session-end/phase-3-6-tail.md +27 -67
- package/skills/session-end/phase-3-7a-recommendations.md +2 -2
- package/skills/session-end/references/phase-2-quality-gate.md +3 -3
- package/skills/session-end/references/phase-3-documentation-updates.md +8 -6
- package/skills/session-end/references/phase-5-issue-cleanup.md +32 -1
- package/skills/session-end/session-metrics-write.md +33 -12
- package/skills/session-plan/SKILL.md +46 -180
- package/skills/session-plan/references/session-plan-task-classification.md +152 -0
- package/skills/session-plan/wave-template.md +8 -15
- package/skills/session-start/SKILL.md +41 -7
- package/skills/session-start/phase-2-5-docs-planning.md +1 -1
- package/skills/session-start/phase-8-5-express-path.md +12 -9
- package/skills/session-start/references/operations-contract.md +114 -0
- package/skills/session-start/references/phase-1-5-session-continuity.md +2 -0
- package/skills/session-start/references/phase-4-ssot-environment-check.md +42 -24
- package/skills/session-start/references/phase-6-7-memory-banner-telemetry-consent.md +3 -1
- package/skills/session-start/soul.md +2 -2
- package/skills/test-runner/SKILL.md +1 -1
- package/skills/test-runner/rubric-v1.md +2 -2
- package/skills/tmux-layout/SKILL.md +3 -1
- package/skills/ux-grill/SKILL.md +211 -0
- package/skills/ux-grill/rubric-v2.md +201 -0
- package/skills/ux-grill/soul.md +76 -0
- package/skills/wave-executor/SKILL.md +32 -127
- package/skills/wave-executor/circuit-breaker.md +3 -1
- package/skills/wave-executor/references/wave-executor-quality-gate.md +61 -0
- package/skills/wave-executor/references/wave-executor-state-init.md +86 -0
- package/skills/wave-executor/references/wave-loop-dispatch.md +12 -2
- package/skills/wave-executor/references/wave-loop-review.md +19 -6
- package/skills/wave-executor/references/wave-loop-scope-manifest.md +6 -2
- package/templates/_shared/ux-manifest.template.md +149 -0
- package/templates/nextjs-minimal/package.json +1 -1
- package/templates/node-minimal/package.json +1 -1
- package/scripts/lib/multi-provider-build/providers.mjs +0 -64
- package/scripts/lib/multi-provider-build/templating.mjs +0 -130
- package/scripts/lib/owner-config/coerce.mjs +0 -29
- package/scripts/lib/owner-config/constants.mjs +0 -21
- package/scripts/lib/owner-config/defaults.mjs +0 -50
- package/scripts/lib/owner-config/error.mjs +0 -19
- package/scripts/lib/owner-config/index.mjs +0 -13
- package/scripts/lib/owner-config/merge.mjs +0 -52
- package/scripts/lib/owner-config/validate.mjs +0 -259
- package/scripts/lib/owner-config-loader.mjs +0 -170
- package/scripts/lib/owner-config.mjs +0 -28
- package/scripts/lib/soul-resolve.mjs +0 -130
- package/scripts/lib/vault-mirror/render.mjs +0 -8
- package/templates/_shared/journey-manifest.md +0 -114
|
@@ -24,21 +24,39 @@ Idempotency is handled by the writer itself:
|
|
|
24
24
|
Shell:
|
|
25
25
|
```bash
|
|
26
26
|
mkdir -p "$REPO_ROOT/.claude"
|
|
27
|
-
|
|
28
|
-
|
|
27
|
+
export PLUGIN_ROOT REPO_ROOT CONFIRMED_ARCHETYPE
|
|
28
|
+
RULES_RESULT=$(node --input-type=module <<'NODE'
|
|
29
|
+
import { pathToFileURL } from 'node:url';
|
|
30
|
+
const { syncBootstrapRules } = await import(pathToFileURL(`${process.env.PLUGIN_ROOT}/scripts/lib/baseline-archetypes.mjs`));
|
|
31
|
+
const result = await syncBootstrapRules({ repoRoot: process.env.REPO_ROOT, archetype: process.env.CONFIRMED_ARCHETYPE || undefined });
|
|
32
|
+
process.stdout.write(`${JSON.stringify(result)}\n`);
|
|
33
|
+
if (result.status === 'error') process.exitCode = 2;
|
|
34
|
+
NODE
|
|
35
|
+
) || exit 2
|
|
36
|
+
printf '%s\n' "$RULES_RESULT"
|
|
37
|
+
while IFS= read -r _file; do BOOTSTRAP_FILES+=("$_file"); done \
|
|
38
|
+
< <(printf '%s\n' "$RULES_RESULT" | jq -r '.created[]')
|
|
39
|
+
if [[ ! -e "$REPO_ROOT/.claude/loop.md" && ! -L "$REPO_ROOT/.claude/loop.md" ]]; then
|
|
40
|
+
cp "$PLUGIN_ROOT/templates/_shared/loop.md" "$REPO_ROOT/.claude/loop.md"
|
|
41
|
+
BOOTSTRAP_FILES+=(.claude/loop.md)
|
|
42
|
+
fi
|
|
29
43
|
```
|
|
30
44
|
|
|
31
45
|
The command prints a JSON report (`written` / `skipped` / `preserved` / `errors` / `warnings` / `sanitizer`) and exits non-zero on any error. Surface `errors[]` to the operator; a non-empty `preserved[]` is normal and means a repo-private rule was left alone.
|
|
32
46
|
|
|
33
47
|
Also surface `sanitizer[]` (issue #1098) — `{file, line, kind, text}` records for citations that read fine inside the plugin repo and dangle once vendored (`repo-local-path`, `unresolvable-see-also`). The CLI additionally prints each one to stderr as `rules-sync: sanitizer <kind> <file>:<line> — <text>`. **Report it to the operator; do not act on it automatically** — the sanitizer never rewrites content and never changes the exit code, because silently stripping a citation would change a rule's meaning at vendoring time. A human decides whether the citation is a leak.
|
|
34
48
|
|
|
35
|
-
|
|
49
|
+
The wrapper re-reads a configured private contract and passes its required plugin
|
|
50
|
+
basenames into the canonical writer. The full set must resolve uniquely before
|
|
51
|
+
any rule is written; source/provenance validation and local preservation still
|
|
52
|
+
apply. On the public path, normal archetype filtering is unchanged. The selected
|
|
53
|
+
ID is explicit during bootstrap; later `/bootstrap --sync-rules` can use the lock.
|
|
36
54
|
|
|
37
55
|
Why: PSA-003 destructive-command safeguards require every consumer repo to carry the parallel-sessions rule. See issue #155. The `loop.md` vendor gives bare `/loop` a repo-aware maintenance prompt (issue #633 Hebel 3).
|
|
38
56
|
|
|
39
|
-
Why one writer (issue #1060): a literal `cp` from a second source directory bypasses the pre-write validator AND lands a file carrying no provenance header. On the next `--sync-rules` a headerless file is classified as a repo-private override and preserved forever — so the plugin can never update it again, and whichever rival copy is smaller silently wins. `rules
|
|
57
|
+
Why one writer (issue #1060): a literal `cp` from a second source directory bypasses the pre-write validator AND lands a file carrying no provenance header. On the next `--sync-rules` a headerless file is classified as a repo-private override and preserved forever — so the plugin can never update it again, and whichever rival copy is smaller silently wins. For every basename declared in `rules/_index.md`, `rules-sync.mjs` is the sole writer: it owns the manifest, archetype scoping, basename-collision guard and pre-write validation. S99 may deliver baseline-only rules after excluding all plugin-owned basenames.
|
|
40
58
|
|
|
41
|
-
Note: This step runs before
|
|
59
|
+
Note: This step runs before S99/D99. Both the private local rule projection and the optional public fetch filter every basename in `rules/_index.md`, including currently nonmatching scoped entries. `parallel-sessions.md` and any future plugin-owned rule therefore remain under the same single writer.
|
|
42
60
|
|
|
43
61
|
---
|
|
44
62
|
|
|
@@ -48,7 +66,13 @@ Copy the opinionated agent templates into the consumer repo:
|
|
|
48
66
|
|
|
49
67
|
```bash
|
|
50
68
|
mkdir -p "$REPO_ROOT/.claude/agents"
|
|
51
|
-
|
|
69
|
+
for _source in "$PLUGIN_ROOT/skills/bootstrap/templates/agents/"*.md; do
|
|
70
|
+
_target=".claude/agents/$(basename "$_source")"
|
|
71
|
+
if [[ ! -e "$REPO_ROOT/$_target" && ! -L "$REPO_ROOT/$_target" ]]; then
|
|
72
|
+
cp "$_source" "$REPO_ROOT/$_target"
|
|
73
|
+
BOOTSTRAP_FILES+=("$_target")
|
|
74
|
+
fi
|
|
75
|
+
done
|
|
52
76
|
```
|
|
53
77
|
|
|
54
78
|
This scaffolds 3 opinionated agents (`project-discovery`, `project-code-review`, `project-quality-gate`) following CLAUDE.md Agent Authoring Rules. Consumer repos should edit descriptions/bodies to match project specifics — but keep the frontmatter structure intact (validated by `agent-frontmatter-invalid` probe).
|
|
@@ -103,7 +127,13 @@ vault:
|
|
|
103
127
|
|
|
104
128
|
## #baseline-fetch — Step S99: (Optional) Fetch Canonical Rules + Agents from Baseline
|
|
105
129
|
|
|
106
|
-
|
|
130
|
+
For `PATH_TYPE = private` and a confirmed archetype, this step applies only the
|
|
131
|
+
validated local contract rule targets from `private-contract.md`. It is offline,
|
|
132
|
+
rechecks conditional dependencies after scaffolding, preserves existing files,
|
|
133
|
+
and fails closed on an invalid configured contract.
|
|
134
|
+
|
|
135
|
+
For `PATH_TYPE = public`, the existing remote fetch remains OPT-IN and only
|
|
136
|
+
executes when ALL of the following are true:
|
|
107
137
|
- `baseline-ref` is present in Session Config (e.g., `baseline-ref: main`)
|
|
108
138
|
- `GITLAB_TOKEN` env var is set
|
|
109
139
|
- The session-orchestrator plugin includes `scripts/lib/fetch-baseline.mjs`
|
|
@@ -116,6 +146,23 @@ Without this step, rules arrive in the repo via Clank's weekly baseline sync MRs
|
|
|
116
146
|
**Implementation:**
|
|
117
147
|
|
|
118
148
|
```bash
|
|
149
|
+
if [[ "${PATH_TYPE:-public}" = "private" ]]; then
|
|
150
|
+
export PLUGIN_ROOT REPO_ROOT CONFIRMED_ARCHETYPE
|
|
151
|
+
BASELINE_RULES_RESULT=$(node --input-type=module <<'NODE'
|
|
152
|
+
import { pathToFileURL } from 'node:url';
|
|
153
|
+
const { applyBaselineRules } = await import(pathToFileURL(`${process.env.PLUGIN_ROOT}/scripts/lib/baseline-archetypes.mjs`));
|
|
154
|
+
const result = await applyBaselineRules({
|
|
155
|
+
repoRoot: process.env.REPO_ROOT,
|
|
156
|
+
archetype: process.env.CONFIRMED_ARCHETYPE,
|
|
157
|
+
});
|
|
158
|
+
process.stdout.write(`${JSON.stringify(result)}\n`);
|
|
159
|
+
if (result.status === 'error') process.exitCode = 2;
|
|
160
|
+
NODE
|
|
161
|
+
) || exit 2
|
|
162
|
+
printf '%s\n' "$BASELINE_RULES_RESULT"
|
|
163
|
+
while IFS= read -r _file; do BOOTSTRAP_FILES+=("$_file"); done \
|
|
164
|
+
< <(printf '%s\n' "$BASELINE_RULES_RESULT" | jq -r '.created[]')
|
|
165
|
+
else
|
|
119
166
|
BASELINE_REF=$(echo "$CONFIG" | jq -r '."baseline-ref" // empty')
|
|
120
167
|
BASELINE_PROJECT_ID=$(echo "$CONFIG" | jq -r '."baseline-project-id" // "52"')
|
|
121
168
|
|
|
@@ -145,6 +192,19 @@ if [[ -n "$BASELINE_REF" && -n "${GITLAB_TOKEN:-}" && -n "${GITLAB_HOST:-}" && -
|
|
|
145
192
|
.claude/rules/ai-agent.md
|
|
146
193
|
.claude/rules/claude-code-usage.md
|
|
147
194
|
MANIFEST
|
|
195
|
+
# Every plugin-owned basename is excluded, including currently unmatched scoped
|
|
196
|
+
# rules. rules-sync is their sole writer; ownership does not depend on scope.
|
|
197
|
+
export PLUGIN_ROOT RULES_MANIFEST
|
|
198
|
+
node --input-type=module <<'NODE'
|
|
199
|
+
import { readFileSync, writeFileSync } from 'node:fs';
|
|
200
|
+
import path from 'node:path';
|
|
201
|
+
import { pathToFileURL } from 'node:url';
|
|
202
|
+
const { pluginRuleTargets } = await import(pathToFileURL(`${process.env.PLUGIN_ROOT}/scripts/lib/baseline-archetypes.mjs`));
|
|
203
|
+
const owned = new Set(pluginRuleTargets(process.env.PLUGIN_ROOT));
|
|
204
|
+
const files = readFileSync(process.env.RULES_MANIFEST, 'utf8').split('\n')
|
|
205
|
+
.filter(file => file && !owned.has(path.posix.basename(file)));
|
|
206
|
+
writeFileSync(process.env.RULES_MANIFEST, files.join('\n') + '\n');
|
|
207
|
+
NODE
|
|
148
208
|
|
|
149
209
|
echo "Fetching canonical rules from baseline (project $BASELINE_PROJECT_ID, ref $BASELINE_REF)…"
|
|
150
210
|
# The .mjs CLI is single-file: it prints ONE file body to stdout, exit 0 on success
|
|
@@ -153,10 +213,13 @@ MANIFEST
|
|
|
153
213
|
SUCCESS_LOG=$(mktemp)
|
|
154
214
|
while IFS= read -r rule_path; do
|
|
155
215
|
[[ -z "$rule_path" ]] && continue
|
|
216
|
+
_RULE_CREATED=false
|
|
217
|
+
[[ -e "$REPO_ROOT/$rule_path" || -L "$REPO_ROOT/$rule_path" ]] || _RULE_CREATED=true
|
|
156
218
|
mkdir -p "$REPO_ROOT/$(dirname "$rule_path")"
|
|
157
219
|
if node "$PLUGIN_ROOT/scripts/lib/fetch-baseline.mjs" \
|
|
158
220
|
"$BASELINE_PROJECT_ID" "$rule_path" "$BASELINE_REF" > "$REPO_ROOT/$rule_path"; then
|
|
159
221
|
printf '%s\n' "$rule_path" >> "$SUCCESS_LOG"
|
|
222
|
+
if [[ "$_RULE_CREATED" = true ]]; then BOOTSTRAP_FILES+=("$rule_path"); fi
|
|
160
223
|
else
|
|
161
224
|
# A 404 (or any error) for one rule must not abort the batch — drop the empty
|
|
162
225
|
# target the redirect created and continue with the next manifest line.
|
|
@@ -167,6 +230,8 @@ MANIFEST
|
|
|
167
230
|
if [[ -s "$SUCCESS_LOG" ]]; then
|
|
168
231
|
FETCHED_JSON=$(jq -R . < "$SUCCESS_LOG" | jq -s .)
|
|
169
232
|
LOCK_FILE="$REPO_ROOT/.claude/.baseline-fetch.lock"
|
|
233
|
+
_FETCH_LOCK_CREATED=false
|
|
234
|
+
[[ -e "$LOCK_FILE" || -L "$LOCK_FILE" ]] || _FETCH_LOCK_CREATED=true
|
|
170
235
|
mkdir -p "$REPO_ROOT/.claude"
|
|
171
236
|
FETCHED_JSON="$FETCHED_JSON" BASELINE_PROJECT_ID="$BASELINE_PROJECT_ID" \
|
|
172
237
|
BASELINE_REF="$BASELINE_REF" LOCK_FILE="$LOCK_FILE" \
|
|
@@ -183,6 +248,7 @@ MANIFEST
|
|
|
183
248
|
writeFileSync(process.env.LOCK_FILE, JSON.stringify(lock, null, 2) + '\n');
|
|
184
249
|
"
|
|
185
250
|
echo "Wrote .claude/.baseline-fetch.lock ($(wc -l < "$SUCCESS_LOG" | tr -d ' ') files)"
|
|
251
|
+
if [[ "$_FETCH_LOCK_CREATED" = true ]]; then BOOTSTRAP_FILES+=(.claude/.baseline-fetch.lock); fi
|
|
186
252
|
else
|
|
187
253
|
echo "WARNING: baseline fetch produced no files; rules will arrive via Clank sync MRs (legacy path)" >&2
|
|
188
254
|
fi
|
|
@@ -191,23 +257,39 @@ MANIFEST
|
|
|
191
257
|
else
|
|
192
258
|
echo "Skipping baseline fetch: baseline-ref / GITLAB_TOKEN / GITLAB_HOST not configured (legacy Clank-sync path)"
|
|
193
259
|
fi
|
|
260
|
+
fi
|
|
194
261
|
```
|
|
195
262
|
|
|
196
|
-
**Failure handling:**
|
|
263
|
+
**Failure handling:** A private contract/apply error aborts bootstrap. For the public optional remote path, if the fetch fails, this step DOES NOT abort bootstrap. The repo still has its scaffold; rules will arrive via the legacy Clank weekly sync MR. The user is informed via stderr.
|
|
197
264
|
|
|
198
|
-
**Idempotency:**
|
|
265
|
+
**Idempotency:** Private local rules preserve existing files and report them for review. On the public optional remote path, re-running bootstrap on an existing repo will overwrite `.claude/rules/*.md` files. Local edits to baseline rules in a repo will be lost on re-fetch — this is intentional (rules are canonical). Repo-specific extensions belong in `.claude/rules/local/*.md` (not fetched).
|
|
199
266
|
|
|
200
267
|
---
|
|
201
268
|
|
|
202
269
|
## #quality-gate-policy — Step 6.5: Quality-Gate Policy File (#183)
|
|
203
270
|
|
|
204
|
-
Write
|
|
271
|
+
Write canonical commands to `.orchestrator/policy/quality-gates.json`. A private
|
|
272
|
+
contract supplies exact test/typecheck/lint IDs, with `false` and an unavailable
|
|
273
|
+
reason for absent IDs. Public bootstrap retains package-manager defaults.
|
|
205
274
|
|
|
206
275
|
**Idempotency:** Skip this step if `.orchestrator/policy/quality-gates.json` already exists. Do not overwrite user edits.
|
|
207
276
|
|
|
208
277
|
```bash
|
|
209
278
|
POLICY_FILE="$REPO_ROOT/.orchestrator/policy/quality-gates.json"
|
|
210
|
-
if [[
|
|
279
|
+
if [[ "${PATH_TYPE:-public}" = private ]]; then
|
|
280
|
+
export PLUGIN_ROOT REPO_ROOT CONFIRMED_ARCHETYPE
|
|
281
|
+
POLICY_RESULT=$(node --input-type=module <<'NODE'
|
|
282
|
+
import { pathToFileURL } from 'node:url';
|
|
283
|
+
const { writeBaselineQualityPolicy } = await import(pathToFileURL(`${process.env.PLUGIN_ROOT}/scripts/lib/baseline-archetypes.mjs`));
|
|
284
|
+
const result = await writeBaselineQualityPolicy({ repoRoot: process.env.REPO_ROOT, archetype: process.env.CONFIRMED_ARCHETYPE });
|
|
285
|
+
process.stdout.write(`${JSON.stringify(result)}\n`);
|
|
286
|
+
if (result.status === 'error') process.exitCode = 2;
|
|
287
|
+
NODE
|
|
288
|
+
) || exit 2
|
|
289
|
+
printf '%s\n' "$POLICY_RESULT"
|
|
290
|
+
while IFS= read -r _file; do BOOTSTRAP_FILES+=("$_file"); done \
|
|
291
|
+
< <(printf '%s\n' "$POLICY_RESULT" | jq -r '.created[]')
|
|
292
|
+
elif [[ ! -e "$POLICY_FILE" && ! -L "$POLICY_FILE" ]]; then
|
|
211
293
|
mkdir -p "$REPO_ROOT/.orchestrator/policy"
|
|
212
294
|
# Detect package manager via scripts/lib/package-manager.mjs (falls back to npm defaults)
|
|
213
295
|
PM_JSON="$(node --input-type=module -e "
|
|
@@ -226,6 +308,7 @@ if [[ ! -f "$POLICY_FILE" ]]; then
|
|
|
226
308
|
"rationale": "Canonical quality-gate commands. Generated by bootstrap. Edit to change test/typecheck/lint invocations across skills. Schema: .orchestrator/policy/quality-gates.schema.json",
|
|
227
309
|
"commands": $cmds
|
|
228
310
|
}' > "$POLICY_FILE"
|
|
311
|
+
BOOTSTRAP_FILES+=(.orchestrator/policy/quality-gates.json)
|
|
229
312
|
echo "Wrote $POLICY_FILE"
|
|
230
313
|
fi
|
|
231
314
|
```
|
|
@@ -234,16 +317,18 @@ fi
|
|
|
234
317
|
|
|
235
318
|
## #state-md-scaffold — Step 6.6: STATE.md Scaffold (#184)
|
|
236
319
|
|
|
237
|
-
Scaffold a placeholder `.claude/STATE.md
|
|
320
|
+
Scaffold a placeholder `.claude/STATE.md`. <!-- path-check: example -->
|
|
321
|
+
Use the template at `skills/bootstrap/STATE.md.template`; the placeholder records `status: idle` — sessions overwrite it at Pre-Wave 1b.
|
|
238
322
|
|
|
239
|
-
**Idempotency:** Skip if `.claude/STATE.md` already exists.
|
|
323
|
+
**Idempotency:** Skip if `.claude/STATE.md` already exists. <!-- path-check: example -->
|
|
240
324
|
|
|
241
325
|
```bash
|
|
242
326
|
STATE_FILE="$REPO_ROOT/.claude/STATE.md"
|
|
243
|
-
if [[ ! -
|
|
327
|
+
if [[ ! -e "$STATE_FILE" && ! -L "$STATE_FILE" ]]; then
|
|
244
328
|
mkdir -p "$REPO_ROOT/.claude"
|
|
245
329
|
ISO_NOW="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
|
246
330
|
sed "s|<ISO>|$ISO_NOW|g" "$PLUGIN_ROOT/skills/bootstrap/STATE.md.template" > "$STATE_FILE"
|
|
331
|
+
BOOTSTRAP_FILES+=(.claude/STATE.md)
|
|
247
332
|
echo "Wrote $STATE_FILE"
|
|
248
333
|
fi
|
|
249
334
|
```
|
|
@@ -5,6 +5,9 @@
|
|
|
5
5
|
|
|
6
6
|
Deep tier is a strict superset of Standard tier. Execute all Standard-tier steps first, then the Deep-specific steps below.
|
|
7
7
|
|
|
8
|
+
Keep the inherited `BOOTSTRAP_FILES` array. Append each new governance file by
|
|
9
|
+
its relative filename when created; do not append existing files or directories.
|
|
10
|
+
|
|
8
11
|
## Step 1–8: Execute Standard Tier
|
|
9
12
|
|
|
10
13
|
Read and execute `skills/bootstrap/standard-template.md` Steps 1–8 in full. Do not skip any step.
|
|
@@ -30,7 +33,13 @@ If `VCS` is empty or `none`, skip CI pipeline, issue templates, MR/PR template,
|
|
|
30
33
|
|
|
31
34
|
## Step D1: CI Pipeline
|
|
32
35
|
|
|
33
|
-
|
|
36
|
+
When `PATH_TYPE = private`, keep the selected baseline's rendered CI and
|
|
37
|
+
`ci.profile` from `private-contract.md`. Respect `ci.required: false`; do not
|
|
38
|
+
create a generic Node pipeline for an exempt archetype. A required CI missing
|
|
39
|
+
from staging already aborts. Resolve VCS mismatch explicitly before changing
|
|
40
|
+
canonical CI. Skip the public D1 examples below and continue at D2.
|
|
41
|
+
|
|
42
|
+
For `PATH_TYPE = public`, create exactly one pipeline based on `VCS`.
|
|
34
43
|
|
|
35
44
|
### If `VCS = gitlab`: `.gitlab-ci.yml`
|
|
36
45
|
|
|
@@ -208,7 +217,7 @@ Replace `<YYYY-MM-DD>` with today's date in ISO 8601 format (e.g., `2026-04-16`)
|
|
|
208
217
|
mkdir -p "$REPO_ROOT/.gitlab/issue_templates"
|
|
209
218
|
```
|
|
210
219
|
|
|
211
|
-
|
|
220
|
+
In the consuming repository, create `.gitlab/issue_templates/Bug.md`: <!-- path-check: example -->
|
|
212
221
|
|
|
213
222
|
```markdown
|
|
214
223
|
## Summary
|
|
@@ -239,7 +248,7 @@ Write `.gitlab/issue_templates/Bug.md`:
|
|
|
239
248
|
<!-- Screenshots, logs, related issues -->
|
|
240
249
|
```
|
|
241
250
|
|
|
242
|
-
|
|
251
|
+
In the consuming repository, create `.gitlab/issue_templates/Feature.md`: <!-- path-check: example -->
|
|
243
252
|
|
|
244
253
|
```markdown
|
|
245
254
|
## Summary
|
|
@@ -334,7 +343,7 @@ labels: enhancement
|
|
|
334
343
|
mkdir -p "$REPO_ROOT/.gitlab/merge_request_templates"
|
|
335
344
|
```
|
|
336
345
|
|
|
337
|
-
|
|
346
|
+
In the consuming repository, create `.gitlab/merge_request_templates/Default.md`: <!-- path-check: example -->
|
|
338
347
|
|
|
339
348
|
```markdown
|
|
340
349
|
## Summary
|
|
@@ -492,12 +501,11 @@ If the call fails, log the structured message above and continue. Raw API respon
|
|
|
492
501
|
|
|
493
502
|
Canonical implementation in [`_shared-template.md#parallel-sessions-rule`](_shared-template.md).
|
|
494
503
|
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
repo-aware maintenance prompt. See shared partial for full shell command. Issues #155, #633, #1060.
|
|
504
|
+
Execute the shared partial's `syncBootstrapRules` action. It supplies private
|
|
505
|
+
required basenames to `scripts/lib/rules-sync.mjs`, preserving its manifest,
|
|
506
|
+
pre-write validation and local-override checks. The partial appends actual newly
|
|
507
|
+
created rule paths, and creates `.claude/loop.md` only when missing. See the
|
|
508
|
+
shared partial for the executable shell command. Issues #155, #633, #1060.
|
|
501
509
|
|
|
502
510
|
Note: Runs before D99. D99 (via inherited S99) no longer fetches `parallel-sessions.md` from the
|
|
503
511
|
baseline — that entry was removed from the S99 manifest in #1060. The baseline copy carries no
|
|
@@ -511,11 +519,13 @@ Deep tier creates both learnings and sessions metrics plus a schema-linking READ
|
|
|
511
519
|
|
|
512
520
|
```bash
|
|
513
521
|
mkdir -p "$REPO_ROOT/.orchestrator/metrics"
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
522
|
+
for _file in learnings.jsonl sessions.jsonl; do
|
|
523
|
+
if [[ ! -e "$REPO_ROOT/.orchestrator/metrics/$_file" && ! -L "$REPO_ROOT/.orchestrator/metrics/$_file" ]]; then
|
|
524
|
+
: > "$REPO_ROOT/.orchestrator/metrics/$_file"
|
|
525
|
+
BOOTSTRAP_FILES+=(".orchestrator/metrics/$_file")
|
|
526
|
+
fi
|
|
527
|
+
done
|
|
528
|
+
if [[ ! -e "$REPO_ROOT/.orchestrator/metrics/README.md" && ! -L "$REPO_ROOT/.orchestrator/metrics/README.md" ]]; then
|
|
519
529
|
cat > "$REPO_ROOT/.orchestrator/metrics/README.md" <<'README'
|
|
520
530
|
# Metrics
|
|
521
531
|
|
|
@@ -530,6 +540,8 @@ Schema: https://github.com/Kanevry/session-orchestrator
|
|
|
530
540
|
**Do NOT gitignore** — these files are project artifacts intended to persist
|
|
531
541
|
across sessions and contributors.
|
|
532
542
|
README
|
|
543
|
+
BOOTSTRAP_FILES+=(.orchestrator/metrics/README.md)
|
|
544
|
+
fi
|
|
533
545
|
```
|
|
534
546
|
|
|
535
547
|
**Idempotent.** Existing files are preserved.
|
|
@@ -547,8 +559,10 @@ Standard-template Step S99 already executed as part of "Step 1–8: Execute Stan
|
|
|
547
559
|
No additional fetch action is needed here.
|
|
548
560
|
|
|
549
561
|
If S99 ran successfully, `.claude/rules/*.md` and `.claude/.baseline-fetch.lock` are already written
|
|
550
|
-
to `$REPO_ROOT`.
|
|
551
|
-
|
|
562
|
+
to `$REPO_ROOT`. Their individual newly created paths remain in `BOOTSTRAP_FILES`
|
|
563
|
+
for the Deep commit at Step D8. If the private contract applies, S99 already
|
|
564
|
+
delivered its local filtered rule union. If public S99 was skipped, rules arrive
|
|
565
|
+
via the legacy Clank weekly sync MR path.
|
|
552
566
|
|
|
553
567
|
---
|
|
554
568
|
|
|
@@ -580,6 +594,8 @@ Write `.orchestrator/bootstrap.lock` **atomically** (mktemp + mv prevents a corr
|
|
|
580
594
|
process is interrupted mid-write):
|
|
581
595
|
|
|
582
596
|
```bash
|
|
597
|
+
_LOCK_CREATED=false
|
|
598
|
+
[[ -e "$REPO_ROOT/.orchestrator/bootstrap.lock" || -L "$REPO_ROOT/.orchestrator/bootstrap.lock" ]] || _LOCK_CREATED=true
|
|
583
599
|
_LOCK_TMP=$(mktemp "$REPO_ROOT/.orchestrator/bootstrap.lock.XXXXXX")
|
|
584
600
|
cat > "$_LOCK_TMP" << LOCK
|
|
585
601
|
# .orchestrator/bootstrap.lock
|
|
@@ -592,6 +608,7 @@ plugin-version: <session-orchestrator plugin version — read from $PLUGIN_ROOT/
|
|
|
592
608
|
bootstrapped-at: <current ISO 8601 UTC — same value as timestamp; distinct field for age-validation probe>
|
|
593
609
|
LOCK
|
|
594
610
|
mv "$_LOCK_TMP" "$REPO_ROOT/.orchestrator/bootstrap.lock"
|
|
611
|
+
if [[ "$_LOCK_CREATED" = true ]]; then BOOTSTRAP_FILES+=(.orchestrator/bootstrap.lock); fi
|
|
595
612
|
```
|
|
596
613
|
|
|
597
614
|
Set `source` using the same logic as fast-template Step 5.
|
|
@@ -604,16 +621,9 @@ Stage all created files and commit:
|
|
|
604
621
|
|
|
605
622
|
```bash
|
|
606
623
|
cd "$REPO_ROOT"
|
|
607
|
-
BOOTSTRAP_FILES=(
|
|
608
|
-
CLAUDE.md AGENTS.md .gitignore README.md .orchestrator/bootstrap.lock
|
|
609
|
-
.orchestrator/policy/quality-gates.json
|
|
610
|
-
package.json pyproject.toml tsconfig.json eslint.config.mjs .prettierrc
|
|
611
|
-
.editorconfig src/ tests/ CHANGELOG.md CODEOWNERS
|
|
612
|
-
.gitlab/ .github/ .claude/
|
|
613
|
-
)
|
|
614
624
|
# Add only the files bootstrap created — no sweeping -u/-A to avoid catching pre-existing files
|
|
615
|
-
for _f in "${BOOTSTRAP_FILES[@]}"; do
|
|
616
|
-
[[ -
|
|
625
|
+
for _f in ${BOOTSTRAP_FILES[@]+"${BOOTSTRAP_FILES[@]}"}; do
|
|
626
|
+
[[ -f "$_f" && ! -L "$_f" ]] && git add -- "$_f"
|
|
617
627
|
done
|
|
618
628
|
git commit -m "chore: bootstrap (deep)"
|
|
619
629
|
```
|
|
@@ -14,6 +14,10 @@
|
|
|
14
14
|
|
|
15
15
|
Intentionally absent: `package.json`, frameworks, tests, CI config. The feature that follows brings its own stack.
|
|
16
16
|
|
|
17
|
+
Maintain the inherited `BOOTSTRAP_FILES` array and append every newly created
|
|
18
|
+
relative file at creation. Preserve existing owner files and never reset this
|
|
19
|
+
array when Fast is inherited by Standard or Deep.
|
|
20
|
+
|
|
17
21
|
## Step 1: Ensure Git Repo is Initialized
|
|
18
22
|
|
|
19
23
|
```bash
|
|
@@ -38,7 +42,12 @@ After `public-fallback.md` completes CLAUDE.md generation, continue to Step 2b t
|
|
|
38
42
|
|
|
39
43
|
**If `PATH_TYPE = private`:**
|
|
40
44
|
|
|
41
|
-
|
|
45
|
+
For Standard/Deep inheritance, `private-contract.md` already rendered the
|
|
46
|
+
instruction file and stack into the repo. Preserve those files and continue
|
|
47
|
+
to Step 2b; use its quality-gate command mapping for missing Session Config
|
|
48
|
+
fields. Preserve the rendered README and `.gitignore` in subsequent Fast steps.
|
|
49
|
+
For a standalone Fast tier, no archetype is selected: use `public-fallback.md`'s
|
|
50
|
+
minimal Fast instruction-file generation and report `source: plugin-template`.
|
|
42
51
|
|
|
43
52
|
**Step 2b: Verify Session Config block.** After writing or updating CLAUDE.md, check for the sentinel string `## Session Config`:
|
|
44
53
|
|
|
@@ -107,7 +116,8 @@ elif ls *.ts *.js package.json 2>/dev/null | head -1 | grep -q .; then STACK="no
|
|
|
107
116
|
else STACK="generic"; fi
|
|
108
117
|
```
|
|
109
118
|
|
|
110
|
-
|
|
119
|
+
If absent, write `.gitignore` with the appropriate content and append `.gitignore`
|
|
120
|
+
to `BOOTSTRAP_FILES`. Preserve an existing file.
|
|
111
121
|
|
|
112
122
|
**Generic (no stack detected):**
|
|
113
123
|
```gitignore
|
|
@@ -166,6 +176,10 @@ Note: `.orchestrator/` is NOT gitignored — `bootstrap.lock` must be committed.
|
|
|
166
176
|
|
|
167
177
|
Vendor the canonical always-on rules from the plugin's `rules/` library into `$REPO_ROOT/.claude/rules/`. `rules/` is the single source of truth for every distributable rule — never `cp` a rule file from anywhere else.
|
|
168
178
|
|
|
179
|
+
`syncBootstrapRules` calls the canonical `scripts/lib/rules-sync.mjs` writer.
|
|
180
|
+
Standalone Fast uses ordinary plugin rules without private archetype selection;
|
|
181
|
+
inherited Fast passes the confirmed contract ID and records all created paths.
|
|
182
|
+
|
|
169
183
|
Idempotency is handled by the writer itself:
|
|
170
184
|
- Missing → create
|
|
171
185
|
- Exists, plugin-owned (first line is the `<!-- source: session-orchestrator plugin ... -->` header) and byte-identical → skip silently
|
|
@@ -175,11 +189,28 @@ Idempotency is handled by the writer itself:
|
|
|
175
189
|
Shell:
|
|
176
190
|
```bash
|
|
177
191
|
mkdir -p "$REPO_ROOT/.claude"
|
|
178
|
-
|
|
179
|
-
|
|
192
|
+
export PLUGIN_ROOT REPO_ROOT CONFIRMED_ARCHETYPE
|
|
193
|
+
RULES_RESULT=$(node --input-type=module <<'NODE'
|
|
194
|
+
import { pathToFileURL } from 'node:url';
|
|
195
|
+
const { syncBootstrapRules } = await import(pathToFileURL(`${process.env.PLUGIN_ROOT}/scripts/lib/baseline-archetypes.mjs`));
|
|
196
|
+
const result = await syncBootstrapRules({ repoRoot: process.env.REPO_ROOT,
|
|
197
|
+
archetype: process.env.CONFIRMED_ARCHETYPE || undefined, minimal: !process.env.CONFIRMED_ARCHETYPE });
|
|
198
|
+
process.stdout.write(`${JSON.stringify(result)}\n`);
|
|
199
|
+
if (result.status === 'error') process.exitCode = 2;
|
|
200
|
+
NODE
|
|
201
|
+
) || exit 2
|
|
202
|
+
printf '%s\n' "$RULES_RESULT"
|
|
203
|
+
while IFS= read -r _file; do BOOTSTRAP_FILES+=("$_file"); done \
|
|
204
|
+
< <(printf '%s\n' "$RULES_RESULT" | jq -r '.created[]')
|
|
205
|
+
if [[ ! -e "$REPO_ROOT/.claude/loop.md" && ! -L "$REPO_ROOT/.claude/loop.md" ]]; then
|
|
206
|
+
cp "$PLUGIN_ROOT/templates/_shared/loop.md" "$REPO_ROOT/.claude/loop.md"
|
|
207
|
+
BOOTSTRAP_FILES+=(.claude/loop.md)
|
|
208
|
+
fi
|
|
180
209
|
```
|
|
181
210
|
|
|
182
|
-
The command prints a JSON report
|
|
211
|
+
The command prints a JSON report and exits non-zero on any error. At standalone
|
|
212
|
+
Fast tier the lock and selected ID are absent, so scoped rules are skipped.
|
|
213
|
+
Inherited Fast delivers private required targets through the same writer.
|
|
183
214
|
|
|
184
215
|
Surface `errors[]` and `sanitizer[]` to the operator. `sanitizer[]` (issue #1098) carries `{file, line, kind, text}` records for citations that read fine inside the plugin repo and dangle once vendored (`repo-local-path`, `unresolvable-see-also`); the CLI also prints each to stderr as `rules-sync: sanitizer <kind> <file>:<line> — <text>`. **Report it, do not act on it automatically** — it never rewrites content and never changes the exit code, so a human decides whether the citation is a leak.
|
|
185
216
|
|
|
@@ -189,6 +220,9 @@ Why one writer (issue #1060): a literal `cp` from a second source directory bypa
|
|
|
189
220
|
|
|
190
221
|
## Step 4: Generate README.md
|
|
191
222
|
|
|
223
|
+
If absent, write the stub below and append `README.md` to `BOOTSTRAP_FILES`.
|
|
224
|
+
Preserve an existing README.
|
|
225
|
+
|
|
192
226
|
```markdown
|
|
193
227
|
# <REPO_NAME>
|
|
194
228
|
|
|
@@ -207,6 +241,8 @@ Write `.orchestrator/bootstrap.lock` **atomically** (mktemp + mv prevents a corr
|
|
|
207
241
|
process is interrupted mid-write):
|
|
208
242
|
|
|
209
243
|
```bash
|
|
244
|
+
_LOCK_CREATED=false
|
|
245
|
+
[[ -e "$REPO_ROOT/.orchestrator/bootstrap.lock" || -L "$REPO_ROOT/.orchestrator/bootstrap.lock" ]] || _LOCK_CREATED=true
|
|
210
246
|
_LOCK_TMP=$(mktemp "$REPO_ROOT/.orchestrator/bootstrap.lock.XXXXXX")
|
|
211
247
|
cat > "$_LOCK_TMP" << LOCK
|
|
212
248
|
# .orchestrator/bootstrap.lock
|
|
@@ -219,6 +255,7 @@ plugin-version: <session-orchestrator plugin version — read from $PLUGIN_ROOT/
|
|
|
219
255
|
bootstrapped-at: <current ISO 8601 UTC — same value as timestamp; distinct field for age-validation probe>
|
|
220
256
|
LOCK
|
|
221
257
|
mv "$_LOCK_TMP" "$REPO_ROOT/.orchestrator/bootstrap.lock"
|
|
258
|
+
if [[ "$_LOCK_CREATED" = true ]]; then BOOTSTRAP_FILES+=(.orchestrator/bootstrap.lock); fi
|
|
222
259
|
```
|
|
223
260
|
|
|
224
261
|
Set `source`:
|
|
@@ -231,10 +268,9 @@ Stage all created files and commit:
|
|
|
231
268
|
|
|
232
269
|
```bash
|
|
233
270
|
cd "$REPO_ROOT"
|
|
234
|
-
BOOTSTRAP_FILES=(CLAUDE.md AGENTS.md .gitignore README.md .orchestrator/bootstrap.lock .claude/rules/parallel-sessions.md)
|
|
235
271
|
# Add only the files bootstrap created — no sweeping -u/-A to avoid catching pre-existing files
|
|
236
|
-
for _f in "${BOOTSTRAP_FILES[@]}"; do
|
|
237
|
-
[[ -
|
|
272
|
+
for _f in ${BOOTSTRAP_FILES[@]+"${BOOTSTRAP_FILES[@]}"}; do
|
|
273
|
+
[[ -f "$_f" && ! -L "$_f" ]] && git add -- "$_f"
|
|
238
274
|
done
|
|
239
275
|
git commit -m "chore: bootstrap (fast)"
|
|
240
276
|
```
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
After executing this algorithm, report:
|
|
9
9
|
|
|
10
10
|
- `RECOMMENDED_TIER`: `fast` | `standard` | `deep`
|
|
11
|
-
- `RECOMMENDED_ARCHETYPE`:
|
|
11
|
+
- `RECOMMENDED_ARCHETYPE`: a validated private contract ID, one of the public IDs, or `null`
|
|
12
12
|
- `HEURISTIC_REASON`: one sentence explaining the recommendation (shown to user)
|
|
13
13
|
- `ARCHETYPE_CONFIDENCE`: `high` | `low` (used to decide whether to ask the optional second question)
|
|
14
14
|
|
|
@@ -54,7 +54,13 @@ Examples:
|
|
|
54
54
|
|
|
55
55
|
**Fast tier:** Always `RECOMMENDED_ARCHETYPE = null`, `ARCHETYPE_CONFIDENCE = high`. No stack needed — skip to output.
|
|
56
56
|
|
|
57
|
-
**Private path (
|
|
57
|
+
**Private path (valid configured contract):** Use `BOOTSTRAP_CONTRACT.selected.id`
|
|
58
|
+
from Phase 0.5 and set `ARCHETYPE_CONFIDENCE = high` when markers match. An
|
|
59
|
+
explicit user ID must pass the reader's `--archetype` lookup and takes priority.
|
|
60
|
+
If no markers match, set `RECOMMENDED_ARCHETYPE = null` and
|
|
61
|
+
`ARCHETYPE_CONFIDENCE = low`; select from the returned ordered catalog using
|
|
62
|
+
`private-contract.md` before Standard/Deep scaffolding. Detection follows the
|
|
63
|
+
exported signal predicates and priority; no public default applies here.
|
|
58
64
|
|
|
59
65
|
**Public path + Standard or Deep:** Scan the prompt for these signals:
|
|
60
66
|
|
|
@@ -66,7 +72,7 @@ Examples:
|
|
|
66
72
|
| python, py, data, daten, ml, machine learning, api (python context), django, fastapi, flask, pandas, numpy | `python-uv` | high |
|
|
67
73
|
| Ambiguous — prompt mentions multiple stacks, no clear frontend/backend split, or is too vague (e.g., "Ich brauche ein Projekt", "neues Repo", "etwas bauen") | `node-minimal` (safe default) | `low` |
|
|
68
74
|
|
|
69
|
-
|
|
75
|
+
On the public path, when `ARCHETYPE_CONFIDENCE = low`, the bootstrap skill will ask a second `AskUserQuestion` to confirm the archetype. `node-minimal` is the pre-selected default for that question.
|
|
70
76
|
|
|
71
77
|
## Step 5: Output
|
|
72
78
|
|
|
@@ -74,7 +80,7 @@ Return all four values to `SKILL.md` Phase 1:
|
|
|
74
80
|
|
|
75
81
|
```
|
|
76
82
|
RECOMMENDED_TIER: fast | standard | deep
|
|
77
|
-
RECOMMENDED_ARCHETYPE: static-html | node-minimal | nextjs-minimal | python-uv | null
|
|
83
|
+
RECOMMENDED_ARCHETYPE: <validated private ID> | static-html | node-minimal | nextjs-minimal | python-uv | null
|
|
78
84
|
HEURISTIC_REASON: <one sentence>
|
|
79
85
|
ARCHETYPE_CONFIDENCE: high | low
|
|
80
86
|
```
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# Configured Baseline Bootstrap
|
|
2
|
+
|
|
3
|
+
Use this flow only after `public-fallback.md` returned `PATH_TYPE = private`.
|
|
4
|
+
The configured local baseline owns the archetype catalog. The plugin consumes
|
|
5
|
+
its validated, reduced export; it carries no private archetype table.
|
|
6
|
+
|
|
7
|
+
## Select
|
|
8
|
+
|
|
9
|
+
For Standard/Deep, use the `selected.id` returned by Phase 0.5 when repository
|
|
10
|
+
markers match. An explicit owner-supplied ID takes precedence: validate it with
|
|
11
|
+
`--archetype` before accepting it. A user description can help present choices,
|
|
12
|
+
but cannot invent a catalog ID. When `selected` is null, present the returned
|
|
13
|
+
`archetypes` in `order`, showing their runtime, package manager, UI/API and deploy
|
|
14
|
+
metadata. Ask for the needed selection; paginate if the UI limits option count.
|
|
15
|
+
Do not substitute a public default for missing evidence or an invalid choice.
|
|
16
|
+
|
|
17
|
+
Once selected, set `CONFIRMED_ARCHETYPE` and refresh the contract:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
BOOTSTRAP_CONTRACT=$(node "$PLUGIN_ROOT/scripts/baseline-archetypes.mjs" \
|
|
21
|
+
--repo "$REPO_ROOT" --archetype "$CONFIRMED_ARCHETYPE") || exit 2
|
|
22
|
+
export BOOTSTRAP_CONTRACT
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
`status: error` aborts before scaffolding. Its reason is safe to report; do not
|
|
26
|
+
print baseline paths, raw producer diagnostics, or private catalog files.
|
|
27
|
+
`insufficient-evidence` is a selection state, not permission to use `node-minimal`.
|
|
28
|
+
Fast tier has no archetype; use the plugin's minimal instruction-file flow and
|
|
29
|
+
skip this file's scaffold/rules actions until upgrading to Standard/Deep.
|
|
30
|
+
|
|
31
|
+
## Scaffold
|
|
32
|
+
|
|
33
|
+
Execute this before Standard inherits the Fast steps. It runs only the local
|
|
34
|
+
baseline's `render_archetype_dir`, `render_shared_and_substitute`, and
|
|
35
|
+
`render_archetype_metadata` functions in temporary staging. It excludes all
|
|
36
|
+
staged rules; S99 below and `rules-sync` own rule delivery. It never invokes the
|
|
37
|
+
interactive setup script, package installation, Git, or a remote service.
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
export PLUGIN_ROOT REPO_ROOT CONFIRMED_ARCHETYPE REPO_NAME
|
|
41
|
+
SCAFFOLD_RESULT=$(node --input-type=module <<'NODE'
|
|
42
|
+
import { pathToFileURL } from 'node:url';
|
|
43
|
+
const { scaffoldBaselineArchetype } = await import(pathToFileURL(`${process.env.PLUGIN_ROOT}/scripts/lib/baseline-archetypes.mjs`));
|
|
44
|
+
const result = await scaffoldBaselineArchetype({
|
|
45
|
+
repoRoot: process.env.REPO_ROOT,
|
|
46
|
+
archetype: process.env.CONFIRMED_ARCHETYPE,
|
|
47
|
+
projectName: process.env.REPO_NAME,
|
|
48
|
+
});
|
|
49
|
+
process.stdout.write(`${JSON.stringify(result)}\n`);
|
|
50
|
+
if (result.status === 'error') process.exitCode = 2;
|
|
51
|
+
NODE
|
|
52
|
+
) || exit 2
|
|
53
|
+
printf '%s\n' "$SCAFFOLD_RESULT"
|
|
54
|
+
while IFS= read -r _file; do BOOTSTRAP_FILES+=("$_file"); done \
|
|
55
|
+
< <(printf '%s\n' "$SCAFFOLD_RESULT" | jq -r '.created[]')
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
The report lists relative `created` and `preserved` files plus `unavailableGates`. Add only `created`
|
|
59
|
+
files to `BOOTSTRAP_FILES`; an existing file is preserved for owner review.
|
|
60
|
+
All sources and destinations are checked for symlinks before the first copy.
|
|
61
|
+
The renderer's commands are fixed function calls; exported `commands` and
|
|
62
|
+
`qualityGates[].command` remain data throughout lookup and staging.
|
|
63
|
+
|
|
64
|
+
Continue Fast's common steps, preserving the rendered instruction files,
|
|
65
|
+
README, manifests and configuration. Then skip Standard's four public stack
|
|
66
|
+
sections and continue at Step 3a, S99 and the lock/quality-policy steps.
|
|
67
|
+
|
|
68
|
+
## Expectations
|
|
69
|
+
|
|
70
|
+
Use `selected.runtimes`, `packageManagers`, `ui`, `api`, `deploy`, `commands`,
|
|
71
|
+
`qualityGates`, `ci`, and `browserAutomation` as the scaffold expectations.
|
|
72
|
+
Keep rendered command documentation and CI. Staging normalizes new Session
|
|
73
|
+
Config `test-command`, `typecheck-command`, and `lint-command` from exactly
|
|
74
|
+
matching `qualityGates[].id` values (`test`, `typecheck`, `lint`). An absent gate
|
|
75
|
+
gets the literal failing command `false` and an unavailable explanation, so a
|
|
76
|
+
later generic gate runner cannot report an unsupported check as passing. No
|
|
77
|
+
other ID is silently relabeled. Existing owner instruction files are preserved.
|
|
78
|
+
|
|
79
|
+
For private verification, enumerate the selected `qualityGates` and report each
|
|
80
|
+
declared result. Separately report absent test/typecheck/lint slots as
|
|
81
|
+
unavailable; do not execute their `false` placeholders as if they were declared
|
|
82
|
+
checks, or claim that all three generic checks passed. Command execution is a
|
|
83
|
+
later explicit bootstrap step, separate from lookup and staging. Step 6.5 writes
|
|
84
|
+
the same exact mapping to a new quality policy, whose commands take precedence
|
|
85
|
+
at runtime. Existing owner policy is preserved; report any divergence for review.
|
|
86
|
+
The generic quality runner is unchanged.
|
|
87
|
+
|
|
88
|
+
Deep D1 preserves the baseline CI and its `ci.profile`. If `ci.required` is
|
|
89
|
+
false, do not create a public Node CI pipeline. If true and the baseline did
|
|
90
|
+
not render CI, staging fails. VCS mismatch or a required translation needs an
|
|
91
|
+
explicit owner choice; do not silently replace the canonical CI with a public
|
|
92
|
+
template. The remaining Deep governance steps apply normally.
|
|
93
|
+
|
|
94
|
+
## Rules
|
|
95
|
+
|
|
96
|
+
S99 re-reads the selected contract after rendering, so dependency-conditional
|
|
97
|
+
targets include the new package manifest. `ruleTargets` is the exported union;
|
|
98
|
+
`pluginRuleTargets` is its intersection with all basenames in `rules/_index.md`.
|
|
99
|
+
Only `baselineRules` may be copied from the local baseline. Every source is a
|
|
100
|
+
validated relative file under `.claude/rules/` or
|
|
101
|
+
`templates/shared/.claude/rules/`, and every target belongs to that union.
|
|
102
|
+
Existing rules are preserved. Plugin rule basenames, including
|
|
103
|
+
`parallel-sessions.md`, are written only by `rules-sync.mjs`. Step 3a invokes
|
|
104
|
+
`syncBootstrapRules`, which reloads the contract and passes `pluginRuleTargets`
|
|
105
|
+
as the writer's validated required basenames. This delivers private requirements
|
|
106
|
+
even when plugin scope tags do not name that archetype. The same action backs
|
|
107
|
+
later `/bootstrap --sync-rules`, resolving the explicit ID, then the lock ID,
|
|
108
|
+
then repository markers. Public/default rule selection remains unchanged.
|
|
109
|
+
Later sync of a valid Fast/null lock without stack markers also uses ordinary
|
|
110
|
+
plugin rules; a configured contract must still validate before that refresh.
|
|
111
|
+
|
|
112
|
+
## Created files
|
|
113
|
+
|
|
114
|
+
Keep one `BOOTSTRAP_FILES` array throughout inherited Fast/Standard/Deep steps.
|
|
115
|
+
Each writer appends only relative files it actually creates; do not replace the
|
|
116
|
+
array with a stack-specific list. Existing owner files and directories are never
|
|
117
|
+
added merely because they exist. A repeated writer reporting `created: []`
|
|
118
|
+
leaves accumulated paths intact. New governance files are appended individually
|
|
119
|
+
at creation, and commit steps consume this accumulated list without broad globs.
|