devflow-kit 2.4.0 → 3.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/CHANGELOG.md +229 -0
- package/README.md +111 -18
- package/dist/agents/git.md +822 -0
- package/dist/cli/commands/agents.js +6 -1
- package/dist/cli/commands/ambient.js +160 -145
- package/dist/cli/commands/attribution-prompts.js +1 -1
- package/dist/cli/commands/capture.js +29 -55
- package/dist/cli/commands/compliance-prompts.js +1 -1
- package/dist/cli/commands/compliance.js +48 -55
- package/dist/cli/commands/context.js +17 -32
- package/dist/cli/commands/debug.js +65 -26
- package/dist/cli/commands/flags.js +3 -3
- package/dist/cli/commands/hud.js +34 -10
- package/dist/cli/commands/init-seed.js +61 -27
- package/dist/cli/commands/init.js +649 -240
- package/dist/cli/commands/install-report.js +200 -0
- package/dist/cli/commands/knowledge/index.js +2 -2
- package/dist/cli/commands/knowledge/toggle.js +35 -37
- package/dist/cli/commands/learning.js +79 -57
- package/dist/cli/commands/legacy-hooks.js +11 -14
- package/dist/cli/commands/memory.js +134 -135
- package/dist/cli/commands/prompt-io.js +4 -4
- package/dist/cli/commands/proxy.js +23 -41
- package/dist/cli/commands/security.js +81 -29
- package/dist/cli/commands/skills.js +71 -7
- package/dist/cli/commands/tracker-prompts.js +145 -0
- package/dist/cli/commands/tracker.js +277 -0
- package/dist/cli/commands/uninstall.js +520 -169
- package/dist/cli.js +2 -0
- package/dist/commands/bug-analysis.md +58 -14
- package/dist/commands/code-review.md +110 -32
- package/dist/commands/debug.md +55 -11
- package/dist/commands/dynamic-build.md +344 -73
- package/dist/commands/dynamic-plan.md +77 -27
- package/dist/commands/dynamic-profile.md +25 -11
- package/dist/commands/dynamic-tickets.md +76 -15
- package/dist/commands/explore.md +37 -7
- package/dist/commands/implement.md +314 -62
- package/dist/commands/plan.md +146 -32
- package/dist/commands/release.md +64 -17
- package/dist/commands/research.md +34 -8
- package/dist/commands/resolve.md +196 -68
- package/dist/commands/self-review.md +45 -9
- package/dist/core/agent-models.js +55 -12
- package/dist/core/assets.js +58 -2
- package/dist/core/compliance-compose.js +27 -27
- package/dist/core/evidence-policy.js +363 -0
- package/dist/core/feature-config.js +200 -65
- package/dist/core/feature-switch.js +112 -0
- package/dist/core/flags.js +34 -6
- package/dist/core/fs-atomic.js +27 -0
- package/dist/core/hook-log-dirs.js +104 -0
- package/dist/core/learning-tuning-config.js +5 -3
- package/dist/core/ledger-root.js +102 -0
- package/dist/core/manifest.js +38 -10
- package/dist/core/mds-variants.js +798 -0
- package/dist/core/migrations.js +49 -23
- package/dist/core/model-discovery.js +12 -1
- package/dist/core/plugins.js +361 -12
- package/dist/core/project-paths.js +1 -18
- package/dist/core/proxy-log.js +8 -6
- package/dist/core/proxy-state.js +11 -8
- package/dist/core/reference-sweep.js +136 -0
- package/dist/core/same-location.js +25 -0
- package/dist/core/tracker.js +494 -0
- package/dist/hud/components/config-counts.js +15 -4
- package/dist/hud/components/learning-counts.js +14 -0
- package/dist/hud/config.js +2 -1
- package/dist/hud/cost-history.js +2 -4
- package/dist/hud/git.js +52 -7
- package/dist/hud/index.js +7 -9
- 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/claude-paths.js +59 -57
- package/dist/targets/claude-code/compliance-install.js +49 -65
- package/dist/targets/claude-code/hooks.js +108 -3
- package/dist/targets/claude-code/installer.js +1187 -32
- package/dist/targets/claude-code/legacy.js +5 -0
- package/dist/targets/claude-code/post-install.js +366 -151
- package/dist/targets/claude-code/tracker-install.js +134 -0
- package/package.json +8 -6
- package/src/assets/agents/code.md +45 -6
- package/src/assets/agents/design.md +2 -1
- package/src/assets/agents/git.mds +825 -0
- package/src/assets/agents/knowledge.md +3 -3
- package/src/assets/agents/learning.md +11 -0
- package/src/assets/agents/review.md +3 -1
- package/src/assets/agents/synthesize.md +1 -1
- package/src/assets/agents/test.md +16 -5
- package/src/assets/agents/tracker.md +474 -0
- package/src/assets/agents/validate.md +7 -5
- package/src/assets/commands/_partials/_compliance.mds +19 -1
- package/src/assets/commands/_partials/_decisions.mds +15 -3
- package/src/assets/commands/_partials/_docs_root.mds +35 -0
- package/src/assets/commands/_partials/_engine.mds +13 -11
- package/src/assets/commands/_partials/_evidence_policy.mds +30 -0
- package/src/assets/commands/_partials/_factory.mds +1 -1
- package/src/assets/commands/_partials/_knowledge.mds +27 -9
- package/src/assets/commands/_partials/_plan_contract.mds +22 -7
- package/src/assets/commands/_partials/_preamble.mds +2 -2
- package/src/assets/commands/_partials/_publication.mds +8 -2
- package/src/assets/commands/_partials/_settings.mds +28 -0
- 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 +31 -19
- package/src/assets/commands/code-review.mds +67 -41
- package/src/assets/commands/debug.mds +13 -7
- package/src/assets/commands/dynamic-build.mds +274 -66
- package/src/assets/commands/dynamic-plan.mds +50 -23
- package/src/assets/commands/dynamic-profile.mds +24 -11
- package/src/assets/commands/dynamic-tickets.mds +63 -16
- package/src/assets/commands/explore.mds +4 -5
- package/src/assets/commands/implement.mds +234 -67
- package/src/assets/commands/plan.mds +91 -33
- package/src/assets/commands/release.md +64 -17
- package/src/assets/commands/research.mds +11 -9
- package/src/assets/commands/resolve.mds +150 -78
- package/src/assets/commands/self-review.mds +24 -25
- 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 +305 -0
- package/src/assets/scripts/hooks/assets/orchestrator-charter.md +5 -8
- package/src/assets/scripts/hooks/background-memory-update +40 -19
- package/src/assets/scripts/hooks/capture-prompt +18 -8
- package/src/assets/scripts/hooks/capture-question +18 -8
- package/src/assets/scripts/hooks/capture-turn +27 -13
- package/src/assets/scripts/hooks/debug-trace +11 -6
- package/src/assets/scripts/hooks/ensure-devflow-init +33 -6
- package/src/assets/scripts/hooks/ensure-proxy +9 -8
- package/src/assets/scripts/hooks/ensure-root-gitignore +236 -60
- package/src/assets/scripts/hooks/git-marker +48 -0
- package/src/assets/scripts/hooks/hook-log-init +3 -1
- package/src/assets/scripts/hooks/json-helper.cjs +228 -5
- package/src/assets/scripts/hooks/lib/project-paths.cjs +1 -20
- package/src/assets/scripts/hooks/log-paths +80 -0
- package/src/assets/scripts/hooks/memory-worker +22 -13
- package/src/assets/scripts/hooks/pre-compact-memory +44 -15
- package/src/assets/scripts/hooks/preamble +1 -4
- package/src/assets/scripts/hooks/queue-append +146 -28
- package/src/assets/scripts/hooks/resolve-project-root +101 -7
- package/src/assets/scripts/hooks/session-start-context +534 -20
- package/src/assets/scripts/hooks/session-start-memory +38 -15
- package/src/assets/scripts/lib/project-config.cjs +633 -0
- 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 +1145 -0
- package/src/assets/scripts/resolve-settings.cjs +1054 -0
- package/src/assets/scripts/verify-evidence.cjs +1822 -0
- package/src/assets/skills/compliance/SKILL.md +4 -2
- package/src/assets/skills/docs-framework/SKILL.md +11 -10
- package/src/assets/skills/docs-framework/references/patterns.md +10 -17
- package/src/assets/skills/gap-analysis/SKILL.md +2 -2
- package/src/assets/skills/git/SKILL.md +8 -78
- package/src/assets/skills/git/references/github-api.md +179 -141
- package/src/assets/skills/git/references/patterns.md +11 -6
- 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/assets/skills/worktree-support/SKILL.md +1 -1
- package/src/assets/skills/worktree-support/references/roots.md +29 -0
- package/src/targets/claude-code/templates/managed-settings.json +25 -9
- package/src/assets/agents/git.md +0 -938
|
@@ -0,0 +1,363 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The CLI's view of the evidence policy — a typed seam onto the package's own
|
|
3
|
+
* `resolve-evidence-policy.cjs`, never a second implementation of it.
|
|
4
|
+
*
|
|
5
|
+
* D-POLICY-CJS-SEAM: the resolver is plain CommonJS under src/assets/scripts/,
|
|
6
|
+
* outside every tsconfig (PF-043, PF-069), so the interfaces below are
|
|
7
|
+
* TRANSCRIBED from its JSDoc typedefs and are the only shape authority on this
|
|
8
|
+
* side — open those typedefs before changing anything here. The module is loaded
|
|
9
|
+
* with `require()` from `scriptsDir()`, which resolves under the package root both
|
|
10
|
+
* from `dist/cli.js` and under vitest (`package.json` `files` ships src/assets/),
|
|
11
|
+
* so the CLI and the resolver it runs are always the same version. The installed
|
|
12
|
+
* `~/.devflow/scripts` copy is never loaded: it may be older than this CLI. There
|
|
13
|
+
* is deliberately no TypeScript copy of the parser, the fold or the grammar.
|
|
14
|
+
*
|
|
15
|
+
* The same seam loads the sibling `resolve-settings.cjs` (loadSettingsModule),
|
|
16
|
+
* the local resolver of the per-repository settings layer — `.devflow/project.json`,
|
|
17
|
+
* the personal `.devflow/config.json` and the machine manifest. Its shapes are
|
|
18
|
+
* transcribed the same way, and there is no TypeScript copy of its fold either.
|
|
19
|
+
* It also loads the shared strict parser both resolvers use,
|
|
20
|
+
* `lib/project-config.cjs` (loadProjectConfigLib), so the CLI judges a config
|
|
21
|
+
* file's bytes exactly as the resolvers do.
|
|
22
|
+
*
|
|
23
|
+
* D-POLICY-NO-WRITE (applies ADR-024): `.devflow/project.json` is team-owned, and
|
|
24
|
+
* devflow never writes or replaces a shared file it cannot prove it wrote. This
|
|
25
|
+
* module therefore imports no fs API; the CLI only PRINTS the bytes a team may
|
|
26
|
+
* choose to commit (`evidencePolicySuggestion`, and the migration lines of
|
|
27
|
+
* `repoComplianceStatusLines`), all from the settings resolver's project.json
|
|
28
|
+
* serializer.
|
|
29
|
+
*
|
|
30
|
+
* D-POLICY-JSON-RETIRED: the evidence resolver never parses `.devflow/policy.json`;
|
|
31
|
+
* at a source whose project.json has no `evidence`, the file's presence alone
|
|
32
|
+
* resolves `required` (see the resolver's own note). This side neither reads nor
|
|
33
|
+
* serializes it — it only names it in the migration hint.
|
|
34
|
+
*/
|
|
35
|
+
import { createRequire } from 'module';
|
|
36
|
+
import { join } from 'path';
|
|
37
|
+
import { scriptsDir } from './assets.js';
|
|
38
|
+
// ── Transcribed shapes (resolve-evidence-policy.cjs JSDoc) ─────────────────────
|
|
39
|
+
/** Basename of the resolver under src/assets/scripts/ (and ~/.devflow/scripts/). */
|
|
40
|
+
export const RESOLVER_SCRIPT_NAME = 'resolve-evidence-policy.cjs';
|
|
41
|
+
/** Basename of the settings resolver under src/assets/scripts/ (and ~/.devflow/scripts/). */
|
|
42
|
+
export const SETTINGS_SCRIPT_NAME = 'resolve-settings.cjs';
|
|
43
|
+
/** The shared strict config parser, relative to src/assets/scripts/ (and ~/.devflow/scripts/). */
|
|
44
|
+
export const PROJECT_CONFIG_LIB_NAME = join('lib', 'project-config.cjs');
|
|
45
|
+
/** The team file the CLI suggests committing, relative to a repository root. */
|
|
46
|
+
const PROJECT_FILE = '.devflow/project.json';
|
|
47
|
+
/** The retired team file project.json's `evidence` replaces, relative to a repository root. */
|
|
48
|
+
const RETIRED_POLICY_FILE = '.devflow/policy.json';
|
|
49
|
+
/**
|
|
50
|
+
* Every key of EvidencePolicyModule and the runtime kind the loader requires of
|
|
51
|
+
* it. `satisfies` makes the compiler reject an interface key missing here.
|
|
52
|
+
*/
|
|
53
|
+
export const EVIDENCE_POLICY_MODULE_SURFACE = Object.freeze({
|
|
54
|
+
POLICIES: 'string-array',
|
|
55
|
+
SOURCES: 'string-array',
|
|
56
|
+
WARNINGS: 'string-array',
|
|
57
|
+
MECHANISM_INPUTS: 'object',
|
|
58
|
+
OUTPUT_LINE_RE: 'regexp',
|
|
59
|
+
FAIL_CLOSED_LINE: 'string',
|
|
60
|
+
complianceDefault: 'function',
|
|
61
|
+
resolve: 'function',
|
|
62
|
+
});
|
|
63
|
+
/** Every key of SettingsModule and the runtime kind the loader requires of it. */
|
|
64
|
+
export const SETTINGS_MODULE_SURFACE = Object.freeze({
|
|
65
|
+
SETTINGS_LINE_RE: 'regexp',
|
|
66
|
+
SETTINGS_FAIL_CLOSED_LINE: 'string',
|
|
67
|
+
resolveSettings: 'function',
|
|
68
|
+
serializeProjectSuggestion: 'function',
|
|
69
|
+
});
|
|
70
|
+
/** Every key of ProjectConfigLib and the runtime kind the loader requires of it. */
|
|
71
|
+
export const PROJECT_CONFIG_LIB_SURFACE = Object.freeze({
|
|
72
|
+
MAX_CONFIG_BYTES: 'number',
|
|
73
|
+
decodeConfigBytes: 'function',
|
|
74
|
+
readBoundedRegularFile: 'function',
|
|
75
|
+
collectDuplicateKeyPaths: 'function',
|
|
76
|
+
});
|
|
77
|
+
function hasKind(value, kind) {
|
|
78
|
+
switch (kind) {
|
|
79
|
+
case 'string-array': return Array.isArray(value) && value.every(v => typeof v === 'string');
|
|
80
|
+
case 'object': return typeof value === 'object' && value !== null;
|
|
81
|
+
case 'regexp': return value instanceof RegExp;
|
|
82
|
+
case 'string': return typeof value === 'string';
|
|
83
|
+
case 'number': return typeof value === 'number' && Number.isFinite(value);
|
|
84
|
+
case 'function': return typeof value === 'function';
|
|
85
|
+
default: {
|
|
86
|
+
const exhaustive = kind;
|
|
87
|
+
return exhaustive;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
/** Surface keys that are absent or of the wrong kind on `value`, in surface order. */
|
|
92
|
+
function surfaceMismatches(value, surface) {
|
|
93
|
+
if (typeof value !== 'object' || value === null)
|
|
94
|
+
return Object.keys(surface);
|
|
95
|
+
const record = value;
|
|
96
|
+
return Object.entries(surface)
|
|
97
|
+
.filter(([key, kind]) => !hasKind(record[key], kind))
|
|
98
|
+
.map(([key]) => key);
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* require() one package script and shape-check it against `surface`. Never
|
|
102
|
+
* throws: a missing file is `not-found`; a module that throws on load or lacks a
|
|
103
|
+
* surface key is `unusable`. The caller's type parameter is justified by the
|
|
104
|
+
* surface check, which `satisfies` ties to the interface's keys.
|
|
105
|
+
*/
|
|
106
|
+
function loadScript(file, surface) {
|
|
107
|
+
let loaded;
|
|
108
|
+
try {
|
|
109
|
+
loaded = createRequire(import.meta.url)(file);
|
|
110
|
+
}
|
|
111
|
+
catch (err) {
|
|
112
|
+
const code = err.code;
|
|
113
|
+
if (code === 'MODULE_NOT_FOUND')
|
|
114
|
+
return { ok: false, error: { kind: 'not-found', path: file } };
|
|
115
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
116
|
+
return { ok: false, error: { kind: 'unusable', path: file, detail } };
|
|
117
|
+
}
|
|
118
|
+
const mismatches = surfaceMismatches(loaded, surface);
|
|
119
|
+
if (mismatches.length > 0) {
|
|
120
|
+
return { ok: false, error: { kind: 'unusable', path: file, detail: `missing or mistyped: ${mismatches.join(', ')}` } };
|
|
121
|
+
}
|
|
122
|
+
return { ok: true, value: loaded };
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Load the evidence resolver from `dir` (default: the package's own scripts
|
|
126
|
+
* directory) and shape-check its surface.
|
|
127
|
+
*/
|
|
128
|
+
export function loadEvidencePolicyModule(dir = scriptsDir()) {
|
|
129
|
+
return loadScript(join(dir, RESOLVER_SCRIPT_NAME), EVIDENCE_POLICY_MODULE_SURFACE);
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Load the settings resolver from `dir` (default: the package's own scripts
|
|
133
|
+
* directory) and shape-check its surface. A `resolveSettings()` call makes one
|
|
134
|
+
* local `git` call and no network call (D-SETTINGS-LOCAL-ONLY).
|
|
135
|
+
*/
|
|
136
|
+
export function loadSettingsModule(dir = scriptsDir()) {
|
|
137
|
+
return loadScript(join(dir, SETTINGS_SCRIPT_NAME), SETTINGS_MODULE_SURFACE);
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Load the shared strict config parser from `dir` (default: the package's own
|
|
141
|
+
* scripts directory) and shape-check its surface.
|
|
142
|
+
*/
|
|
143
|
+
export function loadProjectConfigLib(dir = scriptsDir()) {
|
|
144
|
+
return loadScript(join(dir, PROJECT_CONFIG_LIB_NAME), PROJECT_CONFIG_LIB_SURFACE);
|
|
145
|
+
}
|
|
146
|
+
// ── Presentation (pure) ────────────────────────────────────────────────────────
|
|
147
|
+
/** `Evidence policy: <policy> (source: <source>)`, plus ` [warn: a, b]` when warnings exist. */
|
|
148
|
+
export function formatEvidencePolicyStatus(r) {
|
|
149
|
+
const warn = r.warnings.length > 0 ? ` [warn: ${r.warnings.join(', ')}]` : '';
|
|
150
|
+
return `Evidence policy: ${r.policy} (source: ${r.source})${warn}`;
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* The line shown in place of a policy when the resolver cannot be loaded. The
|
|
154
|
+
* remedy is a package reinstall: the CLI loads the package's own copy, which
|
|
155
|
+
* `devflow init` does not restore.
|
|
156
|
+
*/
|
|
157
|
+
export function formatEvidencePolicyUnavailable(error) {
|
|
158
|
+
switch (error.kind) {
|
|
159
|
+
case 'not-found': return 'Evidence policy: unavailable (resolver not found — reinstall devflow-kit)';
|
|
160
|
+
case 'unusable': return 'Evidence policy: unavailable (resolver failed to load — reinstall devflow-kit)';
|
|
161
|
+
default: {
|
|
162
|
+
const exhaustive = error;
|
|
163
|
+
return exhaustive;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* The `compliance --status` line: the resolved policy for `opts.dir`, or the
|
|
169
|
+
* unavailable line when the loader failed — that line is the whole handling
|
|
170
|
+
* (ADR-028). The caller passes the compliance state it already read, so the
|
|
171
|
+
* manifest is never read twice. `resolve()` makes at most three `gh` calls and
|
|
172
|
+
* bounds every subprocess with a timeout, so an offline machine degrades to a
|
|
173
|
+
* flagged result rather than a hang.
|
|
174
|
+
*/
|
|
175
|
+
export function evidencePolicyStatusLine(loaded, opts) {
|
|
176
|
+
if (!loaded.ok)
|
|
177
|
+
return formatEvidencePolicyUnavailable(loaded.error);
|
|
178
|
+
return formatEvidencePolicyStatus(loaded.value.resolve(opts));
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* The frameworks a compliance state names, for the suggestion: the raw list when
|
|
182
|
+
* the state is well-formed, else none. The settings resolver's serializer
|
|
183
|
+
* normalizes and drops unknown ids, so no id reaches the printed bytes unchecked.
|
|
184
|
+
*/
|
|
185
|
+
function suggestedFrameworks(complianceState) {
|
|
186
|
+
if (typeof complianceState !== 'object' || complianceState === null)
|
|
187
|
+
return [];
|
|
188
|
+
const frameworks = complianceState.frameworks;
|
|
189
|
+
return Array.isArray(frameworks) && frameworks.every(f => typeof f === 'string') ? frameworks : [];
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* What `--enable`/`--set` print when compliance is on: the keys to add to a
|
|
193
|
+
* repository's `.devflow/project.json` on its default branch — merged into the
|
|
194
|
+
* file when it already has one, never replacing it — to hold every developer to
|
|
195
|
+
* what this machine now gets by default: the required evidence policy and this
|
|
196
|
+
* machine's frameworks. Returned only when the evidence resolver's own
|
|
197
|
+
* `complianceDefault` says `required` (compliance enabled, at any framework
|
|
198
|
+
* count); `null` otherwise. The bytes come
|
|
199
|
+
* from the settings resolver's `serializeProjectSuggestion`, which returns them
|
|
200
|
+
* only when they read back through the shared parser as exactly what was asked.
|
|
201
|
+
* Nothing is written (D-POLICY-NO-WRITE, applies ADR-024).
|
|
202
|
+
*/
|
|
203
|
+
export function evidencePolicySuggestion(complianceState, policy, settings) {
|
|
204
|
+
if (policy.complianceDefault(complianceState) !== 'required')
|
|
205
|
+
return null;
|
|
206
|
+
const body = settings.serializeProjectSuggestion({
|
|
207
|
+
evidence: 'required',
|
|
208
|
+
compliance: suggestedFrameworks(complianceState),
|
|
209
|
+
});
|
|
210
|
+
if (body === null)
|
|
211
|
+
return null;
|
|
212
|
+
return [
|
|
213
|
+
'Compliance is enabled on this machine, so repositories without a committed',
|
|
214
|
+
'evidence setting default to the required evidence policy here. To apply it for',
|
|
215
|
+
`everyone working in a repository, add these keys to its ${PROJECT_FILE} on its`,
|
|
216
|
+
'default branch — merged into the file when it already has one, never replacing it:',
|
|
217
|
+
'',
|
|
218
|
+
`${body}`,
|
|
219
|
+
'devflow never writes this file: the team owns it, and once committed it applies',
|
|
220
|
+
'repo-wide.',
|
|
221
|
+
].join('\n');
|
|
222
|
+
}
|
|
223
|
+
// ── The settings layer, for `--status` (pure) ──────────────────────────────────
|
|
224
|
+
/** A repo layer's file, as a `--status` line names it. */
|
|
225
|
+
export function settingsSourceFile(source) {
|
|
226
|
+
switch (source) {
|
|
227
|
+
case 'project': return PROJECT_FILE;
|
|
228
|
+
case 'personal': return '.devflow/config.json';
|
|
229
|
+
default: {
|
|
230
|
+
const exhaustive = source;
|
|
231
|
+
return exhaustive;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* The effective state of a feature switch in this repository, ONLY when a repo
|
|
237
|
+
* layer narrows it — `disabled (.devflow/project.json)` — and null otherwise, so a
|
|
238
|
+
* `--status` whose machine switch alone decides prints exactly what it always has
|
|
239
|
+
* (D-FEATURES-NARROW-ONLY). A repository file that exists but is unreadable fails
|
|
240
|
+
* every field closed but the compliance lens, and a switch that closed off is
|
|
241
|
+
* labelled with that file —
|
|
242
|
+
* `disabled (.devflow/project.json is unreadable)` — since commands act on it. Any
|
|
243
|
+
* other failure (the resolver failed to load, or git could not answer) yields
|
|
244
|
+
* null: it knows nothing about this repository.
|
|
245
|
+
*/
|
|
246
|
+
export function narrowedSwitchLabel(loaded, opts, feature) {
|
|
247
|
+
if (!loaded.ok)
|
|
248
|
+
return null;
|
|
249
|
+
const settings = loaded.value.resolveSettings(opts);
|
|
250
|
+
if (!settings.ok) {
|
|
251
|
+
if (settings.unreadable === null || settings.switches[feature].on)
|
|
252
|
+
return null;
|
|
253
|
+
return `disabled (${settingsSourceFile(settings.unreadable)} is unreadable)`;
|
|
254
|
+
}
|
|
255
|
+
const state = settings.switches[feature];
|
|
256
|
+
if (state.on || state.source === 'machine')
|
|
257
|
+
return null;
|
|
258
|
+
return `disabled (${settingsSourceFile(state.source)})`;
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* The tracker in effect in the repository at `opts.dir`, ONLY when a repository
|
|
262
|
+
* layer decides it — its committed project.json, or the personal config.json
|
|
263
|
+
* narrowing — and null otherwise. A machine whose own selection (or the github
|
|
264
|
+
* default) decides gets null, so `tracker --status` prints exactly what it always
|
|
265
|
+
* has there. So does a resolver that failed to load or failed closed: it knows
|
|
266
|
+
* nothing about this repository, and a fail-closed `github` is not a selection
|
|
267
|
+
* anyone made.
|
|
268
|
+
*/
|
|
269
|
+
export function repoTrackerSelection(loaded, opts) {
|
|
270
|
+
if (!loaded.ok)
|
|
271
|
+
return null;
|
|
272
|
+
const settings = loaded.value.resolveSettings(opts);
|
|
273
|
+
if (!settings.ok)
|
|
274
|
+
return null;
|
|
275
|
+
const source = settings.trackerSource;
|
|
276
|
+
if (source !== 'project' && source !== 'personal')
|
|
277
|
+
return null;
|
|
278
|
+
return { provider: settings.tracker, source };
|
|
279
|
+
}
|
|
280
|
+
/** A declared id list as a `--status` line shows it. */
|
|
281
|
+
function idsLabel(ids) {
|
|
282
|
+
return ids.length > 0 ? ids.join(', ') : 'generic controls only';
|
|
283
|
+
}
|
|
284
|
+
/**
|
|
285
|
+
* The `compliance --status` lines about the repository in `opts.dir`, mirroring
|
|
286
|
+
* the resolver's lens fold (D-LENS-UNION: machine ∪ default branch ∪ worktree):
|
|
287
|
+
* the ids this checkout's project.json declares (`generic controls only` for an
|
|
288
|
+
* empty or malformed list), the ids the default branch's copy declares, the
|
|
289
|
+
* effective lens those add up to with the machine's, and a migration hint while
|
|
290
|
+
* the retired policy file is in the working tree.
|
|
291
|
+
*
|
|
292
|
+
* A broken file affects only the keys it owns. An unreadable project.json is a
|
|
293
|
+
* malformed declaration — generic — and says so, naming the file; an unreadable
|
|
294
|
+
* config.json owns no compliance, so the lines are those of a readable one. Empty
|
|
295
|
+
* when the resolver is unavailable or failed closed for any other reason, or no
|
|
296
|
+
* repository layer declares anything and there is no policy file — the status
|
|
297
|
+
* output is then unchanged.
|
|
298
|
+
*
|
|
299
|
+
* The hint states the rule (D-POLICY-JSON-RETIRED): the file is not read, and
|
|
300
|
+
* while project.json has no `evidence` its presence holds the repository at
|
|
301
|
+
* `required`. The value is not read either, so the hint shows the project.json
|
|
302
|
+
* line for each value the file may hold, from the settings resolver's serializer.
|
|
303
|
+
*/
|
|
304
|
+
export function repoComplianceStatusLines(loaded, opts) {
|
|
305
|
+
if (!loaded.ok)
|
|
306
|
+
return [];
|
|
307
|
+
const settings = loaded.value.resolveSettings(opts);
|
|
308
|
+
if (!settings.ok && settings.unreadable === null)
|
|
309
|
+
return [];
|
|
310
|
+
const lines = [];
|
|
311
|
+
if (settings.unreadable === 'project') {
|
|
312
|
+
lines.push(`Repository: generic controls only (${PROJECT_FILE} is unreadable)`);
|
|
313
|
+
}
|
|
314
|
+
else if (settings.repoCompliance !== null) {
|
|
315
|
+
lines.push(`Repository: ${idsLabel(settings.repoCompliance)} (${PROJECT_FILE})`);
|
|
316
|
+
}
|
|
317
|
+
if (settings.defaultBranchCompliance !== null) {
|
|
318
|
+
lines.push(`Default branch: ${idsLabel(settings.defaultBranchCompliance)} (its ${PROJECT_FILE})`);
|
|
319
|
+
}
|
|
320
|
+
if (lines.length > 0) {
|
|
321
|
+
const lens = settings.compliance;
|
|
322
|
+
lines.push(`Effective here: ${lens.enabled ? idsLabel(lens.frameworks) : 'off'} (this machine + the default branch + this checkout)`);
|
|
323
|
+
}
|
|
324
|
+
if (settings.retiredPolicyFile)
|
|
325
|
+
lines.push(...retiredPolicyHint(loaded.value));
|
|
326
|
+
return lines;
|
|
327
|
+
}
|
|
328
|
+
/**
|
|
329
|
+
* The warning a `--status` prints when this checkout's `.devflow/config.json` is
|
|
330
|
+
* tracked by git, or null (D-PERSONAL-UNTRACKED). The resolver ignores such a file
|
|
331
|
+
* and says so on stderr, but prompts run it with stderr discarded, so a status
|
|
332
|
+
* command is where the user sees why their personal settings have no effect.
|
|
333
|
+
*/
|
|
334
|
+
export function personalConfigTrackedWarning(loaded, opts) {
|
|
335
|
+
if (!loaded.ok)
|
|
336
|
+
return null;
|
|
337
|
+
if (!loaded.value.resolveSettings(opts).personalTracked)
|
|
338
|
+
return null;
|
|
339
|
+
const file = settingsSourceFile('personal');
|
|
340
|
+
return `${file} is tracked by git, so devflow ignores it — it holds personal settings. ` +
|
|
341
|
+
`Untrack it with: git rm --cached ${file}`;
|
|
342
|
+
}
|
|
343
|
+
/** The policies the hint maps, in the order it prints them. */
|
|
344
|
+
const HINT_POLICIES = ['standard', 'required'];
|
|
345
|
+
/**
|
|
346
|
+
* The migration hint for a working tree holding the retired policy file: what the
|
|
347
|
+
* file does now, and the project.json line that states each value it may hold.
|
|
348
|
+
* A value whose line the serializer refuses is left out rather than hand-built.
|
|
349
|
+
*/
|
|
350
|
+
function retiredPolicyHint(settings) {
|
|
351
|
+
const mappings = HINT_POLICIES.flatMap((policy) => {
|
|
352
|
+
const body = settings.serializeProjectSuggestion({ evidence: policy });
|
|
353
|
+
return body === null ? [] : [` ${policy.padEnd(8)} → ${body.trimEnd()}`];
|
|
354
|
+
});
|
|
355
|
+
return [
|
|
356
|
+
`Migration: ${RETIRED_POLICY_FILE} is not read. While ${PROJECT_FILE} has no "evidence",`,
|
|
357
|
+
' its presence alone holds this repository at required. Add its value to',
|
|
358
|
+
` ${PROJECT_FILE} as "evidence", and keep ${RETIRED_POLICY_FILE} until every`,
|
|
359
|
+
` teammate runs devflow 3.0 or later; only then delete it:`,
|
|
360
|
+
...mappings,
|
|
361
|
+
];
|
|
362
|
+
}
|
|
363
|
+
//# sourceMappingURL=evidence-policy.js.map
|