@thiagodiogo/pscode 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (337) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +142 -0
  3. package/bin/pscode.js +5 -0
  4. package/dist/cli/index.d.ts +5 -0
  5. package/dist/cli/index.js +526 -0
  6. package/dist/commands/change.d.ts +35 -0
  7. package/dist/commands/change.js +277 -0
  8. package/dist/commands/completion.d.ts +72 -0
  9. package/dist/commands/completion.js +264 -0
  10. package/dist/commands/config.d.ts +36 -0
  11. package/dist/commands/config.js +611 -0
  12. package/dist/commands/context-store.d.ts +3 -0
  13. package/dist/commands/context-store.js +282 -0
  14. package/dist/commands/feedback.d.ts +9 -0
  15. package/dist/commands/feedback.js +183 -0
  16. package/dist/commands/initiative.d.ts +13 -0
  17. package/dist/commands/initiative.js +318 -0
  18. package/dist/commands/schema.d.ts +6 -0
  19. package/dist/commands/schema.js +869 -0
  20. package/dist/commands/show.d.ts +14 -0
  21. package/dist/commands/show.js +132 -0
  22. package/dist/commands/spec.d.ts +15 -0
  23. package/dist/commands/spec.js +225 -0
  24. package/dist/commands/validate.d.ts +24 -0
  25. package/dist/commands/validate.js +294 -0
  26. package/dist/commands/workflow/index.d.ts +19 -0
  27. package/dist/commands/workflow/index.js +13 -0
  28. package/dist/commands/workflow/initiative-link.d.ts +24 -0
  29. package/dist/commands/workflow/initiative-link.js +47 -0
  30. package/dist/commands/workflow/instructions.d.ts +29 -0
  31. package/dist/commands/workflow/instructions.js +344 -0
  32. package/dist/commands/workflow/new-change.d.ts +17 -0
  33. package/dist/commands/workflow/new-change.js +141 -0
  34. package/dist/commands/workflow/schemas.d.ts +10 -0
  35. package/dist/commands/workflow/schemas.js +34 -0
  36. package/dist/commands/workflow/set-change.d.ts +13 -0
  37. package/dist/commands/workflow/set-change.js +87 -0
  38. package/dist/commands/workflow/shared.d.ts +59 -0
  39. package/dist/commands/workflow/shared.js +116 -0
  40. package/dist/commands/workflow/status.d.ts +14 -0
  41. package/dist/commands/workflow/status.js +90 -0
  42. package/dist/commands/workflow/templates.d.ts +16 -0
  43. package/dist/commands/workflow/templates.js +69 -0
  44. package/dist/commands/workspace/context-status.d.ts +4 -0
  45. package/dist/commands/workspace/context-status.js +59 -0
  46. package/dist/commands/workspace/open-view.d.ts +62 -0
  47. package/dist/commands/workspace/open-view.js +228 -0
  48. package/dist/commands/workspace/open.d.ts +37 -0
  49. package/dist/commands/workspace/open.js +102 -0
  50. package/dist/commands/workspace/opener-selection.d.ts +11 -0
  51. package/dist/commands/workspace/opener-selection.js +93 -0
  52. package/dist/commands/workspace/operations.d.ts +28 -0
  53. package/dist/commands/workspace/operations.js +543 -0
  54. package/dist/commands/workspace/prompt-theme.d.ts +29 -0
  55. package/dist/commands/workspace/prompt-theme.js +24 -0
  56. package/dist/commands/workspace/registration.d.ts +13 -0
  57. package/dist/commands/workspace/registration.js +84 -0
  58. package/dist/commands/workspace/selection.d.ts +6 -0
  59. package/dist/commands/workspace/selection.js +122 -0
  60. package/dist/commands/workspace/types.d.ts +103 -0
  61. package/dist/commands/workspace/types.js +36 -0
  62. package/dist/commands/workspace.d.ts +6 -0
  63. package/dist/commands/workspace.js +678 -0
  64. package/dist/core/archive.d.ts +11 -0
  65. package/dist/core/archive.js +318 -0
  66. package/dist/core/artifact-graph/graph.d.ts +56 -0
  67. package/dist/core/artifact-graph/graph.js +141 -0
  68. package/dist/core/artifact-graph/index.d.ts +9 -0
  69. package/dist/core/artifact-graph/index.js +14 -0
  70. package/dist/core/artifact-graph/instruction-loader.d.ts +183 -0
  71. package/dist/core/artifact-graph/instruction-loader.js +256 -0
  72. package/dist/core/artifact-graph/outputs.d.ts +14 -0
  73. package/dist/core/artifact-graph/outputs.js +39 -0
  74. package/dist/core/artifact-graph/resolver.d.ts +81 -0
  75. package/dist/core/artifact-graph/resolver.js +257 -0
  76. package/dist/core/artifact-graph/schema.d.ts +13 -0
  77. package/dist/core/artifact-graph/schema.js +108 -0
  78. package/dist/core/artifact-graph/state.d.ts +12 -0
  79. package/dist/core/artifact-graph/state.js +31 -0
  80. package/dist/core/artifact-graph/types.d.ts +40 -0
  81. package/dist/core/artifact-graph/types.js +29 -0
  82. package/dist/core/available-tools.d.ts +17 -0
  83. package/dist/core/available-tools.js +43 -0
  84. package/dist/core/change-metadata/index.d.ts +2 -0
  85. package/dist/core/change-metadata/index.js +2 -0
  86. package/dist/core/change-metadata/schema.d.ts +18 -0
  87. package/dist/core/change-metadata/schema.js +28 -0
  88. package/dist/core/change-status-policy.d.ts +50 -0
  89. package/dist/core/change-status-policy.js +70 -0
  90. package/dist/core/collections/index.d.ts +3 -0
  91. package/dist/core/collections/index.js +3 -0
  92. package/dist/core/collections/initiatives/collection.d.ts +4 -0
  93. package/dist/core/collections/initiatives/collection.js +17 -0
  94. package/dist/core/collections/initiatives/index.d.ts +6 -0
  95. package/dist/core/collections/initiatives/index.js +6 -0
  96. package/dist/core/collections/initiatives/operations.d.ts +49 -0
  97. package/dist/core/collections/initiatives/operations.js +175 -0
  98. package/dist/core/collections/initiatives/resolution.d.ts +87 -0
  99. package/dist/core/collections/initiatives/resolution.js +374 -0
  100. package/dist/core/collections/initiatives/schema.d.ts +41 -0
  101. package/dist/core/collections/initiatives/schema.js +134 -0
  102. package/dist/core/collections/initiatives/templates.d.ts +12 -0
  103. package/dist/core/collections/initiatives/templates.js +90 -0
  104. package/dist/core/collections/runtime.d.ts +46 -0
  105. package/dist/core/collections/runtime.js +194 -0
  106. package/dist/core/command-generation/adapters/claude.d.ts +13 -0
  107. package/dist/core/command-generation/adapters/claude.js +50 -0
  108. package/dist/core/command-generation/adapters/codex.d.ts +16 -0
  109. package/dist/core/command-generation/adapters/codex.js +39 -0
  110. package/dist/core/command-generation/adapters/cursor.d.ts +14 -0
  111. package/dist/core/command-generation/adapters/cursor.js +44 -0
  112. package/dist/core/command-generation/adapters/gemini.d.ts +13 -0
  113. package/dist/core/command-generation/adapters/gemini.js +26 -0
  114. package/dist/core/command-generation/adapters/github-copilot.d.ts +13 -0
  115. package/dist/core/command-generation/adapters/github-copilot.js +26 -0
  116. package/dist/core/command-generation/adapters/index.d.ts +11 -0
  117. package/dist/core/command-generation/adapters/index.js +11 -0
  118. package/dist/core/command-generation/generator.d.ts +21 -0
  119. package/dist/core/command-generation/generator.js +27 -0
  120. package/dist/core/command-generation/index.d.ts +22 -0
  121. package/dist/core/command-generation/index.js +24 -0
  122. package/dist/core/command-generation/registry.d.ts +35 -0
  123. package/dist/core/command-generation/registry.js +55 -0
  124. package/dist/core/command-generation/types.d.ts +56 -0
  125. package/dist/core/command-generation/types.js +8 -0
  126. package/dist/core/completions/command-registry.d.ts +3 -0
  127. package/dist/core/completions/command-registry.js +939 -0
  128. package/dist/core/completions/completion-provider.d.ts +71 -0
  129. package/dist/core/completions/completion-provider.js +129 -0
  130. package/dist/core/completions/factory.d.ts +64 -0
  131. package/dist/core/completions/factory.js +75 -0
  132. package/dist/core/completions/generators/bash-generator.d.ts +35 -0
  133. package/dist/core/completions/generators/bash-generator.js +230 -0
  134. package/dist/core/completions/generators/fish-generator.d.ts +32 -0
  135. package/dist/core/completions/generators/fish-generator.js +160 -0
  136. package/dist/core/completions/generators/powershell-generator.d.ts +36 -0
  137. package/dist/core/completions/generators/powershell-generator.js +266 -0
  138. package/dist/core/completions/generators/zsh-generator.d.ts +47 -0
  139. package/dist/core/completions/generators/zsh-generator.js +274 -0
  140. package/dist/core/completions/installers/bash-installer.d.ts +87 -0
  141. package/dist/core/completions/installers/bash-installer.js +318 -0
  142. package/dist/core/completions/installers/fish-installer.d.ts +43 -0
  143. package/dist/core/completions/installers/fish-installer.js +143 -0
  144. package/dist/core/completions/installers/powershell-installer.d.ts +102 -0
  145. package/dist/core/completions/installers/powershell-installer.js +387 -0
  146. package/dist/core/completions/installers/zsh-installer.d.ts +117 -0
  147. package/dist/core/completions/installers/zsh-installer.js +421 -0
  148. package/dist/core/completions/shared-flags.d.ts +12 -0
  149. package/dist/core/completions/shared-flags.js +28 -0
  150. package/dist/core/completions/templates/bash-templates.d.ts +6 -0
  151. package/dist/core/completions/templates/bash-templates.js +30 -0
  152. package/dist/core/completions/templates/fish-templates.d.ts +7 -0
  153. package/dist/core/completions/templates/fish-templates.js +45 -0
  154. package/dist/core/completions/templates/powershell-templates.d.ts +6 -0
  155. package/dist/core/completions/templates/powershell-templates.js +34 -0
  156. package/dist/core/completions/templates/zsh-templates.d.ts +6 -0
  157. package/dist/core/completions/templates/zsh-templates.js +45 -0
  158. package/dist/core/completions/types.d.ts +101 -0
  159. package/dist/core/completions/types.js +2 -0
  160. package/dist/core/config-prompts.d.ts +9 -0
  161. package/dist/core/config-prompts.js +34 -0
  162. package/dist/core/config-schema.d.ts +86 -0
  163. package/dist/core/config-schema.js +213 -0
  164. package/dist/core/config.d.ts +18 -0
  165. package/dist/core/config.js +13 -0
  166. package/dist/core/context-store/binding.d.ts +53 -0
  167. package/dist/core/context-store/binding.js +197 -0
  168. package/dist/core/context-store/errors.d.ts +20 -0
  169. package/dist/core/context-store/errors.js +22 -0
  170. package/dist/core/context-store/foundation.d.ts +54 -0
  171. package/dist/core/context-store/foundation.js +318 -0
  172. package/dist/core/context-store/index.d.ts +6 -0
  173. package/dist/core/context-store/index.js +6 -0
  174. package/dist/core/context-store/operations.d.ts +62 -0
  175. package/dist/core/context-store/operations.js +352 -0
  176. package/dist/core/context-store/registry.d.ts +35 -0
  177. package/dist/core/context-store/registry.js +158 -0
  178. package/dist/core/converters/json-converter.d.ts +6 -0
  179. package/dist/core/converters/json-converter.js +51 -0
  180. package/dist/core/global-config.d.ts +49 -0
  181. package/dist/core/global-config.js +124 -0
  182. package/dist/core/index.d.ts +6 -0
  183. package/dist/core/index.js +7 -0
  184. package/dist/core/init.d.ts +40 -0
  185. package/dist/core/init.js +676 -0
  186. package/dist/core/legacy-cleanup.d.ts +162 -0
  187. package/dist/core/legacy-cleanup.js +489 -0
  188. package/dist/core/list.d.ts +9 -0
  189. package/dist/core/list.js +171 -0
  190. package/dist/core/migration.d.ts +23 -0
  191. package/dist/core/migration.js +108 -0
  192. package/dist/core/openspec-migration.d.ts +71 -0
  193. package/dist/core/openspec-migration.js +320 -0
  194. package/dist/core/parsers/change-parser.d.ts +13 -0
  195. package/dist/core/parsers/change-parser.js +197 -0
  196. package/dist/core/parsers/markdown-parser.d.ts +26 -0
  197. package/dist/core/parsers/markdown-parser.js +227 -0
  198. package/dist/core/parsers/requirement-blocks.d.ts +37 -0
  199. package/dist/core/parsers/requirement-blocks.js +201 -0
  200. package/dist/core/parsers/spec-structure.d.ts +9 -0
  201. package/dist/core/parsers/spec-structure.js +88 -0
  202. package/dist/core/planning-home.d.ts +21 -0
  203. package/dist/core/planning-home.js +108 -0
  204. package/dist/core/profile-sync-drift.d.ts +38 -0
  205. package/dist/core/profile-sync-drift.js +203 -0
  206. package/dist/core/profiles.d.ts +26 -0
  207. package/dist/core/profiles.js +43 -0
  208. package/dist/core/project-config.d.ts +64 -0
  209. package/dist/core/project-config.js +223 -0
  210. package/dist/core/schemas/base.schema.d.ts +13 -0
  211. package/dist/core/schemas/base.schema.js +13 -0
  212. package/dist/core/schemas/change.schema.d.ts +73 -0
  213. package/dist/core/schemas/change.schema.js +31 -0
  214. package/dist/core/schemas/index.d.ts +4 -0
  215. package/dist/core/schemas/index.js +4 -0
  216. package/dist/core/schemas/spec.schema.d.ts +18 -0
  217. package/dist/core/schemas/spec.schema.js +15 -0
  218. package/dist/core/shared/index.d.ts +8 -0
  219. package/dist/core/shared/index.js +8 -0
  220. package/dist/core/shared/skill-generation.d.ts +49 -0
  221. package/dist/core/shared/skill-generation.js +102 -0
  222. package/dist/core/shared/tool-detection.d.ts +71 -0
  223. package/dist/core/shared/tool-detection.js +158 -0
  224. package/dist/core/specs-apply.d.ts +73 -0
  225. package/dist/core/specs-apply.js +392 -0
  226. package/dist/core/styles/palette.d.ts +7 -0
  227. package/dist/core/styles/palette.js +8 -0
  228. package/dist/core/templates/index.d.ts +8 -0
  229. package/dist/core/templates/index.js +9 -0
  230. package/dist/core/templates/skill-templates.d.ts +21 -0
  231. package/dist/core/templates/skill-templates.js +21 -0
  232. package/dist/core/templates/types.d.ts +19 -0
  233. package/dist/core/templates/types.js +5 -0
  234. package/dist/core/templates/workflows/apply-change.d.ts +10 -0
  235. package/dist/core/templates/workflows/apply-change.js +287 -0
  236. package/dist/core/templates/workflows/archive-change.d.ts +10 -0
  237. package/dist/core/templates/workflows/archive-change.js +227 -0
  238. package/dist/core/templates/workflows/bulk-archive-change.d.ts +10 -0
  239. package/dist/core/templates/workflows/bulk-archive-change.js +492 -0
  240. package/dist/core/templates/workflows/continue-change.d.ts +10 -0
  241. package/dist/core/templates/workflows/continue-change.js +234 -0
  242. package/dist/core/templates/workflows/explore.d.ts +10 -0
  243. package/dist/core/templates/workflows/explore.js +755 -0
  244. package/dist/core/templates/workflows/feedback.d.ts +9 -0
  245. package/dist/core/templates/workflows/feedback.js +108 -0
  246. package/dist/core/templates/workflows/ff-change.d.ts +10 -0
  247. package/dist/core/templates/workflows/ff-change.js +200 -0
  248. package/dist/core/templates/workflows/new-change.d.ts +10 -0
  249. package/dist/core/templates/workflows/new-change.js +143 -0
  250. package/dist/core/templates/workflows/onboard.d.ts +10 -0
  251. package/dist/core/templates/workflows/onboard.js +607 -0
  252. package/dist/core/templates/workflows/propose.d.ts +10 -0
  253. package/dist/core/templates/workflows/propose.js +347 -0
  254. package/dist/core/templates/workflows/sync-specs.d.ts +10 -0
  255. package/dist/core/templates/workflows/sync-specs.js +290 -0
  256. package/dist/core/templates/workflows/trello-draft.d.ts +12 -0
  257. package/dist/core/templates/workflows/trello-draft.js +217 -0
  258. package/dist/core/templates/workflows/trello-setup.d.ts +12 -0
  259. package/dist/core/templates/workflows/trello-setup.js +315 -0
  260. package/dist/core/templates/workflows/verify-change.d.ts +10 -0
  261. package/dist/core/templates/workflows/verify-change.js +338 -0
  262. package/dist/core/trello-config.d.ts +90 -0
  263. package/dist/core/trello-config.js +86 -0
  264. package/dist/core/trello-init-prompt.d.ts +61 -0
  265. package/dist/core/trello-init-prompt.js +180 -0
  266. package/dist/core/update.d.ts +82 -0
  267. package/dist/core/update.js +560 -0
  268. package/dist/core/validation/constants.d.ts +34 -0
  269. package/dist/core/validation/constants.js +40 -0
  270. package/dist/core/validation/types.d.ts +18 -0
  271. package/dist/core/validation/types.js +2 -0
  272. package/dist/core/validation/validator.d.ts +33 -0
  273. package/dist/core/validation/validator.js +418 -0
  274. package/dist/core/view.d.ts +8 -0
  275. package/dist/core/view.js +168 -0
  276. package/dist/core/workspace/foundation.d.ts +62 -0
  277. package/dist/core/workspace/foundation.js +274 -0
  278. package/dist/core/workspace/index.d.ts +8 -0
  279. package/dist/core/workspace/index.js +8 -0
  280. package/dist/core/workspace/legacy-state.d.ts +28 -0
  281. package/dist/core/workspace/legacy-state.js +200 -0
  282. package/dist/core/workspace/link-input.d.ts +9 -0
  283. package/dist/core/workspace/link-input.js +32 -0
  284. package/dist/core/workspace/open-surface.d.ts +43 -0
  285. package/dist/core/workspace/open-surface.js +214 -0
  286. package/dist/core/workspace/openers.d.ts +21 -0
  287. package/dist/core/workspace/openers.js +119 -0
  288. package/dist/core/workspace/registry.d.ts +24 -0
  289. package/dist/core/workspace/registry.js +146 -0
  290. package/dist/core/workspace/skills.d.ts +57 -0
  291. package/dist/core/workspace/skills.js +334 -0
  292. package/dist/core/workspace/state-io.d.ts +10 -0
  293. package/dist/core/workspace/state-io.js +119 -0
  294. package/dist/index.d.ts +3 -0
  295. package/dist/index.js +3 -0
  296. package/dist/prompts/searchable-multi-select.d.ts +28 -0
  297. package/dist/prompts/searchable-multi-select.js +159 -0
  298. package/dist/telemetry/config.d.ts +38 -0
  299. package/dist/telemetry/config.js +136 -0
  300. package/dist/telemetry/index.d.ts +31 -0
  301. package/dist/telemetry/index.js +164 -0
  302. package/dist/ui/ascii-patterns.d.ts +16 -0
  303. package/dist/ui/ascii-patterns.js +133 -0
  304. package/dist/ui/welcome-screen.d.ts +10 -0
  305. package/dist/ui/welcome-screen.js +146 -0
  306. package/dist/utils/change-metadata.d.ts +54 -0
  307. package/dist/utils/change-metadata.js +141 -0
  308. package/dist/utils/change-utils.d.ts +71 -0
  309. package/dist/utils/change-utils.js +123 -0
  310. package/dist/utils/command-references.d.ts +18 -0
  311. package/dist/utils/command-references.js +20 -0
  312. package/dist/utils/file-system.d.ts +41 -0
  313. package/dist/utils/file-system.js +301 -0
  314. package/dist/utils/index.d.ts +6 -0
  315. package/dist/utils/index.js +9 -0
  316. package/dist/utils/interactive.d.ts +18 -0
  317. package/dist/utils/interactive.js +21 -0
  318. package/dist/utils/item-discovery.d.ts +4 -0
  319. package/dist/utils/item-discovery.js +72 -0
  320. package/dist/utils/match.d.ts +3 -0
  321. package/dist/utils/match.js +22 -0
  322. package/dist/utils/shell-detection.d.ts +20 -0
  323. package/dist/utils/shell-detection.js +41 -0
  324. package/dist/utils/task-progress.d.ts +8 -0
  325. package/dist/utils/task-progress.js +36 -0
  326. package/package.json +84 -0
  327. package/schemas/spec-driven/schema.yaml +153 -0
  328. package/schemas/spec-driven/templates/design.md +19 -0
  329. package/schemas/spec-driven/templates/proposal.md +23 -0
  330. package/schemas/spec-driven/templates/spec.md +8 -0
  331. package/schemas/spec-driven/templates/tasks.md +9 -0
  332. package/schemas/workspace-planning/schema.yaml +72 -0
  333. package/schemas/workspace-planning/templates/design.md +33 -0
  334. package/schemas/workspace-planning/templates/proposal.md +28 -0
  335. package/schemas/workspace-planning/templates/spec.md +9 -0
  336. package/schemas/workspace-planning/templates/tasks.md +15 -0
  337. package/scripts/postinstall.js +83 -0
