devflow-kit 3.9.0 → 3.10.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 +111 -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/compliance-prompts.js +9 -4
- package/dist/cli/commands/compliance.js +171 -24
- package/dist/cli/commands/curation.js +12 -7
- package/dist/cli/commands/gate-level-prompts.js +39 -25
- package/dist/cli/commands/gates.js +5 -7
- package/dist/cli/commands/init.js +142 -138
- package/dist/cli/commands/install-report.js +34 -0
- package/dist/cli/commands/legacy-sweep.js +64 -0
- package/dist/cli/commands/proxy.js +6 -1
- package/dist/cli/commands/rules.js +29 -12
- package/dist/cli/commands/skills.js +42 -9
- package/dist/cli/commands/tracker.js +9 -3
- package/dist/cli/commands/uninstall.js +277 -51
- 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/curation-variants.js +460 -112
- package/dist/core/flags.js +2 -2
- 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 +11 -2
- package/dist/core/plugins.js +65 -8
- 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 +32 -12
- package/dist/targets/claude-code/compliance-off-files.js +245 -0
- package/dist/targets/claude-code/curation-install.js +570 -100
- package/dist/targets/claude-code/installer.js +467 -62
- package/dist/targets/claude-code/language-stamp.js +6 -0
- package/dist/targets/claude-code/linked-folder.js +182 -0
- package/dist/targets/claude-code/reference-converge.js +118 -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 +231 -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
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { promises as fs } from 'fs';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
import { LEGACY_COMMAND_NAMES, LEGACY_RULE_NAMES } from '../../core/plugins.js';
|
|
4
|
+
import { isUnrealFolder } from '../../targets/claude-code/linked-folder.js';
|
|
5
|
+
/**
|
|
6
|
+
* Whether the sweep may remove files from `dir`: the install did not refuse it, and `lstat` shows a
|
|
7
|
+
* real folder or nothing. `readdir` and `rm` of a path below a link act on the folder it points to.
|
|
8
|
+
*/
|
|
9
|
+
async function mayRemoveFrom(report, dir) {
|
|
10
|
+
return !report.refusedFolders.includes(dir) && !(await isUnrealFolder(dir));
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Remove the files that earlier releases installed into `commands/devflow` and `rules/devflow` and
|
|
14
|
+
* that no release installs now: the legacy command and rule names, and every `*-teams.md` command.
|
|
15
|
+
* Runs on every install shape, since the full install's pre-clean covers only a full install.
|
|
16
|
+
*
|
|
17
|
+
* A folder the install refused (`report.refusedFolders`) or that is a link now is skipped whole: the
|
|
18
|
+
* sweep reads and removes nothing there, and the folder it points to is left as it is. Never throws.
|
|
19
|
+
*
|
|
20
|
+
* @param opts.legacyCommands - Legacy command names; defaults to the registry list.
|
|
21
|
+
* @param opts.legacyRules - Legacy rule names; defaults to the registry list.
|
|
22
|
+
*/
|
|
23
|
+
export async function sweepLegacyDevflowFiles(opts) {
|
|
24
|
+
const { claudeDir, report } = opts;
|
|
25
|
+
const legacyCommands = opts.legacyCommands ?? LEGACY_COMMAND_NAMES;
|
|
26
|
+
const legacyRules = opts.legacyRules ?? LEGACY_RULE_NAMES;
|
|
27
|
+
const result = { staleCommandsRemoved: 0, staleRulesRemoved: 0 };
|
|
28
|
+
const commandsDir = path.join(claudeDir, 'commands', 'devflow');
|
|
29
|
+
if (await mayRemoveFrom(report, commandsDir)) {
|
|
30
|
+
for (const legacy of legacyCommands) {
|
|
31
|
+
try {
|
|
32
|
+
await fs.rm(path.join(commandsDir, `${legacy}.md`));
|
|
33
|
+
result.staleCommandsRemoved++;
|
|
34
|
+
}
|
|
35
|
+
catch { /* absent — expected for most entries */ }
|
|
36
|
+
}
|
|
37
|
+
// Orphaned *-teams.md workflow command variants left by the Agent Teams refactor. None is ever
|
|
38
|
+
// re-installed, so a blanket sweep is safe on any install type.
|
|
39
|
+
try {
|
|
40
|
+
for (const entry of await fs.readdir(commandsDir)) {
|
|
41
|
+
if (!entry.endsWith('-teams.md'))
|
|
42
|
+
continue;
|
|
43
|
+
try {
|
|
44
|
+
await fs.rm(path.join(commandsDir, entry));
|
|
45
|
+
result.staleCommandsRemoved++;
|
|
46
|
+
}
|
|
47
|
+
catch { /* already gone */ }
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
catch { /* commands folder absent — nothing to sweep */ }
|
|
51
|
+
}
|
|
52
|
+
const rulesDir = path.join(claudeDir, 'rules', 'devflow');
|
|
53
|
+
if (await mayRemoveFrom(report, rulesDir)) {
|
|
54
|
+
for (const legacy of legacyRules) {
|
|
55
|
+
try {
|
|
56
|
+
await fs.rm(path.join(rulesDir, `${legacy}.md`));
|
|
57
|
+
result.staleRulesRemoved++;
|
|
58
|
+
}
|
|
59
|
+
catch { /* absent — expected for most entries */ }
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return result;
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=legacy-sweep.js.map
|
|
@@ -31,6 +31,7 @@ import { stripAnsi } from '../../hud/colors.js';
|
|
|
31
31
|
import { reapplyAgentMapping, revertExternalAgents, countExternalMappedAgents, readAgentMapping, } from '../../core/agent-models.js';
|
|
32
32
|
import { getExternalModelsCached, discoverExternalModels, } from '../../core/model-discovery.js';
|
|
33
33
|
import { modelCacheDir } from '../../core/cache.js';
|
|
34
|
+
import { formatLinksSummary } from './install-report.js';
|
|
34
35
|
import { getClaudeDirectory, getDevFlowDirectory, getHomeDirectory, } from '../../targets/claude-code/claude-paths.js';
|
|
35
36
|
import { devflowHookOwner, ensureHook, hasHook, removeHooks, runHookCommand, } from '../../targets/claude-code/hooks.js';
|
|
36
37
|
function Ok(value) {
|
|
@@ -1389,6 +1390,8 @@ async function runEnable(portOption) {
|
|
|
1389
1390
|
s.message('Warming model cache...');
|
|
1390
1391
|
await discoverExternalModels(cacheDir, logPath).catch(() => { });
|
|
1391
1392
|
s.stop(color.green('External model routing enabled'));
|
|
1393
|
+
for (const { message } of formatLinksSummary(reapplyResult))
|
|
1394
|
+
p.log.warn(message);
|
|
1392
1395
|
// D-P4-1: applies-on-restart — env var takes effect only for new sessions
|
|
1393
1396
|
p.log.info(color.dim('Context-window enforcement disabled for relay-routed models — applies to new Claude Code sessions'));
|
|
1394
1397
|
if (adopted) {
|
|
@@ -1472,7 +1475,9 @@ async function runDisable() {
|
|
|
1472
1475
|
// Step 3: Sync manifest
|
|
1473
1476
|
await syncManifestFeature(devflowDir, 'proxy', false);
|
|
1474
1477
|
// Step 4: Revert external agents to shipped defaults
|
|
1475
|
-
await revertExternalAgents({ installDir, devflowDir });
|
|
1478
|
+
const revertResult = await revertExternalAgents({ installDir, devflowDir });
|
|
1479
|
+
for (const { message } of formatLinksSummary(revertResult))
|
|
1480
|
+
p.log.warn(message);
|
|
1476
1481
|
p.log.success('External model routing disabled');
|
|
1477
1482
|
// Step 5: Terminate the relay process.
|
|
1478
1483
|
// Identity is confirmed via TCP + health before signalling — a recycled PID
|
|
@@ -10,6 +10,8 @@ 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
12
|
import { convergeBehaviorFromManifest } from '../../targets/claude-code/behavior-install.js';
|
|
13
|
+
import { newLinkReport, refuseUnrealFolder, refusedFolderMessage, removeReportingLink } from '../../targets/claude-code/linked-folder.js';
|
|
14
|
+
import { formatLinksSummary } from './install-report.js';
|
|
13
15
|
/**
|
|
14
16
|
* Check whether a rule has a user shadow file at ~/.devflow/rules/{name}.md.
|
|
15
17
|
*/
|
|
@@ -213,17 +215,24 @@ export async function runRulesEnable(claudeDir, devflowDir) {
|
|
|
213
215
|
}
|
|
214
216
|
const installedPlugins = DEVFLOW_PLUGINS.filter(pl => manifest.plugins.includes(pl.name));
|
|
215
217
|
const rulesMap = buildRulesMap(installedPlugins);
|
|
216
|
-
// Wipe stale rules from previously uninstalled plugins before re-installing.
|
|
217
|
-
|
|
218
|
-
|
|
218
|
+
// Wipe stale rules from previously uninstalled plugins before re-installing. A rules folder that is
|
|
219
|
+
// a link is unlinked and replaced by a real folder, never emptied through, and the link is reported.
|
|
220
|
+
const links = newLinkReport();
|
|
221
|
+
links.replacedLinks.push(...await removeReportingLink(rulesTarget));
|
|
222
|
+
// A link that could not be removed is still there, and `mkdir` and every rule write would follow it.
|
|
223
|
+
// Prove the folder first; a refused folder gets no rule, no manifest write and one refusal line.
|
|
224
|
+
const rulesFolderRefused = await refuseUnrealFolder(links, rulesTarget);
|
|
219
225
|
let outcomes = [];
|
|
220
|
-
let installFailed =
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
226
|
+
let installFailed = rulesFolderRefused;
|
|
227
|
+
if (!rulesFolderRefused) {
|
|
228
|
+
await fs.mkdir(rulesTarget, { recursive: true });
|
|
229
|
+
try {
|
|
230
|
+
outcomes = await installAllRules(rulesMap, devflowDir, rulesTarget, links);
|
|
231
|
+
}
|
|
232
|
+
catch (err) {
|
|
233
|
+
p.log.error(`Rules installation failed — rules directory has been cleared: ${err instanceof Error ? err.message : String(err)}`);
|
|
234
|
+
installFailed = true;
|
|
235
|
+
}
|
|
227
236
|
}
|
|
228
237
|
if (!installFailed) {
|
|
229
238
|
const shadowedCount = outcomes.filter(o => o.outcome === 'shadow').length;
|
|
@@ -239,6 +248,14 @@ export async function runRulesEnable(claudeDir, devflowDir) {
|
|
|
239
248
|
await writeManifest(devflowDir, manifest);
|
|
240
249
|
p.log.success(`Installed ${rulesMap.size} rule(s) to ${color.dim(rulesTarget)}${shadowSuffix}`);
|
|
241
250
|
}
|
|
251
|
+
for (const { message } of formatLinksSummary(links))
|
|
252
|
+
p.log.warn(message);
|
|
253
|
+
// Each converge below proves the rules folder again and names a refused one itself; the line above
|
|
254
|
+
// has already named it, so the repeat is dropped.
|
|
255
|
+
const warnConverge = (msg) => {
|
|
256
|
+
if (!(rulesFolderRefused && msg === refusedFolderMessage(rulesTarget)))
|
|
257
|
+
p.log.warn(msg);
|
|
258
|
+
};
|
|
242
259
|
// Converge compliance artifacts unconditionally — convergeFromManifest handles the
|
|
243
260
|
// disabled case itself (removes stale artifacts). Running this regardless of installFailed
|
|
244
261
|
// prevents a rules-install failure from leaving the compliance rule in a stale state.
|
|
@@ -249,7 +266,7 @@ export async function runRulesEnable(claudeDir, devflowDir) {
|
|
|
249
266
|
claudeDir,
|
|
250
267
|
devflowDir,
|
|
251
268
|
manifest,
|
|
252
|
-
warn:
|
|
269
|
+
warn: warnConverge,
|
|
253
270
|
rulesEnabledOverride: !installFailed,
|
|
254
271
|
});
|
|
255
272
|
}
|
|
@@ -265,7 +282,7 @@ export async function runRulesEnable(claudeDir, devflowDir) {
|
|
|
265
282
|
claudeDir,
|
|
266
283
|
devflowDir,
|
|
267
284
|
manifest,
|
|
268
|
-
warn:
|
|
285
|
+
warn: warnConverge,
|
|
269
286
|
rulesEnabledOverride: !installFailed,
|
|
270
287
|
});
|
|
271
288
|
}
|
|
@@ -4,7 +4,7 @@ import * as path from 'path';
|
|
|
4
4
|
import * as p from '@clack/prompts';
|
|
5
5
|
import color from 'picocolors';
|
|
6
6
|
import { getClaudeDirectory, getDevFlowDirectory } from '../../targets/claude-code/claude-paths.js';
|
|
7
|
-
import { getAllSkillNames, prefixSkillName, unprefixSkillName, skillOwners, FEATURE_OWNED_SKILLS } from '../../core/plugins.js';
|
|
7
|
+
import { getAllSkillNames, prefixSkillName, unprefixSkillName, skillOwners, FEATURE_OWNED_SKILLS, WORKFLOW_FOLDER_NAMES } from '../../core/plugins.js';
|
|
8
8
|
import { skillsDir } from '../../core/assets.js';
|
|
9
9
|
import { copyDirectory, validateSkillShadow } from '../../targets/claude-code/installer.js';
|
|
10
10
|
/**
|
|
@@ -42,6 +42,22 @@ export function shadowSeedDir(bareName, installedDir) {
|
|
|
42
42
|
return sourceDir;
|
|
43
43
|
return installedDir ?? sourceDir;
|
|
44
44
|
}
|
|
45
|
+
/**
|
|
46
|
+
* D-WORKFLOW-SHADOW-REFUSAL: why `devflow skills shadow <name>` refuses a workflow that ships as a
|
|
47
|
+
* skill folder, or null for any other name.
|
|
48
|
+
*
|
|
49
|
+
* A folder installs from the build tree of the machine's exact variant key, with no source
|
|
50
|
+
* directory to copy and no shadow to overlay, so a shadow of its name could never apply. Refusing
|
|
51
|
+
* at the command says so before the user edits a copy that does nothing; the install ignores a
|
|
52
|
+
* shadow that is already there, with a warning, and keeps it.
|
|
53
|
+
*
|
|
54
|
+
* @param folderWorkflows - The target-layer set; the default is the real set.
|
|
55
|
+
*/
|
|
56
|
+
export function workflowFolderShadowRefusal(bareName, folderWorkflows = WORKFLOW_FOLDER_NAMES) {
|
|
57
|
+
if (!folderWorkflows.has(bareName))
|
|
58
|
+
return null;
|
|
59
|
+
return `${bareName} ships as a skill folder built for the machine's variant, so a shadow cannot replace it. Nothing was shadowed.`;
|
|
60
|
+
}
|
|
45
61
|
/**
|
|
46
62
|
* Check if a skill has a shadow (personal override).
|
|
47
63
|
*/
|
|
@@ -85,16 +101,19 @@ function buildSkillShadowTag(shadowState) {
|
|
|
85
101
|
}
|
|
86
102
|
}
|
|
87
103
|
}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
104
|
+
/**
|
|
105
|
+
* Run one `devflow skills` action: shadow, unshadow or list.
|
|
106
|
+
*
|
|
107
|
+
* @param folderWorkflows - The workflows that ship as skill folders; the default is the real
|
|
108
|
+
* set. They count as known skills, `shadow` refuses them, and `list` tags a leftover shadow
|
|
109
|
+
* of one as ignored. Tests pass a fixture set, because the real set is empty.
|
|
110
|
+
*/
|
|
111
|
+
export async function runSkillsAction(action, name, folderWorkflows = WORKFLOW_FOLDER_NAMES) {
|
|
93
112
|
const devflowDir = getDevFlowDirectory();
|
|
94
113
|
const claudeDir = getClaudeDirectory();
|
|
95
114
|
// Union FEATURE_OWNED_SKILLS (compliance) so shadow/unshadow/list cover feature-managed
|
|
96
115
|
// skills that left the plugin registry but still live in src/assets/skills/ (step 1.5).
|
|
97
|
-
const allSkills = [...getAllSkillNames(), ...FEATURE_OWNED_SKILLS];
|
|
116
|
+
const allSkills = [...getAllSkillNames(folderWorkflows), ...FEATURE_OWNED_SKILLS];
|
|
98
117
|
if (action === 'shadow') {
|
|
99
118
|
if (!name) {
|
|
100
119
|
p.log.error('Skill name required. Usage: devflow skills shadow <name>');
|
|
@@ -103,6 +122,11 @@ export const skillsCommand = new Command('skills')
|
|
|
103
122
|
}
|
|
104
123
|
// Accept both bare and prefixed input
|
|
105
124
|
const bareName = unprefixSkillName(name);
|
|
125
|
+
const refusal = workflowFolderShadowRefusal(bareName, folderWorkflows);
|
|
126
|
+
if (refusal !== null) {
|
|
127
|
+
p.log.error(refusal);
|
|
128
|
+
process.exit(1);
|
|
129
|
+
}
|
|
106
130
|
if (!allSkills.includes(bareName)) {
|
|
107
131
|
p.log.error(`Unknown skill: ${bareName}`);
|
|
108
132
|
p.log.info(`Available skills: ${allSkills.join(', ')}`);
|
|
@@ -183,7 +207,11 @@ export const skillsCommand = new Command('skills')
|
|
|
183
207
|
const provenance = installed
|
|
184
208
|
? color.dim(`installed because: ${describeOwners(skill, ownersBySkill.get(skill))}`)
|
|
185
209
|
: color.dim(`not installed — provided by: ${describeOwners(skill, ownersBySkill.get(skill))}`);
|
|
186
|
-
|
|
210
|
+
// A shadow of a skill folder is kept but never applied (D-WORKFLOW-SHADOW-REFUSAL).
|
|
211
|
+
const tag = workflowFolderShadowRefusal(skill, folderWorkflows) !== null && shadowState !== 'none'
|
|
212
|
+
? color.yellow('shadow ignored — skill folder')
|
|
213
|
+
: buildSkillShadowTag(shadowState);
|
|
214
|
+
return ` ${color.cyan(skill.padEnd(28))} ${tag.padEnd(20)} ${provenance}`;
|
|
187
215
|
});
|
|
188
216
|
// Orphan shadows: in ~/.devflow/skills/ but not a known skill
|
|
189
217
|
for (const dirName of shadowDirNames) {
|
|
@@ -200,5 +228,10 @@ export const skillsCommand = new Command('skills')
|
|
|
200
228
|
p.log.info('Usage: devflow skills <shadow|unshadow|list> [name]');
|
|
201
229
|
process.exit(1);
|
|
202
230
|
}
|
|
203
|
-
}
|
|
231
|
+
}
|
|
232
|
+
export const skillsCommand = new Command('skills')
|
|
233
|
+
.description('Manage skill overrides (shadow/unshadow/list)')
|
|
234
|
+
.argument('<action>', 'Action: shadow, unshadow, or list')
|
|
235
|
+
.argument('[name]', 'Skill name (required for shadow/unshadow)')
|
|
236
|
+
.action((action, name) => runSkillsAction(action, name));
|
|
204
237
|
//# sourceMappingURL=skills.js.map
|
|
@@ -56,12 +56,18 @@ export async function readTrackerProvenance(devflowDir, provider) {
|
|
|
56
56
|
* every install carries them all (D-INSTALL-ALL-PROVIDERS) — rather than listing
|
|
57
57
|
* the directory: the question a user asks `--status` is "can the agent load what
|
|
58
58
|
* it is told to load?", and a stray file in the tree is not an answer to it.
|
|
59
|
+
*
|
|
60
|
+
* `compliance` is the machine's compliance switch, read from the install manifest by the
|
|
61
|
+
* caller and never from a repository file: a compliance-off machine installs the compliance-off
|
|
62
|
+
* manifest, which holds fewer references, so counting against the compliance-on one would read
|
|
63
|
+
* every such machine as damaged.
|
|
64
|
+
*
|
|
59
65
|
* Never throws.
|
|
60
66
|
*/
|
|
61
|
-
export async function readTrackerMechanics(claudeDir) {
|
|
67
|
+
export async function readTrackerMechanics(claudeDir, compliance) {
|
|
62
68
|
const root = path.join(claudeDir, 'skills', prefixSkillName(SKILL_REFS_SKILL_NAME), 'references');
|
|
63
69
|
let present = 0;
|
|
64
|
-
for (const rel of installedReferenceManifest()) {
|
|
70
|
+
for (const rel of installedReferenceManifest({ compliance })) {
|
|
65
71
|
try {
|
|
66
72
|
await fs.access(path.join(root, ...rel.split('/')));
|
|
67
73
|
present++;
|
|
@@ -292,7 +298,7 @@ export const trackerCommand = new Command('tracker')
|
|
|
292
298
|
const selection = repoTrackerSelection(settingsModule, { dir: process.cwd() });
|
|
293
299
|
const effective = selection?.provider ?? current.provider;
|
|
294
300
|
const conventions = await readTrackerStatusConventions(devflowDir, effective);
|
|
295
|
-
const mechanics = await readTrackerMechanics(getClaudeDirectory());
|
|
301
|
+
const mechanics = await readTrackerMechanics(getClaudeDirectory(), manifest.features.compliance.enabled);
|
|
296
302
|
// [D-F] Inspecting the status re-arms the attempt counters. --status is
|
|
297
303
|
// the command a capped user reaches for to find out why nothing is being
|
|
298
304
|
// learned, so it is the command that has to hand back another five
|