panopticon-cli 0.4.28 → 0.4.31

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 (51) hide show
  1. package/dist/{agents-ND4NKCK2.js → agents-GQDAKTEQ.js} +5 -4
  2. package/dist/{chunk-SIAUVHVO.js → chunk-3XAB4IXF.js} +4 -2
  3. package/dist/{chunk-SIAUVHVO.js.map → chunk-3XAB4IXF.js.map} +1 -1
  4. package/dist/chunk-ELK6Q7QI.js +545 -0
  5. package/dist/chunk-ELK6Q7QI.js.map +1 -0
  6. package/dist/{chunk-ZLB6G4NW.js → chunk-HNEWTIR3.js} +41 -9
  7. package/dist/chunk-HNEWTIR3.js.map +1 -0
  8. package/dist/chunk-LYSBSZYV.js +1523 -0
  9. package/dist/chunk-LYSBSZYV.js.map +1 -0
  10. package/dist/{chunk-4KNEZGKZ.js → chunk-TMXN7THF.js} +45 -24
  11. package/dist/chunk-TMXN7THF.js.map +1 -0
  12. package/dist/{chunk-ON5NIBGW.js → chunk-VIWUCJ4V.js} +37 -8
  13. package/dist/chunk-VIWUCJ4V.js.map +1 -0
  14. package/dist/{chunk-VTMXR7JF.js → chunk-VU4FLXV5.js} +47 -40
  15. package/dist/{chunk-VTMXR7JF.js.map → chunk-VU4FLXV5.js.map} +1 -1
  16. package/dist/cli/index.js +153 -86
  17. package/dist/cli/index.js.map +1 -1
  18. package/dist/{config-QWTS63TU.js → config-BOAMSKTF.js} +4 -2
  19. package/dist/dashboard/public/assets/{index--VPaQ2VU.css → index-C7X6LP5Z.css} +1 -1
  20. package/dist/dashboard/public/assets/{index-GYQaqwVS.js → index-izWbAt7V.js} +152 -152
  21. package/dist/dashboard/public/index.html +2 -2
  22. package/dist/dashboard/server.js +94706 -24017
  23. package/dist/feedback-writer-AAKF5BTK.js +111 -0
  24. package/dist/feedback-writer-AAKF5BTK.js.map +1 -0
  25. package/dist/index.d.ts +1 -0
  26. package/dist/index.js +16 -14
  27. package/dist/index.js.map +1 -1
  28. package/dist/{remote-workspace-FNXLMNBG.js → remote-workspace-2G6V2KNP.js} +7 -5
  29. package/dist/{remote-workspace-FNXLMNBG.js.map → remote-workspace-2G6V2KNP.js.map} +1 -1
  30. package/dist/{specialist-context-WXO3FKIB.js → specialist-context-6SE5VRRC.js} +3 -3
  31. package/dist/{specialist-logs-SJWLETJT.js → specialist-logs-EXLOQHQ2.js} +3 -3
  32. package/dist/{specialists-5YJIDRW6.js → specialists-BRUHPAXE.js} +3 -3
  33. package/dist/{traefik-7OLLXUD7.js → traefik-CUJM6K5Z.js} +3 -3
  34. package/package.json +3 -2
  35. package/scripts/record-cost-event.js +243 -79
  36. package/scripts/record-cost-event.ts +128 -68
  37. package/templates/traefik/docker-compose.yml +7 -4
  38. package/templates/traefik/dynamic/panopticon.yml.template +3 -1
  39. package/dist/chunk-46DPNFMW.js +0 -278
  40. package/dist/chunk-46DPNFMW.js.map +0 -1
  41. package/dist/chunk-4KNEZGKZ.js.map +0 -1
  42. package/dist/chunk-ON5NIBGW.js.map +0 -1
  43. package/dist/chunk-SUMIHS2B.js +0 -1714
  44. package/dist/chunk-SUMIHS2B.js.map +0 -1
  45. package/dist/chunk-ZLB6G4NW.js.map +0 -1
  46. /package/dist/{agents-ND4NKCK2.js.map → agents-GQDAKTEQ.js.map} +0 -0
  47. /package/dist/{config-QWTS63TU.js.map → config-BOAMSKTF.js.map} +0 -0
  48. /package/dist/{specialist-context-WXO3FKIB.js.map → specialist-context-6SE5VRRC.js.map} +0 -0
  49. /package/dist/{specialist-logs-SJWLETJT.js.map → specialist-logs-EXLOQHQ2.js.map} +0 -0
  50. /package/dist/{specialists-5YJIDRW6.js.map → specialists-BRUHPAXE.js.map} +0 -0
  51. /package/dist/{traefik-7OLLXUD7.js.map → traefik-CUJM6K5Z.js.map} +0 -0
