devflow-kit 3.4.0 → 3.6.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 +127 -0
- package/README.md +12 -8
- package/dist/agents/code.md +39 -182
- package/dist/agents/{diagnose.md → debug.md} +4 -4
- package/dist/agents/design.md +0 -1
- package/dist/agents/fix.md +165 -0
- package/dist/agents/git.md +31 -693
- package/dist/agents/{scrutinize.md → harden.md} +9 -6
- package/dist/agents/knowledge.md +8 -2
- package/dist/agents/refactor.md +133 -0
- package/dist/agents/research.md +6 -0
- package/dist/agents/review.md +0 -4
- package/dist/agents/skim.md +4 -0
- package/dist/agents/triage.md +8 -1
- package/dist/cli/agents-view/render.js +1 -1
- package/dist/cli/commands/behavior-prompts.js +77 -0
- package/dist/cli/commands/behavior.js +123 -0
- package/dist/cli/commands/flags.js +8 -2
- package/dist/cli/commands/init-seed.js +7 -3
- package/dist/cli/commands/init.js +75 -8
- package/dist/cli/commands/learning.js +12 -12
- package/dist/cli/commands/legacy-hooks.js +1 -1
- package/dist/cli/commands/rules.js +16 -0
- package/dist/cli/commands/tracker.js +112 -15
- package/dist/cli/commands/uninstall.js +111 -5
- package/dist/cli.js +2 -0
- package/dist/commands/bug-analysis.md +22 -18
- package/dist/commands/code-review.md +25 -29
- package/dist/commands/debug.md +36 -15
- package/dist/commands/dynamic-build.md +64 -78
- package/dist/commands/dynamic-plan.md +18 -14
- package/dist/commands/dynamic-profile.md +8 -6
- package/dist/commands/dynamic-tickets.md +19 -15
- package/dist/commands/explore.md +14 -14
- package/dist/commands/implement.md +122 -225
- package/dist/commands/plan.md +32 -47
- package/dist/commands/release.md +12 -7
- package/dist/commands/research.md +26 -15
- package/dist/commands/resolve.md +53 -92
- package/dist/commands/self-review.md +42 -42
- package/dist/core/agent-frontmatter.js +101 -0
- package/dist/core/agent-models.js +47 -11
- package/dist/core/compliance-compose.js +6 -4
- package/dist/core/{learning-tuning-config.js → curate-tuning-config.js} +14 -14
- package/dist/core/feature-switch.js +23 -2
- package/dist/core/flags.js +111 -0
- package/dist/core/learning-queue-cleanup.js +1 -1
- package/dist/core/manifest.js +11 -3
- package/dist/core/mds-variants.js +68 -26
- package/dist/core/migrations.js +63 -44
- package/dist/core/plugins.js +49 -70
- package/dist/core/project-paths.js +3 -7
- package/dist/core/proxy-log.js +1 -1
- package/dist/core/proxy-state.js +1 -1
- package/dist/core/tracker.js +120 -2
- package/dist/hud/codex-usage.js +247 -0
- package/dist/hud/components/codex-quota.js +37 -0
- package/dist/hud/components/usage-quota.js +1 -1
- package/dist/hud/config.js +1 -0
- package/dist/hud/index.js +16 -3
- package/dist/hud/render.js +3 -1
- package/dist/learning-off/agents/code.md +37 -180
- package/dist/learning-off/agents/{diagnose.md → debug.md} +4 -4
- package/dist/learning-off/agents/design.md +0 -1
- package/dist/learning-off/agents/fix.md +161 -0
- package/dist/learning-off/agents/{scrutinize.md → harden.md} +9 -6
- package/dist/learning-off/agents/knowledge.md +8 -2
- package/dist/learning-off/agents/refactor.md +129 -0
- package/dist/learning-off/agents/research.md +6 -0
- package/dist/learning-off/agents/review.md +0 -4
- package/dist/learning-off/agents/skim.md +4 -0
- package/dist/learning-off/agents/triage.md +8 -1
- package/dist/learning-off/commands/bug-analysis.md +12 -12
- package/dist/learning-off/commands/code-review.md +14 -22
- package/dist/learning-off/commands/debug.md +24 -8
- package/dist/learning-off/commands/dynamic-build.md +58 -74
- package/dist/learning-off/commands/dynamic-plan.md +12 -10
- package/dist/learning-off/commands/dynamic-profile.md +2 -2
- package/dist/learning-off/commands/dynamic-tickets.md +13 -11
- package/dist/learning-off/commands/explore.md +3 -7
- package/dist/learning-off/commands/implement.md +110 -217
- package/dist/learning-off/commands/plan.md +21 -39
- package/dist/learning-off/commands/release.md +7 -4
- package/dist/learning-off/commands/research.md +16 -9
- package/dist/learning-off/commands/resolve.md +42 -85
- package/dist/learning-off/commands/self-review.md +30 -34
- package/dist/skills/git/references/learn-conventions.md +27 -3
- package/dist/skills/git/references/pr/check-ci-status.md +19 -0
- package/dist/skills/git/references/pr/check-merge-readiness.md +21 -0
- package/dist/skills/git/references/pr/fetch-review-threads.md +30 -0
- package/dist/skills/git/references/pr/post-resolution-summary.md +18 -0
- package/dist/skills/git/references/pr/post-review-summary.md +20 -0
- package/dist/skills/git/references/pr/resolve-review-threads.md +28 -4
- package/dist/skills/git/references/pr/update-pr-evidence.md +17 -6
- package/dist/skills/git/references/pr/validate-branch.md +26 -0
- package/dist/skills/git/references/tracker/github/associate-release.md +24 -0
- package/dist/skills/git/references/tracker/github/backlink-shipped-issues.md +31 -1
- package/dist/skills/git/references/tracker/github/create-release.md +30 -1
- package/dist/skills/git/references/tracker/github/ensure-pr-ready.md +89 -2
- package/dist/skills/git/references/tracker/github/ensure-traceable-issue.md +16 -1
- package/dist/skills/git/references/tracker/github/fetch-issue.md +36 -1
- package/dist/skills/git/references/tracker/github/fetch-issues-batch.md +47 -1
- package/dist/skills/git/references/tracker/github/gather-release-evidence.md +25 -0
- package/dist/skills/git/references/tracker/github/manage-debt.md +21 -1
- package/dist/skills/git/references/tracker/github/post-wave-report.md +15 -1
- package/dist/skills/git/references/tracker/github/setup-task.md +41 -1
- package/dist/skills/git/references/tracker/jira/associate-release.md +24 -0
- package/dist/skills/git/references/tracker/jira/backlink-shipped-issues.md +31 -1
- package/dist/skills/git/references/tracker/jira/create-release.md +30 -1
- package/dist/skills/git/references/tracker/jira/ensure-pr-ready.md +89 -2
- package/dist/skills/git/references/tracker/jira/ensure-traceable-issue.md +16 -1
- package/dist/skills/git/references/tracker/jira/fetch-issue.md +36 -1
- package/dist/skills/git/references/tracker/jira/fetch-issues-batch.md +47 -1
- package/dist/skills/git/references/tracker/jira/gather-release-evidence.md +25 -0
- package/dist/skills/git/references/tracker/jira/manage-debt.md +21 -1
- package/dist/skills/git/references/tracker/jira/post-wave-report.md +15 -1
- package/dist/skills/git/references/tracker/jira/setup-task.md +41 -1
- package/dist/skills/git/references/tracker/linear/associate-release.md +24 -0
- package/dist/skills/git/references/tracker/linear/backlink-shipped-issues.md +31 -1
- package/dist/skills/git/references/tracker/linear/create-release.md +30 -1
- package/dist/skills/git/references/tracker/linear/ensure-pr-ready.md +89 -2
- package/dist/skills/git/references/tracker/linear/ensure-traceable-issue.md +16 -1
- package/dist/skills/git/references/tracker/linear/fetch-issue.md +36 -1
- package/dist/skills/git/references/tracker/linear/fetch-issues-batch.md +47 -1
- package/dist/skills/git/references/tracker/linear/gather-release-evidence.md +25 -0
- package/dist/skills/git/references/tracker/linear/manage-debt.md +21 -1
- package/dist/skills/git/references/tracker/linear/post-wave-report.md +15 -1
- package/dist/skills/git/references/tracker/linear/setup-task.md +41 -1
- package/dist/targets/claude-code/agent-type-owner.js +164 -0
- package/dist/targets/claude-code/behavior-install.js +111 -0
- package/dist/targets/claude-code/installer.js +177 -77
- package/dist/targets/claude-code/learning-install.js +9 -1
- package/dist/targets/claude-code/tracker-install.js +33 -16
- package/dist/targets/claude-code/tracker-servers.js +107 -0
- package/package.json +4 -3
- package/src/assets/agents/_partials/_code.mds +109 -0
- package/src/assets/agents/code.mds +18 -222
- package/src/assets/agents/{learning.md → curate.md} +22 -72
- package/src/assets/agents/{diagnose.mds → debug.mds} +4 -4
- package/src/assets/agents/design.mds +0 -1
- package/src/assets/agents/evaluate.md +11 -5
- package/src/assets/agents/explore.md +58 -0
- package/src/assets/agents/fix.mds +113 -0
- package/src/assets/agents/git.mds +31 -693
- package/src/assets/agents/{scrutinize.mds → harden.mds} +9 -6
- package/src/assets/agents/knowledge.mds +8 -2
- package/src/assets/agents/{simplify.md → polish.md} +7 -4
- package/src/assets/agents/refactor.mds +81 -0
- package/src/assets/agents/research.mds +6 -0
- package/src/assets/agents/review.mds +0 -4
- package/src/assets/agents/skim.mds +4 -0
- package/src/assets/agents/synthesize.md +26 -352
- package/src/assets/agents/test.md +10 -2
- package/src/assets/agents/tracker.md +20 -7
- package/src/assets/agents/triage.mds +8 -1
- package/src/assets/agents/validate.md +5 -0
- package/src/assets/commands/_partials/_compliance.mds +36 -0
- package/src/assets/commands/_partials/_decisions.mds +26 -6
- package/src/assets/commands/_partials/_engine.mds +17 -17
- package/src/assets/commands/_partials/_evidence_policy.mds +0 -17
- package/src/assets/commands/_partials/_knowledge.mds +14 -9
- package/src/assets/commands/_partials/_preamble.mds +5 -3
- package/src/assets/commands/_partials/_roster.mds +6 -5
- package/src/assets/commands/_partials/_wave.mds +2 -2
- package/src/assets/commands/bug-analysis.mds +10 -10
- package/src/assets/commands/code-review.mds +12 -22
- package/src/assets/commands/debug.mds +24 -2
- package/src/assets/commands/dynamic-build.mds +34 -51
- package/src/assets/commands/dynamic-plan.mds +4 -3
- package/src/assets/commands/dynamic-tickets.mds +5 -4
- package/src/assets/commands/explore.mds +1 -1
- package/src/assets/commands/implement.mds +108 -201
- package/src/assets/commands/plan.mds +19 -44
- package/src/assets/commands/release.mds +8 -3
- package/src/assets/commands/research.mds +14 -7
- package/src/assets/commands/resolve.mds +37 -82
- package/src/assets/commands/self-review.mds +27 -27
- package/src/assets/mds/.mdsroot +4 -0
- package/src/assets/mds/git/_ops.mds +383 -0
- package/src/assets/mds/git/_ops_pr.mds +201 -0
- package/src/assets/mds/git/_ops_steps.mds +147 -0
- package/src/assets/mds/git/_pr.mds +45 -50
- package/src/assets/mds/git/_references.mds +6 -3
- package/src/assets/mds/tracker/_common.mds +5 -5
- package/src/assets/mds/tracker/_contract.mds +4 -3
- package/src/assets/mds/tracker/_github.mds +60 -14
- package/src/assets/mds/tracker/_jira.mds +60 -14
- package/src/assets/mds/tracker/_linear.mds +60 -14
- package/src/assets/mds/tracker/_steps.mds +10 -9
- package/src/assets/rules/behavior.md +6 -0
- package/src/assets/scripts/hooks/assets/orchestrator-charter.md +5 -3
- package/src/assets/scripts/hooks/capture-prompt +1 -1
- package/src/assets/scripts/hooks/capture-question +1 -1
- package/src/assets/scripts/hooks/capture-turn +1 -1
- package/src/assets/scripts/hooks/json-helper.cjs +2 -2
- package/src/assets/scripts/hooks/lib/learning-store.cjs +1 -1
- package/src/assets/scripts/hooks/lib/project-paths.cjs +4 -10
- package/src/assets/scripts/hooks/preamble +1 -1
- package/src/assets/scripts/hooks/session-start-context +58 -45
- package/src/assets/scripts/verify-evidence.cjs +726 -9
- package/src/assets/skills/agent-references/SKILL.md +37 -0
- package/src/assets/skills/agent-references/references/commands/implement-evidence-asks.md +35 -0
- package/src/assets/skills/agent-references/references/commands/implement-revalidate.md +15 -0
- package/src/assets/skills/agent-references/references/curate/maintain.md +71 -0
- package/src/assets/skills/agent-references/references/synthesize/bug-analysis.md +71 -0
- package/src/assets/skills/agent-references/references/synthesize/design.md +36 -0
- package/src/assets/skills/agent-references/references/synthesize/exploration.md +38 -0
- package/src/assets/skills/agent-references/references/synthesize/planning.md +60 -0
- package/src/assets/skills/agent-references/references/synthesize/research.md +61 -0
- package/src/assets/skills/agent-references/references/synthesize/review.md +76 -0
- package/src/assets/skills/apply-decisions/SKILL.md +6 -4
- package/src/assets/skills/compliance/SKILL.md +1 -1
- package/src/assets/skills/docs-framework/SKILL.md +81 -84
- package/src/assets/skills/docs-framework/references/patterns.md +14 -25
- package/src/assets/skills/docs-framework/references/violations.md +7 -7
- package/src/assets/skills/gap-analysis/SKILL.md +0 -16
- package/src/assets/skills/gap-analysis/references/compliance.md +19 -0
- package/src/assets/skills/qa/SKILL.md +1 -1
- package/src/assets/skills/quality-gates/SKILL.md +7 -7
- package/src/assets/skills/quality-gates/references/report-template.md +7 -7
- package/dist/skills/git/references/pr/ensure-pr-ready.md +0 -24
|
@@ -39,7 +39,9 @@ import { removeManagedDenyList, describeManagedDenyRemoval } from './security.js
|
|
|
39
39
|
import { resolveInitSeed, applyCliToggles, resolveResetGatedInputs, resolvePluginsToInstall } from './init-seed.js';
|
|
40
40
|
import { parseFrameworkList, normalizeFrameworks } from '../../core/compliance.js';
|
|
41
41
|
import { formatComplianceSummary, shouldRunComplianceStep, runComplianceStep, buildClackCompliancePrompts, } from './compliance-prompts.js';
|
|
42
|
-
import {
|
|
42
|
+
import { shouldRunBehaviorStep, runBehaviorStep, buildClackBehaviorPrompts } from './behavior-prompts.js';
|
|
43
|
+
import { convergeBehaviorFromManifest } from '../../targets/claude-code/behavior-install.js';
|
|
44
|
+
import { applyTrackerSentinel, effectiveTrackerServers, parseTrackerId, rearmTrackerInference, DEFAULT_TRACKER_PROVIDER, } from '../../core/tracker.js';
|
|
43
45
|
import { formatTrackerSummary, shouldRunTrackerStep, runTrackerStep, buildClackTrackerPrompts, } from './tracker-prompts.js';
|
|
44
46
|
import { shouldRunAttributionStep, runAttributionStep, buildClackAttributionPrompts, applyAttributionAnswer, attributionSeedFrom, } from './attribution-prompts.js';
|
|
45
47
|
import { convergeFromManifest } from '../../targets/claude-code/compliance-install.js';
|
|
@@ -343,7 +345,7 @@ export function claudeMdAuditStep(outcome) {
|
|
|
343
345
|
export function buildTrackerLifecycleIO() {
|
|
344
346
|
return {
|
|
345
347
|
writeManifest,
|
|
346
|
-
convergeArtifacts: (claudeDir, warn) => convergeTrackerArtifacts({ claudeDir, warn }),
|
|
348
|
+
convergeArtifacts: (claudeDir, servers, warn) => convergeTrackerArtifacts({ claudeDir, servers, warn }),
|
|
347
349
|
rearmInference: rearmTrackerInference,
|
|
348
350
|
applySentinel: applyTrackerSentinel,
|
|
349
351
|
};
|
|
@@ -396,7 +398,7 @@ export async function persistManifestThenConvergeTracker(opts) {
|
|
|
396
398
|
// The Tracker agent file — installed on every machine (D-INSTALL-ALL-PROVIDERS),
|
|
397
399
|
// because a repository can select a provider the machine never did.
|
|
398
400
|
const agentWarnings = [];
|
|
399
|
-
const artifacts = await io.convergeArtifacts(claudeDir, (msg) => agentWarnings.push(msg));
|
|
401
|
+
const artifacts = await io.convergeArtifacts(claudeDir, effectiveTrackerServers(manifestData.features.tracker), (msg) => agentWarnings.push(msg));
|
|
400
402
|
for (const text of agentWarnings)
|
|
401
403
|
messages.push({ level: 'warn', text });
|
|
402
404
|
// D-TRACKER-PARALLEL: the two owners touch disjoint files — the attempt
|
|
@@ -495,6 +497,7 @@ export function buildHudOnlyManifest(existing, version, now) {
|
|
|
495
497
|
features: {
|
|
496
498
|
ambient: false, memory: false, hud: true, knowledge: false,
|
|
497
499
|
learning: false, rules: false, flags: {}, proxy: false,
|
|
500
|
+
behavior: false,
|
|
498
501
|
compliance: { enabled: false, frameworks: [] },
|
|
499
502
|
// The exported default, not a literal — the one constant every other
|
|
500
503
|
// module reads, so a moved default moves here too.
|
|
@@ -598,6 +601,8 @@ export const initCommand = new Command('init')
|
|
|
598
601
|
.option('--no-rules', 'Disable rules')
|
|
599
602
|
.option('--proxy', 'Enable external model routing (GPT models via your OpenAI/Codex subscription)')
|
|
600
603
|
.option('--no-proxy', 'Disable external model routing')
|
|
604
|
+
.option('--behavior', 'Enable the behavior rule (agents reply in ASD-STE100 Simplified Technical English; off by default)')
|
|
605
|
+
.option('--no-behavior', 'Disable the behavior rule')
|
|
601
606
|
.option('--compliance <list>', 'Enable compliance with comma-separated framework IDs (e.g., gdpr,hipaa)')
|
|
602
607
|
.option('--no-compliance', 'Disable compliance (removes the rule; the skill and framework references stay installed; frameworks remembered for re-enable)')
|
|
603
608
|
.option('--tracker <id>', 'The machine\'s default issue tracker provider: github, jira, or linear')
|
|
@@ -689,7 +694,7 @@ export const initCommand = new Command('init')
|
|
|
689
694
|
// ── Hoisted reads: the prior state that seeds the prompts (InitSeed, Phase 4) ──
|
|
690
695
|
let existingManifest = null;
|
|
691
696
|
try {
|
|
692
|
-
existingManifest = await readManifest(devflowDir);
|
|
697
|
+
existingManifest = await readManifest(devflowDir, { onWarning: (message) => p.log.warn(message) });
|
|
693
698
|
}
|
|
694
699
|
catch { /* unreadable manifest — seeded as a fresh install */ }
|
|
695
700
|
// D-INIT-NOT-HOME (same-location.ts): a repository rooted at HOME is no
|
|
@@ -779,7 +784,7 @@ export const initCommand = new Command('init')
|
|
|
779
784
|
'devflow-explore': 'codebase exploration + knowledge bases',
|
|
780
785
|
'devflow-research': 'multi-type research with synthesis',
|
|
781
786
|
'devflow-release': 'adaptive release with learned config',
|
|
782
|
-
'devflow-self-review': '
|
|
787
|
+
'devflow-self-review': 'Polish agent + Harden agent',
|
|
783
788
|
'devflow-bug-analysis': 'proactive bug finding, post-pipeline',
|
|
784
789
|
'devflow-typescript': 'TypeScript patterns',
|
|
785
790
|
'devflow-react': 'React patterns',
|
|
@@ -915,6 +920,10 @@ export const initCommand = new Command('init')
|
|
|
915
920
|
// Fresh installs → false (FEATURE_DEFAULTS.proxy). Re-inits → prior manifest value.
|
|
916
921
|
// --reset → false (resolveResetGatedInputs null-seeds the manifest).
|
|
917
922
|
let proxyEnabled = seed.features.proxy;
|
|
923
|
+
// behavior (D-BEHAVIOR-OPT-IN): opt-in, manifest-group like proxy. Fresh installs and --reset
|
|
924
|
+
// → false (FEATURE_DEFAULTS.behavior); re-inits and the Recommended path keep the prior
|
|
925
|
+
// manifest value; only --behavior/--no-behavior and the Advanced wizard change it.
|
|
926
|
+
let behaviorEnabled = seed.features.behavior;
|
|
918
927
|
// compliance: manifest-group (like proxy); seed from prior manifest value.
|
|
919
928
|
// CLI override applied below in both Recommended and Advanced paths.
|
|
920
929
|
let complianceEnabled = seed.features.compliance.enabled;
|
|
@@ -922,6 +931,10 @@ export const initCommand = new Command('init')
|
|
|
922
931
|
// tracker: manifest-group (like proxy and compliance); seed from prior manifest.
|
|
923
932
|
// CLI override applied below in both Recommended and Advanced paths.
|
|
924
933
|
let trackerProvider = seed.features.tracker.provider;
|
|
934
|
+
// The tracker tool servers (D-TRACKER-SERVER-ALLOWLIST) are set by `devflow tracker --servers`
|
|
935
|
+
// alone, so init carries the prior value through untouched: it stamps the installed agents
|
|
936
|
+
// with it and writes it back to the manifest. Absent stays absent (the default list).
|
|
937
|
+
const trackerServers = seed.features.tracker.servers;
|
|
925
938
|
let enabledFlags = { ...seed.flags };
|
|
926
939
|
// viewModeExplicit: true when --reset is passed; signals resolveFinalViewMode to let the
|
|
927
940
|
// seed-time view-mode win over an externally-set value in settings.json.
|
|
@@ -1032,6 +1045,7 @@ export const initCommand = new Command('init')
|
|
|
1032
1045
|
learning: options.learning,
|
|
1033
1046
|
rules: options.rules,
|
|
1034
1047
|
proxy: options.proxy,
|
|
1048
|
+
behavior: options.behavior,
|
|
1035
1049
|
compliance: cliComplianceOverride ?? wizardCompliance,
|
|
1036
1050
|
// Precedence: cliOverride ?? wizardResult ?? seed (applyCliToggles supplies the seed arm).
|
|
1037
1051
|
tracker: cliTrackerOverride ?? wizardTracker,
|
|
@@ -1043,6 +1057,7 @@ export const initCommand = new Command('init')
|
|
|
1043
1057
|
learningEnabled = effectiveFeatures.learning;
|
|
1044
1058
|
rulesEnabled = effectiveFeatures.rules;
|
|
1045
1059
|
proxyEnabled = effectiveFeatures.proxy;
|
|
1060
|
+
behaviorEnabled = effectiveFeatures.behavior;
|
|
1046
1061
|
complianceEnabled = effectiveFeatures.compliance.enabled;
|
|
1047
1062
|
complianceFrameworks = effectiveFeatures.compliance.frameworks;
|
|
1048
1063
|
trackerProvider = effectiveFeatures.tracker.provider;
|
|
@@ -1083,6 +1098,7 @@ export const initCommand = new Command('init')
|
|
|
1083
1098
|
`HUD: ${hudEnabled ? 'enabled' : 'disabled'}`,
|
|
1084
1099
|
`Knowledge bases: ${knowledgeEnabled ? 'enabled' : 'disabled'}`,
|
|
1085
1100
|
`Ext model routing: ${proxyEnabled ? 'enabled' : 'disabled'}`,
|
|
1101
|
+
`Behavior rule: ${behaviorEnabled ? 'enabled' : 'disabled'}`,
|
|
1086
1102
|
`Compliance: ${complianceSummary}`,
|
|
1087
1103
|
// Recommended emits no per-step outcome lines, so this summary row is the
|
|
1088
1104
|
// tracker step's ONLY surface on this path — both surfaces or it is
|
|
@@ -1214,6 +1230,33 @@ export const initCommand = new Command('init')
|
|
|
1214
1230
|
}
|
|
1215
1231
|
rulesEnabled = rulesChoice;
|
|
1216
1232
|
}
|
|
1233
|
+
// Behavior rule (Advanced-only; opt-in, default OFF; D-BEHAVIOR-OPT-IN). Runs after the
|
|
1234
|
+
// rules step because the rule installs only while rules are on, and the gate knows it.
|
|
1235
|
+
// A skipped gate leaves the seeded value, which --behavior/--no-behavior replace.
|
|
1236
|
+
if (shouldRunBehaviorStep({
|
|
1237
|
+
isTTY: process.stdin.isTTY,
|
|
1238
|
+
hasCliOverride: options.behavior !== undefined,
|
|
1239
|
+
rulesEnabled,
|
|
1240
|
+
})) {
|
|
1241
|
+
const behaviorStep = await runBehaviorStep({
|
|
1242
|
+
seed: behaviorEnabled,
|
|
1243
|
+
prompts: buildClackBehaviorPrompts(),
|
|
1244
|
+
});
|
|
1245
|
+
if (behaviorStep.kind === 'cancelled') {
|
|
1246
|
+
p.cancel('Installation cancelled.');
|
|
1247
|
+
process.exit(0);
|
|
1248
|
+
}
|
|
1249
|
+
behaviorEnabled = behaviorStep.enabled;
|
|
1250
|
+
for (const msg of behaviorStep.messages) {
|
|
1251
|
+
if (msg.level === 'success')
|
|
1252
|
+
p.log.success(msg.text);
|
|
1253
|
+
else
|
|
1254
|
+
p.log.info(msg.text);
|
|
1255
|
+
}
|
|
1256
|
+
}
|
|
1257
|
+
else if (options.behavior !== undefined) {
|
|
1258
|
+
behaviorEnabled = options.behavior;
|
|
1259
|
+
}
|
|
1217
1260
|
// External model routing (Advanced-only; default OFF; never part of Recommended)
|
|
1218
1261
|
if (options.proxy !== undefined) {
|
|
1219
1262
|
proxyEnabled = options.proxy;
|
|
@@ -1582,6 +1625,7 @@ export const initCommand = new Command('init')
|
|
|
1582
1625
|
// their say (D-LEARNING-VARIANT-INSTALL): the files installed here and the
|
|
1583
1626
|
// manifest written at the end of init cannot disagree about it.
|
|
1584
1627
|
learning: learningEnabled,
|
|
1628
|
+
trackerServers,
|
|
1585
1629
|
// Non-fatal install notices with no other channel (skipped symlinks in the
|
|
1586
1630
|
// generated reference tree, mode-normalisation failures) reach the user rather
|
|
1587
1631
|
// than the void. Collected now, emitted after the spinner stops.
|
|
@@ -1643,6 +1687,25 @@ export const initCommand = new Command('init')
|
|
|
1643
1687
|
p.log.warn(`Compliance artifact convergence failed — install succeeded but compliance artifacts may be stale: ` +
|
|
1644
1688
|
`${err instanceof Error ? err.message : String(err)}`);
|
|
1645
1689
|
}
|
|
1690
|
+
// D-BEHAVIOR-OPT-IN: converge the behavior rule. The plugin installer never copies it (no
|
|
1691
|
+
// plugin declares it) and a full install wiped rules/devflow/ above, so this is the one
|
|
1692
|
+
// writer: it installs the file when the switch is on and rules are on, and removes it
|
|
1693
|
+
// otherwise. Warn-not-abort, like the compliance convergence.
|
|
1694
|
+
try {
|
|
1695
|
+
await convergeBehaviorFromManifest({
|
|
1696
|
+
claudeDir,
|
|
1697
|
+
devflowDir,
|
|
1698
|
+
manifest: { features: { behavior: behaviorEnabled, rules: rulesEnabled } },
|
|
1699
|
+
warn: (msg) => p.log.warn(msg),
|
|
1700
|
+
});
|
|
1701
|
+
}
|
|
1702
|
+
catch (err) {
|
|
1703
|
+
p.log.warn(`Behavior rule convergence failed — install succeeded but the behavior rule may be stale: ` +
|
|
1704
|
+
`${err instanceof Error ? err.message : String(err)}`);
|
|
1705
|
+
}
|
|
1706
|
+
if (behaviorEnabled && !rulesEnabled) {
|
|
1707
|
+
p.log.info('Behavior rule is on but rules are disabled, so it is not installed — run `devflow rules --enable`.');
|
|
1708
|
+
}
|
|
1646
1709
|
// Clean up stale skills from previous installations
|
|
1647
1710
|
s.message('Cleaning up');
|
|
1648
1711
|
const skillsDir = path.join(claudeDir, 'skills');
|
|
@@ -1904,7 +1967,7 @@ export const initCommand = new Command('init')
|
|
|
1904
1967
|
content = addCaptureHooks(cleanedForCapture, devflowDir);
|
|
1905
1968
|
// Memory hooks — Stop (memory-worker), SessionStart (session-start-memory),
|
|
1906
1969
|
// PreCompact — through the same transform `devflow memory --enable/--disable`
|
|
1907
|
-
// uses (D-FEATURES-NARROW-ONLY).
|
|
1970
|
+
// uses (D-FEATURES-NARROW-ONLY). Curate agent (spawned via
|
|
1908
1971
|
// session-start-context directive) handles decision/pitfall detection.
|
|
1909
1972
|
// Knowledge is handled in-command via write-through (knowledge_writeback MDS partial).
|
|
1910
1973
|
content = convergeMemoryHooks(content, memoryEnabled, devflowDir);
|
|
@@ -1917,7 +1980,7 @@ export const initCommand = new Command('init')
|
|
|
1917
1980
|
content = addContextHook(cleanedForContext, devflowDir);
|
|
1918
1981
|
// Legacy dream-worker hook cleanup — strip any stale spawn-dream-worker entry
|
|
1919
1982
|
// left in settings.json by a prior install (session-start-context now spawns
|
|
1920
|
-
// the
|
|
1983
|
+
// the Curate agent via directive).
|
|
1921
1984
|
content = removeDreamHook(content);
|
|
1922
1985
|
// Strip Devflow-managed teammateMode ("auto"). User-set values (e.g. "tmux") are preserved.
|
|
1923
1986
|
content = stripDevflowTeammateModeFromJson(content);
|
|
@@ -2249,6 +2312,10 @@ export const initCommand = new Command('init')
|
|
|
2249
2312
|
security: securityMode,
|
|
2250
2313
|
// Final resolved value — may be forced off by preflight failure.
|
|
2251
2314
|
proxy: proxyEnabled,
|
|
2315
|
+
// Resolved behavior switch (D-BEHAVIOR-OPT-IN) — seeded from the prior manifest,
|
|
2316
|
+
// overridden by --behavior/--no-behavior and the Advanced wizard. The rule file was
|
|
2317
|
+
// converged above to match it.
|
|
2318
|
+
behavior: behaviorEnabled,
|
|
2252
2319
|
// Resolved compliance state — seeded from prior manifest, overridden by CLI flags
|
|
2253
2320
|
// and Advanced wizard selection. convergeComplianceArtifacts was called above.
|
|
2254
2321
|
// normalizeFrameworks: dedup + filter unknowns before persisting.
|
|
@@ -2256,7 +2323,7 @@ export const initCommand = new Command('init')
|
|
|
2256
2323
|
// Resolved tracker selection. Already a validated TrackerProvider — it came
|
|
2257
2324
|
// through parseTrackerId (CLI), the typed wizard select, or the seed, which
|
|
2258
2325
|
// itself came through normalizeTrackerFeature on read.
|
|
2259
|
-
tracker: { provider: trackerProvider },
|
|
2326
|
+
tracker: { provider: trackerProvider, ...(trackerServers !== undefined ? { servers: trackerServers } : {}) },
|
|
2260
2327
|
},
|
|
2261
2328
|
installedAt: existingManifest?.installedAt ?? now,
|
|
2262
2329
|
updatedAt: now,
|
|
@@ -3,7 +3,7 @@ import { promises as fs } from 'fs';
|
|
|
3
3
|
import * as path from 'path';
|
|
4
4
|
import * as p from '@clack/prompts';
|
|
5
5
|
import color from 'picocolors';
|
|
6
|
-
import { getLearningDir,
|
|
6
|
+
import { getLearningDir, getCurateTuningConfigPath, } from '../../core/project-paths.js';
|
|
7
7
|
import { loadShippedAgentDefaults } from '../../core/agent-models.js';
|
|
8
8
|
import { readMachineFeature, writeMachineFeature } from '../../core/feature-switch.js';
|
|
9
9
|
import { loadSettingsModule, narrowedSwitchLabel, personalConfigTrackedWarning } from '../../core/evidence-policy.js';
|
|
@@ -263,7 +263,7 @@ async function handleRestore(anchor) {
|
|
|
263
263
|
* The scope choices of `devflow learning --configure`.
|
|
264
264
|
*
|
|
265
265
|
* D-LEARNING-MODEL-PRECEDENCE: the session-start hook takes the first layer that
|
|
266
|
-
* supplies a model — the project file, then a `devflow agents`
|
|
266
|
+
* supplies a model — the project file, then a `devflow agents` Curate mapping,
|
|
267
267
|
* then the global file. A global file therefore has no effect for a user who has
|
|
268
268
|
* such a mapping, and its hint says so.
|
|
269
269
|
*/
|
|
@@ -272,24 +272,24 @@ export const CONFIGURE_SCOPE_OPTIONS = [
|
|
|
272
272
|
{
|
|
273
273
|
value: 'global',
|
|
274
274
|
label: 'Global',
|
|
275
|
-
hint: 'All projects (~/.devflow/learning.json); a devflow agents
|
|
275
|
+
hint: 'All projects (~/.devflow/learning.json); a devflow agents Curate mapping takes precedence over it',
|
|
276
276
|
},
|
|
277
277
|
];
|
|
278
278
|
/** The models `devflow learning --configure` offers, each with what it is good for. */
|
|
279
|
-
const
|
|
279
|
+
const CURATE_MODEL_CHOICES = [
|
|
280
280
|
{ value: 'opus', label: 'Opus', note: 'highest quality for detection + curation judgment' },
|
|
281
281
|
{ value: 'sonnet', label: 'Sonnet', note: 'good balance of quality and speed' },
|
|
282
282
|
{ value: 'haiku', label: 'Haiku', note: 'fastest, lowest cost' },
|
|
283
283
|
];
|
|
284
284
|
/**
|
|
285
|
-
* D-LEARNING-SHIPPED-ROW: the model offered as "Recommended" is the one the
|
|
285
|
+
* D-LEARNING-SHIPPED-ROW: the model offered as "Recommended" is the one the Curate
|
|
286
286
|
* agent ships with, the `model:` line of its frontmatter. It is read from there and
|
|
287
287
|
* written nowhere else, so a change of the shipped tier moves the recommendation with
|
|
288
288
|
* it and this list never has to be edited. A shipped model outside the three offered
|
|
289
289
|
* (or none) recommends nothing.
|
|
290
290
|
*/
|
|
291
|
-
export function
|
|
292
|
-
return
|
|
291
|
+
export function curateModelOptions(shippedModel) {
|
|
292
|
+
return CURATE_MODEL_CHOICES.map(choice => ({
|
|
293
293
|
value: choice.value,
|
|
294
294
|
label: choice.label,
|
|
295
295
|
hint: choice.value === shippedModel
|
|
@@ -299,10 +299,10 @@ export function learningModelOptions(shippedModel) {
|
|
|
299
299
|
}
|
|
300
300
|
async function handleConfigure() {
|
|
301
301
|
p.intro(color.bgCyan(color.black(' Learning Configuration ')));
|
|
302
|
-
const shippedModel = (await loadShippedAgentDefaults()).
|
|
302
|
+
const shippedModel = (await loadShippedAgentDefaults()).curate?.model;
|
|
303
303
|
const model = await p.select({
|
|
304
304
|
message: 'Model for decision detection',
|
|
305
|
-
options:
|
|
305
|
+
options: curateModelOptions(shippedModel),
|
|
306
306
|
});
|
|
307
307
|
if (p.isCancel(model)) {
|
|
308
308
|
p.cancel('Configuration cancelled.');
|
|
@@ -341,7 +341,7 @@ async function handleConfigure() {
|
|
|
341
341
|
// main checkout in a linked worktree; the current directory outside git.
|
|
342
342
|
const projectRoot = (await getLedgerRoot()) ?? process.cwd();
|
|
343
343
|
const learningDir = getLearningDir(projectRoot);
|
|
344
|
-
const projectConfigPath =
|
|
344
|
+
const projectConfigPath = getCurateTuningConfigPath(projectRoot);
|
|
345
345
|
// D-CLI-NO-SYMLINK (core/linked-path.ts): nothing is written through a .devflow,
|
|
346
346
|
// a learning folder or a learning.json that is a symbolic link.
|
|
347
347
|
const linked = await firstSymbolicLink([path.dirname(learningDir), learningDir, projectConfigPath]);
|
|
@@ -419,7 +419,7 @@ async function handleClear() {
|
|
|
419
419
|
process.exitCode = 1;
|
|
420
420
|
return;
|
|
421
421
|
}
|
|
422
|
-
// A mid-run
|
|
422
|
+
// A mid-run Curate agent whose claimed batch vanishes stops without further
|
|
423
423
|
// writes — the desired outcome of clearing.
|
|
424
424
|
const drain = await drainLearningQueue(ledgerRoot);
|
|
425
425
|
p.log.success(`Cleared ${counted(cleared.value.cleared, 'observation')} no entry uses and kept ${cleared.value.kept} ` +
|
|
@@ -480,7 +480,7 @@ async function handleToggle(enabled) {
|
|
|
480
480
|
return;
|
|
481
481
|
}
|
|
482
482
|
// Drain the current project's learning (decisions-detection) queue so stale
|
|
483
|
-
// turns don't process on re-enable. A mid-run
|
|
483
|
+
// turns don't process on re-enable. A mid-run Curate agent whose claimed
|
|
484
484
|
// batch vanishes aborts without changes — the desired outcome of disabling.
|
|
485
485
|
const ledgerRoot = await getLedgerRoot();
|
|
486
486
|
if (ledgerRoot) {
|
|
@@ -2,7 +2,7 @@ import { devflowHookOwner, hasHook, removeHooks, } from '../../targets/claude-co
|
|
|
2
2
|
// ─── Dream worker hook cleanup ──────────────────────────────────────────────
|
|
3
3
|
//
|
|
4
4
|
// The spawn-dream-worker SessionStart hook belonged to the retired detached
|
|
5
|
-
// dream worker. Decisions processing runs as the directive-spawned
|
|
5
|
+
// dream worker. Decisions processing runs as the directive-spawned Curate agent
|
|
6
6
|
// (session-start-context Section 2), which needs no hook registration of its
|
|
7
7
|
// own. remove/has exist for upgrade cleanup: init and uninstall strip any
|
|
8
8
|
// stale entry left in settings.json by a prior install.
|
|
@@ -9,6 +9,7 @@ import { readManifest, writeManifest } from '../../core/manifest.js';
|
|
|
9
9
|
import { rulesDir } from '../../core/assets.js';
|
|
10
10
|
import { installAllRules, validateRuleShadow } from '../../targets/claude-code/installer.js';
|
|
11
11
|
import { convergeFromManifest } from '../../targets/claude-code/compliance-install.js';
|
|
12
|
+
import { convergeBehaviorFromManifest } from '../../targets/claude-code/behavior-install.js';
|
|
12
13
|
/**
|
|
13
14
|
* Check whether a rule has a user shadow file at ~/.devflow/rules/{name}.md.
|
|
14
15
|
*/
|
|
@@ -256,6 +257,21 @@ export async function runRulesEnable(claudeDir, devflowDir) {
|
|
|
256
257
|
// Warn-not-abort — compliance convergence failure does not undo rules install
|
|
257
258
|
p.log.warn(`Compliance rule convergence failed — rules installed but compliance rule may be stale: ${err instanceof Error ? err.message : String(err)}`);
|
|
258
259
|
}
|
|
260
|
+
// D-BEHAVIOR-OPT-IN: the wipe above removed the opt-in behavior rule with the rest of
|
|
261
|
+
// the directory, so bring it back when its switch is on. Same rulesEnabledOverride
|
|
262
|
+
// reasoning as compliance: a failed install leaves no rules to add this one to.
|
|
263
|
+
try {
|
|
264
|
+
await convergeBehaviorFromManifest({
|
|
265
|
+
claudeDir,
|
|
266
|
+
devflowDir,
|
|
267
|
+
manifest,
|
|
268
|
+
warn: (msg) => p.log.warn(msg),
|
|
269
|
+
rulesEnabledOverride: !installFailed,
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
catch (err) {
|
|
273
|
+
p.log.warn(`Behavior rule convergence failed — rules installed but the behavior rule may be stale: ${err instanceof Error ? err.message : String(err)}`);
|
|
274
|
+
}
|
|
259
275
|
}
|
|
260
276
|
export const rulesCommand = new Command('rules')
|
|
261
277
|
.description('Manage Devflow rules')
|
|
@@ -16,18 +16,22 @@
|
|
|
16
16
|
* --set converges the sentinel in BOTH directions, so flipping
|
|
17
17
|
* back to github removes what flipping away wrote.
|
|
18
18
|
* A failed re-arm or sentinel step warns, it never aborts.
|
|
19
|
+
* --servers sets the machine's tracker tool servers (D-TRACKER-SERVER-ALLOWLIST) and
|
|
20
|
+
* re-stamps the installed Git and Tracker agents at once; it is orthogonal to --set and
|
|
21
|
+
* neither flag touches the other's manifest field.
|
|
19
22
|
*/
|
|
20
23
|
import { Command } from 'commander';
|
|
21
24
|
import { promises as fs } from 'fs';
|
|
22
25
|
import * as path from 'path';
|
|
23
26
|
import * as p from '@clack/prompts';
|
|
24
27
|
import color from 'picocolors';
|
|
25
|
-
import { DEFAULT_TRACKER_PROVIDER, TRACKER_ATTEMPTS_MAX, TRACKER_CONVENTIONS_READ_BYTES, TRACKER_PROVIDERS, applyTrackerSentinel, describeTrackerValue, parseTrackerFrontmatter, parseTrackerId, readBoundedHead, rearmTrackerInference, trackerConventionsPath, } from '../../core/tracker.js';
|
|
28
|
+
import { DEFAULT_TRACKER_PROVIDER, TRACKER_ATTEMPTS_MAX, TRACKER_CONVENTIONS_READ_BYTES, TRACKER_PROVIDERS, applyTrackerSentinel, describeTrackerValue, effectiveTrackerServers, parseTrackerFrontmatter, parseTrackerId, parseTrackerServers, readBoundedHead, rearmTrackerInference, trackerConventionsPath, } from '../../core/tracker.js';
|
|
26
29
|
import { readManifest, syncManifestFeature } from '../../core/manifest.js';
|
|
27
30
|
import { loadSettingsModule, personalConfigTrackedWarning, repoTrackerSelection } from '../../core/evidence-policy.js';
|
|
28
31
|
import { getClaudeDirectory, getDevFlowDirectory } from '../../targets/claude-code/claude-paths.js';
|
|
29
32
|
import { SKILL_REFS_SKILL_NAME, installedReferenceManifest } from '../../core/mds-variants.js';
|
|
30
33
|
import { prefixSkillName } from '../../core/plugins.js';
|
|
34
|
+
import { TRACKER_STAMPED_AGENTS, restampTrackerAgents, } from '../../targets/claude-code/tracker-servers.js';
|
|
31
35
|
/**
|
|
32
36
|
* Read the provenance header of `~/.devflow/tracker/{provider}.md`.
|
|
33
37
|
*
|
|
@@ -112,6 +116,10 @@ export async function readTrackerStatusConventions(devflowDir, provider) {
|
|
|
112
116
|
provenance: await readTrackerProvenance(devflowDir, provider),
|
|
113
117
|
};
|
|
114
118
|
}
|
|
119
|
+
/** Render the tracker servers for the `--status` note. Pure; every name was validated at its boundary. */
|
|
120
|
+
export function formatTrackerServers(list, isDefault) {
|
|
121
|
+
return `${list.join(', ')}${isDefault ? ` ${color.dim('(default)')}` : ''}`;
|
|
122
|
+
}
|
|
115
123
|
/**
|
|
116
124
|
* The `--status` note's lines. Pure.
|
|
117
125
|
*
|
|
@@ -131,7 +139,7 @@ export function formatTrackerStatus(input) {
|
|
|
131
139
|
}
|
|
132
140
|
lines.push(...(input.conventions.kind === 'none'
|
|
133
141
|
? ['Conventions: none (GitHub needs no learned conventions)', 'File: none']
|
|
134
|
-
: [`Conventions: ${formatTrackerProvenance(input.conventions.provenance)}`, `File: ${input.conventions.file}`]), `Mechanics: ${formatTrackerMechanics(input.mechanics)}`, `Inference: ${input.inference}`);
|
|
142
|
+
: [`Conventions: ${formatTrackerProvenance(input.conventions.provenance)}`, `File: ${input.conventions.file}`]), `Mechanics: ${formatTrackerMechanics(input.mechanics)}`, `Servers: ${formatTrackerServers(input.servers.list, input.servers.isDefault)}`, `Inference: ${input.inference}`);
|
|
135
143
|
return lines.join('\n');
|
|
136
144
|
}
|
|
137
145
|
/** The real adapter — the ONE binding of each operation into the `--set` path. */
|
|
@@ -164,7 +172,8 @@ export function buildTrackerSetIO() {
|
|
|
164
172
|
export async function runTrackerSet(opts) {
|
|
165
173
|
const { devflowDir, current, requested, io } = opts;
|
|
166
174
|
const messages = [];
|
|
167
|
-
|
|
175
|
+
// The provider changes; the tracker servers are a different setting and ride along.
|
|
176
|
+
await io.syncManifest(devflowDir, { ...current, provider: requested });
|
|
168
177
|
// [DR-22] a selection change re-arms the attempt counters; [DR-10] the
|
|
169
178
|
// sentinel converges in both directions.
|
|
170
179
|
const rearm = await io.rearmInference(devflowDir);
|
|
@@ -180,18 +189,72 @@ export async function runTrackerSet(opts) {
|
|
|
180
189
|
});
|
|
181
190
|
return { provider: requested, messages };
|
|
182
191
|
}
|
|
192
|
+
/** The real adapter — the ONE binding of each operation into the `--servers` path. */
|
|
193
|
+
export function buildTrackerServersIO() {
|
|
194
|
+
return {
|
|
195
|
+
syncManifest: (devflowDir, state) => syncManifestFeature(devflowDir, 'tracker', state),
|
|
196
|
+
restamp: (claudeDir, servers, warn) => restampTrackerAgents({ claudeDir, servers, warn }),
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Set the machine's tracker tool servers.
|
|
201
|
+
*
|
|
202
|
+
* Follows `--set`'s convergence order (D-TRACKER-CONVERGE-SET): the manifest first, then
|
|
203
|
+
* the installed agents, which are re-stamped ONLY when the manifest write landed, so an
|
|
204
|
+
* installed agent never names a list the manifest does not record. Unlike `--set`, a failed
|
|
205
|
+
* manifest write is the whole command failing (there is nothing else for it to do), so it is
|
|
206
|
+
* returned as `ok: false` for the caller to exit on; a failed re-stamp warns, it never aborts.
|
|
207
|
+
*
|
|
208
|
+
* `default` removes the key, so an absent `servers` stays the one spelling of the default.
|
|
209
|
+
* Never throws.
|
|
210
|
+
*/
|
|
211
|
+
export async function runTrackerServers(opts) {
|
|
212
|
+
const { devflowDir, claudeDir, current, requested, io } = opts;
|
|
213
|
+
const messages = [];
|
|
214
|
+
const next = requested.kind === 'default'
|
|
215
|
+
? { provider: current.provider }
|
|
216
|
+
: { provider: current.provider, servers: requested.servers };
|
|
217
|
+
try {
|
|
218
|
+
await io.syncManifest(devflowDir, next);
|
|
219
|
+
}
|
|
220
|
+
catch (err) {
|
|
221
|
+
messages.push({
|
|
222
|
+
level: 'error',
|
|
223
|
+
text: `Could not write the manifest — the tracker servers were not changed (${err instanceof Error ? err.message : String(err)})`,
|
|
224
|
+
});
|
|
225
|
+
return { ok: false, state: current, messages };
|
|
226
|
+
}
|
|
227
|
+
const servers = effectiveTrackerServers(next);
|
|
228
|
+
const unchanged = servers.join('\n') === effectiveTrackerServers(current).join('\n');
|
|
229
|
+
const label = `${servers.join(', ')}${requested.kind === 'default' ? ' (default)' : ''}`;
|
|
230
|
+
messages.push({ level: unchanged ? 'info' : 'success', text: `Tracker servers: ${label}${unchanged ? ' (unchanged)' : ''}` });
|
|
231
|
+
const restamp = await io.restamp(claudeDir, servers, (message) => messages.push({ level: 'warn', text: message }));
|
|
232
|
+
const done = restamp.rewritten.length + restamp.unchanged.length;
|
|
233
|
+
if (restamp.absent.length === TRACKER_STAMPED_AGENTS.length && restamp.failed.length === 0) {
|
|
234
|
+
messages.push({ level: 'info', text: 'No installed Git or Tracker agent to update — run devflow init' });
|
|
235
|
+
}
|
|
236
|
+
else if (restamp.rewritten.length > 0) {
|
|
237
|
+
messages.push({ level: 'info', text: `Updated the installed ${restamp.rewritten.join(' and ')} agent${restamp.rewritten.length > 1 ? 's' : ''}` });
|
|
238
|
+
}
|
|
239
|
+
else if (done > 0 && restamp.failed.length === 0) {
|
|
240
|
+
messages.push({ level: 'info', text: 'The installed agents already carry this list' });
|
|
241
|
+
}
|
|
242
|
+
return { ok: true, state: next, messages };
|
|
243
|
+
}
|
|
183
244
|
export const trackerCommand = new Command('tracker')
|
|
184
|
-
.description('Show or set the machine\'s issue tracker provider')
|
|
245
|
+
.description('Show or set the machine\'s issue tracker provider and tracker servers')
|
|
185
246
|
.option('--status', 'Show the provider in effect and its learned conventions file, and re-arm background inference')
|
|
186
247
|
.option('--set <id>', 'Set the machine\'s default issue tracker provider: github, jira, or linear')
|
|
248
|
+
.option('--servers <names>', 'Set the tracker servers the Git and Tracker agents may call: comma-separated names, or "default"')
|
|
187
249
|
.action(async (options) => {
|
|
188
250
|
const devflowDir = getDevFlowDirectory();
|
|
189
|
-
const hasFlag = options.status || options.set !== undefined;
|
|
251
|
+
const hasFlag = options.status || options.set !== undefined || options.servers !== undefined;
|
|
190
252
|
if (!hasFlag) {
|
|
191
253
|
p.intro(color.bgCyan(color.white(' Tracker ')));
|
|
192
254
|
const validIds = TRACKER_PROVIDERS.map(t => `${t.id} — ${t.hint}`).join('\n ');
|
|
193
255
|
p.note(`${color.cyan('devflow tracker --status')} Show the provider and learned conventions\n` +
|
|
194
|
-
`${color.cyan('devflow tracker --set <id>')} Set the machine's default provider\n
|
|
256
|
+
`${color.cyan('devflow tracker --set <id>')} Set the machine's default provider\n` +
|
|
257
|
+
`${color.cyan('devflow tracker --servers <names>')} Set the tracker servers the agents may call\n\n` +
|
|
195
258
|
`Valid provider IDs:\n ${validIds}`, 'Usage');
|
|
196
259
|
p.outro(color.dim('github is the default — devflow tracker --set github returns to it'));
|
|
197
260
|
return;
|
|
@@ -206,7 +269,17 @@ export const trackerCommand = new Command('tracker')
|
|
|
206
269
|
}
|
|
207
270
|
setProvider = parsed.value;
|
|
208
271
|
}
|
|
209
|
-
|
|
272
|
+
// Validate --servers the same way: a bad name exits before any I/O, never repaired.
|
|
273
|
+
let setServers;
|
|
274
|
+
if (options.servers !== undefined) {
|
|
275
|
+
const parsed = parseTrackerServers(options.servers);
|
|
276
|
+
if (!parsed.ok) {
|
|
277
|
+
p.log.error(parsed.error);
|
|
278
|
+
process.exit(1);
|
|
279
|
+
}
|
|
280
|
+
setServers = parsed.value;
|
|
281
|
+
}
|
|
282
|
+
const manifest = await readManifest(devflowDir, { onWarning: (message) => p.log.warn(message) });
|
|
210
283
|
if (!manifest) {
|
|
211
284
|
p.log.error('No manifest found. Run devflow init first.');
|
|
212
285
|
process.exit(1);
|
|
@@ -238,6 +311,7 @@ export const trackerCommand = new Command('tracker')
|
|
|
238
311
|
selection,
|
|
239
312
|
conventions,
|
|
240
313
|
mechanics,
|
|
314
|
+
servers: { list: effectiveTrackerServers(current), isDefault: current.servers === undefined },
|
|
241
315
|
inference,
|
|
242
316
|
}), 'Tracker Status');
|
|
243
317
|
if (!statusRearm.ok)
|
|
@@ -248,13 +322,34 @@ export const trackerCommand = new Command('tracker')
|
|
|
248
322
|
return;
|
|
249
323
|
}
|
|
250
324
|
// ── Set ────────────────────────────────────────────────────────────────────
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
325
|
+
// `--set` and `--servers` are independent settings and may be given together: the provider
|
|
326
|
+
// first, then the servers against the state it left.
|
|
327
|
+
const messages = [];
|
|
328
|
+
let state = current;
|
|
329
|
+
if (setProvider !== undefined) {
|
|
330
|
+
const outcome = await runTrackerSet({
|
|
331
|
+
devflowDir,
|
|
332
|
+
current,
|
|
333
|
+
requested: setProvider,
|
|
334
|
+
io: buildTrackerSetIO(),
|
|
335
|
+
});
|
|
336
|
+
messages.push(...outcome.messages);
|
|
337
|
+
state = { ...current, provider: outcome.provider };
|
|
338
|
+
}
|
|
339
|
+
let failed = false;
|
|
340
|
+
if (setServers !== undefined) {
|
|
341
|
+
const outcome = await runTrackerServers({
|
|
342
|
+
devflowDir,
|
|
343
|
+
claudeDir: getClaudeDirectory(),
|
|
344
|
+
current: state,
|
|
345
|
+
requested: setServers,
|
|
346
|
+
io: buildTrackerServersIO(),
|
|
347
|
+
});
|
|
348
|
+
messages.push(...outcome.messages);
|
|
349
|
+
state = outcome.state;
|
|
350
|
+
failed = !outcome.ok;
|
|
351
|
+
}
|
|
352
|
+
for (const msg of messages) {
|
|
258
353
|
switch (msg.level) {
|
|
259
354
|
case 'success':
|
|
260
355
|
p.log.success(msg.text);
|
|
@@ -270,7 +365,9 @@ export const trackerCommand = new Command('tracker')
|
|
|
270
365
|
break;
|
|
271
366
|
}
|
|
272
367
|
}
|
|
273
|
-
if (
|
|
368
|
+
if (failed)
|
|
369
|
+
process.exit(1);
|
|
370
|
+
if (setProvider !== undefined && state.provider !== DEFAULT_TRACKER_PROVIDER) {
|
|
274
371
|
p.log.info(color.dim('Your issue conventions are learned in the background at the next session start'));
|
|
275
372
|
}
|
|
276
373
|
});
|