prjct-cli 0.28.1 → 0.28.3

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 (45) hide show
  1. package/CHANGELOG.md +93 -0
  2. package/core/agentic/index.ts +11 -1
  3. package/core/agentic/prompt-builder.ts +2 -2
  4. package/core/agentic/token-estimator.ts +264 -0
  5. package/core/commands/command-data.ts +0 -33
  6. package/core/commands/commands.ts +4 -12
  7. package/core/commands/registry.ts +0 -37
  8. package/core/index.ts +0 -2
  9. package/core/infrastructure/setup.ts +28 -0
  10. package/core/infrastructure/slash-command-registry.ts +176 -0
  11. package/core/types/config.ts +1 -1
  12. package/core/types/index.ts +0 -2
  13. package/core/types/integrations.ts +22 -40
  14. package/core/types/storage.ts +0 -8
  15. package/core/types/task.ts +0 -4
  16. package/dist/bin/prjct.mjs +3 -82
  17. package/package.json +1 -1
  18. package/templates/agentic/subagent-generation.md +241 -81
  19. package/templates/commands/init.md +1 -44
  20. package/templates/commands/ship.md +106 -81
  21. package/templates/commands/sync.md +154 -402
  22. package/templates/commands/task.md +14 -31
  23. package/templates/global/CLAUDE.md +166 -35
  24. package/templates/guides/agent-generation.md +164 -0
  25. package/templates/guides/integrations.md +149 -0
  26. package/templates/mcp-config.json +23 -46
  27. package/templates/shared/validation.md +75 -0
  28. package/CLAUDE.md +0 -170
  29. package/core/integrations/notion/client.ts +0 -413
  30. package/core/integrations/notion/index.ts +0 -46
  31. package/core/integrations/notion/setup.ts +0 -235
  32. package/core/integrations/notion/sync.ts +0 -818
  33. package/core/integrations/notion/templates.ts +0 -246
  34. package/core/plugin/builtin/notion.ts +0 -178
  35. package/templates/agentic/agents/uxui.md +0 -218
  36. package/templates/commands/feature.md +0 -46
  37. package/templates/commands/now.md +0 -53
  38. package/templates/skills/notion-push.md +0 -116
  39. package/templates/skills/notion-setup.md +0 -199
  40. package/templates/skills/notion-sync.md +0 -290
  41. package/templates/subagents/domain/backend.md +0 -106
  42. package/templates/subagents/domain/database.md +0 -118
  43. package/templates/subagents/domain/devops.md +0 -149
  44. package/templates/subagents/domain/frontend.md +0 -100
  45. package/templates/subagents/domain/testing.md +0 -166
