@proletariat/cli 0.3.10 → 0.3.12

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 (152) hide show
  1. package/README.md +149 -192
  2. package/bin/dev.js +0 -0
  3. package/dist/commands/action/index.js +1 -1
  4. package/dist/commands/action/run.js +8 -12
  5. package/dist/commands/agent/auth.d.ts +30 -0
  6. package/dist/commands/agent/auth.js +172 -0
  7. package/dist/commands/agent/discover.d.ts +9 -0
  8. package/dist/commands/agent/discover.js +67 -0
  9. package/dist/commands/agent/index.js +47 -12
  10. package/dist/commands/agent/list.d.ts +4 -1
  11. package/dist/commands/agent/list.js +78 -16
  12. package/dist/commands/agent/login.js +35 -31
  13. package/dist/commands/agent/restart.js +2 -0
  14. package/dist/commands/agent/shell.js +78 -19
  15. package/dist/commands/agent/staff/add.js +1 -12
  16. package/dist/commands/agent/staff/remove.js +9 -7
  17. package/dist/commands/agent/status.js +17 -4
  18. package/dist/commands/agent/temp/cleanup.js +7 -3
  19. package/dist/commands/agent/themes/index.js +4 -5
  20. package/dist/commands/agent/themes/list.js +5 -5
  21. package/dist/commands/agent/visit.js +17 -4
  22. package/dist/commands/branch/create.d.ts +4 -0
  23. package/dist/commands/branch/create.js +16 -8
  24. package/dist/commands/branch/index.js +1 -1
  25. package/dist/commands/branch/where.js +1 -0
  26. package/dist/commands/claude.d.ts +38 -0
  27. package/dist/commands/claude.js +899 -0
  28. package/dist/commands/commit.js +1 -1
  29. package/dist/commands/config/index.d.ts +12 -0
  30. package/dist/commands/config/index.js +271 -0
  31. package/dist/commands/docker/clean.js +2 -2
  32. package/dist/commands/docker/index.js +2 -2
  33. package/dist/commands/docker/list.js +3 -8
  34. package/dist/commands/docker/logs.js +2 -2
  35. package/dist/commands/docker/prune.js +1 -1
  36. package/dist/commands/docker/restart.js +2 -2
  37. package/dist/commands/docker/shell.js +2 -2
  38. package/dist/commands/docker/start.js +2 -2
  39. package/dist/commands/docker/status.js +1 -1
  40. package/dist/commands/docker/stop.js +2 -2
  41. package/dist/commands/docker/sync.js +2 -2
  42. package/dist/commands/epic/index.js +1 -1
  43. package/dist/commands/epic/link/index.js +25 -14
  44. package/dist/commands/epic/link/remove.js +2 -0
  45. package/dist/commands/epic/list.js +5 -5
  46. package/dist/commands/epic/progress.js +10 -4
  47. package/dist/commands/epic/spec.js +2 -0
  48. package/dist/commands/epic/ticket.js +3 -0
  49. package/dist/commands/execution/stop.js +1 -0
  50. package/dist/commands/init.js +4 -4
  51. package/dist/commands/project/index.js +1 -1
  52. package/dist/commands/project/spec.js +7 -0
  53. package/dist/commands/repo/add.js +1 -0
  54. package/dist/commands/repo/remove.js +1 -0
  55. package/dist/commands/roadmap/add-project.d.ts +18 -0
  56. package/dist/commands/roadmap/add-project.js +135 -0
  57. package/dist/commands/roadmap/create.d.ts +22 -0
  58. package/dist/commands/roadmap/create.js +156 -0
  59. package/dist/commands/roadmap/delete.d.ts +17 -0
  60. package/dist/commands/roadmap/delete.js +104 -0
  61. package/dist/commands/roadmap/generate.d.ts +22 -0
  62. package/dist/commands/roadmap/generate.js +201 -0
  63. package/dist/commands/roadmap/index.d.ts +13 -0
  64. package/dist/commands/roadmap/index.js +61 -0
  65. package/dist/commands/roadmap/list.d.ts +12 -0
  66. package/dist/commands/roadmap/list.js +42 -0
  67. package/dist/commands/roadmap/remove-project.d.ts +18 -0
  68. package/dist/commands/roadmap/remove-project.js +147 -0
  69. package/dist/commands/roadmap/reorder.d.ts +17 -0
  70. package/dist/commands/roadmap/reorder.js +157 -0
  71. package/dist/commands/roadmap/update.d.ts +19 -0
  72. package/dist/commands/roadmap/update.js +136 -0
  73. package/dist/commands/roadmap/view.d.ts +16 -0
  74. package/dist/commands/roadmap/view.js +103 -0
  75. package/dist/commands/spec/index.js +1 -1
  76. package/dist/commands/spec/link/index.js +24 -13
  77. package/dist/commands/spec/link/remove.js +2 -0
  78. package/dist/commands/status/index.js +1 -1
  79. package/dist/commands/status/list.js +0 -8
  80. package/dist/commands/template/delete.js +2 -0
  81. package/dist/commands/terminal/title.d.ts +12 -0
  82. package/dist/commands/terminal/title.js +48 -0
  83. package/dist/commands/ticket/complete.js +2 -0
  84. package/dist/commands/ticket/create.js +4 -2
  85. package/dist/commands/ticket/delete.js +2 -0
  86. package/dist/commands/ticket/edit.js +8 -2
  87. package/dist/commands/ticket/link/index.js +17 -3
  88. package/dist/commands/ticket/link/remove.js +2 -0
  89. package/dist/commands/ticket/list.js +1 -2
  90. package/dist/commands/ticket/move.js +2 -0
  91. package/dist/commands/ticket/project.js +3 -1
  92. package/dist/commands/ticket/reassign.js +2 -0
  93. package/dist/commands/ticket/spec.js +4 -2
  94. package/dist/commands/ticket/template/apply.js +4 -3
  95. package/dist/commands/ticket/template/create.js +2 -0
  96. package/dist/commands/ticket/template/index.js +1 -1
  97. package/dist/commands/ticket/update.js +2 -0
  98. package/dist/commands/work/index.js +1 -1
  99. package/dist/commands/work/revise.js +7 -1
  100. package/dist/commands/work/spawn.d.ts +2 -1
  101. package/dist/commands/work/spawn.js +131 -36
  102. package/dist/commands/work/start.d.ts +2 -1
  103. package/dist/commands/work/start.js +349 -69
  104. package/dist/commands/work/watch.js +10 -2
  105. package/dist/commands/workflow/create.js +3 -3
  106. package/dist/commands/workflow/switch.js +2 -1
  107. package/dist/commands/workspace/remove.js +0 -8
  108. package/dist/commands/workspace/use.js +1 -9
  109. package/dist/lib/agents/commands.js +18 -13
  110. package/dist/lib/database/index.d.ts +19 -12
  111. package/dist/lib/database/index.js +158 -42
  112. package/dist/lib/docker/resolve.js +1 -1
  113. package/dist/lib/execution/config.d.ts +6 -0
  114. package/dist/lib/execution/config.js +15 -2
  115. package/dist/lib/execution/devcontainer.d.ts +2 -0
  116. package/dist/lib/execution/devcontainer.js +41 -9
  117. package/dist/lib/execution/runners.d.ts +85 -3
  118. package/dist/lib/execution/runners.js +925 -228
  119. package/dist/lib/execution/spawner.d.ts +2 -2
  120. package/dist/lib/execution/spawner.js +4 -3
  121. package/dist/lib/execution/storage.d.ts +2 -1
  122. package/dist/lib/execution/storage.js +9 -13
  123. package/dist/lib/execution/types.d.ts +10 -1
  124. package/dist/lib/execution/types.js +3 -1
  125. package/dist/lib/init/index.js +1 -0
  126. package/dist/lib/machine-config.js +1 -1
  127. package/dist/lib/pmo/base-command.js +5 -9
  128. package/dist/lib/pmo/index.js +2 -0
  129. package/dist/lib/pmo/schema.d.ts +6 -0
  130. package/dist/lib/pmo/schema.js +36 -0
  131. package/dist/lib/pmo/storage/base.js +3 -3
  132. package/dist/lib/pmo/storage/index.d.ts +16 -1
  133. package/dist/lib/pmo/storage/index.js +45 -0
  134. package/dist/lib/pmo/storage/roadmaps.d.ts +62 -0
  135. package/dist/lib/pmo/storage/roadmaps.js +301 -0
  136. package/dist/lib/pmo/storage/specs.js +2 -0
  137. package/dist/lib/pmo/storage/types.d.ts +14 -0
  138. package/dist/lib/pmo/sync-manager.d.ts +1 -1
  139. package/dist/lib/pmo/sync-manager.js +1 -1
  140. package/dist/lib/pmo/types.d.ts +41 -0
  141. package/dist/lib/pmo/utils.d.ts +2 -0
  142. package/dist/lib/pmo/utils.js +22 -1
  143. package/dist/lib/repos/index.js +7 -1
  144. package/dist/lib/terminal.d.ts +31 -0
  145. package/dist/lib/terminal.js +48 -0
  146. package/dist/lib/themes.d.ts +21 -3
  147. package/dist/lib/themes.js +80 -23
  148. package/dist/lib/workspace-config.d.ts +80 -0
  149. package/dist/lib/workspace-config.js +100 -0
  150. package/oclif.manifest.json +2236 -1396
  151. package/package.json +10 -6
  152. package/LICENSE +0 -21