@@ -0,0 +1,676 @@
1
+ /**
2
+ * Init Command
3
+ *
4
+ * Sets up Pscode with Agent Skills and /ps:* slash commands.
5
+ * This is the unified setup command that replaces both the old init and experimental commands.
6
+ */
7
+ import path from 'path';
8
+ import chalk from 'chalk';
9
+ import ora from 'ora';
10
+ import * as fs from 'fs';
11
+ import { createRequire } from 'module';
12
+ import { FileSystemUtils } from '../utils/file-system.js';
13
+ import { transformToHyphenCommands } from '../utils/command-references.js';
14
+ import { AI_TOOLS, PSCODE_DIR_NAME, } from './config.js';
15
+ import { PALETTE } from './styles/palette.js';
16
+ import { isInteractive } from '../utils/interactive.js';
17
+ import { serializeConfig } from './config-prompts.js';
18
+ import { generateCommands, CommandAdapterRegistry, } from './command-generation/index.js';
19
+ import { detectLegacyArtifacts, cleanupLegacyArtifacts, formatCleanupSummary, formatDetectionSummary, } from './legacy-cleanup.js';
20
+ import { detectLegacyToolArtifacts, runLegacyToolMigration, formatLegacyToolDetectionSummary, formatLegacyToolMigrationSummary, pscodeDirExists, } from './openspec-migration.js';
21
+ import { runTrelloInitPrompt } from './trello-init-prompt.js';
22
+ import { getToolsWithSkillsDir, getToolStates, getSkillTemplates, getCommandContents, generateSkillContent, } from './shared/index.js';
23
+ import { getGlobalConfig } from './global-config.js';
24
+ import { getProfileWorkflows, ALL_WORKFLOWS } from './profiles.js';
25
+ import { getAvailableTools } from './available-tools.js';
26
+ import { migrateIfNeeded } from './migration.js';
27
+ const require = createRequire(import.meta.url);
28
+ const { version: PSCODE_VERSION } = require('../../package.json');
29
+ // -----------------------------------------------------------------------------
30
+ // Constants
31
+ // -----------------------------------------------------------------------------
32
+ const DEFAULT_SCHEMA = 'spec-driven';
33
+ const PROGRESS_SPINNER = {
34
+ interval: 80,
35
+ frames: ['░░░', '▒░░', '▒▒░', '▒▒▒', '▓▒▒', '▓▓▒', '▓▓▓', '▒▓▓', '░▒▓'],
36
+ };
37
+ const WORKFLOW_TO_SKILL_DIR = {
38
+ 'explore': 'pscode-explore',
39
+ 'new': 'pscode-new-change',
40
+ 'continue': 'pscode-continue-change',
41
+ 'apply': 'pscode-apply-change',
42
+ 'ff': 'pscode-ff-change',
43
+ 'sync': 'pscode-sync-specs',
44
+ 'archive': 'pscode-archive-change',
45
+ 'bulk-archive': 'pscode-bulk-archive-change',
46
+ 'verify': 'pscode-verify-change',
47
+ 'onboard': 'pscode-onboard',
48
+ 'propose': 'pscode-propose',
49
+ // Trello-specific workflows
50
+ 'trello-setup': 'pscode-trello-setup',
51
+ 'draft': 'pscode-trello-draft',
52
+ };
53
+ // -----------------------------------------------------------------------------
54
+ // Init Command Class
55
+ // -----------------------------------------------------------------------------
56
+ export class InitCommand {
57
+ toolsArg;
58
+ force;
59
+ interactiveOption;
60
+ profileOverride;
61
+ constructor(options = {}) {
62
+ this.toolsArg = options.tools;
63
+ this.force = options.force ?? false;
64
+ this.interactiveOption = options.interactive;
65
+ this.profileOverride = options.profile;
66
+ }
67
+ async execute(targetPath) {
68
+ const projectPath = path.resolve(targetPath);
69
+ const pscodeDir = PSCODE_DIR_NAME;
70
+ const pscodePath = path.join(projectPath, pscodeDir);
71
+ // Validation happens silently in the background
72
+ const extendMode = await this.validate(projectPath, pscodePath);
73
+ // Check for legacy tool migration first (before legacy cleanup)
74
+ await this.handleLegacyToolMigration(projectPath);
75
+ // Check for legacy artifacts and handle cleanup
76
+ await this.handleLegacyCleanup(projectPath, extendMode);
77
+ // Detect available tools in the project (task 7.1)
78
+ const detectedTools = getAvailableTools(projectPath);
79
+ // Migration check: migrate existing projects to profile system (task 7.3)
80
+ if (extendMode) {
81
+ migrateIfNeeded(projectPath, detectedTools);
82
+ }
83
+ // Show animated welcome screen (interactive mode only)
84
+ const canPrompt = this.canPromptInteractively();
85
+ if (canPrompt) {
86
+ const { showWelcomeScreen } = await import('../ui/welcome-screen.js');
87
+ await showWelcomeScreen();
88
+ }
89
+ // Validate profile override early so invalid values fail before tool setup.
90
+ // The resolved value is consumed later when generation reads effective config.
91
+ this.resolveProfileOverride();
92
+ // Get tool states before processing
93
+ const toolStates = getToolStates(projectPath);
94
+ // Get tool selection (pass detected tools for pre-selection)
95
+ const selectedToolIds = await this.getSelectedTools(toolStates, extendMode, detectedTools, projectPath);
96
+ // Validate selected tools
97
+ const validatedTools = this.validateTools(selectedToolIds, toolStates);
98
+ // Create directory structure and config
99
+ await this.createDirectoryStructure(pscodePath, extendMode);
100
+ // Trello integration setup (interactive mode only)
101
+ const trelloConfigured = await this.handleTrelloSetup(pscodePath);
102
+ // Generate skills and commands for each tool
103
+ const results = await this.generateSkillsAndCommands(projectPath, validatedTools);
104
+ // Create config.yaml if needed
105
+ const configStatus = await this.createConfig(pscodePath, extendMode);
106
+ // Display success message
107
+ this.displaySuccessMessage(projectPath, validatedTools, results, configStatus, trelloConfigured);
108
+ }
109
+ // ═══════════════════════════════════════════════════════════
110
+ // VALIDATION & SETUP
111
+ // ═══════════════════════════════════════════════════════════
112
+ async validate(projectPath, pscodePath) {
113
+ const extendMode = await FileSystemUtils.directoryExists(pscodePath);
114
+ // Check write permissions
115
+ if (!(await FileSystemUtils.ensureWritePermissions(projectPath))) {
116
+ throw new Error(`Insufficient permissions to write to ${projectPath}`);
117
+ }
118
+ return extendMode;
119
+ }
120
+ canPromptInteractively() {
121
+ if (this.interactiveOption === false)
122
+ return false;
123
+ if (this.toolsArg !== undefined)
124
+ return false;
125
+ return isInteractive({ interactive: this.interactiveOption });
126
+ }
127
+ resolveProfileOverride() {
128
+ if (this.profileOverride === undefined) {
129
+ return undefined;
130
+ }
131
+ if (this.profileOverride === 'core' || this.profileOverride === 'custom') {
132
+ return this.profileOverride;
133
+ }
134
+ throw new Error(`Invalid profile "${this.profileOverride}". Available profiles: core, custom`);
135
+ }
136
+ // ═══════════════════════════════════════════════════════════
137
+ // LEGACY TOOL MIGRATION
138
+ // ═══════════════════════════════════════════════════════════
139
+ async handleLegacyToolMigration(projectPath) {
140
+ const detection = await detectLegacyToolArtifacts(projectPath);
141
+ if (!detection.hasLegacyArtifacts) {
142
+ return;
143
+ }
144
+ // Determine whether pscode/ already exists so we can show the right summary
145
+ const alreadyExists = await pscodeDirExists(projectPath);
146
+ console.log();
147
+ console.log(formatLegacyToolDetectionSummary(detection, alreadyExists));
148
+ console.log();
149
+ const canPrompt = this.canPromptInteractively();
150
+ if (this.force || !canPrompt) {
151
+ // Non-interactive or --force: migrate automatically
152
+ await this.performLegacyToolMigration(projectPath, detection);
153
+ return;
154
+ }
155
+ const { confirm } = await import('@inquirer/prompts');
156
+ const dirName = detection.legacyDirName;
157
+ const migrateLabel = alreadyExists
158
+ ? `Merge ${dirName}/ into pscode/ and complete the migration?`
159
+ : `Migrate this project from the legacy tool to Pscode?`;
160
+ const shouldMigrate = await confirm({
161
+ message: migrateLabel,
162
+ default: true,
163
+ });
164
+ if (!shouldMigrate) {
165
+ console.log(chalk.dim('Migration cancelled. Re-run with --force to skip this prompt.'));
166
+ process.exit(0);
167
+ }
168
+ await this.performLegacyToolMigration(projectPath, detection);
169
+ }
170
+ async performLegacyToolMigration(projectPath, detection) {
171
+ const spinner = ora('Migrating from legacy tool...').start();
172
+ const result = await runLegacyToolMigration(projectPath, detection);
173
+ spinner.succeed('Migration to Pscode complete');
174
+ const summary = formatLegacyToolMigrationSummary(result);
175
+ if (summary) {
176
+ console.log();
177
+ console.log(summary);
178
+ }
179
+ console.log();
180
+ }
181
+ // ═══════════════════════════════════════════════════════════
182
+ // LEGACY CLEANUP
183
+ // ═══════════════════════════════════════════════════════════
184
+ async handleLegacyCleanup(projectPath, extendMode) {
185
+ // Detect legacy artifacts
186
+ const detection = await detectLegacyArtifacts(projectPath);
187
+ if (!detection.hasLegacyArtifacts) {
188
+ return; // No legacy artifacts found
189
+ }
190
+ // Show what was detected
191
+ console.log();
192
+ console.log(formatDetectionSummary(detection));
193
+ console.log();
194
+ const canPrompt = this.canPromptInteractively();
195
+ if (this.force || !canPrompt) {
196
+ // --force flag or non-interactive mode: proceed with cleanup automatically.
197
+ // Legacy slash commands are 100% Pscode-managed, and config file cleanup
198
+ // only removes markers (never deletes files), so auto-cleanup is safe.
199
+ await this.performLegacyCleanup(projectPath, detection);
200
+ return;
201
+ }
202
+ // Interactive mode: prompt for confirmation
203
+ const { confirm } = await import('@inquirer/prompts');
204
+ const shouldCleanup = await confirm({
205
+ message: 'Upgrade and clean up legacy files?',
206
+ default: true,
207
+ });
208
+ if (!shouldCleanup) {
209
+ console.log(chalk.dim('Initialization cancelled.'));
210
+ console.log(chalk.dim('Run with --force to skip this prompt, or manually remove legacy files.'));
211
+ process.exit(0);
212
+ }
213
+ await this.performLegacyCleanup(projectPath, detection);
214
+ }
215
+ async performLegacyCleanup(projectPath, detection) {
216
+ const spinner = ora('Cleaning up legacy files...').start();
217
+ const result = await cleanupLegacyArtifacts(projectPath, detection);
218
+ spinner.succeed('Legacy files cleaned up');
219
+ const summary = formatCleanupSummary(result);
220
+ if (summary) {
221
+ console.log();
222
+ console.log(summary);
223
+ }
224
+ console.log();
225
+ }
226
+ // ═══════════════════════════════════════════════════════════
227
+ // TOOL SELECTION
228
+ // ═══════════════════════════════════════════════════════════
229
+ async getSelectedTools(toolStates, extendMode, detectedTools, projectPath) {
230
+ // Check for --tools flag first
231
+ const nonInteractiveSelection = this.resolveToolsArg();
232
+ if (nonInteractiveSelection !== null) {
233
+ return nonInteractiveSelection;
234
+ }
235
+ const validTools = getToolsWithSkillsDir();
236
+ const detectedToolIds = new Set(detectedTools.map((t) => t.value));
237
+ const configuredToolIds = new Set([...toolStates.entries()]
238
+ .filter(([, status]) => status.configured)
239
+ .map(([toolId]) => toolId));
240
+ const shouldPreselectDetected = !extendMode && configuredToolIds.size === 0;
241
+ const canPrompt = this.canPromptInteractively();
242
+ // Non-interactive mode: use detected tools, fallback to Claude if nothing detected
243
+ if (!canPrompt) {
244
+ if (detectedToolIds.size > 0) {
245
+ return [...detectedToolIds];
246
+ }
247
+ // Default to Claude Code when no tools detected and no --tools flag
248
+ return ['claude'];
249
+ }
250
+ if (validTools.length === 0) {
251
+ throw new Error(`No tools available for skill generation.`);
252
+ }
253
+ // Interactive mode: show searchable multi-select
254
+ const { searchableMultiSelect } = await import('../prompts/searchable-multi-select.js');
255
+ // Claude is pre-selected by default when nothing is configured or detected yet
256
+ const shouldPreselectClaude = !extendMode && configuredToolIds.size === 0 && detectedToolIds.size === 0;
257
+ // Build choices: pre-select configured tools; keep detected tools visible but unselected.
258
+ const sortedChoices = validTools
259
+ .map((toolId) => {
260
+ const tool = AI_TOOLS.find((t) => t.value === toolId);
261
+ const status = toolStates.get(toolId);
262
+ const configured = status?.configured ?? false;
263
+ const detected = detectedToolIds.has(toolId);
264
+ const isClaudeDefault = toolId === 'claude' && shouldPreselectClaude;
265
+ return {
266
+ name: tool?.name || toolId,
267
+ value: toolId,
268
+ configured,
269
+ detected: detected && !configured,
270
+ preSelected: configured || (shouldPreselectDetected && detected && !configured) || isClaudeDefault,
271
+ };
272
+ })
273
+ .sort((a, b) => {
274
+ // Configured tools first, then detected (not configured), then everything else.
275
+ if (a.configured && !b.configured)
276
+ return -1;
277
+ if (!a.configured && b.configured)
278
+ return 1;
279
+ if (a.detected && !b.detected)
280
+ return -1;
281
+ if (!a.detected && b.detected)
282
+ return 1;
283
+ return 0;
284
+ });
285
+ const configuredNames = validTools
286
+ .filter((toolId) => configuredToolIds.has(toolId))
287
+ .map((toolId) => AI_TOOLS.find((t) => t.value === toolId)?.name || toolId);
288
+ if (configuredNames.length > 0) {
289
+ console.log(`Pscode configured: ${configuredNames.join(', ')} (pre-selected)`);
290
+ }
291
+ const detectedOnlyNames = detectedTools
292
+ .filter((tool) => !configuredToolIds.has(tool.value))
293
+ .map((tool) => tool.name);
294
+ if (detectedOnlyNames.length > 0) {
295
+ const detectionLabel = shouldPreselectDetected
296
+ ? 'pre-selected for first-time setup'
297
+ : 'not pre-selected';
298
+ console.log(`Detected tool directories: ${detectedOnlyNames.join(', ')} (${detectionLabel})`);
299
+ }
300
+ const selectedTools = await searchableMultiSelect({
301
+ message: `Select tools to set up (${validTools.length} available)`,
302
+ pageSize: 15,
303
+ choices: sortedChoices,
304
+ validate: (selected) => selected.length > 0 || 'Select at least one tool',
305
+ });
306
+ if (selectedTools.length === 0) {
307
+ throw new Error('At least one tool must be selected');
308
+ }
309
+ return selectedTools;
310
+ }
311
+ resolveToolsArg() {
312
+ if (typeof this.toolsArg === 'undefined') {
313
+ return null;
314
+ }
315
+ const raw = this.toolsArg.trim();
316
+ if (raw.length === 0) {
317
+ throw new Error('The --tools option requires a value. Use "all", "none", or a comma-separated list of tool IDs.');
318
+ }
319
+ const availableTools = getToolsWithSkillsDir();
320
+ const availableSet = new Set(availableTools);
321
+ const availableList = ['all', 'none', ...availableTools].join(', ');
322
+ const lowerRaw = raw.toLowerCase();
323
+ if (lowerRaw === 'all') {
324
+ return availableTools;
325
+ }
326
+ if (lowerRaw === 'none') {
327
+ return [];
328
+ }
329
+ const tokens = raw
330
+ .split(',')
331
+ .map((token) => token.trim())
332
+ .filter((token) => token.length > 0);
333
+ if (tokens.length === 0) {
334
+ throw new Error('The --tools option requires at least one tool ID when not using "all" or "none".');
335
+ }
336
+ const normalizedTokens = tokens.map((token) => token.toLowerCase());
337
+ if (normalizedTokens.some((token) => token === 'all' || token === 'none')) {
338
+ throw new Error('Cannot combine reserved values "all" or "none" with specific tool IDs.');
339
+ }
340
+ const invalidTokens = tokens.filter((_token, index) => !availableSet.has(normalizedTokens[index]));
341
+ if (invalidTokens.length > 0) {
342
+ throw new Error(`Invalid tool(s): ${invalidTokens.join(', ')}. Available values: ${availableList}`);
343
+ }
344
+ // Deduplicate while preserving order
345
+ const deduped = [];
346
+ for (const token of normalizedTokens) {
347
+ if (!deduped.includes(token)) {
348
+ deduped.push(token);
349
+ }
350
+ }
351
+ return deduped;
352
+ }
353
+ validateTools(toolIds, toolStates) {
354
+ const validatedTools = [];
355
+ for (const toolId of toolIds) {
356
+ const tool = AI_TOOLS.find((t) => t.value === toolId);
357
+ if (!tool) {
358
+ const validToolIds = getToolsWithSkillsDir();
359
+ throw new Error(`Unknown tool '${toolId}'. Valid tools:\n ${validToolIds.join('\n ')}`);
360
+ }
361
+ if (!tool.skillsDir) {
362
+ const validToolsWithSkills = getToolsWithSkillsDir();
363
+ throw new Error(`Tool '${toolId}' does not support skill generation.\nTools with skill generation support:\n ${validToolsWithSkills.join('\n ')}`);
364
+ }
365
+ const preState = toolStates.get(tool.value);
366
+ validatedTools.push({
367
+ value: tool.value,
368
+ name: tool.name,
369
+ skillsDir: tool.skillsDir,
370
+ wasConfigured: preState?.configured ?? false,
371
+ });
372
+ }
373
+ return validatedTools;
374
+ }
375
+ // ═══════════════════════════════════════════════════════════
376
+ // TRELLO SETUP
377
+ // ═══════════════════════════════════════════════════════════
378
+ async handleTrelloSetup(pscodePath) {
379
+ if (!this.canPromptInteractively()) {
380
+ return false;
381
+ }
382
+ try {
383
+ return await runTrelloInitPrompt(pscodePath);
384
+ }
385
+ catch {
386
+ // Non-fatal — Trello setup is optional
387
+ return false;
388
+ }
389
+ }
390
+ // ═══════════════════════════════════════════════════════════
391
+ // DIRECTORY STRUCTURE
392
+ // ═══════════════════════════════════════════════════════════
393
+ async createDirectoryStructure(pscodePath, extendMode) {
394
+ if (extendMode) {
395
+ // In extend mode, just ensure directories exist without spinner
396
+ const directories = [
397
+ pscodePath,
398
+ path.join(pscodePath, 'specs'),
399
+ path.join(pscodePath, 'changes'),
400
+ path.join(pscodePath, 'changes', 'archive'),
401
+ ];
402
+ for (const dir of directories) {
403
+ await FileSystemUtils.createDirectory(dir);
404
+ }
405
+ return;
406
+ }
407
+ const spinner = this.startSpinner('Creating Pscode structure...');
408
+ const directories = [
409
+ pscodePath,
410
+ path.join(pscodePath, 'specs'),
411
+ path.join(pscodePath, 'changes'),
412
+ path.join(pscodePath, 'changes', 'archive'),
413
+ ];
414
+ for (const dir of directories) {
415
+ await FileSystemUtils.createDirectory(dir);
416
+ }
417
+ spinner.stopAndPersist({
418
+ symbol: PALETTE.white('▌'),
419
+ text: PALETTE.white('Pscode structure created'),
420
+ });
421
+ }
422
+ // ═══════════════════════════════════════════════════════════
423
+ // SKILL & COMMAND GENERATION
424
+ // ═══════════════════════════════════════════════════════════
425
+ async generateSkillsAndCommands(projectPath, tools) {
426
+ const createdTools = [];
427
+ const refreshedTools = [];
428
+ const failedTools = [];
429
+ const commandsSkipped = [];
430
+ let removedCommandCount = 0;
431
+ let removedSkillCount = 0;
432
+ // Read global config for profile and delivery settings (use --profile override if set)
433
+ const globalConfig = getGlobalConfig();
434
+ const profile = this.resolveProfileOverride() ?? globalConfig.profile ?? 'core';
435
+ const delivery = globalConfig.delivery ?? 'both';
436
+ const profileWorkflows = getProfileWorkflows(profile, globalConfig.workflows);
437
+ // Trello workflows are always generated regardless of profile, so users can
438
+ // run /ps:trello-setup to configure the integration at any time.
439
+ const TRELLO_WORKFLOWS = ['trello-setup', 'task', 'draft'];
440
+ const workflowsSet = new Set([...profileWorkflows, ...TRELLO_WORKFLOWS]);
441
+ const workflows = [...workflowsSet];
442
+ // Get skill and command templates filtered by profile workflows
443
+ const shouldGenerateSkills = delivery !== 'commands';
444
+ const shouldGenerateCommands = delivery !== 'skills';
445
+ const skillTemplates = shouldGenerateSkills ? getSkillTemplates(workflows) : [];
446
+ const commandContents = shouldGenerateCommands ? getCommandContents(workflows) : [];
447
+ // Process each tool
448
+ for (const tool of tools) {
449
+ const spinner = ora(`Setting up ${tool.name}...`).start();
450
+ try {
451
+ // Generate skill files if delivery includes skills
452
+ if (shouldGenerateSkills) {
453
+ // Use tool-specific skillsDir
454
+ const skillsDir = path.join(projectPath, tool.skillsDir, 'skills');
455
+ // Create skill directories and SKILL.md files
456
+ for (const { template, dirName } of skillTemplates) {
457
+ const skillDir = path.join(skillsDir, dirName);
458
+ const skillFile = path.join(skillDir, 'SKILL.md');
459
+ // Generate SKILL.md content with YAML frontmatter including generatedBy
460
+ // Use hyphen-based command references for tools where filename = command name
461
+ const transformer = (tool.value === 'opencode' || tool.value === 'pi') ? transformToHyphenCommands : undefined;
462
+ const skillContent = generateSkillContent(template, PSCODE_VERSION, transformer);
463
+ // Write the skill file
464
+ await FileSystemUtils.writeFile(skillFile, skillContent);
465
+ }
466
+ }
467
+ if (!shouldGenerateSkills) {
468
+ const skillsDir = path.join(projectPath, tool.skillsDir, 'skills');
469
+ removedSkillCount += await this.removeSkillDirs(skillsDir);
470
+ }
471
+ // Generate commands if delivery includes commands
472
+ if (shouldGenerateCommands) {
473
+ const adapter = CommandAdapterRegistry.get(tool.value);
474
+ if (adapter) {
475
+ const generatedCommands = generateCommands(commandContents, adapter);
476
+ for (const cmd of generatedCommands) {
477
+ const commandFile = path.isAbsolute(cmd.path) ? cmd.path : path.join(projectPath, cmd.path);
478
+ await FileSystemUtils.writeFile(commandFile, cmd.fileContent);
479
+ }
480
+ }
481
+ else {
482
+ commandsSkipped.push(tool.value);
483
+ }
484
+ }
485
+ if (!shouldGenerateCommands) {
486
+ removedCommandCount += await this.removeCommandFiles(projectPath, tool.value);
487
+ }
488
+ spinner.succeed(`Setup complete for ${tool.name}`);
489
+ if (tool.wasConfigured) {
490
+ refreshedTools.push(tool);
491
+ }
492
+ else {
493
+ createdTools.push(tool);
494
+ }
495
+ }
496
+ catch (error) {
497
+ spinner.fail(`Failed for ${tool.name}`);
498
+ failedTools.push({ name: tool.name, error: error });
499
+ }
500
+ }
501
+ return {
502
+ createdTools,
503
+ refreshedTools,
504
+ failedTools,
505
+ commandsSkipped,
506
+ removedCommandCount,
507
+ removedSkillCount,
508
+ };
509
+ }
510
+ // ═══════════════════════════════════════════════════════════
511
+ // CONFIG FILE
512
+ // ═══════════════════════════════════════════════════════════
513
+ async createConfig(pscodePath, extendMode) {
514
+ const configPath = path.join(pscodePath, 'config.yaml');
515
+ const configYmlPath = path.join(pscodePath, 'config.yml');
516
+ const configYamlExists = fs.existsSync(configPath);
517
+ const configYmlExists = fs.existsSync(configYmlPath);
518
+ if (configYamlExists || configYmlExists) {
519
+ return 'exists';
520
+ }
521
+ try {
522
+ const yamlContent = serializeConfig({ schema: DEFAULT_SCHEMA });
523
+ await FileSystemUtils.writeFile(configPath, yamlContent);
524
+ return 'created';
525
+ }
526
+ catch {
527
+ return 'skipped';
528
+ }
529
+ }
530
+ // ═══════════════════════════════════════════════════════════
531
+ // UI & OUTPUT
532
+ // ═══════════════════════════════════════════════════════════
533
+ displaySuccessMessage(projectPath, tools, results, configStatus, trelloConfigured = false) {
534
+ console.log();
535
+ console.log(chalk.bold('Pscode Setup Complete'));
536
+ console.log();
537
+ // Show created vs refreshed tools
538
+ if (results.createdTools.length > 0) {
539
+ console.log(`Created: ${results.createdTools.map((t) => t.name).join(', ')}`);
540
+ }
541
+ if (results.refreshedTools.length > 0) {
542
+ console.log(`Refreshed: ${results.refreshedTools.map((t) => t.name).join(', ')}`);
543
+ }
544
+ // Show counts (respecting profile filter + trello workflows always included)
545
+ const successfulTools = [...results.createdTools, ...results.refreshedTools];
546
+ if (successfulTools.length > 0) {
547
+ const globalConfig = getGlobalConfig();
548
+ const profile = this.profileOverride ?? globalConfig.profile ?? 'core';
549
+ const delivery = globalConfig.delivery ?? 'both';
550
+ const profileWorkflows = getProfileWorkflows(profile, globalConfig.workflows);
551
+ const TRELLO_WORKFLOWS = ['trello-setup', 'task', 'draft'];
552
+ const workflows = [...new Set([...profileWorkflows, ...TRELLO_WORKFLOWS])];
553
+ const toolDirs = [...new Set(successfulTools.map((t) => t.skillsDir))].join(', ');
554
+ const skillCount = delivery !== 'commands' ? getSkillTemplates(workflows).length : 0;
555
+ const commandCount = delivery !== 'skills' ? getCommandContents(workflows).length : 0;
556
+ if (skillCount > 0 && commandCount > 0) {
557
+ console.log(`${skillCount} skills and ${commandCount} commands in ${toolDirs}/`);
558
+ }
559
+ else if (skillCount > 0) {
560
+ console.log(`${skillCount} skills in ${toolDirs}/`);
561
+ }
562
+ else if (commandCount > 0) {
563
+ console.log(`${commandCount} commands in ${toolDirs}/`);
564
+ }
565
+ }
566
+ // Show failures
567
+ if (results.failedTools.length > 0) {
568
+ console.log(chalk.red(`Failed: ${results.failedTools.map((f) => `${f.name} (${f.error.message})`).join(', ')}`));
569
+ }
570
+ // Show skipped commands
571
+ if (results.commandsSkipped.length > 0) {
572
+ console.log(chalk.dim(`Commands skipped for: ${results.commandsSkipped.join(', ')} (no adapter)`));
573
+ }
574
+ if (results.removedCommandCount > 0) {
575
+ console.log(chalk.dim(`Removed: ${results.removedCommandCount} command files (delivery: skills)`));
576
+ }
577
+ if (results.removedSkillCount > 0) {
578
+ console.log(chalk.dim(`Removed: ${results.removedSkillCount} skill directories (delivery: commands)`));
579
+ }
580
+ // Config status
581
+ if (configStatus === 'created') {
582
+ console.log(`Config: pscode/config.yaml (schema: ${DEFAULT_SCHEMA})`);
583
+ }
584
+ else if (configStatus === 'exists') {
585
+ // Show actual filename (config.yaml or config.yml)
586
+ const configYaml = path.join(projectPath, PSCODE_DIR_NAME, 'config.yaml');
587
+ const configYml = path.join(projectPath, PSCODE_DIR_NAME, 'config.yml');
588
+ const configName = fs.existsSync(configYaml) ? 'config.yaml' : fs.existsSync(configYml) ? 'config.yml' : 'config.yaml';
589
+ console.log(`Config: pscode/${configName} (exists)`);
590
+ }
591
+ else {
592
+ console.log(chalk.dim(`Config: skipped (non-interactive mode)`));
593
+ }
594
+ // Getting started (task 7.6: show propose if in profile)
595
+ const globalCfg = getGlobalConfig();
596
+ const activeProfile = this.profileOverride ?? globalCfg.profile ?? 'core';
597
+ const activeWorkflows = [...getProfileWorkflows(activeProfile, globalCfg.workflows)];
598
+ console.log();
599
+ if (activeWorkflows.includes('propose')) {
600
+ console.log(chalk.bold('Getting started:'));
601
+ console.log(' Start your first change: /ps:propose "your idea"');
602
+ }
603
+ else if (activeWorkflows.includes('new')) {
604
+ console.log(chalk.bold('Getting started:'));
605
+ console.log(' Start your first change: /ps:new "your idea"');
606
+ }
607
+ else {
608
+ console.log("Done. Run 'pscode config profile' to configure your workflows.");
609
+ }
610
+ // Trello status
611
+ if (trelloConfigured) {
612
+ console.log();
613
+ console.log(chalk.bold('Trello Integration'));
614
+ console.log(` Preferences saved to ${chalk.cyan('pscode/trello.yaml')}`);
615
+ console.log(` Run ${chalk.cyan('/ps:trello-setup')} in Claude Code to connect your Trello lists.`);
616
+ }
617
+ // Links
618
+ console.log();
619
+ console.log(`Learn more: ${chalk.cyan('https://github.com/thiagodiogo/Pscode')}`);
620
+ console.log(`Feedback: ${chalk.cyan('https://github.com/thiagodiogo/Pscode/issues')}`);
621
+ // Restart instruction if any tools were configured
622
+ if (results.createdTools.length > 0 || results.refreshedTools.length > 0) {
623
+ console.log();
624
+ console.log(chalk.white('Restart your IDE for slash commands to take effect.'));
625
+ }
626
+ console.log();
627
+ }
628
+ startSpinner(text) {
629
+ return ora({
630
+ text,
631
+ stream: process.stdout,
632
+ color: 'gray',
633
+ spinner: PROGRESS_SPINNER,
634
+ }).start();
635
+ }
636
+ async removeSkillDirs(skillsDir) {
637
+ let removed = 0;
638
+ for (const workflow of ALL_WORKFLOWS) {
639
+ const dirName = WORKFLOW_TO_SKILL_DIR[workflow];
640
+ if (!dirName)
641
+ continue;
642
+ const skillDir = path.join(skillsDir, dirName);
643
+ try {
644
+ if (fs.existsSync(skillDir)) {
645
+ await fs.promises.rm(skillDir, { recursive: true, force: true });
646
+ removed++;
647
+ }
648
+ }
649
+ catch {
650
+ // Ignore errors
651
+ }
652
+ }
653
+ return removed;
654
+ }
655
+ async removeCommandFiles(projectPath, toolId) {
656
+ let removed = 0;
657
+ const adapter = CommandAdapterRegistry.get(toolId);
658
+ if (!adapter)
659
+ return 0;
660
+ for (const workflow of ALL_WORKFLOWS) {
661
+ const cmdPath = adapter.getFilePath(workflow);
662
+ const fullPath = path.isAbsolute(cmdPath) ? cmdPath : path.join(projectPath, cmdPath);
663
+ try {
664
+ if (fs.existsSync(fullPath)) {
665
+ await fs.promises.unlink(fullPath);
666
+ removed++;
667
+ }
668
+ }
669
+ catch {
670
+ // Ignore errors
671
+ }
672
+ }
673
+ return removed;
674
+ }
675
+ }
676
+ //# sourceMappingURL=init.js.map