@@ -0,0 +1,111 @@
1
+ import {
2
+ init_projects,
3
+ resolveProjectFromIssue
4
+ } from "./chunk-JY7R7V4G.js";
5
+ import "./chunk-6HXKTOD7.js";
6
+ import {
7
+ __esm,
8
+ init_esm_shims
9
+ } from "./chunk-ZHC57RCV.js";
10
+
11
+ // src/lib/cloister/feedback-writer.ts
12
+ import { writeFile, readFile, mkdir, readdir } from "fs/promises";
13
+ import { existsSync } from "fs";
14
+ import { join } from "path";
15
+ function resolveWorkspacePath(issueId) {
16
+ const resolved = resolveProjectFromIssue(issueId);
17
+ if (!resolved) return null;
18
+ const wsPath = join(resolved.projectPath, "workspaces", `feature-${issueId.toLowerCase()}`);
19
+ return existsSync(wsPath) ? wsPath : null;
20
+ }
21
+ async function getNextSequenceNumber(feedbackDir) {
22
+ try {
23
+ const files = await readdir(feedbackDir);
24
+ let max = 0;
25
+ for (const file of files) {
26
+ const match = file.match(/^(\d{3})-/);
27
+ if (match) {
28
+ const n = parseInt(match[1], 10);
29
+ if (n > max) max = n;
30
+ }
31
+ }
32
+ return max + 1;
33
+ } catch {
34
+ return 1;
35
+ }
36
+ }
37
+ async function appendToStateMd(planningDir, entry) {
38
+ const statePath = join(planningDir, "STATE.md");
39
+ const line = `- **[${entry.timestamp}] ${entry.specialist} \u2192 ${entry.outcome.toUpperCase()}** \u2014 \`${entry.relativePath}\``;
40
+ let content;
41
+ try {
42
+ content = await readFile(statePath, "utf-8");
43
+ } catch {
44
+ content = `# Agent State: ${entry.issueId}
45
+ `;
46
+ }
47
+ const sectionHeader = "## Specialist Feedback";
48
+ const sectionIndex = content.indexOf(sectionHeader);
49
+ if (sectionIndex >= 0) {
50
+ const afterHeader = sectionIndex + sectionHeader.length;
51
+ const nextSection = content.indexOf("\n## ", afterHeader);
52
+ const insertPos = nextSection >= 0 ? nextSection : content.length;
53
+ content = content.slice(0, insertPos).trimEnd() + "\n" + line + "\n" + content.slice(insertPos);
54
+ } else {
55
+ content = content.trimEnd() + "\n\n" + sectionHeader + "\n\n" + line + "\n";
56
+ }
57
+ await writeFile(statePath, content, "utf-8");
58
+ }
59
+ async function writeFeedbackFile(opts) {
60
+ const workspacePath = opts.workspacePath || resolveWorkspacePath(opts.issueId);
61
+ if (!workspacePath) {
62
+ return { success: false, error: `Workspace not found for ${opts.issueId}` };
63
+ }
64
+ const planningDir = join(workspacePath, ".planning");
65
+ const feedbackDir = join(planningDir, "feedback");
66
+ try {
67
+ await mkdir(feedbackDir, { recursive: true });
68
+ const seq = await getNextSequenceNumber(feedbackDir);
69
+ const seqStr = String(seq).padStart(3, "0");
70
+ const filename = `${seqStr}-${opts.specialist}-${opts.outcome}.md`;
71
+ const filePath = join(feedbackDir, filename);
72
+ const relativePath = `.planning/feedback/${filename}`;
73
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/\.\d+Z$/, "Z");
74
+ const shortTimestamp = timestamp.replace(/:\d{2}Z$/, "Z");
75
+ const content = [
76
+ "---",
77
+ `specialist: ${opts.specialist}`,
78
+ `issueId: ${opts.issueId}`,
79
+ `outcome: ${opts.outcome}`,
80
+ `timestamp: ${timestamp}`,
81
+ "---",
82
+ "",
83
+ opts.markdownBody,
84
+ ""
85
+ ].join("\n");
86
+ await writeFile(filePath, content, "utf-8");
87
+ await appendToStateMd(planningDir, {
88
+ timestamp: shortTimestamp,
89
+ specialist: opts.specialist,
90
+ outcome: opts.outcome,
91
+ relativePath,
92
+ issueId: opts.issueId
93
+ });
94
+ console.log(`[feedback-writer] Wrote ${relativePath} for ${opts.issueId}`);
95
+ return { success: true, relativePath, filePath };
96
+ } catch (error) {
97
+ console.error(`[feedback-writer] Failed to write feedback for ${opts.issueId}:`, error);
98
+ return { success: false, error: error.message };
99
+ }
100
+ }
101
+ var init_feedback_writer = __esm({
102
+ "src/lib/cloister/feedback-writer.ts"() {
103
+ init_esm_shims();
104
+ init_projects();
105
+ }
106
+ });
107
+ init_feedback_writer();
108
+ export {
109
+ writeFeedbackFile
110
+ };
111
+ //# sourceMappingURL=feedback-writer-AAKF5BTK.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/lib/cloister/feedback-writer.ts"],"sourcesContent":["/**\n * Feedback Writer — writes specialist feedback to workspace files.\n *\n * All specialist feedback (review, test, merge) is written to\n * .planning/feedback/ in the workspace, with a breadcrumb in STATE.md.\n * The work agent reads these on startup or after crash recovery.\n *\n * All I/O is async (fs/promises) — never execSync.\n */\n\nimport { writeFile, readFile, mkdir, readdir } from 'fs/promises';\nimport { existsSync } from 'fs';\nimport { join } from 'path';\nimport { resolveProjectFromIssue } from '../projects.js';\n\nexport interface WriteFeedbackOptions {\n issueId: string;\n workspacePath?: string;\n specialist: 'review-agent' | 'test-agent' | 'merge-agent';\n outcome: string;\n summary: string;\n markdownBody: string;\n}\n\nexport interface WriteFeedbackResult {\n success: boolean;\n /** Relative path from workspace root */\n relativePath?: string;\n /** Absolute path */\n filePath?: string;\n error?: string;\n}\n\n/**\n * Resolve workspace path from an issue ID.\n */\nfunction resolveWorkspacePath(issueId: string): string | null {\n const resolved = resolveProjectFromIssue(issueId);\n if (!resolved) return null;\n\n const wsPath = join(resolved.projectPath, 'workspaces', `feature-${issueId.toLowerCase()}`);\n return existsSync(wsPath) ? wsPath : null;\n}\n\n/**\n * Get the next sequence number from existing files in the feedback directory.\n */\nasync function getNextSequenceNumber(feedbackDir: string): Promise<number> {\n try {\n const files = await readdir(feedbackDir);\n let max = 0;\n for (const file of files) {\n const match = file.match(/^(\\d{3})-/);\n if (match) {\n const n = parseInt(match[1], 10);\n if (n > max) max = n;\n }\n }\n return max + 1;\n } catch {\n return 1;\n }\n}\n\n/**\n * Append a feedback entry to STATE.md's \"Specialist Feedback\" section.\n * Creates the section if it doesn't exist. Creates STATE.md if it doesn't exist.\n */\nasync function appendToStateMd(\n planningDir: string,\n entry: { timestamp: string; specialist: string; outcome: string; relativePath: string; issueId: string }\n): Promise<void> {\n const statePath = join(planningDir, 'STATE.md');\n const line = `- **[${entry.timestamp}] ${entry.specialist} → ${entry.outcome.toUpperCase()}** — \\`${entry.relativePath}\\``;\n\n let content: string;\n try {\n content = await readFile(statePath, 'utf-8');\n } catch {\n // STATE.md doesn't exist — create a minimal one\n content = `# Agent State: ${entry.issueId}\\n`;\n }\n\n const sectionHeader = '## Specialist Feedback';\n const sectionIndex = content.indexOf(sectionHeader);\n\n if (sectionIndex >= 0) {\n // Find the end of the section (next ## or EOF)\n const afterHeader = sectionIndex + sectionHeader.length;\n const nextSection = content.indexOf('\\n## ', afterHeader);\n const insertPos = nextSection >= 0 ? nextSection : content.length;\n content = content.slice(0, insertPos).trimEnd() + '\\n' + line + '\\n' + content.slice(insertPos);\n } else {\n // Append the section at the end\n content = content.trimEnd() + '\\n\\n' + sectionHeader + '\\n\\n' + line + '\\n';\n }\n\n await writeFile(statePath, content, 'utf-8');\n}\n\n/**\n * Write specialist feedback to a file in the workspace and update STATE.md.\n */\nexport async function writeFeedbackFile(opts: WriteFeedbackOptions): Promise<WriteFeedbackResult> {\n const workspacePath = opts.workspacePath || resolveWorkspacePath(opts.issueId);\n if (!workspacePath) {\n return { success: false, error: `Workspace not found for ${opts.issueId}` };\n }\n\n const planningDir = join(workspacePath, '.planning');\n const feedbackDir = join(planningDir, 'feedback');\n\n try {\n await mkdir(feedbackDir, { recursive: true });\n\n const seq = await getNextSequenceNumber(feedbackDir);\n const seqStr = String(seq).padStart(3, '0');\n const filename = `${seqStr}-${opts.specialist}-${opts.outcome}.md`;\n const filePath = join(feedbackDir, filename);\n const relativePath = `.planning/feedback/${filename}`;\n\n const timestamp = new Date().toISOString().replace(/\\.\\d+Z$/, 'Z');\n const shortTimestamp = timestamp.replace(/:\\d{2}Z$/, 'Z');\n\n const content = [\n '---',\n `specialist: ${opts.specialist}`,\n `issueId: ${opts.issueId}`,\n `outcome: ${opts.outcome}`,\n `timestamp: ${timestamp}`,\n '---',\n '',\n opts.markdownBody,\n '',\n ].join('\\n');\n\n await writeFile(filePath, content, 'utf-8');\n\n // Update STATE.md with breadcrumb\n await appendToStateMd(planningDir, {\n timestamp: shortTimestamp,\n specialist: opts.specialist,\n outcome: opts.outcome,\n relativePath,\n issueId: opts.issueId,\n });\n\n console.log(`[feedback-writer] Wrote ${relativePath} for ${opts.issueId}`);\n return { success: true, relativePath, filePath };\n } catch (error: any) {\n console.error(`[feedback-writer] Failed to write feedback for ${opts.issueId}:`, error);\n return { success: false, error: error.message };\n }\n}\n"],"mappings":"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","names":[]}
package/dist/index.d.ts CHANGED
@@ -593,6 +593,7 @@ type ComplexityModels = {
593
593
  interface ModelsConfig {
594
594
  specialists: SpecialistModels;
595
595
  planning_agent: ModelId;
596
+ status_review: ModelId;
596
597
  complexity: ComplexityModels;
597
598
  }
598
599
  interface ApiKeysConfig {
package/dist/index.js CHANGED
@@ -1,25 +1,14 @@
1
1
  import {
2
- GitHubTracker,
3
- GitLabTracker,
4
- IssueNotFoundError,
5
- LinearTracker,
6
2
  LinkManager,
7
- NotImplementedError,
8
- TrackerAuthError,
9
3
  addAlias,
10
4
  cleanOldBackups,
11
5
  createBackup,
12
6
  createBackupTimestamp,
13
- createTracker,
14
- createTrackerFromConfig,
15
7
  detectShell,
16
8
  executeSync,
17
9
  formatIssueRef,
18
10
  getAliasInstructions,
19
- getAllTrackers,
20
11
  getLinkManager,
21
- getPrimaryTracker,
22
- getSecondaryTracker,
23
12
  getShellRcFile,
24
13
  hasAlias,
25
14
  isPanopticonSymlink,
@@ -29,17 +18,28 @@ import {
29
18
  planSync,
30
19
  restoreBackup,
31
20
  syncHooks
32
- } from "./chunk-SUMIHS2B.js";
21
+ } from "./chunk-ELK6Q7QI.js";
33
22
  import {
23
+ GitHubTracker,
24
+ GitLabTracker,
25
+ IssueNotFoundError,
26
+ LinearTracker,
27
+ NotImplementedError,
34
28
  PROVIDERS,
29
+ TrackerAuthError,
30
+ createTracker,
31
+ createTrackerFromConfig,
35
32
  getAgentCommand,
33
+ getAllTrackers,
36
34
  getAvailableModels,
37
35
  getClaudeModelFlag,
38
36
  getDefaultSettings,
39
37
  getDirectProviders,
38
+ getPrimaryTracker,
40
39
  getProviderEnv,
41
40
  getProviderForModel,
42
41
  getRouterProviders,
42
+ getSecondaryTracker,
43
43
  init_providers,
44
44
  init_settings,
45
45
  isAnthropicModel,
@@ -48,14 +48,15 @@ import {
48
48
  requiresRouter,
49
49
  saveSettings,
50
50
  validateSettings
51
- } from "./chunk-46DPNFMW.js";
51
+ } from "./chunk-LYSBSZYV.js";
52
52
  import "./chunk-BBCUK6N2.js";
53
53
  import {
54
54
  getDashboardApiUrl,
55
55
  getDefaultConfig,
56
+ init_config,
56
57
  loadConfig,
57
58
  saveConfig
58
- } from "./chunk-VTMXR7JF.js";
59
+ } from "./chunk-VU4FLXV5.js";
59
60
  import {
60
61
  AGENTS_DIR,
61
62
  BACKUPS_DIR,
@@ -97,6 +98,7 @@ import {
97
98
  // src/index.ts
98
99
  init_esm_shims();
99
100
  init_paths();
101
+ init_config();
100
102
  init_providers();
101
103
  init_settings();
102
104
  export {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["// Panopticon CLI - Main exports for library usage\nexport * from './lib/paths.js';\nexport * from './lib/config.js';\nexport * from './lib/shell.js';\nexport * from './lib/backup.js';\nexport * from './lib/sync.js';\nexport * from './lib/tracker/index.js';\nexport * from './lib/providers.js';\nexport * from './lib/settings.js';\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AACA;AAMA;AACA;","names":[]}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["// Panopticon CLI - Main exports for library usage\nexport * from './lib/paths.js';\nexport * from './lib/config.js';\nexport * from './lib/shell.js';\nexport * from './lib/backup.js';\nexport * from './lib/sync.js';\nexport * from './lib/tracker/index.js';\nexport * from './lib/providers.js';\nexport * from './lib/settings.js';\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AACA;AACA;AAKA;AACA;","names":[]}
@@ -1,9 +1,6 @@
1
1
  import {
2
2
  saveWorkspaceMetadata
3
3
  } from "./chunk-44EOY2ZL.js";
4
- import {
5
- loadConfig
6
- } from "./chunk-VTMXR7JF.js";
7
4
  import {
8
5
  extractTeamPrefix,
9
6
  findProjectByTeam,
@@ -13,6 +10,10 @@ import {
13
10
  createExeProvider,
14
11
  init_exe_provider
15
12
  } from "./chunk-JM6V62LT.js";
13
+ import {
14
+ init_config,
15
+ loadConfig
16
+ } from "./chunk-VU4FLXV5.js";
16
17
  import "./chunk-6HXKTOD7.js";
17
18
  import {
18
19
  init_esm_shims
@@ -20,10 +21,11 @@ import {
20
21
 
21
22
  // src/lib/remote-workspace.ts
22
23
  init_esm_shims();
24
+ init_config();
25
+ init_exe_provider();
23
26
  import chalk from "chalk";
24
27
  import { exec } from "child_process";
25
28
  import { promisify } from "util";
26
- init_exe_provider();
27
29
  init_projects();
28
30
  var execAsync = promisify(exec);
29
31
  async function createRemoteWorkspace(issueId, options = {}) {
@@ -176,4 +178,4 @@ EOF`);
176
178
  export {
177
179
  createRemoteWorkspace
178
180
  };
179
- //# sourceMappingURL=remote-workspace-FNXLMNBG.js.map
181
+ //# sourceMappingURL=remote-workspace-2G6V2KNP.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/lib/remote-workspace.ts"],"sourcesContent":["/**\n * Remote Workspace Creation\n *\n * Shared module for creating remote workspaces.\n * Used by both workspace.ts (explicit creation) and work/issue.ts (auto-creation).\n */\n\nimport chalk from 'chalk';\nimport { existsSync } from 'fs';\nimport { join } from 'path';\nimport { exec } from 'child_process';\nimport { promisify } from 'util';\nimport { loadConfig } from './config.js';\nimport { createExeProvider } from './remote/exe-provider.js';\nimport { saveWorkspaceMetadata } from './remote/workspace-metadata.js';\nimport type { RemoteWorkspaceMetadata } from './remote/interface.js';\nimport { extractTeamPrefix, findProjectByTeam, resolveProjectFromIssue } from './projects.js';\n\nconst execAsync = promisify(exec);\n\nexport interface CreateRemoteWorkspaceOptions {\n dryRun?: boolean;\n spinner?: { text: string };\n}\n\n/**\n * Create a remote workspace on exe.dev\n */\nexport async function createRemoteWorkspace(\n issueId: string,\n options: CreateRemoteWorkspaceOptions = {}\n): Promise<RemoteWorkspaceMetadata> {\n const config = loadConfig();\n const remoteConfig = config.remote;\n\n if (!remoteConfig?.enabled) {\n throw new Error('Remote workspaces not enabled. Run `pan remote setup`');\n }\n\n const normalizedId = issueId.toLowerCase().replace(/[^a-z0-9-]/g, '-');\n const branchName = `feature/${normalizedId}`;\n const infraVm = remoteConfig.exe?.infra_vm || 'pan-infra';\n const exe = createExeProvider({ infraVm });\n\n // Determine project context\n const teamPrefix = extractTeamPrefix(issueId);\n const projectConfig = teamPrefix ? findProjectByTeam(teamPrefix) : null;\n const projectRoot = projectConfig?.path || process.cwd();\n\n // Determine project identifier for VM name\n let projectId = teamPrefix?.toLowerCase();\n if (!projectId && projectConfig?.linear_team) {\n projectId = projectConfig.linear_team.toLowerCase();\n }\n if (!projectId) {\n try {\n const { stdout } = await execAsync('git remote get-url origin', {\n cwd: projectRoot,\n encoding: 'utf-8',\n });\n const repoMatch = stdout.trim().match(/\\/([^\\/]+?)(\\.git)?$/);\n projectId = repoMatch ? repoMatch[1].toLowerCase().replace(/[^a-z0-9-]/g, '-') : 'proj';\n } catch {\n projectId = 'proj';\n }\n }\n\n // VM names must be valid hostnames (start with letter, alphanumeric + hyphens)\n const vmName = `${projectId}-${normalizedId}-ws`.toLowerCase().replace(/[^a-z0-9-]/g, '-');\n\n if (options.dryRun) {\n console.log(chalk.bold('Would create remote workspace:'));\n console.log(` VM: ${chalk.cyan(vmName)}`);\n console.log(` Project: ${chalk.dim(projectId)}`);\n console.log(` Infra: ${chalk.dim(infraVm)}`);\n console.log(` Branch: ${chalk.dim(branchName)}`);\n throw new Error('Dry run - not implemented in this module');\n }\n\n // Get git remote URL\n let repoUrl = '';\n try {\n const { stdout } = await execAsync('git remote get-url origin', {\n cwd: projectRoot,\n encoding: 'utf-8',\n });\n repoUrl = stdout.trim();\n } catch {\n throw new Error('Could not determine git remote URL. Make sure you are in a git repository with a remote origin.');\n }\n\n if (options.spinner) {\n options.spinner.text = 'Creating VM (this may take 1-2 minutes)...';\n }\n\n // Step 1: Create VM\n await exe.createVm(vmName);\n\n // Step 2: Add GitHub host key and clone repository on VM\n if (options.spinner) {\n options.spinner.text = 'Cloning repository on VM...';\n }\n await exe.ssh(vmName, 'mkdir -p ~/.ssh && ssh-keyscan -t ed25519,rsa github.com >> ~/.ssh/known_hosts 2>/dev/null');\n const cloneResult = await exe.ssh(vmName, `git clone ${repoUrl} ~/workspace`);\n if (cloneResult.exitCode !== 0) {\n await exe.deleteVm(vmName);\n throw new Error(`Failed to clone: ${cloneResult.stderr}`);\n }\n\n // Step 3: Create feature branch\n if (options.spinner) {\n options.spinner.text = 'Creating feature branch...';\n }\n const branchResult = await exe.ssh(vmName, `cd ~/workspace && git checkout -b ${branchName}`);\n if (branchResult.exitCode !== 0) {\n await exe.ssh(vmName, `cd ~/workspace && git checkout ${branchName} || git checkout -b ${branchName}`);\n }\n\n // Step 4: Configure environment for shared infra\n const envContent = `\n# Panopticon Remote Workspace\nWORKSPACE_ID=${normalizedId}\nISSUE_ID=${issueId.toUpperCase()}\n\n# Shared Infrastructure\nPOSTGRES_HOST=${infraVm}\nPOSTGRES_PORT=5432\nPOSTGRES_USER=postgres\nPOSTGRES_PASSWORD=\\${PAN_POSTGRES_PASSWORD:-panopticon}\nDATABASE_NAME=myn_${normalizedId.replace(/-/g, '_')}\n\nREDIS_HOST=${infraVm}\nREDIS_PORT=6379\nREDIS_DATABASE=0\n\n# Spring Boot (if applicable)\nSPRING_DATASOURCE_URL=jdbc:postgresql://${infraVm}:5432/myn_${normalizedId.replace(/-/g, '_')}\nSPRING_DATA_REDIS_HOST=${infraVm}\n`;\n\n await exe.ssh(vmName, `cat > ~/workspace/.env.remote << 'EOF'\n${envContent}\nEOF`);\n\n // Step 5: Create database on shared postgres\n const dbName = `myn_${normalizedId.replace(/-/g, '_')}`;\n try {\n await exe.ssh(infraVm, `docker exec pan-postgres psql -U postgres -c \"CREATE DATABASE ${dbName}\" 2>/dev/null || true`);\n } catch {\n // Non-fatal - database might already exist\n }\n\n // Step 6: Install beads CLI globally on remote VM\n if (options.spinner) {\n options.spinner.text = 'Installing beads CLI...';\n }\n const bdInstalled = await exe.installBeads(vmName);\n if (bdInstalled) {\n await exe.initBeads(vmName, '~/workspace');\n }\n\n // Step 6.5: Copy essential skills to remote VM\n if (options.spinner) {\n options.spinner.text = 'Copying skills to remote VM...';\n }\n await exe.copySkillsToVm(vmName);\n\n // Step 7: Start containers if docker compose exists\n let containersStarted = false;\n let frontendUrl = '';\n let apiUrl = '';\n\n const composeCheck = await exe.ssh(vmName, 'ls ~/workspace/docker-compose.yml ~/workspace/.devcontainer/docker-compose.yml 2>/dev/null | head -1');\n\n if (composeCheck.stdout.trim()) {\n if (options.spinner) {\n options.spinner.text = 'Starting containers...';\n }\n const composeDir = composeCheck.stdout.includes('.devcontainer')\n ? '~/workspace/.devcontainer'\n : '~/workspace';\n\n const upResult = await exe.ssh(vmName, `cd ${composeDir} && docker compose up -d 2>&1`);\n containersStarted = upResult.exitCode === 0;\n\n if (containersStarted) {\n if (options.spinner) {\n options.spinner.text = 'Exposing ports...';\n }\n try {\n frontendUrl = await exe.exposePort(vmName, 4173);\n apiUrl = await exe.exposePort(vmName, 7000);\n } catch {\n // Port exposure failed - not critical\n }\n }\n }\n\n // Step 8: Save workspace metadata\n const metadata: RemoteWorkspaceMetadata = {\n id: normalizedId,\n issue: issueId.toUpperCase(),\n provider: 'exe',\n vmName,\n infraVm,\n database: dbName,\n redisDb: 0,\n urls: {\n frontend: frontendUrl || undefined,\n api: apiUrl || undefined,\n },\n created: new Date(),\n location: 'remote',\n };\n\n saveWorkspaceMetadata(metadata);\n\n return metadata;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAAA;AAOA,OAAO,WAAW;AAGlB,SAAS,YAAY;AACrB,SAAS,iBAAiB;AAE1B;AAGA;AAEA,IAAM,YAAY,UAAU,IAAI;AAUhC,eAAsB,sBACpB,SACA,UAAwC,CAAC,GACP;AAClC,QAAM,SAAS,WAAW;AAC1B,QAAM,eAAe,OAAO;AAE5B,MAAI,CAAC,cAAc,SAAS;AAC1B,UAAM,IAAI,MAAM,uDAAuD;AAAA,EACzE;AAEA,QAAM,eAAe,QAAQ,YAAY,EAAE,QAAQ,eAAe,GAAG;AACrE,QAAM,aAAa,WAAW,YAAY;AAC1C,QAAM,UAAU,aAAa,KAAK,YAAY;AAC9C,QAAM,MAAM,kBAAkB,EAAE,QAAQ,CAAC;AAGzC,QAAM,aAAa,kBAAkB,OAAO;AAC5C,QAAM,gBAAgB,aAAa,kBAAkB,UAAU,IAAI;AACnE,QAAM,cAAc,eAAe,QAAQ,QAAQ,IAAI;AAGvD,MAAI,YAAY,YAAY,YAAY;AACxC,MAAI,CAAC,aAAa,eAAe,aAAa;AAC5C,gBAAY,cAAc,YAAY,YAAY;AAAA,EACpD;AACA,MAAI,CAAC,WAAW;AACd,QAAI;AACF,YAAM,EAAE,OAAO,IAAI,MAAM,UAAU,6BAA6B;AAAA,QAC9D,KAAK;AAAA,QACL,UAAU;AAAA,MACZ,CAAC;AACD,YAAM,YAAY,OAAO,KAAK,EAAE,MAAM,sBAAsB;AAC5D,kBAAY,YAAY,UAAU,CAAC,EAAE,YAAY,EAAE,QAAQ,eAAe,GAAG,IAAI;AAAA,IACnF,QAAQ;AACN,kBAAY;AAAA,IACd;AAAA,EACF;AAGA,QAAM,SAAS,GAAG,SAAS,IAAI,YAAY,MAAM,YAAY,EAAE,QAAQ,eAAe,GAAG;AAEzF,MAAI,QAAQ,QAAQ;AAClB,YAAQ,IAAI,MAAM,KAAK,gCAAgC,CAAC;AACxD,YAAQ,IAAI,gBAAgB,MAAM,KAAK,MAAM,CAAC,EAAE;AAChD,YAAQ,IAAI,gBAAgB,MAAM,IAAI,SAAS,CAAC,EAAE;AAClD,YAAQ,IAAI,gBAAgB,MAAM,IAAI,OAAO,CAAC,EAAE;AAChD,YAAQ,IAAI,gBAAgB,MAAM,IAAI,UAAU,CAAC,EAAE;AACnD,UAAM,IAAI,MAAM,0CAA0C;AAAA,EAC5D;AAGA,MAAI,UAAU;AACd,MAAI;AACF,UAAM,EAAE,OAAO,IAAI,MAAM,UAAU,6BAA6B;AAAA,MAC9D,KAAK;AAAA,MACL,UAAU;AAAA,IACZ,CAAC;AACD,cAAU,OAAO,KAAK;AAAA,EACxB,QAAQ;AACN,UAAM,IAAI,MAAM,iGAAiG;AAAA,EACnH;AAEA,MAAI,QAAQ,SAAS;AACnB,YAAQ,QAAQ,OAAO;AAAA,EACzB;AAGA,QAAM,IAAI,SAAS,MAAM;AAGzB,MAAI,QAAQ,SAAS;AACnB,YAAQ,QAAQ,OAAO;AAAA,EACzB;AACA,QAAM,IAAI,IAAI,QAAQ,4FAA4F;AAClH,QAAM,cAAc,MAAM,IAAI,IAAI,QAAQ,aAAa,OAAO,cAAc;AAC5E,MAAI,YAAY,aAAa,GAAG;AAC9B,UAAM,IAAI,SAAS,MAAM;AACzB,UAAM,IAAI,MAAM,oBAAoB,YAAY,MAAM,EAAE;AAAA,EAC1D;AAGA,MAAI,QAAQ,SAAS;AACnB,YAAQ,QAAQ,OAAO;AAAA,EACzB;AACA,QAAM,eAAe,MAAM,IAAI,IAAI,QAAQ,qCAAqC,UAAU,EAAE;AAC5F,MAAI,aAAa,aAAa,GAAG;AAC/B,UAAM,IAAI,IAAI,QAAQ,kCAAkC,UAAU,uBAAuB,UAAU,EAAE;AAAA,EACvG;AAGA,QAAM,aAAa;AAAA;AAAA,eAEN,YAAY;AAAA,WAChB,QAAQ,YAAY,CAAC;AAAA;AAAA;AAAA,gBAGhB,OAAO;AAAA;AAAA;AAAA;AAAA,oBAIH,aAAa,QAAQ,MAAM,GAAG,CAAC;AAAA;AAAA,aAEtC,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA,0CAKsB,OAAO,aAAa,aAAa,QAAQ,MAAM,GAAG,CAAC;AAAA,yBACpE,OAAO;AAAA;AAG9B,QAAM,IAAI,IAAI,QAAQ;AAAA,EACtB,UAAU;AAAA,IACR;AAGF,QAAM,SAAS,OAAO,aAAa,QAAQ,MAAM,GAAG,CAAC;AACrD,MAAI;AACF,UAAM,IAAI,IAAI,SAAS,iEAAiE,MAAM,uBAAuB;AAAA,EACvH,QAAQ;AAAA,EAER;AAGA,MAAI,QAAQ,SAAS;AACnB,YAAQ,QAAQ,OAAO;AAAA,EACzB;AACA,QAAM,cAAc,MAAM,IAAI,aAAa,MAAM;AACjD,MAAI,aAAa;AACf,UAAM,IAAI,UAAU,QAAQ,aAAa;AAAA,EAC3C;AAGA,MAAI,QAAQ,SAAS;AACnB,YAAQ,QAAQ,OAAO;AAAA,EACzB;AACA,QAAM,IAAI,eAAe,MAAM;AAG/B,MAAI,oBAAoB;AACxB,MAAI,cAAc;AAClB,MAAI,SAAS;AAEb,QAAM,eAAe,MAAM,IAAI,IAAI,QAAQ,sGAAsG;AAEjJ,MAAI,aAAa,OAAO,KAAK,GAAG;AAC9B,QAAI,QAAQ,SAAS;AACnB,cAAQ,QAAQ,OAAO;AAAA,IACzB;AACA,UAAM,aAAa,aAAa,OAAO,SAAS,eAAe,IAC3D,8BACA;AAEJ,UAAM,WAAW,MAAM,IAAI,IAAI,QAAQ,MAAM,UAAU,+BAA+B;AACtF,wBAAoB,SAAS,aAAa;AAE1C,QAAI,mBAAmB;AACrB,UAAI,QAAQ,SAAS;AACnB,gBAAQ,QAAQ,OAAO;AAAA,MACzB;AACA,UAAI;AACF,sBAAc,MAAM,IAAI,WAAW,QAAQ,IAAI;AAC/C,iBAAS,MAAM,IAAI,WAAW,QAAQ,GAAI;AAAA,MAC5C,QAAQ;AAAA,MAER;AAAA,IACF;AAAA,EACF;AAGA,QAAM,WAAoC;AAAA,IACxC,IAAI;AAAA,IACJ,OAAO,QAAQ,YAAY;AAAA,IAC3B,UAAU;AAAA,IACV;AAAA,IACA;AAAA,IACA,UAAU;AAAA,IACV,SAAS;AAAA,IACT,MAAM;AAAA,MACJ,UAAU,eAAe;AAAA,MACzB,KAAK,UAAU;AAAA,IACjB;AAAA,IACA,SAAS,oBAAI,KAAK;AAAA,IAClB,UAAU;AAAA,EACZ;AAEA,wBAAsB,QAAQ;AAE9B,SAAO;AACT;","names":[]}
1
+ {"version":3,"sources":["../src/lib/remote-workspace.ts"],"sourcesContent":["/**\n * Remote Workspace Creation\n *\n * Shared module for creating remote workspaces.\n * Used by both workspace.ts (explicit creation) and work/issue.ts (auto-creation).\n */\n\nimport chalk from 'chalk';\nimport { existsSync } from 'fs';\nimport { join } from 'path';\nimport { exec } from 'child_process';\nimport { promisify } from 'util';\nimport { loadConfig } from './config.js';\nimport { createExeProvider } from './remote/exe-provider.js';\nimport { saveWorkspaceMetadata } from './remote/workspace-metadata.js';\nimport type { RemoteWorkspaceMetadata } from './remote/interface.js';\nimport { extractTeamPrefix, findProjectByTeam, resolveProjectFromIssue } from './projects.js';\n\nconst execAsync = promisify(exec);\n\nexport interface CreateRemoteWorkspaceOptions {\n dryRun?: boolean;\n spinner?: { text: string };\n}\n\n/**\n * Create a remote workspace on exe.dev\n */\nexport async function createRemoteWorkspace(\n issueId: string,\n options: CreateRemoteWorkspaceOptions = {}\n): Promise<RemoteWorkspaceMetadata> {\n const config = loadConfig();\n const remoteConfig = config.remote;\n\n if (!remoteConfig?.enabled) {\n throw new Error('Remote workspaces not enabled. Run `pan remote setup`');\n }\n\n const normalizedId = issueId.toLowerCase().replace(/[^a-z0-9-]/g, '-');\n const branchName = `feature/${normalizedId}`;\n const infraVm = remoteConfig.exe?.infra_vm || 'pan-infra';\n const exe = createExeProvider({ infraVm });\n\n // Determine project context\n const teamPrefix = extractTeamPrefix(issueId);\n const projectConfig = teamPrefix ? findProjectByTeam(teamPrefix) : null;\n const projectRoot = projectConfig?.path || process.cwd();\n\n // Determine project identifier for VM name\n let projectId = teamPrefix?.toLowerCase();\n if (!projectId && projectConfig?.linear_team) {\n projectId = projectConfig.linear_team.toLowerCase();\n }\n if (!projectId) {\n try {\n const { stdout } = await execAsync('git remote get-url origin', {\n cwd: projectRoot,\n encoding: 'utf-8',\n });\n const repoMatch = stdout.trim().match(/\\/([^\\/]+?)(\\.git)?$/);\n projectId = repoMatch ? repoMatch[1].toLowerCase().replace(/[^a-z0-9-]/g, '-') : 'proj';\n } catch {\n projectId = 'proj';\n }\n }\n\n // VM names must be valid hostnames (start with letter, alphanumeric + hyphens)\n const vmName = `${projectId}-${normalizedId}-ws`.toLowerCase().replace(/[^a-z0-9-]/g, '-');\n\n if (options.dryRun) {\n console.log(chalk.bold('Would create remote workspace:'));\n console.log(` VM: ${chalk.cyan(vmName)}`);\n console.log(` Project: ${chalk.dim(projectId)}`);\n console.log(` Infra: ${chalk.dim(infraVm)}`);\n console.log(` Branch: ${chalk.dim(branchName)}`);\n throw new Error('Dry run - not implemented in this module');\n }\n\n // Get git remote URL\n let repoUrl = '';\n try {\n const { stdout } = await execAsync('git remote get-url origin', {\n cwd: projectRoot,\n encoding: 'utf-8',\n });\n repoUrl = stdout.trim();\n } catch {\n throw new Error('Could not determine git remote URL. Make sure you are in a git repository with a remote origin.');\n }\n\n if (options.spinner) {\n options.spinner.text = 'Creating VM (this may take 1-2 minutes)...';\n }\n\n // Step 1: Create VM\n await exe.createVm(vmName);\n\n // Step 2: Add GitHub host key and clone repository on VM\n if (options.spinner) {\n options.spinner.text = 'Cloning repository on VM...';\n }\n await exe.ssh(vmName, 'mkdir -p ~/.ssh && ssh-keyscan -t ed25519,rsa github.com >> ~/.ssh/known_hosts 2>/dev/null');\n const cloneResult = await exe.ssh(vmName, `git clone ${repoUrl} ~/workspace`);\n if (cloneResult.exitCode !== 0) {\n await exe.deleteVm(vmName);\n throw new Error(`Failed to clone: ${cloneResult.stderr}`);\n }\n\n // Step 3: Create feature branch\n if (options.spinner) {\n options.spinner.text = 'Creating feature branch...';\n }\n const branchResult = await exe.ssh(vmName, `cd ~/workspace && git checkout -b ${branchName}`);\n if (branchResult.exitCode !== 0) {\n await exe.ssh(vmName, `cd ~/workspace && git checkout ${branchName} || git checkout -b ${branchName}`);\n }\n\n // Step 4: Configure environment for shared infra\n const envContent = `\n# Panopticon Remote Workspace\nWORKSPACE_ID=${normalizedId}\nISSUE_ID=${issueId.toUpperCase()}\n\n# Shared Infrastructure\nPOSTGRES_HOST=${infraVm}\nPOSTGRES_PORT=5432\nPOSTGRES_USER=postgres\nPOSTGRES_PASSWORD=\\${PAN_POSTGRES_PASSWORD:-panopticon}\nDATABASE_NAME=myn_${normalizedId.replace(/-/g, '_')}\n\nREDIS_HOST=${infraVm}\nREDIS_PORT=6379\nREDIS_DATABASE=0\n\n# Spring Boot (if applicable)\nSPRING_DATASOURCE_URL=jdbc:postgresql://${infraVm}:5432/myn_${normalizedId.replace(/-/g, '_')}\nSPRING_DATA_REDIS_HOST=${infraVm}\n`;\n\n await exe.ssh(vmName, `cat > ~/workspace/.env.remote << 'EOF'\n${envContent}\nEOF`);\n\n // Step 5: Create database on shared postgres\n const dbName = `myn_${normalizedId.replace(/-/g, '_')}`;\n try {\n await exe.ssh(infraVm, `docker exec pan-postgres psql -U postgres -c \"CREATE DATABASE ${dbName}\" 2>/dev/null || true`);\n } catch {\n // Non-fatal - database might already exist\n }\n\n // Step 6: Install beads CLI globally on remote VM\n if (options.spinner) {\n options.spinner.text = 'Installing beads CLI...';\n }\n const bdInstalled = await exe.installBeads(vmName);\n if (bdInstalled) {\n await exe.initBeads(vmName, '~/workspace');\n }\n\n // Step 6.5: Copy essential skills to remote VM\n if (options.spinner) {\n options.spinner.text = 'Copying skills to remote VM...';\n }\n await exe.copySkillsToVm(vmName);\n\n // Step 7: Start containers if docker compose exists\n let containersStarted = false;\n let frontendUrl = '';\n let apiUrl = '';\n\n const composeCheck = await exe.ssh(vmName, 'ls ~/workspace/docker-compose.yml ~/workspace/.devcontainer/docker-compose.yml 2>/dev/null | head -1');\n\n if (composeCheck.stdout.trim()) {\n if (options.spinner) {\n options.spinner.text = 'Starting containers...';\n }\n const composeDir = composeCheck.stdout.includes('.devcontainer')\n ? '~/workspace/.devcontainer'\n : '~/workspace';\n\n const upResult = await exe.ssh(vmName, `cd ${composeDir} && docker compose up -d 2>&1`);\n containersStarted = upResult.exitCode === 0;\n\n if (containersStarted) {\n if (options.spinner) {\n options.spinner.text = 'Exposing ports...';\n }\n try {\n frontendUrl = await exe.exposePort(vmName, 4173);\n apiUrl = await exe.exposePort(vmName, 7000);\n } catch {\n // Port exposure failed - not critical\n }\n }\n }\n\n // Step 8: Save workspace metadata\n const metadata: RemoteWorkspaceMetadata = {\n id: normalizedId,\n issue: issueId.toUpperCase(),\n provider: 'exe',\n vmName,\n infraVm,\n database: dbName,\n redisDb: 0,\n urls: {\n frontend: frontendUrl || undefined,\n api: apiUrl || undefined,\n },\n created: new Date(),\n location: 'remote',\n };\n\n saveWorkspaceMetadata(metadata);\n\n return metadata;\n}\n"],"mappings":"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","names":[]}
@@ -1,11 +1,11 @@
1
1
  import {
2
2
  getRecentRunLogs,
3
3
  init_specialist_logs
4
- } from "./chunk-4KNEZGKZ.js";
4
+ } from "./chunk-TMXN7THF.js";
5
5
  import {
6
6
  getModelId,
7
7
  init_work_type_router
8
- } from "./chunk-ON5NIBGW.js";
8
+ } from "./chunk-VIWUCJ4V.js";
9
9
  import "./chunk-BBCUK6N2.js";
10
10
  import {
11
11
  getProject,
@@ -253,4 +253,4 @@ export {
253
253
  regenerateContextDigest,
254
254
  scheduleDigestGeneration
255
255
  };
256
- //# sourceMappingURL=specialist-context-WXO3FKIB.js.map
256
+ //# sourceMappingURL=specialist-context-6SE5VRRC.js.map
@@ -16,8 +16,8 @@ import {
16
16
  isRunLogActive,
17
17
  listRunLogs,
18
18
  parseLogMetadata
19
- } from "./chunk-4KNEZGKZ.js";
20
- import "./chunk-ON5NIBGW.js";
19
+ } from "./chunk-TMXN7THF.js";
20
+ import "./chunk-VIWUCJ4V.js";
21
21
  import "./chunk-BBCUK6N2.js";
22
22
  import "./chunk-JY7R7V4G.js";
23
23
  import "./chunk-6HXKTOD7.js";
@@ -41,4 +41,4 @@ export {
41
41
  listRunLogs,
42
42
  parseLogMetadata
43
43
  };
44
- //# sourceMappingURL=specialist-logs-SJWLETJT.js.map
44
+ //# sourceMappingURL=specialist-logs-EXLOQHQ2.js.map
@@ -55,8 +55,8 @@ import {
55
55
  wakeSpecialist,
56
56
  wakeSpecialistOrQueue,
57
57
  wakeSpecialistWithTask
58
- } from "./chunk-4KNEZGKZ.js";
59
- import "./chunk-ON5NIBGW.js";
58
+ } from "./chunk-TMXN7THF.js";
59
+ import "./chunk-VIWUCJ4V.js";
60
60
  import "./chunk-BBCUK6N2.js";
61
61
  import "./chunk-JY7R7V4G.js";
62
62
  import "./chunk-6HXKTOD7.js";
@@ -119,4 +119,4 @@ export {
119
119
  wakeSpecialistOrQueue,
120
120
  wakeSpecialistWithTask
121
121
  };
122
- //# sourceMappingURL=specialists-5YJIDRW6.js.map
122
+ //# sourceMappingURL=specialists-BRUHPAXE.js.map
@@ -1,12 +1,12 @@
1
1
  import {
2
2
  cleanupTemplateFiles,
3
3
  generatePanopticonTraefikConfig
4
- } from "./chunk-SIAUVHVO.js";
5
- import "./chunk-VTMXR7JF.js";
4
+ } from "./chunk-3XAB4IXF.js";
5
+ import "./chunk-VU4FLXV5.js";
6
6
  import "./chunk-6HXKTOD7.js";
7
7
  import "./chunk-ZHC57RCV.js";
8
8
  export {
9
9
  cleanupTemplateFiles,
10
10
  generatePanopticonTraefikConfig
11
11
  };
12
- //# sourceMappingURL=traefik-7OLLXUD7.js.map
12
+ //# sourceMappingURL=traefik-CUJM6K5Z.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "panopticon-cli",
3
- "version": "0.4.28",
3
+ "version": "0.4.31",
4
4
  "description": "Multi-agent orchestration for AI coding assistants (Claude Code, Codex, Cursor, Gemini CLI)",
5
5
  "keywords": [
6
6
  "ai-agents",
@@ -48,8 +48,9 @@
48
48
  },
49
49
  "scripts": {
50
50
  "dev": "tsx watch src/cli/index.ts",
51
- "build": "npm run build:cli && npm run build:dashboard",
51
+ "build": "npm run build:cli && npm run build:scripts && npm run build:dashboard",
52
52
  "build:cli": "tsup",
53
+ "build:scripts": "esbuild scripts/record-cost-event.ts --bundle --platform=node --format=esm --outfile=scripts/record-cost-event.js",
53
54
  "build:dashboard": "npm run build:dashboard:frontend && npm run build:dashboard:server",
54
55
  "build:dashboard:frontend": "cd src/dashboard/frontend && npm run build",
55
56
  "build:dashboard:server": "cd src/dashboard/server && npm run build",