@@ -0,0 +1,176 @@
1
+ /**
2
+ * Slash Command Registry
3
+ * Generates Claude Code native slash command configuration.
4
+ *
5
+ * This enables:
6
+ * - Native /p:* command autocomplete in Claude Code
7
+ * - Command validation before execution
8
+ * - Command discoverability in help systems
9
+ *
10
+ * @version 1.0.0
11
+ */
12
+
13
+ import fs from 'fs/promises'
14
+ import path from 'path'
15
+ import os from 'os'
16
+
17
+ export interface SlashCommand {
18
+ name: string
19
+ description: string
20
+ args?: string
21
+ category: 'workflow' | 'planning' | 'shipping' | 'analytics' | 'maintenance'
22
+ requiresProject: boolean
23
+ deprecated?: boolean
24
+ replacedBy?: string
25
+ }
26
+
27
+ export interface SlashCommandRegistry {
28
+ version: string
29
+ generatedAt: string
30
+ commands: Record<string, SlashCommand>
31
+ }
32
+
33
+ /**
34
+ * Core prjct commands with metadata
35
+ */
36
+ const PRJCT_COMMANDS: SlashCommand[] = [
37
+ // Workflow
38
+ { name: 'task', description: 'Start any task with intelligent classification', args: '<description>', category: 'workflow', requiresProject: true },
39
+ { name: 'done', description: 'Complete current subtask', category: 'workflow', requiresProject: true },
40
+ { name: 'pause', description: 'Pause current task', category: 'workflow', requiresProject: true },
41
+ { name: 'resume', description: 'Resume paused task', category: 'workflow', requiresProject: true },
42
+ { name: 'next', description: 'Show next tasks in queue', category: 'workflow', requiresProject: true },
43
+
44
+ // Planning
45
+ { name: 'init', description: 'Initialize prjct in current directory', args: '[description]', category: 'planning', requiresProject: false },
46
+ { name: 'sync', description: 'Deep sync - analyze project, generate agents', category: 'planning', requiresProject: true },
47
+ { name: 'idea', description: 'Capture an idea for later', args: '<idea>', category: 'planning', requiresProject: true },
48
+ { name: 'spec', description: 'Generate feature specification', args: '<feature>', category: 'planning', requiresProject: true },
49
+ { name: 'bug', description: 'Report a bug with auto-priority', args: '<description>', category: 'planning', requiresProject: true },
50
+
51
+ // Shipping
52
+ { name: 'ship', description: 'Ship feature with PR workflow', args: '[feature]', category: 'shipping', requiresProject: true },
53
+ { name: 'review', description: 'Run code review on changes', category: 'shipping', requiresProject: true },
54
+ { name: 'test', description: 'Run tests for current changes', category: 'shipping', requiresProject: true },
55
+ { name: 'verify', description: 'Verify deployment', category: 'shipping', requiresProject: true },
56
+
57
+ // Analytics
58
+ { name: 'dash', description: 'Show project dashboard', category: 'analytics', requiresProject: true },
59
+ { name: 'history', description: 'Show task history', category: 'analytics', requiresProject: true },
60
+ { name: 'analyze', description: 'Analyze codebase', category: 'analytics', requiresProject: true },
61
+
62
+ // Maintenance
63
+ { name: 'cleanup', description: 'Clean up project files', category: 'maintenance', requiresProject: true },
64
+ { name: 'undo', description: 'Undo last action', category: 'maintenance', requiresProject: true },
65
+ { name: 'redo', description: 'Redo undone action', category: 'maintenance', requiresProject: true },
66
+
67
+ // Deprecated
68
+ { name: 'now', description: 'Start task (deprecated)', args: '<task>', category: 'workflow', requiresProject: true, deprecated: true, replacedBy: 'task' },
69
+ { name: 'feature', description: 'Plan feature (deprecated)', args: '<feature>', category: 'planning', requiresProject: true, deprecated: true, replacedBy: 'task' },
70
+ ]
71
+
72
+ /**
73
+ * Generate slash command registry for Claude Code
74
+ */
75
+ export async function generateRegistry(): Promise<SlashCommandRegistry> {
76
+ const commands: Record<string, SlashCommand> = {}
77
+
78
+ for (const cmd of PRJCT_COMMANDS) {
79
+ commands[`p:${cmd.name}`] = cmd
80
+ }
81
+
82
+ return {
83
+ version: '1.0.0',
84
+ generatedAt: new Date().toISOString(),
85
+ commands,
86
+ }
87
+ }
88
+
89
+ /**
90
+ * Write registry to project's global path
91
+ */
92
+ export async function writeRegistry(projectId: string): Promise<{ success: boolean; path?: string; error?: string }> {
93
+ try {
94
+ const globalPath = path.join(os.homedir(), '.prjct-cli', 'projects', projectId, 'config')
95
+ await fs.mkdir(globalPath, { recursive: true })
96
+
97
+ const registry = await generateRegistry()
98
+ const registryPath = path.join(globalPath, 'slash-commands.json')
99
+
100
+ await fs.writeFile(registryPath, JSON.stringify(registry, null, 2), 'utf-8')
101
+
102
+ return { success: true, path: registryPath }
103
+ } catch (error) {
104
+ return { success: false, error: (error as Error).message }
105
+ }
106
+ }
107
+
108
+ /**
109
+ * Get command by name
110
+ */
111
+ export function getCommand(name: string): SlashCommand | undefined {
112
+ return PRJCT_COMMANDS.find(cmd => cmd.name === name)
113
+ }
114
+
115
+ /**
116
+ * Get all commands by category
117
+ */
118
+ export function getCommandsByCategory(category: SlashCommand['category']): SlashCommand[] {
119
+ return PRJCT_COMMANDS.filter(cmd => cmd.category === category && !cmd.deprecated)
120
+ }
121
+
122
+ /**
123
+ * Validate command exists
124
+ */
125
+ export function validateCommand(name: string): { valid: boolean; command?: SlashCommand; error?: string } {
126
+ const cmd = getCommand(name)
127
+
128
+ if (!cmd) {
129
+ return { valid: false, error: `Unknown command: ${name}` }
130
+ }
131
+
132
+ if (cmd.deprecated) {
133
+ return {
134
+ valid: true,
135
+ command: cmd,
136
+ error: `Command '${name}' is deprecated. Use '${cmd.replacedBy}' instead.`,
137
+ }
138
+ }
139
+
140
+ return { valid: true, command: cmd }
141
+ }
142
+
143
+ /**
144
+ * Format commands for help display
145
+ */
146
+ export function formatHelpText(): string {
147
+ const categories = ['workflow', 'planning', 'shipping', 'analytics', 'maintenance'] as const
148
+ const lines: string[] = ['# prjct Commands', '']
149
+
150
+ for (const category of categories) {
151
+ const cmds = getCommandsByCategory(category)
152
+ if (cmds.length === 0) continue
153
+
154
+ lines.push(`## ${category.charAt(0).toUpperCase() + category.slice(1)}`)
155
+ lines.push('')
156
+
157
+ for (const cmd of cmds) {
158
+ const args = cmd.args ? ` ${cmd.args}` : ''
159
+ lines.push(`- \`/p:${cmd.name}${args}\` - ${cmd.description}`)
160
+ }
161
+
162
+ lines.push('')
163
+ }
164
+
165
+ return lines.join('\n')
166
+ }
167
+
168
+ export default {
169
+ generateRegistry,
170
+ writeRegistry,
171
+ getCommand,
172
+ getCommandsByCategory,
173
+ validateCommand,
174
+ formatHelpText,
175
+ PRJCT_COMMANDS,
176
+ }
@@ -25,7 +25,7 @@ export interface GlobalConfig {
25
25
  version: string
26
26
  created?: string
27
27
  lastSync: string
28
- // Optional external integrations (Notion, etc.)
28
+ // Optional external integrations
29
29
  integrations?: IntegrationsConfig
30
30
  }
