@mukulaggarwal/pacman 0.1.2 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,39 +1,185 @@
1
1
  # pacman
2
2
 
3
- Privacy-first personal assistant context manager with onboarding, MCP, and Slack runtime.
3
+ ```text
4
+ ____ _ ____ __ __ _ _ _
5
+ | _ \ / \ / ___| \/ | / \ | \ | |
6
+ | |_) / _ \| | | |\/| | / _ \ | \| |
7
+ | __/ ___ \ |___| | | |/ ___ \| |\ |
8
+ |_| /_/ \_\____|_| |_/_/ \_\_| \_|
9
+ ```
10
+
11
+ > Waka through project context with Claude Code, Codex, and Slack.
12
+ > Your memory stays in local files or a Google Drive folder you control.
13
+
14
+ ## Arcade Pitch
15
+
16
+ Use `pacman` when you want assistants to stay grounded in your actual workspace instead of a hidden hosted database.
17
+
18
+ - Keep context in Markdown and JSON you can inspect
19
+ - Share one workspace across Claude Code, Codex, and Slack
20
+ - Register one MCP server for both coding clients
21
+ - Sync project signals from tools like Slack, GitHub, GitLab, Gmail, and Google Drive
22
+ - Generate replies from saved canonical context, derived summaries, and raw evidence you control
4
23
 
5
- Install:
24
+ ## Insert Coin
6
25
 
7
26
  ```bash
8
27
  npm install -g @mukulaggarwal/pacman
9
28
  ```
10
29
 
11
- Primary commands:
30
+ <details>
31
+ <summary><strong>Check that the cabinet booted</strong></summary>
12
32
 
13
33
  ```bash
14
- pacman init
15
- pacman claude install
16
- pacman codex install
17
- pacman mcp claude install
18
- pacman mcp codex install
19
- pacman daemon
20
- pacman slack listen
34
+ pacman --help
35
+ pacman mcp claude install --help
36
+ pacman mcp codex install --help
21
37
  ```
22
38
 
23
- Compatibility aliases shipped in the same package:
39
+ </details>
40
+
41
+ <details>
42
+ <summary><strong>Upgrade to the latest build</strong></summary>
24
43
 
25
44
  ```bash
26
- personal-assistant
27
- personal-assistant-mcp
45
+ npm install -g @mukulaggarwal/pacman@latest
28
46
  ```
29
47
 
30
- Manual MCP fallback:
48
+ </details>
49
+
50
+ ## Choose Your Route
51
+
52
+ <details open>
53
+ <summary><strong>Level 1: Spawn your workspace</strong></summary>
31
54
 
32
55
  ```bash
33
- claude mcp add -s user --env=PA_WORKSPACE=$HOME/.personal-assistant personal_assistant -- npx -y pacman mcp serve
34
- codex mcp add personal_assistant --env PA_WORKSPACE=$HOME/.personal-assistant -- npx -y pacman mcp serve
56
+ pacman init -d .personal-assistant
35
57
  ```
36
58
 
37
- Full docs, release notes, and contribution guide:
59
+ This launches the onboarding UI and configures your profile, assistant identity, storage backend, integrations, and sync schedule.
60
+
61
+ </details>
62
+
63
+ <details open>
64
+ <summary><strong>Level 2: Equip Claude Code and Codex</strong></summary>
65
+
66
+ ```bash
67
+ pacman claude install -d . -w .personal-assistant
68
+ pacman codex install -d . -w .personal-assistant
69
+ ```
70
+
71
+ This writes:
72
+
73
+ - `CLAUDE.md` for Claude Code
74
+ - `AGENTS.md` for Codex
75
+ - shared Pac-Man skills under `~/.claude/skills/` and `~/.codex/skills/`
76
+
77
+ </details>
78
+
79
+ <details open>
80
+ <summary><strong>Level 3: Power up MCP</strong></summary>
81
+
82
+ ```bash
83
+ pacman mcp claude install -w .personal-assistant
84
+ pacman mcp codex install -w .personal-assistant
85
+ ```
86
+
87
+ Restart Claude Code or Codex after MCP registration.
88
+
89
+ </details>
90
+
91
+ <details>
92
+ <summary><strong>Secret tunnel: Manual MCP fallback</strong></summary>
93
+
94
+ ```bash
95
+ claude mcp add -s user --env=PA_WORKSPACE=$HOME/.personal-assistant pacman -- npx -y pacman mcp serve
96
+ codex mcp add pacman --env PA_WORKSPACE=$HOME/.personal-assistant -- npx -y pacman mcp serve
97
+ ```
98
+
99
+ </details>
100
+
101
+ <details>
102
+ <summary><strong>Level 4: Keep the map fresh</strong></summary>
103
+
104
+ ```bash
105
+ pacman daemon -d .personal-assistant
106
+ ```
107
+
108
+ Run the background sync to ingest enabled integrations and rebuild indexes.
109
+
110
+ </details>
111
+
112
+ <details>
113
+ <summary><strong>Level 5: Turn on Slack mode</strong></summary>
114
+
115
+ ```bash
116
+ pacman slack listen -d .personal-assistant
117
+ ```
118
+
119
+ Use this when you want Slack replies grounded in saved project context.
120
+
121
+ </details>
122
+
123
+ ## Game Modes
124
+
125
+ | Mode | What it unlocks |
126
+ | --- | --- |
127
+ | `pacman init` | Launch onboarding and create the workspace |
128
+ | `pacman claude install` | Add Claude Code project guidance |
129
+ | `pacman codex install` | Add Codex project guidance |
130
+ | `pacman mcp claude install` | Register the MCP server with Claude Code |
131
+ | `pacman mcp codex install` | Register the MCP server with Codex |
132
+ | `pacman daemon` | Run scheduled sync and indexing |
133
+ | `pacman slack listen` | Start Slack auto-reply handling |
134
+
135
+ ## Player Guide
136
+
137
+ <details>
138
+ <summary><strong>Claude Code lane</strong></summary>
139
+
140
+ After install:
141
+
142
+ ```bash
143
+ pacman claude install -d . -w .personal-assistant
144
+ pacman mcp claude install -w .personal-assistant
145
+ ```
146
+
147
+ Then restart Claude Code and use Pac-Man guidance plus MCP-backed context reads and updates.
148
+
149
+ </details>
150
+
151
+ <details>
152
+ <summary><strong>Codex lane</strong></summary>
153
+
154
+ After install:
155
+
156
+ ```bash
157
+ pacman codex install -d . -w .personal-assistant
158
+ pacman mcp codex install -w .personal-assistant
159
+ ```
160
+
161
+ Then restart Codex and ask it to load, search, read, or update project context through Pac-Man MCP tools.
162
+
163
+ </details>
164
+
165
+ <details>
166
+ <summary><strong>Slack lane</strong></summary>
167
+
168
+ ```bash
169
+ pacman slack listen -d .personal-assistant
170
+ ```
171
+
172
+ Slack replies are additive. They use the same saved workspace and do not replace MCP-based context access in Claude Code or Codex.
173
+
174
+ </details>
175
+
176
+ ## High Score Traits
177
+
178
+ - Privacy first: no mandatory hosted project database
179
+ - Inspectable storage: Markdown and JSON live in your workspace
180
+ - Shared memory: Claude Code, Codex, and Slack use the same context base
181
+ - Grounded retrieval: canonical context, derived summaries, and raw evidence stay connected
182
+
183
+ ## Full Map
38
184
 
39
- - https://github.com/mukulaggarwal/personal-assistant-with-context
185
+ - Repository and full docs: https://github.com/mukulaggarwal/personal-assistant-with-context
@@ -21,7 +21,8 @@ import * as path from "path";
21
21
  import { execFile } from "child_process";
22
22
  import { promisify } from "util";
23
23
  var execFileAsync = promisify(execFile);
24
- var MCP_SERVER_NAME = "personal_assistant";
24
+ var MCP_SERVER_NAME = "pacman";
25
+ var LEGACY_MCP_SERVER_NAMES = ["personal_assistant"];
25
26
  var DEFAULT_WORKSPACE = path.join(os.homedir(), ".personal-assistant");