@@ -245,8 +245,8 @@ export function pickRandomThemeName() {
245
245
  }
246
246
  /**
247
247
  * Generate a unique ephemeral agent name.
248
- * Format: {adjective}-{theme_name}-{number}
249
- * Example: "bold-bezos-1", "keen-camry-2"
248
+ * Format: {adjective}-{theme_name} or {adjective}-{theme_name}-{number}
249
+ * Example: "bold-bezos", "keen-camry", "bold-bezos-2" (if bold-bezos exists)
250
250
  *
251
251
  * @param existingNames - Set of existing agent names (for uniqueness checking)
252
252
  * @param options - Optional configuration for name generation
@@ -259,25 +259,55 @@ export function generateEphemeralAgentName(existingNames, options) {
259
259
  const maxAttempts = 100;
260
260
  // Use specified theme or default (no mixing themes)
261
261
  const themeId = opts.themeId ?? DEFAULT_EPHEMERAL_THEME;
262
+ // Get all theme names and partition into preferred (unused) and fallback (in use)
263
+ const theme = BUILTIN_THEMES.find(t => t.id === themeId) ?? BUILTIN_THEMES[0];
264
+ const allBaseNames = [...theme.names];
265
+ const inUseBaseNames = opts.inUseBaseNames ?? new Set();
266
+ // Shuffle arrays for randomness
267
+ const shuffleArray = (arr) => {
268
+ const shuffled = [...arr];
269
+ for (let i = shuffled.length - 1; i > 0; i--) {
270
+ const j = Math.floor(Math.random() * (i + 1));
271
+ [shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]];
272
+ }
273
+ return shuffled;
274
+ };
275
+ // Helper to check if a candidate name is available
276
+ const isAvailable = (candidateName) => {
277
+ // Check database/in-memory conflicts first
278
+ if (existingNames.has(candidateName.toLowerCase())) {
279
+ return false;
280
+ }
281
+ // Check external resource conflicts if callback provided
282
+ if (opts.checkExternalConflict) {
283
+ const result = opts.checkExternalConflict(candidateName);
284
+ if (result.conflict) {
285
+ opts.onConflictSkipped?.(candidateName, result.reason ?? 'external conflict');
286
+ return false;
287
+ }
288
+ }
289
+ return true;
290
+ };
291
+ // Partition base names: prefer unused ones first
292
+ const unusedBaseNames = shuffleArray(allBaseNames.filter(name => !inUseBaseNames.has(name.toLowerCase())));
293
+ const usedBaseNames = shuffleArray(allBaseNames.filter(name => inUseBaseNames.has(name.toLowerCase())));
294
+ // Try unused base names first, then fall back to used ones
295
+ const orderedBaseNames = [...unusedBaseNames, ...usedBaseNames];
262
296
  for (let attempt = 0; attempt < maxAttempts; attempt++) {
263
297
  const adjective = pickAdjective();
264
- const themeName = pickThemeName(themeId);
265
- // Try finding a unique number suffix (4 digits max)
266
- for (let num = 1; num <= 9999; num++) {
298
+ // Pick base name: cycle through ordered list based on attempt
299
+ const themeName = orderedBaseNames[attempt % orderedBaseNames.length];
300
+ // First try without a number suffix: "bold-bezos"
301
+ const nameWithoutNumber = `${adjective}-${themeName}`;
302
+ if (isAvailable(nameWithoutNumber)) {
303
+ return nameWithoutNumber;
304
+ }
305
+ // If taken, try with number suffixes: "bold-bezos-2", "bold-bezos-3", etc.
306
+ for (let num = 2; num <= 9999; num++) {
267
307
  const candidateName = `${adjective}-${themeName}-${num}`;
268
- // Check database/in-memory conflicts first
269
- if (existingNames.has(candidateName.toLowerCase())) {
270
- continue;
308
+ if (isAvailable(candidateName)) {
309
+ return candidateName;
271
310
  }
272
- // Check external resource conflicts if callback provided
273
- if (opts.checkExternalConflict) {
274
- const result = opts.checkExternalConflict(candidateName);
275
- if (result.conflict) {
276
- opts.onConflictSkipped?.(candidateName, result.reason ?? 'external conflict');
277
- continue;
278
- }
279
- }
280
- return candidateName;
281
311
  }
282
312
  }
283
313
  // Fallback: use timestamp if all attempts fail
@@ -286,16 +316,43 @@ export function generateEphemeralAgentName(existingNames, options) {
286
316
  }
287
317
  /**
288
318
  * Check if a name looks like an ephemeral agent name.
289
- * Ephemeral names follow pattern: {adjective}-{name}-{number}
319
+ * Ephemeral names follow pattern: {adjective}-{name} or {adjective}-{name}-{number}
290
320
  */
