devflow-kit 3.9.0 → 3.11.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 +142 -0
- package/README.md +1 -1
- package/dist/agents/code.md +6 -6
- package/dist/agents/fix.md +6 -6
- package/dist/agents/harden.md +7 -6
- package/dist/agents/refactor.md +6 -6
- package/dist/cli/commands/ambient.js +10 -2
- package/dist/cli/commands/backup-session.js +131 -0
- package/dist/cli/commands/compliance-prompts.js +9 -4
- package/dist/cli/commands/compliance.js +184 -24
- package/dist/cli/commands/curation.js +23 -10
- package/dist/cli/commands/gate-level-prompts.js +39 -25
- package/dist/cli/commands/gates.js +5 -7
- package/dist/cli/commands/init.js +169 -184
- package/dist/cli/commands/install-report.js +129 -0
- package/dist/cli/commands/legacy-sweep.js +159 -0
- package/dist/cli/commands/proxy.js +6 -1
- package/dist/cli/commands/rules.js +75 -21
- package/dist/cli/commands/skills.js +42 -9
- package/dist/cli/commands/tracker.js +9 -3
- package/dist/cli/commands/uninstall.js +339 -75
- package/dist/commands/bug-analysis.md +69 -120
- package/dist/commands/dynamic-build.md +23 -23
- package/dist/commands/implement.md +46 -32
- package/dist/commands/release.md +1 -1
- package/dist/commands/resolve.md +35 -31
- package/dist/commands/self-review.md +8 -7
- package/dist/compliance-off/agents/git.md +120 -0
- package/dist/compliance-off/agents/triage.md +180 -0
- package/dist/compliance-off/commands/bug-analysis.md +398 -0
- package/dist/compliance-off/commands/code-review.md +520 -0
- package/dist/compliance-off/commands/dynamic-build.md +1251 -0
- package/dist/compliance-off/commands/dynamic-tickets.md +676 -0
- package/dist/compliance-off/commands/implement.md +736 -0
- package/dist/compliance-off/commands/plan.md +671 -0
- package/dist/compliance-off/commands/release.md +309 -0
- package/dist/compliance-off/commands/resolve.md +742 -0
- package/dist/compliance-off/skills/git/references/decision-markers.md +17 -0
- package/dist/compliance-off/skills/git/references/learn-conventions.md +80 -0
- package/dist/compliance-off/skills/git/references/pr/check-ci-status.md +33 -0
- package/dist/compliance-off/skills/git/references/pr/check-merge-readiness.md +49 -0
- package/dist/compliance-off/skills/git/references/pr/fetch-review-threads.md +52 -0
- package/dist/compliance-off/skills/git/references/pr/validate-branch.md +47 -0
- package/dist/compliance-off/skills/git/references/tracker/_contract.md +33 -0
- package/dist/compliance-off/skills/git/references/tracker/_mcp.md +153 -0
- package/dist/compliance-off/skills/git/references/tracker/github/create-release.md +35 -0
- package/dist/compliance-off/skills/git/references/tracker/github/ensure-pr-ready.md +100 -0
- package/dist/compliance-off/skills/git/references/tracker/github/ensure-traceable-issue.md +74 -0
- package/dist/compliance-off/skills/git/references/tracker/github/fetch-issue.md +69 -0
- package/dist/compliance-off/skills/git/references/tracker/github/fetch-issues-batch.md +65 -0
- package/dist/compliance-off/skills/git/references/tracker/github/gather-release-evidence.md +48 -0
- package/dist/compliance-off/skills/git/references/tracker/github/setup-task.md +77 -0
- package/dist/compliance-off/skills/git/references/tracker/jira/create-release.md +35 -0
- package/dist/compliance-off/skills/git/references/tracker/jira/ensure-pr-ready.md +100 -0
- package/dist/compliance-off/skills/git/references/tracker/jira/ensure-traceable-issue.md +61 -0
- package/dist/compliance-off/skills/git/references/tracker/jira/fetch-issue.md +51 -0
- package/dist/compliance-off/skills/git/references/tracker/jira/fetch-issues-batch.md +63 -0
- package/dist/compliance-off/skills/git/references/tracker/jira/gather-release-evidence.md +47 -0
- package/dist/compliance-off/skills/git/references/tracker/jira/setup-task.md +82 -0
- package/dist/compliance-off/skills/git/references/tracker/linear/create-release.md +35 -0
- package/dist/compliance-off/skills/git/references/tracker/linear/ensure-pr-ready.md +100 -0
- package/dist/compliance-off/skills/git/references/tracker/linear/ensure-traceable-issue.md +61 -0
- package/dist/compliance-off/skills/git/references/tracker/linear/fetch-issue.md +51 -0
- package/dist/compliance-off/skills/git/references/tracker/linear/fetch-issues-batch.md +63 -0
- package/dist/compliance-off/skills/git/references/tracker/linear/gather-release-evidence.md +47 -0
- package/dist/compliance-off/skills/git/references/tracker/linear/setup-task.md +83 -0
- package/dist/compliance-off/skills/git/references/trust-rule.md +7 -0
- package/dist/core/agent-models.js +19 -4
- package/dist/core/assets.js +126 -17
- package/dist/core/compliance-off-files.js +27 -0
- package/dist/core/compliance.js +14 -0
- package/dist/core/curation-variants.js +460 -112
- package/dist/core/flags.js +2 -2
- package/dist/core/fs-atomic.js +5 -1
- package/dist/core/installed-variants.js +63 -0
- package/dist/core/manifest.js +48 -5
- package/dist/core/mds-variants.js +700 -3
- package/dist/core/orphan-sweep.js +29 -2
- package/dist/core/path-set.js +15 -0
- package/dist/core/plugins.js +68 -10
- package/dist/core/reference-sweep.js +42 -25
- package/dist/core/retired-shipped-names.js +278 -0
- package/dist/curation-compliance-off/agents/triage.md +176 -0
- package/dist/curation-compliance-off/commands/bug-analysis.md +349 -0
- package/dist/curation-compliance-off/commands/code-review.md +481 -0
- package/dist/curation-compliance-off/commands/dynamic-build.md +1211 -0
- package/dist/curation-compliance-off/commands/dynamic-tickets.md +634 -0
- package/dist/curation-compliance-off/commands/implement.md +689 -0
- package/dist/curation-compliance-off/commands/plan.md +631 -0
- package/dist/curation-compliance-off/commands/release.md +279 -0
- package/dist/curation-compliance-off/commands/resolve.md +692 -0
- package/dist/curation-off/agents/code.md +6 -6
- package/dist/curation-off/agents/fix.md +6 -6
- package/dist/curation-off/agents/harden.md +7 -6
- package/dist/curation-off/agents/refactor.md +6 -6
- package/dist/curation-off/commands/bug-analysis.md +69 -119
- package/dist/curation-off/commands/dynamic-build.md +23 -23
- package/dist/curation-off/commands/implement.md +46 -32
- package/dist/curation-off/commands/release.md +1 -1
- package/dist/curation-off/commands/resolve.md +35 -31
- package/dist/curation-off/commands/self-review.md +8 -7
- package/dist/skills/git/references/pr/resolve-review-threads.md +1 -1
- package/dist/targets/claude-code/behavior-install.js +23 -9
- package/dist/targets/claude-code/charter-render.js +374 -0
- package/dist/targets/claude-code/compliance-install.js +62 -17
- package/dist/targets/claude-code/compliance-off-files.js +249 -0
- package/dist/targets/claude-code/curation-install.js +632 -117
- package/dist/targets/claude-code/folder-swap.js +142 -0
- package/dist/targets/claude-code/install-backup.js +780 -0
- package/dist/targets/claude-code/installer.js +795 -199
- package/dist/targets/claude-code/language-stamp.js +6 -0
- package/dist/targets/claude-code/legacy-skill-hashes.js +170 -0
- package/dist/targets/claude-code/linked-folder.js +176 -0
- package/dist/targets/claude-code/reference-converge.js +131 -0
- package/dist/targets/claude-code/rules-folder.js +34 -0
- package/dist/targets/claude-code/shipped-set.js +160 -0
- package/dist/targets/claude-code/tracker-install.js +21 -8
- package/dist/targets/claude-code/tracker-servers.js +20 -6
- package/dist/targets/claude-code/workflow-folder-install.js +251 -0
- package/dist/variant-axes.json +109 -0
- package/package.json +1 -1
- package/src/assets/agents/_partials/_code.mds +6 -6
- package/src/assets/agents/evaluate.md +1 -1
- package/src/assets/agents/git.mds +32 -0
- package/src/assets/agents/harden.mds +7 -6
- package/src/assets/agents/test.md +21 -12
- package/src/assets/agents/triage.mds +2 -0
- package/src/assets/agents/validate.md +10 -10
- package/src/assets/commands/_partials/_compliance.mds +5 -3
- package/src/assets/commands/_partials/_engine.mds +9 -8
- package/src/assets/commands/_partials/_publication.mds +10 -1
- package/src/assets/commands/bug-analysis.mds +80 -126
- package/src/assets/commands/code-review.mds +43 -0
- package/src/assets/commands/dynamic-build.mds +109 -15
- package/src/assets/commands/dynamic-tickets.mds +13 -0
- package/src/assets/commands/implement.mds +145 -33
- package/src/assets/commands/plan.mds +19 -0
- package/src/assets/commands/release.mds +50 -1
- package/src/assets/commands/resolve.mds +217 -32
- package/src/assets/commands/self-review.mds +8 -7
- package/src/assets/mds/git/_ops.mds +23 -0
- package/src/assets/mds/git/_ops_steps.mds +17 -0
- package/src/assets/mds/git/_pr.mds +1 -1
- package/src/assets/mds/git/_references.mds +6 -0
- package/src/assets/mds/tracker/_common.mds +4 -0
- package/src/assets/mds/tracker/_github.mds +42 -0
- package/src/assets/mds/tracker/_jira.mds +43 -0
- package/src/assets/mds/tracker/_linear.mds +43 -0
- package/src/assets/rules/quality.md +2 -0
- package/src/assets/scripts/ci-wait.cjs +204 -126
- package/src/assets/scripts/hooks/assets/implement-installed +1 -0
- package/src/assets/scripts/hooks/assets/orchestrator-charter.md +13 -11
- package/src/assets/scripts/hooks/preamble +18 -8
- package/src/assets/scripts/hooks/session-start-orchestrator +4 -2
- package/src/assets/scripts/pr-evidence.cjs +41 -2
- package/src/assets/scripts/verify-evidence.cjs +408 -56
- package/src/assets/skills/agent-references/references/commands/implement-revalidate.md +3 -3
- package/src/assets/skills/agent-references/references/commands/plan-levels.md +1 -1
- package/src/assets/skills/agent-references/references/synthesize/bug-analysis.md +6 -2
- package/src/assets/skills/agent-references/references/validate/passed-alone.md +7 -7
- package/src/assets/skills/docs-framework/SKILL.md +5 -2
- package/src/assets/skills/git/SKILL.md +3 -3
- package/src/assets/skills/git/references/github-api.md +2 -139
- package/src/assets/skills/git/references/github-posting.md +158 -0
- package/src/assets/skills/review-methodology/SKILL.md +1 -1
- package/src/assets/skills/review-methodology/references/patterns.md +1 -1
- package/src/assets/skills/review-methodology/references/report-template.md +1 -2
- package/src/assets/skills/testing/SKILL.md +2 -4
|
@@ -14,11 +14,15 @@ import { loadCurationMove } from '../../core/curation-move.js';
|
|
|
14
14
|
import { describeMoveText, describeOutcome, runInitCurationMove, shownSkipAt } from './curation-move-step.js';
|
|
15
15
|
import { realGlobalTuningMoveIO, realProjectLedgerMoveIO } from './curation-move-io.js';
|
|
16
16
|
import { describeEchoedValue } from '../../core/echo-value.js';
|
|
17
|
-
import { installViaFileCopy,
|
|
18
|
-
import {
|
|
17
|
+
import { installViaFileCopy, installScripts } from '../../targets/claude-code/installer.js';
|
|
18
|
+
import { logSummaryLines, openBackupSession, runWithLateBackupReport } from './backup-session.js';
|
|
19
|
+
import { formatKeptLegacySkills, formatLinksSummary, formatOverlaySummary, formatSkillScopeSummary, formatTrackerAssetSummary, isPluginListUnchanged } from './install-report.js';
|
|
20
|
+
import { mergeLinkReports, newLinkReport } from '../../targets/claude-code/linked-folder.js';
|
|
21
|
+
import { sweepLegacyDevflowFiles, sweepLegacySkillFolders } from './legacy-sweep.js';
|
|
22
|
+
import { removeRulesFolder, rulesFolderRefusedMessage } from '../../targets/claude-code/rules-folder.js';
|
|
19
23
|
import { convergeTrackerArtifacts } from '../../targets/claude-code/tracker-install.js';
|
|
20
24
|
import { installSettings, installManagedSettings, installClaudeignore, hasClaudeignore, discoverProjectGitRoots, ensureDevflowGitignore, applyUserSecurityDenyList, detectDenyState, resolveSecurityAction, assertHistoricalDenySuperset, loadTemplateDenyEntries, stripUserSecurityDenyList, } from '../../targets/claude-code/post-install.js';
|
|
21
|
-
import { DEVFLOW_PLUGINS,
|
|
25
|
+
import { DEVFLOW_PLUGINS, registeredPluginNames, buildAssetMaps, buildScopedSkillsMap, buildRulesMap, partitionSelectablePlugins, WORKFLOW_ORDER, parsePluginSelection, resolveFeatureRedirect } from '../../core/plugins.js';
|
|
22
26
|
import { LEGACY_SKILL_NAMES } from '../../targets/claude-code/legacy.js';
|
|
23
27
|
import { detectPlatform, detectShell, getProfilePath, getSafeDeleteInfo, hasSafeDelete } from '../../core/safe-delete.js';
|
|
24
28
|
import { generateSafeDeleteBlock, installToProfile, removeFromProfile, getInstalledVersion, SAFE_DELETE_BLOCK_VERSION } from '../../core/safe-delete-install.js';
|
|
@@ -49,8 +53,8 @@ import { applyTrackerSentinel, effectiveTrackerServers, parseTrackerId, rearmTra
|
|
|
49
53
|
import { formatTrackerSummary, shouldRunTrackerStep, runTrackerStep, buildClackTrackerPrompts, } from './tracker-prompts.js';
|
|
50
54
|
import { buildClackGateLevelPrompts, carriedGateLevel, formatGateLevelRow, formatGateLevelSummary, readStoredGateLevel, resolveGateLevelForInit, resolveGateLevelInitState, } from './gate-level-prompts.js';
|
|
51
55
|
import { shouldRunAttributionStep, runAttributionStep, buildClackAttributionPrompts, applyAttributionAnswer, attributionSeedFrom, } from './attribution-prompts.js';
|
|
52
|
-
import {
|
|
53
|
-
import {
|
|
56
|
+
import { convergeVariantAxes, describePostingLeft, installedVersionMatches, readRunningVersion } from '../../targets/claude-code/curation-install.js';
|
|
57
|
+
import { POSTING_OFF_NOTICE, installRecordFor, postingNoticeDue, readInstalledVariants } from '../../core/installed-variants.js';
|
|
54
58
|
import { auditAndRecordClaudeMd, formatClaudeMdAuditNote, formatClaudeMdAuditUnavailable, } from '../../core/claude-md-audit.js';
|
|
55
59
|
import * as os from 'os';
|
|
56
60
|
// Re-export pure functions for tests (canonical source is post-install.ts)
|
|
@@ -118,32 +122,41 @@ export function formatSweepSummary(report) {
|
|
|
118
122
|
return lines;
|
|
119
123
|
}
|
|
120
124
|
/**
|
|
121
|
-
*
|
|
122
|
-
*
|
|
125
|
+
* Converge the installed agents onto the saved model and effort assignments, after the file copy
|
|
126
|
+
* wrote the shipped defaults. Per-item failures are non-fatal.
|
|
123
127
|
*
|
|
124
|
-
*
|
|
125
|
-
*
|
|
126
|
-
*
|
|
128
|
+
* Init-only optimization: with an empty mapping and the proxy off, every agent already holds its
|
|
129
|
+
* shipped default, so the walk would read the agent files and write none; it is skipped. The
|
|
130
|
+
* disable and revert paths call `reapplyAgentMapping` directly and always need the full walk.
|
|
131
|
+
* `hasAgentMappingEntries` counts agent entries only: an `agents.memory`-only mapping names no
|
|
132
|
+
* installed file, so it keeps this gate closed (D-WORKER-AGENTS).
|
|
133
|
+
*
|
|
134
|
+
* The links this walk met are returned, not printed: the caller prints them once, through the same
|
|
135
|
+
* summary as the install step. `verbose` prints the other warnings of the walk.
|
|
127
136
|
*/
|
|
128
|
-
function
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
137
|
+
export async function reapplyAgentMappingForInit(opts) {
|
|
138
|
+
const { proxyEnabled, claudeDir, devflowDir, verbose } = opts;
|
|
139
|
+
const preCheckMapping = await readAgentMapping(devflowDir);
|
|
140
|
+
const hasMappingEntries = preCheckMapping.ok && hasAgentMappingEntries(preCheckMapping.value);
|
|
141
|
+
if (!hasMappingEntries && !proxyEnabled)
|
|
142
|
+
return newLinkReport();
|
|
143
|
+
const result = await reapplyAgentMapping({
|
|
144
|
+
proxyEnabled,
|
|
145
|
+
installDir: path.join(claudeDir, 'agents', 'devflow'),
|
|
146
|
+
devflowDir,
|
|
147
|
+
});
|
|
148
|
+
const links = { replacedLinks: result.replacedLinks, refusedFolders: result.refusedFolders };
|
|
149
|
+
if (verbose) {
|
|
150
|
+
const linkLines = new Set(formatLinksSummary(links).map(line => line.message));
|
|
151
|
+
for (const warning of result.warnings) {
|
|
152
|
+
if (!linkLines.has(warning))
|
|
153
|
+
p.log.warn(warning);
|
|
154
|
+
}
|
|
155
|
+
if (result.updated.length > 0) {
|
|
156
|
+
p.log.info(`Agent model mapping reapplied: ${result.updated.length} agent(s) updated`);
|
|
145
157
|
}
|
|
146
158
|
}
|
|
159
|
+
return links;
|
|
147
160
|
}
|
|
148
161
|
/**
|
|
149
162
|
* Classify the safe-delete installation state based on the installed version
|
|
@@ -591,6 +604,20 @@ export function buildHudOnlyManifest(existing, version, now, refusedGateLevel) {
|
|
|
591
604
|
updatedAt: now,
|
|
592
605
|
};
|
|
593
606
|
}
|
|
607
|
+
/**
|
|
608
|
+
* The plugin names `init --hud-only` renders the orchestrator charter for. Pure.
|
|
609
|
+
*
|
|
610
|
+
* D-CHARTER-INSTALL-RENDER: --hud-only reinstalls no plugin, so the installed charter must keep describing
|
|
611
|
+
* what the manifest says is installed: the recorded plugins, with a deleted name pruned and a legacy name
|
|
612
|
+
* mapped as every other partial run does (`resolvePluginList`), and only names this registry has kept
|
|
613
|
+
* ({@link registeredPluginNames}). With no manifest, or one `readManifest()` refused, nothing is known to be installed, so the set is EMPTY: the
|
|
614
|
+
* render then names no workflow, and no sentinel is written. The registry fallback that uninstall takes
|
|
615
|
+
* would hand a machine with no record every workflow's routing line, which is the failure the render exists
|
|
616
|
+
* to prevent.
|
|
617
|
+
*/
|
|
618
|
+
export function hudOnlyCharterPlugins(manifest) {
|
|
619
|
+
return registeredPluginNames(resolvePluginList([], manifest, true));
|
|
620
|
+
}
|
|
594
621
|
/**
|
|
595
622
|
* The line `init --hud-only` prints when the version the manifest records is not the
|
|
596
623
|
* running version, or null when there is nothing to say. Pure.
|
|
@@ -704,8 +731,8 @@ export const initCommand = new Command('init')
|
|
|
704
731
|
.option('--no-proxy', 'Disable external model routing')
|
|
705
732
|
.option('--behavior', 'Enable the behavior rule (agents reply in ASD-STE100 Simplified Technical English; off by default)')
|
|
706
733
|
.option('--no-behavior', 'Disable the behavior rule')
|
|
707
|
-
.option('--compliance <list>', 'Enable compliance with comma-separated framework IDs (e.g., gdpr,hipaa)')
|
|
708
|
-
.option('--no-compliance', 'Disable compliance (removes the rule; the skill and framework references stay installed; frameworks remembered for re-enable)')
|
|
734
|
+
.option('--compliance <list>', 'Enable compliance with comma-separated framework IDs (e.g., gdpr,hipaa); installs the steps that post evidence and summaries to GitHub or a tracker')
|
|
735
|
+
.option('--no-compliance', 'Disable compliance (removes the rule and every step that posts evidence or summaries to GitHub or a tracker; the skill and framework references stay installed; frameworks remembered for re-enable)')
|
|
709
736
|
.option('--tracker <id>', 'The machine\'s default issue tracker provider: github, jira, or linear')
|
|
710
737
|
.option('--gate-level <full|standard|lean>', 'The machine\'s default gate level: full, standard, or lean (skips the gate level prompt)')
|
|
711
738
|
.option('--security <mode>', 'Security deny list location: user, managed, or none', /^(user|managed|none)$/i)
|
|
@@ -713,7 +740,7 @@ export const initCommand = new Command('init')
|
|
|
713
740
|
.option('--recommended', 'Apply recommended defaults after plugin selection (skip advanced prompts)')
|
|
714
741
|
.option('--advanced', 'Show all configuration prompts')
|
|
715
742
|
.option('--reset', 'Factory reset — restore all defaults, ignoring prior installation state')
|
|
716
|
-
.action(async (
|
|
743
|
+
.action((options) => runWithLateBackupReport(async (backupReport) => {
|
|
717
744
|
// Get package version
|
|
718
745
|
const packageJsonPath = path.join(getPackageRoot(), 'package.json');
|
|
719
746
|
let version = '';
|
|
@@ -781,22 +808,28 @@ export const initCommand = new Command('init')
|
|
|
781
808
|
p.log.error(`Failed to update settings: ${error instanceof Error ? error.message : error}`);
|
|
782
809
|
process.exit(1);
|
|
783
810
|
}
|
|
784
|
-
// Install HUD scripts to devflow dir
|
|
785
|
-
const scriptsTarget = path.join(devflowDir, 'scripts');
|
|
786
|
-
try {
|
|
787
|
-
await composeScripts(scriptsTarget);
|
|
788
|
-
}
|
|
789
|
-
catch (error) {
|
|
790
|
-
p.log.error(`Failed to install HUD scripts: ${error instanceof Error ? error.message : error}`);
|
|
791
|
-
process.exit(1);
|
|
792
|
-
}
|
|
793
811
|
// Read the existing manifest: over a prior install, --hud-only touches only
|
|
794
|
-
// the HUD (D-HUD-ONLY-PRESERVE in buildHudOnlyManifest).
|
|
812
|
+
// the HUD (D-HUD-ONLY-PRESERVE in buildHudOnlyManifest). Read before the scripts are
|
|
813
|
+
// installed, so the charter render works from the record as the run found it.
|
|
795
814
|
let existingHudManifest = null;
|
|
796
815
|
try {
|
|
797
816
|
existingHudManifest = await readManifest(devflowDir);
|
|
798
817
|
}
|
|
799
818
|
catch { /* absent on fresh install — existingHudManifest stays null */ }
|
|
819
|
+
// Install HUD scripts to devflow dir. The orchestrator charter and the implement sentinel
|
|
820
|
+
// render for the plugins the manifest records, and for the empty set when it records none
|
|
821
|
+
// (D-CHARTER-INSTALL-RENDER). A render failure is a warning.
|
|
822
|
+
try {
|
|
823
|
+
await installScripts({
|
|
824
|
+
scriptsTarget: path.join(devflowDir, 'scripts'),
|
|
825
|
+
plugins: hudOnlyCharterPlugins(existingHudManifest),
|
|
826
|
+
warn: (msg) => p.log.warn(msg),
|
|
827
|
+
});
|
|
828
|
+
}
|
|
829
|
+
catch (error) {
|
|
830
|
+
p.log.error(`Failed to install HUD scripts: ${error instanceof Error ? error.message : error}`);
|
|
831
|
+
process.exit(1);
|
|
832
|
+
}
|
|
800
833
|
// A manifest readManifest() refuses reads as none, but its machine gate level is still
|
|
801
834
|
// stored there: --hud-only keeps it and says so, as the full init does. --reset does not
|
|
802
835
|
// apply here, so nothing asks to forget it.
|
|
@@ -1312,9 +1345,9 @@ export const initCommand = new Command('init')
|
|
|
1312
1345
|
}
|
|
1313
1346
|
else {
|
|
1314
1347
|
p.note('Puts every session (git repos only) in orchestrator posture:\n' +
|
|
1315
|
-
'a ~
|
|
1348
|
+
'a charter of up to ~850 tokens at session start plus a per-prompt reminder\n' +
|
|
1316
1349
|
'steer the main model to delegate work to agents and devflow workflows\n' +
|
|
1317
|
-
'instead of doing it mainline. Plan-mode handoffs
|
|
1350
|
+
'instead of doing it mainline. Plan-mode handoffs run devflow:implement when it is installed.', 'Ambient Mode');
|
|
1318
1351
|
const ambientChoice = await p.select({
|
|
1319
1352
|
message: 'Enable ambient mode?',
|
|
1320
1353
|
options: [
|
|
@@ -1763,6 +1796,17 @@ export const initCommand = new Command('init')
|
|
|
1763
1796
|
const { agentsMap } = buildAssetMaps(pluginsToInstall);
|
|
1764
1797
|
// Rules: install only from selected plugins (plugin-scoped, not universal)
|
|
1765
1798
|
const rulesMap = rulesEnabled ? buildRulesMap(pluginsToInstall) : new Map();
|
|
1799
|
+
// The one backup session of this run, made before any change. The install and the converge
|
|
1800
|
+
// after it share it, so the run makes at most one backup folder. When the shipped set cannot
|
|
1801
|
+
// be built, init changes nothing.
|
|
1802
|
+
const openedBackups = await openBackupSession({ claudeDir, devflowDir });
|
|
1803
|
+
if (!openedBackups.ok) {
|
|
1804
|
+
s.stop('Installation failed');
|
|
1805
|
+
p.log.error(openedBackups.message);
|
|
1806
|
+
process.exit(1);
|
|
1807
|
+
}
|
|
1808
|
+
const backups = openedBackups.session;
|
|
1809
|
+
backupReport.begin(backups);
|
|
1766
1810
|
// D32/D35: Apply one-time migrations (global + per-project) tracked at ~/.devflow/migrations.json.
|
|
1767
1811
|
// Migrations clean up ~/.devflow runtime data and never touch the installer's copy
|
|
1768
1812
|
// targets, so their position relative to installViaFileCopy carries no dependency.
|
|
@@ -1810,67 +1854,64 @@ export const initCommand = new Command('init')
|
|
|
1810
1854
|
// their say (D-LEARNING-VARIANT-INSTALL): the files installed here and the
|
|
1811
1855
|
// manifest written at the end of init cannot disagree about it.
|
|
1812
1856
|
curation: curationEnabled,
|
|
1857
|
+
// The SETTLED compliance switch, never a raw seed or a repository's narrowing: the
|
|
1858
|
+
// variant follows the machine switch alone, and with it off the install refuses
|
|
1859
|
+
// before it writes a file when the variant files are not all there.
|
|
1860
|
+
compliance: complianceEnabled,
|
|
1813
1861
|
trackerServers,
|
|
1814
1862
|
// Non-fatal install notices with no other channel (skipped symlinks in the
|
|
1815
1863
|
// generated reference tree, mode-normalisation failures) reach the user rather
|
|
1816
1864
|
// than the void. Collected now, emitted after the spinner stops.
|
|
1817
1865
|
warn: (msg) => { installWarnings.push(msg); },
|
|
1866
|
+
backups,
|
|
1818
1867
|
});
|
|
1819
1868
|
}
|
|
1820
1869
|
catch (error) {
|
|
1821
1870
|
s.stop('Installation failed');
|
|
1822
1871
|
p.log.error(`${error}`);
|
|
1872
|
+
// A file the install moved aside before it failed is named now: nothing runs after the exit.
|
|
1873
|
+
backupReport.print();
|
|
1823
1874
|
process.exit(1);
|
|
1824
1875
|
}
|
|
1825
|
-
// D-LEARNING-VARIANT-INSTALL:
|
|
1826
|
-
// installed the variant of everything IT installed; on a `--plugin` install the
|
|
1827
|
-
// other plugins' files, already on disk, may still be
|
|
1828
|
-
//
|
|
1829
|
-
//
|
|
1830
|
-
//
|
|
1831
|
-
//
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
// partial install; hadComplianceRule covers full installs, where installViaFileCopy
|
|
1865
|
-
// wipes the rules dir before converge probes it.
|
|
1866
|
-
if (!complianceEnabled && (convergeResult.removedPreexisting || hadComplianceRule)) {
|
|
1867
|
-
p.log.info('Compliance rule removed — if you previously had devflow-compliance installed, ' +
|
|
1868
|
-
'run `devflow compliance --enable` to re-enable with your framework selection.');
|
|
1869
|
-
}
|
|
1870
|
-
}
|
|
1871
|
-
catch (err) {
|
|
1872
|
-
p.log.warn(`Compliance artifact convergence failed — install succeeded but compliance artifacts may be stale: ` +
|
|
1873
|
-
`${err instanceof Error ? err.message : String(err)}`);
|
|
1876
|
+
// The one converge for both switches (D-LEARNING-VARIANT-INSTALL, AC-27): the file copy
|
|
1877
|
+
// above installed the variant of everything IT installed; on a `--plugin` install the
|
|
1878
|
+
// other plugins' files, already on disk, may still be another variant (this run may
|
|
1879
|
+
// have flipped a switch), and the apply-decisions skill is removed here when the copy
|
|
1880
|
+
// skipped it on a partial install. It also converges the compliance skill and rule, so
|
|
1881
|
+
// enabling or disabling compliance during init needs no separate devflow compliance run.
|
|
1882
|
+
// Rewrites only what is installed. Warn-not-abort: a failure is a warning here and the
|
|
1883
|
+
// install record below is withheld, so the status line says to run init again. The agent
|
|
1884
|
+
// mapping is reapplied below.
|
|
1885
|
+
const variantConverge = await convergeVariantAxes({
|
|
1886
|
+
claudeDir,
|
|
1887
|
+
devflowDir,
|
|
1888
|
+
manifest: {
|
|
1889
|
+
features: {
|
|
1890
|
+
curation: curationEnabled,
|
|
1891
|
+
compliance: { enabled: complianceEnabled, frameworks: complianceFrameworks },
|
|
1892
|
+
rules: rulesEnabled,
|
|
1893
|
+
},
|
|
1894
|
+
},
|
|
1895
|
+
plugins: effectivePlugins,
|
|
1896
|
+
warn: (msg) => installWarnings.push(msg),
|
|
1897
|
+
backups,
|
|
1898
|
+
});
|
|
1899
|
+
if (verbose && variantConverge.converged) {
|
|
1900
|
+
p.log.info(`Curation ${curationEnabled ? 'on' : 'off'}, compliance ${complianceEnabled ? 'on' : 'off'} variants: ` +
|
|
1901
|
+
`${variantConverge.commandsRewritten.length} command(s) and ${variantConverge.agentsRewritten.length} agent(s) ` +
|
|
1902
|
+
`rewritten, ${variantConverge.unchanged} already current`);
|
|
1903
|
+
}
|
|
1904
|
+
// A compliance-off converge that cannot prove the installed prompts free of posting steps
|
|
1905
|
+
// warns and names the files; init never exits non-zero for it (AC-28 binds the compliance command).
|
|
1906
|
+
installWarnings.push(...describePostingLeft(variantConverge.posting));
|
|
1907
|
+
// I41: emit legacy-upgrade notice when compliance is disabled AND a pre-existing rule
|
|
1908
|
+
// was found. The skill is no signal — converge installs it on every machine
|
|
1909
|
+
// (D-COMPLIANCE-INSTALL-ALWAYS) — so removedPreexisting reports the rule alone, on a
|
|
1910
|
+
// partial install; hadComplianceRule covers full installs, where installViaFileCopy
|
|
1911
|
+
// wipes the rules dir before converge probes it.
|
|
1912
|
+
if (!complianceEnabled && (variantConverge.compliance.removedPreexisting || hadComplianceRule)) {
|
|
1913
|
+
p.log.info('Compliance rule removed — if you previously had devflow-compliance installed, ' +
|
|
1914
|
+
'run `devflow compliance --enable` to re-enable with your framework selection.');
|
|
1874
1915
|
}
|
|
1875
1916
|
// D-BEHAVIOR-OPT-IN: converge the behavior rule. The plugin installer never copies it (no
|
|
1876
1917
|
// plugin declares it) and a full install wiped rules/devflow/ above, so this is the one
|
|
@@ -1891,69 +1932,22 @@ export const initCommand = new Command('init')
|
|
|
1891
1932
|
if (behaviorEnabled && !rulesEnabled) {
|
|
1892
1933
|
p.log.info('Behavior rule is on but rules are disabled, so it is not installed — run `devflow rules --enable`.');
|
|
1893
1934
|
}
|
|
1894
|
-
//
|
|
1935
|
+
// Stale skill folders from previous installations move whole to the backup folder and are named,
|
|
1936
|
+
// but a bare folder moves only when its SKILL.md is a copy that a release of devflow installed.
|
|
1937
|
+
// A bare folder that the check cannot judge stays where it is, and is named here.
|
|
1895
1938
|
s.message('Cleaning up');
|
|
1896
|
-
const
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
}
|
|
1902
|
-
//
|
|
1903
|
-
const commandsDir = path.join(claudeDir, 'commands', 'devflow');
|
|
1904
|
-
let staleCommandsRemoved = 0;
|
|
1905
|
-
for (const legacy of LEGACY_COMMAND_NAMES) {
|
|
1906
|
-
for (const suffix of ['.md']) {
|
|
1907
|
-
const legacyPath = path.join(commandsDir, `${legacy}${suffix}`);
|
|
1908
|
-
try {
|
|
1909
|
-
await fs.rm(legacyPath);
|
|
1910
|
-
staleCommandsRemoved++;
|
|
1911
|
-
}
|
|
1912
|
-
catch {
|
|
1913
|
-
// Doesn't exist — expected for most entries
|
|
1914
|
-
}
|
|
1915
|
-
}
|
|
1916
|
-
}
|
|
1917
|
-
// Sweep orphaned *-teams.md workflow command variants left by the Agent Teams
|
|
1918
|
-
// refactor. None are ever re-installed, so a blanket sweep is safe on any
|
|
1919
|
-
// install type (the full-install dir wipe only covers full installs).
|
|
1920
|
-
try {
|
|
1921
|
-
for (const f of await fs.readdir(commandsDir)) {
|
|
1922
|
-
if (f.endsWith('-teams.md')) {
|
|
1923
|
-
try {
|
|
1924
|
-
await fs.rm(path.join(commandsDir, f));
|
|
1925
|
-
staleCommandsRemoved++;
|
|
1926
|
-
}
|
|
1927
|
-
catch { /* already gone */ }
|
|
1928
|
-
}
|
|
1929
|
-
}
|
|
1930
|
-
}
|
|
1931
|
-
catch { /* commands dir absent — nothing to sweep */ }
|
|
1932
|
-
if (staleCommandsRemoved > 0 && verbose) {
|
|
1933
|
-
p.log.info(`Cleaned up ${staleCommandsRemoved} legacy command(s)`);
|
|
1934
|
-
}
|
|
1935
|
-
// Clean up stale rules from previous installations
|
|
1936
|
-
const rulesDir = path.join(claudeDir, 'rules', 'devflow');
|
|
1937
|
-
let staleRulesRemoved = 0;
|
|
1938
|
-
for (const legacy of LEGACY_RULE_NAMES) {
|
|
1939
|
-
const legacyPath = path.join(rulesDir, `${legacy}.md`);
|
|
1940
|
-
try {
|
|
1941
|
-
await fs.rm(legacyPath);
|
|
1942
|
-
staleRulesRemoved++;
|
|
1943
|
-
}
|
|
1944
|
-
catch {
|
|
1945
|
-
// Doesn't exist — expected for most entries
|
|
1946
|
-
}
|
|
1947
|
-
}
|
|
1948
|
-
if (staleRulesRemoved > 0 && verbose) {
|
|
1949
|
-
p.log.info(`Cleaned up ${staleRulesRemoved} legacy rule(s)`);
|
|
1950
|
-
}
|
|
1951
|
-
// Disable rules directory if rules not enabled
|
|
1939
|
+
const legacySkills = await sweepLegacySkillFolders({ claudeDir, backups, legacySkills: LEGACY_SKILL_NAMES });
|
|
1940
|
+
logSummaryLines(formatKeptLegacySkills(legacySkills.kept));
|
|
1941
|
+
// Clean up stale commands (e.g., /review → /code-review) and rules from previous installations.
|
|
1942
|
+
// A folder the install refused, or that is a link, is not swept: nothing is read or removed through it.
|
|
1943
|
+
// Each removed file is named on the retired line of the backup record.
|
|
1944
|
+
await sweepLegacyDevflowFiles({ claudeDir, report: installReport, backups });
|
|
1945
|
+
// Disable rules directory if rules not enabled: the files devflow did not ship move aside first.
|
|
1952
1946
|
if (!rulesEnabled) {
|
|
1953
|
-
|
|
1954
|
-
|
|
1947
|
+
const rulesFolder = path.join(claudeDir, 'rules', 'devflow');
|
|
1948
|
+
if ((await removeRulesFolder(rulesFolder, backups)) === 'refused') {
|
|
1949
|
+
p.log.warn(rulesFolderRefusedMessage(rulesFolder));
|
|
1955
1950
|
}
|
|
1956
|
-
catch { /* ignore */ }
|
|
1957
1951
|
}
|
|
1958
1952
|
// Clean up legacy hook scripts and lib files left by prior installs
|
|
1959
1953
|
// (paths relative to hooksDir; copyDirectory is additive, so stale files
|
|
@@ -1995,12 +1989,11 @@ export const initCommand = new Command('init')
|
|
|
1995
1989
|
];
|
|
1996
1990
|
const hooksDir = path.join(devflowDir, 'scripts', 'hooks');
|
|
1997
1991
|
for (const legacy of LEGACY_HOOK_FILES) {
|
|
1998
|
-
|
|
1999
|
-
try {
|
|
2000
|
-
await fs.rm(legacyPath);
|
|
2001
|
-
}
|
|
2002
|
-
catch { /* doesn't exist */ }
|
|
1992
|
+
await backups.removeExact(path.join(hooksDir, legacy));
|
|
2003
1993
|
}
|
|
1994
|
+
// Every step that moves or removes files in devflow's folders has run: name what the session
|
|
1995
|
+
// moved aside, ahead of the summary below. A throw before this point prints it on the way out.
|
|
1996
|
+
backupReport.print();
|
|
2004
1997
|
// The curation move (#529): after the legacy sweep, before the manifest persist and
|
|
2005
1998
|
// the disabled-feature drain below, so the drain sees the moved folder. Its lines
|
|
2006
1999
|
// and its one notice print with the install warnings, after the spinner stops.
|
|
@@ -2114,33 +2107,9 @@ export const initCommand = new Command('init')
|
|
|
2114
2107
|
// MUST run AFTER the proxy preflight block above: preflight can force proxyEnabled=false
|
|
2115
2108
|
// on failure, and reapply's dormancy (GPT models materialize only while proxy enabled)
|
|
2116
2109
|
// depends on the FINAL proxyEnabled value — running earlier would leave GPT model lines
|
|
2117
|
-
// in agent frontmatter after a preflight failure. Per-item failures are non-fatal.
|
|
2118
|
-
//
|
|
2119
|
-
|
|
2120
|
-
// An empty mapping means every agent uses its shipped default; the file copy already
|
|
2121
|
-
// wrote those defaults, so reapply would read ~34 files and write zero. The
|
|
2122
|
-
// disable/revert paths call reapplyAgentMapping directly and always need the full walk.
|
|
2123
|
-
{
|
|
2124
|
-
const agentInstallDir = path.join(claudeDir, 'agents', 'devflow');
|
|
2125
|
-
const preCheckMapping = await readAgentMapping(devflowDir);
|
|
2126
|
-
// hasAgentMappingEntries counts agent entries only: an agents.memory-only
|
|
2127
|
-
// mapping names no installed file, so it keeps this gate closed (D-WORKER-AGENTS).
|
|
2128
|
-
const hasMappingEntries = preCheckMapping.ok && hasAgentMappingEntries(preCheckMapping.value);
|
|
2129
|
-
if (hasMappingEntries || proxyEnabled) {
|
|
2130
|
-
const reapplyResult = await reapplyAgentMapping({
|
|
2131
|
-
proxyEnabled,
|
|
2132
|
-
installDir: agentInstallDir,
|
|
2133
|
-
devflowDir,
|
|
2134
|
-
onWarning: (msg) => { if (verbose)
|
|
2135
|
-
p.log.warn(msg); },
|
|
2136
|
-
});
|
|
2137
|
-
if (reapplyResult.updated.length > 0) {
|
|
2138
|
-
if (verbose) {
|
|
2139
|
-
p.log.info(`Agent model mapping reapplied: ${reapplyResult.updated.length} agent(s) updated`);
|
|
2140
|
-
}
|
|
2141
|
-
}
|
|
2142
|
-
}
|
|
2143
|
-
}
|
|
2110
|
+
// in agent frontmatter after a preflight failure. Per-item failures are non-fatal. The links
|
|
2111
|
+
// the walk met are printed below, through the install summary.
|
|
2112
|
+
const agentMappingLinks = await reapplyAgentMappingForInit({ proxyEnabled, claudeDir, devflowDir, verbose });
|
|
2144
2113
|
// Configure ambient hook, memory hooks, and HUD statusLine in a single read-modify-write pass
|
|
2145
2114
|
try {
|
|
2146
2115
|
let content = await fs.readFile(settingsPath, 'utf-8');
|
|
@@ -2437,6 +2406,10 @@ export const initCommand = new Command('init')
|
|
|
2437
2406
|
// Reference-overlay reporting: the overlay rewrites files inside an installed skill
|
|
2438
2407
|
// the user may have shadowed, and reports any unit it had to leave alone.
|
|
2439
2408
|
logSummaryLines(formatOverlaySummary(installReport));
|
|
2409
|
+
// A link the install or the agent model reapply replaced is a change to a path the user made.
|
|
2410
|
+
// A folder either refused is not refreshed, and looks refreshed on disk. A path the two steps
|
|
2411
|
+
// both met is named once.
|
|
2412
|
+
logSummaryLines(formatLinksSummary(mergeLinkReports(installReport, agentMappingLinks)));
|
|
2440
2413
|
// Skill-scoping reporting: a deselected skill is deleted and a dormant shadow
|
|
2441
2414
|
// is inert, and neither is distinguishable from "never installed" on disk.
|
|
2442
2415
|
//
|
|
@@ -2484,6 +2457,7 @@ export const initCommand = new Command('init')
|
|
|
2484
2457
|
}
|
|
2485
2458
|
// Write installation manifest for upgrade tracking (non-fatal — install already succeeded)
|
|
2486
2459
|
const now = new Date().toISOString();
|
|
2460
|
+
const installRecord = installRecordFor(variantConverge.converged, { curation: curationEnabled, compliance: complianceEnabled });
|
|
2487
2461
|
const manifestData = {
|
|
2488
2462
|
version,
|
|
2489
2463
|
// Resolved above, before the install, because the skills install set is
|
|
@@ -2525,6 +2499,9 @@ export const initCommand = new Command('init')
|
|
|
2525
2499
|
},
|
|
2526
2500
|
installedAt: existingManifest?.installedAt ?? now,
|
|
2527
2501
|
updatedAt: now,
|
|
2502
|
+
// The install record, written only after a converge that finished clean (AC-29): an
|
|
2503
|
+
// unclean one leaves the field out, which reads as unknown and names `devflow init`.
|
|
2504
|
+
...(installRecord !== null ? { installedVariants: installRecord } : {}),
|
|
2528
2505
|
};
|
|
2529
2506
|
// ── Manifest write + tracker selection lifecycle (the ONE call site) ──────
|
|
2530
2507
|
// persistManifestThenConvergeTracker owns the ordering invariant: the
|
|
@@ -2542,6 +2519,14 @@ export const initCommand = new Command('init')
|
|
|
2542
2519
|
else
|
|
2543
2520
|
p.log.info(msg.text);
|
|
2544
2521
|
}
|
|
2522
|
+
// The posting notice (AC-30): once, when the record moves from posting (compliance on, or no
|
|
2523
|
+
// record before this release) to non-posting. It follows the record write, so a record that
|
|
2524
|
+
// was withheld or never reached the disk leaves the notice due for the next init.
|
|
2525
|
+
if (trackerLifecycle.manifestWritten &&
|
|
2526
|
+
installRecord !== null &&
|
|
2527
|
+
postingNoticeDue(readInstalledVariants(existingManifest?.installedVariants), complianceEnabled)) {
|
|
2528
|
+
p.log.info(POSTING_OFF_NOTICE);
|
|
2529
|
+
}
|
|
2545
2530
|
// Only now that the machine-wide switch is on disk (D-INIT-DRAIN-AFTER-SWITCH).
|
|
2546
2531
|
const drainRoot = await lookupDrainLedgerRoot({ gitRoot, curationEnabled, manifestWritten: trackerLifecycle.manifestWritten });
|
|
2547
2532
|
if (drainRoot.warning !== null)
|
|
@@ -2607,5 +2592,5 @@ export const initCommand = new Command('init')
|
|
|
2607
2592
|
p.log.info(`External model routing: ${color.green('enabled')} — takes effect in new Claude Code sessions`);
|
|
2608
2593
|
}
|
|
2609
2594
|
p.outro(color.green('Ready! Run any command in Claude Code to get started.'));
|
|
2610
|
-
});
|
|
2595
|
+
}));
|
|
2611
2596
|
//# sourceMappingURL=init.js.map
|