devflow-kit 3.7.0 → 3.9.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/CHANGELOG.md +479 -1
- package/README.md +15 -15
- package/dist/agents/code.md +6 -8
- package/dist/agents/design.md +1 -1
- package/dist/agents/fix.md +7 -8
- package/dist/agents/git.md +3 -3
- package/dist/agents/harden.md +1 -1
- package/dist/agents/refactor.md +2 -4
- package/dist/agents/review.md +4 -4
- package/dist/agents/skim.md +2 -2
- package/dist/agents/triage.md +9 -2
- package/dist/cli/commands/capture.js +1 -1
- package/dist/cli/commands/curation-move-io.js +102 -0
- package/dist/cli/commands/curation-move-step.js +374 -0
- package/dist/cli/commands/curation.js +808 -0
- package/dist/cli/commands/gate-level-prompts.js +428 -0
- package/dist/cli/commands/gates.js +35 -11
- package/dist/cli/commands/init-seed.js +11 -8
- package/dist/cli/commands/init.js +244 -57
- package/dist/cli/commands/memory.js +60 -13
- package/dist/cli/commands/prompt-io.js +37 -0
- package/dist/cli/commands/uninstall.js +157 -17
- package/dist/cli.js +2 -2
- package/dist/commands/bug-analysis.md +25 -36
- package/dist/commands/code-review.md +40 -44
- package/dist/commands/debug.md +5 -5
- package/dist/commands/dynamic-build.md +26 -25
- package/dist/commands/dynamic-plan.md +5 -5
- package/dist/commands/dynamic-profile.md +5 -5
- package/dist/commands/dynamic-tickets.md +5 -5
- package/dist/commands/explore.md +6 -6
- package/dist/commands/implement.md +53 -82
- package/dist/commands/plan.md +6 -6
- package/dist/commands/release.md +5 -5
- package/dist/commands/research.md +6 -6
- package/dist/commands/resolve.md +39 -41
- package/dist/commands/self-review.md +5 -13
- package/dist/core/area-pause-notice.js +44 -0
- package/dist/core/assets.js +20 -20
- package/dist/core/curate-tuning-config.js +5 -6
- package/dist/core/curation-move-notice.js +84 -0
- package/dist/core/curation-move-skip.js +35 -0
- package/dist/core/curation-move.js +35 -0
- package/dist/core/curation-queue-cleanup.js +135 -0
- package/dist/core/curation-store.js +99 -0
- package/dist/core/{learning-variants.js → curation-variants.js} +65 -41
- package/dist/core/echo-value.js +11 -5
- package/dist/core/evidence-policy.js +11 -9
- package/dist/core/feature-switch.js +95 -19
- package/dist/core/fs-atomic.js +1 -1
- package/dist/core/gate-level.js +10 -2
- package/dist/core/git.js +16 -14
- package/dist/core/ledger-root.js +82 -22
- package/dist/core/linked-path.js +4 -4
- package/dist/core/manifest-lock.js +238 -0
- package/dist/core/manifest.js +58 -14
- package/dist/core/migrations.js +1 -13
- package/dist/core/observations.js +2 -2
- package/dist/core/plugins.js +19 -19
- package/dist/core/pool.js +26 -0
- package/dist/core/project-paths.js +103 -34
- package/dist/core/queue-drain.js +2 -2
- package/dist/core/tracked-areas.js +159 -0
- package/dist/core/tracker.js +1 -1
- package/dist/{learning-off → curation-off}/agents/code.md +6 -8
- package/dist/{learning-off → curation-off}/agents/fix.md +7 -8
- package/dist/{learning-off → curation-off}/agents/refactor.md +2 -4
- package/dist/{learning-off → curation-off}/agents/review.md +3 -3
- package/dist/{learning-off → curation-off}/agents/triage.md +8 -1
- package/dist/{learning-off → curation-off}/commands/bug-analysis.md +20 -31
- package/dist/{learning-off → curation-off}/commands/code-review.md +37 -41
- package/dist/{learning-off → curation-off}/commands/debug.md +2 -2
- package/dist/{learning-off → curation-off}/commands/dynamic-build.md +23 -22
- package/dist/{learning-off → curation-off}/commands/explore.md +2 -2
- package/dist/{learning-off → curation-off}/commands/implement.md +50 -79
- package/dist/{learning-off → curation-off}/commands/plan.md +2 -2
- package/dist/{learning-off → curation-off}/commands/resolve.md +36 -38
- package/dist/{learning-off → curation-off}/commands/self-review.md +2 -10
- package/dist/hud/components/{learning-counts.js → curation-counts.js} +63 -17
- package/dist/hud/config.js +1 -1
- package/dist/hud/index.js +6 -6
- package/dist/hud/render.js +3 -3
- package/dist/skills/git/references/pr/post-resolution-summary.md +12 -11
- package/dist/skills/git/references/pr/post-review-summary.md +12 -11
- package/dist/skills/git/references/pr/update-pr-evidence.md +2 -2
- package/dist/skills/git/references/pr/validate-branch.md +8 -5
- package/dist/skills/git/references/publication-gate.md +6 -7
- package/dist/skills/git/references/tracker/github/ensure-pr-ready.md +13 -5
- package/dist/skills/git/references/tracker/github/manage-debt.md +6 -2
- package/dist/skills/git/references/tracker/jira/ensure-pr-ready.md +13 -5
- package/dist/skills/git/references/tracker/jira/manage-debt.md +6 -2
- package/dist/skills/git/references/tracker/linear/ensure-pr-ready.md +13 -5
- package/dist/skills/git/references/tracker/linear/manage-debt.md +6 -2
- package/dist/targets/claude-code/{learning-install.js → curation-install.js} +85 -65
- package/dist/targets/claude-code/installer.js +15 -15
- package/dist/targets/claude-code/language-stamp.js +5 -5
- package/dist/targets/claude-code/post-install.js +2 -2
- package/dist/targets/claude-code/tracker-servers.js +1 -1
- package/package.json +3 -2
- package/src/assets/agents/_partials/_code.mds +11 -11
- package/src/assets/agents/code.mds +6 -6
- package/src/assets/agents/curate.md +8 -8
- package/src/assets/agents/debug.mds +6 -6
- package/src/assets/agents/design.mds +18 -18
- package/src/assets/agents/evaluate.md +6 -12
- package/src/assets/agents/fix.mds +7 -6
- package/src/assets/agents/git.mds +3 -3
- package/src/assets/agents/harden.mds +7 -7
- package/src/assets/agents/knowledge.mds +23 -23
- package/src/assets/agents/refactor.mds +2 -2
- package/src/assets/agents/research.mds +15 -15
- package/src/assets/agents/review.mds +43 -43
- package/src/assets/agents/skim.mds +11 -11
- package/src/assets/agents/triage.mds +29 -22
- package/src/assets/agents/validate.md +30 -50
- package/src/assets/commands/_partials/_decisions.mds +22 -20
- package/src/assets/commands/_partials/_engine.mds +8 -8
- package/src/assets/commands/_partials/_knowledge.mds +29 -15
- package/src/assets/commands/_partials/_preamble.mds +4 -4
- package/src/assets/commands/_partials/_settings.mds +3 -3
- package/src/assets/commands/_partials/_wave.mds +7 -7
- package/src/assets/commands/bug-analysis.mds +37 -48
- package/src/assets/commands/code-review.mds +53 -57
- package/src/assets/commands/debug.mds +14 -14
- package/src/assets/commands/dynamic-build.mds +38 -37
- package/src/assets/commands/dynamic-plan.mds +22 -22
- package/src/assets/commands/dynamic-profile.mds +2 -2
- package/src/assets/commands/dynamic-tickets.mds +8 -8
- package/src/assets/commands/explore.mds +20 -20
- package/src/assets/commands/implement.mds +77 -98
- package/src/assets/commands/plan.mds +27 -27
- package/src/assets/commands/release.mds +12 -12
- package/src/assets/commands/research.mds +19 -19
- package/src/assets/commands/resolve.mds +66 -60
- package/src/assets/commands/self-review.mds +20 -20
- package/src/assets/mds/git/_ops.mds +9 -2
- package/src/assets/mds/git/_ops_pr.mds +21 -11
- package/src/assets/mds/git/_ops_steps.mds +20 -4
- package/src/assets/mds/git/_pr.mds +21 -18
- package/src/assets/mds/git/_references.mds +6 -7
- package/src/assets/mds/tracker/_github.mds +1 -4
- package/src/assets/mds/tracker/_jira.mds +1 -4
- package/src/assets/mds/tracker/_linear.mds +1 -4
- package/src/assets/rules/quality.md +1 -0
- package/src/assets/scripts/ci-wait.cjs +389 -92
- package/src/assets/scripts/hooks/background-memory-update +81 -3
- package/src/assets/scripts/hooks/capture-prompt +12 -12
- package/src/assets/scripts/hooks/capture-question +11 -11
- package/src/assets/scripts/hooks/capture-turn +12 -12
- package/src/assets/scripts/hooks/{learning-lock → curation-lock} +2 -2
- package/src/assets/scripts/hooks/curation-move +293 -0
- package/src/assets/scripts/hooks/ensure-devflow-init +45 -13
- package/src/assets/scripts/hooks/ensure-proxy +4 -4
- package/src/assets/scripts/hooks/ensure-root-gitignore +4 -4
- package/src/assets/scripts/hooks/git-marker +81 -0
- package/src/assets/scripts/hooks/json-helper.cjs +176 -51
- package/src/assets/scripts/hooks/json-parse +1 -1
- package/src/assets/scripts/hooks/lib/curation-move.cjs +1582 -0
- package/src/assets/scripts/hooks/lib/{learning-store.cjs → curation-store.cjs} +308 -122
- package/src/assets/scripts/hooks/lib/decisions-format.cjs +3 -3
- package/src/assets/scripts/hooks/lib/mkdir-lock.cjs +24 -7
- package/src/assets/scripts/hooks/lib/project-paths.cjs +132 -39
- package/src/assets/scripts/hooks/lib/render-decisions.cjs +42 -22
- package/src/assets/scripts/hooks/lib/tracked-areas.cjs +452 -0
- package/src/assets/scripts/hooks/memory-permission +10 -2
- package/src/assets/scripts/hooks/memory-worker +12 -1
- package/src/assets/scripts/hooks/pre-compact-memory +17 -16
- package/src/assets/scripts/hooks/queue-append +444 -102
- package/src/assets/scripts/hooks/resolve-project-root +2 -2
- package/src/assets/scripts/hooks/session-start-context +198 -72
- package/src/assets/scripts/hooks/session-start-memory +42 -43
- package/src/assets/scripts/lib/project-config.cjs +12 -5
- package/src/assets/scripts/pr-evidence.cjs +5 -2
- package/src/assets/scripts/resolve-base.cjs +1043 -0
- package/src/assets/scripts/resolve-settings.cjs +283 -45
- package/src/assets/scripts/verify-evidence.cjs +307 -75
- package/src/assets/skills/agent-references/SKILL.md +11 -2
- package/src/assets/skills/agent-references/references/commands/implement-levels.md +29 -0
- package/src/assets/skills/agent-references/references/commands/implement-revalidate.md +6 -4
- package/src/assets/skills/agent-references/references/commands/resolve-levels.md +25 -0
- package/src/assets/skills/agent-references/references/synthesize/review.md +4 -4
- package/src/assets/skills/agent-references/references/triage/severity-tiers.md +43 -0
- package/src/assets/skills/agent-references/references/validate/passed-alone.md +14 -0
- package/src/assets/skills/apply-decisions/SKILL.md +1 -1
- package/src/assets/skills/docs-framework/SKILL.md +7 -7
- package/src/assets/skills/docs-framework/references/patterns.md +3 -4
- package/src/assets/skills/quality-gates/SKILL.md +1 -1
- package/src/assets/skills/worktree-support/references/roots.md +2 -2
- package/templates/lint-pack/.lint-pack.conf +86 -0
- package/templates/lint-pack/README.md +190 -0
- package/templates/lint-pack/lint-pack.sh +905 -0
- package/dist/cli/commands/learning.js +0 -554
- package/dist/core/learning-queue-cleanup.js +0 -27
- package/dist/core/learning-store.js +0 -61
- /package/dist/{learning-off → curation-off}/agents/debug.md +0 -0
- /package/dist/{learning-off → curation-off}/agents/design.md +0 -0
- /package/dist/{learning-off → curation-off}/agents/harden.md +0 -0
- /package/dist/{learning-off → curation-off}/agents/knowledge.md +0 -0
- /package/dist/{learning-off → curation-off}/agents/research.md +0 -0
- /package/dist/{learning-off → curation-off}/agents/skim.md +0 -0
- /package/dist/{learning-off → curation-off}/commands/dynamic-plan.md +0 -0
- /package/dist/{learning-off → curation-off}/commands/dynamic-profile.md +0 -0
- /package/dist/{learning-off → curation-off}/commands/dynamic-tickets.md +0 -0
- /package/dist/{learning-off → curation-off}/commands/release.md +0 -0
- /package/dist/{learning-off → curation-off}/commands/research.md +0 -0
|
@@ -0,0 +1,428 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gate-level prompt helpers for devflow init.
|
|
3
|
+
*
|
|
4
|
+
* CLI-layer module: prompt-rendering logic lives in src/cli/commands/, the closed
|
|
5
|
+
* set of levels and its parser stay in src/core/gate-level.ts.
|
|
6
|
+
*
|
|
7
|
+
* `devflow init` asks for the MACHINE gate level, `features.gateLevel` in
|
|
8
|
+
* `~/.devflow/manifest.json`, the same field `devflow gates --set` writes. It never
|
|
9
|
+
* writes the personal `gateLevel` in a repository's `.devflow/config.json`, which
|
|
10
|
+
* still overrides the machine level there.
|
|
11
|
+
*
|
|
12
|
+
* The wizard gate keys on `modePromptShown` (was the Setup-mode p.select prompt
|
|
13
|
+
* actually shown?), never on the mode name, so --recommended (flag, no prompt) and
|
|
14
|
+
* the non-TTY fallback keep their promptless contracts: they carry the stored value
|
|
15
|
+
* through untouched. `--gate-level <level>` sets the level on every path with no
|
|
16
|
+
* prompt. runGateLevelStep and resolveGateLevelForInit never call process.exit() or
|
|
17
|
+
* throw: callers own the cancel idiom (p.cancel + process.exit(0)).
|
|
18
|
+
*
|
|
19
|
+
* The shared DI seam (PromptOutcome, WizardPromptIO, clackNote, clackSelect) is
|
|
20
|
+
* defined once in prompt-io.ts and imported here, never re-declared.
|
|
21
|
+
*
|
|
22
|
+
* Init never writes a level the user did not choose. readManifest() reads a manifest
|
|
23
|
+
* it refuses as no manifest at all, yet `devflow gates` and the settings resolver
|
|
24
|
+
* still read that file's level, so init reads the raw file in that case
|
|
25
|
+
* (storedGateLevelFromRaw): a level found there is kept as stored, and a file that
|
|
26
|
+
* cannot be read at all is named as unreadable, never shown as the default.
|
|
27
|
+
*/
|
|
28
|
+
import { clackNote, clackSelect, shouldRunPromptedWizardStep, } from './prompt-io.js';
|
|
29
|
+
import { DEFAULT_GATE_LEVEL, GATE_LEVELS, MALFORMED_GATE_LEVEL_READS_AS, parseGateLevel, readGateManifest, } from '../../core/gate-level.js';
|
|
30
|
+
// ── Shared prompt content ──────────────────────────────────────────────────────
|
|
31
|
+
/** Message shown on the gate level select prompt. */
|
|
32
|
+
export const GATE_LEVEL_SELECT_MESSAGE = 'Gate level for this machine';
|
|
33
|
+
/**
|
|
34
|
+
* The one-line effect of each level, as the select hint and the catalogue show it.
|
|
35
|
+
* Each hint says what its level does. GATE_LEVEL_EFFECT in gates.ts says which commands
|
|
36
|
+
* read the level. Change a hint when what a level does changes. A command that reads the
|
|
37
|
+
* level and has no rule that changes a phase leaves the hints true, so it changes
|
|
38
|
+
* GATE_LEVEL_EFFECT alone. One test pins the exact text of both tables, so a change to
|
|
39
|
+
* either fails it until you check the other table and update the pin; further rows check
|
|
40
|
+
* the clauses the two tables share (the lint pack level, the levels that run fewer review
|
|
41
|
+
* focuses and the levels that skip Polish). The clauses that lean skips Harden on a
|
|
42
|
+
* docs-only diff, that standard and lean run one Evaluate pass and that standard and lean
|
|
43
|
+
* apply severity tiers in /resolve have no facet row in `tests/gate-level-prompts.test.ts`:
|
|
44
|
+
* the docs guard checks each at every doc site, against its row in the /implement or
|
|
45
|
+
* /resolve level reference.
|
|
46
|
+
*/
|
|
47
|
+
export const GATE_LEVEL_HINTS = Object.freeze({
|
|
48
|
+
full: 'the most checking: every review focus, the full planning shape and Polish',
|
|
49
|
+
standard: 'fewer review focuses and planning agents, no Polish in /implement and /resolve, severity tiers in /resolve, and one Evaluate pass in /implement (the default)',
|
|
50
|
+
lean: 'the least checking, and no Polish in /implement and /resolve; /resolve also applies severity tiers; /implement also runs one Evaluate pass, has Validate run the project lint pack, and skips Harden on a docs-only diff',
|
|
51
|
+
});
|
|
52
|
+
/** Build clack select options for the gate level list, most to least checking. */
|
|
53
|
+
export function gateLevelChoices() {
|
|
54
|
+
return GATE_LEVELS.map(level => ({ value: level, label: level, hint: GATE_LEVEL_HINTS[level] }));
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Format a padded level catalogue suitable for a clack note body.
|
|
58
|
+
* Produces: ` standard fewer review focuses and planning agents, no Polish in /implement and /resolve, severity tiers in /resolve, and one Evaluate pass in /implement (the default)`
|
|
59
|
+
*/
|
|
60
|
+
export function formatGateLevelCatalogue() {
|
|
61
|
+
const width = Math.max(...GATE_LEVELS.map(level => level.length));
|
|
62
|
+
return 'Levels:\n' + GATE_LEVELS.map(level => ` ${level.padEnd(width)} ${GATE_LEVEL_HINTS[level]}`).join('\n');
|
|
63
|
+
}
|
|
64
|
+
/** `features.gateLevel` of a raw manifest, exactly as stored; `undefined` for an absent key. */
|
|
65
|
+
function rawGateLevelOf(raw) {
|
|
66
|
+
const features = raw.features;
|
|
67
|
+
if (typeof features !== 'object' || features === null)
|
|
68
|
+
return undefined;
|
|
69
|
+
return Object.getOwnPropertyDescriptor(features, 'gateLevel')?.value;
|
|
70
|
+
}
|
|
71
|
+
const UNREADABLE_GATE_LEVEL = Object.freeze({ origin: 'unreadable', value: undefined });
|
|
72
|
+
/**
|
|
73
|
+
* Whether a raw value can be written back as JSON. The file parses a value that nests
|
|
74
|
+
* deeper than the serializer's stack, and writing that value back fails, which would stop
|
|
75
|
+
* init from ever replacing the manifest that stores it.
|
|
76
|
+
*/
|
|
77
|
+
function serializes(value) {
|
|
78
|
+
try {
|
|
79
|
+
JSON.stringify(value);
|
|
80
|
+
return true;
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
return false;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Classify the stored level from the raw read of a manifest that readManifest()
|
|
88
|
+
* returned null for. Pure — the caller reads the file.
|
|
89
|
+
*
|
|
90
|
+
* absent a first install: nothing stored
|
|
91
|
+
* rejected, with a key the key's value, raw: a malformed value or `null` passes
|
|
92
|
+
* through untouched, never defaulted, narrowed or healed
|
|
93
|
+
* rejected, no key nothing stored
|
|
94
|
+
* corrupt unreadable: no level can be known
|
|
95
|
+
* object readManifest() would accept it, so its level is an ordinary
|
|
96
|
+
* stored level (a file that changed between the two reads)
|
|
97
|
+
* a value that does not serialize
|
|
98
|
+
* unreadable, whatever the file: the level cannot be kept
|
|
99
|
+
*/
|
|
100
|
+
export function storedGateLevelFromRaw(read) {
|
|
101
|
+
switch (read.kind) {
|
|
102
|
+
case 'absent':
|
|
103
|
+
return { origin: 'manifest', value: undefined };
|
|
104
|
+
case 'corrupt':
|
|
105
|
+
return UNREADABLE_GATE_LEVEL;
|
|
106
|
+
case 'object':
|
|
107
|
+
case 'rejected': {
|
|
108
|
+
const value = rawGateLevelOf(read.raw);
|
|
109
|
+
if (value !== undefined && !serializes(value))
|
|
110
|
+
return UNREADABLE_GATE_LEVEL;
|
|
111
|
+
return { origin: read.kind === 'rejected' && value !== undefined ? 'rejected' : 'manifest', value };
|
|
112
|
+
}
|
|
113
|
+
default: {
|
|
114
|
+
const exhaustive = read;
|
|
115
|
+
return exhaustive;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Where init finds the stored level when it reads the machine manifest: the manifest
|
|
121
|
+
* readManifest() returned, else the raw file. Never throws — readGateManifest() reports
|
|
122
|
+
* every failure as a result.
|
|
123
|
+
*
|
|
124
|
+
* This is the level the run replaces, which the summary names. Every writer that
|
|
125
|
+
* replaces the manifest reads it through this one function, so `devflow init` and
|
|
126
|
+
* `devflow init --hud-only` report the same stored level. `--reset` forgets a level in
|
|
127
|
+
* what it writes (see {@link carriedGateLevel}), not in what it reports, except for a
|
|
128
|
+
* manifest it cannot read: there is no level to name, and the reset forgets it anyway.
|
|
129
|
+
*/
|
|
130
|
+
export async function readStoredGateLevel(devflowDir, manifest, reset) {
|
|
131
|
+
if (manifest !== null)
|
|
132
|
+
return { origin: 'manifest', value: manifest.features.gateLevel };
|
|
133
|
+
const stored = storedGateLevelFromRaw(await readGateManifest(devflowDir));
|
|
134
|
+
return reset && stored.origin === 'unreadable' ? { origin: 'manifest', value: undefined } : stored;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* The level a full init starts from, and where it was found: what the manifest it writes
|
|
138
|
+
* holds unless --gate-level or the wizard answer sets another. Pure.
|
|
139
|
+
*
|
|
140
|
+
* The seed holds the level of the manifest readManifest() returned, and none after
|
|
141
|
+
* --reset. When readManifest() returned none, the raw reading is the level to keep: init
|
|
142
|
+
* never writes a level the user did not choose, and `init --hud-only` keeps the same one.
|
|
143
|
+
* That holds for a refused manifest and for a file that changed between the two reads.
|
|
144
|
+
* --reset forgets it.
|
|
145
|
+
*/
|
|
146
|
+
export function carriedGateLevel(input) {
|
|
147
|
+
const { manifest, reset, stored, seedLevel } = input;
|
|
148
|
+
if (manifest !== null || reset)
|
|
149
|
+
return { origin: 'manifest', value: seedLevel };
|
|
150
|
+
return stored;
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Classify a raw stored value, and where it was found (default: the manifest init
|
|
154
|
+
* reads). Pure and total — the one place that tells absent, valid and malformed
|
|
155
|
+
* apart.
|
|
156
|
+
*
|
|
157
|
+
* `unreadable` is an absent value from a manifest that could not be read: no value
|
|
158
|
+
* was read, so none is shown as the default. A value that is present is classified
|
|
159
|
+
* as itself whatever the origin.
|
|
160
|
+
*/
|
|
161
|
+
export function classifyGateLevel(stored, origin = 'manifest') {
|
|
162
|
+
if (stored === undefined)
|
|
163
|
+
return origin === 'unreadable' ? { kind: 'unreadable' } : { kind: 'default' };
|
|
164
|
+
const parsed = parseGateLevel(stored);
|
|
165
|
+
return parsed.ok ? { kind: 'level', level: parsed.value } : { kind: 'malformed' };
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* The level that applies for a reading, as every reader gives it: the level itself,
|
|
169
|
+
* the default for an absent or unknown one, and the fold for a malformed one.
|
|
170
|
+
*/
|
|
171
|
+
function appliedLevel(reading) {
|
|
172
|
+
switch (reading.kind) {
|
|
173
|
+
case 'level':
|
|
174
|
+
return reading.level;
|
|
175
|
+
case 'malformed':
|
|
176
|
+
return MALFORMED_GATE_LEVEL_READS_AS;
|
|
177
|
+
case 'default':
|
|
178
|
+
case 'unreadable':
|
|
179
|
+
return DEFAULT_GATE_LEVEL;
|
|
180
|
+
default: {
|
|
181
|
+
const exhaustive = reading;
|
|
182
|
+
return exhaustive;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* A malformed value, in the words of the `Machine:` line of `devflow gates`
|
|
188
|
+
* (MACHINE_INVALID_LINE in gates.ts): a parity test holds the two to the same text.
|
|
189
|
+
* The raw value is never shown.
|
|
190
|
+
*/
|
|
191
|
+
const MALFORMED_TEXT = `invalid (manifest.json; reads as ${MALFORMED_GATE_LEVEL_READS_AS})`;
|
|
192
|
+
/** A reading as the note header and the summary line name it. */
|
|
193
|
+
function describeReading(reading) {
|
|
194
|
+
switch (reading.kind) {
|
|
195
|
+
case 'default':
|
|
196
|
+
return `${DEFAULT_GATE_LEVEL} (default)`;
|
|
197
|
+
case 'level':
|
|
198
|
+
return reading.level;
|
|
199
|
+
case 'malformed':
|
|
200
|
+
return MALFORMED_TEXT;
|
|
201
|
+
case 'unreadable':
|
|
202
|
+
return 'unknown (the stored gate level cannot be read)';
|
|
203
|
+
default: {
|
|
204
|
+
const exhaustive = reading;
|
|
205
|
+
return exhaustive;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Name the level a stored manifest value stands for, for the note header and the
|
|
211
|
+
* summary line. Pure function — no I/O, no side effects.
|
|
212
|
+
*
|
|
213
|
+
* undefined no level is recorded: `standard (default)`
|
|
214
|
+
* a level that level
|
|
215
|
+
* otherwise malformed: `invalid`, and the level it reads as, as `devflow gates` words it
|
|
216
|
+
*
|
|
217
|
+
* `standard` carries the `(default)` marker only when nothing is recorded, so a
|
|
218
|
+
* reader can tell "I chose this" from "this is what devflow does when nobody chooses".
|
|
219
|
+
*/
|
|
220
|
+
export function describeGateLevel(stored) {
|
|
221
|
+
return describeReading(classifyGateLevel(stored));
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* The level the select starts on: the stored level on a re-init, the default on a
|
|
225
|
+
* first install, after --reset or when the stored level cannot be read, and the level
|
|
226
|
+
* a malformed value reads as. Pure and total.
|
|
227
|
+
*/
|
|
228
|
+
export function gateLevelPromptSeed(stored, origin = 'manifest') {
|
|
229
|
+
return appliedLevel(classifyGateLevel(stored, origin));
|
|
230
|
+
}
|
|
231
|
+
/** The "Current setting" lines of the prompt note, from the stored value and where it was found. */
|
|
232
|
+
function currentSettingLines(stored, origin) {
|
|
233
|
+
switch (origin) {
|
|
234
|
+
case 'manifest':
|
|
235
|
+
return `Current setting: ${describeGateLevel(stored)}`;
|
|
236
|
+
case 'rejected':
|
|
237
|
+
return `Current setting: ${describeGateLevel(stored)}\n` +
|
|
238
|
+
'It comes from a manifest that devflow rejects. Init replaces that manifest and keeps this level unless you choose another.';
|
|
239
|
+
case 'unreadable':
|
|
240
|
+
return 'Current setting: unknown\n' +
|
|
241
|
+
`The stored gate level cannot be read, so ${DEFAULT_GATE_LEVEL} applies until you choose a level.`;
|
|
242
|
+
default: {
|
|
243
|
+
const exhaustive = origin;
|
|
244
|
+
return exhaustive;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
// ── The --gate-level boundary ──────────────────────────────────────────────────
|
|
249
|
+
/**
|
|
250
|
+
* Parse the --gate-level option at the boundary, before any prompt or write.
|
|
251
|
+
*
|
|
252
|
+
* Strict — reject, never repair — so `Lean` or an empty value exits instead of
|
|
253
|
+
* silently resolving. `--hud-only` installs only the HUD and writes no level, so
|
|
254
|
+
* the pair is refused rather than the flag silently ignored.
|
|
255
|
+
*
|
|
256
|
+
* Returns undefined when the option was not passed.
|
|
257
|
+
*/
|
|
258
|
+
export function resolveGateLevelInitState(option, hudOnly) {
|
|
259
|
+
if (typeof option !== 'string')
|
|
260
|
+
return undefined;
|
|
261
|
+
const parsed = parseGateLevel(option);
|
|
262
|
+
if (!parsed.ok)
|
|
263
|
+
return { ok: false, error: parsed.error };
|
|
264
|
+
if (hudOnly) {
|
|
265
|
+
return {
|
|
266
|
+
ok: false,
|
|
267
|
+
error: '--gate-level cannot be used with --hud-only, which installs only the HUD. Use devflow gates --set, or run init without --hud-only.',
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
return { ok: true, value: parsed.value };
|
|
271
|
+
}
|
|
272
|
+
// ── Gate predicate ─────────────────────────────────────────────────────────────
|
|
273
|
+
/**
|
|
274
|
+
* Determines whether the gate-level wizard step should run for a given init invocation.
|
|
275
|
+
*
|
|
276
|
+
* The gate table, keyed on modePromptShown and never on the mode name, is
|
|
277
|
+
* `shouldRunPromptedWizardStep` in prompt-io.ts: the one authority for both wizard
|
|
278
|
+
* paths, which reach it through resolveGateLevelForInit. `--gate-level <level>` is
|
|
279
|
+
* the CLI override that suppresses the step on every path.
|
|
280
|
+
*
|
|
281
|
+
* Pure predicate — no side effects, fully testable without a TTY.
|
|
282
|
+
*/
|
|
283
|
+
export function shouldRunGateLevelStep(input) {
|
|
284
|
+
return shouldRunPromptedWizardStep(input);
|
|
285
|
+
}
|
|
286
|
+
/**
|
|
287
|
+
* Build the real (clack) GateLevelPromptIO adapter.
|
|
288
|
+
* Delegates the shared note + select to the shared adapters (prompt-io.ts).
|
|
289
|
+
* Translates clack's cancel symbol into the PromptOutcome discriminated union.
|
|
290
|
+
*/
|
|
291
|
+
export function buildClackGateLevelPrompts() {
|
|
292
|
+
return {
|
|
293
|
+
note: clackNote,
|
|
294
|
+
select: (opts) => clackSelect(opts),
|
|
295
|
+
selectLevel: (opts) => clackSelect(opts),
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
/**
|
|
299
|
+
* Run the gate-level wizard step.
|
|
300
|
+
*
|
|
301
|
+
* Flow:
|
|
302
|
+
* 1. Note — "Current setting: …" header, what the level is, and the catalogue.
|
|
303
|
+
* 2. Level select — full / standard / lean with a one-line effect each, starting
|
|
304
|
+
* on the stored level (re-init) or the default (first install). `p.select`,
|
|
305
|
+
* never `p.confirm`: Enter-through must be an INFORMED keep of a named level.
|
|
306
|
+
*
|
|
307
|
+
* `stored` is the raw manifest value (see FeatureSeed.gateLevel): the step shows
|
|
308
|
+
* and starts from it, and never narrows it. `storedOrigin` says where it was found
|
|
309
|
+
* (default: the manifest); an unreadable level is shown as unknown, not as the default,
|
|
310
|
+
* and the select then starts on the level that applies.
|
|
311
|
+
*
|
|
312
|
+
* Returns:
|
|
313
|
+
* {kind:'resolved', level} — the chosen level.
|
|
314
|
+
* {kind:'cancelled'} — user pressed Escape; caller runs p.cancel + process.exit(0).
|
|
315
|
+
*
|
|
316
|
+
* Invariants:
|
|
317
|
+
* - Never calls process.exit(), never throws.
|
|
318
|
+
* - All I/O is routed through the `prompts` parameter (injectable for tests).
|
|
319
|
+
*/
|
|
320
|
+
export async function runGateLevelStep(opts) {
|
|
321
|
+
const { stored, storedOrigin = 'manifest', prompts } = opts;
|
|
322
|
+
prompts.note(`${currentSettingLines(stored, storedOrigin)}\n\n` +
|
|
323
|
+
'Sets how much checking /code-review, /plan and /implement apply on this\n' +
|
|
324
|
+
'machine. A personal "gateLevel" in a repository\'s .devflow/config.json\n' +
|
|
325
|
+
'overrides it in that repository. Change it later with\n' +
|
|
326
|
+
'devflow gates --set <level>.\n\n' +
|
|
327
|
+
formatGateLevelCatalogue(), 'Gate level');
|
|
328
|
+
const outcome = await prompts.selectLevel({
|
|
329
|
+
message: GATE_LEVEL_SELECT_MESSAGE,
|
|
330
|
+
options: gateLevelChoices(),
|
|
331
|
+
initialValue: gateLevelPromptSeed(stored, storedOrigin),
|
|
332
|
+
});
|
|
333
|
+
if (outcome.kind === 'cancel')
|
|
334
|
+
return { kind: 'cancelled' };
|
|
335
|
+
return { kind: 'resolved', level: outcome.value };
|
|
336
|
+
}
|
|
337
|
+
/**
|
|
338
|
+
* Decide the machine gate level for one init wizard path.
|
|
339
|
+
*
|
|
340
|
+
* Precedence: --gate-level > wizard answer > the stored value (a first install
|
|
341
|
+
* stores none, and the default then applies at read time). Both wizard paths call
|
|
342
|
+
* this with their own `mode`; they share one gate, one cancel idiom and one prompt
|
|
343
|
+
* adapter, so the paths cannot drift.
|
|
344
|
+
*/
|
|
345
|
+
export async function resolveGateLevelForInit(opts) {
|
|
346
|
+
const { cliLevel, stored, storedOrigin, mode, modePromptShown, isTTY, prompts } = opts;
|
|
347
|
+
if (shouldRunGateLevelStep({ mode, modePromptShown, isTTY, hasCliOverride: cliLevel !== undefined })) {
|
|
348
|
+
const step = await runGateLevelStep({ stored, storedOrigin, prompts });
|
|
349
|
+
return step.kind === 'cancelled' ? { kind: 'cancelled' } : { kind: 'resolved', level: step.level, carried: false };
|
|
350
|
+
}
|
|
351
|
+
return cliLevel === undefined
|
|
352
|
+
? { kind: 'resolved', level: stored, carried: true }
|
|
353
|
+
: { kind: 'resolved', level: cliLevel, carried: false };
|
|
354
|
+
}
|
|
355
|
+
// ── Summary ────────────────────────────────────────────────────────────────────
|
|
356
|
+
/**
|
|
357
|
+
* The gate-level row of the Recommended settings note, from the level the run will
|
|
358
|
+
* record (or the stored value it keeps) and where the stored value was found. Pure.
|
|
359
|
+
*
|
|
360
|
+
* It names the level the way the post-install summary does. A level that could not be
|
|
361
|
+
* read, when this run records none, is shown as unknown, never as the default.
|
|
362
|
+
*/
|
|
363
|
+
export function formatGateLevelRow(level, origin) {
|
|
364
|
+
const reading = classifyGateLevel(level, origin);
|
|
365
|
+
return reading.kind === 'unreadable'
|
|
366
|
+
? 'unknown (cannot be read, so init records none)'
|
|
367
|
+
: describeReading(reading);
|
|
368
|
+
}
|
|
369
|
+
/**
|
|
370
|
+
* ` (was X)` when a run changed the level that applies, else empty. It compares the
|
|
371
|
+
* levels the two readings stand for, so a malformed value written back as it was
|
|
372
|
+
* stored, or accepted at the prompt as the level it reads as, is no change. An
|
|
373
|
+
* unreadable prior has no level to name, so none is invented.
|
|
374
|
+
*/
|
|
375
|
+
function replacedLevelNote(prior, recorded) {
|
|
376
|
+
if (prior.kind === 'unreadable')
|
|
377
|
+
return '';
|
|
378
|
+
const was = appliedLevel(prior);
|
|
379
|
+
return was === appliedLevel(recorded) ? '' : ` (was ${was})`;
|
|
380
|
+
}
|
|
381
|
+
/**
|
|
382
|
+
* The gate-level lines of init's post-install summary, from the state the run acted
|
|
383
|
+
* on (D-INIT-REAL-OUTCOME): the level this run recorded when the manifest reached
|
|
384
|
+
* disk, else the level the manifest on disk still holds, with a warning that the gate
|
|
385
|
+
* level did not change. Pure — the caller renders.
|
|
386
|
+
*
|
|
387
|
+
* A run that changes the level that applies names the one it replaced: `(was lean)`.
|
|
388
|
+
*
|
|
389
|
+
* `priorOrigin` says where the prior level was found (default: the manifest):
|
|
390
|
+
*
|
|
391
|
+
* rejected the level came from a manifest that was replaced; when `kept` is
|
|
392
|
+
* true, a warning says init kept it
|
|
393
|
+
* unreadable no level could be read; a run that recorded none warns that standard
|
|
394
|
+
* now applies and how to set the level again
|
|
395
|
+
*
|
|
396
|
+
* `kept` is true only when the manifest was written with the stored level carried
|
|
397
|
+
* over: no --reset, no --gate-level and no prompt answer chose the level. A level the
|
|
398
|
+
* user chose is a choice, even when it equals the stored one.
|
|
399
|
+
*/
|
|
400
|
+
export function formatGateLevelSummary(input) {
|
|
401
|
+
const origin = input.priorOrigin ?? 'manifest';
|
|
402
|
+
const prior = classifyGateLevel(input.priorLevel, origin);
|
|
403
|
+
if (!input.manifestWritten) {
|
|
404
|
+
return [{
|
|
405
|
+
level: 'warn',
|
|
406
|
+
message: `Gate level: ${describeReading(prior)} — this run could not save the manifest, so the gate level did not change`,
|
|
407
|
+
}];
|
|
408
|
+
}
|
|
409
|
+
const recorded = classifyGateLevel(input.level, origin);
|
|
410
|
+
if (recorded.kind === 'unreadable') {
|
|
411
|
+
return [{
|
|
412
|
+
level: 'warn',
|
|
413
|
+
message: `Gate level: the stored gate level could not be read, so init recorded none and ${DEFAULT_GATE_LEVEL} applies (the machine default); set it again with devflow gates --set <level>`,
|
|
414
|
+
}];
|
|
415
|
+
}
|
|
416
|
+
const lines = [{
|
|
417
|
+
level: 'info',
|
|
418
|
+
message: `Gate level: ${describeReading(recorded)}${replacedLevelNote(prior, recorded)} — the machine default; change it with devflow gates --set <level>`,
|
|
419
|
+
}];
|
|
420
|
+
if (origin === 'rejected' && input.kept) {
|
|
421
|
+
lines.push({
|
|
422
|
+
level: 'warn',
|
|
423
|
+
message: 'Init kept the stored gate level while it replaced a manifest that devflow rejects',
|
|
424
|
+
});
|
|
425
|
+
}
|
|
426
|
+
return lines;
|
|
427
|
+
}
|
|
428
|
+
//# sourceMappingURL=gate-level-prompts.js.map
|
|
@@ -21,24 +21,38 @@ import { Command } from 'commander';
|
|
|
21
21
|
import * as path from 'path';
|
|
22
22
|
import * as p from '@clack/prompts';
|
|
23
23
|
import color from 'picocolors';
|
|
24
|
-
import { DEFAULT_GATE_LEVEL, GATE_LEVELS, machineGateLevel, parseGateLevel, readGateManifest, writeMachineGateLevel, } from '../../core/gate-level.js';
|
|
24
|
+
import { DEFAULT_GATE_LEVEL, GATE_LEVELS, MALFORMED_GATE_LEVEL_READS_AS, machineGateLevel, parseGateLevel, readGateManifest, writeMachineGateLevel, } from '../../core/gate-level.js';
|
|
25
25
|
import { describeEchoedValue } from '../../core/echo-value.js';
|
|
26
26
|
import { loadSettingsModule, settingsSourceFile, trackedConfigWarning, } from '../../core/evidence-policy.js';
|
|
27
27
|
import { getDevFlowDirectory } from '../../targets/claude-code/claude-paths.js';
|
|
28
28
|
// ── Wording ────────────────────────────────────────────────────────────────────
|
|
29
29
|
/**
|
|
30
30
|
* What each level means, in one line. Each line says what the word stands for and
|
|
31
|
-
* not what a command does with it.
|
|
31
|
+
* not what a command does with it. The line for MALFORMED_GATE_LEVEL_READS_AS says
|
|
32
|
+
* that a value that is not a level reads as it.
|
|
32
33
|
*/
|
|
33
34
|
export const GATE_LEVEL_MEANINGS = Object.freeze({
|
|
34
35
|
full: 'the most checking; any value that is not a level also reads as full',
|
|
35
36
|
standard: 'the default when no level is set',
|
|
36
37
|
lean: 'the least checking',
|
|
37
38
|
});
|
|
38
|
-
/**
|
|
39
|
-
|
|
39
|
+
/**
|
|
40
|
+
* Which commands read the level today; each later command that reads it updates this text.
|
|
41
|
+
*
|
|
42
|
+
* The init prompt says what each level does in GATE_LEVEL_HINTS (gate-level-prompts.ts).
|
|
43
|
+
* Change the hints too when what a level does changes. A command that reads the level and
|
|
44
|
+
* has no rule that changes a phase leaves the hints true, so it changes this text alone.
|
|
45
|
+
* One test pins the exact text of both tables, so a change to either fails it until you
|
|
46
|
+
* check the other table and update the pin; further rows check the clauses the two tables
|
|
47
|
+
* share (the lint pack level, the levels that run fewer review focuses and the levels that
|
|
48
|
+
* skip Polish). The clauses that lean skips Harden on a docs-only diff, that standard
|
|
49
|
+
* and lean run one Evaluate pass and that standard and lean apply severity tiers in /resolve
|
|
50
|
+
* have no facet row in `tests/gate-level-prompts.test.ts`: the docs guard checks each at
|
|
51
|
+
* every doc site, against its row in the /implement or /resolve level reference.
|
|
52
|
+
*/
|
|
53
|
+
export const GATE_LEVEL_EFFECT = '/code-review and /plan read the level: standard and lean run fewer review focuses and fewer planning agents. At lean, /implement has Validate run the project\'s lint pack. /implement and /resolve also read the level and name it in their report; at standard and lean they skip Polish, and full keeps it. At lean, /implement skips Harden on a docs-only diff. At standard and lean, /implement runs one Evaluate pass and at most one Fix round. At standard and lean, /resolve applies severity tiers: it fixes or escalates every security finding, fixes CRITICAL, HIGH and severe MEDIUM findings in the branch\'s own code, fixes prose-only MEDIUM findings with text edits alone, and sends lower findings and pre-existing non-security findings to one backlog issue.';
|
|
40
54
|
const MACHINE_MANIFEST_NAME = 'manifest.json';
|
|
41
|
-
const MACHINE_INVALID_LINE = `invalid (${MACHINE_MANIFEST_NAME}; reads as
|
|
55
|
+
const MACHINE_INVALID_LINE = `invalid (${MACHINE_MANIFEST_NAME}; reads as ${MALFORMED_GATE_LEVEL_READS_AS})`;
|
|
42
56
|
const VALID_LEVELS = GATE_LEVELS.join(', ');
|
|
43
57
|
const VALID_LEVELS_OR = `${GATE_LEVELS.slice(0, -1).join(', ')}, or ${GATE_LEVELS[GATE_LEVELS.length - 1]}`;
|
|
44
58
|
/** The resolved settings, or null when the resolver is unusable or throws despite its contract. */
|
|
@@ -54,8 +68,8 @@ function manifestState(read) {
|
|
|
54
68
|
switch (read.kind) {
|
|
55
69
|
case 'absent': return 'absent';
|
|
56
70
|
case 'object': return 'readable';
|
|
57
|
-
case '
|
|
58
|
-
case '
|
|
71
|
+
case 'rejected': return 'rejected';
|
|
72
|
+
case 'corrupt': return 'unreadable';
|
|
59
73
|
default: {
|
|
60
74
|
const exhaustive = read;
|
|
61
75
|
return exhaustive;
|
|
@@ -114,9 +128,19 @@ function machineLine(machine) {
|
|
|
114
128
|
return `Machine: ${machine}`;
|
|
115
129
|
}
|
|
116
130
|
function manifestWarning(status) {
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
131
|
+
switch (status.manifest) {
|
|
132
|
+
case 'absent':
|
|
133
|
+
case 'readable':
|
|
134
|
+
return null;
|
|
135
|
+
case 'rejected':
|
|
136
|
+
return `Manifest at ${status.manifestPath} is a manifest that devflow rejects; devflow init will replace this file and keep a gate level stored in it unless you choose another level or use --reset.`;
|
|
137
|
+
case 'unreadable':
|
|
138
|
+
return `Manifest at ${status.manifestPath} cannot be read by devflow gates; devflow init will replace this file. Init keeps a gate level stored in it only if init can read the file. If init reports that it could not read the level, set it again with devflow gates --set <level>.`;
|
|
139
|
+
default: {
|
|
140
|
+
const exhaustive = status.manifest;
|
|
141
|
+
return exhaustive;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
120
144
|
}
|
|
121
145
|
/**
|
|
122
146
|
* Render a {@link GateStatus}. Pure and total over every `kind`.
|
|
@@ -231,7 +255,7 @@ function levelsHelp() {
|
|
|
231
255
|
export const gatesCommand = new Command('gates')
|
|
232
256
|
.description('Show or set the machine\'s default gate level')
|
|
233
257
|
.option('--status', 'Show the gate level in effect here, which layer decided it, and the machine default')
|
|
234
|
-
.option(
|
|
258
|
+
.option(`--set <${GATE_LEVELS.join('|')}>`, `Set the machine's default gate level: ${VALID_LEVELS_OR}`)
|
|
235
259
|
.addHelpText('after', `\nGate levels:\n${levelsHelp()}\n\n` +
|
|
236
260
|
`The default is ${DEFAULT_GATE_LEVEL}. --set writes only the machine default. A personal .devflow/config.json ` +
|
|
237
261
|
'"gateLevel" overrides it in one repository; no command writes that key.\n' +
|
|
@@ -21,7 +21,7 @@ export const FEATURE_DEFAULTS = {
|
|
|
21
21
|
memory: true,
|
|
22
22
|
hud: true,
|
|
23
23
|
knowledge: true,
|
|
24
|
-
|
|
24
|
+
curation: true,
|
|
25
25
|
rules: true,
|
|
26
26
|
proxy: false,
|
|
27
27
|
behavior: false,
|
|
@@ -35,7 +35,7 @@ export const FEATURE_DEFAULTS = {
|
|
|
35
35
|
* manifest.features, with registry defaults when the manifest is absent.
|
|
36
36
|
*
|
|
37
37
|
* D-FEATURES-NARROW-ONLY (src/core/feature-switch.ts): the machine switches for
|
|
38
|
-
* memory,
|
|
38
|
+
* memory, curation and knowledge are recorded in the manifest alone (a repository
|
|
39
39
|
* only narrows them at read time), so the seed takes no per-repo input at all. Seeding from whatever repo init happens to run in
|
|
40
40
|
* would flip the switch for EVERY repo as a side effect — a stale per-repo
|
|
41
41
|
* `true` would silently re-enable a feature the user turned off. State-aware
|
|
@@ -60,12 +60,12 @@ export function resolveSeedFeatures(manifest) {
|
|
|
60
60
|
const tracker = { ...rawTracker };
|
|
61
61
|
const memory = manifest?.features.memory ?? FEATURE_DEFAULTS.memory;
|
|
62
62
|
const knowledge = manifest?.features.knowledge ?? FEATURE_DEFAULTS.knowledge;
|
|
63
|
-
const
|
|
63
|
+
const curation = manifest?.features.curation ?? FEATURE_DEFAULTS.curation;
|
|
64
64
|
// The raw stored level, with no default operator: `??` would turn a stored `null`
|
|
65
65
|
// into the default, and init would then write the default over a value the
|
|
66
66
|
// fold reads as the strictest level.
|
|
67
67
|
const gateLevel = manifest?.features.gateLevel;
|
|
68
|
-
return { ambient, memory, hud, knowledge,
|
|
68
|
+
return { ambient, memory, hud, knowledge, curation, rules, proxy, behavior, compliance, tracker, gateLevel };
|
|
69
69
|
}
|
|
70
70
|
/**
|
|
71
71
|
* Resolve the flag record for the init seed.
|
|
@@ -310,6 +310,11 @@ export function resolveResetGatedInputs(reset, manifest, projectConfig, settings
|
|
|
310
310
|
* undefined means "user did not specify this flag, keep the seed value".
|
|
311
311
|
*
|
|
312
312
|
* Applies explicit --ambient/--no-ambient etc. passed alongside --recommended.
|
|
313
|
+
*
|
|
314
|
+
* The machine gate level is not a toggle: `resolveGateLevelForInit` (gate-level-prompts.ts)
|
|
315
|
+
* is the one place that decides it (--gate-level, then the wizard answer, then the stored
|
|
316
|
+
* value), and init holds that decision itself. The result carries the seed's raw value only
|
|
317
|
+
* to stay a complete FeatureSeed.
|
|
313
318
|
*/
|
|
314
319
|
export function applyCliToggles(base, toggles) {
|
|
315
320
|
return {
|
|
@@ -317,15 +322,13 @@ export function applyCliToggles(base, toggles) {
|
|
|
317
322
|
memory: toggles.memory ?? base.memory,
|
|
318
323
|
hud: toggles.hud ?? base.hud,
|
|
319
324
|
knowledge: toggles.knowledge ?? base.knowledge,
|
|
320
|
-
|
|
325
|
+
curation: toggles.curation ?? base.curation,
|
|
321
326
|
rules: toggles.rules ?? base.rules,
|
|
322
327
|
proxy: toggles.proxy ?? base.proxy,
|
|
323
328
|
behavior: toggles.behavior ?? base.behavior,
|
|
324
329
|
compliance: toggles.compliance ?? base.compliance,
|
|
325
330
|
tracker: toggles.tracker ?? base.tracker,
|
|
326
|
-
|
|
327
|
-
// through. Only `undefined` means "not specified": `null` is a value, not a gap.
|
|
328
|
-
gateLevel: toggles.gateLevel !== undefined ? toggles.gateLevel : base.gateLevel,
|
|
331
|
+
gateLevel: base.gateLevel,
|
|
329
332
|
};
|
|
330
333
|
}
|
|
331
334
|
//# sourceMappingURL=init-seed.js.map
|