26
27
  async function runCommand(command, args) {
27
28
  const result = await execFileAsync(command, args);
@@ -56,12 +57,14 @@ async function installClaudeMcp(workspacePath, resolveCommand = resolvePacmanSer
56
57
  const serverCommand = await resolveCommand();
57
58
  const fallbackCommand = formatClaudeManualInstallCommand(workspacePath, serverCommand);
58
59
  try {
59
- try {
60
- await runner("claude", ["mcp", "remove", "-s", "user", MCP_SERVER_NAME]);
61
- } catch (err) {
62
- const code = typeof err === "object" && err !== null && "code" in err ? String(err.code) : "";
63
- if (code === "ENOENT") {
64
- throw err;
60
+ for (const serverName of [MCP_SERVER_NAME, ...LEGACY_MCP_SERVER_NAMES]) {
61
+ try {
62
+ await runner("claude", ["mcp", "remove", "-s", "user", serverName]);
63
+ } catch (err) {
64
+ const code = typeof err === "object" && err !== null && "code" in err ? String(err.code) : "";
65
+ if (code === "ENOENT") {
66
+ throw err;
67
+ }
65
68
  }
66
69
  }
67
70
  await runner("claude", [
@@ -121,8 +124,10 @@ async function installCodexMcp(workspacePath, resolveCommand = resolvePacmanServ
121
124
  try {
122
125
  const { stdout } = await runner("codex", ["mcp", "list", "--json"]);
123
126
  const servers = parseCodexServerList(stdout);
124
- if (servers.some((server) => server.name === MCP_SERVER_NAME)) {
125
- await runner("codex", ["mcp", "remove", MCP_SERVER_NAME]);
127
+ for (const serverName of [MCP_SERVER_NAME, ...LEGACY_MCP_SERVER_NAMES]) {
128
+ if (servers.some((server) => server.name === serverName)) {
129
+ await runner("codex", ["mcp", "remove", serverName]);
130
+ }
126
131
  }
127
132
  await runner("codex", [
128
133
  "mcp",
@@ -155,7 +160,7 @@ function normalizeCodexInstallError(err, fallbackCommand) {
155
160
  }
156
161
  const details = stderr.trim() || message;
157
162
  return new Error(
158
- `Unable to register the Personal Assistant MCP server with Codex. ${details} Manual fallback: \`${fallbackCommand}\``
163
+ `Unable to register the Pac-Man MCP server with Codex. ${details} Manual fallback: \`${fallbackCommand}\``
159
164
  );
160
165
  }
161
166
  function normalizeClaudeInstallError(err, fallbackCommand) {
@@ -169,7 +174,7 @@ function normalizeClaudeInstallError(err, fallbackCommand) {
169
174
  }
170
175
  const details = stderr.trim() || message;
171
176
  return new Error(
172
- `Unable to register the Personal Assistant MCP server with Claude Code. ${details} Manual fallback: \`${fallbackCommand}\``
177
+ `Unable to register the Pac-Man MCP server with Claude Code. ${details} Manual fallback: \`${fallbackCommand}\``
173
178
  );
174
179
  }
175
180
 
@@ -207,7 +212,7 @@ async function startMcpServer(workspacePath) {
207
212
  alerts: []
208
213
  };
209
214
  const server = new McpServer({
210
- name: "personal-assistant",
215
+ name: "pacman",
211
216
  version: "0.1.0"
212
217
  });
213
218
  function textResult(text, isError = false) {
@@ -256,7 +261,7 @@ ${steps.map((step, index) => `${index + 1}. ${step}`).join("\n")}`;
256
261
  }
257
262
  function storageUnavailableMessage() {
258
263
  const sections = [
259
- `Personal Assistant MCP storage is unavailable: ${runtimeHealth.storage.reason ?? runtimeHealth.storage.summary}`,
264
+ `Pac-Man MCP storage is unavailable: ${runtimeHealth.storage.reason ?? runtimeHealth.storage.summary}`,
260
265
  formatSteps("Fix", runtimeHealth.storage.fix),
261
266
  formatSteps("Restart", runtimeHealth.storage.restart)
262
267
  ].filter(Boolean);
@@ -264,10 +269,10 @@ ${steps.map((step, index) => `${index + 1}. ${step}`).join("\n")}`;
264
269
  }
265
270
  function logStartupHealth() {
266
271
  if (runtimeHealth.alerts.length === 0) {
267
- console.error(`Personal Assistant MCP ready. Storage: ${runtimeHealth.storage.mode}`);
272
+ console.error(`Pac-Man MCP ready. Storage: ${runtimeHealth.storage.mode}`);
268
273
  return;
269
274
  }
270
- console.error("Personal Assistant MCP startup alerts:");
275
+ console.error("Pac-Man MCP startup alerts:");
271
276
  for (const alert of runtimeHealth.alerts) {
272
277
  console.error(`- ${alert.component} ${alert.name}: ${alert.reason}`);
273
278
  for (const step of alert.fix) {
@@ -804,4 +809,4 @@ export {
804
809
  installCodexMcp,
805
810
  startMcpServer
806
811
  };
807
- //# sourceMappingURL=chunk-VCDPIN57.js.map
812
+ //# sourceMappingURL=chunk-WH3UMGHQ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/mcp-installers.ts","../src/mcp-server.ts"],"sourcesContent":["import * as fs from 'node:fs/promises';\nimport * as os from 'node:os';\nimport * as path from 'node:path';\nimport { execFile } from 'node:child_process';\nimport { promisify } from 'node:util';\n\nconst execFileAsync = promisify(execFile);\n\nexport const MCP_SERVER_NAME = 'pacman';\nexport const LEGACY_MCP_SERVER_NAMES = ['personal_assistant'] as const;\nexport const DEFAULT_WORKSPACE = path.join(os.homedir(), '.personal-assistant');\n\nexport interface ServerCommand {\n command: string;\n args: string[];\n}\n\nexport interface CommandResult {\n stdout: string;\n stderr: string;\n}\n\nexport interface CodexMcpServer {\n name: string;\n}\n\nexport type CommandRunner = (\n command: string,\n args: string[],\n) => Promise<CommandResult>;\n\nasync function runCommand(command: string, args: string[]): Promise<CommandResult> {\n const result = await execFileAsync(command, args);\n return {\n stdout: result.stdout ?? '',\n stderr: result.stderr ?? '',\n };\n}\n\nexport async function resolveWorkspacePath(dirOpt?: string): Promise<string> {\n if (dirOpt) {\n return path.resolve(dirOpt);\n }\n\n const rcPath = path.join(os.homedir(), '.personal-assistant-rc.json');\n try {\n const rc = JSON.parse(await fs.readFile(rcPath, 'utf-8')) as { workspacePath?: string };\n if (rc.workspacePath) {\n return rc.workspacePath;\n }\n } catch {\n // Fall back to the default workspace.\n }\n\n return DEFAULT_WORKSPACE;\n}\n\nexport async function resolvePacmanServerCommand(): Promise<ServerCommand> {\n const scriptPath = path.resolve(process.argv[1]);\n return { command: process.execPath, args: [scriptPath, 'mcp', 'serve'] };\n}\n\nexport async function resolveCompatServerCommand(): Promise<ServerCommand> {\n const scriptPath = path.resolve(process.argv[1]);\n return { command: process.execPath, args: [scriptPath] };\n}\n\nexport async function installClaudeMcp(\n workspacePath: string,\n resolveCommand: () => Promise<ServerCommand> = resolvePacmanServerCommand,\n runner: CommandRunner = runCommand,\n): Promise<void> {\n const serverCommand = await resolveCommand();\n const fallbackCommand = formatClaudeManualInstallCommand(workspacePath, serverCommand);\n\n try {\n for (const serverName of [MCP_SERVER_NAME, ...LEGACY_MCP_SERVER_NAMES]) {\n try {\n await runner('claude', ['mcp', 'remove', '-s', 'user', serverName]);\n } catch (err) {\n const code = typeof err === 'object' && err !== null && 'code' in err\n ? String((err as { code?: unknown }).code)\n : '';\n if (code === 'ENOENT') {\n throw err;\n }\n }\n }\n\n await runner('claude', [\n 'mcp',\n 'add',\n '-s',\n 'user',\n `--env=PA_WORKSPACE=${workspacePath}`,\n MCP_SERVER_NAME,\n '--',\n serverCommand.command,\n ...serverCommand.args,\n ]);\n } catch (err) {\n throw normalizeClaudeInstallError(err, fallbackCommand);\n }\n}\n\nexport function formatClaudeManualInstallCommand(\n workspacePath: string,\n serverCommand: ServerCommand,\n): string {\n return [\n 'claude',\n 'mcp',\n 'add',\n '-s',\n 'user',\n `--env=${shellQuote(`PA_WORKSPACE=${workspacePath}`)}`,\n MCP_SERVER_NAME,\n '--',\n shellQuote(serverCommand.command),\n ...serverCommand.args.map(shellQuote),\n ].join(' ');\n}\n\nexport function formatCodexManualInstallCommand(\n workspacePath: string,\n serverCommand: ServerCommand,\n): string {\n return [\n 'codex',\n 'mcp',\n 'add',\n MCP_SERVER_NAME,\n '--env',\n shellQuote(`PA_WORKSPACE=${workspacePath}`),\n '--',\n shellQuote(serverCommand.command),\n ...serverCommand.args.map(shellQuote),\n ].join(' ');\n}\n\nexport function parseCodexServerList(stdout: string): CodexMcpServer[] {\n const trimmed = stdout.trim();\n if (trimmed.length === 0) {\n return [];\n }\n\n const jsonStart = trimmed.indexOf('[');\n const json = jsonStart >= 0 ? trimmed.slice(jsonStart) : trimmed;\n return JSON.parse(json) as CodexMcpServer[];\n}\n\nexport async function installCodexMcp(\n workspacePath: string,\n resolveCommand: () => Promise<ServerCommand> = resolvePacmanServerCommand,\n runner: CommandRunner = runCommand,\n): Promise<void> {\n const serverCommand = await resolveCommand();\n const fallbackCommand = formatCodexManualInstallCommand(workspacePath, serverCommand);\n\n try {\n const { stdout } = await runner('codex', ['mcp', 'list', '--json']);\n const servers = parseCodexServerList(stdout);\n\n for (const serverName of [MCP_SERVER_NAME, ...LEGACY_MCP_SERVER_NAMES]) {\n if (servers.some((server) => server.name === serverName)) {\n await runner('codex', ['mcp', 'remove', serverName]);\n }\n }\n\n await runner('codex', [\n 'mcp',\n 'add',\n MCP_SERVER_NAME,\n '--env',\n `PA_WORKSPACE=${workspacePath}`,\n '--',\n serverCommand.command,\n ...serverCommand.args,\n ]);\n } catch (err) {\n throw normalizeCodexInstallError(err, fallbackCommand);\n }\n}\n\nfunction shellQuote(value: string): string {\n if (/^[A-Za-z0-9_./:=+-]+$/.test(value)) {\n return value;\n }\n return `'${value.replace(/'/g, `'\\\\''`)}'`;\n}\n\nfunction normalizeCodexInstallError(err: unknown, fallbackCommand: string): Error {\n const code = typeof err === 'object' && err !== null && 'code' in err\n ? String((err as { code?: unknown }).code)\n : '';\n const stderr = typeof err === 'object' && err !== null && 'stderr' in err\n ? String((err as { stderr?: unknown }).stderr ?? '')\n : '';\n const message = err instanceof Error ? err.message : String(err);\n\n if (code === 'ENOENT') {\n return new Error(\n `Codex CLI was not found on PATH. Install Codex, then rerun \\`pacman mcp codex install\\`. Manual registration once Codex is available: \\`${fallbackCommand}\\``,\n );\n }\n\n const details = stderr.trim() || message;\n return new Error(\n `Unable to register the Pac-Man MCP server with Codex. ${details} Manual fallback: \\`${fallbackCommand}\\``,\n );\n}\n\nfunction normalizeClaudeInstallError(err: unknown, fallbackCommand: string): Error {\n const code = typeof err === 'object' && err !== null && 'code' in err\n ? String((err as { code?: unknown }).code)\n : '';\n const stderr = typeof err === 'object' && err !== null && 'stderr' in err\n ? String((err as { stderr?: unknown }).stderr ?? '')\n : '';\n const message = err instanceof Error ? err.message : String(err);\n\n if (code === 'ENOENT') {\n return new Error(\n `Claude Code CLI was not found on PATH. Install Claude Code, then rerun \\`pacman mcp claude install\\`. Manual registration once Claude Code is available: \\`${fallbackCommand}\\``,\n );\n }\n\n const details = stderr.trim() || message;\n return new Error(\n `Unable to register the Pac-Man MCP server with Claude Code. ${details} Manual fallback: \\`${fallbackCommand}\\``,\n );\n}\n","import * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\nimport { z } from 'zod';\nimport { createLocalStorage } from '@personal-assistant/storage-local';\nimport { createGDriveStorage } from '@personal-assistant/storage-gdrive';\nimport { createConfigManager } from '@personal-assistant/config-manager';\nimport { createContextManager } from '@personal-assistant/context-manager';\nimport { createIndexer } from '@personal-assistant/indexer';\nimport { createNoopEventClient } from '@personal-assistant/event-client';\nimport { validateIntegrationConfig } from '@personal-assistant/integration-runtime';\nimport type {\n AppConfig,\n GDriveStorageConfig,\n IntegrationConfig,\n StorageBackend,\n} from '@personal-assistant/core-types';\n\ntype ToolResult = {\n content: Array<{ type: 'text'; text: string }>;\n isError?: boolean;\n};\n\ntype HealthStatus = 'healthy' | 'error';\n\ninterface StorageHealth {\n status: HealthStatus;\n mode: 'local' | 'gdrive';\n summary: string;\n reason?: string;\n fix: string[];\n restart: string[];\n}\n\ninterface IntegrationHealth {\n type: IntegrationConfig['type'];\n status: HealthStatus;\n summary: string;\n reason?: string;\n fix: string[];\n restart: string[];\n}\n\ninterface StartupAlert {\n component: 'storage' | 'integration';\n name: string;\n reason: string;\n fix: string[];\n restart: string[];\n}\n\nconst DEFAULT_RESTART_STEPS = [\n 'Restart your MCP client after the configuration has been updated.',\n 'If the registered workspace path changed, rerun `pacman mcp claude install` for Claude Code or `pacman mcp codex install` for Codex before restarting.',\n];\n\nexport async function startMcpServer(workspacePath: string): Promise<void> {\n const localStore = createLocalStorage(workspacePath);\n let storage: StorageBackend = localStore;\n let configManager = createConfigManager(localStore);\n let contextManager = createContextManager(localStore);\n let indexer = createIndexer(localStore);\n const eventClient = createNoopEventClient();\n\n let bootstrapConfig: AppConfig | null = null;\n let storageReadyResolve: (() => void) | undefined;\n const storageReady = new Promise<void>((resolve) => {\n storageReadyResolve = resolve;\n });\n\n const runtimeHealth: {\n storage: StorageHealth;\n integrations: IntegrationHealth[];\n alerts: StartupAlert[];\n } = {\n storage: {\n status: 'healthy',\n mode: 'local',\n summary: `Using local workspace at ${workspacePath}`,\n fix: [],\n restart: DEFAULT_RESTART_STEPS,\n },\n integrations: [],\n alerts: [],\n };\n\n const server = new McpServer({\n name: 'pacman',\n version: '0.1.0',\n });\n\n function textResult(text: string, isError = false): ToolResult {\n return {\n content: [{ type: 'text', text }],\n ...(isError ? { isError: true } : {}),\n };\n }\n\n function getStatusConfig(): AppConfig {\n return bootstrapConfig ?? {\n user: { name: '', assistantName: 'Jarvis', profileType: 'software-engineer', responsibilities: [] },\n storage: { mode: 'local', workspacePath },\n integrations: [],\n sync: {\n dailySyncTime: '09:00',\n timezone: 'UTC',\n manualSyncEnabled: false,\n asyncUpdateEnabled: false,\n },\n };\n }\n\n function addAlert(alert: StartupAlert): void {\n runtimeHealth.alerts.push(alert);\n }\n\n function setStorageFailure(\n mode: 'local' | 'gdrive',\n reason: string,\n fix: string[],\n ): void {\n runtimeHealth.storage = {\n status: 'error',\n mode,\n summary: `Unable to use ${mode} storage`,\n reason,\n fix,\n restart: DEFAULT_RESTART_STEPS,\n };\n addAlert({\n component: 'storage',\n name: mode,\n reason,\n fix,\n restart: DEFAULT_RESTART_STEPS,\n });\n }\n\n function formatSteps(label: string, steps: string[]): string {\n if (steps.length === 0) return '';\n return `${label}:\\n${steps.map((step, index) => `${index + 1}. ${step}`).join('\\n')}`;\n }\n\n function storageUnavailableMessage(): string {\n const sections = [\n `Pac-Man MCP storage is unavailable: ${runtimeHealth.storage.reason ?? runtimeHealth.storage.summary}`,\n formatSteps('Fix', runtimeHealth.storage.fix),\n formatSteps('Restart', runtimeHealth.storage.restart),\n ].filter(Boolean);\n\n return sections.join('\\n\\n');\n }\n\n function logStartupHealth(): void {\n if (runtimeHealth.alerts.length === 0) {\n console.error(`Pac-Man MCP ready. Storage: ${runtimeHealth.storage.mode}`);\n return;\n }\n\n console.error('Pac-Man MCP startup alerts:');\n for (const alert of runtimeHealth.alerts) {\n console.error(`- ${alert.component} ${alert.name}: ${alert.reason}`);\n for (const step of alert.fix) {\n console.error(` Fix: ${step}`);\n }\n for (const step of alert.restart) {\n console.error(` Restart: ${step}`);\n }\n }\n }\n\n function getStorageFixSteps(mode: 'local' | 'gdrive', config?: GDriveStorageConfig): string[] {\n if (mode === 'gdrive') {\n return [\n 'Verify the Google Drive folder ID and OAuth credentials in profile/storage.json.',\n 'If the refresh token is no longer valid, reconnect Google Drive and save the updated configuration.',\n ...(config?.cachePath ? [`Ensure the local cache path exists and is writable: ${config.cachePath}`] : []),\n ];\n }\n\n return [\n `Verify that PA_WORKSPACE points to the correct workspace directory: ${workspacePath}`,\n 'Ensure the workspace directory exists and is writable.',\n 'Run `pacman init` if the workspace has not been initialized yet.',\n ];\n }\n\n function getIntegrationHealth(type: IntegrationConfig['type']): IntegrationHealth | undefined {\n return runtimeHealth.integrations.find((integration) => integration.type === type);\n }\n\n async function ensureStorageAvailable(): Promise<ToolResult | null> {\n await storageReady;\n if (runtimeHealth.storage.status === 'error') {\n return textResult(storageUnavailableMessage(), true);\n }\n return null;\n }\n\n async function resolveStorageBackend(): Promise<void> {\n bootstrapConfig = await configManager.loadConfig();\n runtimeHealth.storage.mode = bootstrapConfig.storage.mode;\n\n if (bootstrapConfig.storage.mode === 'gdrive') {\n const gdriveConfig = bootstrapConfig.storage as GDriveStorageConfig;\n const resolvedCachePath = path.isAbsolute(gdriveConfig.cachePath)\n ? gdriveConfig.cachePath\n : path.resolve(path.dirname(workspacePath), gdriveConfig.cachePath);\n\n try {\n const gdriveStorage = createGDriveStorage({\n ...gdriveConfig,\n cachePath: resolvedCachePath,\n });\n await gdriveStorage.initialize();\n\n storage = gdriveStorage;\n configManager = createConfigManager(gdriveStorage);\n contextManager = createContextManager(gdriveStorage);\n indexer = createIndexer(gdriveStorage);\n bootstrapConfig = await configManager.loadConfig();\n\n runtimeHealth.storage = {\n status: 'healthy',\n mode: 'gdrive',\n summary: `Connected to Google Drive storage${gdriveConfig.folderName ? ` (${gdriveConfig.folderName})` : ''}`,\n fix: [],\n restart: DEFAULT_RESTART_STEPS,\n };\n } catch (err) {\n setStorageFailure(\n 'gdrive',\n err instanceof Error ? err.message : String(err),\n getStorageFixSteps('gdrive', {\n ...gdriveConfig,\n cachePath: resolvedCachePath,\n }),\n );\n }\n } else {\n try {\n await fs.mkdir(workspacePath, { recursive: true });\n runtimeHealth.storage = {\n status: 'healthy',\n mode: 'local',\n summary: `Using local workspace at ${workspacePath}`,\n fix: [],\n restart: DEFAULT_RESTART_STEPS,\n };\n } catch (err) {\n setStorageFailure(\n 'local',\n err instanceof Error ? err.message : String(err),\n getStorageFixSteps('local'),\n );\n }\n }\n\n const configForIntegrations = getStatusConfig();\n runtimeHealth.integrations = [];\n for (const integration of configForIntegrations.integrations.filter((item) => item.enabled)) {\n const result = await validateIntegrationConfig(integration);\n\n if (result.ok) {\n runtimeHealth.integrations.push({\n type: integration.type,\n status: 'healthy',\n summary: result.summary ?? `Connected to ${integration.type}`,\n fix: [],\n restart: DEFAULT_RESTART_STEPS,\n });\n continue;\n }\n\n runtimeHealth.integrations.push({\n type: integration.type,\n status: 'error',\n summary: `Unable to connect to ${integration.type}`,\n reason: result.reason ?? `Unable to connect to ${integration.type}`,\n fix: result.fix ?? [],\n restart: DEFAULT_RESTART_STEPS,\n });\n addAlert({\n component: 'integration',\n name: integration.type,\n reason: result.reason ?? `Unable to connect to ${integration.type}`,\n fix: result.fix ?? [],\n restart: DEFAULT_RESTART_STEPS,\n });\n }\n\n logStartupHealth();\n }\n\n server.tool('config_get', 'Get the full application configuration', {}, async () => {\n const unavailable = await ensureStorageAvailable();\n if (unavailable) return unavailable;\n try {\n const config = await configManager.loadConfig();\n return textResult(JSON.stringify(config, null, 2));\n } catch (err) {\n return textResult(`Error loading config: ${err}`, true);\n }\n });\n\n server.tool('config_get_storage_mode', 'Get the current storage mode (local or gdrive)', {}, async () => {\n const unavailable = await ensureStorageAvailable();\n if (unavailable) return unavailable;\n try {\n const mode = await configManager.getStorageMode();\n return textResult(mode);\n } catch (err) {\n return textResult(`Error: ${err}`, true);\n }\n });\n\n server.tool('config_get_active_project', 'Get the currently active project name', {}, async () => {\n const unavailable = await ensureStorageAvailable();\n if (unavailable) return unavailable;\n try {\n const project = await configManager.getActiveProject();\n return textResult(project ?? 'No active project set');\n } catch (err) {\n return textResult(`Error: ${err}`, true);\n }\n });\n\n server.tool(\n 'config_set_active_project',\n 'Set the active project',\n { project_name: z.string().describe('The project name to set as active') },\n async ({ project_name }) => {\n const unavailable = await ensureStorageAvailable();\n if (unavailable) return unavailable;\n try {\n await configManager.setActiveProject(project_name);\n await eventClient.emitWithProject('project_selected', project_name);\n return textResult(`Active project set to: ${project_name}`);\n } catch (err) {\n return textResult(`Error: ${err}`, true);\n }\n },\n );\n\n server.tool('project_list', 'List all known projects', {}, async () => {\n const unavailable = await ensureStorageAvailable();\n if (unavailable) return unavailable;\n try {\n const projects = await contextManager.listProjects();\n return textResult(projects.length > 0 ? projects.join('\\n') : 'No projects found');\n } catch (err) {\n return textResult(`Error: ${err}`, true);\n }\n });\n\n server.tool(\n 'project_suggest',\n 'Suggest a project based on context',\n {\n hint: z.string().optional().describe('Optional hint to narrow project suggestion'),\n },\n async ({ hint }) => {\n const unavailable = await ensureStorageAvailable();\n if (unavailable) return unavailable;\n try {\n const suggestion = await contextManager.suggestProject(hint);\n if (!suggestion) {\n return textResult('No projects found to suggest');\n }\n return textResult(JSON.stringify(suggestion, null, 2));\n } catch (err) {\n return textResult(`Error: ${err}`, true);\n }\n },\n );\n\n server.tool(\n 'project_get_context',\n 'Get the full context for a project',\n { project_name: z.string().describe('The project name') },\n async ({ project_name }) => {\n const unavailable = await ensureStorageAvailable();\n if (unavailable) return unavailable;\n try {\n const context = await contextManager.getProjectContext(project_name);\n await eventClient.emit('mcp_query_executed', { tool: 'project_get_context' });\n\n const parts: string[] = [];\n parts.push(`# Project: ${context.name}\\n`);\n\n for (const file of context.canonicalFiles) {\n parts.push(`## ${file.path}\\n${file.content}\\n`);\n }\n\n for (const file of context.derivedFiles) {\n if (file.path.endsWith('.json')) {\n parts.push(`## ${file.path}\\n\\`\\`\\`json\\n${file.content.slice(0, 2000)}\\n\\`\\`\\`\\n`);\n } else {\n parts.push(`## ${file.path}\\n${file.content}\\n`);\n }\n }\n\n return textResult(parts.join('\\n'));\n } catch (err) {\n return textResult(`Error: ${err}`, true);\n }\n },\n );\n\n server.tool(\n 'context_search',\n 'Search across all context files',\n { query: z.string().describe('Search query') },\n async ({ query }) => {\n const unavailable = await ensureStorageAvailable();\n if (unavailable) return unavailable;\n try {\n const results = await indexer.search(query);\n await eventClient.emit('mcp_query_executed', { tool: 'context_search' });\n\n if (results.length === 0) {\n return textResult('No results found');\n }\n\n const text = results\n .map(\n (result) =>\n `[${result.matchType}] ${result.filePath}${result.section ? ` > ${result.section}` : ''} (score: ${result.score})\\n${result.content}\\n`,\n )\n .join('\\n---\\n');\n\n return textResult(text);\n } catch (err) {\n return textResult(`Error: ${err}`, true);\n }\n },\n );\n\n server.tool(\n 'context_read_file',\n 'Read a specific context file',\n { file_path: z.string().describe('Path to the context file') },\n async ({ file_path }) => {\n const unavailable = await ensureStorageAvailable();\n if (unavailable) return unavailable;\n try {\n const content = await contextManager.readFile(file_path);\n return textResult(content);\n } catch (err) {\n return textResult(`Error reading file: ${err}`, true);\n }\n },\n );\n\n server.tool(\n 'context_read_section',\n 'Read a specific section from a context file',\n {\n file_path: z.string().describe('Path to the context file'),\n section_name: z.string().describe('Name of the section to read'),\n },\n async ({ file_path, section_name }) => {\n const unavailable = await ensureStorageAvailable();\n if (unavailable) return unavailable;\n try {\n const section = await contextManager.readSection(file_path, section_name);\n if (!section) {\n return textResult(`Section \"${section_name}\" not found in ${file_path}`);\n }\n return textResult(section);\n } catch (err) {\n return textResult(`Error: ${err}`, true);\n }\n },\n );\n\n server.tool(\n 'context_list_recent_updates',\n 'List recent context update proposals',\n { limit: z.number().optional().describe('Maximum number of updates to return') },\n async ({ limit }) => {\n const unavailable = await ensureStorageAvailable();\n if (unavailable) return unavailable;\n try {\n const updates = await contextManager.listRecentUpdates(limit ?? 10);\n if (updates.length === 0) {\n return textResult('No recent updates');\n }\n return textResult(JSON.stringify(updates, null, 2));\n } catch (err) {\n return textResult(`Error: ${err}`, true);\n }\n },\n );\n\n server.tool(\n 'context_get_daily_summary',\n 'Get the daily summary for a specific date',\n { date: z.string().optional().describe('Date in YYYY-MM-DD format (defaults to today)') },\n async ({ date }) => {\n const unavailable = await ensureStorageAvailable();\n if (unavailable) return unavailable;\n try {\n const summary = await contextManager.getDailySummary(date);\n if (!summary) {\n return textResult(`No daily summary found for ${date ?? 'today'}`);\n }\n return textResult(summary);\n } catch (err) {\n return textResult(`Error: ${err}`, true);\n }\n },\n );\n\n server.tool(\n 'context_propose_update',\n 'Propose an update to a context file',\n {\n target_file: z.string().describe('Path to the target file'),\n section: z.string().optional().describe('Section name to update (omit for full file)'),\n proposed_content: z.string().describe('The proposed new content'),\n reason: z.string().describe('Reason for the update'),\n },\n async ({ target_file, section, proposed_content, reason }) => {\n const unavailable = await ensureStorageAvailable();\n if (unavailable) return unavailable;\n try {\n const proposal = await contextManager.proposeUpdate({\n targetFile: target_file,\n section,\n proposedContent: proposed_content,\n reason,\n });\n await eventClient.emit('context_update_proposed');\n return textResult(\n `Update proposal created: ${proposal.id}\\nTarget: ${proposal.targetFile}\\nReason: ${proposal.reason}\\nStatus: ${proposal.status}`,\n );\n } catch (err) {\n return textResult(`Error: ${err}`, true);\n }\n },\n );\n\n server.tool(\n 'context_apply_update',\n 'Apply a pending update proposal',\n { proposal_id: z.string().describe('ID of the proposal to apply') },\n async ({ proposal_id }) => {\n const unavailable = await ensureStorageAvailable();\n if (unavailable) return unavailable;\n try {\n const applied = await contextManager.applyUpdate(proposal_id);\n await eventClient.emit('context_update_applied');\n return textResult(\n `Update applied: ${applied.id}\\nTarget: ${applied.targetFile}\\nApplied at: ${applied.appliedAt}`,\n );\n } catch (err) {\n return textResult(`Error: ${err}`, true);\n }\n },\n );\n\n server.tool(\n 'context_append_note',\n 'Append a note to a project context file',\n {\n project_name: z.string().describe('The project name'),\n note: z.string().describe('The note to append'),\n },\n async ({ project_name, note }) => {\n const unavailable = await ensureStorageAvailable();\n if (unavailable) return unavailable;\n try {\n await contextManager.appendNote(project_name, note);\n return textResult(`Note appended to project: ${project_name}`);\n } catch (err) {\n return textResult(`Error: ${err}`, true);\n }\n },\n );\n\n server.tool('context_rebuild_indexes', 'Rebuild all context indexes', {}, async () => {\n const unavailable = await ensureStorageAvailable();\n if (unavailable) return unavailable;\n try {\n await indexer.buildIndexes();\n return textResult('Indexes rebuilt successfully');\n } catch (err) {\n return textResult(`Error: ${err}`, true);\n }\n });\n\n server.tool(\n 'session_end',\n 'End the current session: force-apply all pending proposals, save session notes, rebuild indexes, and clear the active project',\n {\n project_name: z.string().optional().describe('The active project name'),\n session_notes: z.string().optional().describe('Summary of what was learned or decided during this session'),\n },\n async ({ project_name, session_notes }) => {\n const unavailable = await ensureStorageAvailable();\n if (unavailable) return unavailable;\n try {\n const results: string[] = [];\n\n const appliedIds = await contextManager.applyAllPending();\n if (appliedIds.length > 0) {\n results.push(`Applied ${appliedIds.length} pending proposal(s): ${appliedIds.join(', ')}`);\n } else {\n results.push('No pending proposals to apply.');\n }\n\n if (session_notes && project_name) {\n await contextManager.appendNote(project_name, session_notes);\n results.push(`Session notes saved to project: ${project_name}`);\n }\n\n await indexer.buildIndexes();\n results.push('Indexes rebuilt.');\n\n await configManager.setActiveProject('');\n results.push('Active project cleared.');\n\n const timestamp = new Date().toISOString();\n const logEntry = `[${timestamp}] Session ended for project \"${project_name ?? 'none'}\". Applied ${appliedIds.length} proposals.\\n`;\n await storage.append('logs/audit.log', logEntry);\n\n return textResult(`Session ended successfully.\\n\\n${results.join('\\n')}`);\n } catch (err) {\n return textResult(`Error ending session: ${err}`, true);\n }\n },\n );\n\n server.tool('sync_run_now', 'Trigger an immediate sync', {}, async () => {\n const unavailable = await ensureStorageAvailable();\n if (unavailable) return unavailable;\n try {\n await indexer.buildIndexes();\n return textResult('Sync completed. Indexes rebuilt.');\n } catch (err) {\n return textResult(`Error: ${err}`, true);\n }\n });\n\n server.tool('sync_status', 'Get the current sync status', {}, async () => {\n await storageReady;\n try {\n const config = getStatusConfig();\n const integrations = config.integrations\n .filter((integration) => integration.enabled)\n .map((integration) => {\n const health = getIntegrationHealth(integration.type);\n return {\n type: integration.type,\n lastSyncAt: integration.lastSyncAt ?? 'never',\n cursor: integration.cursor ?? 'none',\n connectionStatus: health?.status ?? 'healthy',\n connectionSummary: health?.summary ?? `No startup health check recorded for ${integration.type}`,\n connectionReason: health?.reason ?? null,\n fix: health?.fix ?? [],\n restart: health?.restart ?? DEFAULT_RESTART_STEPS,\n };\n });\n\n const status = {\n syncTime: config.sync.dailySyncTime,\n timezone: config.sync.timezone,\n storage: {\n mode: runtimeHealth.storage.mode,\n status: runtimeHealth.storage.status,\n summary: runtimeHealth.storage.summary,\n reason: runtimeHealth.storage.reason ?? null,\n fix: runtimeHealth.storage.fix,\n restart: runtimeHealth.storage.restart,\n },\n integrations,\n alerts: runtimeHealth.alerts,\n };\n\n return textResult(JSON.stringify(status, null, 2));\n } catch (err) {\n return textResult(`Error: ${err}`, true);\n }\n });\n\n server.tool('sync_list_integrations', 'List all configured integrations', {}, async () => {\n await storageReady;\n try {\n const config = getStatusConfig();\n const list = config.integrations.map((integration) => {\n const health = getIntegrationHealth(integration.type);\n const connection = health\n ? health.status === 'healthy'\n ? `healthy - ${health.summary}`\n : `error - ${health.reason ?? health.summary}`\n : 'not checked';\n return `${integration.type}: ${integration.enabled ? 'enabled' : 'disabled'} (connection: ${connection}; last sync: ${integration.lastSyncAt ?? 'never'})`;\n });\n\n return textResult(list.join('\\n') || 'No integrations configured');\n } catch (err) {\n return textResult(`Error: ${err}`, true);\n }\n });\n\n server.tool(\n 'events_ping',\n 'Emit a metadata-only event',\n {\n event_name: z.string().describe('Name of the event'),\n metadata: z.record(z.string()).optional().describe('Optional metadata key-value pairs'),\n },\n async ({ event_name, metadata }) => {\n await storageReady;\n try {\n await eventClient.emit(event_name as any, metadata);\n return textResult(`Event emitted: ${event_name}`);\n } catch (err) {\n return textResult(`Error: ${err}`, true);\n }\n },\n );\n\n const transport = new StdioServerTransport();\n await server.connect(transport);\n\n await resolveStorageBackend();\n storageReadyResolve?.();\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAAA,YAAY,QAAQ;AACpB,YAAY,QAAQ;AACpB,YAAY,UAAU;AACtB,SAAS,gBAAgB;AACzB,SAAS,iBAAiB;AAE1B,IAAM,gBAAgB,UAAU,QAAQ;AAEjC,IAAM,kBAAkB;AACxB,IAAM,0BAA0B,CAAC,oBAAoB;AACrD,IAAM,oBAAyB,UAAQ,WAAQ,GAAG,qBAAqB;AAqB9E,eAAe,WAAW,SAAiB,MAAwC;AACjF,QAAM,SAAS,MAAM,cAAc,SAAS,IAAI;AAChD,SAAO;AAAA,IACL,QAAQ,OAAO,UAAU;AAAA,IACzB,QAAQ,OAAO,UAAU;AAAA,EAC3B;AACF;AAEA,eAAsB,qBAAqB,QAAkC;AAC3E,MAAI,QAAQ;AACV,WAAY,aAAQ,MAAM;AAAA,EAC5B;AAEA,QAAM,SAAc,UAAQ,WAAQ,GAAG,6BAA6B;AACpE,MAAI;AACF,UAAM,KAAK,KAAK,MAAM,MAAS,YAAS,QAAQ,OAAO,CAAC;AACxD,QAAI,GAAG,eAAe;AACpB,aAAO,GAAG;AAAA,IACZ;AAAA,EACF,QAAQ;AAAA,EAER;AAEA,SAAO;AACT;AAEA,eAAsB,6BAAqD;AACzE,QAAM,aAAkB,aAAQ,QAAQ,KAAK,CAAC,CAAC;AAC/C,SAAO,EAAE,SAAS,QAAQ,UAAU,MAAM,CAAC,YAAY,OAAO,OAAO,EAAE;AACzE;AAEA,eAAsB,6BAAqD;AACzE,QAAM,aAAkB,aAAQ,QAAQ,KAAK,CAAC,CAAC;AAC/C,SAAO,EAAE,SAAS,QAAQ,UAAU,MAAM,CAAC,UAAU,EAAE;AACzD;AAEA,eAAsB,iBACpB,eACA,iBAA+C,4BAC/C,SAAwB,YACT;AACf,QAAM,gBAAgB,MAAM,eAAe;AAC3C,QAAM,kBAAkB,iCAAiC,eAAe,aAAa;AAErF,MAAI;AACF,eAAW,cAAc,CAAC,iBAAiB,GAAG,uBAAuB,GAAG;AACtE,UAAI;AACF,cAAM,OAAO,UAAU,CAAC,OAAO,UAAU,MAAM,QAAQ,UAAU,CAAC;AAAA,MACpE,SAAS,KAAK;AACZ,cAAM,OAAO,OAAO,QAAQ,YAAY,QAAQ,QAAQ,UAAU,MAC9D,OAAQ,IAA2B,IAAI,IACvC;AACJ,YAAI,SAAS,UAAU;AACrB,gBAAM;AAAA,QACR;AAAA,MACF;AAAA,IACF;AAEA,UAAM,OAAO,UAAU;AAAA,MACrB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,sBAAsB,aAAa;AAAA,MACnC;AAAA,MACA;AAAA,MACA,cAAc;AAAA,MACd,GAAG,cAAc;AAAA,IACnB,CAAC;AAAA,EACH,SAAS,KAAK;AACZ,UAAM,4BAA4B,KAAK,eAAe;AAAA,EACxD;AACF;AAEO,SAAS,iCACd,eACA,eACQ;AACR,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,SAAS,WAAW,gBAAgB,aAAa,EAAE,CAAC;AAAA,IACpD;AAAA,IACA;AAAA,IACA,WAAW,cAAc,OAAO;AAAA,IAChC,GAAG,cAAc,KAAK,IAAI,UAAU;AAAA,EACtC,EAAE,KAAK,GAAG;AACZ;AAEO,SAAS,gCACd,eACA,eACQ;AACR,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,WAAW,gBAAgB,aAAa,EAAE;AAAA,IAC1C;AAAA,IACA,WAAW,cAAc,OAAO;AAAA,IAChC,GAAG,cAAc,KAAK,IAAI,UAAU;AAAA,EACtC,EAAE,KAAK,GAAG;AACZ;AAEO,SAAS,qBAAqB,QAAkC;AACrE,QAAM,UAAU,OAAO,KAAK;AAC5B,MAAI,QAAQ,WAAW,GAAG;AACxB,WAAO,CAAC;AAAA,EACV;AAEA,QAAM,YAAY,QAAQ,QAAQ,GAAG;AACrC,QAAM,OAAO,aAAa,IAAI,QAAQ,MAAM,SAAS,IAAI;AACzD,SAAO,KAAK,MAAM,IAAI;AACxB;AAEA,eAAsB,gBACpB,eACA,iBAA+C,4BAC/C,SAAwB,YACT;AACf,QAAM,gBAAgB,MAAM,eAAe;AAC3C,QAAM,kBAAkB,gCAAgC,eAAe,aAAa;AAEpF,MAAI;AACF,UAAM,EAAE,OAAO,IAAI,MAAM,OAAO,SAAS,CAAC,OAAO,QAAQ,QAAQ,CAAC;AAClE,UAAM,UAAU,qBAAqB,MAAM;AAE3C,eAAW,cAAc,CAAC,iBAAiB,GAAG,uBAAuB,GAAG;AACtE,UAAI,QAAQ,KAAK,CAAC,WAAW,OAAO,SAAS,UAAU,GAAG;AACxD,cAAM,OAAO,SAAS,CAAC,OAAO,UAAU,UAAU,CAAC;AAAA,MACrD;AAAA,IACF;AAEA,UAAM,OAAO,SAAS;AAAA,MACpB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,gBAAgB,aAAa;AAAA,MAC7B;AAAA,MACA,cAAc;AAAA,MACd,GAAG,cAAc;AAAA,IACnB,CAAC;AAAA,EACH,SAAS,KAAK;AACZ,UAAM,2BAA2B,KAAK,eAAe;AAAA,EACvD;AACF;AAEA,SAAS,WAAW,OAAuB;AACzC,MAAI,wBAAwB,KAAK,KAAK,GAAG;AACvC,WAAO;AAAA,EACT;AACA,SAAO,IAAI,MAAM,QAAQ,MAAM,OAAO,CAAC;AACzC;AAEA,SAAS,2BAA2B,KAAc,iBAAgC;AAChF,QAAM,OAAO,OAAO,QAAQ,YAAY,QAAQ,QAAQ,UAAU,MAC9D,OAAQ,IAA2B,IAAI,IACvC;AACJ,QAAM,SAAS,OAAO,QAAQ,YAAY,QAAQ,QAAQ,YAAY,MAClE,OAAQ,IAA6B,UAAU,EAAE,IACjD;AACJ,QAAM,UAAU,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAE/D,MAAI,SAAS,UAAU;AACrB,WAAO,IAAI;AAAA,MACT,2IAA2I,eAAe;AAAA,IAC5J;AAAA,EACF;AAEA,QAAM,UAAU,OAAO,KAAK,KAAK;AACjC,SAAO,IAAI;AAAA,IACT,yDAAyD,OAAO,uBAAuB,eAAe;AAAA,EACxG;AACF;AAEA,SAAS,4BAA4B,KAAc,iBAAgC;AACjF,QAAM,OAAO,OAAO,QAAQ,YAAY,QAAQ,QAAQ,UAAU,MAC9D,OAAQ,IAA2B,IAAI,IACvC;AACJ,QAAM,SAAS,OAAO,QAAQ,YAAY,QAAQ,QAAQ,YAAY,MAClE,OAAQ,IAA6B,UAAU,EAAE,IACjD;AACJ,QAAM,UAAU,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAE/D,MAAI,SAAS,UAAU;AACrB,WAAO,IAAI;AAAA,MACT,8JAA8J,eAAe;AAAA,IAC/K;AAAA,EACF;AAEA,QAAM,UAAU,OAAO,KAAK,KAAK;AACjC,SAAO,IAAI;AAAA,IACT,+DAA+D,OAAO,uBAAuB,eAAe;AAAA,EAC9G;AACF;;;ACvOA,YAAYA,SAAQ;AACpB,YAAYC,WAAU;AACtB,SAAS,iBAAiB;AAC1B,SAAS,4BAA4B;AACrC,SAAS,SAAS;AAgDlB,IAAM,wBAAwB;AAAA,EAC5B;AAAA,EACA;AACF;AAEA,eAAsB,eAAe,eAAsC;AACzE,QAAM,aAAa,mBAAmB,aAAa;AACnD,MAAI,UAA0B;AAC9B,MAAI,gBAAgB,oBAAoB,UAAU;AAClD,MAAI,iBAAiB,qBAAqB,UAAU;AACpD,MAAI,UAAU,cAAc,UAAU;AACtC,QAAM,cAAc,sBAAsB;AAE1C,MAAI,kBAAoC;AACxC,MAAI;AACJ,QAAM,eAAe,IAAI,QAAc,CAACC,aAAY;AAClD,0BAAsBA;AAAA,EACxB,CAAC;AAED,QAAM,gBAIF;AAAA,IACF,SAAS;AAAA,MACP,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,SAAS,4BAA4B,aAAa;AAAA,MAClD,KAAK,CAAC;AAAA,MACN,SAAS;AAAA,IACX;AAAA,IACA,cAAc,CAAC;AAAA,IACf,QAAQ,CAAC;AAAA,EACX;AAEA,QAAM,SAAS,IAAI,UAAU;AAAA,IAC3B,MAAM;AAAA,IACN,SAAS;AAAA,EACX,CAAC;AAED,WAAS,WAAW,MAAc,UAAU,OAAmB;AAC7D,WAAO;AAAA,MACL,SAAS,CAAC,EAAE,MAAM,QAAQ,KAAK,CAAC;AAAA,MAChC,GAAI,UAAU,EAAE,SAAS,KAAK,IAAI,CAAC;AAAA,IACrC;AAAA,EACF;AAEA,WAAS,kBAA6B;AACpC,WAAO,mBAAmB;AAAA,MACxB,MAAM,EAAE,MAAM,IAAI,eAAe,UAAU,aAAa,qBAAqB,kBAAkB,CAAC,EAAE;AAAA,MAClG,SAAS,EAAE,MAAM,SAAS,cAAc;AAAA,MACxC,cAAc,CAAC;AAAA,MACf,MAAM;AAAA,QACJ,eAAe;AAAA,QACf,UAAU;AAAA,QACV,mBAAmB;AAAA,QACnB,oBAAoB;AAAA,MACtB;AAAA,IACF;AAAA,EACF;AAEA,WAAS,SAAS,OAA2B;AAC3C,kBAAc,OAAO,KAAK,KAAK;AAAA,EACjC;AAEA,WAAS,kBACP,MACA,QACA,KACM;AACN,kBAAc,UAAU;AAAA,MACtB,QAAQ;AAAA,MACR;AAAA,MACA,SAAS,iBAAiB,IAAI;AAAA,MAC9B;AAAA,MACA;AAAA,MACA,SAAS;AAAA,IACX;AACA,aAAS;AAAA,MACP,WAAW;AAAA,MACX,MAAM;AAAA,MACN;AAAA,MACA;AAAA,MACA,SAAS;AAAA,IACX,CAAC;AAAA,EACH;AAEA,WAAS,YAAY,OAAe,OAAyB;AAC3D,QAAI,MAAM,WAAW,EAAG,QAAO;AAC/B,WAAO,GAAG,KAAK;AAAA,EAAM,MAAM,IAAI,CAAC,MAAM,UAAU,GAAG,QAAQ,CAAC,KAAK,IAAI,EAAE,EAAE,KAAK,IAAI,CAAC;AAAA,EACrF;AAEA,WAAS,4BAAoC;AAC3C,UAAM,WAAW;AAAA,MACf,uCAAuC,cAAc,QAAQ,UAAU,cAAc,QAAQ,OAAO;AAAA,MACpG,YAAY,OAAO,cAAc,QAAQ,GAAG;AAAA,MAC5C,YAAY,WAAW,cAAc,QAAQ,OAAO;AAAA,IACtD,EAAE,OAAO,OAAO;AAEhB,WAAO,SAAS,KAAK,MAAM;AAAA,EAC7B;AAEA,WAAS,mBAAyB;AAChC,QAAI,cAAc,OAAO,WAAW,GAAG;AACrC,cAAQ,MAAM,+BAA+B,cAAc,QAAQ,IAAI,EAAE;AACzE;AAAA,IACF;AAEA,YAAQ,MAAM,6BAA6B;AAC3C,eAAW,SAAS,cAAc,QAAQ;AACxC,cAAQ,MAAM,KAAK,MAAM,SAAS,IAAI,MAAM,IAAI,KAAK,MAAM,MAAM,EAAE;AACnE,iBAAW,QAAQ,MAAM,KAAK;AAC5B,gBAAQ,MAAM,UAAU,IAAI,EAAE;AAAA,MAChC;AACA,iBAAW,QAAQ,MAAM,SAAS;AAChC,gBAAQ,MAAM,cAAc,IAAI,EAAE;AAAA,MACpC;AAAA,IACF;AAAA,EACF;AAEA,WAAS,mBAAmB,MAA0B,QAAwC;AAC5F,QAAI,SAAS,UAAU;AACrB,aAAO;AAAA,QACL;AAAA,QACA;AAAA,QACA,GAAI,QAAQ,YAAY,CAAC,uDAAuD,OAAO,SAAS,EAAE,IAAI,CAAC;AAAA,MACzG;AAAA,IACF;AAEA,WAAO;AAAA,MACL,uEAAuE,aAAa;AAAA,MACpF;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAEA,WAAS,qBAAqB,MAAgE;AAC5F,WAAO,cAAc,aAAa,KAAK,CAAC,gBAAgB,YAAY,SAAS,IAAI;AAAA,EACnF;AAEA,iBAAe,yBAAqD;AAClE,UAAM;AACN,QAAI,cAAc,QAAQ,WAAW,SAAS;AAC5C,aAAO,WAAW,0BAA0B,GAAG,IAAI;AAAA,IACrD;AACA,WAAO;AAAA,EACT;AAEA,iBAAe,wBAAuC;AACpD,sBAAkB,MAAM,cAAc,WAAW;AACjD,kBAAc,QAAQ,OAAO,gBAAgB,QAAQ;AAErD,QAAI,gBAAgB,QAAQ,SAAS,UAAU;AAC7C,YAAM,eAAe,gBAAgB;AACrC,YAAM,oBAAyB,iBAAW,aAAa,SAAS,IAC5D,aAAa,YACR,cAAa,cAAQ,aAAa,GAAG,aAAa,SAAS;AAEpE,UAAI;AACF,cAAM,gBAAgB,oBAAoB;AAAA,UACxC,GAAG;AAAA,UACH,WAAW;AAAA,QACb,CAAC;AACD,cAAM,cAAc,WAAW;AAE/B,kBAAU;AACV,wBAAgB,oBAAoB,aAAa;AACjD,yBAAiB,qBAAqB,aAAa;AACnD,kBAAU,cAAc,aAAa;AACrC,0BAAkB,MAAM,cAAc,WAAW;AAEjD,sBAAc,UAAU;AAAA,UACtB,QAAQ;AAAA,UACR,MAAM;AAAA,UACN,SAAS,oCAAoC,aAAa,aAAa,KAAK,aAAa,UAAU,MAAM,EAAE;AAAA,UAC3G,KAAK,CAAC;AAAA,UACN,SAAS;AAAA,QACX;AAAA,MACF,SAAS,KAAK;AACZ;AAAA,UACE;AAAA,UACA,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAAA,UAC/C,mBAAmB,UAAU;AAAA,YAC3B,GAAG;AAAA,YACH,WAAW;AAAA,UACb,CAAC;AAAA,QACH;AAAA,MACF;AAAA,IACF,OAAO;AACL,UAAI;AACF,cAAS,UAAM,eAAe,EAAE,WAAW,KAAK,CAAC;AACjD,sBAAc,UAAU;AAAA,UACtB,QAAQ;AAAA,UACR,MAAM;AAAA,UACN,SAAS,4BAA4B,aAAa;AAAA,UAClD,KAAK,CAAC;AAAA,UACN,SAAS;AAAA,QACX;AAAA,MACF,SAAS,KAAK;AACZ;AAAA,UACE;AAAA,UACA,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAAA,UAC/C,mBAAmB,OAAO;AAAA,QAC5B;AAAA,MACF;AAAA,IACF;AAEA,UAAM,wBAAwB,gBAAgB;AAC9C,kBAAc,eAAe,CAAC;AAC9B,eAAW,eAAe,sBAAsB,aAAa,OAAO,CAAC,SAAS,KAAK,OAAO,GAAG;AAC3F,YAAM,SAAS,MAAM,0BAA0B,WAAW;AAE1D,UAAI,OAAO,IAAI;AACb,sBAAc,aAAa,KAAK;AAAA,UAC9B,MAAM,YAAY;AAAA,UAClB,QAAQ;AAAA,UACR,SAAS,OAAO,WAAW,gBAAgB,YAAY,IAAI;AAAA,UAC3D,KAAK,CAAC;AAAA,UACN,SAAS;AAAA,QACX,CAAC;AACD;AAAA,MACF;AAEA,oBAAc,aAAa,KAAK;AAAA,QAC9B,MAAM,YAAY;AAAA,QAClB,QAAQ;AAAA,QACR,SAAS,wBAAwB,YAAY,IAAI;AAAA,QACjD,QAAQ,OAAO,UAAU,wBAAwB,YAAY,IAAI;AAAA,QACjE,KAAK,OAAO,OAAO,CAAC;AAAA,QACpB,SAAS;AAAA,MACX,CAAC;AACD,eAAS;AAAA,QACP,WAAW;AAAA,QACX,MAAM,YAAY;AAAA,QAClB,QAAQ,OAAO,UAAU,wBAAwB,YAAY,IAAI;AAAA,QACjE,KAAK,OAAO,OAAO,CAAC;AAAA,QACpB,SAAS;AAAA,MACX,CAAC;AAAA,IACH;AAEA,qBAAiB;AAAA,EACnB;AAEA,SAAO,KAAK,cAAc,0CAA0C,CAAC,GAAG,YAAY;AAClF,UAAM,cAAc,MAAM,uBAAuB;AACjD,QAAI,YAAa,QAAO;AACxB,QAAI;AACF,YAAM,SAAS,MAAM,cAAc,WAAW;AAC9C,aAAO,WAAW,KAAK,UAAU,QAAQ,MAAM,CAAC,CAAC;AAAA,IACnD,SAAS,KAAK;AACZ,aAAO,WAAW,yBAAyB,GAAG,IAAI,IAAI;AAAA,IACxD;AAAA,EACF,CAAC;AAED,SAAO,KAAK,2BAA2B,kDAAkD,CAAC,GAAG,YAAY;AACvG,UAAM,cAAc,MAAM,uBAAuB;AACjD,QAAI,YAAa,QAAO;AACxB,QAAI;AACF,YAAM,OAAO,MAAM,cAAc,eAAe;AAChD,aAAO,WAAW,IAAI;AAAA,IACxB,SAAS,KAAK;AACZ,aAAO,WAAW,UAAU,GAAG,IAAI,IAAI;AAAA,IACzC;AAAA,EACF,CAAC;AAED,SAAO,KAAK,6BAA6B,yCAAyC,CAAC,GAAG,YAAY;AAChG,UAAM,cAAc,MAAM,uBAAuB;AACjD,QAAI,YAAa,QAAO;AACxB,QAAI;AACF,YAAM,UAAU,MAAM,cAAc,iBAAiB;AACrD,aAAO,WAAW,WAAW,uBAAuB;AAAA,IACtD,SAAS,KAAK;AACZ,aAAO,WAAW,UAAU,GAAG,IAAI,IAAI;AAAA,IACzC;AAAA,EACF,CAAC;AAED,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,EAAE,cAAc,EAAE,OAAO,EAAE,SAAS,mCAAmC,EAAE;AAAA,IACzE,OAAO,EAAE,aAAa,MAAM;AAC1B,YAAM,cAAc,MAAM,uBAAuB;AACjD,UAAI,YAAa,QAAO;AACxB,UAAI;AACF,cAAM,cAAc,iBAAiB,YAAY;AACjD,cAAM,YAAY,gBAAgB,oBAAoB,YAAY;AAClE,eAAO,WAAW,0BAA0B,YAAY,EAAE;AAAA,MAC5D,SAAS,KAAK;AACZ,eAAO,WAAW,UAAU,GAAG,IAAI,IAAI;AAAA,MACzC;AAAA,IACF;AAAA,EACF;AAEA,SAAO,KAAK,gBAAgB,2BAA2B,CAAC,GAAG,YAAY;AACrE,UAAM,cAAc,MAAM,uBAAuB;AACjD,QAAI,YAAa,QAAO;AACxB,QAAI;AACF,YAAM,WAAW,MAAM,eAAe,aAAa;AACnD,aAAO,WAAW,SAAS,SAAS,IAAI,SAAS,KAAK,IAAI,IAAI,mBAAmB;AAAA,IACnF,SAAS,KAAK;AACZ,aAAO,WAAW,UAAU,GAAG,IAAI,IAAI;AAAA,IACzC;AAAA,EACF,CAAC;AAED,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,MACE,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,4CAA4C;AAAA,IACnF;AAAA,IACA,OAAO,EAAE,KAAK,MAAM;AAClB,YAAM,cAAc,MAAM,uBAAuB;AACjD,UAAI,YAAa,QAAO;AACxB,UAAI;AACF,cAAM,aAAa,MAAM,eAAe,eAAe,IAAI;AAC3D,YAAI,CAAC,YAAY;AACf,iBAAO,WAAW,8BAA8B;AAAA,QAClD;AACA,eAAO,WAAW,KAAK,UAAU,YAAY,MAAM,CAAC,CAAC;AAAA,MACvD,SAAS,KAAK;AACZ,eAAO,WAAW,UAAU,GAAG,IAAI,IAAI;AAAA,MACzC;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,EAAE,cAAc,EAAE,OAAO,EAAE,SAAS,kBAAkB,EAAE;AAAA,IACxD,OAAO,EAAE,aAAa,MAAM;AAC1B,YAAM,cAAc,MAAM,uBAAuB;AACjD,UAAI,YAAa,QAAO;AACxB,UAAI;AACF,cAAM,UAAU,MAAM,eAAe,kBAAkB,YAAY;AACnE,cAAM,YAAY,KAAK,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAE5E,cAAM,QAAkB,CAAC;AACzB,cAAM,KAAK,cAAc,QAAQ,IAAI;AAAA,CAAI;AAEzC,mBAAW,QAAQ,QAAQ,gBAAgB;AACzC,gBAAM,KAAK,MAAM,KAAK,IAAI;AAAA,EAAK,KAAK,OAAO;AAAA,CAAI;AAAA,QACjD;AAEA,mBAAW,QAAQ,QAAQ,cAAc;AACvC,cAAI,KAAK,KAAK,SAAS,OAAO,GAAG;AAC/B,kBAAM,KAAK,MAAM,KAAK,IAAI;AAAA;AAAA,EAAiB,KAAK,QAAQ,MAAM,GAAG,GAAI,CAAC;AAAA;AAAA,CAAY;AAAA,UACpF,OAAO;AACL,kBAAM,KAAK,MAAM,KAAK,IAAI;AAAA,EAAK,KAAK,OAAO;AAAA,CAAI;AAAA,UACjD;AAAA,QACF;AAEA,eAAO,WAAW,MAAM,KAAK,IAAI,CAAC;AAAA,MACpC,SAAS,KAAK;AACZ,eAAO,WAAW,UAAU,GAAG,IAAI,IAAI;AAAA,MACzC;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,cAAc,EAAE;AAAA,IAC7C,OAAO,EAAE,MAAM,MAAM;AACnB,YAAM,cAAc,MAAM,uBAAuB;AACjD,UAAI,YAAa,QAAO;AACxB,UAAI;AACF,cAAM,UAAU,MAAM,QAAQ,OAAO,KAAK;AAC1C,cAAM,YAAY,KAAK,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AAEvE,YAAI,QAAQ,WAAW,GAAG;AACxB,iBAAO,WAAW,kBAAkB;AAAA,QACtC;AAEA,cAAM,OAAO,QACV;AAAA,UACC,CAAC,WACC,IAAI,OAAO,SAAS,KAAK,OAAO,QAAQ,GAAG,OAAO,UAAU,MAAM,OAAO,OAAO,KAAK,EAAE,YAAY,OAAO,KAAK;AAAA,EAAM,OAAO,OAAO;AAAA;AAAA,QACvI,EACC,KAAK,SAAS;AAEjB,eAAO,WAAW,IAAI;AAAA,MACxB,SAAS,KAAK;AACZ,eAAO,WAAW,UAAU,GAAG,IAAI,IAAI;AAAA,MACzC;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,EAAE,WAAW,EAAE,OAAO,EAAE,SAAS,0BAA0B,EAAE;AAAA,IAC7D,OAAO,EAAE,UAAU,MAAM;AACvB,YAAM,cAAc,MAAM,uBAAuB;AACjD,UAAI,YAAa,QAAO;AACxB,UAAI;AACF,cAAM,UAAU,MAAM,eAAe,SAAS,SAAS;AACvD,eAAO,WAAW,OAAO;AAAA,MAC3B,SAAS,KAAK;AACZ,eAAO,WAAW,uBAAuB,GAAG,IAAI,IAAI;AAAA,MACtD;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,MACE,WAAW,EAAE,OAAO,EAAE,SAAS,0BAA0B;AAAA,MACzD,cAAc,EAAE,OAAO,EAAE,SAAS,6BAA6B;AAAA,IACjE;AAAA,IACA,OAAO,EAAE,WAAW,aAAa,MAAM;AACrC,YAAM,cAAc,MAAM,uBAAuB;AACjD,UAAI,YAAa,QAAO;AACxB,UAAI;AACF,cAAM,UAAU,MAAM,eAAe,YAAY,WAAW,YAAY;AACxE,YAAI,CAAC,SAAS;AACZ,iBAAO,WAAW,YAAY,YAAY,kBAAkB,SAAS,EAAE;AAAA,QACzE;AACA,eAAO,WAAW,OAAO;AAAA,MAC3B,SAAS,KAAK;AACZ,eAAO,WAAW,UAAU,GAAG,IAAI,IAAI;AAAA,MACzC;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,qCAAqC,EAAE;AAAA,IAC/E,OAAO,EAAE,MAAM,MAAM;AACnB,YAAM,cAAc,MAAM,uBAAuB;AACjD,UAAI,YAAa,QAAO;AACxB,UAAI;AACF,cAAM,UAAU,MAAM,eAAe,kBAAkB,SAAS,EAAE;AAClE,YAAI,QAAQ,WAAW,GAAG;AACxB,iBAAO,WAAW,mBAAmB;AAAA,QACvC;AACA,eAAO,WAAW,KAAK,UAAU,SAAS,MAAM,CAAC,CAAC;AAAA,MACpD,SAAS,KAAK;AACZ,eAAO,WAAW,UAAU,GAAG,IAAI,IAAI;AAAA,MACzC;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,+CAA+C,EAAE;AAAA,IACxF,OAAO,EAAE,KAAK,MAAM;AAClB,YAAM,cAAc,MAAM,uBAAuB;AACjD,UAAI,YAAa,QAAO;AACxB,UAAI;AACF,cAAM,UAAU,MAAM,eAAe,gBAAgB,IAAI;AACzD,YAAI,CAAC,SAAS;AACZ,iBAAO,WAAW,8BAA8B,QAAQ,OAAO,EAAE;AAAA,QACnE;AACA,eAAO,WAAW,OAAO;AAAA,MAC3B,SAAS,KAAK;AACZ,eAAO,WAAW,UAAU,GAAG,IAAI,IAAI;AAAA,MACzC;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,MACE,aAAa,EAAE,OAAO,EAAE,SAAS,yBAAyB;AAAA,MAC1D,SAAS,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,6CAA6C;AAAA,MACrF,kBAAkB,EAAE,OAAO,EAAE,SAAS,0BAA0B;AAAA,MAChE,QAAQ,EAAE,OAAO,EAAE,SAAS,uBAAuB;AAAA,IACrD;AAAA,IACA,OAAO,EAAE,aAAa,SAAS,kBAAkB,OAAO,MAAM;AAC5D,YAAM,cAAc,MAAM,uBAAuB;AACjD,UAAI,YAAa,QAAO;AACxB,UAAI;AACF,cAAM,WAAW,MAAM,eAAe,cAAc;AAAA,UAClD,YAAY;AAAA,UACZ;AAAA,UACA,iBAAiB;AAAA,UACjB;AAAA,QACF,CAAC;AACD,cAAM,YAAY,KAAK,yBAAyB;AAChD,eAAO;AAAA,UACL,4BAA4B,SAAS,EAAE;AAAA,UAAa,SAAS,UAAU;AAAA,UAAa,SAAS,MAAM;AAAA,UAAa,SAAS,MAAM;AAAA,QACjI;AAAA,MACF,SAAS,KAAK;AACZ,eAAO,WAAW,UAAU,GAAG,IAAI,IAAI;AAAA,MACzC;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,EAAE,aAAa,EAAE,OAAO,EAAE,SAAS,6BAA6B,EAAE;AAAA,IAClE,OAAO,EAAE,YAAY,MAAM;AACzB,YAAM,cAAc,MAAM,uBAAuB;AACjD,UAAI,YAAa,QAAO;AACxB,UAAI;AACF,cAAM,UAAU,MAAM,eAAe,YAAY,WAAW;AAC5D,cAAM,YAAY,KAAK,wBAAwB;AAC/C,eAAO;AAAA,UACL,mBAAmB,QAAQ,EAAE;AAAA,UAAa,QAAQ,UAAU;AAAA,cAAiB,QAAQ,SAAS;AAAA,QAChG;AAAA,MACF,SAAS,KAAK;AACZ,eAAO,WAAW,UAAU,GAAG,IAAI,IAAI;AAAA,MACzC;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,MACE,cAAc,EAAE,OAAO,EAAE,SAAS,kBAAkB;AAAA,MACpD,MAAM,EAAE,OAAO,EAAE,SAAS,oBAAoB;AAAA,IAChD;AAAA,IACA,OAAO,EAAE,cAAc,KAAK,MAAM;AAChC,YAAM,cAAc,MAAM,uBAAuB;AACjD,UAAI,YAAa,QAAO;AACxB,UAAI;AACF,cAAM,eAAe,WAAW,cAAc,IAAI;AAClD,eAAO,WAAW,6BAA6B,YAAY,EAAE;AAAA,MAC/D,SAAS,KAAK;AACZ,eAAO,WAAW,UAAU,GAAG,IAAI,IAAI;AAAA,MACzC;AAAA,IACF;AAAA,EACF;AAEA,SAAO,KAAK,2BAA2B,+BAA+B,CAAC,GAAG,YAAY;AACpF,UAAM,cAAc,MAAM,uBAAuB;AACjD,QAAI,YAAa,QAAO;AACxB,QAAI;AACF,YAAM,QAAQ,aAAa;AAC3B,aAAO,WAAW,8BAA8B;AAAA,IAClD,SAAS,KAAK;AACZ,aAAO,WAAW,UAAU,GAAG,IAAI,IAAI;AAAA,IACzC;AAAA,EACF,CAAC;AAED,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,MACE,cAAc,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,yBAAyB;AAAA,MACtE,eAAe,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,4DAA4D;AAAA,IAC5G;AAAA,IACA,OAAO,EAAE,cAAc,cAAc,MAAM;AACzC,YAAM,cAAc,MAAM,uBAAuB;AACjD,UAAI,YAAa,QAAO;AACxB,UAAI;AACF,cAAM,UAAoB,CAAC;AAE3B,cAAM,aAAa,MAAM,eAAe,gBAAgB;AACxD,YAAI,WAAW,SAAS,GAAG;AACzB,kBAAQ,KAAK,WAAW,WAAW,MAAM,yBAAyB,WAAW,KAAK,IAAI,CAAC,EAAE;AAAA,QAC3F,OAAO;AACL,kBAAQ,KAAK,gCAAgC;AAAA,QAC/C;AAEA,YAAI,iBAAiB,cAAc;AACjC,gBAAM,eAAe,WAAW,cAAc,aAAa;AAC3D,kBAAQ,KAAK,mCAAmC,YAAY,EAAE;AAAA,QAChE;AAEA,cAAM,QAAQ,aAAa;AAC3B,gBAAQ,KAAK,kBAAkB;AAE/B,cAAM,cAAc,iBAAiB,EAAE;AACvC,gBAAQ,KAAK,yBAAyB;AAEtC,cAAM,aAAY,oBAAI,KAAK,GAAE,YAAY;AACzC,cAAM,WAAW,IAAI,SAAS,gCAAgC,gBAAgB,MAAM,cAAc,WAAW,MAAM;AAAA;AACnH,cAAM,QAAQ,OAAO,kBAAkB,QAAQ;AAE/C,eAAO,WAAW;AAAA;AAAA,EAAkC,QAAQ,KAAK,IAAI,CAAC,EAAE;AAAA,MAC1E,SAAS,KAAK;AACZ,eAAO,WAAW,yBAAyB,GAAG,IAAI,IAAI;AAAA,MACxD;AAAA,IACF;AAAA,EACF;AAEA,SAAO,KAAK,gBAAgB,6BAA6B,CAAC,GAAG,YAAY;AACvE,UAAM,cAAc,MAAM,uBAAuB;AACjD,QAAI,YAAa,QAAO;AACxB,QAAI;AACF,YAAM,QAAQ,aAAa;AAC3B,aAAO,WAAW,kCAAkC;AAAA,IACtD,SAAS,KAAK;AACZ,aAAO,WAAW,UAAU,GAAG,IAAI,IAAI;AAAA,IACzC;AAAA,EACF,CAAC;AAED,SAAO,KAAK,eAAe,+BAA+B,CAAC,GAAG,YAAY;AACxE,UAAM;AACN,QAAI;AACF,YAAM,SAAS,gBAAgB;AAC/B,YAAM,eAAe,OAAO,aACzB,OAAO,CAAC,gBAAgB,YAAY,OAAO,EAC3C,IAAI,CAAC,gBAAgB;AACpB,cAAM,SAAS,qBAAqB,YAAY,IAAI;AACpD,eAAO;AAAA,UACL,MAAM,YAAY;AAAA,UAClB,YAAY,YAAY,cAAc;AAAA,UACtC,QAAQ,YAAY,UAAU;AAAA,UAC9B,kBAAkB,QAAQ,UAAU;AAAA,UACpC,mBAAmB,QAAQ,WAAW,wCAAwC,YAAY,IAAI;AAAA,UAC9F,kBAAkB,QAAQ,UAAU;AAAA,UACpC,KAAK,QAAQ,OAAO,CAAC;AAAA,UACrB,SAAS,QAAQ,WAAW;AAAA,QAC9B;AAAA,MACF,CAAC;AAEH,YAAM,SAAS;AAAA,QACb,UAAU,OAAO,KAAK;AAAA,QACtB,UAAU,OAAO,KAAK;AAAA,QACtB,SAAS;AAAA,UACP,MAAM,cAAc,QAAQ;AAAA,UAC5B,QAAQ,cAAc,QAAQ;AAAA,UAC9B,SAAS,cAAc,QAAQ;AAAA,UAC/B,QAAQ,cAAc,QAAQ,UAAU;AAAA,UACxC,KAAK,cAAc,QAAQ;AAAA,UAC3B,SAAS,cAAc,QAAQ;AAAA,QACjC;AAAA,QACA;AAAA,QACA,QAAQ,cAAc;AAAA,MACxB;AAEA,aAAO,WAAW,KAAK,UAAU,QAAQ,MAAM,CAAC,CAAC;AAAA,IACnD,SAAS,KAAK;AACZ,aAAO,WAAW,UAAU,GAAG,IAAI,IAAI;AAAA,IACzC;AAAA,EACF,CAAC;AAED,SAAO,KAAK,0BAA0B,oCAAoC,CAAC,GAAG,YAAY;AACxF,UAAM;AACN,QAAI;AACF,YAAM,SAAS,gBAAgB;AAC/B,YAAM,OAAO,OAAO,aAAa,IAAI,CAAC,gBAAgB;AACpD,cAAM,SAAS,qBAAqB,YAAY,IAAI;AACpD,cAAM,aAAa,SACf,OAAO,WAAW,YAChB,aAAa,OAAO,OAAO,KAC3B,WAAW,OAAO,UAAU,OAAO,OAAO,KAC5C;AACJ,eAAO,GAAG,YAAY,IAAI,KAAK,YAAY,UAAU,YAAY,UAAU,iBAAiB,UAAU,gBAAgB,YAAY,cAAc,OAAO;AAAA,MACzJ,CAAC;AAED,aAAO,WAAW,KAAK,KAAK,IAAI,KAAK,4BAA4B;AAAA,IACnE,SAAS,KAAK;AACZ,aAAO,WAAW,UAAU,GAAG,IAAI,IAAI;AAAA,IACzC;AAAA,EACF,CAAC;AAED,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,MACE,YAAY,EAAE,OAAO,EAAE,SAAS,mBAAmB;AAAA,MACnD,UAAU,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,SAAS,EAAE,SAAS,mCAAmC;AAAA,IACxF;AAAA,IACA,OAAO,EAAE,YAAY,SAAS,MAAM;AAClC,YAAM;AACN,UAAI;AACF,cAAM,YAAY,KAAK,YAAmB,QAAQ;AAClD,eAAO,WAAW,kBAAkB,UAAU,EAAE;AAAA,MAClD,SAAS,KAAK;AACZ,eAAO,WAAW,UAAU,GAAG,IAAI,IAAI;AAAA,MACzC;AAAA,IACF;AAAA,EACF;AAEA,QAAM,YAAY,IAAI,qBAAqB;AAC3C,QAAM,OAAO,QAAQ,SAAS;AAE9B,QAAM,sBAAsB;AAC5B,wBAAsB;AACxB;","names":["fs","path","resolve"]}
package/dist/index.js CHANGED
@@ -4,7 +4,7 @@ import {
4
4
  installCodexMcp,
5
5
  resolvePacmanServerCommand,
6
6
  startMcpServer
7
- } from "./chunk-VCDPIN57.js";
7
+ } from "./chunk-WH3UMGHQ.js";
8
8
  import {
9
9
  createIndexer
10
10
  } from "./chunk-3QNXXON5.js";
@@ -36,6 +36,8 @@ var TOOL_GROUPS = [
36
36
  "- Sync: `sync_run_now`, `sync_status`, `sync_list_integrations`",
37
37
  "- Events: `events_ping`"
38
38
  ];
39
+ var MCP_SERVER_NAME = "pacman";
40
+ var CLAUDE_START_COMMAND = "/pacman start <project_name>";
39
41
  function getStorageDescription(config) {
40
42
  return config.storage.mode === "local" ? `Local workspace at: ${config.storage.workspacePath}` : `Google Drive folder: ${config.storage.folderName} (ID: ${config.storage.folderId})`;
41
43
  }
@@ -58,7 +60,7 @@ Read context in this order:
58
60
  ## Retrieval rule
59
61
 
60
62
  When the user asks about responsibilities, projects, stakeholders, status, history, routines, or prior decisions:
61
- - Call the Personal Assistant MCP tools first
63
+ - Call the Pac-Man MCP tools first
62
64
  - Use \`context_search\` to find relevant files
63
65
  - Use \`context_read_file\` or \`context_read_section\` for specific content
64
66
  - Answer only from retrieved context files
@@ -80,7 +82,7 @@ When the conversation creates stable new context (new ownership, priority change
80
82
 
81
83
  ## MCP usage
82
84
 
83
- This project uses the Personal Assistant MCP server. All context operations go through MCP tools:
85
+ This project uses the Pac-Man MCP server. All context operations go through MCP tools:
84
86
  ${TOOL_GROUPS.join("\n")}
85
87
 
86
88
  ## User profile
@@ -91,14 +93,14 @@ ${TOOL_GROUPS.join("\n")}
91
93
  `;
92
94
  }
93
95
  function buildClaudeProjectMemory(config) {
94
- return `# Personal Assistant Project Rules
96
+ return `# Pac-Man Project Rules
95
97
 
96
98
  This project uses a local or Google Drive based context manager.
97
99
 
98
100
  ${buildSharedProjectSections(config)}`;
99
101
  }
100
102
  function buildCodexProjectGuidance(config) {
101
- return `# Personal Assistant Project Instructions
103
+ return `# Pac-Man Project Instructions
102
104
 
103
105
  This repository uses a local or Google Drive based context manager.
104
106
 
@@ -106,30 +108,30 @@ ${buildSharedProjectSections(config)}
106
108
 
107
109
  ## Codex startup rule
108
110
 
109
- - If Personal Assistant MCP tools are unavailable, tell the user to run \`pacman mcp codex install\`
111
+ - If Pac-Man MCP tools are unavailable, tell the user to run \`pacman mcp codex install\`
110
112
  - If the package is not installed globally, show the fallback command:
111
- \`codex mcp add personal_assistant --env PA_WORKSPACE=$HOME/.personal-assistant -- npx -y pacman mcp serve\`
113
+ \`codex mcp add ${MCP_SERVER_NAME} --env PA_WORKSPACE=$HOME/.personal-assistant -- npx -y pacman mcp serve\`
112
114
  - Tell the user to restart Codex after installing or updating the MCP registration
113
115
  `;
114
116
  }
115
117
  function buildClaudeSkillContent() {
116
118
  return `---
117
- name: personal-assistant
118
- description: Start the personal assistant workflow for a project using local or Google Drive context through MCP.
119
+ name: pacman
120
+ description: Start the Pac-Man workflow for a project using local or Google Drive context through MCP.
119
121
  argument-hint: start [project_name]
120
- allowed-tools: mcp__personal_assistant__*
122
+ allowed-tools: mcp__pacman__*
121
123
  ---
122
124
 
123
- # Personal Assistant Skill
125
+ # Pac-Man Skill
124
126
 
125
- When this skill is invoked with \`/personal-assistant start <project_name>\`:
127
+ When this skill is invoked with \`${CLAUDE_START_COMMAND}\`:
126
128
 
127
129
  ## Steps
128
130
 
129
131
  1. **Check MCP availability**:
130
- - If Personal Assistant MCP tools are unavailable, stop and tell the user to install them with \`pacman mcp claude install\`
132
+ - If Pac-Man MCP tools are unavailable, stop and tell the user to install them with \`pacman mcp claude install\`
131
133
  - If the package is not installed globally, show the fallback command:
132
- \`claude mcp add -s user --env=PA_WORKSPACE=$HOME/.personal-assistant personal_assistant -- npx -y pacman mcp serve\`
134
+ \`claude mcp add -s user --env=PA_WORKSPACE=$HOME/.personal-assistant ${MCP_SERVER_NAME} -- npx -y pacman mcp serve\`
133
135
  - Tell the user to restart Claude Code after installing or updating the MCP registration
134
136
 
135
137
  2. **Check MCP health**:
@@ -170,20 +172,20 @@ When this skill is invoked with \`/personal-assistant start <project_name>\`:
170
172
  }
171
173
  function buildCodexSkillContent() {
172
174
  return `---
173
- name: personal-assistant
174
- description: Use when the user asks to start, load, refresh, or inspect Personal Assistant project context stored through the Personal Assistant MCP workspace.
175
+ name: pacman
176
+ description: Use when the user asks to start, load, refresh, or inspect Pac-Man project context stored through the Pac-Man MCP workspace.
175
177
  ---
176
178
 
177
- # Personal Assistant
179
+ # Pac-Man
178
180
 
179
- Use this skill when the user asks to load or refresh personal assistant context for a project.
181
+ Use this skill when the user asks to load or refresh Pac-Man context for a project.
180
182
 
181
183
  ## Steps
182
184
 
183
185
  1. **Check MCP availability**:
184
- - If Personal Assistant MCP tools are unavailable, stop and tell the user to install them with \`pacman mcp codex install\`
186
+ - If Pac-Man MCP tools are unavailable, stop and tell the user to install them with \`pacman mcp codex install\`
185
187
  - If the package is not installed globally, show the fallback command:
186
- \`codex mcp add personal_assistant --env PA_WORKSPACE=$HOME/.personal-assistant -- npx -y pacman mcp serve\`
188
+ \`codex mcp add ${MCP_SERVER_NAME} --env PA_WORKSPACE=$HOME/.personal-assistant -- npx -y pacman mcp serve\`
187
189
  - Tell the user to restart Codex after installing or updating the MCP registration
188
190
 
189
191
  2. **Check MCP health**:
@@ -234,12 +236,14 @@ async function generateClaudeMd(projectPath, config) {
234
236
  await fs.writeFile(path.join(projectPath, "CLAUDE.md"), buildClaudeProjectMemory(config), "utf-8");
235
237
  }
236
238
  async function generateGlobalSkill() {
237
- const globalSkillDir = path.join(
239
+ const skillsRoot = path.join(
238
240
  process.env.HOME ?? process.env.USERPROFILE ?? "~",
239
241
  ".claude",
240
- "skills",
241
- "personal-assistant"
242
+ "skills"
242
243
  );
244
+ const legacySkillDir = path.join(skillsRoot, "personal-assistant");
245
+ const globalSkillDir = path.join(skillsRoot, "pacman");
246
+ await fs.rm(legacySkillDir, { recursive: true, force: true });
243
247
  await fs.mkdir(globalSkillDir, { recursive: true });
244
248
  await fs.writeFile(path.join(globalSkillDir, "SKILL.md"), buildClaudeSkillContent(), "utf-8");
245
249
  }
@@ -263,12 +267,14 @@ async function generateAgentsMd(projectPath, config) {
263
267
  );
264
268
  }
265
269
  async function generateGlobalSkill2() {
266
- const globalSkillDir = path2.join(
270
+ const skillsRoot = path2.join(
267
271
  process.env.HOME ?? process.env.USERPROFILE ?? "~",
268
272
  ".codex",
269
- "skills",
270
- "personal-assistant"
273
+ "skills"
271
274
  );
275
+ const legacySkillDir = path2.join(skillsRoot, "personal-assistant");
276
+ const globalSkillDir = path2.join(skillsRoot, "pacman");
277
+ await fs2.rm(legacySkillDir, { recursive: true, force: true });
272
278
  await fs2.mkdir(globalSkillDir, { recursive: true });
273
279
  await fs2.writeFile(
274
280
  path2.join(globalSkillDir, "SKILL.md"),
@@ -291,11 +297,11 @@ async function resolveWorkspacePath(dirOpt) {
291
297
  return path3.resolve(dirOpt);
292
298
  }
293
299
  var program = new Command();
294
- program.name("pacman").description("Claude Code and Codex compatible, file-backed personal context manager").version("0.1.0");
295
- program.command("init").description("Initialize the personal assistant and open onboarding UI").option("-p, --port <port>", "Port for onboarding server", "3847").option("-d, --dir <dir>", "Workspace directory", ".personal-assistant").action(async (opts) => {
300
+ program.name("pacman").description("Claude Code and Codex compatible, file-backed personal context manager").version("0.1.3");
301
+ program.command("init").description("Initialize Pac-Man and open onboarding UI").option("-p, --port <port>", "Port for onboarding server", "3847").option("-d, --dir <dir>", "Workspace directory", ".personal-assistant").action(async (opts) => {
296
302
  const workspacePath = path3.resolve(opts.dir);
297
303
  const port = parseInt(opts.port, 10);
298
- console.log(`Initializing Personal Assistant workspace at ${workspacePath}...`);
304
+ console.log(`Initializing Pac-Man workspace at ${workspacePath}...`);
299
305
  await fs3.mkdir(workspacePath, { recursive: true });
300
306
  const storage = createLocalStorage(workspacePath);
301
307
  const contextManager = createContextManager(storage);
@@ -338,13 +344,13 @@ program.command("claude").description("Claude integration management").command("
338
344
  });
339
345
  console.log("Claude Code integration installed:");
340
346
  console.log(` - ${projectPath}/CLAUDE.md`);
341
- console.log(` - ~/.claude/skills/personal-assistant/SKILL.md`);
347
+ console.log(` - ~/.claude/skills/pacman/SKILL.md`);
342
348
  console.log("");
343
349
  console.log("Next, register the MCP server with:");
344
350
  console.log(" pacman mcp claude install");
345
351
  console.log("");
346
352
  console.log("Restart Claude Code after the MCP install, then use:");
347
- console.log(" /personal-assistant start <project_name>");
353
+ console.log(" /pacman start <project_name>");
348
354
  });
349
355
  program.command("codex").description("Codex integration management").command("install").description("Install Codex integration (AGENTS.md, skill)").option("-d, --dir <dir>", "Project directory", ".").option("-w, --workspace <workspace>", "Workspace directory", ".personal-assistant").action(async (opts) => {
350
356
  const projectPath = path3.resolve(opts.dir);
@@ -368,38 +374,36 @@ program.command("codex").description("Codex integration management").command("in
368
374
  });
369
375
  console.log("Codex integration installed:");
370
376
  console.log(` - ${projectPath}/AGENTS.md`);
371
- console.log(` - ~/.codex/skills/personal-assistant/SKILL.md`);
377
+ console.log(` - ~/.codex/skills/pacman/SKILL.md`);
372
378
  console.log("");
373
379
  console.log("Next, register the MCP server with:");
374
380
  console.log(" pacman mcp codex install");
375
381
  console.log("");
376
382
  console.log("Restart Codex after the MCP install, then ask it to load or refresh");
377
- console.log("your Personal Assistant context for a project.");
383
+ console.log("your Pac-Man context for a project.");
378
384
  });
379
385
  var mcpCommand = program.command("mcp").description("MCP server management");
380
- mcpCommand.command("serve").description("Start the Personal Assistant MCP server over stdio").option("-w, --workspace <workspace>", "Workspace directory", ".personal-assistant").action(async (opts) => {
386
+ mcpCommand.command("serve").description("Start the Pac-Man MCP server over stdio").option("-w, --workspace <workspace>", "Workspace directory", ".personal-assistant").action(async (opts) => {
381
387
  const workspacePath = await resolveWorkspacePath(opts.workspace);
382
388
  await startMcpServer(workspacePath);
383
389
  });
384
- mcpCommand.command("claude").description("Claude MCP integration management").command("install").description("Register the Personal Assistant MCP server with Claude Code").option("-w, --workspace <workspace>", "Workspace directory", ".personal-assistant").action(async (opts) => {
390
+ mcpCommand.command("claude").description("Claude MCP integration management").command("install").description("Register the Pac-Man MCP server with Claude Code").option("-w, --workspace <workspace>", "Workspace directory", ".personal-assistant").action(async (opts) => {
385
391
  const workspacePath = await resolveWorkspacePath(opts.workspace);
386
392
  await installClaudeMcp(workspacePath, resolvePacmanServerCommand);
387
393
  console.log("Claude MCP registration installed:");
388
394
  console.log(" - managed by Claude Code CLI");
389
395
  console.log(` - PA_WORKSPACE=${workspacePath}`);
390
396
  console.log("");
391
- console.log("Restart Claude Code to reload the Personal Assistant MCP server.");
392
- console.log("Legacy alias still available: personal-assistant-mcp claude install");
397
+ console.log("Restart Claude Code to reload the Pac-Man MCP server.");
393
398
  });
394
- mcpCommand.command("codex").description("Codex MCP integration management").command("install").description("Register the Personal Assistant MCP server with Codex").option("-w, --workspace <workspace>", "Workspace directory", ".personal-assistant").action(async (opts) => {
399
+ mcpCommand.command("codex").description("Codex MCP integration management").command("install").description("Register the Pac-Man MCP server with Codex").option("-w, --workspace <workspace>", "Workspace directory", ".personal-assistant").action(async (opts) => {
395
400
  const workspacePath = await resolveWorkspacePath(opts.workspace);
396
401
  await installCodexMcp(workspacePath, resolvePacmanServerCommand);
397
402
  console.log("Codex MCP registration installed:");
398
403
  console.log(" - managed by Codex CLI");
399
404
  console.log(` - PA_WORKSPACE=${workspacePath}`);
400
405
  console.log("");
401
- console.log("Restart Codex to reload the Personal Assistant MCP server.");
402
- console.log("Legacy alias still available: personal-assistant-mcp codex install");
406
+ console.log("Restart Codex to reload the Pac-Man MCP server.");
403
407
  });
404
408
  program.command("sync").description("Run a one-time sync").option("-d, --dir <dir>", "Workspace directory", ".personal-assistant").action(async (opts) => {
405
409
  const workspacePath = await resolveWorkspacePath(opts.dir);