31
31
 
@@ -225,10 +225,8 @@ export type {
225
225
  // Integration Types
226
226
  // =============================================================================
227
227
  export type {
228
- NotionIntegrationConfig,
229
228
  IntegrationsConfig,
230
229
  } from './integrations'
231
- export { DEFAULT_NOTION_CONFIG } from './integrations'
232
230
 
233
231
  // =============================================================================
234
232
  // Template Types
@@ -1,57 +1,39 @@
1
1
  /**
2
2
  * Integration Types
3
- * Types for external service integrations (Notion, etc.)
3
+ * Types for external service integrations
4
4
  */
5
5
 
6
6
  /**
7
- * Notion Integration Config
8
- * Stored in GlobalConfig.integrations.notion
7
+ * MCP Server Configuration
9
8
  */
10
- export interface NotionIntegrationConfig {
9
+ export interface McpServerConfig {
10
+ name: string
11
+ description?: string
12
+ command: string
13
+ args: string[]
11
14
  enabled: boolean
12
- workspaceId?: string
13
- workspaceName?: string
14
-
15
- // Database IDs (created on first setup)
16
- databases: {
17
- shipped?: string // "prjct: Shipped Features"
18
- roadmap?: string // "prjct: Roadmap"
19
- ideas?: string // "prjct: Ideas"
20
- tasks?: string // "prjct: Active Tasks"
21
- }
22
-
23
- // Dashboard page (links all databases)
24
- dashboardPageId?: string
25
-
26
- // Sync preferences
27
- syncOn: {
28
- ship: boolean // Auto-sync on /p:ship
29
- done: boolean // Sync task completion
30
- idea: boolean // Sync new ideas
31
- }
32
-
33
- // Setup metadata
15
+ linkedAgents?: string[]
16
+ autoLoad?: boolean
34
17
  setupAt?: string
35
- lastSyncAt?: string
36
18
  }
37
19
 
38
20
  /**
39
- * Integrations Config
40
- * Container for all external integrations
21
+ * MCP Servers Configuration for a project
41
22
  */
42
- export interface IntegrationsConfig {
43
- notion?: NotionIntegrationConfig
23
+ export interface McpServersConfig {
24
+ projectId: string
25
+ version: string
26
+ servers: Record<string, McpServerConfig>
27
+ agentMcpMap: Record<string, string[]>
44
28
  }
45
29
 
46
30
  /**
47
- * Default Notion config (disabled)
31
+ * Integrations Config
32
+ * Container for all external integrations
48
33
  */
49
- export const DEFAULT_NOTION_CONFIG: NotionIntegrationConfig = {
50
- enabled: false,
51
- databases: {},
52
- syncOn: {
53
- ship: true,
54
- done: false,
55
- idea: true,
56
- },
34
+ export interface IntegrationsConfig {
35
+ mcp?: {
36
+ enabled: boolean
37
+ configPath: string
38
+ }
57
39
  }
@@ -43,10 +43,6 @@ export interface ShippedFeature {
43
43
  quantitativeImpact?: string
44
44
  tasksCompleted?: number
45
45
  featureId?: string
46
- /** Notion page ID for bidirectional sync */
47
- notionPageId?: string
48
- /** Last sync timestamp for conflict resolution */
49
- lastSyncedAt?: string
50
46
  }
51
47
 
52
48
  export interface ShipChange {
@@ -117,10 +113,6 @@ export interface Idea {
117
113
  risks?: string[]
118
114
  risksCount?: number
119
115
  createdAt?: string
120
- /** Notion page ID for bidirectional sync */
121
- notionPageId?: string
122
- /** Last sync timestamp for conflict resolution */
123
- lastSyncedAt?: string
124
116
  }
125
117
 
126
118
  export interface ImpactEffort {
@@ -11,10 +11,6 @@ export interface Task {
11
11
  completedAt?: string
12
12
  duration?: string
13
13
  metadata?: TaskMetadata
14
- /** Notion page ID for bidirectional sync */
15
- notionPageId?: string
16
- /** Last sync timestamp for conflict resolution */
17
- lastSyncedAt?: string
18
14
  }
19
15
 
20
16
  export interface TaskMetadata {
@@ -4786,13 +4786,6 @@ var init_memory = __esm({
4786
4786
  }
4787
4787
  });
4788
4788
 
4789
- // core/types/integrations.ts
4790
- var init_integrations = __esm({
4791
- "core/types/integrations.ts"() {
4792
- "use strict";
4793
- }
4794
- });
4795
-
4796
4789
  // core/types/bus.ts
4797
4790
  var init_bus = __esm({
4798
4791
  "core/types/bus.ts"() {
@@ -4806,7 +4799,6 @@ var init_types = __esm({
4806
4799
  "use strict";
4807
4800
  init_fs();
4808
4801
  init_memory();
4809
- init_integrations();
4810
4802
  init_bus();
4811
4803
  }
4812
4804
  });
@@ -5007,7 +4999,7 @@ var init_prompt_builder = __esm({
5007
4999
  const parts = [];
5008
5000
  this._currentContext = context;
5009
5001
  const commandName = template.frontmatter?.name?.replace("p:", "") || "";
5010
- const agentCommands = ["now", "build", "feature", "design", "fix", "bug", "test", "work", "cleanup", "spec"];
5002
+ const agentCommands = ["task", "design", "fix", "bug", "test", "cleanup", "spec"];
5011
5003
  const needsAgent = agentCommands.includes(commandName);
5012
5004
  if (agent && needsAgent) {
5013
5005
  parts.push(`# AGENT: ${agent.name}
@@ -5054,7 +5046,7 @@ Read files before modifying.
5054
5046
 
5055
5047
  `);
5056
5048
  }
5057
- const codeCommands = ["now", "build", "feature", "design", "cleanup", "fix", "bug", "test", "init", "spec", "work"];
5049
+ const codeCommands = ["task", "design", "cleanup", "fix", "bug", "test", "init", "spec"];
5058
5050
  const needsPatterns = codeCommands.includes(commandName);
5059
5051
  const codePatternsContent = state?.codePatterns || "";
5060
5052
  if (needsPatterns && codePatternsContent && codePatternsContent.trim()) {
@@ -10730,36 +10722,6 @@ var init_registry = __esm({
10730
10722
  error: `Command not found: ${name}`
10731
10723
  };
10732
10724
  }
10733
- /**
10734
- * Execute without requiring project (for init, setup commands)
10735
- * @deprecated Use execute() - it auto-detects based on command metadata
10736
- */
10737
- async executeWithoutProject(name, params, projectPath = process.cwd()) {
10738
- const handler = this.handlers.get(name);
10739
- if (handler) {
10740
- const context = {
10741
- projectId: "",
10742
- projectPath,
10743
- globalPath: "",
10744
- timestamp: getTimestamp()
10745
- };
10746
- return handler.execute(params, context);
10747
- }
10748
- const handlerFn = this.handlerFns.get(name);
10749
- if (handlerFn) {
10750
- const context = {
10751
- projectId: "",
10752
- projectPath,
10753
- globalPath: "",
10754
- timestamp: getTimestamp()
10755
- };
10756
- return handlerFn(params, context);
10757
- }
10758
- return {
10759
- success: false,
10760
- error: `Command not found: ${name}`
10761
- };
10762
- }
10763
10725
  /**
10764
10726
  * Clear all registrations (useful for testing)
10765
10727
  */
@@ -11779,9 +11741,6 @@ var init_commands = __esm({
11779
11741
  this.prjctDir = ".prjct";
11780
11742
  }
11781
11743
  // ========== Workflow Commands ==========
11782
- async work(task = null, projectPath = process.cwd()) {
11783
- return this.workflow.now(task, projectPath);
11784
- }
11785
11744
  async done(projectPath = process.cwd()) {
11786
11745
  return this.workflow.done(projectPath);
11787
11746
  }
@@ -11798,9 +11757,6 @@ var init_commands = __esm({
11798
11757
  async init(idea = null, projectPath = process.cwd()) {
11799
11758
  return this.planning.init(idea, projectPath);
11800
11759
  }
11801
- async feature(description, projectPath = process.cwd()) {
11802
- return this.planning.feature(description, projectPath);
11803
- }
11804
11760
  async bug(description, projectPath = process.cwd()) {
11805
11761
  return this.planning.bug(description, projectPath);
11806
11762
  }
@@ -11941,17 +11897,6 @@ var init_command_data = __esm({
11941
11897
  requiresProject: true,
11942
11898
  features: ["Agentic type classification", "7-phase workflow", "Git branch management", "Task breakdown"]
11943
11899
  },
11944
- {
11945
- name: "feature",
11946
- group: "core",
11947
- description: "DEPRECATED - Use /p:task instead",
11948
- usage: { claude: '/p:task "<description>"', terminal: 'prjct task "<description>"' },
11949
- params: "<description>",
11950
- implemented: true,
11951
- hasTemplate: true,
11952
- requiresProject: true,
11953
- deprecated: true
11954
- },
11955
11900
  {
11956
11901
  name: "spec",
11957
11902
  group: "core",
@@ -11962,28 +11907,6 @@ var init_command_data = __esm({
11962
11907
  hasTemplate: true,
11963
11908
  requiresProject: true
11964
11909
  },
11965
- {
11966
- name: "now",
11967
- group: "core",
11968
- description: "DEPRECATED - Use /p:task instead",
11969
- usage: { claude: '/p:task "<description>"', terminal: 'prjct task "<description>"' },
11970
- params: "[task]",
11971
- implemented: true,
11972
- hasTemplate: true,
11973
- requiresProject: true,
11974
- deprecated: true
11975
- },
11976
- {
11977
- name: "work",
11978
- group: "core",
11979
- description: "DEPRECATED - Use /p:task instead",
11980
- usage: { claude: '/p:task "<description>"', terminal: 'prjct task "<description>"' },
11981
- params: "[task]",
11982
- implemented: true,
11983
- hasTemplate: true,
11984
- requiresProject: true,
11985
- deprecated: true
11986
- },
11987
11910
  {
11988
11911
  name: "pause",
11989
11912
  group: "core",
@@ -12307,7 +12230,7 @@ var require_package = __commonJS({
12307
12230
  "package.json"(exports, module) {
12308
12231
  module.exports = {
12309
12232
  name: "prjct-cli",
12310
- version: "0.27.0",
12233
+ version: "0.28.1",
12311
12234
  description: "Built for Claude - Ship fast, track progress, stay focused. Developer momentum tool for indie hackers.",
12312
12235
  main: "core/index.ts",
12313
12236
  bin: {
@@ -12467,14 +12390,12 @@ Use 'prjct --help' to see available commands.`);
12467
12390
  const param = parsedArgs.join(" ") || null;
12468
12391
  const standardCommands = {
12469
12392
  // Core workflow
12470
- work: /* @__PURE__ */ __name((p) => commands.work(p), "work"),
12471
12393
  done: /* @__PURE__ */ __name(() => commands.done(), "done"),
12472
12394
  next: /* @__PURE__ */ __name(() => commands.next(), "next"),
12473
12395
  pause: /* @__PURE__ */ __name((p) => commands.pause(p || ""), "pause"),
12474
12396
  resume: /* @__PURE__ */ __name((p) => commands.resume(p), "resume"),
12475
12397
  // Planning
12476
12398
  init: /* @__PURE__ */ __name((p) => commands.init(p), "init"),
12477
- feature: /* @__PURE__ */ __name((p) => commands.feature(p || ""), "feature"),
12478
12399
  bug: /* @__PURE__ */ __name((p) => commands.bug(p || ""), "bug"),
12479
12400
  idea: /* @__PURE__ */ __name((p) => commands.idea(p || ""), "idea"),
12480
12401
  spec: /* @__PURE__ */ __name((p) => commands.spec(p), "spec"),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prjct-cli",
3
- "version": "0.28.1",
3
+ "version": "0.28.3",
4
4
  "description": "Built for Claude - Ship fast, track progress, stay focused. Developer momentum tool for indie hackers.",
5
5
  "main": "core/index.ts",
6
6
  "bin": {