devflow-kit 2.3.0 → 2.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +177 -0
- package/README.md +86 -18
- package/dist/agents/git.md +824 -0
- package/dist/cli/commands/agents.js +6 -1
- package/dist/cli/commands/attribution-prompts.js +144 -0
- package/dist/cli/commands/compliance-prompts.js +7 -11
- package/dist/cli/commands/compliance.js +23 -1
- package/dist/cli/commands/init-seed.js +69 -30
- package/dist/cli/commands/init.js +551 -77
- package/dist/cli/commands/install-report.js +205 -0
- package/dist/cli/commands/knowledge/index.js +2 -2
- package/dist/cli/commands/knowledge/toggle.js +27 -37
- package/dist/cli/commands/learning.js +37 -30
- package/dist/cli/commands/memory.js +79 -69
- package/dist/cli/commands/prompt-io.js +38 -0
- package/dist/cli/commands/proxy.js +91 -31
- package/dist/cli/commands/security.js +76 -16
- package/dist/cli/commands/skills.js +53 -7
- package/dist/cli/commands/tracker-prompts.js +145 -0
- package/dist/cli/commands/tracker.js +405 -0
- package/dist/cli/commands/uninstall.js +233 -77
- package/dist/cli.js +2 -0
- package/dist/commands/bug-analysis.md +22 -4
- package/dist/commands/code-review.md +44 -15
- package/dist/commands/debug.md +20 -6
- package/dist/commands/dynamic-build.md +289 -67
- package/dist/commands/dynamic-plan.md +60 -21
- package/dist/commands/dynamic-profile.md +1 -1
- package/dist/commands/dynamic-tickets.md +58 -8
- package/dist/commands/explore.md +2 -2
- package/dist/commands/implement.md +241 -53
- package/dist/commands/plan.md +88 -17
- package/dist/commands/release.md +64 -17
- package/dist/commands/resolve.md +138 -58
- package/dist/commands/self-review.md +2 -2
- package/dist/core/agent-models.js +55 -12
- package/dist/core/assets.js +58 -2
- package/dist/core/evidence-policy.js +147 -0
- package/dist/core/feature-config.js +130 -64
- package/dist/core/feature-switch.js +112 -0
- package/dist/core/flags.js +149 -8
- package/dist/core/manifest.js +33 -7
- package/dist/core/mds-variants.js +861 -0
- package/dist/core/model-discovery.js +12 -1
- package/dist/core/plugins.js +357 -9
- package/dist/core/project-paths.js +1 -1
- package/dist/core/proxy-log.js +8 -4
- package/dist/core/proxy-state.js +100 -43
- package/dist/core/reference-sweep.js +136 -0
- package/dist/core/tracker.js +407 -0
- package/dist/skills/git/references/decision-markers.md +19 -0
- package/dist/skills/git/references/learn-conventions.md +56 -0
- package/dist/skills/git/references/pr/check-ci-status.md +14 -0
- package/dist/skills/git/references/pr/check-merge-readiness.md +28 -0
- package/dist/skills/git/references/pr/ensure-pr-ready.md +24 -0
- package/dist/skills/git/references/pr/fetch-review-threads.md +22 -0
- package/dist/skills/git/references/pr/post-resolution-summary.md +40 -0
- package/dist/skills/git/references/pr/post-review-summary.md +42 -0
- package/dist/skills/git/references/pr/resolve-review-threads.md +35 -0
- package/dist/skills/git/references/pr/update-pr-evidence.md +14 -0
- package/dist/skills/git/references/pr/validate-branch.md +18 -0
- package/dist/skills/git/references/publication-gate.md +13 -0
- package/dist/skills/git/references/tracker/_mcp.md +153 -0
- package/dist/skills/git/references/tracker/github/associate-release.md +18 -0
- package/dist/skills/git/references/tracker/github/backlink-shipped-issues.md +40 -0
- package/dist/skills/git/references/tracker/github/create-release.md +11 -0
- package/dist/skills/git/references/tracker/github/ensure-pr-ready.md +16 -0
- package/dist/skills/git/references/tracker/github/ensure-traceable-issue.md +69 -0
- package/dist/skills/git/references/tracker/github/fetch-issue.md +32 -0
- package/dist/skills/git/references/tracker/github/fetch-issues-batch.md +17 -0
- package/dist/skills/git/references/tracker/github/gather-release-evidence.md +19 -0
- package/dist/skills/git/references/tracker/github/manage-debt.md +101 -0
- package/dist/skills/git/references/tracker/github/post-wave-report.md +28 -0
- package/dist/skills/git/references/tracker/github/setup-task.md +26 -0
- package/dist/skills/git/references/tracker/jira/associate-release.md +18 -0
- package/dist/skills/git/references/tracker/jira/backlink-shipped-issues.md +49 -0
- package/dist/skills/git/references/tracker/jira/create-release.md +17 -0
- package/dist/skills/git/references/tracker/jira/ensure-pr-ready.md +22 -0
- package/dist/skills/git/references/tracker/jira/ensure-traceable-issue.md +53 -0
- package/dist/skills/git/references/tracker/jira/fetch-issue.md +14 -0
- package/dist/skills/git/references/tracker/jira/fetch-issues-batch.md +15 -0
- package/dist/skills/git/references/tracker/jira/gather-release-evidence.md +18 -0
- package/dist/skills/git/references/tracker/jira/manage-debt.md +37 -0
- package/dist/skills/git/references/tracker/jira/post-wave-report.md +33 -0
- package/dist/skills/git/references/tracker/jira/setup-task.md +31 -0
- package/dist/skills/git/references/tracker/linear/associate-release.md +18 -0
- package/dist/skills/git/references/tracker/linear/backlink-shipped-issues.md +53 -0
- package/dist/skills/git/references/tracker/linear/create-release.md +17 -0
- package/dist/skills/git/references/tracker/linear/ensure-pr-ready.md +22 -0
- package/dist/skills/git/references/tracker/linear/ensure-traceable-issue.md +53 -0
- package/dist/skills/git/references/tracker/linear/fetch-issue.md +14 -0
- package/dist/skills/git/references/tracker/linear/fetch-issues-batch.md +15 -0
- package/dist/skills/git/references/tracker/linear/gather-release-evidence.md +18 -0
- package/dist/skills/git/references/tracker/linear/manage-debt.md +37 -0
- package/dist/skills/git/references/tracker/linear/post-wave-report.md +33 -0
- package/dist/skills/git/references/tracker/linear/setup-task.md +32 -0
- package/dist/skills/git/references/trust-rule.md +7 -0
- package/dist/targets/claude-code/installer.js +1213 -31
- package/dist/targets/claude-code/legacy.js +5 -0
- package/dist/targets/claude-code/post-install.js +303 -104
- package/dist/targets/claude-code/tracker-install.js +161 -0
- package/package.json +4 -3
- package/src/assets/agents/code.md +42 -4
- package/src/assets/agents/design.md +1 -1
- package/src/assets/agents/git.mds +827 -0
- package/src/assets/agents/knowledge.md +1 -1
- package/src/assets/agents/learning.md +11 -0
- package/src/assets/agents/synthesize.md +1 -1
- package/src/assets/agents/test.md +16 -5
- package/src/assets/agents/tracker.md +467 -0
- package/src/assets/agents/validate.md +7 -5
- package/src/assets/commands/_partials/_engine.mds +11 -9
- package/src/assets/commands/_partials/_evidence_policy.mds +30 -0
- package/src/assets/commands/_partials/_knowledge.mds +2 -2
- package/src/assets/commands/_partials/_plan_contract.mds +22 -7
- package/src/assets/commands/_partials/_preamble.mds +1 -1
- package/src/assets/commands/_partials/_publication.mds +3 -1
- package/src/assets/commands/_partials/_ticket_template.mds +3 -2
- package/src/assets/commands/_partials/_tracker.mds +18 -0
- package/src/assets/commands/_partials/_wave.mds +16 -10
- package/src/assets/commands/bug-analysis.mds +15 -5
- package/src/assets/commands/code-review.mds +34 -14
- package/src/assets/commands/debug.mds +11 -4
- package/src/assets/commands/dynamic-build.mds +227 -41
- package/src/assets/commands/dynamic-plan.mds +35 -13
- package/src/assets/commands/dynamic-tickets.mds +47 -5
- package/src/assets/commands/implement.mds +206 -52
- package/src/assets/commands/plan.mds +70 -17
- package/src/assets/commands/release.md +64 -17
- package/src/assets/commands/resolve.mds +126 -56
- package/src/assets/mds/git/_pr.mds +331 -0
- package/src/assets/mds/git/_references.mds +135 -0
- package/src/assets/mds/tracker/_common.mds +156 -0
- package/src/assets/mds/tracker/_github.mds +472 -0
- package/src/assets/mds/tracker/_jira.mds +407 -0
- package/src/assets/mds/tracker/_linear.mds +449 -0
- package/src/assets/mds/tracker/_mcp.mds +299 -0
- package/src/assets/scripts/hooks/assets/orchestrator-charter.md +5 -8
- package/src/assets/scripts/hooks/background-memory-update +14 -9
- package/src/assets/scripts/hooks/capture-prompt +6 -2
- package/src/assets/scripts/hooks/capture-question +6 -2
- package/src/assets/scripts/hooks/capture-turn +6 -2
- package/src/assets/scripts/hooks/ensure-devflow-init +1 -1
- package/src/assets/scripts/hooks/ensure-proxy +64 -5
- package/src/assets/scripts/hooks/ensure-root-gitignore +161 -60
- package/src/assets/scripts/hooks/hook-log-init +3 -1
- package/src/assets/scripts/hooks/json-helper.cjs +223 -5
- package/src/assets/scripts/hooks/lib/project-paths.cjs +1 -1
- package/src/assets/scripts/hooks/memory-worker +15 -8
- package/src/assets/scripts/hooks/pre-compact-memory +12 -8
- package/src/assets/scripts/hooks/preamble +1 -4
- package/src/assets/scripts/hooks/queue-append +68 -24
- package/src/assets/scripts/hooks/session-start-context +355 -8
- package/src/assets/scripts/hooks/session-start-memory +12 -8
- package/src/assets/scripts/pr-evidence.cjs +1961 -0
- package/src/assets/scripts/redact-secrets.cjs +490 -62
- package/src/assets/scripts/release-trace.cjs +1143 -0
- package/src/assets/scripts/resolve-evidence-policy.cjs +1065 -0
- package/src/assets/scripts/verify-evidence.cjs +1822 -0
- package/src/assets/skills/compliance/SKILL.md +2 -0
- package/src/assets/skills/docs-framework/SKILL.md +5 -3
- package/src/assets/skills/git/SKILL.md +8 -82
- package/src/assets/skills/git/references/github-api.md +179 -141
- package/src/assets/skills/git/references/patterns.md +11 -12
- package/src/assets/skills/review-methodology/SKILL.md +1 -1
- package/src/assets/skills/review-methodology/references/patterns.md +6 -61
- package/src/assets/skills/review-methodology/references/violations.md +14 -22
- package/src/targets/claude-code/templates/settings.json +0 -4
- package/src/assets/agents/git.md +0 -938
|
@@ -373,7 +373,12 @@ export const agentsCommand = new Command('agents')
|
|
|
373
373
|
}
|
|
374
374
|
const mapping = mappingResult.value;
|
|
375
375
|
const proxyEnabled = await isProxyEnabled(devflowDir);
|
|
376
|
-
|
|
376
|
+
// An agent with no shipped default renders a blank DEFAULT column and can
|
|
377
|
+
// never be reverted off an external model; surface the gap rather than
|
|
378
|
+
// letting the table imply the agent simply ships without one.
|
|
379
|
+
const shippedDefaults = await loadShippedDefaults(undefined, {
|
|
380
|
+
onWarning: (msg) => p.log.warn(msg),
|
|
381
|
+
});
|
|
377
382
|
// ── --list ──────────────────────────────────────────────────────────────
|
|
378
383
|
if (options.list) {
|
|
379
384
|
const agentNames = getAllAgentNames().sort();
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Attribution prompt helpers for devflow init.
|
|
3
|
+
*
|
|
4
|
+
* CLI-layer module (ADR-013): prompt-rendering logic lives in src/cli/commands/,
|
|
5
|
+
* core business logic stays in src/core/.
|
|
6
|
+
*
|
|
7
|
+
* Applies PF-029: the gate is an exported pure predicate with an explicit isTTY guard,
|
|
8
|
+
* so --recommended (flag, no prompt) and the non-TTY fallback keep their promptless
|
|
9
|
+
* contracts and the reachability rule is unit-testable without a terminal.
|
|
10
|
+
* Applies PF-014: runAttributionStep never calls process.exit() or throws — callers
|
|
11
|
+
* own the cancel idiom (p.cancel + process.exit(0)), keeping try/finally cleanup safe.
|
|
12
|
+
*
|
|
13
|
+
* D27: suppress-attribution flag — gates Claude Code's AI-attribution injection.
|
|
14
|
+
* The question is ADVANCED-ONLY; Recommended never asks. See shouldRunAttributionStep.
|
|
15
|
+
*
|
|
16
|
+
* Shared DI seam (PromptOutcome, WizardPromptIO, clackNote, clackSelect) lives in
|
|
17
|
+
* prompt-io.ts — one definition, both wizard modules import from there.
|
|
18
|
+
*/
|
|
19
|
+
import { clackNote, clackSelect } from './prompt-io.js';
|
|
20
|
+
// ── Gate predicate ─────────────────────────────────────────────────────────────
|
|
21
|
+
/**
|
|
22
|
+
* Determines whether the attribution wizard step should run for a given init invocation.
|
|
23
|
+
*
|
|
24
|
+
* D27 — ADVANCED-ONLY. The attribution question is reachable from the Advanced path
|
|
25
|
+
* and nowhere else. This DIVERGES DELIBERATELY from shouldRunComplianceStep, which also
|
|
26
|
+
* runs on interactive Recommended: attribution rewrites the user's git history metadata,
|
|
27
|
+
* so Recommended stays a zero-question path and silently applies the seeded value
|
|
28
|
+
* (fresh install: off). Do not "restore symmetry" with the compliance gate.
|
|
29
|
+
*
|
|
30
|
+
* Gate table:
|
|
31
|
+
*
|
|
32
|
+
* --advanced flag / re-init (banner path) / prompt → Advanced → yes
|
|
33
|
+
* Interactive mode-prompt → Recommended → NO (D27 divergence)
|
|
34
|
+
* --recommended flag → no
|
|
35
|
+
* !isTTY (any mode) → no
|
|
36
|
+
*
|
|
37
|
+
* Gating on the mode name is sound here because 'advanced' is only ever resolved on an
|
|
38
|
+
* interactive path (the Advanced branch exit-1s on non-TTY), and the explicit isTTY guard
|
|
39
|
+
* keeps the promptless contracts of --recommended and the non-TTY fallback pinned
|
|
40
|
+
* regardless (PF-029).
|
|
41
|
+
*
|
|
42
|
+
* There is no CLI override for attribution — it is toggled post-install via
|
|
43
|
+
* `devflow flags --enable/--disable suppress-attribution`.
|
|
44
|
+
*
|
|
45
|
+
* Pure predicate — no side effects, fully testable without a TTY.
|
|
46
|
+
*/
|
|
47
|
+
export function shouldRunAttributionStep(input) {
|
|
48
|
+
if (!input.isTTY)
|
|
49
|
+
return false;
|
|
50
|
+
return input.mode === 'advanced';
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Build the real (clack) AttributionPromptIO adapter.
|
|
54
|
+
* Delegates to the shared clackNote / clackSelect adapters (prompt-io.ts).
|
|
55
|
+
*/
|
|
56
|
+
export function buildClackAttributionPrompts() {
|
|
57
|
+
return {
|
|
58
|
+
note: clackNote,
|
|
59
|
+
select: (opts) => clackSelect(opts),
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
// ── Seed / apply helpers ───────────────────────────────────────────────────────
|
|
63
|
+
/**
|
|
64
|
+
* Derive the boolean seed for the attribution prompt from the current FlagsRecord.
|
|
65
|
+
*
|
|
66
|
+
* Returns true only when `suppress-attribution` is explicitly set to the boolean
|
|
67
|
+
* true — undefined, null, and false all map to false, giving `p.select` a real
|
|
68
|
+
* boolean rather than an unchecked cast (PF-018: non-vacuous path).
|
|
69
|
+
*
|
|
70
|
+
* Pure function — no side effects, fully testable without a TTY.
|
|
71
|
+
*/
|
|
72
|
+
export function attributionSeedFrom(flags) {
|
|
73
|
+
return flags['suppress-attribution'] === true;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Apply the resolved wizard answer back onto the FlagsRecord.
|
|
77
|
+
*
|
|
78
|
+
* Returns a new record with `suppress-attribution` updated to outcome.suppress.
|
|
79
|
+
* Never mutates the input (immutability principle). The caller replaces its local
|
|
80
|
+
* enabledFlags binding with the return value.
|
|
81
|
+
*
|
|
82
|
+
* D27: this is the single merge site for the wizard answer; init.ts must not
|
|
83
|
+
* duplicate the spread inline.
|
|
84
|
+
*
|
|
85
|
+
* Pure function — no side effects, fully testable without a TTY.
|
|
86
|
+
*/
|
|
87
|
+
export function applyAttributionAnswer(flags, outcome) {
|
|
88
|
+
return { ...flags, 'suppress-attribution': outcome.suppress };
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Run the attribution wizard step.
|
|
92
|
+
*
|
|
93
|
+
* Flow:
|
|
94
|
+
* 1. Note — "Current setting: …" header with context about what the flag does.
|
|
95
|
+
* 2. Enable select — labeled Yes / No with hints (seeded from prior state);
|
|
96
|
+
* p.select is immune to Enter-through muscle memory while still preserving
|
|
97
|
+
* the seeded value (ambient-prompt style — per PF-029).
|
|
98
|
+
*
|
|
99
|
+
* Returns:
|
|
100
|
+
* {kind:'resolved', suppress, messages} — step completed; `suppress` is the chosen
|
|
101
|
+
* boolean; `messages` are emitted by the caller.
|
|
102
|
+
* {kind:'cancelled'} — user pressed Escape; caller runs p.cancel + process.exit(0).
|
|
103
|
+
*
|
|
104
|
+
* Invariants (PF-014):
|
|
105
|
+
* - Never calls process.exit(), never throws.
|
|
106
|
+
* - All I/O is routed through the `prompts` parameter (injectable for tests).
|
|
107
|
+
*/
|
|
108
|
+
export async function runAttributionStep(opts) {
|
|
109
|
+
const { seed, prompts } = opts;
|
|
110
|
+
const currentStr = seed ? 'suppressed' : 'shown (default)';
|
|
111
|
+
// security-02: name the destructive branch (Yes) BEFORE the user consents.
|
|
112
|
+
// ADR-024 corollary (b): turning the flag ON replaces any existing attribution
|
|
113
|
+
// value, including a custom one — this is deliberate. Only the exact
|
|
114
|
+
// devflow-managed shape {"commit":"","pr":""} is removed on disable.
|
|
115
|
+
// security-04: surface the org AI-disclosure-policy dimension as a note (not a gate).
|
|
116
|
+
prompts.note(`Current setting: ${currentStr}\n\n` +
|
|
117
|
+
'Choosing Yes REPLACES any existing \`attribution\` value in settings.json,\n' +
|
|
118
|
+
'including a custom one, with {"commit":"","pr":""}.\n' +
|
|
119
|
+
'Choosing No leaves a custom value untouched — only the exact\n' +
|
|
120
|
+
'devflow-managed block is ever removed on disable.\n' +
|
|
121
|
+
'Some organisations require machine-readable AI-authorship disclosure\n' +
|
|
122
|
+
'— check your policy before enabling.\n\n' +
|
|
123
|
+
'Toggle any time with: devflow flags --enable suppress-attribution', 'AI Attribution');
|
|
124
|
+
const enableOutcome = await prompts.select({
|
|
125
|
+
message: 'Suppress AI attribution in commits and PRs?',
|
|
126
|
+
options: [
|
|
127
|
+
{ value: true, label: 'Yes', hint: 'hides Claude attribution labels in git history' },
|
|
128
|
+
{ value: false, label: 'No', hint: 'keeps Claude attribution labels (default)' },
|
|
129
|
+
],
|
|
130
|
+
initialValue: seed,
|
|
131
|
+
});
|
|
132
|
+
if (enableOutcome.kind === 'cancel')
|
|
133
|
+
return { kind: 'cancelled' };
|
|
134
|
+
const suppress = enableOutcome.value;
|
|
135
|
+
const text = suppress
|
|
136
|
+
? 'Attribution: suppressed — disable with devflow flags --disable suppress-attribution'
|
|
137
|
+
: 'Attribution: shown (default)';
|
|
138
|
+
return {
|
|
139
|
+
kind: 'resolved',
|
|
140
|
+
suppress,
|
|
141
|
+
messages: [{ level: suppress ? 'success' : 'info', text }],
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
//# sourceMappingURL=attribution-prompts.js.map
|
|
@@ -9,9 +9,13 @@
|
|
|
9
9
|
* no prompt) and the non-TTY fallback preserve their promptless contracts.
|
|
10
10
|
* Applies PF-014: runComplianceStep never calls process.exit() or throws — callers
|
|
11
11
|
* own the cancel idiom (p.cancel + process.exit(0)), keeping try/finally cleanup safe.
|
|
12
|
+
*
|
|
13
|
+
* Shared DI seam (PromptOutcome, WizardPromptIO, clackNote, clackSelect) lives in
|
|
14
|
+
* prompt-io.ts — one definition, both wizard modules import from there.
|
|
12
15
|
*/
|
|
13
16
|
import * as p from '@clack/prompts';
|
|
14
17
|
import { COMPLIANCE_FRAMEWORKS } from '../../core/compliance.js';
|
|
18
|
+
import { clackNote, clackSelect } from './prompt-io.js';
|
|
15
19
|
// ── Shared prompt content ──────────────────────────────────────────────────────
|
|
16
20
|
/** Message shown on the compliance framework multiselect prompt. */
|
|
17
21
|
export const FRAMEWORK_SELECT_MESSAGE = 'Select compliance frameworks (Enter to skip — generic controls only)';
|
|
@@ -75,21 +79,13 @@ export function shouldRunComplianceStep(input) {
|
|
|
75
79
|
}
|
|
76
80
|
/**
|
|
77
81
|
* Build the real (clack) CompliancePromptIO adapter.
|
|
82
|
+
* Delegates the shared note + select to the shared adapters (prompt-io.ts).
|
|
78
83
|
* Translates clack's cancel symbol into the PromptOutcome discriminated union.
|
|
79
84
|
*/
|
|
80
85
|
export function buildClackCompliancePrompts() {
|
|
81
86
|
return {
|
|
82
|
-
note:
|
|
83
|
-
select:
|
|
84
|
-
const result = await p.select({
|
|
85
|
-
message: opts.message,
|
|
86
|
-
options: opts.options,
|
|
87
|
-
initialValue: opts.initialValue,
|
|
88
|
-
});
|
|
89
|
-
if (p.isCancel(result))
|
|
90
|
-
return { kind: 'cancel' };
|
|
91
|
-
return { kind: 'value', value: result };
|
|
92
|
-
},
|
|
87
|
+
note: clackNote,
|
|
88
|
+
select: (opts) => clackSelect(opts),
|
|
93
89
|
multiselect: async (opts) => {
|
|
94
90
|
const result = await p.multiselect({
|
|
95
91
|
message: opts.message,
|
|
@@ -6,6 +6,9 @@
|
|
|
6
6
|
* Applies ADR-001: compliance is manifest-group (like proxy), not config.json-gated.
|
|
7
7
|
* Avoids PF-009: per-artifact failures are warn-not-throw.
|
|
8
8
|
* Avoids PF-015: enable/disable each converge BOTH artifacts unconditionally.
|
|
9
|
+
* The evidence-policy lines (--status, and the --enable/--set suggestion) come
|
|
10
|
+
* from src/core/evidence-policy.ts, the seam onto the package's own resolver;
|
|
11
|
+
* the CLI prints .devflow/policy.json and never writes it (applies ADR-024).
|
|
9
12
|
*/
|
|
10
13
|
import { Command } from 'commander';
|
|
11
14
|
import { promises as fs } from 'fs';
|
|
@@ -15,6 +18,7 @@ import color from 'picocolors';
|
|
|
15
18
|
import { ALWAYS_PRESENT_REFS, COMPLIANCE_FRAMEWORKS, normalizeFrameworks, parseFrameworkList, } from '../../core/compliance.js';
|
|
16
19
|
import { frameworkChoices, FRAMEWORK_SELECT_MESSAGE } from './compliance-prompts.js';
|
|
17
20
|
import { COMPLIANCE_SKILL_TOKENS } from '../../core/compliance-compose.js';
|
|
21
|
+
import { evidencePolicyStatusLine, evidencePolicySuggestion, formatEvidencePolicyUnavailable, loadEvidencePolicyModule, } from '../../core/evidence-policy.js';
|
|
18
22
|
import { readManifest, writeManifest } from '../../core/manifest.js';
|
|
19
23
|
import { convergeFromManifest } from '../../targets/claude-code/compliance-install.js';
|
|
20
24
|
import { validateRuleShadow, validateSkillShadow } from '../../targets/claude-code/installer.js';
|
|
@@ -177,7 +181,7 @@ export const complianceCommand = new Command('compliance')
|
|
|
177
181
|
.description('Enable, disable, or configure the compliance feature')
|
|
178
182
|
.option('--enable', 'Enable compliance (restores previously selected frameworks)')
|
|
179
183
|
.option('--disable', 'Disable compliance (artifacts removed; frameworks remembered for re-enable)')
|
|
180
|
-
.option('--status', 'Show compliance state: manifest, installed artifacts, and
|
|
184
|
+
.option('--status', 'Show compliance state: manifest, installed artifacts, shadow presence, and the evidence policy for the current repository')
|
|
181
185
|
.option('--set <list>', 'Set active frameworks (comma-separated IDs); enables compliance. Use --set "" for zero frameworks (generic controls only)')
|
|
182
186
|
.action(async (options) => {
|
|
183
187
|
const claudeDir = getClaudeDirectory();
|
|
@@ -247,6 +251,11 @@ export const complianceCommand = new Command('compliance')
|
|
|
247
251
|
? color.yellow(' (withheld — rules disabled)')
|
|
248
252
|
: '') +
|
|
249
253
|
(isRuleShadowed ? color.green(' [shadowed]') : ''),
|
|
254
|
+
'',
|
|
255
|
+
// The repository in cwd, resolved by the package's own resolver with the
|
|
256
|
+
// compliance state already read above (D-POLICY-CJS-SEAM). Bounded: at most
|
|
257
|
+
// two `gh` calls, each with a timeout, so offline degrades to a flagged line.
|
|
258
|
+
evidencePolicyStatusLine(loadEvidencePolicyModule(), { dir: process.cwd(), compliance: current }),
|
|
250
259
|
];
|
|
251
260
|
if (driftInstalled.length > 0 || validMissing.length > 0 || invalidIds.length > 0) {
|
|
252
261
|
lines.push('');
|
|
@@ -333,5 +342,18 @@ export const complianceCommand = new Command('compliance')
|
|
|
333
342
|
p.log.info(color.dim('Note: compliance rule withheld (rules disabled) — ' +
|
|
334
343
|
'run `devflow rules --enable` to install the stamped rule'));
|
|
335
344
|
}
|
|
345
|
+
// Suggest the team policy file compliance now implies. Printed, never written:
|
|
346
|
+
// .devflow/policy.json is team-owned (D-POLICY-NO-WRITE, applies ADR-024).
|
|
347
|
+
if (resolved.nextState.enabled) {
|
|
348
|
+
const policyModule = loadEvidencePolicyModule();
|
|
349
|
+
if (!policyModule.ok) {
|
|
350
|
+
p.log.warn(formatEvidencePolicyUnavailable(policyModule.error));
|
|
351
|
+
}
|
|
352
|
+
else {
|
|
353
|
+
const suggestion = evidencePolicySuggestion(resolved.nextState, policyModule.value);
|
|
354
|
+
if (suggestion !== null)
|
|
355
|
+
p.note(suggestion, 'Evidence policy');
|
|
356
|
+
}
|
|
357
|
+
}
|
|
336
358
|
});
|
|
337
359
|
//# sourceMappingURL=compliance.js.map
|
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Computes the initial state (seed) for init prompts from:
|
|
5
5
|
* - The existing manifest (from a prior install)
|
|
6
|
-
* - The project feature config (.devflow/config.json)
|
|
7
6
|
* - The current settings.json snapshot (for view-mode resolution)
|
|
8
7
|
* - The plugin registry
|
|
9
8
|
*
|
|
@@ -13,8 +12,9 @@
|
|
|
13
12
|
* beside init.ts in src/cli/commands/ rather than in src/core/ (which holds
|
|
14
13
|
* agent-neutral, target-agnostic utilities).
|
|
15
14
|
*/
|
|
16
|
-
import { resolveExistingViewMode, FLAG_REGISTRY, defaultValueOf, readViewMode, } from '../../core/flags.js';
|
|
15
|
+
import { resolveExistingViewMode, settingHoldsManagedShape, FLAG_REGISTRY, defaultValueOf, readViewMode, } from '../../core/flags.js';
|
|
17
16
|
import { partitionSelectablePlugins } from '../../core/plugins.js';
|
|
17
|
+
import { DEFAULT_TRACKER_PROVIDER } from '../../core/tracker.js';
|
|
18
18
|
/** Registry defaults — all features enabled except proxy (advanced-only, off by default). */
|
|
19
19
|
export const FEATURE_DEFAULTS = {
|
|
20
20
|
ambient: true,
|
|
@@ -25,24 +25,21 @@ export const FEATURE_DEFAULTS = {
|
|
|
25
25
|
rules: true,
|
|
26
26
|
proxy: false,
|
|
27
27
|
compliance: { enabled: false, frameworks: [] },
|
|
28
|
+
tracker: { provider: DEFAULT_TRACKER_PROVIDER },
|
|
28
29
|
};
|
|
29
30
|
// ── Helpers ───────────────────────────────────────────────────────────────────
|
|
30
31
|
/**
|
|
31
|
-
* Resolve feature booleans for the init seed
|
|
32
|
+
* Resolve feature booleans for the init seed: every feature comes from
|
|
33
|
+
* manifest.features, with registry defaults when the manifest is absent.
|
|
32
34
|
*
|
|
33
|
-
* -
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
* Applies ADR-001: .devflow/config.json is the source of truth for
|
|
40
|
-
* memory/learning/knowledge; manifest reflects the last install choices for
|
|
41
|
-
* the remaining toggles.
|
|
35
|
+
* D-FEATURES-MACHINE-WIDE (src/core/feature-switch.ts): memory, learning and
|
|
36
|
+
* knowledge are machine-wide, recorded in the manifest alone, so the seed takes
|
|
37
|
+
* no per-repo input at all. Seeding from whatever repo init happens to run in
|
|
38
|
+
* would flip the switch for EVERY repo as a side effect — a stale per-repo
|
|
39
|
+
* `true` would silently re-enable a feature the user turned off. ADR-014's
|
|
40
|
+
* state-aware re-init preserves the prior machine-wide choice, the manifest's.
|
|
42
41
|
*/
|
|
43
|
-
export function resolveSeedFeatures(manifest
|
|
44
|
-
// ambient/hud/rules/proxy/compliance: manifest is the source; fall back to registry defaults.
|
|
45
|
-
// proxy and compliance follow the manifest group (like ambient) per ADR-001 — NOT config.json-gated.
|
|
42
|
+
export function resolveSeedFeatures(manifest) {
|
|
46
43
|
const ambient = manifest?.features.ambient ?? FEATURE_DEFAULTS.ambient;
|
|
47
44
|
const hud = manifest?.features.hud ?? FEATURE_DEFAULTS.hud;
|
|
48
45
|
const rules = manifest?.features.rules ?? FEATURE_DEFAULTS.rules;
|
|
@@ -52,15 +49,15 @@ export function resolveSeedFeatures(manifest, projectConfig) {
|
|
|
52
49
|
// the module-level default by reference — downstream mutation would corrupt it process-wide.
|
|
53
50
|
const rawCompliance = manifest?.features.compliance ?? FEATURE_DEFAULTS.compliance;
|
|
54
51
|
const compliance = { ...rawCompliance, frameworks: [...rawCompliance.frameworks] };
|
|
55
|
-
//
|
|
56
|
-
//
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
const memory =
|
|
61
|
-
const knowledge =
|
|
62
|
-
const learning =
|
|
63
|
-
return { ambient, memory, hud, knowledge, learning, rules, proxy, compliance };
|
|
52
|
+
// Same defensive spread, same reason: `?? FEATURE_DEFAULTS.tracker` alone would
|
|
53
|
+
// return the module-level default BY REFERENCE and downstream mutation would
|
|
54
|
+
// corrupt it process-wide.
|
|
55
|
+
const rawTracker = manifest?.features.tracker ?? FEATURE_DEFAULTS.tracker;
|
|
56
|
+
const tracker = { ...rawTracker };
|
|
57
|
+
const memory = manifest?.features.memory ?? FEATURE_DEFAULTS.memory;
|
|
58
|
+
const knowledge = manifest?.features.knowledge ?? FEATURE_DEFAULTS.knowledge;
|
|
59
|
+
const learning = manifest?.features.learning ?? FEATURE_DEFAULTS.learning;
|
|
60
|
+
return { ambient, memory, hud, knowledge, learning, rules, proxy, compliance, tracker };
|
|
64
61
|
}
|
|
65
62
|
/**
|
|
66
63
|
* Resolve the flag record for the init seed.
|
|
@@ -161,17 +158,41 @@ export function resolveSeedPlugins(manifestPlugins, knownPlugins, allPlugins) {
|
|
|
161
158
|
return { workflowPlugins, languagePlugins };
|
|
162
159
|
}
|
|
163
160
|
/**
|
|
164
|
-
*
|
|
161
|
+
* Extract the attribution suppression state from a settings JSON string.
|
|
162
|
+
*
|
|
163
|
+
* Returns `true` when the exact devflow-managed attribution shape is present —
|
|
164
|
+
* delegating to `settingHoldsManagedShape('suppress-attribution')`, which is the
|
|
165
|
+
* single place that decides "on-disk value equals the managed shape" (consistency-01).
|
|
166
|
+
* Returns `undefined` when the block is absent, holds a custom value, or JSON is
|
|
167
|
+
* malformed — callers fall through to the manifest FlagsRecord entry or the registry
|
|
168
|
+
* default.
|
|
169
|
+
*
|
|
170
|
+
* Return type is `true | undefined` (typescript-06): settings.json can signal ON or
|
|
171
|
+
* nothing — never explicitly OFF. That asymmetry is load-bearing for seeding priority:
|
|
172
|
+
* `undefined` lets the manifest entry or the registry default win, while `true` is an
|
|
173
|
+
* unambiguous "this key was devflow-managed and active".
|
|
174
|
+
*
|
|
175
|
+
* Mirrors resolveExistingViewMode: returns undefined on malformed JSON, absent key,
|
|
176
|
+
* or any non-devflow attribution value.
|
|
177
|
+
*
|
|
178
|
+
* Pure function — no I/O, no side effects.
|
|
179
|
+
*/
|
|
180
|
+
export function resolveExistingAttributionSuppression(settingsJson) {
|
|
181
|
+
return settingHoldsManagedShape(settingsJson, 'suppress-attribution') ? true : undefined;
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Compose the full init seed from manifest, settings, and registry.
|
|
165
185
|
*
|
|
166
186
|
* view-mode priority: existing settings.json (non-default) → manifest → 'default'.
|
|
167
|
-
*
|
|
168
|
-
*
|
|
187
|
+
* suppress-attribution priority: settings.json exact devflow shape → manifest → false.
|
|
188
|
+
* All flag overrides are encoded into flags so all flag state lives in one FlagsRecord
|
|
189
|
+
* (applying PF-015: fold before strip — the fold happens here).
|
|
169
190
|
*
|
|
170
191
|
* This is the single composition point; callers (init.ts hoist block) call this
|
|
171
192
|
* once and pass `seed` down to prompt wiring.
|
|
172
193
|
*/
|
|
173
|
-
export function resolveInitSeed(seedManifest,
|
|
174
|
-
const features = resolveSeedFeatures(seedManifest
|
|
194
|
+
export function resolveInitSeed(seedManifest, settingsSnapshot, plugins) {
|
|
195
|
+
const features = resolveSeedFeatures(seedManifest);
|
|
175
196
|
// features.flags is FlagsRecord; null for fresh install (no manifest).
|
|
176
197
|
// seedManifest?.features.flags may be absent at runtime on very old manifests not yet
|
|
177
198
|
// healed — ?? null collapses to fresh-install behavior (all flags at registry defaults).
|
|
@@ -194,9 +215,26 @@ export function resolveInitSeed(seedManifest, seedConfig, settingsSnapshot, plug
|
|
|
194
215
|
else {
|
|
195
216
|
resolvedViewMode = 'default'; // fall back to neutral
|
|
196
217
|
}
|
|
218
|
+
// Encode resolved attribution suppression (D27) into flags['suppress-attribution'].
|
|
219
|
+
// Priority: settings.json exact devflow shape → manifest FlagsRecord entry → false.
|
|
220
|
+
// resolveExistingAttributionSuppression returns true only for the exact managed shape
|
|
221
|
+
// {"commit":"","pr":""}; custom values return undefined so the manifest entry wins.
|
|
222
|
+
const existingAttr = resolveExistingAttributionSuppression(settingsSnapshot);
|
|
223
|
+
const resolvedSuppressAttr = existingAttr !== undefined
|
|
224
|
+
? existingAttr // settings.json exact shape wins
|
|
225
|
+
: flags['suppress-attribution'] === true; // manifest or registry default
|
|
197
226
|
// Return a fresh spread rather than mutating flags in place — keeps this function pure
|
|
198
227
|
// per the module docblock and avoids aliasing if the caller inspects seed.flags.
|
|
199
|
-
return {
|
|
228
|
+
return {
|
|
229
|
+
features,
|
|
230
|
+
flags: {
|
|
231
|
+
...flags,
|
|
232
|
+
'view-mode': resolvedViewMode,
|
|
233
|
+
'suppress-attribution': resolvedSuppressAttr,
|
|
234
|
+
},
|
|
235
|
+
workflowPlugins,
|
|
236
|
+
languagePlugins,
|
|
237
|
+
};
|
|
200
238
|
}
|
|
201
239
|
/**
|
|
202
240
|
* Resolve the three seed inputs under the --reset gate.
|
|
@@ -239,6 +277,7 @@ export function applyCliToggles(base, toggles) {
|
|
|
239
277
|
rules: toggles.rules ?? base.rules,
|
|
240
278
|
proxy: toggles.proxy ?? base.proxy,
|
|
241
279
|
compliance: toggles.compliance ?? base.compliance,
|
|
280
|
+
tracker: toggles.tracker ?? base.tracker,
|
|
242
281
|
};
|
|
243
282
|
}
|
|
244
283
|
//# sourceMappingURL=init-seed.js.map
|