@thiagodiogo/pscode 2.3.0 → 2.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/core/init.d.ts +0 -2
- package/dist/core/init.js +7 -77
- package/dist/core/profile-sync-drift.js +1 -15
- package/dist/core/profiles.d.ts +1 -1
- package/dist/core/profiles.js +0 -13
- package/dist/core/shared/index.d.ts +1 -0
- package/dist/core/shared/index.js +1 -0
- package/dist/core/shared/prune-orphans.d.ts +39 -0
- package/dist/core/shared/prune-orphans.js +149 -0
- package/dist/core/shared/skill-generation.js +2 -14
- package/dist/core/shared/tool-detection.d.ts +2 -2
- package/dist/core/shared/tool-detection.js +1 -13
- package/dist/core/templates/skill-templates.d.ts +1 -7
- package/dist/core/templates/skill-templates.js +1 -7
- package/dist/core/templates/workflows/apply-change.js +27 -2
- package/dist/core/templates/workflows/{archive-change.d.ts → complete-change.d.ts} +1 -1
- package/dist/core/templates/workflows/{archive-change.js → complete-change.js} +2 -2
- package/dist/core/templates/workflows/propose.js +56 -1
- package/dist/core/update.d.ts +0 -20
- package/dist/core/update.js +29 -115
- package/package.json +1 -1
- package/dist/core/templates/workflows/bulk-archive-change.d.ts +0 -10
- package/dist/core/templates/workflows/bulk-archive-change.js +0 -491
- package/dist/core/templates/workflows/continue-change.d.ts +0 -10
- package/dist/core/templates/workflows/continue-change.js +0 -233
- package/dist/core/templates/workflows/ff-change.d.ts +0 -10
- package/dist/core/templates/workflows/ff-change.js +0 -199
- package/dist/core/templates/workflows/new-change.d.ts +0 -10
- package/dist/core/templates/workflows/new-change.js +0 -142
- package/dist/core/templates/workflows/onboard.d.ts +0 -10
- package/dist/core/templates/workflows/onboard.js +0 -606
- package/dist/core/templates/workflows/verify-change.d.ts +0 -10
- package/dist/core/templates/workflows/verify-change.js +0 -337
package/dist/core/init.d.ts
CHANGED
package/dist/core/init.js
CHANGED
|
@@ -19,9 +19,9 @@ import { generateCommands, CommandAdapterRegistry, } from './command-generation/
|
|
|
19
19
|
import { detectLegacyArtifacts, cleanupLegacyArtifacts, formatCleanupSummary, formatDetectionSummary, } from './legacy-cleanup.js';
|
|
20
20
|
import { detectLegacyToolArtifacts, runLegacyToolMigration, formatLegacyToolDetectionSummary, formatLegacyToolMigrationSummary, pscodeDirExists, } from './openspec-migration.js';
|
|
21
21
|
import { runTrelloInitPrompt } from './trello-init-prompt.js';
|
|
22
|
-
import { getToolsWithSkillsDir, getToolStates, getSkillTemplates, getCommandContents, generateSkillContent, } from './shared/index.js';
|
|
22
|
+
import { getToolsWithSkillsDir, getToolStates, getSkillTemplates, getCommandContents, generateSkillContent, pruneOrphansForTool, } from './shared/index.js';
|
|
23
23
|
import { getGlobalConfig } from './global-config.js';
|
|
24
|
-
import { getProfileWorkflows, isValidProfile, DEFAULT_PROFILE, PROFILES
|
|
24
|
+
import { getProfileWorkflows, isValidProfile, DEFAULT_PROFILE, PROFILES } from './profiles.js';
|
|
25
25
|
import { detectDixiStack, getDixiStackFamily, getDixiStackLabel, installDixiExtras, migrateLegacyPastelsddDir } from './presets/dixi.js';
|
|
26
26
|
import { stringify as stringifyYaml } from 'yaml';
|
|
27
27
|
import { parse as parseYaml } from 'yaml';
|
|
@@ -38,31 +38,6 @@ const PROGRESS_SPINNER = {
|
|
|
38
38
|
interval: 80,
|
|
39
39
|
frames: ['░░░', '▒░░', '▒▒░', '▒▒▒', '▓▒▒', '▓▓▒', '▓▓▓', '▒▓▓', '░▒▓'],
|
|
40
40
|
};
|
|
41
|
-
const WORKFLOW_TO_SKILL_DIR = {
|
|
42
|
-
'explore': 'pscode-explore',
|
|
43
|
-
'new': 'pscode-new-change',
|
|
44
|
-
'continue': 'pscode-continue-change',
|
|
45
|
-
'apply': 'pscode-apply-change',
|
|
46
|
-
'ff': 'pscode-ff-change',
|
|
47
|
-
'complete': 'pscode-archive-change',
|
|
48
|
-
'bulk-archive': 'pscode-bulk-archive-change',
|
|
49
|
-
'verify': 'pscode-verify-change',
|
|
50
|
-
'onboard': 'pscode-onboard',
|
|
51
|
-
'propose': 'pscode-propose',
|
|
52
|
-
// Trello-specific workflows
|
|
53
|
-
'trello-setup': 'pscode-trello-setup',
|
|
54
|
-
'draft': 'pscode-trello-draft',
|
|
55
|
-
// Productivity workflows
|
|
56
|
-
'handoff': 'pscode-handoff',
|
|
57
|
-
// Dixi-specific workflows
|
|
58
|
-
'rfc': 'pscode-dixi-rfc',
|
|
59
|
-
'design': 'pscode-dixi-design',
|
|
60
|
-
'tasks': 'pscode-dixi-tasks',
|
|
61
|
-
'arch-check': 'pscode-dixi-arch-check',
|
|
62
|
-
'adr': 'pscode-dixi-adr',
|
|
63
|
-
'jira-sync': 'pscode-dixi-jira-sync',
|
|
64
|
-
'dod': 'pscode-dixi-dod',
|
|
65
|
-
};
|
|
66
41
|
// -----------------------------------------------------------------------------
|
|
67
42
|
// Init Command Class
|
|
68
43
|
// -----------------------------------------------------------------------------
|
|
@@ -529,10 +504,6 @@ export class InitCommand {
|
|
|
529
504
|
await FileSystemUtils.writeFile(skillFile, skillContent);
|
|
530
505
|
}
|
|
531
506
|
}
|
|
532
|
-
if (!shouldGenerateSkills) {
|
|
533
|
-
const skillsDir = path.join(projectPath, tool.skillsDir, 'skills');
|
|
534
|
-
removedSkillCount += await this.removeSkillDirs(skillsDir);
|
|
535
|
-
}
|
|
536
507
|
// Generate commands if delivery includes commands
|
|
537
508
|
if (shouldGenerateCommands) {
|
|
538
509
|
const adapter = CommandAdapterRegistry.get(tool.value);
|
|
@@ -547,9 +518,11 @@ export class InitCommand {
|
|
|
547
518
|
commandsSkipped.push(tool.value);
|
|
548
519
|
}
|
|
549
520
|
}
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
521
|
+
// Prune by filesystem scan: drop any Pscode-managed artifact not desired
|
|
522
|
+
// for the active profile/delivery, including orphans of removed workflows.
|
|
523
|
+
const pruned = pruneOrphansForTool(projectPath, tool.value, workflows, delivery);
|
|
524
|
+
removedSkillCount += pruned.removedSkillDirs;
|
|
525
|
+
removedCommandCount += pruned.removedCommandFiles;
|
|
553
526
|
spinner.succeed(`Setup complete for ${tool.name}`);
|
|
554
527
|
if (tool.wasConfigured) {
|
|
555
528
|
refreshedTools.push(tool);
|
|
@@ -689,10 +662,6 @@ export class InitCommand {
|
|
|
689
662
|
console.log(chalk.bold('Getting started:'));
|
|
690
663
|
console.log(' Start your first change: /ps:propose "your idea"');
|
|
691
664
|
}
|
|
692
|
-
else if (activeWorkflows.includes('new')) {
|
|
693
|
-
console.log(chalk.bold('Getting started:'));
|
|
694
|
-
console.log(' Start your first change: /ps:new "your idea"');
|
|
695
|
-
}
|
|
696
665
|
else {
|
|
697
666
|
console.log("Done. Run 'pscode config profile' to switch profiles.");
|
|
698
667
|
}
|
|
@@ -773,44 +742,5 @@ export class InitCommand {
|
|
|
773
742
|
spinner: PROGRESS_SPINNER,
|
|
774
743
|
}).start();
|
|
775
744
|
}
|
|
776
|
-
async removeSkillDirs(skillsDir) {
|
|
777
|
-
let removed = 0;
|
|
778
|
-
for (const workflow of ALL_WORKFLOWS) {
|
|
779
|
-
const dirName = WORKFLOW_TO_SKILL_DIR[workflow];
|
|
780
|
-
if (!dirName)
|
|
781
|
-
continue;
|
|
782
|
-
const skillDir = path.join(skillsDir, dirName);
|
|
783
|
-
try {
|
|
784
|
-
if (fs.existsSync(skillDir)) {
|
|
785
|
-
await fs.promises.rm(skillDir, { recursive: true, force: true });
|
|
786
|
-
removed++;
|
|
787
|
-
}
|
|
788
|
-
}
|
|
789
|
-
catch {
|
|
790
|
-
// Ignore errors
|
|
791
|
-
}
|
|
792
|
-
}
|
|
793
|
-
return removed;
|
|
794
|
-
}
|
|
795
|
-
async removeCommandFiles(projectPath, toolId) {
|
|
796
|
-
let removed = 0;
|
|
797
|
-
const adapter = CommandAdapterRegistry.get(toolId);
|
|
798
|
-
if (!adapter)
|
|
799
|
-
return 0;
|
|
800
|
-
for (const workflow of ALL_WORKFLOWS) {
|
|
801
|
-
const cmdPath = adapter.getFilePath(workflow);
|
|
802
|
-
const fullPath = path.isAbsolute(cmdPath) ? cmdPath : path.join(projectPath, cmdPath);
|
|
803
|
-
try {
|
|
804
|
-
if (fs.existsSync(fullPath)) {
|
|
805
|
-
await fs.promises.unlink(fullPath);
|
|
806
|
-
removed++;
|
|
807
|
-
}
|
|
808
|
-
}
|
|
809
|
-
catch {
|
|
810
|
-
// Ignore errors
|
|
811
|
-
}
|
|
812
|
-
}
|
|
813
|
-
return removed;
|
|
814
|
-
}
|
|
815
745
|
}
|
|
816
746
|
//# sourceMappingURL=init.js.map
|
|
@@ -9,14 +9,8 @@ import { COMMAND_IDS, getConfiguredTools } from './shared/index.js';
|
|
|
9
9
|
*/
|
|
10
10
|
export const WORKFLOW_TO_SKILL_DIR = {
|
|
11
11
|
'explore': 'pscode-explore',
|
|
12
|
-
'new': 'pscode-new-change',
|
|
13
|
-
'continue': 'pscode-continue-change',
|
|
14
12
|
'apply': 'pscode-apply-change',
|
|
15
|
-
'
|
|
16
|
-
'complete': 'pscode-archive-change',
|
|
17
|
-
'bulk-archive': 'pscode-bulk-archive-change',
|
|
18
|
-
'verify': 'pscode-verify-change',
|
|
19
|
-
'onboard': 'pscode-onboard',
|
|
13
|
+
'complete': 'pscode-complete-change',
|
|
20
14
|
'propose': 'pscode-propose',
|
|
21
15
|
// Trello-specific workflows
|
|
22
16
|
'trello-setup': 'pscode-trello-setup',
|
|
@@ -24,14 +18,6 @@ export const WORKFLOW_TO_SKILL_DIR = {
|
|
|
24
18
|
// Productivity workflows
|
|
25
19
|
'handoff': 'pscode-handoff',
|
|
26
20
|
'grill-me': 'pscode-grill-me',
|
|
27
|
-
// Dixi-specific workflows
|
|
28
|
-
'rfc': 'pscode-dixi-rfc',
|
|
29
|
-
'design': 'pscode-dixi-design',
|
|
30
|
-
'tasks': 'pscode-dixi-tasks',
|
|
31
|
-
'arch-check': 'pscode-dixi-arch-check',
|
|
32
|
-
'adr': 'pscode-dixi-adr',
|
|
33
|
-
'jira-sync': 'pscode-dixi-jira-sync',
|
|
34
|
-
'dod': 'pscode-dixi-dod',
|
|
35
21
|
};
|
|
36
22
|
function toKnownWorkflows(workflows) {
|
|
37
23
|
return workflows.filter((workflow) => ALL_WORKFLOWS.includes(workflow));
|
package/dist/core/profiles.d.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* `pscode init --profile <name>` or `pscode config profile <name>`.
|
|
6
6
|
* The workflow lists are fixed in code — users cannot customise them.
|
|
7
7
|
*/
|
|
8
|
-
export declare const ALL_WORKFLOWS: readonly ["propose", "explore", "
|
|
8
|
+
export declare const ALL_WORKFLOWS: readonly ["propose", "explore", "apply", "complete", "trello-setup", "draft", "handoff", "grill-me"];
|
|
9
9
|
export type WorkflowId = (typeof ALL_WORKFLOWS)[number];
|
|
10
10
|
export interface ProfileDefinition {
|
|
11
11
|
description: string;
|
package/dist/core/profiles.js
CHANGED
|
@@ -8,23 +8,10 @@
|
|
|
8
8
|
export const ALL_WORKFLOWS = [
|
|
9
9
|
'propose',
|
|
10
10
|
'explore',
|
|
11
|
-
'new',
|
|
12
|
-
'continue',
|
|
13
11
|
'apply',
|
|
14
|
-
'ff',
|
|
15
12
|
'complete',
|
|
16
|
-
'bulk-archive',
|
|
17
|
-
'verify',
|
|
18
|
-
'onboard',
|
|
19
13
|
'trello-setup',
|
|
20
14
|
'draft',
|
|
21
|
-
'rfc',
|
|
22
|
-
'design',
|
|
23
|
-
'tasks',
|
|
24
|
-
'arch-check',
|
|
25
|
-
'adr',
|
|
26
|
-
'jira-sync',
|
|
27
|
-
'dod',
|
|
28
15
|
'handoff',
|
|
29
16
|
'grill-me',
|
|
30
17
|
];
|
|
@@ -5,4 +5,5 @@
|
|
|
5
5
|
*/
|
|
6
6
|
export { SKILL_NAMES, type SkillName, COMMAND_IDS, type CommandId, type ToolSkillStatus, type ToolVersionStatus, getToolsWithSkillsDir, getToolSkillStatus, getToolStates, extractGeneratedByVersion, getToolVersionStatus, getConfiguredTools, getAllToolVersionStatus, } from './tool-detection.js';
|
|
7
7
|
export { type SkillTemplateEntry, type CommandTemplateEntry, getSkillTemplates, getCommandTemplates, getCommandContents, generateSkillContent, } from './skill-generation.js';
|
|
8
|
+
export { type PruneResult, pruneOrphans, pruneOrphansForTool, } from './prune-orphans.js';
|
|
8
9
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -5,4 +5,5 @@
|
|
|
5
5
|
*/
|
|
6
6
|
export { SKILL_NAMES, COMMAND_IDS, getToolsWithSkillsDir, getToolSkillStatus, getToolStates, extractGeneratedByVersion, getToolVersionStatus, getConfiguredTools, getAllToolVersionStatus, } from './tool-detection.js';
|
|
7
7
|
export { getSkillTemplates, getCommandTemplates, getCommandContents, generateSkillContent, } from './skill-generation.js';
|
|
8
|
+
export { pruneOrphans, pruneOrphansForTool, } from './prune-orphans.js';
|
|
8
9
|
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Orphan Artifact Pruning
|
|
3
|
+
*
|
|
4
|
+
* Removes Pscode-managed skill directories and slash command files that no
|
|
5
|
+
* longer correspond to a desired workflow, by **scanning the filesystem**
|
|
6
|
+
* rather than iterating `ALL_WORKFLOWS`. This is what lets `init`/`update`
|
|
7
|
+
* clean up artifacts of workflows that were deleted (or renamed) from the
|
|
8
|
+
* enum entirely — a loop over `ALL_WORKFLOWS` would never visit them.
|
|
9
|
+
*
|
|
10
|
+
* The "desired" set is computed from the same generators used when writing
|
|
11
|
+
* (`getSkillTemplates` / `adapter.getFilePath`), so there is a single source
|
|
12
|
+
* of truth and a valid artifact is never removed.
|
|
13
|
+
*
|
|
14
|
+
* Removal is strictly limited to Pscode-managed naming patterns (skill dirs
|
|
15
|
+
* prefixed `pscode-`; command files matching the adapter's own filename
|
|
16
|
+
* pattern), so user files are preserved.
|
|
17
|
+
*/
|
|
18
|
+
import type { Delivery } from '../global-config.js';
|
|
19
|
+
export interface PruneResult {
|
|
20
|
+
removedSkillDirs: number;
|
|
21
|
+
removedCommandFiles: number;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Scans installed Pscode artifacts for a single tool and removes orphans —
|
|
25
|
+
* artifacts that do not belong to a desired workflow for the active delivery.
|
|
26
|
+
*
|
|
27
|
+
* - Skills: every `pscode-*` directory whose name is not in the desired set is
|
|
28
|
+
* removed. When skills are not generated (commands-only delivery) the desired
|
|
29
|
+
* set is empty, so all Pscode skill dirs are removed.
|
|
30
|
+
* - Commands: every Pscode-managed command file whose decoded id is not in the
|
|
31
|
+
* desired set is removed. When commands are not generated (skills-only) the
|
|
32
|
+
* desired set is empty, so all managed command files are removed.
|
|
33
|
+
*/
|
|
34
|
+
export declare function pruneOrphansForTool(projectPath: string, toolId: string, desiredWorkflows: readonly string[], delivery: Delivery): PruneResult;
|
|
35
|
+
/**
|
|
36
|
+
* Prunes orphan artifacts across multiple tools, aggregating the counts.
|
|
37
|
+
*/
|
|
38
|
+
export declare function pruneOrphans(projectPath: string, toolIds: readonly string[], desiredWorkflows: readonly string[], delivery: Delivery): PruneResult;
|
|
39
|
+
//# sourceMappingURL=prune-orphans.d.ts.map
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Orphan Artifact Pruning
|
|
3
|
+
*
|
|
4
|
+
* Removes Pscode-managed skill directories and slash command files that no
|
|
5
|
+
* longer correspond to a desired workflow, by **scanning the filesystem**
|
|
6
|
+
* rather than iterating `ALL_WORKFLOWS`. This is what lets `init`/`update`
|
|
7
|
+
* clean up artifacts of workflows that were deleted (or renamed) from the
|
|
8
|
+
* enum entirely — a loop over `ALL_WORKFLOWS` would never visit them.
|
|
9
|
+
*
|
|
10
|
+
* The "desired" set is computed from the same generators used when writing
|
|
11
|
+
* (`getSkillTemplates` / `adapter.getFilePath`), so there is a single source
|
|
12
|
+
* of truth and a valid artifact is never removed.
|
|
13
|
+
*
|
|
14
|
+
* Removal is strictly limited to Pscode-managed naming patterns (skill dirs
|
|
15
|
+
* prefixed `pscode-`; command files matching the adapter's own filename
|
|
16
|
+
* pattern), so user files are preserved.
|
|
17
|
+
*/
|
|
18
|
+
import path from 'path';
|
|
19
|
+
import * as fs from 'fs';
|
|
20
|
+
import { CommandAdapterRegistry } from '../command-generation/index.js';
|
|
21
|
+
import { AI_TOOLS } from '../config.js';
|
|
22
|
+
import { getSkillTemplates } from './skill-generation.js';
|
|
23
|
+
const SKILL_DIR_PREFIX = 'pscode-';
|
|
24
|
+
/** Sentinel unlikely to collide with a real command id. */
|
|
25
|
+
const PROBE_ID = '__pscode_probe__';
|
|
26
|
+
/**
|
|
27
|
+
* Lists the immediate child directory names of `dir`, or `[]` if it doesn't exist.
|
|
28
|
+
*/
|
|
29
|
+
function listDirs(dir) {
|
|
30
|
+
try {
|
|
31
|
+
return fs
|
|
32
|
+
.readdirSync(dir, { withFileTypes: true })
|
|
33
|
+
.filter((e) => e.isDirectory())
|
|
34
|
+
.map((e) => e.name);
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
return [];
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Lists the immediate child file names of `dir`, or `[]` if it doesn't exist.
|
|
42
|
+
*/
|
|
43
|
+
function listFiles(dir) {
|
|
44
|
+
try {
|
|
45
|
+
return fs
|
|
46
|
+
.readdirSync(dir, { withFileTypes: true })
|
|
47
|
+
.filter((e) => e.isFile())
|
|
48
|
+
.map((e) => e.name);
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
return [];
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Derives the command directory and the Pscode-managed filename pattern for an
|
|
56
|
+
* adapter by probing `getFilePath` with a sentinel id. Returns the directory,
|
|
57
|
+
* the filename prefix/suffix that wrap the id, and a decoder from filename → id.
|
|
58
|
+
*/
|
|
59
|
+
function resolveCommandPattern(toolId, projectPath) {
|
|
60
|
+
const adapter = CommandAdapterRegistry.get(toolId);
|
|
61
|
+
if (!adapter)
|
|
62
|
+
return null;
|
|
63
|
+
const probePath = adapter.getFilePath(PROBE_ID);
|
|
64
|
+
const absProbe = path.isAbsolute(probePath) ? probePath : path.join(projectPath, probePath);
|
|
65
|
+
const dir = path.dirname(absProbe);
|
|
66
|
+
const base = path.basename(absProbe);
|
|
67
|
+
const idx = base.indexOf(PROBE_ID);
|
|
68
|
+
if (idx === -1)
|
|
69
|
+
return null;
|
|
70
|
+
const prefix = base.slice(0, idx);
|
|
71
|
+
const suffix = base.slice(idx + PROBE_ID.length);
|
|
72
|
+
const idFromFile = (file) => {
|
|
73
|
+
if (!file.startsWith(prefix) || !file.endsWith(suffix))
|
|
74
|
+
return null;
|
|
75
|
+
const id = file.slice(prefix.length, file.length - suffix.length);
|
|
76
|
+
return id.length > 0 ? id : null;
|
|
77
|
+
};
|
|
78
|
+
return { dir, prefix, suffix, idFromFile };
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Scans installed Pscode artifacts for a single tool and removes orphans —
|
|
82
|
+
* artifacts that do not belong to a desired workflow for the active delivery.
|
|
83
|
+
*
|
|
84
|
+
* - Skills: every `pscode-*` directory whose name is not in the desired set is
|
|
85
|
+
* removed. When skills are not generated (commands-only delivery) the desired
|
|
86
|
+
* set is empty, so all Pscode skill dirs are removed.
|
|
87
|
+
* - Commands: every Pscode-managed command file whose decoded id is not in the
|
|
88
|
+
* desired set is removed. When commands are not generated (skills-only) the
|
|
89
|
+
* desired set is empty, so all managed command files are removed.
|
|
90
|
+
*/
|
|
91
|
+
export function pruneOrphansForTool(projectPath, toolId, desiredWorkflows, delivery) {
|
|
92
|
+
const tool = AI_TOOLS.find((t) => t.value === toolId);
|
|
93
|
+
if (!tool?.skillsDir)
|
|
94
|
+
return { removedSkillDirs: 0, removedCommandFiles: 0 };
|
|
95
|
+
const shouldGenerateSkills = delivery !== 'commands';
|
|
96
|
+
const shouldGenerateCommands = delivery !== 'skills';
|
|
97
|
+
let removedSkillDirs = 0;
|
|
98
|
+
let removedCommandFiles = 0;
|
|
99
|
+
// ── Skills ──────────────────────────────────────────────────────────────
|
|
100
|
+
const skillsDir = path.join(projectPath, tool.skillsDir, 'skills');
|
|
101
|
+
const desiredSkillDirs = new Set(shouldGenerateSkills ? getSkillTemplates(desiredWorkflows).map((t) => t.dirName) : []);
|
|
102
|
+
for (const name of listDirs(skillsDir)) {
|
|
103
|
+
if (!name.startsWith(SKILL_DIR_PREFIX))
|
|
104
|
+
continue; // never touch user dirs
|
|
105
|
+
if (desiredSkillDirs.has(name))
|
|
106
|
+
continue;
|
|
107
|
+
try {
|
|
108
|
+
fs.rmSync(path.join(skillsDir, name), { recursive: true, force: true });
|
|
109
|
+
removedSkillDirs++;
|
|
110
|
+
}
|
|
111
|
+
catch {
|
|
112
|
+
// Ignore errors
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
// ── Commands ────────────────────────────────────────────────────────────
|
|
116
|
+
const pattern = resolveCommandPattern(toolId, projectPath);
|
|
117
|
+
if (pattern) {
|
|
118
|
+
const desiredCommandIds = new Set(shouldGenerateCommands ? desiredWorkflows : []);
|
|
119
|
+
for (const file of listFiles(pattern.dir)) {
|
|
120
|
+
const id = pattern.idFromFile(file);
|
|
121
|
+
if (id == null)
|
|
122
|
+
continue; // not a Pscode-managed command file
|
|
123
|
+
if (desiredCommandIds.has(id))
|
|
124
|
+
continue;
|
|
125
|
+
try {
|
|
126
|
+
fs.unlinkSync(path.join(pattern.dir, file));
|
|
127
|
+
removedCommandFiles++;
|
|
128
|
+
}
|
|
129
|
+
catch {
|
|
130
|
+
// Ignore errors
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
return { removedSkillDirs, removedCommandFiles };
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Prunes orphan artifacts across multiple tools, aggregating the counts.
|
|
138
|
+
*/
|
|
139
|
+
export function pruneOrphans(projectPath, toolIds, desiredWorkflows, delivery) {
|
|
140
|
+
let removedSkillDirs = 0;
|
|
141
|
+
let removedCommandFiles = 0;
|
|
142
|
+
for (const toolId of toolIds) {
|
|
143
|
+
const result = pruneOrphansForTool(projectPath, toolId, desiredWorkflows, delivery);
|
|
144
|
+
removedSkillDirs += result.removedSkillDirs;
|
|
145
|
+
removedCommandFiles += result.removedCommandFiles;
|
|
146
|
+
}
|
|
147
|
+
return { removedSkillDirs, removedCommandFiles };
|
|
148
|
+
}
|
|
149
|
+
//# sourceMappingURL=prune-orphans.js.map
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Shared utilities for generating skill and command files.
|
|
5
5
|
*/
|
|
6
|
-
import { getExploreSkillTemplate,
|
|
6
|
+
import { getExploreSkillTemplate, getApplyChangeSkillTemplate, getCompleteChangeSkillTemplate, getProposeSkillTemplate, getTrelloSetupSkillTemplate, getTrelloDraftSkillTemplate, getHandoffSkillTemplate, getGrillMeSkillTemplate, getPsExploreCommandTemplate, getPsApplyCommandTemplate, getPsCompleteCommandTemplate, getPsProposeCommandTemplate, getTrelloSetupCommandTemplate, getTrelloDraftCommandTemplate, getHandoffCommandTemplate, getGrillMeCommandTemplate, } from '../templates/skill-templates.js';
|
|
7
7
|
/**
|
|
8
8
|
* Gets skill templates with their directory names, optionally filtered by workflow IDs.
|
|
9
9
|
*
|
|
@@ -12,14 +12,8 @@ import { getExploreSkillTemplate, getNewChangeSkillTemplate, getContinueChangeSk
|
|
|
12
12
|
export function getSkillTemplates(workflowFilter) {
|
|
13
13
|
const all = [
|
|
14
14
|
{ template: getExploreSkillTemplate(), dirName: 'pscode-explore', workflowId: 'explore' },
|
|
15
|
-
{ template: getNewChangeSkillTemplate(), dirName: 'pscode-new-change', workflowId: 'new' },
|
|
16
|
-
{ template: getContinueChangeSkillTemplate(), dirName: 'pscode-continue-change', workflowId: 'continue' },
|
|
17
15
|
{ template: getApplyChangeSkillTemplate(), dirName: 'pscode-apply-change', workflowId: 'apply' },
|
|
18
|
-
{ template:
|
|
19
|
-
{ template: getCompleteChangeSkillTemplate(), dirName: 'pscode-archive-change', workflowId: 'complete' },
|
|
20
|
-
{ template: getBulkArchiveChangeSkillTemplate(), dirName: 'pscode-bulk-archive-change', workflowId: 'bulk-archive' },
|
|
21
|
-
{ template: getVerifyChangeSkillTemplate(), dirName: 'pscode-verify-change', workflowId: 'verify' },
|
|
22
|
-
{ template: getOnboardSkillTemplate(), dirName: 'pscode-onboard', workflowId: 'onboard' },
|
|
16
|
+
{ template: getCompleteChangeSkillTemplate(), dirName: 'pscode-complete-change', workflowId: 'complete' },
|
|
23
17
|
{ template: getProposeSkillTemplate(), dirName: 'pscode-propose', workflowId: 'propose' },
|
|
24
18
|
// Trello-specific workflows
|
|
25
19
|
{ template: getTrelloSetupSkillTemplate(), dirName: 'pscode-trello-setup', workflowId: 'trello-setup' },
|
|
@@ -41,14 +35,8 @@ export function getSkillTemplates(workflowFilter) {
|
|
|
41
35
|
export function getCommandTemplates(workflowFilter) {
|
|
42
36
|
const all = [
|
|
43
37
|
{ template: getPsExploreCommandTemplate(), id: 'explore' },
|
|
44
|
-
{ template: getPsNewCommandTemplate(), id: 'new' },
|
|
45
|
-
{ template: getPsContinueCommandTemplate(), id: 'continue' },
|
|
46
38
|
{ template: getPsApplyCommandTemplate(), id: 'apply' },
|
|
47
|
-
{ template: getPsFfCommandTemplate(), id: 'ff' },
|
|
48
39
|
{ template: getPsCompleteCommandTemplate(), id: 'complete' },
|
|
49
|
-
{ template: getPsBulkArchiveCommandTemplate(), id: 'bulk-archive' },
|
|
50
|
-
{ template: getPsVerifyCommandTemplate(), id: 'verify' },
|
|
51
|
-
{ template: getPsOnboardCommandTemplate(), id: 'onboard' },
|
|
52
40
|
{ template: getPsProposeCommandTemplate(), id: 'propose' },
|
|
53
41
|
// Trello-specific workflows
|
|
54
42
|
{ template: getTrelloSetupCommandTemplate(), id: 'trello-setup' },
|
|
@@ -6,12 +6,12 @@
|
|
|
6
6
|
/**
|
|
7
7
|
* Names of skill directories created by pscode init.
|
|
8
8
|
*/
|
|
9
|
-
export declare const SKILL_NAMES: readonly ["pscode-explore", "pscode-
|
|
9
|
+
export declare const SKILL_NAMES: readonly ["pscode-explore", "pscode-apply-change", "pscode-complete-change", "pscode-propose"];
|
|
10
10
|
export type SkillName = (typeof SKILL_NAMES)[number];
|
|
11
11
|
/**
|
|
12
12
|
* IDs of command templates created by pscode init.
|
|
13
13
|
*/
|
|
14
|
-
export declare const COMMAND_IDS: readonly ["explore", "
|
|
14
|
+
export declare const COMMAND_IDS: readonly ["explore", "apply", "complete", "propose"];
|
|
15
15
|
export type CommandId = (typeof COMMAND_IDS)[number];
|
|
16
16
|
/**
|
|
17
17
|
* Status of skill configuration for a tool.
|
|
@@ -11,14 +11,8 @@ import { AI_TOOLS } from '../config.js';
|
|
|
11
11
|
*/
|
|
12
12
|
export const SKILL_NAMES = [
|
|
13
13
|
'pscode-explore',
|
|
14
|
-
'pscode-new-change',
|
|
15
|
-
'pscode-continue-change',
|
|
16
14
|
'pscode-apply-change',
|
|
17
|
-
'pscode-
|
|
18
|
-
'pscode-archive-change',
|
|
19
|
-
'pscode-bulk-archive-change',
|
|
20
|
-
'pscode-verify-change',
|
|
21
|
-
'pscode-onboard',
|
|
15
|
+
'pscode-complete-change',
|
|
22
16
|
'pscode-propose',
|
|
23
17
|
];
|
|
24
18
|
/**
|
|
@@ -26,14 +20,8 @@ export const SKILL_NAMES = [
|
|
|
26
20
|
*/
|
|
27
21
|
export const COMMAND_IDS = [
|
|
28
22
|
'explore',
|
|
29
|
-
'new',
|
|
30
|
-
'continue',
|
|
31
23
|
'apply',
|
|
32
|
-
'ff',
|
|
33
24
|
'complete',
|
|
34
|
-
'bulk-archive',
|
|
35
|
-
'verify',
|
|
36
|
-
'onboard',
|
|
37
25
|
'propose',
|
|
38
26
|
];
|
|
39
27
|
/**
|
|
@@ -5,14 +5,8 @@
|
|
|
5
5
|
*/
|
|
6
6
|
export type { SkillTemplate, CommandTemplate } from './types.js';
|
|
7
7
|
export { getExploreSkillTemplate, getPsExploreCommandTemplate } from './workflows/explore.js';
|
|
8
|
-
export { getNewChangeSkillTemplate, getPsNewCommandTemplate } from './workflows/new-change.js';
|
|
9
|
-
export { getContinueChangeSkillTemplate, getPsContinueCommandTemplate } from './workflows/continue-change.js';
|
|
10
8
|
export { getApplyChangeSkillTemplate, getPsApplyCommandTemplate } from './workflows/apply-change.js';
|
|
11
|
-
export {
|
|
12
|
-
export { getCompleteChangeSkillTemplate, getPsCompleteCommandTemplate } from './workflows/archive-change.js';
|
|
13
|
-
export { getBulkArchiveChangeSkillTemplate, getPsBulkArchiveCommandTemplate } from './workflows/bulk-archive-change.js';
|
|
14
|
-
export { getVerifyChangeSkillTemplate, getPsVerifyCommandTemplate } from './workflows/verify-change.js';
|
|
15
|
-
export { getOnboardSkillTemplate, getPsOnboardCommandTemplate } from './workflows/onboard.js';
|
|
9
|
+
export { getCompleteChangeSkillTemplate, getPsCompleteCommandTemplate } from './workflows/complete-change.js';
|
|
16
10
|
export { getProposeSkillTemplate, getPsProposeCommandTemplate } from './workflows/propose.js';
|
|
17
11
|
export { getFeedbackSkillTemplate } from './workflows/feedback.js';
|
|
18
12
|
export { getTrelloSetupSkillTemplate, getTrelloSetupCommandTemplate } from './workflows/trello-setup.js';
|
|
@@ -4,14 +4,8 @@
|
|
|
4
4
|
* Compatibility facade that re-exports split workflow template modules.
|
|
5
5
|
*/
|
|
6
6
|
export { getExploreSkillTemplate, getPsExploreCommandTemplate } from './workflows/explore.js';
|
|
7
|
-
export { getNewChangeSkillTemplate, getPsNewCommandTemplate } from './workflows/new-change.js';
|
|
8
|
-
export { getContinueChangeSkillTemplate, getPsContinueCommandTemplate } from './workflows/continue-change.js';
|
|
9
7
|
export { getApplyChangeSkillTemplate, getPsApplyCommandTemplate } from './workflows/apply-change.js';
|
|
10
|
-
export {
|
|
11
|
-
export { getCompleteChangeSkillTemplate, getPsCompleteCommandTemplate } from './workflows/archive-change.js';
|
|
12
|
-
export { getBulkArchiveChangeSkillTemplate, getPsBulkArchiveCommandTemplate } from './workflows/bulk-archive-change.js';
|
|
13
|
-
export { getVerifyChangeSkillTemplate, getPsVerifyCommandTemplate } from './workflows/verify-change.js';
|
|
14
|
-
export { getOnboardSkillTemplate, getPsOnboardCommandTemplate } from './workflows/onboard.js';
|
|
8
|
+
export { getCompleteChangeSkillTemplate, getPsCompleteCommandTemplate } from './workflows/complete-change.js';
|
|
15
9
|
export { getProposeSkillTemplate, getPsProposeCommandTemplate } from './workflows/propose.js';
|
|
16
10
|
export { getFeedbackSkillTemplate } from './workflows/feedback.js';
|
|
17
11
|
// Trello-specific workflows
|
|
@@ -118,10 +118,35 @@ function getApplyInstructions() {
|
|
|
118
118
|
> - Descrição do PR: use o template definido em \`pr.description.template\`
|
|
119
119
|
> - Ao abrir o PR: \`<"comente o link do PR nesta task" se pr.comments.linkInTask: true, senão omita>\`
|
|
120
120
|
|
|
121
|
-
The agent MUST create the branch with the configured pattern before making any code changes.
|
|
122
121
|
Template variables available: \`{change-name}\` = current change name, \`{type}\` = feat/fix/chore, \`{ticket}\` = ticket ID if available.
|
|
123
122
|
|
|
124
|
-
**
|
|
123
|
+
**Detect whether a PR already exists for this change** (it may have been opened in \`/ps:propose\`). Resolve the branch name from \`pr.branch.pattern\`, then check the current branch and its PR:
|
|
124
|
+
\`\`\`bash
|
|
125
|
+
git checkout <branch> # if it already exists; otherwise it will be created below
|
|
126
|
+
gh pr view --json state,url
|
|
127
|
+
\`\`\`
|
|
128
|
+
|
|
129
|
+
- **If a PR already exists** (the \`gh pr view\` returns an open PR): do NOT open another — just continue working on the existing PR. Save its URL as \`prUrl\`.
|
|
130
|
+
|
|
131
|
+
- **If NO PR exists:** open one in **DRAFT automatically, without asking the user**:
|
|
132
|
+
1. Create the branch with the configured \`pr.branch.pattern\` if it does not exist yet (\`git checkout -b <branch>\`) — the agent MUST be on this branch before making any code changes.
|
|
133
|
+
2. Commit any pending planning artifacts: \`git add -A && git commit -m "chore(<change-name>): planning artifacts"\` (skip if nothing to commit).
|
|
134
|
+
3. Push and set upstream: \`git push -u origin <branch>\`.
|
|
135
|
+
4. Open the PR in DRAFT, deriving the title from \`pr.title.template\` and the body from \`pr.description.template\`:
|
|
136
|
+
\`gh pr create --draft --title "<resolved title>" --body "<resolved description>"\`.
|
|
137
|
+
5. Capture the PR URL as \`prUrl\`.
|
|
138
|
+
|
|
139
|
+
**Comentário do link no tracker:** after opening a PR (or detecting an existing one just opened), if \`pr.comments.linkInTask: true\` and a Trello \`cardId\` was saved in Step 2, comment the PR link on the card:
|
|
140
|
+
\`\`\`tool
|
|
141
|
+
mcp__claude_ai_Trello_Custom__add_comment
|
|
142
|
+
card_id: "<cardId>"
|
|
143
|
+
text: |
|
|
144
|
+
🔀 Pull Request (DRAFT): <prUrl>
|
|
145
|
+
\`\`\`
|
|
146
|
+
|
|
147
|
+
**Tratamento de falha (não-bloqueante):** if \`gh\` or \`git\` fails — \`gh\` not installed, not authenticated, or no GitHub remote — **do NOT block**: state what failed and how to fix it (e.g., \`gh auth login\`), ask whether the user wants the agent to resolve it in parallel, and **continue the implementation regardless**. The branch and local commits are preserved.
|
|
148
|
+
|
|
149
|
+
**If \`pscode/config.yaml\` does not exist, or \`pr.enabled: false\`, or file not found:** continue normally without any PR instructions — no branch, no PR.
|
|
125
150
|
|
|
126
151
|
6. **Show current progress**
|
|
127
152
|
|
|
@@ -7,4 +7,4 @@
|
|
|
7
7
|
import type { SkillTemplate, CommandTemplate } from '../types.js';
|
|
8
8
|
export declare function getCompleteChangeSkillTemplate(): SkillTemplate;
|
|
9
9
|
export declare function getPsCompleteCommandTemplate(): CommandTemplate;
|
|
10
|
-
//# sourceMappingURL=
|
|
10
|
+
//# sourceMappingURL=complete-change.d.ts.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export function getCompleteChangeSkillTemplate() {
|
|
2
2
|
return {
|
|
3
|
-
name: 'pscode-
|
|
3
|
+
name: 'pscode-complete-change',
|
|
4
4
|
description: 'Complete a completed change. Use when the user wants to finalize and complete a change after implementation is complete.',
|
|
5
5
|
instructions: getArchiveInstructions(),
|
|
6
6
|
compatibility: 'Requires pscode CLI.',
|
|
@@ -223,4 +223,4 @@ Target archive directory already exists.
|
|
|
223
223
|
- All content written to Trello must be in Portuguese
|
|
224
224
|
`;
|
|
225
225
|
}
|
|
226
|
-
//# sourceMappingURL=
|
|
226
|
+
//# sourceMappingURL=complete-change.js.map
|