291
321
  export function isEphemeralAgentName(name) {
292
322
  const parts = name.split('-');
293
- if (parts.length < 3)
294
- return false;
295
- const lastPart = parts[parts.length - 1];
296
- const num = parseInt(lastPart, 10);
297
- if (isNaN(num) || num < 1)
323
+ // Need at least 2 parts: adjective-baseName
324
+ if (parts.length < 2)
298
325
  return false;
299
326
  const adjective = parts[0].toLowerCase();
300
327
  return AGENT_ADJECTIVES.includes(adjective);
301
328
  }
329
+ /**
330
+ * Extract the base name from an ephemeral agent name.
331
+ * Handles both formats: "bold-bezos" -> "bezos", "bold-bezos-2" -> "bezos"
332
+ */
333
+ export function extractBaseName(agentName) {
334
+ const parts = agentName.split('-');
335
+ if (parts.length < 2)
336
+ return agentName;
337
+ // Check if last part is a number
338
+ const lastPart = parts[parts.length - 1];
339
+ const hasNumber = !isNaN(parseInt(lastPart, 10)) && parts.length >= 3;
340
+ // If has number: adjective-baseName-number -> baseName is middle parts
341
+ // If no number: adjective-baseName -> baseName is everything after adjective
342
+ return hasNumber
343
+ ? parts.slice(1, -1).join('-')
344
+ : parts.slice(1).join('-');
345
+ }
346
+ /**
347
+ * Get the base name for any agent type.
348
+ * - If agent has explicit base_name, use it
349
+ * - If ephemeral, extract from name pattern
350
+ * - Otherwise (staff), use agent name directly
351
+ */
352
+ export function getAgentBaseName(agent) {
353
+ if (agent.base_name)
354
+ return agent.base_name;
355
+ if (agent.type === 'ephemeral')
356
+ return extractBaseName(agent.name);
357
+ return agent.name;
358
+ }
@@ -0,0 +1,80 @@
1
+ /**
2
+ * Workspace Config (config.json) Management
3
+ *
4
+ * Reads and writes settings from .proletariat/config.json.
5
+ * This is distinct from execution config (stored in database).
6
+ *
7
+ * Config structure:
8
+ * {
9
+ * "type": "hq",
10
+ * "name": "workspace-name",
11
+ * "version": "1.0.0",
12
+ * "schemaVersion": 1,
13
+ * "prlt": {
14
+ * "channel": "npm" | "npm:dev" | "gh" | "gh:dev" | "mount"
15
+ * }
16
+ * }
17
+ */
18
+ /**
19
+ * prlt channel options:
20
+ *
21
+ * Public npm (npmjs.com) - no auth required:
22
+ * - "npm": Install @proletariat/cli@latest from public npm (default)
23
+ * - "npm:dev": Install @proletariat/cli@dev from public npm
24
+ * - "npm:next": Install @proletariat/cli@next from public npm
25
+ * - "npm:x.y.z": Install specific version from public npm
26
+ *
27
+ * Local development:
28
+ * - "mount": Mount local prlt build from PRLT_REPO_PATH
29
+ *
30
+ * Legacy (deprecated, now uses npm):
31
+ * - "gh": Alias for npm (GitHub Packages no longer used)
32
+ */
33
+ export type PrltChannel = 'npm' | 'npm:dev' | 'npm:next' | 'gh' | 'gh:dev' | 'mount' | string;
34
+ export interface PrltConfig {
35
+ /** prlt source: "npm", "npm:dev", "gh", "gh:dev", "mount", or specific version like "npm:1.2.3" */
36
+ channel?: PrltChannel;
37
+ }
38
+ export interface WorkspaceConfig {
39
+ type: 'hq' | 'workspace';
40
+ name: string;
41
+ version?: string;
42
+ schemaVersion?: number;
43
+ /** prlt CLI configuration for containers */
44
+ prlt?: PrltConfig;
45
+ }
46
+ /**
47
+ * Read workspace config from .proletariat/config.json
48
+ */
49
+ export declare function readWorkspaceConfig(hqPath: string): WorkspaceConfig | null;
50
+ /**
51
+ * Write workspace config to .proletariat/config.json
52
+ */
53
+ export declare function writeWorkspaceConfig(hqPath: string, config: WorkspaceConfig): void;
54
+ /**
55
+ * Get prlt config from workspace, with defaults
56
+ */
57
+ export declare function getPrltConfig(hqPath: string): PrltConfig;
58
+ /**
59
+ * Update prlt config section
60
+ */
61
+ export declare function updatePrltConfig(hqPath: string, prltConfig: Partial<PrltConfig>): void;
62
+ /**
63
+ * Get the prlt channel to use for container builds.
64
+ * Priority: override > workspace config > default "npm"
65
+ */
66
+ export declare function getPrltChannel(hqPath: string, override?: string): string;
67
+ /**
68
+ * Parse a prlt channel string into registry and version components.
69
+ * Examples:
70
+ * "npm" -> { registry: "npm", version: "latest" }
71
+ * "npm:dev" -> { registry: "npm", version: "dev" }
72
+ * "npm:1.2.3" -> { registry: "npm", version: "1.2.3" }
73
+ * "gh" -> { registry: "gh", version: "latest" }
74
+ * "gh:dev" -> { registry: "gh", version: "dev" }
75
+ * "mount" -> { registry: "mount", version: null }
76
+ */
77
+ export declare function parseChannel(channel: string): {
78
+ registry: 'npm' | 'gh' | 'mount';
79
+ version: string | null;
80
+ };
@@ -0,0 +1,100 @@
1
+ /**
2
+ * Workspace Config (config.json) Management
3
+ *
4
+ * Reads and writes settings from .proletariat/config.json.
5
+ * This is distinct from execution config (stored in database).
6
+ *
7
+ * Config structure:
8
+ * {
9
+ * "type": "hq",
10
+ * "name": "workspace-name",
11
+ * "version": "1.0.0",
12
+ * "schemaVersion": 1,
13
+ * "prlt": {
14
+ * "channel": "npm" | "npm:dev" | "gh" | "gh:dev" | "mount"
15
+ * }
16
+ * }
17
+ */
18
+ import * as fs from 'node:fs';
19
+ import * as path from 'node:path';
20
+ /**
21
+ * Read workspace config from .proletariat/config.json
22
+ */
23
+ export function readWorkspaceConfig(hqPath) {
24
+ const configPath = path.join(hqPath, '.proletariat', 'config.json');
25
+ if (!fs.existsSync(configPath)) {
26
+ return null;
27
+ }
28
+ try {
29
+ const content = fs.readFileSync(configPath, 'utf-8');
30
+ return JSON.parse(content);
31
+ }
32
+ catch {
33
+ return null;
34
+ }
35
+ }
36
+ /**
37
+ * Write workspace config to .proletariat/config.json
38
+ */
39
+ export function writeWorkspaceConfig(hqPath, config) {
40
+ const configPath = path.join(hqPath, '.proletariat', 'config.json');
41
+ fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + '\n');
42
+ }
43
+ /**
44
+ * Get prlt config from workspace, with defaults
45
+ */
46
+ export function getPrltConfig(hqPath) {
47
+ const config = readWorkspaceConfig(hqPath);
48
+ return config?.prlt ?? {};
49
+ }
50
+ /**
51
+ * Update prlt config section
52
+ */
53
+ export function updatePrltConfig(hqPath, prltConfig) {
54
+ const config = readWorkspaceConfig(hqPath);
55
+ if (!config) {
56
+ throw new Error('No workspace config found');
57
+ }
58
+ config.prlt = {
59
+ ...config.prlt,
60
+ ...prltConfig,
61
+ };
62
+ writeWorkspaceConfig(hqPath, config);
63
+ }
64
+ /**
65
+ * Get the prlt channel to use for container builds.
66
+ * Priority: override > workspace config > default "npm"
67
+ */
68
+ export function getPrltChannel(hqPath, override) {
69
+ if (override) {
70
+ return override;
71
+ }
72
+ const prltConfig = getPrltConfig(hqPath);
73
+ return prltConfig.channel ?? 'npm';
74
+ }
75
+ /**
76
+ * Parse a prlt channel string into registry and version components.
77
+ * Examples:
78
+ * "npm" -> { registry: "npm", version: "latest" }
79
+ * "npm:dev" -> { registry: "npm", version: "dev" }
80
+ * "npm:1.2.3" -> { registry: "npm", version: "1.2.3" }
81
+ * "gh" -> { registry: "gh", version: "latest" }
82
+ * "gh:dev" -> { registry: "gh", version: "dev" }
83
+ * "mount" -> { registry: "mount", version: null }
84
+ */
85
+ export function parseChannel(channel) {
86
+ if (channel === 'mount') {
87
+ return { registry: 'mount', version: null };
88
+ }
89
+ if (channel.startsWith('gh')) {
90
+ const version = channel.includes(':') ? channel.split(':')[1] : 'latest';
91
+ return { registry: 'gh', version };
92
+ }
93
+ // Default to npm
94
+ if (channel.startsWith('npm')) {
95
+ const version = channel.includes(':') ? channel.split(':')[1] : 'latest';
96
+ return { registry: 'npm', version };
97
+ }
98
+ // Bare version numbers default to npm
99
+ return { registry: 'npm', version: channel };
100
+ }