appostle-installer 0.0.13 → 0.0.14

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/worker.js CHANGED
@@ -16,10 +16,10 @@ __export(rightfont_service_exports, {
16
16
  isRightFontLibrary: () => isRightFontLibrary,
17
17
  readRightFontLibrary: () => readRightFontLibrary
18
18
  });
19
- import { existsSync as existsSync10, readdirSync, readFileSync as readFileSync6 } from "node:fs";
19
+ import { existsSync as existsSync11, readdirSync, readFileSync as readFileSync6 } from "node:fs";
20
20
  import { join as join12 } from "node:path";
21
21
  function isRightFontLibrary(libraryPath) {
22
- return libraryPath.endsWith(".rightfontlibrary") && existsSync10(join12(libraryPath, "fonts")) && existsSync10(join12(libraryPath, "metadata"));
22
+ return libraryPath.endsWith(".rightfontlibrary") && existsSync11(join12(libraryPath, "fonts")) && existsSync11(join12(libraryPath, "metadata"));
23
23
  }
24
24
  function readRightFontLibrary(libraryPath) {
25
25
  if (!isRightFontLibrary(libraryPath)) {
@@ -30,7 +30,7 @@ function readRightFontLibrary(libraryPath) {
30
30
  const metadataListsDir = join12(libraryPath, "metadata", "fontlists");
31
31
  const familyMap = /* @__PURE__ */ new Map();
32
32
  let totalFonts = 0;
33
- if (existsSync10(metadataFontsDir)) {
33
+ if (existsSync11(metadataFontsDir)) {
34
34
  const files = readdirSync(metadataFontsDir).filter((f) => f.endsWith(".rightfontmetadata"));
35
35
  for (const file of files) {
36
36
  try {
@@ -70,7 +70,7 @@ function readRightFontLibrary(libraryPath) {
70
70
  fam.fonts.sort((a, b) => a.weight - b.weight || a.style.localeCompare(b.style));
71
71
  }
72
72
  const collections = [];
73
- if (existsSync10(metadataListsDir)) {
73
+ if (existsSync11(metadataListsDir)) {
74
74
  const files = readdirSync(metadataListsDir).filter((f) => f.endsWith(".rightfontmetadata"));
75
75
  for (const file of files) {
76
76
  try {
@@ -255,11 +255,11 @@ import { fileURLToPath as fileURLToPath7 } from "node:url";
255
255
  // ../server/src/server/bootstrap.ts
256
256
  import express from "express";
257
257
  import { createServer as createHTTPServer } from "http";
258
- import { createReadStream, unlinkSync, existsSync as existsSync19 } from "fs";
258
+ import { createReadStream, unlinkSync, existsSync as existsSync20 } from "fs";
259
259
  import { stat as stat9 } from "fs/promises";
260
260
  import { randomUUID as randomUUID16 } from "node:crypto";
261
261
  import { hostname as getHostname2 } from "node:os";
262
- import path33 from "node:path";
262
+ import path34 from "node:path";
263
263
  import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
264
264
  import { isInitializeRequest } from "@modelcontextprotocol/sdk/types.js";
265
265
 
@@ -712,18 +712,18 @@ function resolveNodePtyPackageRoot() {
712
712
  return null;
713
713
  }
714
714
  }
715
- function ensureExecutableBit(path37) {
716
- if (!existsSync2(path37)) {
715
+ function ensureExecutableBit(path38) {
716
+ if (!existsSync2(path38)) {
717
717
  return;
718
718
  }
719
- const stat10 = statSync(path37);
719
+ const stat10 = statSync(path38);
720
720
  if (!stat10.isFile()) {
721
721
  return;
722
722
  }
723
723
  if ((stat10.mode & 73) === 73) {
724
724
  return;
725
725
  }
726
- chmodSync(path37, stat10.mode | 73);
726
+ chmodSync(path38, stat10.mode | 73);
727
727
  }
728
728
  function ensureNodePtySpawnHelperExecutableForCurrentPlatform(options = {}) {
729
729
  const platform = options.platform ?? process.platform;
@@ -1341,11 +1341,11 @@ function parseGitRevParsePath(stdout) {
1341
1341
  if (lines.length !== 1) {
1342
1342
  return null;
1343
1343
  }
1344
- const path37 = lines[0]?.trim() ?? "";
1345
- if (!path37 || path37.startsWith("--")) {
1344
+ const path38 = lines[0]?.trim() ?? "";
1345
+ if (!path38 || path38.startsWith("--")) {
1346
1346
  return null;
1347
1347
  }
1348
- return path37;
1348
+ return path38;
1349
1349
  }
1350
1350
  function resolveGitRevParsePath(cwd, stdout) {
1351
1351
  const parsed = parseGitRevParsePath(stdout);
@@ -2118,9 +2118,9 @@ async function deleteAppostleWorktree({
2118
2118
  }
2119
2119
  }
2120
2120
  }
2121
- async function pathExists(path37) {
2121
+ async function pathExists(path38) {
2122
2122
  try {
2123
- await stat(path37);
2123
+ await stat(path38);
2124
2124
  return true;
2125
2125
  } catch (error) {
2126
2126
  if (error.code === "ENOENT") {
@@ -2129,8 +2129,8 @@ async function pathExists(path37) {
2129
2129
  throw error;
2130
2130
  }
2131
2131
  }
2132
- async function removeDirectoryWithRetries(path37) {
2133
- if (!await pathExists(path37)) {
2132
+ async function removeDirectoryWithRetries(path38) {
2133
+ if (!await pathExists(path38)) {
2134
2134
  return;
2135
2135
  }
2136
2136
  const delaysMs = [0, 100, 300, 700, 1500];
@@ -2140,17 +2140,17 @@ async function removeDirectoryWithRetries(path37) {
2140
2140
  await new Promise((resolve15) => setTimeout(resolve15, delay));
2141
2141
  }
2142
2142
  try {
2143
- await rm(path37, { recursive: true, force: true });
2144
- if (!await pathExists(path37)) {
2143
+ await rm(path38, { recursive: true, force: true });
2144
+ if (!await pathExists(path38)) {
2145
2145
  return;
2146
2146
  }
2147
- lastError = new Error(`Directory still present after rm: ${path37}`);
2147
+ lastError = new Error(`Directory still present after rm: ${path38}`);
2148
2148
  } catch (error) {
2149
2149
  lastError = error;
2150
2150
  }
2151
2151
  }
2152
- if (await pathExists(path37)) {
2153
- throw lastError instanceof Error ? lastError : new Error(`Failed to remove worktree directory: ${path37}`);
2152
+ if (await pathExists(path38)) {
2153
+ throw lastError instanceof Error ? lastError : new Error(`Failed to remove worktree directory: ${path38}`);
2154
2154
  }
2155
2155
  }
2156
2156
  var createWorktree = async ({
@@ -5836,6 +5836,50 @@ var LinkAccountResponseMessageSchema = z11.object({
5836
5836
  })
5837
5837
  ])
5838
5838
  });
5839
+ var ClaudeProfileLoginRequestMessageSchema = z11.object({
5840
+ type: z11.literal("claude_profile_login_request"),
5841
+ requestId: z11.string(),
5842
+ /** Username for the profile dir (~/.claude-{username}/). */
5843
+ username: z11.string().min(1)
5844
+ });
5845
+ var ClaudeProfileLoginUrlMessageSchema = z11.object({
5846
+ type: z11.literal("claude_profile_login_url"),
5847
+ requestId: z11.string(),
5848
+ url: z11.string().min(1)
5849
+ });
5850
+ var ClaudeProfileLoginCallbackMessageSchema = z11.object({
5851
+ type: z11.literal("claude_profile_login_callback"),
5852
+ requestId: z11.string(),
5853
+ callbackToken: z11.string().min(1)
5854
+ });
5855
+ var ClaudeProfileLoginResultMessageSchema = z11.object({
5856
+ type: z11.literal("claude_profile_login_result"),
5857
+ requestId: z11.string(),
5858
+ ok: z11.boolean(),
5859
+ error: z11.string().optional()
5860
+ });
5861
+ var ClaudeProfileRemoveRequestMessageSchema = z11.object({
5862
+ type: z11.literal("claude_profile_remove_request"),
5863
+ requestId: z11.string(),
5864
+ username: z11.string().min(1)
5865
+ });
5866
+ var ClaudeProfileRemoveResponseMessageSchema = z11.object({
5867
+ type: z11.literal("claude_profile_remove_response"),
5868
+ requestId: z11.string(),
5869
+ ok: z11.boolean(),
5870
+ error: z11.string().optional()
5871
+ });
5872
+ var ClaudeProfileStatusRequestMessageSchema = z11.object({
5873
+ type: z11.literal("claude_profile_status_request"),
5874
+ requestId: z11.string(),
5875
+ username: z11.string().min(1)
5876
+ });
5877
+ var ClaudeProfileStatusResponseMessageSchema = z11.object({
5878
+ type: z11.literal("claude_profile_status_response"),
5879
+ requestId: z11.string(),
5880
+ hasProfile: z11.boolean(),
5881
+ isAuthenticated: z11.boolean()
5882
+ });
5839
5883
  var ListSessionUploadsRequestSchema = z11.object({
5840
5884
  type: z11.literal("list_session_uploads_request"),
5841
5885
  requestId: z11.string(),
@@ -5966,6 +6010,10 @@ var SessionInboundMessageSchema = z11.discriminatedUnion("type", [
5966
6010
  AbortRequestMessageSchema,
5967
6011
  AudioPlayedMessageSchema,
5968
6012
  LinkAccountRequestMessageSchema,
6013
+ ClaudeProfileLoginRequestMessageSchema,
6014
+ ClaudeProfileLoginCallbackMessageSchema,
6015
+ ClaudeProfileStatusRequestMessageSchema,
6016
+ ClaudeProfileRemoveRequestMessageSchema,
5969
6017
  FetchAgentsRequestMessageSchema,
5970
6018
  FetchWorkspacesRequestMessageSchema,
5971
6019
  FetchAgentRequestMessageSchema,
@@ -7691,6 +7739,10 @@ var SessionOutboundMessageSchema = z11.discriminatedUnion("type", [
7691
7739
  GoogleFontsDownloadResponseSchema,
7692
7740
  GetVapidPublicKeyResponseSchema,
7693
7741
  LinkAccountResponseMessageSchema,
7742
+ ClaudeProfileLoginUrlMessageSchema,
7743
+ ClaudeProfileLoginResultMessageSchema,
7744
+ ClaudeProfileStatusResponseMessageSchema,
7745
+ ClaudeProfileRemoveResponseMessageSchema,
7694
7746
  ListSessionUploadsResponseSchema,
7695
7747
  DeleteSessionUploadResponseSchema,
7696
7748
  ListSessionImagesResponseSchema,
@@ -7712,7 +7764,11 @@ var WSHelloMessageSchema = z11.object({
7712
7764
  capabilities: z11.object({
7713
7765
  voice: z11.boolean().optional(),
7714
7766
  pushNotifications: z11.boolean().optional()
7715
- }).passthrough().optional()
7767
+ }).passthrough().optional(),
7768
+ /** Auth-server userId of the connecting user. Used for per-user Claude profile selection. */
7769
+ userId: z11.string().optional(),
7770
+ /** Display name of the connecting user (for profile dir naming). */
7771
+ username: z11.string().optional()
7716
7772
  });
7717
7773
  var WSRecordingStateMessageSchema = z11.object({
7718
7774
  type: z11.literal("recording_state"),
@@ -10229,14 +10285,14 @@ var DictationStreamManager = class {
10229
10285
  PCM_CHANNELS,
10230
10286
  PCM_BITS_PER_SAMPLE
10231
10287
  );
10232
- const path37 = await maybePersistDictationDebugAudio(
10288
+ const path38 = await maybePersistDictationDebugAudio(
10233
10289
  wavBuffer,
10234
10290
  { sessionId: state.sessionId, dictationId: state.dictationId, format: "audio/wav" },
10235
10291
  this.logger,
10236
10292
  state.debugChunkWriter?.folder
10237
10293
  );
10238
- state.debugRecordingPath = path37;
10239
- return path37;
10294
+ state.debugRecordingPath = path38;
10295
+ return path38;
10240
10296
  }
10241
10297
  failDictationStream(dictationId, error, retryable) {
10242
10298
  this.emit({
@@ -12247,14 +12303,14 @@ function parseDiff(diffText) {
12247
12303
  const firstLine = lines[0];
12248
12304
  const isNew = section.includes("new file mode") || section.includes("--- /dev/null");
12249
12305
  const isDeleted = section.includes("deleted file mode") || section.includes("+++ /dev/null");
12250
- let path37 = "unknown";
12306
+ let path38 = "unknown";
12251
12307
  const pathMatch = firstLine.match(/a\/(.*?) b\//);
12252
12308
  if (pathMatch) {
12253
- path37 = pathMatch[1];
12309
+ path38 = pathMatch[1];
12254
12310
  } else {
12255
12311
  const newFileMatch = firstLine.match(/b\/(.+)$/);
12256
12312
  if (newFileMatch) {
12257
- path37 = newFileMatch[1];
12313
+ path38 = newFileMatch[1];
12258
12314
  }
12259
12315
  }
12260
12316
  const hunks = [];
@@ -12298,7 +12354,7 @@ function parseDiff(diffText) {
12298
12354
  if (currentHunk) {
12299
12355
  hunks.push(currentHunk);
12300
12356
  }
12301
- files.push({ path: path37, isNew, isDeleted, additions, deletions, hunks });
12357
+ files.push({ path: path38, isNew, isDeleted, additions, deletions, hunks });
12302
12358
  }
12303
12359
  return files;
12304
12360
  }
@@ -12354,9 +12410,9 @@ function buildTokenLookup(lineMap, highlighted) {
12354
12410
  }
12355
12411
  return lookup;
12356
12412
  }
12357
- function buildFullFileTokenLookup(fileContent, path37) {
12413
+ function buildFullFileTokenLookup(fileContent, path38) {
12358
12414
  const lookup = /* @__PURE__ */ new Map();
12359
- const highlighted = highlightCode(fileContent, path37);
12415
+ const highlighted = highlightCode(fileContent, path38);
12360
12416
  for (let i = 0; i < highlighted.length; i++) {
12361
12417
  lookup.set(i + 1, highlighted[i]);
12362
12418
  }
@@ -14061,11 +14117,11 @@ async function listCheckoutFileChanges(cwd, ref, ignoreWhitespace = false) {
14061
14117
  }
14062
14118
  continue;
14063
14119
  }
14064
- const path37 = tabParts[1];
14065
- if (!path37) continue;
14120
+ const path38 = tabParts[1];
14121
+ if (!path38) continue;
14066
14122
  const code = rawStatus[0];
14067
14123
  changes.push({
14068
- path: path37,
14124
+ path: path38,
14069
14125
  status: rawStatus,
14070
14126
  isNew: code === "A",
14071
14127
  isDeleted: code === "D"
@@ -14100,9 +14156,9 @@ async function listCheckoutFileChanges(cwd, ref, ignoreWhitespace = false) {
14100
14156
  }
14101
14157
  return Array.from(byPath.values());
14102
14158
  }
14103
- async function readGitFileContentAtRef(cwd, ref, path37) {
14159
+ async function readGitFileContentAtRef(cwd, ref, path38) {
14104
14160
  try {
14105
- const { stdout } = await runGitCommand(["show", `${ref}:${path37}`], {
14161
+ const { stdout } = await runGitCommand(["show", `${ref}:${path38}`], {
14106
14162
  cwd,
14107
14163
  env: READ_ONLY_GIT_ENV2
14108
14164
  });
@@ -14163,21 +14219,21 @@ async function getTrackedNumstatByPath(cwd, ref, ignoreWhitespace = false) {
14163
14219
  const additionsField = parts[0] ?? "";
14164
14220
  const deletionsField = parts[1] ?? "";
14165
14221
  const rawPath = parts.slice(2).join(" ");
14166
- const path37 = normalizeNumstatPath(rawPath);
14167
- if (!path37) {
14222
+ const path38 = normalizeNumstatPath(rawPath);
14223
+ if (!path38) {
14168
14224
  continue;
14169
14225
  }
14170
14226
  if (additionsField === "-" || deletionsField === "-") {
14171
- stats.set(path37, { additions: 0, deletions: 0, isBinary: true });
14227
+ stats.set(path38, { additions: 0, deletions: 0, isBinary: true });
14172
14228
  continue;
14173
14229
  }
14174
14230
  const additions = Number.parseInt(additionsField, 10);
14175
14231
  const deletions = Number.parseInt(deletionsField, 10);
14176
14232
  if (Number.isNaN(additions) || Number.isNaN(deletions)) {
14177
- stats.set(path37, null);
14233
+ stats.set(path38, null);
14178
14234
  continue;
14179
14235
  }
14180
- stats.set(path37, { additions, deletions, isBinary: false });
14236
+ stats.set(path38, { additions, deletions, isBinary: false });
14181
14237
  }
14182
14238
  return stats;
14183
14239
  }
@@ -14869,10 +14925,10 @@ async function listUncommittedFiles(cwd) {
14869
14925
  if (dest) results.push({ path: dest, changeType: code });
14870
14926
  continue;
14871
14927
  }
14872
- const path37 = parts[1];
14873
- if (!path37) continue;
14928
+ const path38 = parts[1];
14929
+ if (!path38) continue;
14874
14930
  if (code === "A" || code === "M" || code === "D") {
14875
- results.push({ path: path37, changeType: code });
14931
+ results.push({ path: path38, changeType: code });
14876
14932
  }
14877
14933
  }
14878
14934
  } catch {
@@ -18915,12 +18971,12 @@ function extractPlanNameFromFrontmatter(content) {
18915
18971
  return null;
18916
18972
  }
18917
18973
  function resolvePlanFilename(options) {
18918
- const { originalPath, newSlug, existsSync: existsSync22 } = options;
18974
+ const { originalPath, newSlug, existsSync: existsSync23 } = options;
18919
18975
  const dir = path8.dirname(originalPath);
18920
18976
  const base = `${newSlug}.md`;
18921
18977
  let candidate = path8.join(dir, base);
18922
18978
  let counter = 2;
18923
- while (candidate !== originalPath && existsSync22(candidate)) {
18979
+ while (candidate !== originalPath && existsSync23(candidate)) {
18924
18980
  candidate = path8.join(dir, `${newSlug}-${counter}.md`);
18925
18981
  counter += 1;
18926
18982
  }
@@ -23157,14 +23213,14 @@ function codexApplyPatchToUnifiedDiff(text) {
23157
23213
  for (const line of lines) {
23158
23214
  const directive = parseCodexApplyPatchDirective(line);
23159
23215
  if (directive) {
23160
- const path37 = normalizeDiffHeaderPath(directive.path);
23161
- if (path37.length > 0) {
23216
+ const path38 = normalizeDiffHeaderPath(directive.path);
23217
+ if (path38.length > 0) {
23162
23218
  if (output.length > 0 && output[output.length - 1] !== "") {
23163
23219
  output.push("");
23164
23220
  }
23165
- const left = directive.kind === "add" ? "/dev/null" : `a/${path37}`;
23166
- const right = directive.kind === "delete" ? "/dev/null" : `b/${path37}`;
23167
- output.push(`diff --git a/${path37} b/${path37}`);
23221
+ const left = directive.kind === "add" ? "/dev/null" : `a/${path38}`;
23222
+ const right = directive.kind === "delete" ? "/dev/null" : `b/${path38}`;
23223
+ output.push(`diff --git a/${path38} b/${path38}`);
23168
23224
  output.push(`--- ${left}`);
23169
23225
  output.push(`+++ ${right}`);
23170
23226
  sawDiffContent = true;
@@ -23234,9 +23290,9 @@ function asEditTextFields(text) {
23234
23290
  function normalizeRolloutEditInput(input) {
23235
23291
  if (typeof input === "string") {
23236
23292
  const textFields2 = asEditTextFields(input);
23237
- const path37 = extractPatchPrimaryFilePath(input);
23293
+ const path38 = extractPatchPrimaryFilePath(input);
23238
23294
  return {
23239
- ...path37 ? { path: path37 } : {},
23295
+ ...path38 ? { path: path38 } : {},
23240
23296
  ...textFields2.unifiedDiff ? { patch: textFields2.unifiedDiff } : {},
23241
23297
  ...textFields2.newString ? { content: textFields2.newString } : {}
23242
23298
  };
@@ -23384,12 +23440,12 @@ function parseFileChangeDiff(entry) {
23384
23440
  ]);
23385
23441
  }
23386
23442
  function toFileChangeEntry(entry, options, fallbackPath) {
23387
- const path37 = parseFileChangePath(entry, options, fallbackPath);
23388
- if (!path37) {
23443
+ const path38 = parseFileChangePath(entry, options, fallbackPath);
23444
+ if (!path38) {
23389
23445
  return null;
23390
23446
  }
23391
23447
  return {
23392
- path: path37,
23448
+ path: path38,
23393
23449
  kind: parseFileChangeKind(entry),
23394
23450
  diff: parseFileChangeDiff(entry)
23395
23451
  };
@@ -23411,12 +23467,12 @@ function parseFileChangeEntries(changes, options) {
23411
23467
  if (singleEntry) {
23412
23468
  return [singleEntry];
23413
23469
  }
23414
- return Object.entries(changes).map(([path37, value]) => {
23470
+ return Object.entries(changes).map(([path38, value]) => {
23415
23471
  if (isRecord2(value)) {
23416
- return toFileChangeEntry(value, options, path37);
23472
+ return toFileChangeEntry(value, options, path38);
23417
23473
  }
23418
23474
  if (typeof value === "string") {
23419
- const normalizedPath = normalizeCodexFilePath(path37.trim(), options?.cwd);
23475
+ const normalizedPath = normalizeCodexFilePath(path38.trim(), options?.cwd);
23420
23476
  if (!normalizedPath) {
23421
23477
  return null;
23422
23478
  }
@@ -24161,16 +24217,16 @@ function isObjectSchemaNode(schema) {
24161
24217
  const type = schema.type;
24162
24218
  return isSchemaRecord(schema.properties) || type === "object" || Array.isArray(type) && type.includes("object");
24163
24219
  }
24164
- function normalizeCodexOutputSchemaNode(schema, path37) {
24220
+ function normalizeCodexOutputSchemaNode(schema, path38) {
24165
24221
  if (Array.isArray(schema)) {
24166
- return schema.map((entry, index) => normalizeCodexOutputSchemaNode(entry, `${path37}[${index}]`));
24222
+ return schema.map((entry, index) => normalizeCodexOutputSchemaNode(entry, `${path38}[${index}]`));
24167
24223
  }
24168
24224
  if (!isSchemaRecord(schema)) {
24169
24225
  return schema;
24170
24226
  }
24171
24227
  const normalized = {};
24172
24228
  for (const [key, value] of Object.entries(schema)) {
24173
- normalized[key] = normalizeCodexOutputSchemaNode(value, `${path37}.${key}`);
24229
+ normalized[key] = normalizeCodexOutputSchemaNode(value, `${path38}.${key}`);
24174
24230
  }
24175
24231
  if (!isObjectSchemaNode(normalized)) {
24176
24232
  return normalized;
@@ -24179,7 +24235,7 @@ function normalizeCodexOutputSchemaNode(schema, path37) {
24179
24235
  normalized.additionalProperties = false;
24180
24236
  } else if (normalized.additionalProperties !== false) {
24181
24237
  throw new Error(
24182
- `Codex structured outputs require ${path37} to set additionalProperties to false for object schemas.`
24238
+ `Codex structured outputs require ${path38} to set additionalProperties to false for object schemas.`
24183
24239
  );
24184
24240
  }
24185
24241
  const properties = isSchemaRecord(normalized.properties) ? normalized.properties : null;
@@ -24943,8 +24999,8 @@ function parseCodexPatchChanges(changes) {
24943
24999
  }
24944
25000
  ];
24945
25001
  }
24946
- return Object.entries(recordChanges).map(([path37, value]) => {
24947
- const normalizedPath = path37.trim();
25002
+ return Object.entries(recordChanges).map(([path38, value]) => {
25003
+ const normalizedPath = path38.trim();
24948
25004
  if (!normalizedPath) {
24949
25005
  return null;
24950
25006
  }
@@ -32717,8 +32773,8 @@ function buildZodValidator(schema, schemaName) {
32717
32773
  return { ok: true, value: result.data };
32718
32774
  }
32719
32775
  const errors = result.error.issues.map((issue) => {
32720
- const path37 = issue.path.length > 0 ? issue.path.join(".") : "(root)";
32721
- return `${path37}: ${issue.message}`;
32776
+ const path38 = issue.path.length > 0 ? issue.path.join(".") : "(root)";
32777
+ return `${path38}: ${issue.message}`;
32722
32778
  });
32723
32779
  return { ok: false, errors };
32724
32780
  }
@@ -32736,9 +32792,9 @@ function buildJsonSchemaValidator(schema) {
32736
32792
  return { ok: true, value };
32737
32793
  }
32738
32794
  const errors = (validate.errors ?? []).map((error) => {
32739
- const path37 = error.instancePath && error.instancePath.length > 0 ? error.instancePath : "(root)";
32795
+ const path38 = error.instancePath && error.instancePath.length > 0 ? error.instancePath : "(root)";
32740
32796
  const message = error.message ?? "is invalid";
32741
- return `${path37}: ${message}`;
32797
+ return `${path38}: ${message}`;
32742
32798
  });
32743
32799
  return { ok: false, errors };
32744
32800
  }
@@ -34342,15 +34398,15 @@ async function getProjectIcon(projectDir) {
34342
34398
 
34343
34399
  // ../server/src/utils/path.ts
34344
34400
  import os5 from "os";
34345
- function expandTilde(path37) {
34346
- if (path37.startsWith("~/")) {
34401
+ function expandTilde(path38) {
34402
+ if (path38.startsWith("~/")) {
34347
34403
  const homeDir3 = process.env.HOME || os5.homedir();
34348
- return path37.replace("~", homeDir3);
34404
+ return path38.replace("~", homeDir3);
34349
34405
  }
34350
- if (path37 === "~") {
34406
+ if (path38 === "~") {
34351
34407
  return process.env.HOME || os5.homedir();
34352
34408
  }
34353
- return path37;
34409
+ return path38;
34354
34410
  }
34355
34411
 
34356
34412
  // ../server/src/server/skills/scanner.ts
@@ -37280,6 +37336,45 @@ async function generateAndApplyArtDirection(options) {
37280
37336
  return { generatedCount: acceptedUpdates.size };
37281
37337
  }
37282
37338
 
37339
+ // ../server/src/server/claude-profile.ts
37340
+ import { existsSync as existsSync10, mkdirSync as mkdirSync5, symlinkSync, rmSync as rmSync2 } from "node:fs";
37341
+ import path22 from "node:path";
37342
+ import os8 from "node:os";
37343
+ var SHARED_ITEMS = ["settings.json", "hooks", "agents", "skills", "plugins", "keybindings.json"];
37344
+ function getClaudeProfileDir(username) {
37345
+ return path22.join(os8.homedir(), `.claude-${username}`);
37346
+ }
37347
+ function ensureClaudeProfile(username, logger) {
37348
+ const profileDir = getClaudeProfileDir(username);
37349
+ const ownerDir = path22.join(os8.homedir(), ".claude");
37350
+ if (!existsSync10(ownerDir)) {
37351
+ throw new Error(`Owner claude config dir not found: ${ownerDir}`);
37352
+ }
37353
+ if (!existsSync10(profileDir)) {
37354
+ mkdirSync5(profileDir, { recursive: true });
37355
+ logger?.info({ profileDir, username }, "created claude profile directory");
37356
+ }
37357
+ for (const item of SHARED_ITEMS) {
37358
+ const target = path22.join(ownerDir, item);
37359
+ const link = path22.join(profileDir, item);
37360
+ if (!existsSync10(target)) continue;
37361
+ if (existsSync10(link)) continue;
37362
+ symlinkSync(target, link);
37363
+ logger?.info({ item, profileDir }, "symlinked shared config item");
37364
+ }
37365
+ return profileDir;
37366
+ }
37367
+ function hasClaudeAuth(username) {
37368
+ const profileDir = getClaudeProfileDir(username);
37369
+ return existsSync10(profileDir);
37370
+ }
37371
+ function removeClaudeProfile(username, logger) {
37372
+ const profileDir = getClaudeProfileDir(username);
37373
+ if (!existsSync10(profileDir)) return;
37374
+ rmSync2(profileDir, { recursive: true, force: true });
37375
+ logger?.info({ profileDir, username }, "removed claude profile directory");
37376
+ }
37377
+
37283
37378
  // ../server/src/services/oauth-service.ts
37284
37379
  import { createHash as createHash4, randomBytes as randomBytes2 } from "node:crypto";
37285
37380
  import { mkdir as mkdir4, readFile as readFile3, rename, unlink, writeFile as writeFile4 } from "node:fs/promises";
@@ -37525,57 +37620,57 @@ async function fetchGitLabUsername(fetchImpl, accessToken) {
37525
37620
  return null;
37526
37621
  }
37527
37622
  }
37528
- async function readCredential(path37, log) {
37623
+ async function readCredential(path38, log) {
37529
37624
  try {
37530
- const raw = await readFile3(path37, "utf8");
37625
+ const raw = await readFile3(path38, "utf8");
37531
37626
  const parsed = JSON.parse(raw);
37532
37627
  return parsed.gitlab ?? null;
37533
37628
  } catch (error) {
37534
37629
  if (isNotFound(error)) return null;
37535
- log.warn({ err: error, path: path37 }, "oauth.credentials.read_failed");
37630
+ log.warn({ err: error, path: path38 }, "oauth.credentials.read_failed");
37536
37631
  return null;
37537
37632
  }
37538
37633
  }
37539
- async function persistCredential(path37, credential, log) {
37540
- await mkdir4(dirname4(path37), { recursive: true });
37634
+ async function persistCredential(path38, credential, log) {
37635
+ await mkdir4(dirname4(path38), { recursive: true });
37541
37636
  let current = {};
37542
37637
  try {
37543
- const raw = await readFile3(path37, "utf8");
37638
+ const raw = await readFile3(path38, "utf8");
37544
37639
  current = JSON.parse(raw);
37545
37640
  } catch (error) {
37546
37641
  if (!isNotFound(error)) {
37547
- log.warn({ err: error, path: path37 }, "oauth.credentials.read_failed_overwriting");
37642
+ log.warn({ err: error, path: path38 }, "oauth.credentials.read_failed_overwriting");
37548
37643
  }
37549
37644
  }
37550
37645
  const next = { ...current, gitlab: credential };
37551
- const tmpPath = `${path37}.tmp-${process.pid}-${Date.now()}`;
37646
+ const tmpPath = `${path38}.tmp-${process.pid}-${Date.now()}`;
37552
37647
  await writeFile4(tmpPath, JSON.stringify(next, null, 2), { mode: 384 });
37553
- await rename(tmpPath, path37);
37648
+ await rename(tmpPath, path38);
37554
37649
  }
37555
- async function deleteCredential(path37, log) {
37650
+ async function deleteCredential(path38, log) {
37556
37651
  let current = {};
37557
37652
  try {
37558
- const raw = await readFile3(path37, "utf8");
37653
+ const raw = await readFile3(path38, "utf8");
37559
37654
  current = JSON.parse(raw);
37560
37655
  } catch (error) {
37561
37656
  if (isNotFound(error)) return;
37562
- log.warn({ err: error, path: path37 }, "oauth.credentials.delete_read_failed");
37657
+ log.warn({ err: error, path: path38 }, "oauth.credentials.delete_read_failed");
37563
37658
  return;
37564
37659
  }
37565
37660
  delete current.gitlab;
37566
37661
  if (Object.keys(current).length === 0) {
37567
37662
  try {
37568
- await unlink(path37);
37663
+ await unlink(path38);
37569
37664
  } catch (error) {
37570
37665
  if (!isNotFound(error)) {
37571
- log.warn({ err: error, path: path37 }, "oauth.credentials.unlink_failed");
37666
+ log.warn({ err: error, path: path38 }, "oauth.credentials.unlink_failed");
37572
37667
  }
37573
37668
  }
37574
37669
  return;
37575
37670
  }
37576
- const tmpPath = `${path37}.tmp-${process.pid}-${Date.now()}`;
37671
+ const tmpPath = `${path38}.tmp-${process.pid}-${Date.now()}`;
37577
37672
  await writeFile4(tmpPath, JSON.stringify(current, null, 2), { mode: 384 });
37578
- await rename(tmpPath, path37);
37673
+ await rename(tmpPath, path38);
37579
37674
  }
37580
37675
  function defaultGlabConfigPath() {
37581
37676
  const home = homedir4();
@@ -37590,15 +37685,15 @@ function defaultGlabConfigPath() {
37590
37685
  const xdg = process.env.XDG_CONFIG_HOME;
37591
37686
  return join11(xdg && xdg.length > 0 ? xdg : join11(home, ".config"), "glab-cli", "config.yml");
37592
37687
  }
37593
- async function writeGlabConfig(path37, credential, log) {
37594
- await mkdir4(dirname4(path37), { recursive: true });
37688
+ async function writeGlabConfig(path38, credential, log) {
37689
+ await mkdir4(dirname4(path38), { recursive: true });
37595
37690
  let doc;
37596
37691
  try {
37597
- const raw = await readFile3(path37, "utf8");
37692
+ const raw = await readFile3(path38, "utf8");
37598
37693
  doc = YAML.parseDocument(raw);
37599
37694
  if (doc.errors.length > 0) {
37600
37695
  log.warn(
37601
- { errors: doc.errors.map((e) => e.message), path: path37 },
37696
+ { errors: doc.errors.map((e) => e.message), path: path38 },
37602
37697
  "oauth.glab.parse_errors_replacing"
37603
37698
  );
37604
37699
  doc = YAML.parseDocument("{}");
@@ -37607,7 +37702,7 @@ async function writeGlabConfig(path37, credential, log) {
37607
37702
  if (isNotFound(error)) {
37608
37703
  doc = YAML.parseDocument("{}");
37609
37704
  } else {
37610
- log.warn({ err: error, path: path37 }, "oauth.glab.read_failed_replacing");
37705
+ log.warn({ err: error, path: path38 }, "oauth.glab.read_failed_replacing");
37611
37706
  doc = YAML.parseDocument("{}");
37612
37707
  }
37613
37708
  }
@@ -37620,18 +37715,18 @@ async function writeGlabConfig(path37, credential, log) {
37620
37715
  if (credential.username) {
37621
37716
  hostEntry.set("user", credential.username);
37622
37717
  }
37623
- const tmpPath = `${path37}.tmp-${process.pid}-${Date.now()}`;
37718
+ const tmpPath = `${path38}.tmp-${process.pid}-${Date.now()}`;
37624
37719
  await writeFile4(tmpPath, doc.toString(), { mode: 384 });
37625
- await rename(tmpPath, path37);
37720
+ await rename(tmpPath, path38);
37626
37721
  }
37627
- async function removeGlabHost(path37, log) {
37722
+ async function removeGlabHost(path38, log) {
37628
37723
  let doc;
37629
37724
  try {
37630
- const raw = await readFile3(path37, "utf8");
37725
+ const raw = await readFile3(path38, "utf8");
37631
37726
  doc = YAML.parseDocument(raw);
37632
37727
  } catch (error) {
37633
37728
  if (isNotFound(error)) return;
37634
- log.warn({ err: error, path: path37 }, "oauth.glab.remove_read_failed");
37729
+ log.warn({ err: error, path: path38 }, "oauth.glab.remove_read_failed");
37635
37730
  return;
37636
37731
  }
37637
37732
  const hosts = doc.get("hosts");
@@ -37640,9 +37735,9 @@ async function removeGlabHost(path37, log) {
37640
37735
  if (hosts.items.length === 0) {
37641
37736
  doc.delete("hosts");
37642
37737
  }
37643
- const tmpPath = `${path37}.tmp-${process.pid}-${Date.now()}`;
37738
+ const tmpPath = `${path38}.tmp-${process.pid}-${Date.now()}`;
37644
37739
  await writeFile4(tmpPath, doc.toString(), { mode: 384 });
37645
- await rename(tmpPath, path37);
37740
+ await rename(tmpPath, path38);
37646
37741
  }
37647
37742
  function ensureMap(doc, key) {
37648
37743
  const existing = doc.get(key);
@@ -38768,6 +38863,8 @@ var Session = class _Session {
38768
38863
  this.nextTerminalSlot = 0;
38769
38864
  this.inflightRequests = 0;
38770
38865
  this.peakInflightRequests = 0;
38866
+ /** In-progress `claude login` processes, keyed by requestId. */
38867
+ this.pendingClaudeLogins = /* @__PURE__ */ new Map();
38771
38868
  this.checkoutDiffSubscriptions = /* @__PURE__ */ new Map();
38772
38869
  this.workspaceGitWatchTargets = /* @__PURE__ */ new Map();
38773
38870
  this.workspaceSetupSnapshots = /* @__PURE__ */ new Map();
@@ -38829,6 +38926,8 @@ var Session = class _Session {
38829
38926
  this.clientId = clientId;
38830
38927
  this.appVersion = appVersion ?? null;
38831
38928
  this.sessionId = uuidv47();
38929
+ this.userId = options.userId ?? null;
38930
+ this.username = options.username ?? null;
38832
38931
  this.onMessage = onMessage;
38833
38932
  this.onBinaryMessage = onBinaryMessage ?? null;
38834
38933
  this.onLifecycleIntent = onLifecycleIntent ?? null;
@@ -39448,6 +39547,18 @@ var Session = class _Session {
39448
39547
  case "link_account_request":
39449
39548
  await this.handleLinkAccountRequest(msg);
39450
39549
  break;
39550
+ case "claude_profile_login_request":
39551
+ await this.handleClaudeProfileLoginRequest(msg);
39552
+ break;
39553
+ case "claude_profile_login_callback":
39554
+ await this.handleClaudeProfileLoginCallback(msg);
39555
+ break;
39556
+ case "claude_profile_status_request":
39557
+ await this.handleClaudeProfileStatusRequest(msg);
39558
+ break;
39559
+ case "claude_profile_remove_request":
39560
+ await this.handleClaudeProfileRemoveRequest(msg);
39561
+ break;
39451
39562
  case "fetch_agents_request":
39452
39563
  await this.handleFetchAgents(msg);
39453
39564
  break;
@@ -40154,6 +40265,138 @@ var Session = class _Session {
40154
40265
  respond({ ok: false, error: message });
40155
40266
  }
40156
40267
  }
40268
+ // ---------------------------------------------------------------------------
40269
+ // Claude profile login — per-user subscription on shared hosts
40270
+ // ---------------------------------------------------------------------------
40271
+ async handleClaudeProfileLoginRequest(msg) {
40272
+ const { requestId, username } = msg;
40273
+ const log = this.sessionLogger.child({ handler: "claude_profile_login" });
40274
+ try {
40275
+ const profileDir = ensureClaudeProfile(username, log);
40276
+ const child = spawnProcess("claude", ["auth", "login"], {
40277
+ env: {
40278
+ ...process.env,
40279
+ CLAUDE_CONFIG_DIR: profileDir
40280
+ },
40281
+ stdio: ["pipe", "pipe", "pipe"]
40282
+ });
40283
+ this.pendingClaudeLogins.set(requestId, { process: child, username });
40284
+ let stdoutBuffer = "";
40285
+ child.stdout?.on("data", (chunk) => {
40286
+ stdoutBuffer += chunk.toString();
40287
+ const urlMatch = stdoutBuffer.match(/(https?:\/\/[^\s]+)/);
40288
+ if (urlMatch) {
40289
+ this.emit({
40290
+ type: "claude_profile_login_url",
40291
+ requestId,
40292
+ url: urlMatch[1]
40293
+ });
40294
+ }
40295
+ });
40296
+ child.stderr?.on("data", (chunk) => {
40297
+ log.debug({ stderr: chunk.toString() }, "claude login stderr");
40298
+ });
40299
+ child.on("close", (code) => {
40300
+ this.pendingClaudeLogins.delete(requestId);
40301
+ if (code === 0) {
40302
+ log.info({ username }, "claude profile login succeeded");
40303
+ this.emit({
40304
+ type: "claude_profile_login_result",
40305
+ requestId,
40306
+ ok: true
40307
+ });
40308
+ } else {
40309
+ log.warn({ username, code }, "claude profile login failed");
40310
+ this.emit({
40311
+ type: "claude_profile_login_result",
40312
+ requestId,
40313
+ ok: false,
40314
+ error: `claude login exited with code ${code}`
40315
+ });
40316
+ }
40317
+ });
40318
+ child.on("error", (err) => {
40319
+ this.pendingClaudeLogins.delete(requestId);
40320
+ log.error({ err }, "claude login process error");
40321
+ this.emit({
40322
+ type: "claude_profile_login_result",
40323
+ requestId,
40324
+ ok: false,
40325
+ error: err.message
40326
+ });
40327
+ });
40328
+ } catch (err) {
40329
+ const message = err instanceof Error ? err.message : "unknown_error";
40330
+ log.error({ err }, "claude profile login request failed");
40331
+ this.emit({
40332
+ type: "claude_profile_login_result",
40333
+ requestId,
40334
+ ok: false,
40335
+ error: message
40336
+ });
40337
+ }
40338
+ }
40339
+ async handleClaudeProfileLoginCallback(msg) {
40340
+ const { requestId, callbackToken } = msg;
40341
+ const pending = this.pendingClaudeLogins.get(requestId);
40342
+ if (!pending) {
40343
+ this.sessionLogger.warn({ requestId }, "claude_profile_login_callback: no pending login");
40344
+ this.emit({
40345
+ type: "claude_profile_login_result",
40346
+ requestId,
40347
+ ok: false,
40348
+ error: "no_pending_login"
40349
+ });
40350
+ return;
40351
+ }
40352
+ try {
40353
+ pending.process.stdin?.write(callbackToken + "\n");
40354
+ } catch (err) {
40355
+ this.sessionLogger.error({ err }, "failed to write callback token to claude login stdin");
40356
+ }
40357
+ }
40358
+ async handleClaudeProfileStatusRequest(msg) {
40359
+ const { requestId, username } = msg;
40360
+ const profileExists = hasClaudeAuth(username);
40361
+ let isAuthenticated = false;
40362
+ if (profileExists) {
40363
+ try {
40364
+ const profileDir = ensureClaudeProfile(username);
40365
+ const result = await execCommand("claude", ["auth", "status"], {
40366
+ env: { ...process.env, CLAUDE_CONFIG_DIR: profileDir },
40367
+ timeout: 5e3
40368
+ });
40369
+ isAuthenticated = !result.stdout.toLowerCase().includes("not logged in");
40370
+ } catch {
40371
+ }
40372
+ }
40373
+ this.emit({
40374
+ type: "claude_profile_status_response",
40375
+ requestId,
40376
+ hasProfile: profileExists,
40377
+ isAuthenticated
40378
+ });
40379
+ }
40380
+ async handleClaudeProfileRemoveRequest(msg) {
40381
+ const { requestId, username } = msg;
40382
+ try {
40383
+ removeClaudeProfile(username, this.sessionLogger);
40384
+ this.emit({
40385
+ type: "claude_profile_remove_response",
40386
+ requestId,
40387
+ ok: true
40388
+ });
40389
+ } catch (err) {
40390
+ const message = err instanceof Error ? err.message : "unknown_error";
40391
+ this.sessionLogger.error({ err, username }, "claude profile remove failed");
40392
+ this.emit({
40393
+ type: "claude_profile_remove_response",
40394
+ requestId,
40395
+ ok: false,
40396
+ error: message
40397
+ });
40398
+ }
40399
+ }
40157
40400
  async handleRestartServerRequest(requestId, reason) {
40158
40401
  const payload = {
40159
40402
  status: "restart_requested",
@@ -40987,7 +41230,9 @@ var Session = class _Session {
40987
41230
  {
40988
41231
  labels,
40989
41232
  workspaceId: resolvedWorkspace.workspaceId,
40990
- initialPrompt: trimmedPrompt
41233
+ initialPrompt: trimmedPrompt,
41234
+ userId: this.userId ?? void 0,
41235
+ username: this.username ?? void 0
40991
41236
  }
40992
41237
  );
40993
41238
  await this.forwardAgentUpdate(snapshot);
@@ -42455,7 +42700,7 @@ var Session = class _Session {
42455
42700
  homeDir: process.env.HOME ?? homedir5(),
42456
42701
  query: query2,
42457
42702
  limit
42458
- })).map((path37) => ({ path: path37, kind: "directory" }));
42703
+ })).map((path38) => ({ path: path38, kind: "directory" }));
42459
42704
  const directories = entries.filter((entry) => entry.kind === "directory").map((entry) => entry.path);
42460
42705
  this.emit({
42461
42706
  type: "directory_suggestions_response",
@@ -47590,7 +47835,7 @@ function toErrorMessage(error) {
47590
47835
  }
47591
47836
 
47592
47837
  // ../server/src/server/push/token-store.ts
47593
- import { existsSync as existsSync11, mkdirSync as mkdirSync5, readFileSync as readFileSync7, renameSync, writeFileSync as writeFileSync5 } from "node:fs";
47838
+ import { existsSync as existsSync12, mkdirSync as mkdirSync6, readFileSync as readFileSync7, renameSync, writeFileSync as writeFileSync5 } from "node:fs";
47594
47839
  import { dirname as dirname5 } from "node:path";
47595
47840
  var PushTokenStore = class {
47596
47841
  constructor(logger, filePath) {
@@ -47684,7 +47929,7 @@ var PushTokenStore = class {
47684
47929
  }
47685
47930
  loadFromDisk() {
47686
47931
  try {
47687
- if (!existsSync11(this.filePath)) {
47932
+ if (!existsSync12(this.filePath)) {
47688
47933
  return;
47689
47934
  }
47690
47935
  const raw = readFileSync7(this.filePath, "utf-8");
@@ -47720,7 +47965,7 @@ var PushTokenStore = class {
47720
47965
  }
47721
47966
  persist() {
47722
47967
  try {
47723
- mkdirSync5(dirname5(this.filePath), { recursive: true });
47968
+ mkdirSync6(dirname5(this.filePath), { recursive: true });
47724
47969
  const tmpPath = `${this.filePath}.tmp`;
47725
47970
  const payload = { entries: Array.from(this.entries.values()) };
47726
47971
  writeFileSync5(tmpPath, JSON.stringify(payload, null, 2) + "\n");
@@ -47800,7 +48045,7 @@ var PushService = class {
47800
48045
  };
47801
48046
 
47802
48047
  // ../server/src/server/push/web-push-store.ts
47803
- import { existsSync as existsSync12, mkdirSync as mkdirSync6, readFileSync as readFileSync8, renameSync as renameSync2, writeFileSync as writeFileSync6, chmodSync as chmodSync2 } from "node:fs";
48048
+ import { existsSync as existsSync13, mkdirSync as mkdirSync7, readFileSync as readFileSync8, renameSync as renameSync2, writeFileSync as writeFileSync6, chmodSync as chmodSync2 } from "node:fs";
47804
48049
  import { dirname as dirname6 } from "node:path";
47805
48050
  import webpush from "web-push";
47806
48051
  var WebPushStore = class {
@@ -47906,7 +48151,7 @@ var WebPushStore = class {
47906
48151
  }
47907
48152
  loadOrCreateVapidKeys() {
47908
48153
  try {
47909
- if (existsSync12(this.vapidPath)) {
48154
+ if (existsSync13(this.vapidPath)) {
47910
48155
  const raw = readFileSync8(this.vapidPath, "utf-8");
47911
48156
  const parsed = JSON.parse(raw);
47912
48157
  if (parsed.publicKey && parsed.privateKey) {
@@ -47918,7 +48163,7 @@ var WebPushStore = class {
47918
48163
  }
47919
48164
  const generated = webpush.generateVAPIDKeys();
47920
48165
  try {
47921
- mkdirSync6(dirname6(this.vapidPath), { recursive: true });
48166
+ mkdirSync7(dirname6(this.vapidPath), { recursive: true });
47922
48167
  writeFileSync6(this.vapidPath, JSON.stringify(generated, null, 2) + "\n");
47923
48168
  if (process.platform !== "win32") {
47924
48169
  try {
@@ -47934,7 +48179,7 @@ var WebPushStore = class {
47934
48179
  }
47935
48180
  loadSubscriptions() {
47936
48181
  try {
47937
- if (!existsSync12(this.subsPath)) return;
48182
+ if (!existsSync13(this.subsPath)) return;
47938
48183
  const raw = readFileSync8(this.subsPath, "utf-8");
47939
48184
  const parsed = JSON.parse(raw);
47940
48185
  if (parsed.vapidKey && parsed.vapidKey !== this.vapid.publicKey) {
@@ -47975,7 +48220,7 @@ var WebPushStore = class {
47975
48220
  }
47976
48221
  persist() {
47977
48222
  try {
47978
- mkdirSync6(dirname6(this.subsPath), { recursive: true });
48223
+ mkdirSync7(dirname6(this.subsPath), { recursive: true });
47979
48224
  const tmpPath = `${this.subsPath}.tmp`;
47980
48225
  const payload = {
47981
48226
  vapidKey: this.vapid.publicKey,
@@ -48705,6 +48950,8 @@ var VoiceAssistantWebSocketServer = class {
48705
48950
  const session = new Session({
48706
48951
  clientId,
48707
48952
  appVersion,
48953
+ userId: params.userId,
48954
+ username: params.username,
48708
48955
  onMessage: (msg) => {
48709
48956
  if (!connection) {
48710
48957
  return;
@@ -48782,7 +49029,9 @@ var VoiceAssistantWebSocketServer = class {
48782
49029
  appVersion,
48783
49030
  connectionLogger,
48784
49031
  sockets: /* @__PURE__ */ new Set([ws]),
48785
- externalDisconnectCleanupTimeout: null
49032
+ externalDisconnectCleanupTimeout: null,
49033
+ userId: params.userId ?? null,
49034
+ username: params.username ?? null
48786
49035
  };
48787
49036
  return connection;
48788
49037
  }
@@ -48857,7 +49106,9 @@ var VoiceAssistantWebSocketServer = class {
48857
49106
  ws,
48858
49107
  clientId,
48859
49108
  appVersion: message.appVersion ?? null,
48860
- connectionLogger
49109
+ connectionLogger,
49110
+ userId: message.userId,
49111
+ username: message.username
48861
49112
  });
48862
49113
  this.sessions.set(ws, connection);
48863
49114
  this.externalSessionsByKey.set(clientId, connection);
@@ -49560,7 +49811,7 @@ import { join as join17 } from "node:path";
49560
49811
  // ../server/src/server/speech/providers/local/sherpa/model-downloader.ts
49561
49812
  import { createWriteStream } from "node:fs";
49562
49813
  import { mkdir as mkdir6, rename as rename2, rm as rm2, stat as stat5 } from "node:fs/promises";
49563
- import path22 from "node:path";
49814
+ import path23 from "node:path";
49564
49815
  import { Readable as Readable2 } from "node:stream";
49565
49816
  import { pipeline } from "node:stream/promises";
49566
49817
  import { spawn as spawn7 } from "node:child_process";
@@ -49696,11 +49947,11 @@ function getSherpaOnnxModelSpec(id) {
49696
49947
  // ../server/src/server/speech/providers/local/sherpa/model-downloader.ts
49697
49948
  function getSherpaOnnxModelDir(modelsDir, modelId) {
49698
49949
  const spec = getSherpaOnnxModelSpec(modelId);
49699
- return path22.join(modelsDir, spec.extractedDir);
49950
+ return path23.join(modelsDir, spec.extractedDir);
49700
49951
  }
49701
49952
  async function hasRequiredFiles(modelDir, requiredFiles) {
49702
49953
  for (const rel of requiredFiles) {
49703
- const abs = path22.join(modelDir, rel);
49954
+ const abs = path23.join(modelDir, rel);
49704
49955
  try {
49705
49956
  const s = await stat5(abs);
49706
49957
  if (s.isDirectory()) {
@@ -49726,7 +49977,7 @@ async function downloadToFile(options) {
49726
49977
  throw new Error(`Failed to download ${url}: missing response body`);
49727
49978
  }
49728
49979
  const tmpPath = `${outputPath}.tmp-${Date.now()}`;
49729
- await mkdir6(path22.dirname(outputPath), { recursive: true });
49980
+ await mkdir6(path23.dirname(outputPath), { recursive: true });
49730
49981
  const nodeStream = Readable2.fromWeb(res.body);
49731
49982
  try {
49732
49983
  await pipeline(nodeStream, createWriteStream(tmpPath));
@@ -49763,16 +50014,16 @@ async function ensureSherpaOnnxModel(options) {
49763
50014
  modelId: options.modelId
49764
50015
  });
49765
50016
  const spec = getSherpaOnnxModelSpec(options.modelId);
49766
- const modelDir = path22.join(options.modelsDir, spec.extractedDir);
50017
+ const modelDir = path23.join(options.modelsDir, spec.extractedDir);
49767
50018
  if (await hasRequiredFiles(modelDir, spec.requiredFiles)) {
49768
50019
  return modelDir;
49769
50020
  }
49770
50021
  logger.info({ modelsDir: options.modelsDir }, "Starting model download");
49771
50022
  try {
49772
50023
  if (spec.archiveUrl) {
49773
- const downloadsDir = path22.join(options.modelsDir, ".downloads");
49774
- const archiveFilename = path22.basename(new URL(spec.archiveUrl).pathname);
49775
- const archivePath = path22.join(downloadsDir, archiveFilename);
50024
+ const downloadsDir = path23.join(options.modelsDir, ".downloads");
50025
+ const archiveFilename = path23.basename(new URL(spec.archiveUrl).pathname);
50026
+ const archivePath = path23.join(downloadsDir, archiveFilename);
49776
50027
  if (!await isNonEmptyFile(archivePath)) {
49777
50028
  await downloadToFile({
49778
50029
  url: spec.archiveUrl,
@@ -49817,7 +50068,7 @@ async function ensureSherpaOnnxModel(options) {
49817
50068
  if (spec.downloadFiles && spec.downloadFiles.length > 0) {
49818
50069
  await mkdir6(modelDir, { recursive: true });
49819
50070
  for (const file of spec.downloadFiles) {
49820
- const dst = path22.join(modelDir, file.relPath);
50071
+ const dst = path23.join(modelDir, file.relPath);
49821
50072
  if (await isNonEmptyFile(dst)) {
49822
50073
  continue;
49823
50074
  }
@@ -49876,17 +50127,17 @@ async function ensureLocalSpeechModels(options) {
49876
50127
  }
49877
50128
 
49878
50129
  // ../server/src/server/speech/providers/local/sherpa/sherpa-offline-recognizer.ts
49879
- import { existsSync as existsSync14 } from "node:fs";
50130
+ import { existsSync as existsSync15 } from "node:fs";
49880
50131
 
49881
50132
  // ../server/src/server/speech/providers/local/sherpa/sherpa-onnx-node-loader.ts
49882
50133
  import { createRequire as createRequire4 } from "node:module";
49883
- import path24 from "node:path";
49884
- import { existsSync as existsSync13 } from "node:fs";
50134
+ import path25 from "node:path";
50135
+ import { existsSync as existsSync14 } from "node:fs";
49885
50136
  import { spawnSync } from "node:child_process";
49886
50137
 
49887
50138
  // ../server/src/server/speech/providers/local/sherpa/sherpa-runtime-env.ts
49888
50139
  import { createRequire as createRequire3 } from "node:module";
49889
- import path23 from "node:path";
50140
+ import path24 from "node:path";
49890
50141
  function sherpaPlatformArch(platform = process.platform, arch = process.arch) {
49891
50142
  const normalizedPlatform = platform === "win32" ? "win" : platform;
49892
50143
  return `${normalizedPlatform}-${arch}`;
@@ -49907,11 +50158,11 @@ function sherpaLoaderEnvKey(platform = process.platform) {
49907
50158
  return null;
49908
50159
  }
49909
50160
  function prependEnvPath(existing, value) {
49910
- const parts = (existing ?? "").split(path23.delimiter).filter(Boolean);
50161
+ const parts = (existing ?? "").split(path24.delimiter).filter(Boolean);
49911
50162
  if (parts.includes(value)) {
49912
- return parts.join(path23.delimiter);
50163
+ return parts.join(path24.delimiter);
49913
50164
  }
49914
- return [value, ...parts].join(path23.delimiter);
50165
+ return [value, ...parts].join(path24.delimiter);
49915
50166
  }
49916
50167
  function resolveSherpaLoaderEnv(platform = process.platform, arch = process.arch) {
49917
50168
  const key = sherpaLoaderEnvKey(platform);
@@ -49924,7 +50175,7 @@ function resolveSherpaLoaderEnv(platform = process.platform, arch = process.arch
49924
50175
  const pkgJson = require4.resolve(`${packageName}/package.json`);
49925
50176
  return {
49926
50177
  key,
49927
- libDir: path23.dirname(pkgJson),
50178
+ libDir: path24.dirname(pkgJson),
49928
50179
  packageName
49929
50180
  };
49930
50181
  } catch {
@@ -50033,8 +50284,8 @@ function loadSherpaOnnxNode() {
50033
50284
  const platformPkgDir = resolvedEnv?.libDir ?? null;
50034
50285
  if (platformPkgDir) {
50035
50286
  applySherpaLoaderEnv(process.env);
50036
- const addonPath = path24.join(platformPkgDir, "sherpa-onnx.node");
50037
- if (existsSync13(addonPath)) {
50287
+ const addonPath = path25.join(platformPkgDir, "sherpa-onnx.node");
50288
+ if (existsSync14(addonPath)) {
50038
50289
  const byPath = loadWithRequire(require4, addonPath, attempts);
50039
50290
  if (byPath) {
50040
50291
  cached = byPath;
@@ -50053,7 +50304,7 @@ function loadSherpaOnnxNode() {
50053
50304
 
50054
50305
  // ../server/src/server/speech/providers/local/sherpa/sherpa-offline-recognizer.ts
50055
50306
  function assertFileExists(filePath, label) {
50056
- if (!existsSync14(filePath)) {
50307
+ if (!existsSync15(filePath)) {
50057
50308
  throw new Error(`Missing ${label}: ${filePath}`);
50058
50309
  }
50059
50310
  }
@@ -50120,7 +50371,7 @@ var SherpaOfflineRecognizerEngine = class {
50120
50371
  };
50121
50372
 
50122
50373
  // ../server/src/server/speech/providers/local/sherpa/sherpa-online-recognizer.ts
50123
- import { existsSync as existsSync15 } from "node:fs";
50374
+ import { existsSync as existsSync16 } from "node:fs";
50124
50375
 
50125
50376
  // ../server/src/server/speech/providers/local/sherpa/sherpa-onnx-loader.ts
50126
50377
  import { createRequire as createRequire5 } from "node:module";
@@ -50136,7 +50387,7 @@ function loadSherpaOnnx() {
50136
50387
 
50137
50388
  // ../server/src/server/speech/providers/local/sherpa/sherpa-online-recognizer.ts
50138
50389
  function assertFileExists2(filePath, label) {
50139
- if (!existsSync15(filePath)) {
50390
+ if (!existsSync16(filePath)) {
50140
50391
  throw new Error(`Missing ${label}: ${filePath}`);
50141
50392
  }
50142
50393
  }
@@ -50712,9 +50963,9 @@ var SherpaOnnxSTT = class {
50712
50963
 
50713
50964
  // ../server/src/server/speech/providers/local/sherpa/sherpa-tts.ts
50714
50965
  import { Readable as Readable3 } from "node:stream";
50715
- import { existsSync as existsSync16 } from "node:fs";
50966
+ import { existsSync as existsSync17 } from "node:fs";
50716
50967
  function assertFileExists3(filePath, label) {
50717
- if (!existsSync16(filePath)) {
50968
+ if (!existsSync17(filePath)) {
50718
50969
  throw new Error(`Missing ${label}: ${filePath}`);
50719
50970
  }
50720
50971
  }
@@ -50805,7 +51056,7 @@ var SherpaOnnxTTS = class {
50805
51056
 
50806
51057
  // ../server/src/server/speech/providers/local/sherpa/silero-vad-provider.ts
50807
51058
  import { copyFile, mkdir as mkdir7, stat as stat6 } from "node:fs/promises";
50808
- import path25 from "node:path";
51059
+ import path26 from "node:path";
50809
51060
 
50810
51061
  // ../server/src/server/speech/providers/local/sherpa/silero-vad-session.ts
50811
51062
  import { EventEmitter as EventEmitter6 } from "node:events";
@@ -50997,8 +51248,8 @@ var SherpaSileroVadSession = class extends EventEmitter6 {
50997
51248
  var SILERO_VAD_DIR = "silero-vad";
50998
51249
  var SILERO_VAD_FILE = "silero_vad.onnx";
50999
51250
  async function ensureSileroVadModel(modelsDir, logger) {
51000
- const destDir = path25.join(modelsDir, SILERO_VAD_DIR);
51001
- const destPath = path25.join(destDir, SILERO_VAD_FILE);
51251
+ const destDir = path26.join(modelsDir, SILERO_VAD_DIR);
51252
+ const destPath = path26.join(destDir, SILERO_VAD_FILE);
51002
51253
  try {
51003
51254
  const s = await stat6(destPath);
51004
51255
  if (s.isFile() && s.size > 0) return destPath;
@@ -52422,7 +52673,7 @@ import { z as z40 } from "zod";
52422
52673
  import { getSessionMessages } from "@anthropic-ai/claude-agent-sdk";
52423
52674
 
52424
52675
  // ../server/src/server/agent/session-fork.ts
52425
- import { readFileSync as readFileSync9, writeFileSync as writeFileSync7, readdirSync as readdirSync2, existsSync as existsSync17 } from "node:fs";
52676
+ import { readFileSync as readFileSync9, writeFileSync as writeFileSync7, readdirSync as readdirSync2, existsSync as existsSync18 } from "node:fs";
52426
52677
  import { dirname as dirname7, join as join18 } from "node:path";
52427
52678
  import { homedir as homedir6 } from "node:os";
52428
52679
  var ForkPointInvalidError = class extends Error {
@@ -52457,11 +52708,11 @@ function extractUserMessageText2(message) {
52457
52708
  function findClaudeSessionFile(params) {
52458
52709
  const home = params.claudeHomeDir ?? join18(homedir6(), ".claude");
52459
52710
  const projectsDir = join18(home, "projects");
52460
- if (!existsSync17(projectsDir)) return null;
52711
+ if (!existsSync18(projectsDir)) return null;
52461
52712
  for (const entry of readdirSync2(projectsDir, { withFileTypes: true })) {
52462
52713
  if (!entry.isDirectory()) continue;
52463
52714
  const candidate = join18(projectsDir, entry.name, `${params.sessionId}.jsonl`);
52464
- if (existsSync17(candidate)) return candidate;
52715
+ if (existsSync18(candidate)) return candidate;
52465
52716
  }
52466
52717
  return null;
52467
52718
  }
@@ -52514,7 +52765,7 @@ function forkSession(input) {
52514
52765
  }
52515
52766
  const copied = lines.slice(0, forkLineIndex).filter((l) => l.length > 0);
52516
52767
  const targetDir = dirname7(input.targetSessionPath);
52517
- if (!existsSync17(targetDir)) {
52768
+ if (!existsSync18(targetDir)) {
52518
52769
  throw new Error(`Target directory does not exist: ${targetDir}`);
52519
52770
  }
52520
52771
  const payload = copied.length > 0 ? copied.join("\n") + "\n" : "";
@@ -53124,6 +53375,7 @@ var AgentManager = class {
53124
53375
  this.mcpBaseUrl = options?.mcpBaseUrl ?? null;
53125
53376
  this.appostleHome = options?.appostleHome ?? null;
53126
53377
  this.chromeEnabled = options?.chromeEnabled ?? true;
53378
+ this.ownerUserId = options?.ownerUserId ?? null;
53127
53379
  this.logger = options.logger.child({ module: "agent", component: "agent-manager" });
53128
53380
  this.agentStreamCoalescer = new AgentStreamCoalescer({
53129
53381
  windowMs: options.agentStreamCoalesceWindowMs ?? AGENT_STREAM_COALESCE_DEFAULT_WINDOW_MS,
@@ -53381,7 +53633,10 @@ var AgentManager = class {
53381
53633
  mcpServers
53382
53634
  };
53383
53635
  const normalizedConfig = await this.normalizeConfig(injectedConfig);
53384
- const launchContext = this.buildLaunchContext(resolvedAgentId);
53636
+ const launchContext = this.buildLaunchContext(resolvedAgentId, {
53637
+ userId: options?.userId,
53638
+ username: options?.username
53639
+ });
53385
53640
  const client = this.requireClient(normalizedConfig.provider);
53386
53641
  const available = await client.isAvailable();
53387
53642
  if (!available) {
@@ -55266,13 +55521,19 @@ var AgentManager = class {
55266
55521
  }
55267
55522
  return normalized;
55268
55523
  }
55269
- buildLaunchContext(agentId) {
55270
- return {
55271
- env: {
55272
- APPOSTLE_AGENT_ID: agentId
55273
- },
55274
- chromeEnabled: this.chromeEnabled
55524
+ buildLaunchContext(agentId, user) {
55525
+ const env = {
55526
+ APPOSTLE_AGENT_ID: agentId
55275
55527
  };
55528
+ if (user?.username && user?.userId && this.ownerUserId && user.userId !== this.ownerUserId) {
55529
+ const profileDir = ensureClaudeProfile(user.username, this.logger);
55530
+ env.CLAUDE_CONFIG_DIR = profileDir;
55531
+ this.logger.info(
55532
+ { username: user.username, userId: user.userId, profileDir },
55533
+ "using shared user claude profile"
55534
+ );
55535
+ }
55536
+ return { env, chromeEnabled: this.chromeEnabled };
55276
55537
  }
55277
55538
  requireClient(provider) {
55278
55539
  const client = this.clients.get(provider);
@@ -55301,7 +55562,7 @@ var AgentManager = class {
55301
55562
  // ../server/src/server/agent/agent-storage.ts
55302
55563
  import { randomUUID as randomUUID12 } from "node:crypto";
55303
55564
  import { promises as fs15 } from "node:fs";
55304
- import path26 from "node:path";
55565
+ import path27 from "node:path";
55305
55566
  import { z as z41 } from "zod";
55306
55567
  var SERIALIZABLE_CONFIG_SCHEMA = z41.object({
55307
55568
  title: z41.string().nullable().optional(),
@@ -55388,7 +55649,7 @@ var AgentStorage = class {
55388
55649
  }
55389
55650
  const nextPath = this.buildRecordPath(record);
55390
55651
  const previousPath = this.pathById.get(agentId);
55391
- await fs15.mkdir(path26.dirname(nextPath), { recursive: true });
55652
+ await fs15.mkdir(path27.dirname(nextPath), { recursive: true });
55392
55653
  await writeFileAtomically(nextPath, JSON.stringify(record, null, 2));
55393
55654
  this.addIndexedPath(agentId, nextPath);
55394
55655
  if (previousPath && previousPath !== nextPath) {
@@ -55504,7 +55765,7 @@ var AgentStorage = class {
55504
55765
  }
55505
55766
  for (const entry of entries) {
55506
55767
  if (entry.isFile() && entry.name.endsWith(".json")) {
55507
- const rootPath = path26.join(this.baseDir, entry.name);
55768
+ const rootPath = path27.join(this.baseDir, entry.name);
55508
55769
  const rootRecord = await this.readRecordFile(rootPath);
55509
55770
  if (!rootRecord) {
55510
55771
  continue;
@@ -55518,7 +55779,7 @@ var AgentStorage = class {
55518
55779
  if (!entry.isDirectory()) {
55519
55780
  continue;
55520
55781
  }
55521
- const projectDir = path26.join(this.baseDir, entry.name);
55782
+ const projectDir = path27.join(this.baseDir, entry.name);
55522
55783
  let files = [];
55523
55784
  try {
55524
55785
  files = await fs15.readdir(projectDir, { withFileTypes: true });
@@ -55529,7 +55790,7 @@ var AgentStorage = class {
55529
55790
  if (!file.isFile() || !file.name.endsWith(".json")) {
55530
55791
  continue;
55531
55792
  }
55532
- const filePath = path26.join(projectDir, file.name);
55793
+ const filePath = path27.join(projectDir, file.name);
55533
55794
  const record = await this.readRecordFile(filePath);
55534
55795
  if (!record) {
55535
55796
  continue;
@@ -55554,7 +55815,7 @@ var AgentStorage = class {
55554
55815
  }
55555
55816
  buildRecordPath(record) {
55556
55817
  const projectDir = projectDirNameFromCwd(record.cwd);
55557
- return path26.join(this.baseDir, projectDir, `${record.id}.json`);
55818
+ return path27.join(this.baseDir, projectDir, `${record.id}.json`);
55558
55819
  }
55559
55820
  addIndexedPath(agentId, filePath) {
55560
55821
  const paths = this.pathsById.get(agentId) ?? /* @__PURE__ */ new Set();
@@ -55576,7 +55837,7 @@ var AgentStorage = class {
55576
55837
  }
55577
55838
  };
55578
55839
  function projectDirNameFromCwd(cwd) {
55579
- const { root } = path26.win32.parse(cwd);
55840
+ const { root } = path27.win32.parse(cwd);
55580
55841
  const withoutRoot = cwd.slice(root.length).replace(/[\\/]+$/, "");
55581
55842
  const sanitizedRoot = root.replace(/[:\\/]+/g, "-").replace(/^-+|-+$/g, "");
55582
55843
  const prefix = sanitizedRoot ? sanitizedRoot + "-" : "";
@@ -55586,8 +55847,8 @@ function projectDirNameFromCwd(cwd) {
55586
55847
  return prefix + withoutRoot.replace(/[\\/]+/g, "-");
55587
55848
  }
55588
55849
  async function writeFileAtomically(targetPath, payload) {
55589
- const directory = path26.dirname(targetPath);
55590
- const tempPath = path26.join(directory, `.agent.tmp-${process.pid}-${Date.now()}-${randomUUID12()}`);
55850
+ const directory = path27.dirname(targetPath);
55851
+ const tempPath = path27.join(directory, `.agent.tmp-${process.pid}-${Date.now()}-${randomUUID12()}`);
55591
55852
  await fs15.writeFile(tempPath, payload, "utf8");
55592
55853
  await fs15.rename(tempPath, targetPath);
55593
55854
  }
@@ -57095,7 +57356,7 @@ async function createMcpWorktree(options) {
57095
57356
  }
57096
57357
 
57097
57358
  // ../server/src/server/workspace-registry-bootstrap.ts
57098
- import path27 from "node:path";
57359
+ import path28 from "node:path";
57099
57360
  function minIsoDate(left, right) {
57100
57361
  if (!left) {
57101
57362
  return right;
@@ -57192,8 +57453,8 @@ async function bootstrapWorkspaceRegistries(options) {
57192
57453
  }
57193
57454
  options.logger.info(
57194
57455
  {
57195
- projectsFile: path27.join(options.appostleHome, "projects", "projects.json"),
57196
- workspacesFile: path27.join(options.appostleHome, "projects", "workspaces.json"),
57456
+ projectsFile: path28.join(options.appostleHome, "projects", "projects.json"),
57457
+ workspacesFile: path28.join(options.appostleHome, "projects", "workspaces.json"),
57197
57458
  materializedProjects: projectRanges.size,
57198
57459
  materializedWorkspaces: recordsByWorkspaceId.size
57199
57460
  },
@@ -57390,7 +57651,7 @@ var CheckoutDiffManager = class {
57390
57651
  // ../server/src/server/loop-service.ts
57391
57652
  import { randomUUID as randomUUID13 } from "node:crypto";
57392
57653
  import { promises as fs16 } from "node:fs";
57393
- import path28 from "node:path";
57654
+ import path29 from "node:path";
57394
57655
  import { z as z43 } from "zod";
57395
57656
  var LOOP_ID_LENGTH = 8;
57396
57657
  var DEFAULT_LOOP_PROVIDER = "claude";
@@ -57596,7 +57857,7 @@ var LoopService = class {
57596
57857
  this.loops = /* @__PURE__ */ new Map();
57597
57858
  this.persistQueue = Promise.resolve();
57598
57859
  this.running = /* @__PURE__ */ new Map();
57599
- this.storePath = path28.join(options.appostleHome, "loops", "loops.json");
57860
+ this.storePath = path29.join(options.appostleHome, "loops", "loops.json");
57600
57861
  this.logger = options.logger.child({ module: "loop-service" });
57601
57862
  }
57602
57863
  async initialize() {
@@ -57665,7 +57926,7 @@ var LoopService = class {
57665
57926
  id: createLoopId(),
57666
57927
  name: normalizeName(input.name),
57667
57928
  prompt,
57668
- cwd: path28.resolve(input.cwd),
57929
+ cwd: path29.resolve(input.cwd),
57669
57930
  provider: input.provider ?? DEFAULT_LOOP_PROVIDER,
57670
57931
  model: normalizePrompt(input.model, "model"),
57671
57932
  workerProvider: input.workerProvider ?? null,
@@ -58113,7 +58374,7 @@ ${output}` : `exit ${result.exitCode}`
58113
58374
  }
58114
58375
  async persist() {
58115
58376
  const nextPersist = this.persistQueue.then(async () => {
58116
- await fs16.mkdir(path28.dirname(this.storePath), { recursive: true });
58377
+ await fs16.mkdir(path29.dirname(this.storePath), { recursive: true });
58117
58378
  const records = Array.from(this.loops.values()).sort(
58118
58379
  (left, right) => left.createdAt.localeCompare(right.createdAt)
58119
58380
  );
@@ -58659,12 +58920,12 @@ import { randomUUID as randomUUID15 } from "node:crypto";
58659
58920
 
58660
58921
  // ../server/src/server/quest/store.ts
58661
58922
  import { promises as fs17 } from "node:fs";
58662
- import path29 from "node:path";
58923
+ import path30 from "node:path";
58663
58924
  import { z as z44 } from "zod";
58664
58925
  var StoredQuestsSchema = z44.array(QuestRecordSchema);
58665
58926
  var QuestStore = class {
58666
58927
  constructor(options) {
58667
- this.filePath = path29.join(options.appostleHome, "quests", "quests.json");
58928
+ this.filePath = path30.join(options.appostleHome, "quests", "quests.json");
58668
58929
  this.logger = options.logger;
58669
58930
  this.records = /* @__PURE__ */ new Map();
58670
58931
  this.persistQueue = Promise.resolve();
@@ -58705,7 +58966,7 @@ var QuestStore = class {
58705
58966
  }
58706
58967
  async persist() {
58707
58968
  this.persistQueue = this.persistQueue.then(async () => {
58708
- await fs17.mkdir(path29.dirname(this.filePath), { recursive: true });
58969
+ await fs17.mkdir(path30.dirname(this.filePath), { recursive: true });
58709
58970
  const payload = JSON.stringify([...this.records.values()], null, 2);
58710
58971
  await fs17.writeFile(this.filePath, payload, "utf8");
58711
58972
  }).catch((err) => {
@@ -59471,7 +59732,7 @@ ${text || "(no output)"}`).join("\n\n");
59471
59732
 
59472
59733
  // ../server/src/server/quest/runner-orchestrator.ts
59473
59734
  import { access, readFile as readFile5 } from "node:fs/promises";
59474
- import path30 from "node:path";
59735
+ import path31 from "node:path";
59475
59736
  import { fileURLToPath as fileURLToPath5 } from "node:url";
59476
59737
 
59477
59738
  // ../server/src/server/quest/orchestrator-mcp.ts
@@ -59702,16 +59963,16 @@ var FALLBACK_QUEEN_PROMPT_TEMPLATE = [
59702
59963
  var QUEEN_PROMPT_FILENAME = "queen-prompt.md";
59703
59964
  var QUEEN_PROMPT_MAX_LOOKUP_LEVELS = 10;
59704
59965
  async function findQueenPromptOnDisk() {
59705
- const start = path30.dirname(fileURLToPath5(import.meta.url));
59966
+ const start = path31.dirname(fileURLToPath5(import.meta.url));
59706
59967
  let cursor = start;
59707
59968
  for (let i = 0; i < QUEEN_PROMPT_MAX_LOOKUP_LEVELS; i += 1) {
59708
- const candidate = path30.join(cursor, QUEEN_PROMPT_FILENAME);
59969
+ const candidate = path31.join(cursor, QUEEN_PROMPT_FILENAME);
59709
59970
  try {
59710
59971
  await access(candidate);
59711
59972
  return candidate;
59712
59973
  } catch {
59713
59974
  }
59714
- const parent = path30.dirname(cursor);
59975
+ const parent = path31.dirname(cursor);
59715
59976
  if (parent === cursor) break;
59716
59977
  cursor = parent;
59717
59978
  }
@@ -59757,7 +60018,7 @@ async function resolveWorkerConfigForHandoff(args) {
59757
60018
  title: `quest ${record.id} handoff: ${taskTitle}`,
59758
60019
  internal: true
59759
60020
  };
59760
- const roleName = path30.basename(rolePath, path30.extname(rolePath));
60021
+ const roleName = path31.basename(rolePath, path31.extname(rolePath));
59761
60022
  try {
59762
60023
  const resolved = await resolveRole({
59763
60024
  roleName,
@@ -59936,7 +60197,7 @@ var OrchestratorRunner = class {
59936
60197
  import { promisify as promisify4 } from "node:util";
59937
60198
  import { execFile as execFile3 } from "node:child_process";
59938
60199
  import { appendFile, mkdir as mkdir9, writeFile as writeFile8 } from "node:fs/promises";
59939
- import path31 from "node:path";
60200
+ import path32 from "node:path";
59940
60201
  var execFileAsync3 = promisify4(execFile3);
59941
60202
  var MAX_VERIFY_OUTPUT_BYTES2 = 64 * 1024;
59942
60203
  function nowIso5() {
@@ -60011,7 +60272,7 @@ function runContainsPromise(run, completionPromise) {
60011
60272
  return finalText.includes(completionPromise);
60012
60273
  }
60013
60274
  function resolveRalphStatePaths(cwd) {
60014
- const dir = path31.join(cwd, ".hiveminds", "ralph loop");
60275
+ const dir = path32.join(cwd, ".hiveminds", "ralph loop");
60015
60276
  return {
60016
60277
  dir,
60017
60278
  logPath: ""
@@ -60021,7 +60282,7 @@ async function initializeRalphState(args) {
60021
60282
  const base = resolveRalphStatePaths(args.record.cwd);
60022
60283
  const paths = {
60023
60284
  dir: base.dir,
60024
- logPath: path31.join(base.dir, `ralphloop_${args.record.id}.md`)
60285
+ logPath: path32.join(base.dir, `ralphloop_${args.record.id}.md`)
60025
60286
  };
60026
60287
  await mkdir9(paths.dir, { recursive: true });
60027
60288
  await writeFile8(
@@ -60256,8 +60517,8 @@ function deepMerge(current, patch) {
60256
60517
  }
60257
60518
  return next;
60258
60519
  }
60259
- function getValueAtPath(config, path37) {
60260
- return path37.split(".").reduce((value, segment) => isRecord3(value) ? value[segment] : void 0, config);
60520
+ function getValueAtPath(config, path38) {
60521
+ return path38.split(".").reduce((value, segment) => isRecord3(value) ? value[segment] : void 0, config);
60261
60522
  }
60262
60523
  function isEqualValue(a, b) {
60263
60524
  return JSON.stringify(a) === JSON.stringify(b);
@@ -60276,20 +60537,20 @@ var DaemonConfigStore = class {
60276
60537
  patch(partial) {
60277
60538
  const parsedPatch = MutableDaemonConfigPatchSchema.parse(partial);
60278
60539
  const next = MutableDaemonConfigSchema.parse(deepMerge(this.current, parsedPatch));
60279
- const changedFieldPaths = Array.from(this.fieldChangeHandlers.keys()).filter((path37) => {
60280
- return !isEqualValue(getValueAtPath(this.current, path37), getValueAtPath(next, path37));
60540
+ const changedFieldPaths = Array.from(this.fieldChangeHandlers.keys()).filter((path38) => {
60541
+ return !isEqualValue(getValueAtPath(this.current, path38), getValueAtPath(next, path38));
60281
60542
  });
60282
60543
  if (changedFieldPaths.length === 0 && isEqualValue(this.current, next)) {
60283
60544
  return this.current;
60284
60545
  }
60285
60546
  this.persistConfig(next);
60286
60547
  this.current = next;
60287
- for (const path37 of changedFieldPaths) {
60288
- const handlers = this.fieldChangeHandlers.get(path37);
60548
+ for (const path38 of changedFieldPaths) {
60549
+ const handlers = this.fieldChangeHandlers.get(path38);
60289
60550
  if (!handlers) {
60290
60551
  continue;
60291
60552
  }
60292
- const value = getValueAtPath(next, path37);
60553
+ const value = getValueAtPath(next, path38);
60293
60554
  for (const handler of handlers) {
60294
60555
  handler(value);
60295
60556
  }
@@ -60299,18 +60560,18 @@ var DaemonConfigStore = class {
60299
60560
  }
60300
60561
  return next;
60301
60562
  }
60302
- onFieldChange(path37, handler) {
60303
- const handlers = this.fieldChangeHandlers.get(path37) ?? /* @__PURE__ */ new Set();
60563
+ onFieldChange(path38, handler) {
60564
+ const handlers = this.fieldChangeHandlers.get(path38) ?? /* @__PURE__ */ new Set();
60304
60565
  handlers.add(handler);
60305
- this.fieldChangeHandlers.set(path37, handlers);
60566
+ this.fieldChangeHandlers.set(path38, handlers);
60306
60567
  return () => {
60307
- const currentHandlers = this.fieldChangeHandlers.get(path37);
60568
+ const currentHandlers = this.fieldChangeHandlers.get(path38);
60308
60569
  if (!currentHandlers) {
60309
60570
  return;
60310
60571
  }
60311
60572
  currentHandlers.delete(handler);
60312
60573
  if (currentHandlers.size === 0) {
60313
- this.fieldChangeHandlers.delete(path37);
60574
+ this.fieldChangeHandlers.delete(path38);
60314
60575
  }
60315
60576
  };
60316
60577
  }
@@ -61806,8 +62067,8 @@ function createAuthServerClient(options) {
61806
62067
  }
61807
62068
 
61808
62069
  // ../server/src/server/package-version.ts
61809
- import { existsSync as existsSync18, readFileSync as readFileSync10 } from "node:fs";
61810
- import path32 from "node:path";
62070
+ import { existsSync as existsSync19, readFileSync as readFileSync10 } from "node:fs";
62071
+ import path33 from "node:path";
61811
62072
  import { fileURLToPath as fileURLToPath6 } from "node:url";
61812
62073
  var PackageVersionResolutionError = class extends Error {
61813
62074
  constructor(params) {
@@ -61817,10 +62078,10 @@ var PackageVersionResolutionError = class extends Error {
61817
62078
  };
61818
62079
  function resolvePackageVersion(params) {
61819
62080
  const moduleUrl = params.moduleUrl ?? import.meta.url;
61820
- let currentDir = path32.dirname(fileURLToPath6(moduleUrl));
62081
+ let currentDir = path33.dirname(fileURLToPath6(moduleUrl));
61821
62082
  while (true) {
61822
- const packageJsonPath = path32.join(currentDir, "package.json");
61823
- if (existsSync18(packageJsonPath)) {
62083
+ const packageJsonPath = path33.join(currentDir, "package.json");
62084
+ if (existsSync19(packageJsonPath)) {
61824
62085
  try {
61825
62086
  const packageJson = JSON.parse(readFileSync10(packageJsonPath, "utf8"));
61826
62087
  if (packageJson.name === params.packageName) {
@@ -61838,7 +62099,7 @@ function resolvePackageVersion(params) {
61838
62099
  }
61839
62100
  }
61840
62101
  }
61841
- const parentDir = path32.dirname(currentDir);
62102
+ const parentDir = path33.dirname(currentDir);
61842
62103
  if (parentDir === currentDir) {
61843
62104
  break;
61844
62105
  }
@@ -62203,8 +62464,10 @@ async function createAppostleDaemon(config, rootLogger) {
62203
62464
  const daemonKeyPair = await loadOrCreateDaemonKeyPair(config.appostleHome, logger);
62204
62465
  let relayTransport = null;
62205
62466
  let authServerClient = null;
62467
+ let ownerUserId = null;
62206
62468
  {
62207
62469
  const persisted = loadPersistedConfig(config.appostleHome, logger);
62470
+ ownerUserId = persisted.account?.userId ?? null;
62208
62471
  if (persisted.account) {
62209
62472
  authServerClient = createAuthServerClient({
62210
62473
  logger,
@@ -62341,11 +62604,11 @@ async function createAppostleDaemon(config, rootLogger) {
62341
62604
  httpServer.on("upgrade", scriptProxyUpgradeHandler);
62342
62605
  const agentStorage = new AgentStorage(config.agentStoragePath, logger);
62343
62606
  const projectRegistry = new FileBackedProjectRegistry(
62344
- path33.join(config.appostleHome, "projects", "projects.json"),
62607
+ path34.join(config.appostleHome, "projects", "projects.json"),
62345
62608
  logger
62346
62609
  );
62347
62610
  workspaceRegistry = new FileBackedWorkspaceRegistry(
62348
- path33.join(config.appostleHome, "projects", "workspaces.json"),
62611
+ path34.join(config.appostleHome, "projects", "workspaces.json"),
62349
62612
  logger
62350
62613
  );
62351
62614
  const chatService = new FileBackedChatService({
@@ -62363,6 +62626,7 @@ async function createAppostleDaemon(config, rootLogger) {
62363
62626
  registry: agentStorage,
62364
62627
  appostleHome: config.appostleHome,
62365
62628
  chromeEnabled: config.chromeEnabled ?? true,
62629
+ ownerUserId: ownerUserId ?? void 0,
62366
62630
  logger
62367
62631
  });
62368
62632
  const providerRegistry = buildProviderRegistry(logger, {
@@ -62691,7 +62955,7 @@ async function createAppostleDaemon(config, rootLogger) {
62691
62955
  if (listenTarget.type === "tcp") {
62692
62956
  httpServer.listen(listenTarget.port, listenTarget.host);
62693
62957
  } else {
62694
- if (listenTarget.type === "socket" && existsSync19(listenTarget.path)) {
62958
+ if (listenTarget.type === "socket" && existsSync20(listenTarget.path)) {
62695
62959
  unlinkSync(listenTarget.path);
62696
62960
  }
62697
62961
  httpServer.listen(listenTarget.path);
@@ -62721,7 +62985,7 @@ async function createAppostleDaemon(config, rootLogger) {
62721
62985
  await new Promise((resolve15) => {
62722
62986
  httpServer.close(() => resolve15());
62723
62987
  });
62724
- if (listenTarget.type === "socket" && existsSync19(listenTarget.path)) {
62988
+ if (listenTarget.type === "socket" && existsSync20(listenTarget.path)) {
62725
62989
  unlinkSync(listenTarget.path);
62726
62990
  }
62727
62991
  };
@@ -62752,16 +63016,16 @@ async function closeAllAgents(logger, agentManager) {
62752
63016
  }
62753
63017
 
62754
63018
  // ../server/src/server/config.ts
62755
- import path35 from "node:path";
63019
+ import path36 from "node:path";
62756
63020
  import { z as z51 } from "zod";
62757
63021
 
62758
63022
  // ../server/src/server/speech/speech-config-resolver.ts
62759
63023
  import { z as z50 } from "zod";
62760
63024
 
62761
63025
  // ../server/src/server/speech/providers/local/config.ts
62762
- import path34 from "node:path";
63026
+ import path35 from "node:path";
62763
63027
  import { z as z48 } from "zod";
62764
- var DEFAULT_LOCAL_MODELS_SUBDIR = path34.join("models", "local-speech");
63028
+ var DEFAULT_LOCAL_MODELS_SUBDIR = path35.join("models", "local-speech");
62765
63029
  var NumberLikeSchema2 = z48.union([z48.number(), z48.string().trim().min(1)]);
62766
63030
  var OptionalFiniteNumberSchema2 = NumberLikeSchema2.pipe(z48.coerce.number().finite()).optional();
62767
63031
  var OptionalIntegerSchema = NumberLikeSchema2.pipe(z48.coerce.number().int()).optional();
@@ -62788,7 +63052,7 @@ function resolveLocalSpeechConfig(params) {
62788
63052
  const includeProviderConfig = shouldIncludeLocalProviderConfig(params);
62789
63053
  const parsed = LocalSpeechResolutionSchema.parse({
62790
63054
  includeProviderConfig,
62791
- modelsDir: params.env.APPOSTLE_LOCAL_MODELS_DIR ?? params.persisted.providers?.local?.modelsDir ?? path34.join(params.appostleHome, DEFAULT_LOCAL_MODELS_SUBDIR),
63055
+ modelsDir: params.env.APPOSTLE_LOCAL_MODELS_DIR ?? params.persisted.providers?.local?.modelsDir ?? path35.join(params.appostleHome, DEFAULT_LOCAL_MODELS_SUBDIR),
62792
63056
  dictationLocalSttModel: params.env.APPOSTLE_DICTATION_LOCAL_STT_MODEL ?? persistedLocalFeatureModel(
62793
63057
  params.providers.dictationStt.provider,
62794
63058
  params.providers.dictationStt.enabled,
@@ -63044,7 +63308,7 @@ function loadConfig(appostleHome, options) {
63044
63308
  chromeEnabled,
63045
63309
  mcpDebug: env.MCP_DEBUG === "1",
63046
63310
  daemonIcon,
63047
- agentStoragePath: path35.join(appostleHome, "agents"),
63311
+ agentStoragePath: path36.join(appostleHome, "agents"),
63048
63312
  staticDir: "public",
63049
63313
  agentClients: {},
63050
63314
  relayEnabled,
@@ -63062,8 +63326,8 @@ function loadConfig(appostleHome, options) {
63062
63326
  }
63063
63327
 
63064
63328
  // ../server/src/server/logger.ts
63065
- import { existsSync as existsSync20, mkdirSync as mkdirSync7, readdirSync as readdirSync3, renameSync as renameSync3, unlinkSync as unlinkSync2 } from "node:fs";
63066
- import path36 from "node:path";
63329
+ import { existsSync as existsSync21, mkdirSync as mkdirSync8, readdirSync as readdirSync3, renameSync as renameSync3, unlinkSync as unlinkSync2 } from "node:fs";
63330
+ import path37 from "node:path";
63067
63331
  import pino from "pino";
63068
63332
  import pretty from "pino-pretty";
63069
63333
  import { createStream as createRotatingFileStream } from "rotating-file-stream";
@@ -63106,14 +63370,14 @@ function parsePositiveInteger(value) {
63106
63370
  return parsed;
63107
63371
  }
63108
63372
  function resolveFilePath(appostleHome, configuredPath) {
63109
- const fallback = path36.join(appostleHome, DEFAULT_DAEMON_LOG_FILENAME);
63373
+ const fallback = path37.join(appostleHome, DEFAULT_DAEMON_LOG_FILENAME);
63110
63374
  if (!configuredPath) {
63111
63375
  return fallback;
63112
63376
  }
63113
- if (path36.isAbsolute(configuredPath)) {
63377
+ if (path37.isAbsolute(configuredPath)) {
63114
63378
  return configuredPath;
63115
63379
  }
63116
- return path36.resolve(appostleHome, configuredPath);
63380
+ return path37.resolve(appostleHome, configuredPath);
63117
63381
  }
63118
63382
  function minLogLevel(levels) {
63119
63383
  let minLevel = levels[0];
@@ -63149,21 +63413,21 @@ function normalizeLoggerConfigInput(config) {
63149
63413
  return config;
63150
63414
  }
63151
63415
  function rotateOnRestart(filePath, maxFiles) {
63152
- if (!existsSync20(filePath)) return;
63153
- const dir = path36.dirname(filePath);
63154
- const base = path36.basename(filePath);
63416
+ if (!existsSync21(filePath)) return;
63417
+ const dir = path37.dirname(filePath);
63418
+ const base = path37.basename(filePath);
63155
63419
  const now = /* @__PURE__ */ new Date();
63156
63420
  const pad = (n) => String(n).padStart(2, "0");
63157
63421
  const ts = `${now.getFullYear()}${pad(now.getMonth() + 1)}${pad(now.getDate())}-${pad(now.getHours())}${pad(now.getMinutes())}`;
63158
63422
  try {
63159
- renameSync3(filePath, path36.join(dir, `${ts}-00-${base}`));
63423
+ renameSync3(filePath, path37.join(dir, `${ts}-00-${base}`));
63160
63424
  } catch {
63161
63425
  return;
63162
63426
  }
63163
63427
  const rotatedFiles = readdirSync3(dir).filter((f) => f.endsWith(`-${base}`) && f !== base).sort().reverse();
63164
63428
  for (const file of rotatedFiles.slice(maxFiles)) {
63165
63429
  try {
63166
- unlinkSync2(path36.join(dir, file));
63430
+ unlinkSync2(path37.join(dir, file));
63167
63431
  } catch {
63168
63432
  }
63169
63433
  }
@@ -63212,15 +63476,15 @@ function resolveLogConfig(configInput, options) {
63212
63476
  }
63213
63477
  function createRootLogger(configInput, options) {
63214
63478
  const config = resolveLogConfig(configInput, options);
63215
- mkdirSync7(path36.dirname(config.file.path), { recursive: true });
63479
+ mkdirSync8(path37.dirname(config.file.path), { recursive: true });
63216
63480
  const consoleStream = config.console.format === "pretty" ? pretty({
63217
63481
  colorize: true,
63218
63482
  singleLine: true,
63219
63483
  ignore: "pid,hostname"
63220
63484
  }) : pino.destination({ dest: 1, sync: false });
63221
63485
  rotateOnRestart(config.file.path, config.file.rotate.maxFiles);
63222
- const fileStream = createRotatingFileStream(path36.basename(config.file.path), {
63223
- path: path36.dirname(config.file.path),
63486
+ const fileStream = createRotatingFileStream(path37.basename(config.file.path), {
63487
+ path: path37.dirname(config.file.path),
63224
63488
  size: toRotatingFileStreamSize(config.file.rotate.maxSize),
63225
63489
  maxFiles: config.file.rotate.maxFiles
63226
63490
  });
@@ -63235,7 +63499,7 @@ function createRootLogger(configInput, options) {
63235
63499
 
63236
63500
  // ../server/src/server/pid-lock.ts
63237
63501
  import { open, readFile as readFile7, unlink as unlink4, mkdir as mkdir10 } from "node:fs/promises";
63238
- import { existsSync as existsSync21 } from "node:fs";
63502
+ import { existsSync as existsSync22 } from "node:fs";
63239
63503
  import { join as join23 } from "node:path";
63240
63504
  import { hostname } from "node:os";
63241
63505
  var PidLockError = class extends Error {
@@ -63264,7 +63528,7 @@ function resolveOwnerPid(ownerPid) {
63264
63528
  }
63265
63529
  async function acquirePidLock(appostleHome, listen, options) {
63266
63530
  const pidPath = getPidFilePath(appostleHome);
63267
- if (!existsSync21(appostleHome)) {
63531
+ if (!existsSync22(appostleHome)) {
63268
63532
  await mkdir10(appostleHome, { recursive: true });
63269
63533
  }
63270
63534
  let existingLock = null;