@mukulaggarwal/pacman 0.1.0 → 0.1.1
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/dist/{chunk-43PUZDIZ.js → chunk-DNI6TIXZ.js} +7 -7
- package/dist/{chunk-AYFIQNZ5.js → chunk-VCDPIN57.js} +2 -2
- package/dist/chunk-YJ32S56Q.js +291 -0
- package/dist/chunk-YJ32S56Q.js.map +1 -0
- package/dist/daemon.js +1 -2
- package/dist/daemon.js.map +1 -1
- package/dist/{dist-TWNHTXYH.js → dist-3BOY3CPO.js} +1 -3
- package/dist/{dist-TWNHTXYH.js.map → dist-3BOY3CPO.js.map} +1 -1
- package/dist/{dist-RMYCRZIU.js → dist-EOAIYOVP.js} +1 -3
- package/dist/{dist-RMYCRZIU.js.map → dist-EOAIYOVP.js.map} +1 -1
- package/dist/{dist-NV2YVVHI.js → dist-HJU53U7M.js} +1 -3
- package/dist/{dist-NV2YVVHI.js.map → dist-HJU53U7M.js.map} +1 -1
- package/dist/{dist-THLCZNOZ.js → dist-RFHCRKM3.js} +2 -3
- package/dist/{dist-3PIJOFZ4.js → dist-WFQSK6BF.js} +1 -3
- package/dist/{dist-3PIJOFZ4.js.map → dist-WFQSK6BF.js.map} +1 -1
- package/dist/{dist-L76NGFFH.js → dist-ZK23POW6.js} +1 -3
- package/dist/{dist-L76NGFFH.js.map → dist-ZK23POW6.js.map} +1 -1
- package/dist/index.js +2 -3
- package/dist/index.js.map +1 -1
- package/dist/mcp-compat.js +2 -3
- package/dist/mcp-compat.js.map +1 -1
- package/dist/onboarding-server.js +2 -3
- package/dist/onboarding-server.js.map +1 -1
- package/dist/provider-runtime.js +0 -1
- package/dist/slack-listener.js +1 -2
- package/dist/slack-listener.js.map +1 -1
- package/dist/storage.js +0 -1
- package/package.json +2 -1
- package/dist/chunk-7D4SUZUM.js +0 -38
- package/dist/chunk-ZKKMIDRK.js +0 -3923
- package/dist/chunk-ZKKMIDRK.js.map +0 -1
- package/dist/dist-THLCZNOZ.js.map +0 -1
- /package/dist/{chunk-43PUZDIZ.js.map → chunk-DNI6TIXZ.js.map} +0 -0
- /package/dist/{chunk-AYFIQNZ5.js.map → chunk-VCDPIN57.js.map} +0 -0
- /package/dist/{chunk-7D4SUZUM.js.map → dist-RFHCRKM3.js.map} +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../integrations-gitlab/dist/index.js"],"sourcesContent":["// src/index.ts\nvar GitLabConnector = class {\n type = \"gitlab\";\n token;\n baseUrl = \"https://gitlab.com/api/v4\";\n async authenticate(config) {\n this.token = config.credentials?.token;\n if (config.credentials?.baseUrl) {\n this.baseUrl = config.credentials.baseUrl;\n }\n if (!this.token) {\n throw new Error(\"GitLab personal access token is required\");\n }\n }\n async healthCheck() {\n if (!this.token) throw new Error(\"GitLab personal access token is required\");\n const res = await fetch(`${this.baseUrl.replace(/\\/$/, \"\")}/user`, {\n headers: { \"PRIVATE-TOKEN\": this.token }\n });\n if (!res.ok) {\n throw new Error(\"GitLab auth test failed: invalid token or base URL\");\n }\n const data = await res.json();\n return { summary: `Connected as ${data.username ?? \"unknown\"}` };\n }\n async fetchDelta(cursor) {\n if (!this.token) throw new Error(\"Not authenticated\");\n const since = cursor ?? new Date(Date.now() - 864e5).toISOString();\n const items = [];\n const res = await fetch(\n `${this.baseUrl}/events?after=${since.slice(0, 10)}&per_page=50`,\n {\n headers: { \"PRIVATE-TOKEN\": this.token }\n }\n );\n if (res.ok) {\n const events = await res.json();\n for (const event of events) {\n items.push({\n id: String(event.id),\n source: \"gitlab\",\n type: event.target_type?.toLowerCase() ?? event.action_name,\n content: `${event.action_name}: ${event.target_title ?? \"no title\"} (project ${event.project_id})`,\n metadata: {\n action: event.action_name,\n targetType: event.target_type,\n projectId: String(event.project_id)\n },\n timestamp: event.created_at\n });\n }\n }\n const mrRes = await fetch(\n `${this.baseUrl}/merge_requests?scope=assigned_to_me&state=opened&per_page=20`,\n {\n headers: { \"PRIVATE-TOKEN\": this.token }\n }\n );\n if (mrRes.ok) {\n const mrs = await mrRes.json();\n for (const mr of mrs) {\n items.push({\n id: `mr-${mr.id}`,\n source: \"gitlab\",\n type: \"merge_request\",\n content: `MR !${mr.iid}: ${mr.title}`,\n metadata: {\n url: mr.web_url,\n projectId: String(mr.project_id),\n state: mr.state\n },\n timestamp: mr.updated_at\n });\n }\n }\n return {\n items,\n newCursor: (/* @__PURE__ */ new Date()).toISOString(),\n hasMore: false\n };\n }\n async normalize(rawItems) {\n return rawItems.map((item) => ({\n id: item.id,\n source: \"gitlab\",\n title: item.content,\n body: item.content,\n entities: [item.metadata.projectId].filter(Boolean),\n timestamp: item.timestamp\n }));\n }\n};\nfunction createGitLabConnector() {\n return new GitLabConnector();\n}\nexport {\n GitLabConnector,\n createGitLabConnector\n};\n"],"mappings":"
|
|
1
|
+
{"version":3,"sources":["../../integrations-gitlab/dist/index.js"],"sourcesContent":["// src/index.ts\nvar GitLabConnector = class {\n type = \"gitlab\";\n token;\n baseUrl = \"https://gitlab.com/api/v4\";\n async authenticate(config) {\n this.token = config.credentials?.token;\n if (config.credentials?.baseUrl) {\n this.baseUrl = config.credentials.baseUrl;\n }\n if (!this.token) {\n throw new Error(\"GitLab personal access token is required\");\n }\n }\n async healthCheck() {\n if (!this.token) throw new Error(\"GitLab personal access token is required\");\n const res = await fetch(`${this.baseUrl.replace(/\\/$/, \"\")}/user`, {\n headers: { \"PRIVATE-TOKEN\": this.token }\n });\n if (!res.ok) {\n throw new Error(\"GitLab auth test failed: invalid token or base URL\");\n }\n const data = await res.json();\n return { summary: `Connected as ${data.username ?? \"unknown\"}` };\n }\n async fetchDelta(cursor) {\n if (!this.token) throw new Error(\"Not authenticated\");\n const since = cursor ?? new Date(Date.now() - 864e5).toISOString();\n const items = [];\n const res = await fetch(\n `${this.baseUrl}/events?after=${since.slice(0, 10)}&per_page=50`,\n {\n headers: { \"PRIVATE-TOKEN\": this.token }\n }\n );\n if (res.ok) {\n const events = await res.json();\n for (const event of events) {\n items.push({\n id: String(event.id),\n source: \"gitlab\",\n type: event.target_type?.toLowerCase() ?? event.action_name,\n content: `${event.action_name}: ${event.target_title ?? \"no title\"} (project ${event.project_id})`,\n metadata: {\n action: event.action_name,\n targetType: event.target_type,\n projectId: String(event.project_id)\n },\n timestamp: event.created_at\n });\n }\n }\n const mrRes = await fetch(\n `${this.baseUrl}/merge_requests?scope=assigned_to_me&state=opened&per_page=20`,\n {\n headers: { \"PRIVATE-TOKEN\": this.token }\n }\n );\n if (mrRes.ok) {\n const mrs = await mrRes.json();\n for (const mr of mrs) {\n items.push({\n id: `mr-${mr.id}`,\n source: \"gitlab\",\n type: \"merge_request\",\n content: `MR !${mr.iid}: ${mr.title}`,\n metadata: {\n url: mr.web_url,\n projectId: String(mr.project_id),\n state: mr.state\n },\n timestamp: mr.updated_at\n });\n }\n }\n return {\n items,\n newCursor: (/* @__PURE__ */ new Date()).toISOString(),\n hasMore: false\n };\n }\n async normalize(rawItems) {\n return rawItems.map((item) => ({\n id: item.id,\n source: \"gitlab\",\n title: item.content,\n body: item.content,\n entities: [item.metadata.projectId].filter(Boolean),\n timestamp: item.timestamp\n }));\n }\n};\nfunction createGitLabConnector() {\n return new GitLabConnector();\n}\nexport {\n GitLabConnector,\n createGitLabConnector\n};\n"],"mappings":"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","names":[]}
|
package/dist/index.js
CHANGED
|
@@ -4,11 +4,11 @@ import {
|
|
|
4
4
|
installCodexMcp,
|
|
5
5
|
resolvePacmanServerCommand,
|
|
6
6
|
startMcpServer
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-VCDPIN57.js";
|
|
8
8
|
import {
|
|
9
9
|
createIndexer
|
|
10
10
|
} from "./chunk-3QNXXON5.js";
|
|
11
|
-
import "./chunk-
|
|
11
|
+
import "./chunk-DNI6TIXZ.js";
|
|
12
12
|
import {
|
|
13
13
|
createContextManager
|
|
14
14
|
} from "./chunk-UWT6AFJB.js";
|
|
@@ -17,7 +17,6 @@ import {
|
|
|
17
17
|
createGDriveStorage,
|
|
18
18
|
createLocalStorage
|
|
19
19
|
} from "./chunk-TRQIZP6Z.js";
|
|
20
|
-
import "./chunk-7D4SUZUM.js";
|
|
21
20
|
|
|
22
21
|
// src/index.ts
|
|
23
22
|
import { Command } from "commander";
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../../claude-installer/dist/index.js","../../client-guidance/dist/index.js","../../codex-installer/dist/index.js"],"sourcesContent":["#!/usr/bin/env node\n\nimport { Command } from 'commander';\nimport * as path from 'node:path';\nimport * as fs from 'node:fs/promises';\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 { renderTemplate, getTemplate } from '@personal-assistant/template-engine';\nimport { installClaude } from '@personal-assistant/claude-installer';\nimport { installCodex } from '@personal-assistant/codex-installer';\nimport { createNoopEventClient } from '@personal-assistant/event-client';\nimport type { StorageBackend, GDriveStorageConfig } from '@personal-assistant/core-types';\nimport {\n installClaudeMcp,\n installCodexMcp,\n resolvePacmanServerCommand,\n} from './mcp-installers.js';\nimport { startMcpServer } from './mcp-server.js';\n\n// Resolve workspace path: the pointer file written during `init` always wins\n// so all commands automatically find the configured workspace without --dir.\n// Pass an explicit absolute path via --dir to override (e.g. for multi-workspace setups).\nasync function resolveWorkspacePath(dirOpt: string): Promise<string> {\n const rcPath = path.join(\n process.env.HOME ?? process.env.USERPROFILE ?? '~',\n '.personal-assistant-rc.json',\n );\n try {\n const rc = JSON.parse(await fs.readFile(rcPath, 'utf-8')) as { workspacePath?: string };\n if (rc.workspacePath) return rc.workspacePath;\n } catch {\n // no pointer yet — fall through to explicit path\n }\n return path.resolve(dirOpt);\n}\n\nconst program = new Command();\n\nprogram\n .name('pacman')\n .description('Claude Code and Codex compatible, file-backed personal context manager')\n .version('0.1.0');\n\n// ---- init command ----\nprogram\n .command('init')\n .description('Initialize the personal assistant and open onboarding UI')\n .option('-p, --port <port>', 'Port for onboarding server', '3847')\n .option('-d, --dir <dir>', 'Workspace directory', '.personal-assistant')\n .action(async (opts) => {\n const workspacePath = path.resolve(opts.dir);\n const port = parseInt(opts.port, 10);\n\n console.log(`Initializing Personal Assistant workspace at ${workspacePath}...`);\n\n // Create workspace directory\n await fs.mkdir(workspacePath, { recursive: true });\n\n // Initialize storage and context\n const storage = createLocalStorage(workspacePath);\n const contextManager = createContextManager(storage);\n await contextManager.initWorkspace();\n\n console.log('Workspace initialized. Starting onboarding server...');\n\n // Start onboarding server\n const { startOnboardingServer } = await import('./onboarding-server.js');\n await startOnboardingServer(port, workspacePath);\n });\n\n// ---- daemon command ----\nprogram\n .command('daemon')\n .description('Start the sync daemon')\n .option('-d, --dir <dir>', 'Workspace directory', '.personal-assistant')\n .action(async (opts) => {\n const workspacePath = await resolveWorkspacePath(opts.dir);\n console.log(`Starting daemon with workspace at ${workspacePath}...`);\n\n const { startDaemon } = await import('./daemon.js');\n await startDaemon(workspacePath);\n });\n\n// ---- slack command ----\nprogram\n .command('slack')\n .description('Slack runtime management')\n .command('listen')\n .description('Start the real-time Slack listener')\n .option('-d, --dir <dir>', 'Workspace directory', '.personal-assistant')\n .action(async (opts) => {\n const workspacePath = await resolveWorkspacePath(opts.dir);\n console.log(`Starting Slack listener with workspace at ${workspacePath}...`);\n\n const { startSlackListener } = await import('./slack-listener.js');\n await startSlackListener(workspacePath);\n });\n\n// ---- claude install command ----\nprogram\n .command('claude')\n .description('Claude integration management')\n .command('install')\n .description('Install Claude Code integration (CLAUDE.md, settings, skill)')\n .option('-d, --dir <dir>', 'Project directory', '.')\n .option('-w, --workspace <workspace>', 'Workspace directory', '.personal-assistant')\n .action(async (opts) => {\n const projectPath = path.resolve(opts.dir);\n const workspacePath = await resolveWorkspacePath(opts.workspace);\n\n console.log('Installing Claude Code integration...');\n\n const storage = createLocalStorage(workspacePath);\n const configManager = createConfigManager(storage);\n\n let config;\n try {\n config = await configManager.loadConfig();\n } catch {\n console.error(\n 'Error: No configuration found. Run `pacman init` first.',\n );\n process.exit(1);\n }\n\n await installClaude({\n projectPath,\n workspacePath,\n config,\n });\n\n console.log('Claude Code integration installed:');\n console.log(` - ${projectPath}/CLAUDE.md`);\n console.log(` - ~/.claude/skills/personal-assistant/SKILL.md`);\n console.log('');\n console.log('Next, register the MCP server with:');\n console.log(' pacman mcp claude install');\n console.log('');\n console.log('Restart Claude Code after the MCP install, then use:');\n console.log(' /personal-assistant start <project_name>');\n });\n\n// ---- codex install command ----\nprogram\n .command('codex')\n .description('Codex integration management')\n .command('install')\n .description('Install Codex integration (AGENTS.md, skill)')\n .option('-d, --dir <dir>', 'Project directory', '.')\n .option('-w, --workspace <workspace>', 'Workspace directory', '.personal-assistant')\n .action(async (opts) => {\n const projectPath = path.resolve(opts.dir);\n const workspacePath = await resolveWorkspacePath(opts.workspace);\n\n console.log('Installing Codex integration...');\n\n const storage = createLocalStorage(workspacePath);\n const configManager = createConfigManager(storage);\n\n let config;\n try {\n config = await configManager.loadConfig();\n } catch {\n console.error(\n 'Error: No configuration found. Run `pacman init` first.',\n );\n process.exit(1);\n }\n\n await installCodex({\n projectPath,\n workspacePath,\n config,\n });\n\n console.log('Codex integration installed:');\n console.log(` - ${projectPath}/AGENTS.md`);\n console.log(` - ~/.codex/skills/personal-assistant/SKILL.md`);\n console.log('');\n console.log('Next, register the MCP server with:');\n console.log(' pacman mcp codex install');\n console.log('');\n console.log('Restart Codex after the MCP install, then ask it to load or refresh');\n console.log('your Personal Assistant context for a project.');\n });\n\n// ---- mcp command ----\nconst mcpCommand = program\n .command('mcp')\n .description('MCP server management');\n\nmcpCommand\n .command('serve')\n .description('Start the Personal Assistant MCP server over stdio')\n .option('-w, --workspace <workspace>', 'Workspace directory', '.personal-assistant')\n .action(async (opts) => {\n const workspacePath = await resolveWorkspacePath(opts.workspace);\n await startMcpServer(workspacePath);\n });\n\nmcpCommand\n .command('claude')\n .description('Claude MCP integration management')\n .command('install')\n .description('Register the Personal Assistant MCP server with Claude Code')\n .option('-w, --workspace <workspace>', 'Workspace directory', '.personal-assistant')\n .action(async (opts) => {\n const workspacePath = await resolveWorkspacePath(opts.workspace);\n\n await installClaudeMcp(workspacePath, resolvePacmanServerCommand);\n\n console.log('Claude MCP registration installed:');\n console.log(' - managed by Claude Code CLI');\n console.log(` - PA_WORKSPACE=${workspacePath}`);\n console.log('');\n console.log('Restart Claude Code to reload the Personal Assistant MCP server.');\n console.log('Legacy alias still available: personal-assistant-mcp claude install');\n });\n\nmcpCommand\n .command('codex')\n .description('Codex MCP integration management')\n .command('install')\n .description('Register the Personal Assistant MCP server with Codex')\n .option('-w, --workspace <workspace>', 'Workspace directory', '.personal-assistant')\n .action(async (opts) => {\n const workspacePath = await resolveWorkspacePath(opts.workspace);\n\n await installCodexMcp(workspacePath, resolvePacmanServerCommand);\n\n console.log('Codex MCP registration installed:');\n console.log(' - managed by Codex CLI');\n console.log(` - PA_WORKSPACE=${workspacePath}`);\n console.log('');\n console.log('Restart Codex to reload the Personal Assistant MCP server.');\n console.log('Legacy alias still available: personal-assistant-mcp codex install');\n });\n\n// ---- sync command ----\nprogram\n .command('sync')\n .description('Run a one-time sync')\n .option('-d, --dir <dir>', 'Workspace directory', '.personal-assistant')\n .action(async (opts) => {\n const workspacePath = await resolveWorkspacePath(opts.dir);\n console.log('Running sync...');\n\n // Bootstrap: read config from local to determine storage backend\n const localStore = createLocalStorage(workspacePath);\n const bootConfigManager = createConfigManager(localStore);\n\n // Resolve storage — all operations use the user's chosen backend\n let resolvedStorage: StorageBackend = localStore;\n try {\n const config = await bootConfigManager.loadConfig();\n if (config.storage.mode === 'gdrive') {\n const gdriveConfig = config.storage as GDriveStorageConfig;\n const resolvedCachePath = path.isAbsolute(gdriveConfig.cachePath)\n ? gdriveConfig.cachePath\n : path.resolve(path.dirname(workspacePath), gdriveConfig.cachePath);\n\n const gdriveStorage = createGDriveStorage({\n ...gdriveConfig,\n cachePath: resolvedCachePath,\n });\n await gdriveStorage.initialize();\n resolvedStorage = gdriveStorage;\n console.log('Using Google Drive storage backend');\n }\n } catch {\n // Config not readable — continue with local storage\n }\n\n const indexer = createIndexer(resolvedStorage);\n await indexer.buildIndexes();\n\n console.log('Sync complete. Indexes rebuilt.');\n });\n\n// ---- status command ----\nprogram\n .command('status')\n .description('Show current configuration and status')\n .option('-d, --dir <dir>', 'Workspace directory', '.personal-assistant')\n .action(async (opts) => {\n const workspacePath = await resolveWorkspacePath(opts.dir);\n\n const storage = createLocalStorage(workspacePath);\n const configManager = createConfigManager(storage);\n\n try {\n const config = await configManager.loadConfig();\n console.log('Personal Assistant Status');\n console.log('========================');\n console.log(`Workspace: ${workspacePath}`);\n console.log(`User: ${config.user.name}`);\n console.log(`Assistant: ${config.user.assistantName}`);\n console.log(`Profile: ${config.user.profileType}`);\n console.log(`Storage: ${config.storage.mode}`);\n console.log(`Active Project: ${config.activeProject ?? 'none'}`);\n console.log(`Integrations: ${config.integrations.filter((i) => i.enabled).map((i) => i.type).join(', ') || 'none'}`);\n console.log(`Sync Time: ${config.sync.dailySyncTime} ${config.sync.timezone}`);\n console.log(`Slack Runtime: ${config.slackRuntime?.enabled ? `${config.slackRuntime.transport} (${config.slackRuntime.reviewMode})` : 'disabled'}`);\n } catch {\n console.log('No configuration found. Run `pacman init` first.');\n }\n });\n\nprogram.parse();\n","// src/index.ts\nimport * as fs from \"fs/promises\";\nimport * as path from \"path\";\nimport {\n buildClaudeProjectMemory,\n buildClaudeSkillContent\n} from \"@personal-assistant/client-guidance\";\nasync function installClaude(options) {\n const { projectPath, config } = options;\n await Promise.all([\n generateClaudeMd(projectPath, config),\n generateGlobalSkill()\n ]);\n}\nasync function generateClaudeMd(projectPath, config) {\n await fs.mkdir(projectPath, { recursive: true });\n await fs.writeFile(path.join(projectPath, \"CLAUDE.md\"), buildClaudeProjectMemory(config), \"utf-8\");\n}\nasync function generateGlobalSkill() {\n const globalSkillDir = path.join(\n process.env.HOME ?? process.env.USERPROFILE ?? \"~\",\n \".claude\",\n \"skills\",\n \"personal-assistant\"\n );\n await fs.mkdir(globalSkillDir, { recursive: true });\n await fs.writeFile(path.join(globalSkillDir, \"SKILL.md\"), buildClaudeSkillContent(), \"utf-8\");\n}\nexport {\n installClaude\n};\n","// src/index.ts\nvar TOOL_GROUPS = [\n \"- Config: `config_get`, `config_get_storage_mode`, `config_get_active_project`, `config_set_active_project`\",\n \"- Projects: `project_list`, `project_suggest`, `project_get_context`\",\n \"- Read: `context_search`, `context_read_file`, `context_read_section`, `context_list_recent_updates`, `context_get_daily_summary`\",\n \"- Update: `context_propose_update`, `context_apply_update`, `context_append_note`, `context_rebuild_indexes`\",\n \"- Sync: `sync_run_now`, `sync_status`, `sync_list_integrations`\",\n \"- Events: `events_ping`\"\n];\nfunction getStorageDescription(config) {\n return config.storage.mode === \"local\" ? `Local workspace at: ${config.storage.workspacePath}` : `Google Drive folder: ${config.storage.folderName} (ID: ${config.storage.folderId})`;\n}\nfunction buildSharedProjectSections(config) {\n return `## Context source of truth\n\nAll context is stored in:\n- ${getStorageDescription(config)}\n\nDo not assume any cloud database exists. Never store raw context outside user-controlled storage.\n\n## Context structure\n\nRead context in this order:\n1. context/canonical/ - long-lived, human-readable context (role, projects, stakeholders)\n2. context/derived/daily/ - machine-generated daily summaries\n3. context/derived/indexes/entities.json - extracted entities index\n4. context/raw/ - only when deeper detail is needed from integration data\n\n## Retrieval rule\n\nWhen the user asks about responsibilities, projects, stakeholders, status, history, routines, or prior decisions:\n- Call the Personal Assistant MCP tools first\n- Use \\`context_search\\` to find relevant files\n- Use \\`context_read_file\\` or \\`context_read_section\\` for specific content\n- Answer only from retrieved context files\n- State uncertainty if context is missing or insufficient\n\n## Update rule\n\nWhen the conversation creates stable new context (new ownership, priority changes, new contacts):\n- Call \\`context_propose_update\\` with the target file, section, proposed content, and reason\n- If the auto-apply policy allows, call \\`context_apply_update\\`\n- Never silently mutate canonical context without proposing first\n\n## Project rule\n\n- If an active project is set, prefer project-specific files from context/canonical/projects/\n- If no project is set, call \\`project_suggest\\` to infer likely project\n- If multiple candidates exist, ask the user to confirm\n- Use \\`config_set_active_project\\` to set the active project\n\n## MCP usage\n\nThis project uses the Personal Assistant MCP server. All context operations go through MCP tools:\n${TOOL_GROUPS.join(\"\\n\")}\n\n## User profile\n\n- Name: ${config.user.name}\n- Assistant name: ${config.user.assistantName}\n- Profile: ${config.user.profileType}\n`;\n}\nfunction buildClaudeProjectMemory(config) {\n return `# Personal Assistant Project Rules\n\nThis project uses a local or Google Drive based context manager.\n\n${buildSharedProjectSections(config)}`;\n}\nfunction buildCodexProjectGuidance(config) {\n return `# Personal Assistant Project Instructions\n\nThis repository uses a local or Google Drive based context manager.\n\n${buildSharedProjectSections(config)}\n\n## Codex startup rule\n\n- If Personal Assistant MCP tools are unavailable, tell the user to run \\`pacman mcp codex install\\`\n- If the package is not installed globally, show the fallback command:\n \\`codex mcp add personal_assistant --env PA_WORKSPACE=$HOME/.personal-assistant -- npx -y pacman mcp serve\\`\n- Tell the user to restart Codex after installing or updating the MCP registration\n`;\n}\nfunction buildClaudeSkillContent() {\n return `---\nname: personal-assistant\ndescription: Start the personal assistant workflow for a project using local or Google Drive context through MCP.\nargument-hint: start [project_name]\nallowed-tools: mcp__personal_assistant__*\n---\n\n# Personal Assistant Skill\n\nWhen this skill is invoked with \\`/personal-assistant start <project_name>\\`:\n\n## Steps\n\n1. **Check MCP availability**:\n - If Personal Assistant MCP tools are unavailable, stop and tell the user to install them with \\`pacman mcp claude install\\`\n - If the package is not installed globally, show the fallback command:\n \\`claude mcp add -s user --env=PA_WORKSPACE=$HOME/.personal-assistant personal_assistant -- npx -y pacman mcp serve\\`\n - Tell the user to restart Claude Code after installing or updating the MCP registration\n\n2. **Check MCP health**:\n - Call \\`sync_status\\` before doing project selection\n - If the response shows an unhealthy storage backend, summarize the reason, fix steps, and restart steps, then stop\n - If the response shows failing integrations, warn the user that sync inputs may be stale and continue unless they want to troubleshoot first\n\n3. **Parse arguments**: Extract the project name from the command arguments.\n\n4. **Set active project**: If a project name is provided:\n - Call \\`config_set_active_project\\` with the project name\n - Call \\`project_get_context\\` to retrieve project-scoped context\n\n5. **Suggest project**: If no project name is provided:\n - Call \\`project_suggest\\` to get a suggested project\n - If one strong candidate exists (confidence > 0.7), suggest it to the user\n - If multiple candidates or low confidence, call \\`project_list\\` and ask the user to choose\n\n6. **Load context**: Once the project is set:\n - Read the project's canonical file from context/canonical/projects/\n - Read the latest daily summary from context/derived/daily/\n - Read the entities index for relevant people and services\n - Present a brief status summary to the user\n\n7. **Continue with MCP**: For all subsequent questions:\n - Use MCP tools to search and retrieve context\n - Answer only from retrieved context files\n - Propose updates when stable new facts emerge\n - State uncertainty when context is insufficient\n\n## Important rules\n\n- Never fabricate context that isn't in the retrieved files\n- Always use MCP tools for context operations\n- Propose updates rather than silently modifying canonical files\n- Respect the context hierarchy: canonical > derived > raw\n`;\n}\nfunction buildCodexSkillContent() {\n return `---\nname: personal-assistant\ndescription: Use when the user asks to start, load, refresh, or inspect Personal Assistant project context stored through the Personal Assistant MCP workspace.\n---\n\n# Personal Assistant\n\nUse this skill when the user asks to load or refresh personal assistant context for a project.\n\n## Steps\n\n1. **Check MCP availability**:\n - If Personal Assistant MCP tools are unavailable, stop and tell the user to install them with \\`pacman mcp codex install\\`\n - If the package is not installed globally, show the fallback command:\n \\`codex mcp add personal_assistant --env PA_WORKSPACE=$HOME/.personal-assistant -- npx -y pacman mcp serve\\`\n - Tell the user to restart Codex after installing or updating the MCP registration\n\n2. **Check MCP health**:\n - Call \\`sync_status\\` before doing project selection\n - If the response shows an unhealthy storage backend, summarize the reason, fix steps, and restart steps, then stop\n - If the response shows failing integrations, warn the user that sync inputs may be stale and continue unless they want to troubleshoot first\n\n3. **Parse the project name**:\n - Extract the project name from the user's request if one is provided\n\n4. **Set or suggest the project**:\n - If a project name is provided, call \\`config_set_active_project\\` and then \\`project_get_context\\`\n - If no project name is provided, call \\`project_suggest\\`\n - If one strong candidate exists (confidence > 0.7), suggest it to the user\n - If multiple candidates or low confidence, call \\`project_list\\` and ask the user to choose\n\n5. **Load context**:\n - Read the project's canonical file from context/canonical/projects/\n - Read the latest daily summary from context/derived/daily/\n - Read the entities index for relevant people and services\n - Present a brief status summary to the user\n\n6. **Continue with MCP**:\n - Use MCP tools to search and retrieve context\n - Answer only from retrieved context files\n - Propose updates when stable new facts emerge\n - State uncertainty when context is insufficient\n\n## Important rules\n\n- Never fabricate context that isn't in the retrieved files\n- Always use MCP tools for context operations\n- Propose updates rather than silently modifying canonical files\n- Respect the context hierarchy: canonical > derived > raw\n`;\n}\nexport {\n buildClaudeProjectMemory,\n buildClaudeSkillContent,\n buildCodexProjectGuidance,\n buildCodexSkillContent\n};\n","// src/index.ts\nimport * as fs from \"fs/promises\";\nimport * as path from \"path\";\nimport {\n buildCodexProjectGuidance,\n buildCodexSkillContent\n} from \"@personal-assistant/client-guidance\";\nasync function installCodex(options) {\n const { projectPath, config } = options;\n await Promise.all([\n generateAgentsMd(projectPath, config),\n generateGlobalSkill()\n ]);\n}\nasync function generateAgentsMd(projectPath, config) {\n await fs.mkdir(projectPath, { recursive: true });\n await fs.writeFile(\n path.join(projectPath, \"AGENTS.md\"),\n buildCodexProjectGuidance(config),\n \"utf-8\"\n );\n}\nasync function generateGlobalSkill() {\n const globalSkillDir = path.join(\n process.env.HOME ?? process.env.USERPROFILE ?? \"~\",\n \".codex\",\n \"skills\",\n \"personal-assistant\"\n );\n await fs.mkdir(globalSkillDir, { recursive: true });\n await fs.writeFile(\n path.join(globalSkillDir, \"SKILL.md\"),\n buildCodexSkillContent(),\n \"utf-8\"\n );\n}\nexport {\n installCodex\n};\n"],"mappings":"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","names":["path","fs","fs","path","generateGlobalSkill"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../../claude-installer/dist/index.js","../../client-guidance/dist/index.js","../../codex-installer/dist/index.js"],"sourcesContent":["#!/usr/bin/env node\n\nimport { Command } from 'commander';\nimport * as path from 'node:path';\nimport * as fs from 'node:fs/promises';\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 { renderTemplate, getTemplate } from '@personal-assistant/template-engine';\nimport { installClaude } from '@personal-assistant/claude-installer';\nimport { installCodex } from '@personal-assistant/codex-installer';\nimport { createNoopEventClient } from '@personal-assistant/event-client';\nimport type { StorageBackend, GDriveStorageConfig } from '@personal-assistant/core-types';\nimport {\n installClaudeMcp,\n installCodexMcp,\n resolvePacmanServerCommand,\n} from './mcp-installers.js';\nimport { startMcpServer } from './mcp-server.js';\n\n// Resolve workspace path: the pointer file written during `init` always wins\n// so all commands automatically find the configured workspace without --dir.\n// Pass an explicit absolute path via --dir to override (e.g. for multi-workspace setups).\nasync function resolveWorkspacePath(dirOpt: string): Promise<string> {\n const rcPath = path.join(\n process.env.HOME ?? process.env.USERPROFILE ?? '~',\n '.personal-assistant-rc.json',\n );\n try {\n const rc = JSON.parse(await fs.readFile(rcPath, 'utf-8')) as { workspacePath?: string };\n if (rc.workspacePath) return rc.workspacePath;\n } catch {\n // no pointer yet — fall through to explicit path\n }\n return path.resolve(dirOpt);\n}\n\nconst program = new Command();\n\nprogram\n .name('pacman')\n .description('Claude Code and Codex compatible, file-backed personal context manager')\n .version('0.1.0');\n\n// ---- init command ----\nprogram\n .command('init')\n .description('Initialize the personal assistant and open onboarding UI')\n .option('-p, --port <port>', 'Port for onboarding server', '3847')\n .option('-d, --dir <dir>', 'Workspace directory', '.personal-assistant')\n .action(async (opts) => {\n const workspacePath = path.resolve(opts.dir);\n const port = parseInt(opts.port, 10);\n\n console.log(`Initializing Personal Assistant workspace at ${workspacePath}...`);\n\n // Create workspace directory\n await fs.mkdir(workspacePath, { recursive: true });\n\n // Initialize storage and context\n const storage = createLocalStorage(workspacePath);\n const contextManager = createContextManager(storage);\n await contextManager.initWorkspace();\n\n console.log('Workspace initialized. Starting onboarding server...');\n\n // Start onboarding server\n const { startOnboardingServer } = await import('./onboarding-server.js');\n await startOnboardingServer(port, workspacePath);\n });\n\n// ---- daemon command ----\nprogram\n .command('daemon')\n .description('Start the sync daemon')\n .option('-d, --dir <dir>', 'Workspace directory', '.personal-assistant')\n .action(async (opts) => {\n const workspacePath = await resolveWorkspacePath(opts.dir);\n console.log(`Starting daemon with workspace at ${workspacePath}...`);\n\n const { startDaemon } = await import('./daemon.js');\n await startDaemon(workspacePath);\n });\n\n// ---- slack command ----\nprogram\n .command('slack')\n .description('Slack runtime management')\n .command('listen')\n .description('Start the real-time Slack listener')\n .option('-d, --dir <dir>', 'Workspace directory', '.personal-assistant')\n .action(async (opts) => {\n const workspacePath = await resolveWorkspacePath(opts.dir);\n console.log(`Starting Slack listener with workspace at ${workspacePath}...`);\n\n const { startSlackListener } = await import('./slack-listener.js');\n await startSlackListener(workspacePath);\n });\n\n// ---- claude install command ----\nprogram\n .command('claude')\n .description('Claude integration management')\n .command('install')\n .description('Install Claude Code integration (CLAUDE.md, settings, skill)')\n .option('-d, --dir <dir>', 'Project directory', '.')\n .option('-w, --workspace <workspace>', 'Workspace directory', '.personal-assistant')\n .action(async (opts) => {\n const projectPath = path.resolve(opts.dir);\n const workspacePath = await resolveWorkspacePath(opts.workspace);\n\n console.log('Installing Claude Code integration...');\n\n const storage = createLocalStorage(workspacePath);\n const configManager = createConfigManager(storage);\n\n let config;\n try {\n config = await configManager.loadConfig();\n } catch {\n console.error(\n 'Error: No configuration found. Run `pacman init` first.',\n );\n process.exit(1);\n }\n\n await installClaude({\n projectPath,\n workspacePath,\n config,\n });\n\n console.log('Claude Code integration installed:');\n console.log(` - ${projectPath}/CLAUDE.md`);\n console.log(` - ~/.claude/skills/personal-assistant/SKILL.md`);\n console.log('');\n console.log('Next, register the MCP server with:');\n console.log(' pacman mcp claude install');\n console.log('');\n console.log('Restart Claude Code after the MCP install, then use:');\n console.log(' /personal-assistant start <project_name>');\n });\n\n// ---- codex install command ----\nprogram\n .command('codex')\n .description('Codex integration management')\n .command('install')\n .description('Install Codex integration (AGENTS.md, skill)')\n .option('-d, --dir <dir>', 'Project directory', '.')\n .option('-w, --workspace <workspace>', 'Workspace directory', '.personal-assistant')\n .action(async (opts) => {\n const projectPath = path.resolve(opts.dir);\n const workspacePath = await resolveWorkspacePath(opts.workspace);\n\n console.log('Installing Codex integration...');\n\n const storage = createLocalStorage(workspacePath);\n const configManager = createConfigManager(storage);\n\n let config;\n try {\n config = await configManager.loadConfig();\n } catch {\n console.error(\n 'Error: No configuration found. Run `pacman init` first.',\n );\n process.exit(1);\n }\n\n await installCodex({\n projectPath,\n workspacePath,\n config,\n });\n\n console.log('Codex integration installed:');\n console.log(` - ${projectPath}/AGENTS.md`);\n console.log(` - ~/.codex/skills/personal-assistant/SKILL.md`);\n console.log('');\n console.log('Next, register the MCP server with:');\n console.log(' pacman mcp codex install');\n console.log('');\n console.log('Restart Codex after the MCP install, then ask it to load or refresh');\n console.log('your Personal Assistant context for a project.');\n });\n\n// ---- mcp command ----\nconst mcpCommand = program\n .command('mcp')\n .description('MCP server management');\n\nmcpCommand\n .command('serve')\n .description('Start the Personal Assistant MCP server over stdio')\n .option('-w, --workspace <workspace>', 'Workspace directory', '.personal-assistant')\n .action(async (opts) => {\n const workspacePath = await resolveWorkspacePath(opts.workspace);\n await startMcpServer(workspacePath);\n });\n\nmcpCommand\n .command('claude')\n .description('Claude MCP integration management')\n .command('install')\n .description('Register the Personal Assistant MCP server with Claude Code')\n .option('-w, --workspace <workspace>', 'Workspace directory', '.personal-assistant')\n .action(async (opts) => {\n const workspacePath = await resolveWorkspacePath(opts.workspace);\n\n await installClaudeMcp(workspacePath, resolvePacmanServerCommand);\n\n console.log('Claude MCP registration installed:');\n console.log(' - managed by Claude Code CLI');\n console.log(` - PA_WORKSPACE=${workspacePath}`);\n console.log('');\n console.log('Restart Claude Code to reload the Personal Assistant MCP server.');\n console.log('Legacy alias still available: personal-assistant-mcp claude install');\n });\n\nmcpCommand\n .command('codex')\n .description('Codex MCP integration management')\n .command('install')\n .description('Register the Personal Assistant MCP server with Codex')\n .option('-w, --workspace <workspace>', 'Workspace directory', '.personal-assistant')\n .action(async (opts) => {\n const workspacePath = await resolveWorkspacePath(opts.workspace);\n\n await installCodexMcp(workspacePath, resolvePacmanServerCommand);\n\n console.log('Codex MCP registration installed:');\n console.log(' - managed by Codex CLI');\n console.log(` - PA_WORKSPACE=${workspacePath}`);\n console.log('');\n console.log('Restart Codex to reload the Personal Assistant MCP server.');\n console.log('Legacy alias still available: personal-assistant-mcp codex install');\n });\n\n// ---- sync command ----\nprogram\n .command('sync')\n .description('Run a one-time sync')\n .option('-d, --dir <dir>', 'Workspace directory', '.personal-assistant')\n .action(async (opts) => {\n const workspacePath = await resolveWorkspacePath(opts.dir);\n console.log('Running sync...');\n\n // Bootstrap: read config from local to determine storage backend\n const localStore = createLocalStorage(workspacePath);\n const bootConfigManager = createConfigManager(localStore);\n\n // Resolve storage — all operations use the user's chosen backend\n let resolvedStorage: StorageBackend = localStore;\n try {\n const config = await bootConfigManager.loadConfig();\n if (config.storage.mode === 'gdrive') {\n const gdriveConfig = config.storage as GDriveStorageConfig;\n const resolvedCachePath = path.isAbsolute(gdriveConfig.cachePath)\n ? gdriveConfig.cachePath\n : path.resolve(path.dirname(workspacePath), gdriveConfig.cachePath);\n\n const gdriveStorage = createGDriveStorage({\n ...gdriveConfig,\n cachePath: resolvedCachePath,\n });\n await gdriveStorage.initialize();\n resolvedStorage = gdriveStorage;\n console.log('Using Google Drive storage backend');\n }\n } catch {\n // Config not readable — continue with local storage\n }\n\n const indexer = createIndexer(resolvedStorage);\n await indexer.buildIndexes();\n\n console.log('Sync complete. Indexes rebuilt.');\n });\n\n// ---- status command ----\nprogram\n .command('status')\n .description('Show current configuration and status')\n .option('-d, --dir <dir>', 'Workspace directory', '.personal-assistant')\n .action(async (opts) => {\n const workspacePath = await resolveWorkspacePath(opts.dir);\n\n const storage = createLocalStorage(workspacePath);\n const configManager = createConfigManager(storage);\n\n try {\n const config = await configManager.loadConfig();\n console.log('Personal Assistant Status');\n console.log('========================');\n console.log(`Workspace: ${workspacePath}`);\n console.log(`User: ${config.user.name}`);\n console.log(`Assistant: ${config.user.assistantName}`);\n console.log(`Profile: ${config.user.profileType}`);\n console.log(`Storage: ${config.storage.mode}`);\n console.log(`Active Project: ${config.activeProject ?? 'none'}`);\n console.log(`Integrations: ${config.integrations.filter((i) => i.enabled).map((i) => i.type).join(', ') || 'none'}`);\n console.log(`Sync Time: ${config.sync.dailySyncTime} ${config.sync.timezone}`);\n console.log(`Slack Runtime: ${config.slackRuntime?.enabled ? `${config.slackRuntime.transport} (${config.slackRuntime.reviewMode})` : 'disabled'}`);\n } catch {\n console.log('No configuration found. Run `pacman init` first.');\n }\n });\n\nprogram.parse();\n","// src/index.ts\nimport * as fs from \"fs/promises\";\nimport * as path from \"path\";\nimport {\n buildClaudeProjectMemory,\n buildClaudeSkillContent\n} from \"@personal-assistant/client-guidance\";\nasync function installClaude(options) {\n const { projectPath, config } = options;\n await Promise.all([\n generateClaudeMd(projectPath, config),\n generateGlobalSkill()\n ]);\n}\nasync function generateClaudeMd(projectPath, config) {\n await fs.mkdir(projectPath, { recursive: true });\n await fs.writeFile(path.join(projectPath, \"CLAUDE.md\"), buildClaudeProjectMemory(config), \"utf-8\");\n}\nasync function generateGlobalSkill() {\n const globalSkillDir = path.join(\n process.env.HOME ?? process.env.USERPROFILE ?? \"~\",\n \".claude\",\n \"skills\",\n \"personal-assistant\"\n );\n await fs.mkdir(globalSkillDir, { recursive: true });\n await fs.writeFile(path.join(globalSkillDir, \"SKILL.md\"), buildClaudeSkillContent(), \"utf-8\");\n}\nexport {\n installClaude\n};\n","// src/index.ts\nvar TOOL_GROUPS = [\n \"- Config: `config_get`, `config_get_storage_mode`, `config_get_active_project`, `config_set_active_project`\",\n \"- Projects: `project_list`, `project_suggest`, `project_get_context`\",\n \"- Read: `context_search`, `context_read_file`, `context_read_section`, `context_list_recent_updates`, `context_get_daily_summary`\",\n \"- Update: `context_propose_update`, `context_apply_update`, `context_append_note`, `context_rebuild_indexes`\",\n \"- Sync: `sync_run_now`, `sync_status`, `sync_list_integrations`\",\n \"- Events: `events_ping`\"\n];\nfunction getStorageDescription(config) {\n return config.storage.mode === \"local\" ? `Local workspace at: ${config.storage.workspacePath}` : `Google Drive folder: ${config.storage.folderName} (ID: ${config.storage.folderId})`;\n}\nfunction buildSharedProjectSections(config) {\n return `## Context source of truth\n\nAll context is stored in:\n- ${getStorageDescription(config)}\n\nDo not assume any cloud database exists. Never store raw context outside user-controlled storage.\n\n## Context structure\n\nRead context in this order:\n1. context/canonical/ - long-lived, human-readable context (role, projects, stakeholders)\n2. context/derived/daily/ - machine-generated daily summaries\n3. context/derived/indexes/entities.json - extracted entities index\n4. context/raw/ - only when deeper detail is needed from integration data\n\n## Retrieval rule\n\nWhen the user asks about responsibilities, projects, stakeholders, status, history, routines, or prior decisions:\n- Call the Personal Assistant MCP tools first\n- Use \\`context_search\\` to find relevant files\n- Use \\`context_read_file\\` or \\`context_read_section\\` for specific content\n- Answer only from retrieved context files\n- State uncertainty if context is missing or insufficient\n\n## Update rule\n\nWhen the conversation creates stable new context (new ownership, priority changes, new contacts):\n- Call \\`context_propose_update\\` with the target file, section, proposed content, and reason\n- If the auto-apply policy allows, call \\`context_apply_update\\`\n- Never silently mutate canonical context without proposing first\n\n## Project rule\n\n- If an active project is set, prefer project-specific files from context/canonical/projects/\n- If no project is set, call \\`project_suggest\\` to infer likely project\n- If multiple candidates exist, ask the user to confirm\n- Use \\`config_set_active_project\\` to set the active project\n\n## MCP usage\n\nThis project uses the Personal Assistant MCP server. All context operations go through MCP tools:\n${TOOL_GROUPS.join(\"\\n\")}\n\n## User profile\n\n- Name: ${config.user.name}\n- Assistant name: ${config.user.assistantName}\n- Profile: ${config.user.profileType}\n`;\n}\nfunction buildClaudeProjectMemory(config) {\n return `# Personal Assistant Project Rules\n\nThis project uses a local or Google Drive based context manager.\n\n${buildSharedProjectSections(config)}`;\n}\nfunction buildCodexProjectGuidance(config) {\n return `# Personal Assistant Project Instructions\n\nThis repository uses a local or Google Drive based context manager.\n\n${buildSharedProjectSections(config)}\n\n## Codex startup rule\n\n- If Personal Assistant MCP tools are unavailable, tell the user to run \\`pacman mcp codex install\\`\n- If the package is not installed globally, show the fallback command:\n \\`codex mcp add personal_assistant --env PA_WORKSPACE=$HOME/.personal-assistant -- npx -y pacman mcp serve\\`\n- Tell the user to restart Codex after installing or updating the MCP registration\n`;\n}\nfunction buildClaudeSkillContent() {\n return `---\nname: personal-assistant\ndescription: Start the personal assistant workflow for a project using local or Google Drive context through MCP.\nargument-hint: start [project_name]\nallowed-tools: mcp__personal_assistant__*\n---\n\n# Personal Assistant Skill\n\nWhen this skill is invoked with \\`/personal-assistant start <project_name>\\`:\n\n## Steps\n\n1. **Check MCP availability**:\n - If Personal Assistant MCP tools are unavailable, stop and tell the user to install them with \\`pacman mcp claude install\\`\n - If the package is not installed globally, show the fallback command:\n \\`claude mcp add -s user --env=PA_WORKSPACE=$HOME/.personal-assistant personal_assistant -- npx -y pacman mcp serve\\`\n - Tell the user to restart Claude Code after installing or updating the MCP registration\n\n2. **Check MCP health**:\n - Call \\`sync_status\\` before doing project selection\n - If the response shows an unhealthy storage backend, summarize the reason, fix steps, and restart steps, then stop\n - If the response shows failing integrations, warn the user that sync inputs may be stale and continue unless they want to troubleshoot first\n\n3. **Parse arguments**: Extract the project name from the command arguments.\n\n4. **Set active project**: If a project name is provided:\n - Call \\`config_set_active_project\\` with the project name\n - Call \\`project_get_context\\` to retrieve project-scoped context\n\n5. **Suggest project**: If no project name is provided:\n - Call \\`project_suggest\\` to get a suggested project\n - If one strong candidate exists (confidence > 0.7), suggest it to the user\n - If multiple candidates or low confidence, call \\`project_list\\` and ask the user to choose\n\n6. **Load context**: Once the project is set:\n - Read the project's canonical file from context/canonical/projects/\n - Read the latest daily summary from context/derived/daily/\n - Read the entities index for relevant people and services\n - Present a brief status summary to the user\n\n7. **Continue with MCP**: For all subsequent questions:\n - Use MCP tools to search and retrieve context\n - Answer only from retrieved context files\n - Propose updates when stable new facts emerge\n - State uncertainty when context is insufficient\n\n## Important rules\n\n- Never fabricate context that isn't in the retrieved files\n- Always use MCP tools for context operations\n- Propose updates rather than silently modifying canonical files\n- Respect the context hierarchy: canonical > derived > raw\n`;\n}\nfunction buildCodexSkillContent() {\n return `---\nname: personal-assistant\ndescription: Use when the user asks to start, load, refresh, or inspect Personal Assistant project context stored through the Personal Assistant MCP workspace.\n---\n\n# Personal Assistant\n\nUse this skill when the user asks to load or refresh personal assistant context for a project.\n\n## Steps\n\n1. **Check MCP availability**:\n - If Personal Assistant MCP tools are unavailable, stop and tell the user to install them with \\`pacman mcp codex install\\`\n - If the package is not installed globally, show the fallback command:\n \\`codex mcp add personal_assistant --env PA_WORKSPACE=$HOME/.personal-assistant -- npx -y pacman mcp serve\\`\n - Tell the user to restart Codex after installing or updating the MCP registration\n\n2. **Check MCP health**:\n - Call \\`sync_status\\` before doing project selection\n - If the response shows an unhealthy storage backend, summarize the reason, fix steps, and restart steps, then stop\n - If the response shows failing integrations, warn the user that sync inputs may be stale and continue unless they want to troubleshoot first\n\n3. **Parse the project name**:\n - Extract the project name from the user's request if one is provided\n\n4. **Set or suggest the project**:\n - If a project name is provided, call \\`config_set_active_project\\` and then \\`project_get_context\\`\n - If no project name is provided, call \\`project_suggest\\`\n - If one strong candidate exists (confidence > 0.7), suggest it to the user\n - If multiple candidates or low confidence, call \\`project_list\\` and ask the user to choose\n\n5. **Load context**:\n - Read the project's canonical file from context/canonical/projects/\n - Read the latest daily summary from context/derived/daily/\n - Read the entities index for relevant people and services\n - Present a brief status summary to the user\n\n6. **Continue with MCP**:\n - Use MCP tools to search and retrieve context\n - Answer only from retrieved context files\n - Propose updates when stable new facts emerge\n - State uncertainty when context is insufficient\n\n## Important rules\n\n- Never fabricate context that isn't in the retrieved files\n- Always use MCP tools for context operations\n- Propose updates rather than silently modifying canonical files\n- Respect the context hierarchy: canonical > derived > raw\n`;\n}\nexport {\n buildClaudeProjectMemory,\n buildClaudeSkillContent,\n buildCodexProjectGuidance,\n buildCodexSkillContent\n};\n","// src/index.ts\nimport * as fs from \"fs/promises\";\nimport * as path from \"path\";\nimport {\n buildCodexProjectGuidance,\n buildCodexSkillContent\n} from \"@personal-assistant/client-guidance\";\nasync function installCodex(options) {\n const { projectPath, config } = options;\n await Promise.all([\n generateAgentsMd(projectPath, config),\n generateGlobalSkill()\n ]);\n}\nasync function generateAgentsMd(projectPath, config) {\n await fs.mkdir(projectPath, { recursive: true });\n await fs.writeFile(\n path.join(projectPath, \"AGENTS.md\"),\n buildCodexProjectGuidance(config),\n \"utf-8\"\n );\n}\nasync function generateGlobalSkill() {\n const globalSkillDir = path.join(\n process.env.HOME ?? process.env.USERPROFILE ?? \"~\",\n \".codex\",\n \"skills\",\n \"personal-assistant\"\n );\n await fs.mkdir(globalSkillDir, { recursive: true });\n await fs.writeFile(\n path.join(globalSkillDir, \"SKILL.md\"),\n buildCodexSkillContent(),\n \"utf-8\"\n );\n}\nexport {\n installCodex\n};\n"],"mappings":"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","names":["path","fs","fs","path","generateGlobalSkill"]}
|
package/dist/mcp-compat.js
CHANGED
|
@@ -6,12 +6,11 @@ import {
|
|
|
6
6
|
resolveCompatServerCommand,
|
|
7
7
|
resolveWorkspacePath,
|
|
8
8
|
startMcpServer
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-VCDPIN57.js";
|
|
10
10
|
import "./chunk-3QNXXON5.js";
|
|
11
|
-
import "./chunk-
|
|
11
|
+
import "./chunk-DNI6TIXZ.js";
|
|
12
12
|
import "./chunk-UWT6AFJB.js";
|
|
13
13
|
import "./chunk-TRQIZP6Z.js";
|
|
14
|
-
import "./chunk-7D4SUZUM.js";
|
|
15
14
|
|
|
16
15
|
// src/mcp-compat.ts
|
|
17
16
|
import * as path from "path";
|
package/dist/mcp-compat.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/mcp-compat.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport * as path from 'node:path';\nimport {\n DEFAULT_WORKSPACE,\n installClaudeMcp,\n installCodexMcp,\n resolveCompatServerCommand,\n resolveWorkspacePath,\n} from './mcp-installers.js';\nimport { startMcpServer } from './mcp-server.js';\n\nfunction printHelp(): void {\n console.log(`personal-assistant-mcp\n\nLegacy compatibility entrypoint. Prefer:\n pacman mcp serve\n pacman mcp claude install\n pacman mcp codex install\n\nUsage:\n personal-assistant-mcp\n personal-assistant-mcp claude install [--workspace <path>]\n personal-assistant-mcp codex install [--workspace <path>]\n`);\n}\n\nfunction parseWorkspaceArg(args: string[]): string | undefined {\n for (let index = 0; index < args.length; index += 1) {\n if (args[index] === '-w' || args[index] === '--workspace') {\n return args[index + 1];\n }\n }\n return undefined;\n}\n\nasync function main(): Promise<void> {\n const args = process.argv.slice(2);\n\n if (args.length === 0) {\n const workspacePath = path.resolve(process.env.PA_WORKSPACE ?? DEFAULT_WORKSPACE);\n await startMcpServer(workspacePath);\n return;\n }\n\n if (args.length === 1 && (args[0] === '-h' || args[0] === '--help')) {\n printHelp();\n return;\n }\n\n if (args[0] === 'claude' && args[1] === 'install') {\n const workspacePath = await resolveWorkspacePath(parseWorkspaceArg(args.slice(2)));\n await installClaudeMcp(workspacePath, resolveCompatServerCommand);\n\n console.log('Claude MCP registration installed.');\n console.log('Preferred command going forward: `pacman mcp claude install`');\n console.log(`PA_WORKSPACE=${workspacePath}`);\n console.log('');\n console.log('Restart Claude Code to reload the Personal Assistant MCP server.');\n return;\n }\n\n if (args[0] === 'codex' && args[1] === 'install') {\n const workspacePath = await resolveWorkspacePath(parseWorkspaceArg(args.slice(2)));\n await installCodexMcp(workspacePath, resolveCompatServerCommand);\n\n console.log('Codex MCP registration installed.');\n console.log('Preferred command going forward: `pacman mcp codex install`');\n console.log(`PA_WORKSPACE=${workspacePath}`);\n console.log('');\n console.log('Restart Codex to reload the Personal Assistant MCP server.');\n return;\n }\n\n printHelp();\n process.exitCode = 1;\n}\n\nmain().catch((err) => {\n console.error('MCP server error:', err);\n process.exit(1);\n});\n"],"mappings":"
|
|
1
|
+
{"version":3,"sources":["../src/mcp-compat.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport * as path from 'node:path';\nimport {\n DEFAULT_WORKSPACE,\n installClaudeMcp,\n installCodexMcp,\n resolveCompatServerCommand,\n resolveWorkspacePath,\n} from './mcp-installers.js';\nimport { startMcpServer } from './mcp-server.js';\n\nfunction printHelp(): void {\n console.log(`personal-assistant-mcp\n\nLegacy compatibility entrypoint. Prefer:\n pacman mcp serve\n pacman mcp claude install\n pacman mcp codex install\n\nUsage:\n personal-assistant-mcp\n personal-assistant-mcp claude install [--workspace <path>]\n personal-assistant-mcp codex install [--workspace <path>]\n`);\n}\n\nfunction parseWorkspaceArg(args: string[]): string | undefined {\n for (let index = 0; index < args.length; index += 1) {\n if (args[index] === '-w' || args[index] === '--workspace') {\n return args[index + 1];\n }\n }\n return undefined;\n}\n\nasync function main(): Promise<void> {\n const args = process.argv.slice(2);\n\n if (args.length === 0) {\n const workspacePath = path.resolve(process.env.PA_WORKSPACE ?? DEFAULT_WORKSPACE);\n await startMcpServer(workspacePath);\n return;\n }\n\n if (args.length === 1 && (args[0] === '-h' || args[0] === '--help')) {\n printHelp();\n return;\n }\n\n if (args[0] === 'claude' && args[1] === 'install') {\n const workspacePath = await resolveWorkspacePath(parseWorkspaceArg(args.slice(2)));\n await installClaudeMcp(workspacePath, resolveCompatServerCommand);\n\n console.log('Claude MCP registration installed.');\n console.log('Preferred command going forward: `pacman mcp claude install`');\n console.log(`PA_WORKSPACE=${workspacePath}`);\n console.log('');\n console.log('Restart Claude Code to reload the Personal Assistant MCP server.');\n return;\n }\n\n if (args[0] === 'codex' && args[1] === 'install') {\n const workspacePath = await resolveWorkspacePath(parseWorkspaceArg(args.slice(2)));\n await installCodexMcp(workspacePath, resolveCompatServerCommand);\n\n console.log('Codex MCP registration installed.');\n console.log('Preferred command going forward: `pacman mcp codex install`');\n console.log(`PA_WORKSPACE=${workspacePath}`);\n console.log('');\n console.log('Restart Codex to reload the Personal Assistant MCP server.');\n return;\n }\n\n printHelp();\n process.exitCode = 1;\n}\n\nmain().catch((err) => {\n console.error('MCP server error:', err);\n process.exit(1);\n});\n"],"mappings":";;;;;;;;;;;;;;;AAEA,YAAY,UAAU;AAUtB,SAAS,YAAkB;AACzB,UAAQ,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,CAWb;AACD;AAEA,SAAS,kBAAkB,MAAoC;AAC7D,WAAS,QAAQ,GAAG,QAAQ,KAAK,QAAQ,SAAS,GAAG;AACnD,QAAI,KAAK,KAAK,MAAM,QAAQ,KAAK,KAAK,MAAM,eAAe;AACzD,aAAO,KAAK,QAAQ,CAAC;AAAA,IACvB;AAAA,EACF;AACA,SAAO;AACT;AAEA,eAAe,OAAsB;AACnC,QAAM,OAAO,QAAQ,KAAK,MAAM,CAAC;AAEjC,MAAI,KAAK,WAAW,GAAG;AACrB,UAAM,gBAAqB,aAAQ,QAAQ,IAAI,gBAAgB,iBAAiB;AAChF,UAAM,eAAe,aAAa;AAClC;AAAA,EACF;AAEA,MAAI,KAAK,WAAW,MAAM,KAAK,CAAC,MAAM,QAAQ,KAAK,CAAC,MAAM,WAAW;AACnE,cAAU;AACV;AAAA,EACF;AAEA,MAAI,KAAK,CAAC,MAAM,YAAY,KAAK,CAAC,MAAM,WAAW;AACjD,UAAM,gBAAgB,MAAM,qBAAqB,kBAAkB,KAAK,MAAM,CAAC,CAAC,CAAC;AACjF,UAAM,iBAAiB,eAAe,0BAA0B;AAEhE,YAAQ,IAAI,oCAAoC;AAChD,YAAQ,IAAI,8DAA8D;AAC1E,YAAQ,IAAI,gBAAgB,aAAa,EAAE;AAC3C,YAAQ,IAAI,EAAE;AACd,YAAQ,IAAI,kEAAkE;AAC9E;AAAA,EACF;AAEA,MAAI,KAAK,CAAC,MAAM,WAAW,KAAK,CAAC,MAAM,WAAW;AAChD,UAAM,gBAAgB,MAAM,qBAAqB,kBAAkB,KAAK,MAAM,CAAC,CAAC,CAAC;AACjF,UAAM,gBAAgB,eAAe,0BAA0B;AAE/D,YAAQ,IAAI,mCAAmC;AAC/C,YAAQ,IAAI,6DAA6D;AACzE,YAAQ,IAAI,gBAAgB,aAAa,EAAE;AAC3C,YAAQ,IAAI,EAAE;AACd,YAAQ,IAAI,4DAA4D;AACxE;AAAA,EACF;AAEA,YAAU;AACV,UAAQ,WAAW;AACrB;AAEA,KAAK,EAAE,MAAM,CAAC,QAAQ;AACpB,UAAQ,MAAM,qBAAqB,GAAG;AACtC,UAAQ,KAAK,CAAC;AAChB,CAAC;","names":[]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createNoopEventClient,
|
|
3
3
|
validateIntegrationConfig
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-DNI6TIXZ.js";
|
|
5
5
|
import {
|
|
6
6
|
createContextManager
|
|
7
7
|
} from "./chunk-UWT6AFJB.js";
|
|
@@ -16,8 +16,7 @@ import {
|
|
|
16
16
|
import {
|
|
17
17
|
createSlackConnector,
|
|
18
18
|
validateSlackAppToken
|
|
19
|
-
} from "./chunk-
|
|
20
|
-
import "./chunk-7D4SUZUM.js";
|
|
19
|
+
} from "./chunk-YJ32S56Q.js";
|
|
21
20
|
|
|
22
21
|
// src/onboarding-server.ts
|
|
23
22
|
import express from "express";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/onboarding-server.ts","../../template-engine/dist/index.js"],"sourcesContent":["import express from 'express';\nimport * as path from 'node:path';\nimport * as fs from 'node:fs/promises';\nimport { exec } from 'node:child_process';\nimport { promisify } from 'node:util';\n\nconst execAsync = promisify(exec);\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 {\n getTemplate,\n renderTemplate,\n listProfiles,\n getResponsibilities,\n} from '@personal-assistant/template-engine';\nimport { validateIntegrationConfig } from '@personal-assistant/integration-runtime';\nimport { createSlackConnector, validateSlackAppToken } from '@personal-assistant/integrations-slack';\nimport { createNoopEventClient } from '@personal-assistant/event-client';\nimport type {\n AppConfig,\n LlmProvider,\n ProfileType,\n UserProfile,\n StorageConfig,\n GDriveStorageConfig,\n IntegrationConfig,\n SyncConfig,\n} from '@personal-assistant/core-types';\nimport { validateProviderConfig } from './provider-runtime.js';\n\ninterface GDriveAuthSession {\n clientId: string;\n clientSecret: string;\n status: 'pending' | 'authenticated' | 'complete' | 'error';\n // set after OAuth callback\n accessToken?: string;\n refreshToken?: string;\n // set after folder creation\n folderId?: string;\n folderName?: string;\n folderPath?: string;\n error?: string;\n}\n\nexport async function startOnboardingServer(\n port: number,\n workspacePath: string,\n): Promise<void> {\n const app = express();\n app.use(express.json());\n\n let gdriveAuthSession: GDriveAuthSession | null = null;\n\n // Serve static files from onboarding-web dist\n const staticPath = path.resolve(\n import.meta.dirname ?? __dirname,\n '../../../apps/onboarding-web/dist',\n );\n\n // Try to serve built static files; fallback to inline HTML\n try {\n await fs.access(staticPath);\n app.use(express.static(staticPath));\n } catch {\n // Serve inline onboarding page if the web app isn't built\n app.get('/', (_req, res) => {\n res.send(getInlineOnboardingHtml());\n });\n }\n\n // --- API Routes ---\n\n app.get('/api/profiles', (_req, res) => {\n const profiles = listProfiles();\n res.json({ profiles });\n });\n\n app.get('/api/responsibilities/:profileType', (req, res) => {\n try {\n const responsibilities = getResponsibilities(req.params.profileType as ProfileType);\n res.json({ responsibilities });\n } catch {\n res.status(400).json({ error: 'Invalid profile type' });\n }\n });\n\n app.get('/api/template/:profileType', (req, res) => {\n try {\n const template = getTemplate(req.params.profileType as ProfileType);\n res.json({ template });\n } catch {\n res.status(400).json({ error: 'Invalid profile type' });\n }\n });\n\n app.post('/api/preview-template', (req, res) => {\n const { profileType, name, assistantName, responsibilities } = req.body;\n try {\n const template = getTemplate(profileType);\n const files = renderTemplate(template, { name, assistantName, responsibilities });\n res.json({ files });\n } catch (err) {\n res.status(400).json({ error: String(err) });\n }\n });\n\n app.post('/api/save', async (req, res) => {\n try {\n const config: AppConfig = req.body;\n\n // Use the user-chosen local path if provided, otherwise fall back to CLI --dir\n const effectivePath =\n config.storage.mode === 'local' && (config.storage as { workspacePath?: string }).workspacePath\n ? path.resolve((config.storage as { workspacePath: string }).workspacePath)\n : workspacePath;\n\n // Ensure the local directory exists (needed for bootstrap even in GDrive mode)\n await fs.mkdir(effectivePath, { recursive: true });\n\n // Save a global pointer so CLI commands can find the workspace without --dir\n const rcPath = path.join(process.env.HOME ?? process.env.USERPROFILE ?? '~', '.personal-assistant-rc.json');\n await fs.writeFile(rcPath, JSON.stringify({ workspacePath: effectivePath }, null, 2), 'utf-8');\n\n // Always save storage.json locally for bootstrap (so MCP server knows which backend to use)\n const localStorage = createLocalStorage(effectivePath);\n const localConfigManager = createConfigManager(localStorage);\n await localConfigManager.saveConfig(config);\n\n // Resolve the user's chosen storage backend\n let targetStorage: import('@personal-assistant/core-types').StorageBackend = localStorage;\n if (config.storage.mode === 'gdrive') {\n const gdriveConfig = config.storage as GDriveStorageConfig;\n const resolvedCachePath = path.isAbsolute(gdriveConfig.cachePath)\n ? gdriveConfig.cachePath\n : path.resolve(path.dirname(effectivePath), gdriveConfig.cachePath);\n\n const gdriveStorage = createGDriveStorage({\n ...gdriveConfig,\n cachePath: resolvedCachePath,\n });\n await gdriveStorage.initialize();\n targetStorage = gdriveStorage;\n\n // Write config to GDrive so all reads go through GDrive\n const gdriveConfigManager = createConfigManager(gdriveStorage);\n await gdriveConfigManager.saveConfig(config);\n }\n\n const contextManager = createContextManager(targetStorage);\n\n // Initialize workspace structure on the target backend\n await contextManager.initWorkspace();\n\n // Render and write template files to the target backend\n const template = getTemplate(config.user.profileType);\n const files = renderTemplate(template, {\n name: config.user.name,\n assistantName: config.user.assistantName,\n responsibilities: config.user.responsibilities,\n });\n await contextManager.writeCanonicalFiles(files);\n\n // Emit onboarding completed event\n const eventClient = createNoopEventClient();\n await eventClient.emit('onboarding_completed', {\n profile: config.user.profileType,\n storage_mode: config.storage.mode,\n });\n\n res.json({ success: true, workspacePath: effectivePath });\n } catch (err) {\n res.status(500).json({ error: String(err) });\n }\n });\n\n // --- Integration credential validation ---\n\n app.post('/api/validate-integration', async (req, res) => {\n const { type, credentials } = req.body as {\n type: string;\n credentials: Record<string, string>;\n };\n\n try {\n const result = await validateIntegrationConfig({\n type: type as IntegrationConfig['type'],\n enabled: true,\n credentials,\n });\n\n if (result.ok) {\n res.json({ valid: true, info: result.summary ?? `Connected to ${type}` });\n return;\n }\n\n res.json({\n valid: false,\n error: [result.reason, ...(result.fix ?? [])].filter(Boolean).join(' '),\n });\n } catch (err) {\n res.json({ valid: false, error: String(err) });\n }\n });\n\n app.post('/api/validate-provider', async (req, res) => {\n const { provider, apiKey, model } = req.body as {\n provider: LlmProvider;\n apiKey: string;\n model?: string;\n };\n\n try {\n const result = await validateProviderConfig(provider, apiKey, model);\n res.json(result);\n } catch (err) {\n res.json({ valid: false, error: String(err) });\n }\n });\n\n app.post('/api/validate-slack-runtime', async (req, res) => {\n const {\n botToken,\n appToken,\n generationEnabled,\n providers,\n } = req.body as {\n botToken?: string;\n appToken?: string;\n generationEnabled?: boolean;\n providers?: {\n openai?: { apiKey?: string; model?: string };\n anthropic?: { apiKey?: string; model?: string };\n };\n };\n\n if (!botToken || !appToken) {\n res.json({ valid: false, error: 'Slack bot token and app token are required.' });\n return;\n }\n\n if (!botToken.startsWith('xoxb-')) {\n res.json({\n valid: false,\n error: 'Slack bot token must start with xoxb-. Paste the Bot User OAuth Token from OAuth & Permissions.',\n });\n return;\n }\n\n if (!appToken.startsWith('xapp-')) {\n res.json({\n valid: false,\n error: 'Slack Socket Mode app token must start with xapp-. Create an App-Level Token with connections:write under Socket Mode.',\n });\n return;\n }\n\n try {\n const connector = createSlackConnector();\n await connector.authenticate({\n type: 'slack',\n enabled: true,\n credentials: { botToken },\n });\n const health = await connector.healthCheck();\n await validateSlackAppToken(appToken);\n\n if (generationEnabled) {\n const providerEntries = [\n ['openai', providers?.openai],\n ['anthropic', providers?.anthropic],\n ] as const;\n\n const configuredProviders = providerEntries.filter(([, value]) => value?.apiKey);\n if (configuredProviders.length === 0) {\n res.json({ valid: false, error: 'Enable at least one provider when Slack generation is turned on.' });\n return;\n }\n\n for (const [provider, value] of configuredProviders) {\n const result = await validateProviderConfig(provider, value?.apiKey ?? '', value?.model);\n if (!result.valid) {\n res.json({ valid: false, error: result.error ?? `Failed to validate ${provider}` });\n return;\n }\n }\n }\n\n res.json({\n valid: true,\n info: `${health.summary ?? 'Slack connected'} via Socket Mode. Atlas will monitor channels where the bot is added.`,\n });\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n if (message.includes('not_allowed_token_type')) {\n res.json({\n valid: false,\n error: 'Slack rejected the Socket Mode token. Use an App-Level Token that starts with xapp- and has the connections:write scope.',\n });\n return;\n }\n\n res.json({\n valid: false,\n error: message,\n });\n }\n });\n\n // --- Local folder picker ---\n\n app.get('/api/pick-folder', async (_req, res) => {\n try {\n let folderPath: string;\n const platform = process.platform;\n\n if (platform === 'darwin') {\n const { stdout } = await execAsync(\n `osascript -e 'POSIX path of (choose folder with prompt \"Select a folder for your personal assistant context\")'`,\n );\n folderPath = stdout.trim();\n } else if (platform === 'linux') {\n const { stdout } = await execAsync(\n 'zenity --file-selection --directory --title=\"Select storage folder\"',\n );\n folderPath = stdout.trim();\n } else if (platform === 'win32') {\n const ps =\n '[System.Reflection.Assembly]::LoadWithPartialName(\\'System.windows.forms\\') | Out-Null; ' +\n '$f = New-Object System.Windows.Forms.FolderBrowserDialog; ' +\n '$f.Description = \\'Select a folder for your personal assistant context\\'; ' +\n '$f.ShowDialog() | Out-Null; $f.SelectedPath';\n const { stdout } = await execAsync(`powershell -command \"${ps}\"`);\n folderPath = stdout.trim();\n } else {\n res.status(400).json({ error: 'Folder picker not supported on this platform' });\n return;\n }\n\n if (!folderPath) {\n res.json({ cancelled: true });\n return;\n }\n\n res.json({ path: folderPath });\n } catch (err) {\n // osascript throws when the user clicks Cancel — treat as cancellation\n if (String(err).includes('User canceled') || String(err).includes('cancel')) {\n res.json({ cancelled: true });\n return;\n }\n res.status(500).json({ error: String(err) });\n }\n });\n\n // --- Google Drive OAuth routes ---\n\n app.post('/api/gdrive/auth-start', async (req, res) => {\n const { clientId, clientSecret } = req.body as { clientId?: string; clientSecret?: string };\n if (!clientId || !clientSecret) {\n res.status(400).json({ error: 'clientId and clientSecret are required' });\n return;\n }\n\n try {\n const { google } = await import('googleapis');\n const redirectUri = `http://localhost:${port}/api/gdrive/callback`;\n const oauth2Client = new google.auth.OAuth2(clientId, clientSecret, redirectUri);\n const authUrl = oauth2Client.generateAuthUrl({\n access_type: 'offline',\n prompt: 'consent',\n scope: ['https://www.googleapis.com/auth/drive.file'],\n });\n\n gdriveAuthSession = { clientId, clientSecret, status: 'pending' };\n res.json({ authUrl });\n } catch (err) {\n res.status(500).json({ error: String(err) });\n }\n });\n\n app.get('/api/gdrive/callback', async (req, res) => {\n const { code } = req.query as { code?: string };\n\n if (!code || !gdriveAuthSession) {\n res.status(400).send('Invalid OAuth callback — no pending auth session.');\n return;\n }\n\n try {\n const { google } = await import('googleapis');\n const redirectUri = `http://localhost:${port}/api/gdrive/callback`;\n const oauth2Client = new google.auth.OAuth2(\n gdriveAuthSession.clientId,\n gdriveAuthSession.clientSecret,\n redirectUri,\n );\n\n const { tokens } = await oauth2Client.getToken(code);\n\n // Store tokens only — folder is created in a separate step\n gdriveAuthSession = {\n ...gdriveAuthSession,\n status: 'authenticated',\n refreshToken: tokens.refresh_token ?? undefined,\n accessToken: tokens.access_token ?? undefined,\n };\n\n res.send(`<!DOCTYPE html><html><body>\n <script>window.close();</script>\n <p style=\"font-family:sans-serif;padding:2rem;color:#4ade80;\">\n ✓ Authentication successful — you can close this tab and return to the setup.\n </p>\n </body></html>`);\n } catch (err) {\n if (gdriveAuthSession) {\n gdriveAuthSession.status = 'error';\n gdriveAuthSession.error = String(err);\n }\n res.status(500).send('Authentication failed: ' + String(err));\n }\n });\n\n app.get('/api/gdrive/auth-status', (_req, res) => {\n if (!gdriveAuthSession) {\n res.json({ status: 'idle' });\n return;\n }\n const { clientId: _cid, clientSecret: _csec, accessToken: _at, refreshToken: _rt, ...publicSession } = gdriveAuthSession;\n res.json(publicSession);\n });\n\n app.post('/api/gdrive/create-folder', async (req, res) => {\n if (!gdriveAuthSession || gdriveAuthSession.status !== 'authenticated') {\n res.status(400).json({ error: 'Not authenticated. Please connect Google Drive first.' });\n return;\n }\n\n const { folderName = 'Personal Assistant', parentFolderName = '' } =\n req.body as { folderName?: string; parentFolderName?: string };\n\n try {\n const { google } = await import('googleapis');\n const redirectUri = `http://localhost:${port}/api/gdrive/callback`;\n const oauth2Client = new google.auth.OAuth2(\n gdriveAuthSession.clientId,\n gdriveAuthSession.clientSecret,\n redirectUri,\n );\n oauth2Client.setCredentials({\n access_token: gdriveAuthSession.accessToken,\n refresh_token: gdriveAuthSession.refreshToken,\n });\n\n const drive = google.drive({ version: 'v3', auth: oauth2Client });\n\n // Resolve parent folder\n let parentId = 'root';\n let locationPath = 'My Drive';\n\n if (parentFolderName.trim()) {\n const searchRes = await drive.files.list({\n q: `name='${parentFolderName.trim()}' and mimeType='application/vnd.google-apps.folder' and trashed=false`,\n fields: 'files(id,name)',\n spaces: 'drive',\n });\n\n if (searchRes.data.files && searchRes.data.files.length > 0) {\n parentId = searchRes.data.files[0].id!;\n } else {\n // Create the parent folder at root\n const parentRes = await drive.files.create({\n requestBody: {\n name: parentFolderName.trim(),\n mimeType: 'application/vnd.google-apps.folder',\n },\n fields: 'id',\n });\n parentId = parentRes.data.id!;\n }\n locationPath = `My Drive / ${parentFolderName.trim()}`;\n }\n\n // Check if the main folder already exists under the parent before creating\n let folderId: string | undefined;\n let resolvedFolderName = folderName.trim();\n const existingSearch = await drive.files.list({\n q: `name='${resolvedFolderName}' and '${parentId}' in parents and mimeType='application/vnd.google-apps.folder' and trashed=false`,\n fields: 'files(id,name)',\n spaces: 'drive',\n });\n\n if (existingSearch.data.files && existingSearch.data.files.length > 0) {\n folderId = existingSearch.data.files[0].id!;\n resolvedFolderName = existingSearch.data.files[0].name!;\n } else {\n const folderRes = await drive.files.create({\n requestBody: {\n name: resolvedFolderName,\n mimeType: 'application/vnd.google-apps.folder',\n parents: [parentId],\n },\n fields: 'id,name',\n });\n folderId = folderRes.data.id!;\n resolvedFolderName = folderRes.data.name!;\n }\n\n const folderPath = `${locationPath} / ${resolvedFolderName}`;\n\n // Refresh tokens in case they were rotated\n const freshCredentials = await oauth2Client.getAccessToken();\n const latestRefreshToken =\n (oauth2Client.credentials.refresh_token as string | undefined) ??\n gdriveAuthSession.refreshToken;\n\n gdriveAuthSession = {\n ...gdriveAuthSession,\n status: 'complete',\n folderId: folderId!,\n folderName: resolvedFolderName,\n folderPath,\n refreshToken: latestRefreshToken,\n accessToken: freshCredentials.token ?? undefined,\n };\n\n res.json({\n folderId,\n folderName: resolvedFolderName,\n folderPath,\n refreshToken: latestRefreshToken,\n });\n } catch (err) {\n res.status(500).json({ error: String(err) });\n }\n });\n\n app.get('/api/status', async (_req, res) => {\n const storage = createLocalStorage(workspacePath);\n const configManager = createConfigManager(storage);\n try {\n const config = await configManager.loadConfig();\n res.json({ configured: true, config });\n } catch {\n res.json({ configured: false });\n }\n });\n\n // Start server\n const server = app.listen(port, () => {\n const url = `http://localhost:${port}`;\n console.log(`Onboarding server running at ${url}`);\n\n // Try to open browser\n import('open')\n .then((openModule) => openModule.default(url))\n .catch(() => {\n console.log(`Open ${url} in your browser to continue.`);\n });\n });\n\n // Handle graceful shutdown\n process.on('SIGINT', () => {\n console.log('\\nShutting down onboarding server...');\n server.close();\n process.exit(0);\n });\n}\n\nfunction getInlineOnboardingHtml(): string {\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>Personal Assistant - Setup</title>\n <style>\n * { margin: 0; padding: 0; box-sizing: border-box; }\n body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; background: #0f172a; color: #e2e8f0; min-height: 100vh; }\n .container { max-width: 640px; margin: 0 auto; padding: 2rem; }\n h1 { font-size: 1.8rem; margin-bottom: 0.5rem; color: #f8fafc; }\n h2 { font-size: 1.2rem; margin-bottom: 1rem; color: #94a3b8; font-weight: 400; }\n .step { display: none; }\n .step.active { display: block; }\n .progress { display: flex; gap: 0.5rem; margin-bottom: 2rem; }\n .progress-dot { width: 2rem; height: 0.25rem; background: #334155; border-radius: 2px; transition: background 0.3s; }\n .progress-dot.done { background: #3b82f6; }\n .progress-dot.current { background: #60a5fa; }\n label { display: block; margin-bottom: 0.5rem; color: #cbd5e1; font-size: 0.9rem; }\n input, select, textarea { width: 100%; padding: 0.75rem; background: #1e293b; border: 1px solid #334155; border-radius: 0.5rem; color: #f8fafc; font-size: 1rem; margin-bottom: 1rem; }\n input:focus, select:focus, textarea:focus { outline: none; border-color: #3b82f6; }\n textarea { min-height: 200px; font-family: 'SF Mono', 'Fira Code', monospace; font-size: 0.85rem; }\n button { padding: 0.75rem 1.5rem; border: none; border-radius: 0.5rem; font-size: 1rem; cursor: pointer; transition: all 0.2s; }\n .btn-primary { background: #3b82f6; color: white; }\n .btn-primary:hover { background: #2563eb; }\n .btn-secondary { background: #334155; color: #e2e8f0; }\n .btn-secondary:hover { background: #475569; }\n .btn-group { display: flex; gap: 0.75rem; margin-top: 1.5rem; }\n .checkbox-group { display: grid; grid-template-columns: 1fr 1fr; gap: 0.5rem; margin-bottom: 1rem; }\n .checkbox-item { display: flex; align-items: center; gap: 0.5rem; padding: 0.5rem; background: #1e293b; border: 1px solid #334155; border-radius: 0.375rem; cursor: pointer; }\n .checkbox-item:hover { border-color: #475569; }\n .checkbox-item input[type=\"checkbox\"] { width: auto; margin: 0; }\n .radio-group { display: flex; gap: 1rem; margin-bottom: 1rem; }\n .radio-item { flex: 1; padding: 1rem; background: #1e293b; border: 2px solid #334155; border-radius: 0.5rem; cursor: pointer; text-align: center; transition: all 0.2s; }\n .radio-item:hover { border-color: #475569; }\n .radio-item.selected { border-color: #3b82f6; background: #1e3a5f; }\n .success { text-align: center; padding: 3rem 0; }\n .success h2 { color: #4ade80; font-size: 1.5rem; }\n </style>\n</head>\n<body>\n <div class=\"container\">\n <div class=\"progress\" id=\"progress\"></div>\n\n <!-- Step 1: Identity -->\n <div class=\"step active\" data-step=\"0\">\n <h1>Welcome</h1>\n <h2>Let's set up your personal assistant</h2>\n <label>Your Name</label>\n <input type=\"text\" id=\"userName\" placeholder=\"Jane Smith\">\n <label>Assistant Name</label>\n <input type=\"text\" id=\"assistantName\" placeholder=\"Atlas\" value=\"Atlas\">\n <label>Profile</label>\n <select id=\"profileType\">\n <option value=\"software-engineer\">Software Engineer</option>\n <option value=\"product-manager\">Product Manager</option>\n <option value=\"engineering-manager\">Engineering Manager</option>\n <option value=\"devops\">DevOps Engineer</option>\n </select>\n <div class=\"btn-group\"><button class=\"btn-primary\" onclick=\"nextStep()\">Continue</button></div>\n </div>\n\n <!-- Step 2: Responsibilities -->\n <div class=\"step\" data-step=\"1\">\n <h1>Responsibilities</h1>\n <h2>Select your core responsibilities</h2>\n <div class=\"checkbox-group\" id=\"responsibilitiesGroup\"></div>\n <div class=\"btn-group\">\n <button class=\"btn-secondary\" onclick=\"prevStep()\">Back</button>\n <button class=\"btn-primary\" onclick=\"nextStep()\">Continue</button>\n </div>\n </div>\n\n <!-- Step 3: Template Preview -->\n <div class=\"step\" data-step=\"2\">\n <h1>Context Template</h1>\n <h2>Preview and customize your context template</h2>\n <textarea id=\"templatePreview\"></textarea>\n <div class=\"btn-group\">\n <button class=\"btn-secondary\" onclick=\"prevStep()\">Back</button>\n <button class=\"btn-primary\" onclick=\"nextStep()\">Continue</button>\n </div>\n </div>\n\n <!-- Step 4: Storage -->\n <div class=\"step\" data-step=\"3\">\n <h1>Storage</h1>\n <h2>Where should your context be stored?</h2>\n <div class=\"radio-group\">\n <div class=\"radio-item selected\" onclick=\"selectStorage('local')\" id=\"storage-local\">\n <strong>Local Workspace</strong><br><small>Files stored on this machine</small>\n </div>\n <div class=\"radio-item\" onclick=\"selectStorage('gdrive')\" id=\"storage-gdrive\">\n <strong>Google Drive</strong><br><small>Files stored in your Drive folder</small>\n </div>\n </div>\n <div id=\"storage-local-fields\">\n <label>Storage path</label>\n <div style=\"display:flex;gap:0.5rem;align-items:center;\">\n <input type=\"text\" id=\"localPath\" value=\".personal-assistant\" placeholder=\".personal-assistant\" style=\"flex:1;margin-bottom:0;\">\n <button class=\"btn-secondary\" onclick=\"browseFolder()\" id=\"browseBtn\" style=\"white-space:nowrap;flex-shrink:0;\">Browse</button>\n </div>\n <small style=\"color:#64748b;font-size:0.8rem;display:block;margin-top:0.4rem;margin-bottom:1rem;\">Click Browse to open a folder picker, or type a path directly.</small>\n </div>\n <div id=\"storage-gdrive-fields\" style=\"display:none;\">\n <p style=\"color:#f59e0b;font-size:0.85rem;margin-bottom:1rem;\">\n Google Drive OAuth is only supported in the full onboarding UI.<br>\n Run <code>pnpm build</code> in <code>apps/onboarding-web</code> then restart <code>pacman init</code>.\n </p>\n </div>\n <div style=\"background:#1c1917;border:1px solid #92400e;border-radius:0.5rem;padding:0.75rem 1rem;margin-bottom:1.5rem;font-size:0.85rem;color:#fbbf24;\">\n ⚠️ Do not delete, move, or rename the folder structure created by this setup. Claude and the sync daemon rely on the exact file layout to load and update your context.\n </div>\n <div class=\"btn-group\">\n <button class=\"btn-secondary\" onclick=\"prevStep()\">Back</button>\n <button class=\"btn-primary\" onclick=\"nextStep()\">Continue</button>\n </div>\n </div>\n\n <!-- Step 5: Integrations -->\n <div class=\"step\" data-step=\"4\">\n <h1>Integrations</h1>\n <h2>Connect your tools (optional)</h2>\n <div class=\"checkbox-group\" id=\"integrationsGroup\">\n <label class=\"checkbox-item\"><input type=\"checkbox\" value=\"slack\"> Slack</label>\n <label class=\"checkbox-item\"><input type=\"checkbox\" value=\"gmail\"> Gmail</label>\n <label class=\"checkbox-item\"><input type=\"checkbox\" value=\"github\"> GitHub</label>\n <label class=\"checkbox-item\"><input type=\"checkbox\" value=\"gitlab\"> GitLab</label>\n <label class=\"checkbox-item\"><input type=\"checkbox\" value=\"gdrive\"> Google Drive Docs</label>\n <label class=\"checkbox-item\"><input type=\"checkbox\" value=\"gchat\"> Google Chat</label>\n </div>\n <div class=\"btn-group\">\n <button class=\"btn-secondary\" onclick=\"prevStep()\">Back</button>\n <button class=\"btn-primary\" onclick=\"nextStep()\">Continue</button>\n </div>\n </div>\n\n <!-- Step 6: Sync Schedule -->\n <div class=\"step\" data-step=\"5\">\n <h1>Sync Schedule</h1>\n <h2>When should context be refreshed?</h2>\n <label>Daily Sync Time</label>\n <input type=\"time\" id=\"syncTime\" value=\"08:00\">\n <label>Timezone</label>\n <select id=\"timezone\">\n <option value=\"America/New_York\">Eastern Time (ET)</option>\n <option value=\"America/Chicago\">Central Time (CT)</option>\n <option value=\"America/Denver\">Mountain Time (MT)</option>\n <option value=\"America/Los_Angeles\">Pacific Time (PT)</option>\n <option value=\"UTC\">UTC</option>\n <option value=\"Europe/London\">London (GMT/BST)</option>\n <option value=\"Europe/Berlin\">Berlin (CET)</option>\n <option value=\"Asia/Tokyo\">Tokyo (JST)</option>\n <option value=\"Asia/Kolkata\">India (IST)</option>\n <option value=\"Australia/Sydney\">Sydney (AEST)</option>\n </select>\n <div class=\"checkbox-group\">\n <label class=\"checkbox-item\"><input type=\"checkbox\" id=\"manualSync\" checked> Manual sync</label>\n <label class=\"checkbox-item\"><input type=\"checkbox\" id=\"asyncUpdate\" checked> Async updates</label>\n </div>\n <div class=\"btn-group\">\n <button class=\"btn-secondary\" onclick=\"prevStep()\">Back</button>\n <button class=\"btn-primary\" onclick=\"nextStep()\">Continue</button>\n </div>\n </div>\n\n <!-- Step 7: Finish -->\n <div class=\"step\" data-step=\"6\">\n <h1>All Set!</h1>\n <h2>Review and save your configuration</h2>\n <div id=\"summary\" style=\"background:#1e293b;padding:1rem;border-radius:0.5rem;margin-bottom:1rem;font-family:monospace;font-size:0.85rem;white-space:pre-wrap;\"></div>\n <div class=\"btn-group\">\n <button class=\"btn-secondary\" onclick=\"prevStep()\">Back</button>\n <button class=\"btn-primary\" onclick=\"saveConfig()\">Save & Finish</button>\n </div>\n </div>\n\n <!-- Success -->\n <div class=\"step\" data-step=\"7\">\n <div class=\"success\">\n <h2>Setup Complete!</h2>\n <p style=\"margin-top:1rem;color:#94a3b8;\">Your personal assistant context has been initialized.</p>\n <p style=\"margin-top:1rem;color:#94a3b8;\">Next steps:</p>\n <pre style=\"text-align:left;margin-top:1rem;background:#1e293b;padding:1rem;border-radius:0.5rem;font-size:0.85rem;\">\n# Install Claude Code integration\npacman claude install\npacman mcp claude install\n\n# Install Codex integration\npacman codex install\npacman mcp codex install\n\n# Start the sync daemon\npacman daemon\n\n# Start the real-time Slack listener\npacman slack listen\n\n# Use in Claude Code\n/personal-assistant start <project>\n\n# Use in Codex\nAsk Codex to load or refresh your Personal Assistant context for <project></pre>\n <p style=\"margin-top:1rem;color:#64748b;font-size:0.85rem;\">Restart Claude Code or Codex after installing the MCP server.<br>If <code style=\"background:#1e293b;padding:0 4px;border-radius:3px;\">pacman</code> is not found, link it first. The legacy alias <code style=\"background:#1e293b;padding:0 4px;border-radius:3px;\">personal-assistant</code> also remains available:<br>\n <code style=\"background:#1e293b;padding:2px 6px;border-radius:3px;\">pnpm setup && source ~/.zshrc && cd packages/cli && pnpm link --global</code></p>\n </div>\n </div>\n </div>\n\n <script>\n let currentStep = 0;\n const totalSteps = 7;\n let state = { storageMode: 'local', responsibilities: [] };\n\n function updateProgress() {\n const bar = document.getElementById('progress');\n bar.innerHTML = '';\n for (let i = 0; i < totalSteps; i++) {\n const dot = document.createElement('div');\n dot.className = 'progress-dot' + (i < currentStep ? ' done' : i === currentStep ? ' current' : '');\n bar.appendChild(dot);\n }\n }\n\n function showStep(n) {\n document.querySelectorAll('.step').forEach(s => s.classList.remove('active'));\n document.querySelector('[data-step=\"' + n + '\"]').classList.add('active');\n currentStep = n;\n updateProgress();\n }\n\n async function nextStep() {\n if (currentStep === 0) await loadResponsibilities();\n if (currentStep === 1) await loadTemplatePreview();\n if (currentStep === 5) updateSummary();\n showStep(currentStep + 1);\n }\n\n function prevStep() { showStep(currentStep - 1); }\n\n async function loadResponsibilities() {\n const profileType = document.getElementById('profileType').value;\n const res = await fetch('/api/responsibilities/' + profileType);\n const data = await res.json();\n const group = document.getElementById('responsibilitiesGroup');\n group.innerHTML = data.responsibilities.map(r =>\n '<label class=\"checkbox-item\"><input type=\"checkbox\" value=\"' + r + '\" checked> ' + r + '</label>'\n ).join('');\n }\n\n async function loadTemplatePreview() {\n const profileType = document.getElementById('profileType').value;\n const name = document.getElementById('userName').value;\n const assistantName = document.getElementById('assistantName').value;\n const responsibilities = Array.from(document.querySelectorAll('#responsibilitiesGroup input:checked')).map(c => c.value);\n state.responsibilities = responsibilities;\n\n const res = await fetch('/api/preview-template', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ profileType, name, assistantName, responsibilities })\n });\n const data = await res.json();\n const preview = Object.entries(data.files).map(([f, c]) => '--- ' + f + ' ---\\\\n' + c).join('\\\\n\\\\n');\n document.getElementById('templatePreview').value = preview;\n }\n\n function selectStorage(mode) {\n state.storageMode = mode;\n document.querySelectorAll('.radio-item').forEach(r => r.classList.remove('selected'));\n document.getElementById('storage-' + mode).classList.add('selected');\n document.getElementById('storage-local-fields').style.display = mode === 'local' ? 'block' : 'none';\n document.getElementById('storage-gdrive-fields').style.display = mode === 'gdrive' ? 'block' : 'none';\n }\n\n async function browseFolder() {\n const btn = document.getElementById('browseBtn');\n btn.textContent = '…';\n btn.disabled = true;\n try {\n const res = await fetch('/api/pick-folder');\n const data = await res.json();\n if (!data.cancelled && data.path) {\n document.getElementById('localPath').value = data.path;\n }\n } catch (e) {\n // ignore — user can type path manually\n } finally {\n btn.textContent = 'Browse';\n btn.disabled = false;\n }\n }\n\n function updateSummary() {\n const config = buildConfig();\n document.getElementById('summary').textContent = JSON.stringify(config, null, 2);\n }\n\n function buildConfig() {\n const integrations = Array.from(document.querySelectorAll('#integrationsGroup input:checked')).map(c => ({\n type: c.value, enabled: true, credentials: {}, cursor: null, lastSyncAt: null\n }));\n\n return {\n user: {\n name: document.getElementById('userName').value,\n assistantName: document.getElementById('assistantName').value,\n profileType: document.getElementById('profileType').value,\n responsibilities: state.responsibilities\n },\n storage: state.storageMode === 'local'\n ? { mode: 'local', workspacePath: document.getElementById('localPath').value || '.personal-assistant' }\n : { mode: 'gdrive', folderId: '', folderName: 'Personal Assistant', cachePath: '.personal-assistant/cache' },\n integrations,\n sync: {\n dailySyncTime: document.getElementById('syncTime').value,\n timezone: document.getElementById('timezone').value,\n manualSyncEnabled: document.getElementById('manualSync').checked,\n asyncUpdateEnabled: document.getElementById('asyncUpdate').checked\n }\n };\n }\n\n async function saveConfig() {\n const config = buildConfig();\n const res = await fetch('/api/save', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(config)\n });\n const data = await res.json();\n if (data.success) showStep(7);\n else alert('Error: ' + data.error);\n }\n\n updateProgress();\n </script>\n</body>\n</html>`;\n}\n","// src/index.ts\nvar PROFILE_TEMPLATES = {\n \"software-engineer\": {\n profileType: \"software-engineer\",\n name: \"Software Engineer\",\n description: \"Context template for software engineers\",\n responsibilities: [\n \"Code review and PR management\",\n \"Feature development\",\n \"Bug fixing and debugging\",\n \"Architecture decisions\",\n \"Technical documentation\",\n \"On-call and incident response\",\n \"Mentoring junior engineers\",\n \"Sprint planning and estimation\",\n \"CI/CD pipeline maintenance\",\n \"API design and development\"\n ],\n sections: [\n {\n name: \"Overview\",\n fileName: \"overview.md\",\n required: true,\n defaultContent: `# Overview\n\n## Role\nSoftware Engineer\n\n## Team\n<!-- Your team name -->\n\n## Primary Focus\n<!-- Main area of work -->\n\n## Key Repositories\n<!-- List your main repos -->\n\n## Tech Stack\n<!-- Languages, frameworks, tools -->\n`\n },\n {\n name: \"Responsibilities\",\n fileName: \"responsibilities.md\",\n required: true,\n defaultContent: `# Responsibilities\n\n## Core Duties\n<!-- Your primary responsibilities -->\n\n## On-Call\n<!-- On-call schedule and escalation paths -->\n\n## Code Review\n<!-- Review expectations and areas -->\n`\n },\n {\n name: \"Stakeholders\",\n fileName: \"stakeholders.md\",\n required: false,\n defaultContent: `# Stakeholders\n\n## Direct Manager\n<!-- Name, role -->\n\n## Team Members\n<!-- Key teammates -->\n\n## Cross-Team Contacts\n<!-- People you work with in other teams -->\n\n## Escalation Path\n<!-- Who to escalate to and when -->\n`\n },\n {\n name: \"Documentation\",\n fileName: \"docs.md\",\n required: false,\n defaultContent: `# Documentation References\n\n## Internal Docs\n<!-- Links to internal documentation -->\n\n## Runbooks\n<!-- Links to runbooks -->\n\n## Architecture Docs\n<!-- Links to architecture documents -->\n`\n }\n ]\n },\n \"product-manager\": {\n profileType: \"product-manager\",\n name: \"Product Manager\",\n description: \"Context template for product managers\",\n responsibilities: [\n \"Product roadmap management\",\n \"Feature prioritization\",\n \"Stakeholder communication\",\n \"User research and interviews\",\n \"Metrics and KPI tracking\",\n \"Sprint planning and grooming\",\n \"Go-to-market strategy\",\n \"Competitive analysis\",\n \"Cross-team coordination\",\n \"Product requirements documentation\"\n ],\n sections: [\n {\n name: \"Overview\",\n fileName: \"overview.md\",\n required: true,\n defaultContent: `# Overview\n\n## Role\nProduct Manager\n\n## Product Area\n<!-- Your product area -->\n\n## Key Metrics\n<!-- North star and supporting metrics -->\n\n## Current Quarter Goals\n<!-- OKRs or key goals -->\n`\n },\n {\n name: \"Responsibilities\",\n fileName: \"responsibilities.md\",\n required: true,\n defaultContent: `# Responsibilities\n\n## Product Areas\n<!-- Products/features you own -->\n\n## Decision Authority\n<!-- What you can decide vs. escalate -->\n\n## Regular Meetings\n<!-- Recurring meetings and cadences -->\n`\n },\n {\n name: \"Stakeholders\",\n fileName: \"stakeholders.md\",\n required: false,\n defaultContent: `# Stakeholders\n\n## Engineering Leads\n<!-- Engineering partners -->\n\n## Design Partners\n<!-- Design team contacts -->\n\n## Business Stakeholders\n<!-- Sales, marketing, exec sponsors -->\n\n## Customers\n<!-- Key customer contacts or segments -->\n`\n },\n {\n name: \"Documentation\",\n fileName: \"docs.md\",\n required: false,\n defaultContent: `# Documentation References\n\n## PRDs\n<!-- Product requirement documents -->\n\n## Roadmap\n<!-- Roadmap links -->\n\n## Analytics Dashboards\n<!-- Links to dashboards -->\n`\n }\n ]\n },\n \"engineering-manager\": {\n profileType: \"engineering-manager\",\n name: \"Engineering Manager\",\n description: \"Context template for engineering managers\",\n responsibilities: [\n \"Team management and 1:1s\",\n \"Hiring and interviewing\",\n \"Performance reviews\",\n \"Technical strategy\",\n \"Cross-team coordination\",\n \"Sprint planning and velocity\",\n \"Incident management\",\n \"Budget and resource planning\",\n \"Career development coaching\",\n \"Process improvement\"\n ],\n sections: [\n {\n name: \"Overview\",\n fileName: \"overview.md\",\n required: true,\n defaultContent: `# Overview\n\n## Role\nEngineering Manager\n\n## Team\n<!-- Team name and size -->\n\n## Charter\n<!-- Team charter / mission -->\n\n## Key Systems\n<!-- Systems your team owns -->\n`\n },\n {\n name: \"Responsibilities\",\n fileName: \"responsibilities.md\",\n required: true,\n defaultContent: `# Responsibilities\n\n## People Management\n<!-- Direct reports, 1:1 cadence -->\n\n## Technical Oversight\n<!-- Architecture, code quality, tech debt -->\n\n## Process\n<!-- Agile ceremonies, team rituals -->\n\n## Hiring\n<!-- Open roles, pipeline -->\n`\n },\n {\n name: \"Stakeholders\",\n fileName: \"stakeholders.md\",\n required: false,\n defaultContent: `# Stakeholders\n\n## Direct Reports\n<!-- Team members -->\n\n## Skip Level\n<!-- Your manager -->\n\n## Product Partners\n<!-- PMs you work with -->\n\n## Peer Managers\n<!-- Other EMs -->\n`\n },\n {\n name: \"Documentation\",\n fileName: \"docs.md\",\n required: false,\n defaultContent: `# Documentation References\n\n## Team Docs\n<!-- Team wiki, confluence pages -->\n\n## Process Docs\n<!-- Runbooks, playbooks -->\n\n## HR Resources\n<!-- Performance review templates, etc. -->\n`\n }\n ]\n },\n devops: {\n profileType: \"devops\",\n name: \"DevOps Engineer\",\n description: \"Context template for DevOps engineers\",\n responsibilities: [\n \"CI/CD pipeline management\",\n \"Infrastructure as code\",\n \"Monitoring and alerting\",\n \"Incident response\",\n \"Security compliance\",\n \"Cost optimization\",\n \"Deployment automation\",\n \"Container orchestration\",\n \"Database management\",\n \"Disaster recovery planning\"\n ],\n sections: [\n {\n name: \"Overview\",\n fileName: \"overview.md\",\n required: true,\n defaultContent: `# Overview\n\n## Role\nDevOps Engineer\n\n## Infrastructure\n<!-- Cloud provider, key services -->\n\n## Key Environments\n<!-- Production, staging, dev -->\n\n## Monitoring Stack\n<!-- Tools and dashboards -->\n`\n },\n {\n name: \"Responsibilities\",\n fileName: \"responsibilities.md\",\n required: true,\n defaultContent: `# Responsibilities\n\n## Infrastructure\n<!-- IaC, cloud resources -->\n\n## CI/CD\n<!-- Pipelines, deployment processes -->\n\n## On-Call\n<!-- PagerDuty, escalation paths -->\n\n## Security\n<!-- Compliance, access management -->\n`\n },\n {\n name: \"Stakeholders\",\n fileName: \"stakeholders.md\",\n required: false,\n defaultContent: `# Stakeholders\n\n## Platform Team\n<!-- Team members -->\n\n## Engineering Teams\n<!-- Teams you support -->\n\n## Security Team\n<!-- Security contacts -->\n\n## Vendor Contacts\n<!-- Cloud, tooling vendors -->\n`\n },\n {\n name: \"Documentation\",\n fileName: \"docs.md\",\n required: false,\n defaultContent: `# Documentation References\n\n## Runbooks\n<!-- Incident response runbooks -->\n\n## Architecture Diagrams\n<!-- Infrastructure diagrams -->\n\n## Compliance Docs\n<!-- SOC2, security policies -->\n`\n }\n ]\n }\n};\nfunction getTemplate(profileType) {\n const template = PROFILE_TEMPLATES[profileType];\n if (!template) {\n throw new Error(`Unknown profile type: ${profileType}`);\n }\n return { ...template };\n}\nfunction listProfiles() {\n return Object.keys(PROFILE_TEMPLATES);\n}\nfunction getResponsibilities(profileType) {\n const template = PROFILE_TEMPLATES[profileType];\n if (!template) {\n throw new Error(`Unknown profile type: ${profileType}`);\n }\n return [...template.responsibilities];\n}\nfunction renderTemplate(template, user) {\n const files = {};\n for (const section of template.sections) {\n let content = section.defaultContent;\n content = content.replace(\"<!-- Your team name -->\", `${user.name}'s team`);\n if (section.fileName === \"responsibilities.md\" && user.responsibilities.length > 0) {\n content += \"\\n## Selected Responsibilities\\n\";\n for (const r of user.responsibilities) {\n content += `- ${r}\n`;\n }\n }\n files[section.fileName] = content;\n }\n return files;\n}\nfunction getTemplateSections(profileType) {\n const template = PROFILE_TEMPLATES[profileType];\n if (!template) {\n throw new Error(`Unknown profile type: ${profileType}`);\n }\n return template.sections.map((s) => ({ ...s }));\n}\nexport {\n getResponsibilities,\n getTemplate,\n getTemplateSections,\n listProfiles,\n renderTemplate\n};\n"],"mappings":"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AA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAmVT;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/onboarding-server.ts","../../template-engine/dist/index.js"],"sourcesContent":["import express from 'express';\nimport * as path from 'node:path';\nimport * as fs from 'node:fs/promises';\nimport { exec } from 'node:child_process';\nimport { promisify } from 'node:util';\n\nconst execAsync = promisify(exec);\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 {\n getTemplate,\n renderTemplate,\n listProfiles,\n getResponsibilities,\n} from '@personal-assistant/template-engine';\nimport { validateIntegrationConfig } from '@personal-assistant/integration-runtime';\nimport { createSlackConnector, validateSlackAppToken } from '@personal-assistant/integrations-slack';\nimport { createNoopEventClient } from '@personal-assistant/event-client';\nimport type {\n AppConfig,\n LlmProvider,\n ProfileType,\n UserProfile,\n StorageConfig,\n GDriveStorageConfig,\n IntegrationConfig,\n SyncConfig,\n} from '@personal-assistant/core-types';\nimport { validateProviderConfig } from './provider-runtime.js';\n\ninterface GDriveAuthSession {\n clientId: string;\n clientSecret: string;\n status: 'pending' | 'authenticated' | 'complete' | 'error';\n // set after OAuth callback\n accessToken?: string;\n refreshToken?: string;\n // set after folder creation\n folderId?: string;\n folderName?: string;\n folderPath?: string;\n error?: string;\n}\n\nexport async function startOnboardingServer(\n port: number,\n workspacePath: string,\n): Promise<void> {\n const app = express();\n app.use(express.json());\n\n let gdriveAuthSession: GDriveAuthSession | null = null;\n\n // Serve static files from onboarding-web dist\n const staticPath = path.resolve(\n import.meta.dirname ?? __dirname,\n '../../../apps/onboarding-web/dist',\n );\n\n // Try to serve built static files; fallback to inline HTML\n try {\n await fs.access(staticPath);\n app.use(express.static(staticPath));\n } catch {\n // Serve inline onboarding page if the web app isn't built\n app.get('/', (_req, res) => {\n res.send(getInlineOnboardingHtml());\n });\n }\n\n // --- API Routes ---\n\n app.get('/api/profiles', (_req, res) => {\n const profiles = listProfiles();\n res.json({ profiles });\n });\n\n app.get('/api/responsibilities/:profileType', (req, res) => {\n try {\n const responsibilities = getResponsibilities(req.params.profileType as ProfileType);\n res.json({ responsibilities });\n } catch {\n res.status(400).json({ error: 'Invalid profile type' });\n }\n });\n\n app.get('/api/template/:profileType', (req, res) => {\n try {\n const template = getTemplate(req.params.profileType as ProfileType);\n res.json({ template });\n } catch {\n res.status(400).json({ error: 'Invalid profile type' });\n }\n });\n\n app.post('/api/preview-template', (req, res) => {\n const { profileType, name, assistantName, responsibilities } = req.body;\n try {\n const template = getTemplate(profileType);\n const files = renderTemplate(template, { name, assistantName, responsibilities });\n res.json({ files });\n } catch (err) {\n res.status(400).json({ error: String(err) });\n }\n });\n\n app.post('/api/save', async (req, res) => {\n try {\n const config: AppConfig = req.body;\n\n // Use the user-chosen local path if provided, otherwise fall back to CLI --dir\n const effectivePath =\n config.storage.mode === 'local' && (config.storage as { workspacePath?: string }).workspacePath\n ? path.resolve((config.storage as { workspacePath: string }).workspacePath)\n : workspacePath;\n\n // Ensure the local directory exists (needed for bootstrap even in GDrive mode)\n await fs.mkdir(effectivePath, { recursive: true });\n\n // Save a global pointer so CLI commands can find the workspace without --dir\n const rcPath = path.join(process.env.HOME ?? process.env.USERPROFILE ?? '~', '.personal-assistant-rc.json');\n await fs.writeFile(rcPath, JSON.stringify({ workspacePath: effectivePath }, null, 2), 'utf-8');\n\n // Always save storage.json locally for bootstrap (so MCP server knows which backend to use)\n const localStorage = createLocalStorage(effectivePath);\n const localConfigManager = createConfigManager(localStorage);\n await localConfigManager.saveConfig(config);\n\n // Resolve the user's chosen storage backend\n let targetStorage: import('@personal-assistant/core-types').StorageBackend = localStorage;\n if (config.storage.mode === 'gdrive') {\n const gdriveConfig = config.storage as GDriveStorageConfig;\n const resolvedCachePath = path.isAbsolute(gdriveConfig.cachePath)\n ? gdriveConfig.cachePath\n : path.resolve(path.dirname(effectivePath), gdriveConfig.cachePath);\n\n const gdriveStorage = createGDriveStorage({\n ...gdriveConfig,\n cachePath: resolvedCachePath,\n });\n await gdriveStorage.initialize();\n targetStorage = gdriveStorage;\n\n // Write config to GDrive so all reads go through GDrive\n const gdriveConfigManager = createConfigManager(gdriveStorage);\n await gdriveConfigManager.saveConfig(config);\n }\n\n const contextManager = createContextManager(targetStorage);\n\n // Initialize workspace structure on the target backend\n await contextManager.initWorkspace();\n\n // Render and write template files to the target backend\n const template = getTemplate(config.user.profileType);\n const files = renderTemplate(template, {\n name: config.user.name,\n assistantName: config.user.assistantName,\n responsibilities: config.user.responsibilities,\n });\n await contextManager.writeCanonicalFiles(files);\n\n // Emit onboarding completed event\n const eventClient = createNoopEventClient();\n await eventClient.emit('onboarding_completed', {\n profile: config.user.profileType,\n storage_mode: config.storage.mode,\n });\n\n res.json({ success: true, workspacePath: effectivePath });\n } catch (err) {\n res.status(500).json({ error: String(err) });\n }\n });\n\n // --- Integration credential validation ---\n\n app.post('/api/validate-integration', async (req, res) => {\n const { type, credentials } = req.body as {\n type: string;\n credentials: Record<string, string>;\n };\n\n try {\n const result = await validateIntegrationConfig({\n type: type as IntegrationConfig['type'],\n enabled: true,\n credentials,\n });\n\n if (result.ok) {\n res.json({ valid: true, info: result.summary ?? `Connected to ${type}` });\n return;\n }\n\n res.json({\n valid: false,\n error: [result.reason, ...(result.fix ?? [])].filter(Boolean).join(' '),\n });\n } catch (err) {\n res.json({ valid: false, error: String(err) });\n }\n });\n\n app.post('/api/validate-provider', async (req, res) => {\n const { provider, apiKey, model } = req.body as {\n provider: LlmProvider;\n apiKey: string;\n model?: string;\n };\n\n try {\n const result = await validateProviderConfig(provider, apiKey, model);\n res.json(result);\n } catch (err) {\n res.json({ valid: false, error: String(err) });\n }\n });\n\n app.post('/api/validate-slack-runtime', async (req, res) => {\n const {\n botToken,\n appToken,\n generationEnabled,\n providers,\n } = req.body as {\n botToken?: string;\n appToken?: string;\n generationEnabled?: boolean;\n providers?: {\n openai?: { apiKey?: string; model?: string };\n anthropic?: { apiKey?: string; model?: string };\n };\n };\n\n if (!botToken || !appToken) {\n res.json({ valid: false, error: 'Slack bot token and app token are required.' });\n return;\n }\n\n if (!botToken.startsWith('xoxb-')) {\n res.json({\n valid: false,\n error: 'Slack bot token must start with xoxb-. Paste the Bot User OAuth Token from OAuth & Permissions.',\n });\n return;\n }\n\n if (!appToken.startsWith('xapp-')) {\n res.json({\n valid: false,\n error: 'Slack Socket Mode app token must start with xapp-. Create an App-Level Token with connections:write under Socket Mode.',\n });\n return;\n }\n\n try {\n const connector = createSlackConnector();\n await connector.authenticate({\n type: 'slack',\n enabled: true,\n credentials: { botToken },\n });\n const health = await connector.healthCheck();\n await validateSlackAppToken(appToken);\n\n if (generationEnabled) {\n const providerEntries = [\n ['openai', providers?.openai],\n ['anthropic', providers?.anthropic],\n ] as const;\n\n const configuredProviders = providerEntries.filter(([, value]) => value?.apiKey);\n if (configuredProviders.length === 0) {\n res.json({ valid: false, error: 'Enable at least one provider when Slack generation is turned on.' });\n return;\n }\n\n for (const [provider, value] of configuredProviders) {\n const result = await validateProviderConfig(provider, value?.apiKey ?? '', value?.model);\n if (!result.valid) {\n res.json({ valid: false, error: result.error ?? `Failed to validate ${provider}` });\n return;\n }\n }\n }\n\n res.json({\n valid: true,\n info: `${health.summary ?? 'Slack connected'} via Socket Mode. Atlas will monitor channels where the bot is added.`,\n });\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n if (message.includes('not_allowed_token_type')) {\n res.json({\n valid: false,\n error: 'Slack rejected the Socket Mode token. Use an App-Level Token that starts with xapp- and has the connections:write scope.',\n });\n return;\n }\n\n res.json({\n valid: false,\n error: message,\n });\n }\n });\n\n // --- Local folder picker ---\n\n app.get('/api/pick-folder', async (_req, res) => {\n try {\n let folderPath: string;\n const platform = process.platform;\n\n if (platform === 'darwin') {\n const { stdout } = await execAsync(\n `osascript -e 'POSIX path of (choose folder with prompt \"Select a folder for your personal assistant context\")'`,\n );\n folderPath = stdout.trim();\n } else if (platform === 'linux') {\n const { stdout } = await execAsync(\n 'zenity --file-selection --directory --title=\"Select storage folder\"',\n );\n folderPath = stdout.trim();\n } else if (platform === 'win32') {\n const ps =\n '[System.Reflection.Assembly]::LoadWithPartialName(\\'System.windows.forms\\') | Out-Null; ' +\n '$f = New-Object System.Windows.Forms.FolderBrowserDialog; ' +\n '$f.Description = \\'Select a folder for your personal assistant context\\'; ' +\n '$f.ShowDialog() | Out-Null; $f.SelectedPath';\n const { stdout } = await execAsync(`powershell -command \"${ps}\"`);\n folderPath = stdout.trim();\n } else {\n res.status(400).json({ error: 'Folder picker not supported on this platform' });\n return;\n }\n\n if (!folderPath) {\n res.json({ cancelled: true });\n return;\n }\n\n res.json({ path: folderPath });\n } catch (err) {\n // osascript throws when the user clicks Cancel — treat as cancellation\n if (String(err).includes('User canceled') || String(err).includes('cancel')) {\n res.json({ cancelled: true });\n return;\n }\n res.status(500).json({ error: String(err) });\n }\n });\n\n // --- Google Drive OAuth routes ---\n\n app.post('/api/gdrive/auth-start', async (req, res) => {\n const { clientId, clientSecret } = req.body as { clientId?: string; clientSecret?: string };\n if (!clientId || !clientSecret) {\n res.status(400).json({ error: 'clientId and clientSecret are required' });\n return;\n }\n\n try {\n const { google } = await import('googleapis');\n const redirectUri = `http://localhost:${port}/api/gdrive/callback`;\n const oauth2Client = new google.auth.OAuth2(clientId, clientSecret, redirectUri);\n const authUrl = oauth2Client.generateAuthUrl({\n access_type: 'offline',\n prompt: 'consent',\n scope: ['https://www.googleapis.com/auth/drive.file'],\n });\n\n gdriveAuthSession = { clientId, clientSecret, status: 'pending' };\n res.json({ authUrl });\n } catch (err) {\n res.status(500).json({ error: String(err) });\n }\n });\n\n app.get('/api/gdrive/callback', async (req, res) => {\n const { code } = req.query as { code?: string };\n\n if (!code || !gdriveAuthSession) {\n res.status(400).send('Invalid OAuth callback — no pending auth session.');\n return;\n }\n\n try {\n const { google } = await import('googleapis');\n const redirectUri = `http://localhost:${port}/api/gdrive/callback`;\n const oauth2Client = new google.auth.OAuth2(\n gdriveAuthSession.clientId,\n gdriveAuthSession.clientSecret,\n redirectUri,\n );\n\n const { tokens } = await oauth2Client.getToken(code);\n\n // Store tokens only — folder is created in a separate step\n gdriveAuthSession = {\n ...gdriveAuthSession,\n status: 'authenticated',\n refreshToken: tokens.refresh_token ?? undefined,\n accessToken: tokens.access_token ?? undefined,\n };\n\n res.send(`<!DOCTYPE html><html><body>\n <script>window.close();</script>\n <p style=\"font-family:sans-serif;padding:2rem;color:#4ade80;\">\n ✓ Authentication successful — you can close this tab and return to the setup.\n </p>\n </body></html>`);\n } catch (err) {\n if (gdriveAuthSession) {\n gdriveAuthSession.status = 'error';\n gdriveAuthSession.error = String(err);\n }\n res.status(500).send('Authentication failed: ' + String(err));\n }\n });\n\n app.get('/api/gdrive/auth-status', (_req, res) => {\n if (!gdriveAuthSession) {\n res.json({ status: 'idle' });\n return;\n }\n const { clientId: _cid, clientSecret: _csec, accessToken: _at, refreshToken: _rt, ...publicSession } = gdriveAuthSession;\n res.json(publicSession);\n });\n\n app.post('/api/gdrive/create-folder', async (req, res) => {\n if (!gdriveAuthSession || gdriveAuthSession.status !== 'authenticated') {\n res.status(400).json({ error: 'Not authenticated. Please connect Google Drive first.' });\n return;\n }\n\n const { folderName = 'Personal Assistant', parentFolderName = '' } =\n req.body as { folderName?: string; parentFolderName?: string };\n\n try {\n const { google } = await import('googleapis');\n const redirectUri = `http://localhost:${port}/api/gdrive/callback`;\n const oauth2Client = new google.auth.OAuth2(\n gdriveAuthSession.clientId,\n gdriveAuthSession.clientSecret,\n redirectUri,\n );\n oauth2Client.setCredentials({\n access_token: gdriveAuthSession.accessToken,\n refresh_token: gdriveAuthSession.refreshToken,\n });\n\n const drive = google.drive({ version: 'v3', auth: oauth2Client });\n\n // Resolve parent folder\n let parentId = 'root';\n let locationPath = 'My Drive';\n\n if (parentFolderName.trim()) {\n const searchRes = await drive.files.list({\n q: `name='${parentFolderName.trim()}' and mimeType='application/vnd.google-apps.folder' and trashed=false`,\n fields: 'files(id,name)',\n spaces: 'drive',\n });\n\n if (searchRes.data.files && searchRes.data.files.length > 0) {\n parentId = searchRes.data.files[0].id!;\n } else {\n // Create the parent folder at root\n const parentRes = await drive.files.create({\n requestBody: {\n name: parentFolderName.trim(),\n mimeType: 'application/vnd.google-apps.folder',\n },\n fields: 'id',\n });\n parentId = parentRes.data.id!;\n }\n locationPath = `My Drive / ${parentFolderName.trim()}`;\n }\n\n // Check if the main folder already exists under the parent before creating\n let folderId: string | undefined;\n let resolvedFolderName = folderName.trim();\n const existingSearch = await drive.files.list({\n q: `name='${resolvedFolderName}' and '${parentId}' in parents and mimeType='application/vnd.google-apps.folder' and trashed=false`,\n fields: 'files(id,name)',\n spaces: 'drive',\n });\n\n if (existingSearch.data.files && existingSearch.data.files.length > 0) {\n folderId = existingSearch.data.files[0].id!;\n resolvedFolderName = existingSearch.data.files[0].name!;\n } else {\n const folderRes = await drive.files.create({\n requestBody: {\n name: resolvedFolderName,\n mimeType: 'application/vnd.google-apps.folder',\n parents: [parentId],\n },\n fields: 'id,name',\n });\n folderId = folderRes.data.id!;\n resolvedFolderName = folderRes.data.name!;\n }\n\n const folderPath = `${locationPath} / ${resolvedFolderName}`;\n\n // Refresh tokens in case they were rotated\n const freshCredentials = await oauth2Client.getAccessToken();\n const latestRefreshToken =\n (oauth2Client.credentials.refresh_token as string | undefined) ??\n gdriveAuthSession.refreshToken;\n\n gdriveAuthSession = {\n ...gdriveAuthSession,\n status: 'complete',\n folderId: folderId!,\n folderName: resolvedFolderName,\n folderPath,\n refreshToken: latestRefreshToken,\n accessToken: freshCredentials.token ?? undefined,\n };\n\n res.json({\n folderId,\n folderName: resolvedFolderName,\n folderPath,\n refreshToken: latestRefreshToken,\n });\n } catch (err) {\n res.status(500).json({ error: String(err) });\n }\n });\n\n app.get('/api/status', async (_req, res) => {\n const storage = createLocalStorage(workspacePath);\n const configManager = createConfigManager(storage);\n try {\n const config = await configManager.loadConfig();\n res.json({ configured: true, config });\n } catch {\n res.json({ configured: false });\n }\n });\n\n // Start server\n const server = app.listen(port, () => {\n const url = `http://localhost:${port}`;\n console.log(`Onboarding server running at ${url}`);\n\n // Try to open browser\n import('open')\n .then((openModule) => openModule.default(url))\n .catch(() => {\n console.log(`Open ${url} in your browser to continue.`);\n });\n });\n\n // Handle graceful shutdown\n process.on('SIGINT', () => {\n console.log('\\nShutting down onboarding server...');\n server.close();\n process.exit(0);\n });\n}\n\nfunction getInlineOnboardingHtml(): string {\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>Personal Assistant - Setup</title>\n <style>\n * { margin: 0; padding: 0; box-sizing: border-box; }\n body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; background: #0f172a; color: #e2e8f0; min-height: 100vh; }\n .container { max-width: 640px; margin: 0 auto; padding: 2rem; }\n h1 { font-size: 1.8rem; margin-bottom: 0.5rem; color: #f8fafc; }\n h2 { font-size: 1.2rem; margin-bottom: 1rem; color: #94a3b8; font-weight: 400; }\n .step { display: none; }\n .step.active { display: block; }\n .progress { display: flex; gap: 0.5rem; margin-bottom: 2rem; }\n .progress-dot { width: 2rem; height: 0.25rem; background: #334155; border-radius: 2px; transition: background 0.3s; }\n .progress-dot.done { background: #3b82f6; }\n .progress-dot.current { background: #60a5fa; }\n label { display: block; margin-bottom: 0.5rem; color: #cbd5e1; font-size: 0.9rem; }\n input, select, textarea { width: 100%; padding: 0.75rem; background: #1e293b; border: 1px solid #334155; border-radius: 0.5rem; color: #f8fafc; font-size: 1rem; margin-bottom: 1rem; }\n input:focus, select:focus, textarea:focus { outline: none; border-color: #3b82f6; }\n textarea { min-height: 200px; font-family: 'SF Mono', 'Fira Code', monospace; font-size: 0.85rem; }\n button { padding: 0.75rem 1.5rem; border: none; border-radius: 0.5rem; font-size: 1rem; cursor: pointer; transition: all 0.2s; }\n .btn-primary { background: #3b82f6; color: white; }\n .btn-primary:hover { background: #2563eb; }\n .btn-secondary { background: #334155; color: #e2e8f0; }\n .btn-secondary:hover { background: #475569; }\n .btn-group { display: flex; gap: 0.75rem; margin-top: 1.5rem; }\n .checkbox-group { display: grid; grid-template-columns: 1fr 1fr; gap: 0.5rem; margin-bottom: 1rem; }\n .checkbox-item { display: flex; align-items: center; gap: 0.5rem; padding: 0.5rem; background: #1e293b; border: 1px solid #334155; border-radius: 0.375rem; cursor: pointer; }\n .checkbox-item:hover { border-color: #475569; }\n .checkbox-item input[type=\"checkbox\"] { width: auto; margin: 0; }\n .radio-group { display: flex; gap: 1rem; margin-bottom: 1rem; }\n .radio-item { flex: 1; padding: 1rem; background: #1e293b; border: 2px solid #334155; border-radius: 0.5rem; cursor: pointer; text-align: center; transition: all 0.2s; }\n .radio-item:hover { border-color: #475569; }\n .radio-item.selected { border-color: #3b82f6; background: #1e3a5f; }\n .success { text-align: center; padding: 3rem 0; }\n .success h2 { color: #4ade80; font-size: 1.5rem; }\n </style>\n</head>\n<body>\n <div class=\"container\">\n <div class=\"progress\" id=\"progress\"></div>\n\n <!-- Step 1: Identity -->\n <div class=\"step active\" data-step=\"0\">\n <h1>Welcome</h1>\n <h2>Let's set up your personal assistant</h2>\n <label>Your Name</label>\n <input type=\"text\" id=\"userName\" placeholder=\"Jane Smith\">\n <label>Assistant Name</label>\n <input type=\"text\" id=\"assistantName\" placeholder=\"Atlas\" value=\"Atlas\">\n <label>Profile</label>\n <select id=\"profileType\">\n <option value=\"software-engineer\">Software Engineer</option>\n <option value=\"product-manager\">Product Manager</option>\n <option value=\"engineering-manager\">Engineering Manager</option>\n <option value=\"devops\">DevOps Engineer</option>\n </select>\n <div class=\"btn-group\"><button class=\"btn-primary\" onclick=\"nextStep()\">Continue</button></div>\n </div>\n\n <!-- Step 2: Responsibilities -->\n <div class=\"step\" data-step=\"1\">\n <h1>Responsibilities</h1>\n <h2>Select your core responsibilities</h2>\n <div class=\"checkbox-group\" id=\"responsibilitiesGroup\"></div>\n <div class=\"btn-group\">\n <button class=\"btn-secondary\" onclick=\"prevStep()\">Back</button>\n <button class=\"btn-primary\" onclick=\"nextStep()\">Continue</button>\n </div>\n </div>\n\n <!-- Step 3: Template Preview -->\n <div class=\"step\" data-step=\"2\">\n <h1>Context Template</h1>\n <h2>Preview and customize your context template</h2>\n <textarea id=\"templatePreview\"></textarea>\n <div class=\"btn-group\">\n <button class=\"btn-secondary\" onclick=\"prevStep()\">Back</button>\n <button class=\"btn-primary\" onclick=\"nextStep()\">Continue</button>\n </div>\n </div>\n\n <!-- Step 4: Storage -->\n <div class=\"step\" data-step=\"3\">\n <h1>Storage</h1>\n <h2>Where should your context be stored?</h2>\n <div class=\"radio-group\">\n <div class=\"radio-item selected\" onclick=\"selectStorage('local')\" id=\"storage-local\">\n <strong>Local Workspace</strong><br><small>Files stored on this machine</small>\n </div>\n <div class=\"radio-item\" onclick=\"selectStorage('gdrive')\" id=\"storage-gdrive\">\n <strong>Google Drive</strong><br><small>Files stored in your Drive folder</small>\n </div>\n </div>\n <div id=\"storage-local-fields\">\n <label>Storage path</label>\n <div style=\"display:flex;gap:0.5rem;align-items:center;\">\n <input type=\"text\" id=\"localPath\" value=\".personal-assistant\" placeholder=\".personal-assistant\" style=\"flex:1;margin-bottom:0;\">\n <button class=\"btn-secondary\" onclick=\"browseFolder()\" id=\"browseBtn\" style=\"white-space:nowrap;flex-shrink:0;\">Browse</button>\n </div>\n <small style=\"color:#64748b;font-size:0.8rem;display:block;margin-top:0.4rem;margin-bottom:1rem;\">Click Browse to open a folder picker, or type a path directly.</small>\n </div>\n <div id=\"storage-gdrive-fields\" style=\"display:none;\">\n <p style=\"color:#f59e0b;font-size:0.85rem;margin-bottom:1rem;\">\n Google Drive OAuth is only supported in the full onboarding UI.<br>\n Run <code>pnpm build</code> in <code>apps/onboarding-web</code> then restart <code>pacman init</code>.\n </p>\n </div>\n <div style=\"background:#1c1917;border:1px solid #92400e;border-radius:0.5rem;padding:0.75rem 1rem;margin-bottom:1.5rem;font-size:0.85rem;color:#fbbf24;\">\n ⚠️ Do not delete, move, or rename the folder structure created by this setup. Claude and the sync daemon rely on the exact file layout to load and update your context.\n </div>\n <div class=\"btn-group\">\n <button class=\"btn-secondary\" onclick=\"prevStep()\">Back</button>\n <button class=\"btn-primary\" onclick=\"nextStep()\">Continue</button>\n </div>\n </div>\n\n <!-- Step 5: Integrations -->\n <div class=\"step\" data-step=\"4\">\n <h1>Integrations</h1>\n <h2>Connect your tools (optional)</h2>\n <div class=\"checkbox-group\" id=\"integrationsGroup\">\n <label class=\"checkbox-item\"><input type=\"checkbox\" value=\"slack\"> Slack</label>\n <label class=\"checkbox-item\"><input type=\"checkbox\" value=\"gmail\"> Gmail</label>\n <label class=\"checkbox-item\"><input type=\"checkbox\" value=\"github\"> GitHub</label>\n <label class=\"checkbox-item\"><input type=\"checkbox\" value=\"gitlab\"> GitLab</label>\n <label class=\"checkbox-item\"><input type=\"checkbox\" value=\"gdrive\"> Google Drive Docs</label>\n <label class=\"checkbox-item\"><input type=\"checkbox\" value=\"gchat\"> Google Chat</label>\n </div>\n <div class=\"btn-group\">\n <button class=\"btn-secondary\" onclick=\"prevStep()\">Back</button>\n <button class=\"btn-primary\" onclick=\"nextStep()\">Continue</button>\n </div>\n </div>\n\n <!-- Step 6: Sync Schedule -->\n <div class=\"step\" data-step=\"5\">\n <h1>Sync Schedule</h1>\n <h2>When should context be refreshed?</h2>\n <label>Daily Sync Time</label>\n <input type=\"time\" id=\"syncTime\" value=\"08:00\">\n <label>Timezone</label>\n <select id=\"timezone\">\n <option value=\"America/New_York\">Eastern Time (ET)</option>\n <option value=\"America/Chicago\">Central Time (CT)</option>\n <option value=\"America/Denver\">Mountain Time (MT)</option>\n <option value=\"America/Los_Angeles\">Pacific Time (PT)</option>\n <option value=\"UTC\">UTC</option>\n <option value=\"Europe/London\">London (GMT/BST)</option>\n <option value=\"Europe/Berlin\">Berlin (CET)</option>\n <option value=\"Asia/Tokyo\">Tokyo (JST)</option>\n <option value=\"Asia/Kolkata\">India (IST)</option>\n <option value=\"Australia/Sydney\">Sydney (AEST)</option>\n </select>\n <div class=\"checkbox-group\">\n <label class=\"checkbox-item\"><input type=\"checkbox\" id=\"manualSync\" checked> Manual sync</label>\n <label class=\"checkbox-item\"><input type=\"checkbox\" id=\"asyncUpdate\" checked> Async updates</label>\n </div>\n <div class=\"btn-group\">\n <button class=\"btn-secondary\" onclick=\"prevStep()\">Back</button>\n <button class=\"btn-primary\" onclick=\"nextStep()\">Continue</button>\n </div>\n </div>\n\n <!-- Step 7: Finish -->\n <div class=\"step\" data-step=\"6\">\n <h1>All Set!</h1>\n <h2>Review and save your configuration</h2>\n <div id=\"summary\" style=\"background:#1e293b;padding:1rem;border-radius:0.5rem;margin-bottom:1rem;font-family:monospace;font-size:0.85rem;white-space:pre-wrap;\"></div>\n <div class=\"btn-group\">\n <button class=\"btn-secondary\" onclick=\"prevStep()\">Back</button>\n <button class=\"btn-primary\" onclick=\"saveConfig()\">Save & Finish</button>\n </div>\n </div>\n\n <!-- Success -->\n <div class=\"step\" data-step=\"7\">\n <div class=\"success\">\n <h2>Setup Complete!</h2>\n <p style=\"margin-top:1rem;color:#94a3b8;\">Your personal assistant context has been initialized.</p>\n <p style=\"margin-top:1rem;color:#94a3b8;\">Next steps:</p>\n <pre style=\"text-align:left;margin-top:1rem;background:#1e293b;padding:1rem;border-radius:0.5rem;font-size:0.85rem;\">\n# Install Claude Code integration\npacman claude install\npacman mcp claude install\n\n# Install Codex integration\npacman codex install\npacman mcp codex install\n\n# Start the sync daemon\npacman daemon\n\n# Start the real-time Slack listener\npacman slack listen\n\n# Use in Claude Code\n/personal-assistant start <project>\n\n# Use in Codex\nAsk Codex to load or refresh your Personal Assistant context for <project></pre>\n <p style=\"margin-top:1rem;color:#64748b;font-size:0.85rem;\">Restart Claude Code or Codex after installing the MCP server.<br>If <code style=\"background:#1e293b;padding:0 4px;border-radius:3px;\">pacman</code> is not found, link it first. The legacy alias <code style=\"background:#1e293b;padding:0 4px;border-radius:3px;\">personal-assistant</code> also remains available:<br>\n <code style=\"background:#1e293b;padding:2px 6px;border-radius:3px;\">pnpm setup && source ~/.zshrc && cd packages/cli && pnpm link --global</code></p>\n </div>\n </div>\n </div>\n\n <script>\n let currentStep = 0;\n const totalSteps = 7;\n let state = { storageMode: 'local', responsibilities: [] };\n\n function updateProgress() {\n const bar = document.getElementById('progress');\n bar.innerHTML = '';\n for (let i = 0; i < totalSteps; i++) {\n const dot = document.createElement('div');\n dot.className = 'progress-dot' + (i < currentStep ? ' done' : i === currentStep ? ' current' : '');\n bar.appendChild(dot);\n }\n }\n\n function showStep(n) {\n document.querySelectorAll('.step').forEach(s => s.classList.remove('active'));\n document.querySelector('[data-step=\"' + n + '\"]').classList.add('active');\n currentStep = n;\n updateProgress();\n }\n\n async function nextStep() {\n if (currentStep === 0) await loadResponsibilities();\n if (currentStep === 1) await loadTemplatePreview();\n if (currentStep === 5) updateSummary();\n showStep(currentStep + 1);\n }\n\n function prevStep() { showStep(currentStep - 1); }\n\n async function loadResponsibilities() {\n const profileType = document.getElementById('profileType').value;\n const res = await fetch('/api/responsibilities/' + profileType);\n const data = await res.json();\n const group = document.getElementById('responsibilitiesGroup');\n group.innerHTML = data.responsibilities.map(r =>\n '<label class=\"checkbox-item\"><input type=\"checkbox\" value=\"' + r + '\" checked> ' + r + '</label>'\n ).join('');\n }\n\n async function loadTemplatePreview() {\n const profileType = document.getElementById('profileType').value;\n const name = document.getElementById('userName').value;\n const assistantName = document.getElementById('assistantName').value;\n const responsibilities = Array.from(document.querySelectorAll('#responsibilitiesGroup input:checked')).map(c => c.value);\n state.responsibilities = responsibilities;\n\n const res = await fetch('/api/preview-template', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ profileType, name, assistantName, responsibilities })\n });\n const data = await res.json();\n const preview = Object.entries(data.files).map(([f, c]) => '--- ' + f + ' ---\\\\n' + c).join('\\\\n\\\\n');\n document.getElementById('templatePreview').value = preview;\n }\n\n function selectStorage(mode) {\n state.storageMode = mode;\n document.querySelectorAll('.radio-item').forEach(r => r.classList.remove('selected'));\n document.getElementById('storage-' + mode).classList.add('selected');\n document.getElementById('storage-local-fields').style.display = mode === 'local' ? 'block' : 'none';\n document.getElementById('storage-gdrive-fields').style.display = mode === 'gdrive' ? 'block' : 'none';\n }\n\n async function browseFolder() {\n const btn = document.getElementById('browseBtn');\n btn.textContent = '…';\n btn.disabled = true;\n try {\n const res = await fetch('/api/pick-folder');\n const data = await res.json();\n if (!data.cancelled && data.path) {\n document.getElementById('localPath').value = data.path;\n }\n } catch (e) {\n // ignore — user can type path manually\n } finally {\n btn.textContent = 'Browse';\n btn.disabled = false;\n }\n }\n\n function updateSummary() {\n const config = buildConfig();\n document.getElementById('summary').textContent = JSON.stringify(config, null, 2);\n }\n\n function buildConfig() {\n const integrations = Array.from(document.querySelectorAll('#integrationsGroup input:checked')).map(c => ({\n type: c.value, enabled: true, credentials: {}, cursor: null, lastSyncAt: null\n }));\n\n return {\n user: {\n name: document.getElementById('userName').value,\n assistantName: document.getElementById('assistantName').value,\n profileType: document.getElementById('profileType').value,\n responsibilities: state.responsibilities\n },\n storage: state.storageMode === 'local'\n ? { mode: 'local', workspacePath: document.getElementById('localPath').value || '.personal-assistant' }\n : { mode: 'gdrive', folderId: '', folderName: 'Personal Assistant', cachePath: '.personal-assistant/cache' },\n integrations,\n sync: {\n dailySyncTime: document.getElementById('syncTime').value,\n timezone: document.getElementById('timezone').value,\n manualSyncEnabled: document.getElementById('manualSync').checked,\n asyncUpdateEnabled: document.getElementById('asyncUpdate').checked\n }\n };\n }\n\n async function saveConfig() {\n const config = buildConfig();\n const res = await fetch('/api/save', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(config)\n });\n const data = await res.json();\n if (data.success) showStep(7);\n else alert('Error: ' + data.error);\n }\n\n updateProgress();\n </script>\n</body>\n</html>`;\n}\n","// src/index.ts\nvar PROFILE_TEMPLATES = {\n \"software-engineer\": {\n profileType: \"software-engineer\",\n name: \"Software Engineer\",\n description: \"Context template for software engineers\",\n responsibilities: [\n \"Code review and PR management\",\n \"Feature development\",\n \"Bug fixing and debugging\",\n \"Architecture decisions\",\n \"Technical documentation\",\n \"On-call and incident response\",\n \"Mentoring junior engineers\",\n \"Sprint planning and estimation\",\n \"CI/CD pipeline maintenance\",\n \"API design and development\"\n ],\n sections: [\n {\n name: \"Overview\",\n fileName: \"overview.md\",\n required: true,\n defaultContent: `# Overview\n\n## Role\nSoftware Engineer\n\n## Team\n<!-- Your team name -->\n\n## Primary Focus\n<!-- Main area of work -->\n\n## Key Repositories\n<!-- List your main repos -->\n\n## Tech Stack\n<!-- Languages, frameworks, tools -->\n`\n },\n {\n name: \"Responsibilities\",\n fileName: \"responsibilities.md\",\n required: true,\n defaultContent: `# Responsibilities\n\n## Core Duties\n<!-- Your primary responsibilities -->\n\n## On-Call\n<!-- On-call schedule and escalation paths -->\n\n## Code Review\n<!-- Review expectations and areas -->\n`\n },\n {\n name: \"Stakeholders\",\n fileName: \"stakeholders.md\",\n required: false,\n defaultContent: `# Stakeholders\n\n## Direct Manager\n<!-- Name, role -->\n\n## Team Members\n<!-- Key teammates -->\n\n## Cross-Team Contacts\n<!-- People you work with in other teams -->\n\n## Escalation Path\n<!-- Who to escalate to and when -->\n`\n },\n {\n name: \"Documentation\",\n fileName: \"docs.md\",\n required: false,\n defaultContent: `# Documentation References\n\n## Internal Docs\n<!-- Links to internal documentation -->\n\n## Runbooks\n<!-- Links to runbooks -->\n\n## Architecture Docs\n<!-- Links to architecture documents -->\n`\n }\n ]\n },\n \"product-manager\": {\n profileType: \"product-manager\",\n name: \"Product Manager\",\n description: \"Context template for product managers\",\n responsibilities: [\n \"Product roadmap management\",\n \"Feature prioritization\",\n \"Stakeholder communication\",\n \"User research and interviews\",\n \"Metrics and KPI tracking\",\n \"Sprint planning and grooming\",\n \"Go-to-market strategy\",\n \"Competitive analysis\",\n \"Cross-team coordination\",\n \"Product requirements documentation\"\n ],\n sections: [\n {\n name: \"Overview\",\n fileName: \"overview.md\",\n required: true,\n defaultContent: `# Overview\n\n## Role\nProduct Manager\n\n## Product Area\n<!-- Your product area -->\n\n## Key Metrics\n<!-- North star and supporting metrics -->\n\n## Current Quarter Goals\n<!-- OKRs or key goals -->\n`\n },\n {\n name: \"Responsibilities\",\n fileName: \"responsibilities.md\",\n required: true,\n defaultContent: `# Responsibilities\n\n## Product Areas\n<!-- Products/features you own -->\n\n## Decision Authority\n<!-- What you can decide vs. escalate -->\n\n## Regular Meetings\n<!-- Recurring meetings and cadences -->\n`\n },\n {\n name: \"Stakeholders\",\n fileName: \"stakeholders.md\",\n required: false,\n defaultContent: `# Stakeholders\n\n## Engineering Leads\n<!-- Engineering partners -->\n\n## Design Partners\n<!-- Design team contacts -->\n\n## Business Stakeholders\n<!-- Sales, marketing, exec sponsors -->\n\n## Customers\n<!-- Key customer contacts or segments -->\n`\n },\n {\n name: \"Documentation\",\n fileName: \"docs.md\",\n required: false,\n defaultContent: `# Documentation References\n\n## PRDs\n<!-- Product requirement documents -->\n\n## Roadmap\n<!-- Roadmap links -->\n\n## Analytics Dashboards\n<!-- Links to dashboards -->\n`\n }\n ]\n },\n \"engineering-manager\": {\n profileType: \"engineering-manager\",\n name: \"Engineering Manager\",\n description: \"Context template for engineering managers\",\n responsibilities: [\n \"Team management and 1:1s\",\n \"Hiring and interviewing\",\n \"Performance reviews\",\n \"Technical strategy\",\n \"Cross-team coordination\",\n \"Sprint planning and velocity\",\n \"Incident management\",\n \"Budget and resource planning\",\n \"Career development coaching\",\n \"Process improvement\"\n ],\n sections: [\n {\n name: \"Overview\",\n fileName: \"overview.md\",\n required: true,\n defaultContent: `# Overview\n\n## Role\nEngineering Manager\n\n## Team\n<!-- Team name and size -->\n\n## Charter\n<!-- Team charter / mission -->\n\n## Key Systems\n<!-- Systems your team owns -->\n`\n },\n {\n name: \"Responsibilities\",\n fileName: \"responsibilities.md\",\n required: true,\n defaultContent: `# Responsibilities\n\n## People Management\n<!-- Direct reports, 1:1 cadence -->\n\n## Technical Oversight\n<!-- Architecture, code quality, tech debt -->\n\n## Process\n<!-- Agile ceremonies, team rituals -->\n\n## Hiring\n<!-- Open roles, pipeline -->\n`\n },\n {\n name: \"Stakeholders\",\n fileName: \"stakeholders.md\",\n required: false,\n defaultContent: `# Stakeholders\n\n## Direct Reports\n<!-- Team members -->\n\n## Skip Level\n<!-- Your manager -->\n\n## Product Partners\n<!-- PMs you work with -->\n\n## Peer Managers\n<!-- Other EMs -->\n`\n },\n {\n name: \"Documentation\",\n fileName: \"docs.md\",\n required: false,\n defaultContent: `# Documentation References\n\n## Team Docs\n<!-- Team wiki, confluence pages -->\n\n## Process Docs\n<!-- Runbooks, playbooks -->\n\n## HR Resources\n<!-- Performance review templates, etc. -->\n`\n }\n ]\n },\n devops: {\n profileType: \"devops\",\n name: \"DevOps Engineer\",\n description: \"Context template for DevOps engineers\",\n responsibilities: [\n \"CI/CD pipeline management\",\n \"Infrastructure as code\",\n \"Monitoring and alerting\",\n \"Incident response\",\n \"Security compliance\",\n \"Cost optimization\",\n \"Deployment automation\",\n \"Container orchestration\",\n \"Database management\",\n \"Disaster recovery planning\"\n ],\n sections: [\n {\n name: \"Overview\",\n fileName: \"overview.md\",\n required: true,\n defaultContent: `# Overview\n\n## Role\nDevOps Engineer\n\n## Infrastructure\n<!-- Cloud provider, key services -->\n\n## Key Environments\n<!-- Production, staging, dev -->\n\n## Monitoring Stack\n<!-- Tools and dashboards -->\n`\n },\n {\n name: \"Responsibilities\",\n fileName: \"responsibilities.md\",\n required: true,\n defaultContent: `# Responsibilities\n\n## Infrastructure\n<!-- IaC, cloud resources -->\n\n## CI/CD\n<!-- Pipelines, deployment processes -->\n\n## On-Call\n<!-- PagerDuty, escalation paths -->\n\n## Security\n<!-- Compliance, access management -->\n`\n },\n {\n name: \"Stakeholders\",\n fileName: \"stakeholders.md\",\n required: false,\n defaultContent: `# Stakeholders\n\n## Platform Team\n<!-- Team members -->\n\n## Engineering Teams\n<!-- Teams you support -->\n\n## Security Team\n<!-- Security contacts -->\n\n## Vendor Contacts\n<!-- Cloud, tooling vendors -->\n`\n },\n {\n name: \"Documentation\",\n fileName: \"docs.md\",\n required: false,\n defaultContent: `# Documentation References\n\n## Runbooks\n<!-- Incident response runbooks -->\n\n## Architecture Diagrams\n<!-- Infrastructure diagrams -->\n\n## Compliance Docs\n<!-- SOC2, security policies -->\n`\n }\n ]\n }\n};\nfunction getTemplate(profileType) {\n const template = PROFILE_TEMPLATES[profileType];\n if (!template) {\n throw new Error(`Unknown profile type: ${profileType}`);\n }\n return { ...template };\n}\nfunction listProfiles() {\n return Object.keys(PROFILE_TEMPLATES);\n}\nfunction getResponsibilities(profileType) {\n const template = PROFILE_TEMPLATES[profileType];\n if (!template) {\n throw new Error(`Unknown profile type: ${profileType}`);\n }\n return [...template.responsibilities];\n}\nfunction renderTemplate(template, user) {\n const files = {};\n for (const section of template.sections) {\n let content = section.defaultContent;\n content = content.replace(\"<!-- Your team name -->\", `${user.name}'s team`);\n if (section.fileName === \"responsibilities.md\" && user.responsibilities.length > 0) {\n content += \"\\n## Selected Responsibilities\\n\";\n for (const r of user.responsibilities) {\n content += `- ${r}\n`;\n }\n }\n files[section.fileName] = content;\n }\n return files;\n}\nfunction getTemplateSections(profileType) {\n const template = PROFILE_TEMPLATES[profileType];\n if (!template) {\n throw new Error(`Unknown profile type: ${profileType}`);\n }\n return template.sections.map((s) => ({ ...s }));\n}\nexport {\n getResponsibilities,\n getTemplate,\n getTemplateSections,\n listProfiles,\n renderTemplate\n};\n"],"mappings":"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A;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAmVT;","names":[]}
|