appostle-installer 0.0.13 → 0.0.15
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/appostle.js +1069 -381
- package/dist/appostle.js.map +4 -4
- package/dist/worker.js +20852 -20028
- package/dist/worker.js.map +4 -4
- package/package.json +1 -1
package/dist/appostle.js
CHANGED
|
@@ -16,10 +16,10 @@ __export(rightfont_service_exports, {
|
|
|
16
16
|
isRightFontLibrary: () => isRightFontLibrary,
|
|
17
17
|
readRightFontLibrary: () => readRightFontLibrary
|
|
18
18
|
});
|
|
19
|
-
import { existsSync as
|
|
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") &&
|
|
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 (
|
|
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 (
|
|
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,7 +255,7 @@ import { createRequire as createRequire5 } from "node:module";
|
|
|
255
255
|
import { Command as Command2 } from "commander";
|
|
256
256
|
|
|
257
257
|
// ../cli/src/utils/client.ts
|
|
258
|
-
import { existsSync as
|
|
258
|
+
import { existsSync as existsSync12, readFileSync as readFileSync7 } from "node:fs";
|
|
259
259
|
|
|
260
260
|
// ../server/src/server/bootstrap.ts
|
|
261
261
|
import express from "express";
|
|
@@ -700,18 +700,18 @@ function resolveNodePtyPackageRoot() {
|
|
|
700
700
|
return null;
|
|
701
701
|
}
|
|
702
702
|
}
|
|
703
|
-
function ensureExecutableBit(
|
|
704
|
-
if (!existsSync2(
|
|
703
|
+
function ensureExecutableBit(path29) {
|
|
704
|
+
if (!existsSync2(path29)) {
|
|
705
705
|
return;
|
|
706
706
|
}
|
|
707
|
-
const stat5 = statSync(
|
|
707
|
+
const stat5 = statSync(path29);
|
|
708
708
|
if (!stat5.isFile()) {
|
|
709
709
|
return;
|
|
710
710
|
}
|
|
711
711
|
if ((stat5.mode & 73) === 73) {
|
|
712
712
|
return;
|
|
713
713
|
}
|
|
714
|
-
chmodSync(
|
|
714
|
+
chmodSync(path29, stat5.mode | 73);
|
|
715
715
|
}
|
|
716
716
|
function ensureNodePtySpawnHelperExecutableForCurrentPlatform(options = {}) {
|
|
717
717
|
const platform2 = options.platform ?? process.platform;
|
|
@@ -793,11 +793,11 @@ function parseGitRevParsePath(stdout) {
|
|
|
793
793
|
if (lines.length !== 1) {
|
|
794
794
|
return null;
|
|
795
795
|
}
|
|
796
|
-
const
|
|
797
|
-
if (!
|
|
796
|
+
const path29 = lines[0]?.trim() ?? "";
|
|
797
|
+
if (!path29 || path29.startsWith("--")) {
|
|
798
798
|
return null;
|
|
799
799
|
}
|
|
800
|
-
return
|
|
800
|
+
return path29;
|
|
801
801
|
}
|
|
802
802
|
function resolveGitRevParsePath(cwd, stdout) {
|
|
803
803
|
const parsed = parseGitRevParsePath(stdout);
|
|
@@ -1570,9 +1570,9 @@ async function deleteAppostleWorktree({
|
|
|
1570
1570
|
}
|
|
1571
1571
|
}
|
|
1572
1572
|
}
|
|
1573
|
-
async function pathExists(
|
|
1573
|
+
async function pathExists(path29) {
|
|
1574
1574
|
try {
|
|
1575
|
-
await stat(
|
|
1575
|
+
await stat(path29);
|
|
1576
1576
|
return true;
|
|
1577
1577
|
} catch (error) {
|
|
1578
1578
|
if (error.code === "ENOENT") {
|
|
@@ -1581,8 +1581,8 @@ async function pathExists(path28) {
|
|
|
1581
1581
|
throw error;
|
|
1582
1582
|
}
|
|
1583
1583
|
}
|
|
1584
|
-
async function removeDirectoryWithRetries(
|
|
1585
|
-
if (!await pathExists(
|
|
1584
|
+
async function removeDirectoryWithRetries(path29) {
|
|
1585
|
+
if (!await pathExists(path29)) {
|
|
1586
1586
|
return;
|
|
1587
1587
|
}
|
|
1588
1588
|
const delaysMs = [0, 100, 300, 700, 1500];
|
|
@@ -1592,17 +1592,17 @@ async function removeDirectoryWithRetries(path28) {
|
|
|
1592
1592
|
await new Promise((resolve12) => setTimeout(resolve12, delay));
|
|
1593
1593
|
}
|
|
1594
1594
|
try {
|
|
1595
|
-
await rm(
|
|
1596
|
-
if (!await pathExists(
|
|
1595
|
+
await rm(path29, { recursive: true, force: true });
|
|
1596
|
+
if (!await pathExists(path29)) {
|
|
1597
1597
|
return;
|
|
1598
1598
|
}
|
|
1599
|
-
lastError = new Error(`Directory still present after rm: ${
|
|
1599
|
+
lastError = new Error(`Directory still present after rm: ${path29}`);
|
|
1600
1600
|
} catch (error) {
|
|
1601
1601
|
lastError = error;
|
|
1602
1602
|
}
|
|
1603
1603
|
}
|
|
1604
|
-
if (await pathExists(
|
|
1605
|
-
throw lastError instanceof Error ? lastError : new Error(`Failed to remove worktree directory: ${
|
|
1604
|
+
if (await pathExists(path29)) {
|
|
1605
|
+
throw lastError instanceof Error ? lastError : new Error(`Failed to remove worktree directory: ${path29}`);
|
|
1606
1606
|
}
|
|
1607
1607
|
}
|
|
1608
1608
|
var createWorktree = async ({
|
|
@@ -1832,7 +1832,13 @@ function extractTimestamps(record) {
|
|
|
1832
1832
|
// Fork lineage — preserved across resume so the in-memory ManagedAgent
|
|
1833
1833
|
// can flow `parentAgentId` into snapshots that drive the tab Split icon.
|
|
1834
1834
|
...record.parentAgentId ? { parentAgentId: record.parentAgentId } : {},
|
|
1835
|
-
...record.forkedFromMessageUuid ? { forkedFromMessageUuid: record.forkedFromMessageUuid } : {}
|
|
1835
|
+
...record.forkedFromMessageUuid ? { forkedFromMessageUuid: record.forkedFromMessageUuid } : {},
|
|
1836
|
+
// Multi-tenant ownership — closes the daemon-restart gap. Old records
|
|
1837
|
+
// lack these fields → ownerUserId stays undefined (→ null in
|
|
1838
|
+
// registerSession), agent rehydrates as unscoped.
|
|
1839
|
+
ownerUserId: record.ownerUserId ?? null,
|
|
1840
|
+
sharedWithUserIds: record.sharedWithUserIds ?? [],
|
|
1841
|
+
ownerUsername: record.ownerUsername ?? null
|
|
1836
1842
|
};
|
|
1837
1843
|
}
|
|
1838
1844
|
function hasRegisteredProvider(registeredProviders, value) {
|
|
@@ -1916,6 +1922,11 @@ function toAgentPayload(agent, options) {
|
|
|
1916
1922
|
title: options?.title ?? null,
|
|
1917
1923
|
labels: agent.labels,
|
|
1918
1924
|
internal: agent.internal,
|
|
1925
|
+
// Surface ownership so the client can render an owner badge / detect
|
|
1926
|
+
// "shared with me" agents. `sharedWithUserIds` deliberately stays off
|
|
1927
|
+
// the snapshot — only owners read the full ACL, via the dedicated
|
|
1928
|
+
// `list_agent_shared_users_request` RPC.
|
|
1929
|
+
ownerUserId: agent.ownerUserId,
|
|
1919
1930
|
// Fork lineage — the client's tab descriptor uses `parentAgentId` to
|
|
1920
1931
|
// mark the agent as a fork (Split glyph). Carry it from the live
|
|
1921
1932
|
// ManagedAgent so the marker doesn't disappear once the agent is
|
|
@@ -3982,7 +3993,19 @@ var AgentSnapshotPayloadSchema = z11.object({
|
|
|
3982
3993
|
* lists at display time. The agent itself is a real, full-featured session
|
|
3983
3994
|
* in every other respect; `internal` is a UI visibility hint, nothing more.
|
|
3984
3995
|
*/
|
|
3985
|
-
internal: z11.boolean().optional()
|
|
3996
|
+
internal: z11.boolean().optional(),
|
|
3997
|
+
/**
|
|
3998
|
+
* Multi-tenant ownership (Phase 2c/4). Surfaces the auth-server user-id
|
|
3999
|
+
* of the agent's creator so the app can render an owner badge and
|
|
4000
|
+
* detect "shared with me" state (owner !== current user). Optional/
|
|
4001
|
+
* nullable for legacy agents created before per-agent ownership
|
|
4002
|
+
* existed — those render without a badge.
|
|
4003
|
+
*
|
|
4004
|
+
* NOTE: `sharedWithUserIds` is intentionally NOT exposed here. Only the
|
|
4005
|
+
* owner can enumerate the full ACL, via `list_agent_shared_users_request`.
|
|
4006
|
+
* The snapshot stays cheap and recipient-safe.
|
|
4007
|
+
*/
|
|
4008
|
+
ownerUserId: z11.string().nullable().optional()
|
|
3986
4009
|
});
|
|
3987
4010
|
var VoiceAudioChunkMessageSchema = z11.object({
|
|
3988
4011
|
type: z11.literal("voice_audio_chunk"),
|
|
@@ -5105,6 +5128,50 @@ var LinkAccountResponseMessageSchema = z11.object({
|
|
|
5105
5128
|
})
|
|
5106
5129
|
])
|
|
5107
5130
|
});
|
|
5131
|
+
var ClaudeProfileLoginRequestMessageSchema = z11.object({
|
|
5132
|
+
type: z11.literal("claude_profile_login_request"),
|
|
5133
|
+
requestId: z11.string(),
|
|
5134
|
+
/** Username for the profile dir (~/.claude-{username}/). */
|
|
5135
|
+
username: z11.string().min(1)
|
|
5136
|
+
});
|
|
5137
|
+
var ClaudeProfileLoginUrlMessageSchema = z11.object({
|
|
5138
|
+
type: z11.literal("claude_profile_login_url"),
|
|
5139
|
+
requestId: z11.string(),
|
|
5140
|
+
url: z11.string().min(1)
|
|
5141
|
+
});
|
|
5142
|
+
var ClaudeProfileLoginCallbackMessageSchema = z11.object({
|
|
5143
|
+
type: z11.literal("claude_profile_login_callback"),
|
|
5144
|
+
requestId: z11.string(),
|
|
5145
|
+
callbackToken: z11.string().min(1)
|
|
5146
|
+
});
|
|
5147
|
+
var ClaudeProfileLoginResultMessageSchema = z11.object({
|
|
5148
|
+
type: z11.literal("claude_profile_login_result"),
|
|
5149
|
+
requestId: z11.string(),
|
|
5150
|
+
ok: z11.boolean(),
|
|
5151
|
+
error: z11.string().optional()
|
|
5152
|
+
});
|
|
5153
|
+
var ClaudeProfileRemoveRequestMessageSchema = z11.object({
|
|
5154
|
+
type: z11.literal("claude_profile_remove_request"),
|
|
5155
|
+
requestId: z11.string(),
|
|
5156
|
+
username: z11.string().min(1)
|
|
5157
|
+
});
|
|
5158
|
+
var ClaudeProfileRemoveResponseMessageSchema = z11.object({
|
|
5159
|
+
type: z11.literal("claude_profile_remove_response"),
|
|
5160
|
+
requestId: z11.string(),
|
|
5161
|
+
ok: z11.boolean(),
|
|
5162
|
+
error: z11.string().optional()
|
|
5163
|
+
});
|
|
5164
|
+
var ClaudeProfileStatusRequestMessageSchema = z11.object({
|
|
5165
|
+
type: z11.literal("claude_profile_status_request"),
|
|
5166
|
+
requestId: z11.string(),
|
|
5167
|
+
username: z11.string().min(1)
|
|
5168
|
+
});
|
|
5169
|
+
var ClaudeProfileStatusResponseMessageSchema = z11.object({
|
|
5170
|
+
type: z11.literal("claude_profile_status_response"),
|
|
5171
|
+
requestId: z11.string(),
|
|
5172
|
+
hasProfile: z11.boolean(),
|
|
5173
|
+
isAuthenticated: z11.boolean()
|
|
5174
|
+
});
|
|
5108
5175
|
var ListSessionUploadsRequestSchema = z11.object({
|
|
5109
5176
|
type: z11.literal("list_session_uploads_request"),
|
|
5110
5177
|
requestId: z11.string(),
|
|
@@ -5147,6 +5214,74 @@ var DeleteSessionUploadResponseSchema = z11.object({
|
|
|
5147
5214
|
})
|
|
5148
5215
|
])
|
|
5149
5216
|
});
|
|
5217
|
+
var ShareAgentWithUserRequestSchema = z11.object({
|
|
5218
|
+
type: z11.literal("share_agent_with_user_request"),
|
|
5219
|
+
requestId: z11.string(),
|
|
5220
|
+
/** Accepts full ID, unique prefix, or exact full title (server resolves). */
|
|
5221
|
+
agentId: z11.string(),
|
|
5222
|
+
/** Auth-server user-id of the recipient. */
|
|
5223
|
+
userId: z11.string()
|
|
5224
|
+
});
|
|
5225
|
+
var ShareAgentWithUserResponseSchema = z11.object({
|
|
5226
|
+
type: z11.literal("share_agent_with_user_response"),
|
|
5227
|
+
payload: z11.discriminatedUnion("ok", [
|
|
5228
|
+
z11.object({
|
|
5229
|
+
requestId: z11.string(),
|
|
5230
|
+
ok: z11.literal(true),
|
|
5231
|
+
/** Updated ACL after the share applied (owner is not included). */
|
|
5232
|
+
sharedWithUserIds: z11.array(z11.string())
|
|
5233
|
+
}),
|
|
5234
|
+
z11.object({
|
|
5235
|
+
requestId: z11.string(),
|
|
5236
|
+
ok: z11.literal(false),
|
|
5237
|
+
error: z11.string()
|
|
5238
|
+
})
|
|
5239
|
+
])
|
|
5240
|
+
});
|
|
5241
|
+
var UnshareAgentWithUserRequestSchema = z11.object({
|
|
5242
|
+
type: z11.literal("unshare_agent_with_user_request"),
|
|
5243
|
+
requestId: z11.string(),
|
|
5244
|
+
agentId: z11.string(),
|
|
5245
|
+
userId: z11.string()
|
|
5246
|
+
});
|
|
5247
|
+
var UnshareAgentWithUserResponseSchema = z11.object({
|
|
5248
|
+
type: z11.literal("unshare_agent_with_user_response"),
|
|
5249
|
+
payload: z11.discriminatedUnion("ok", [
|
|
5250
|
+
z11.object({
|
|
5251
|
+
requestId: z11.string(),
|
|
5252
|
+
ok: z11.literal(true),
|
|
5253
|
+
sharedWithUserIds: z11.array(z11.string())
|
|
5254
|
+
}),
|
|
5255
|
+
z11.object({
|
|
5256
|
+
requestId: z11.string(),
|
|
5257
|
+
ok: z11.literal(false),
|
|
5258
|
+
error: z11.string()
|
|
5259
|
+
})
|
|
5260
|
+
])
|
|
5261
|
+
});
|
|
5262
|
+
var ListAgentSharedUsersRequestSchema = z11.object({
|
|
5263
|
+
type: z11.literal("list_agent_shared_users_request"),
|
|
5264
|
+
requestId: z11.string(),
|
|
5265
|
+
agentId: z11.string()
|
|
5266
|
+
});
|
|
5267
|
+
var ListAgentSharedUsersResponseSchema = z11.object({
|
|
5268
|
+
type: z11.literal("list_agent_shared_users_response"),
|
|
5269
|
+
payload: z11.discriminatedUnion("ok", [
|
|
5270
|
+
z11.object({
|
|
5271
|
+
requestId: z11.string(),
|
|
5272
|
+
ok: z11.literal(true),
|
|
5273
|
+
/** Auth-server user-id of the owner (always present when ok). */
|
|
5274
|
+
ownerUserId: z11.string().nullable(),
|
|
5275
|
+
/** Auth-server user-ids that the owner has granted access to. */
|
|
5276
|
+
sharedWithUserIds: z11.array(z11.string())
|
|
5277
|
+
}),
|
|
5278
|
+
z11.object({
|
|
5279
|
+
requestId: z11.string(),
|
|
5280
|
+
ok: z11.literal(false),
|
|
5281
|
+
error: z11.string()
|
|
5282
|
+
})
|
|
5283
|
+
])
|
|
5284
|
+
});
|
|
5150
5285
|
var SessionImageSchema = z11.object({
|
|
5151
5286
|
id: z11.string(),
|
|
5152
5287
|
fileName: z11.string(),
|
|
@@ -5235,6 +5370,10 @@ var SessionInboundMessageSchema = z11.discriminatedUnion("type", [
|
|
|
5235
5370
|
AbortRequestMessageSchema,
|
|
5236
5371
|
AudioPlayedMessageSchema,
|
|
5237
5372
|
LinkAccountRequestMessageSchema,
|
|
5373
|
+
ClaudeProfileLoginRequestMessageSchema,
|
|
5374
|
+
ClaudeProfileLoginCallbackMessageSchema,
|
|
5375
|
+
ClaudeProfileStatusRequestMessageSchema,
|
|
5376
|
+
ClaudeProfileRemoveRequestMessageSchema,
|
|
5238
5377
|
FetchAgentsRequestMessageSchema,
|
|
5239
5378
|
FetchWorkspacesRequestMessageSchema,
|
|
5240
5379
|
FetchAgentRequestMessageSchema,
|
|
@@ -5385,6 +5524,9 @@ var SessionInboundMessageSchema = z11.discriminatedUnion("type", [
|
|
|
5385
5524
|
DeleteSessionUploadRequestSchema,
|
|
5386
5525
|
ListSessionImagesRequestSchema,
|
|
5387
5526
|
DeleteSessionImageRequestSchema,
|
|
5527
|
+
ShareAgentWithUserRequestSchema,
|
|
5528
|
+
UnshareAgentWithUserRequestSchema,
|
|
5529
|
+
ListAgentSharedUsersRequestSchema,
|
|
5388
5530
|
FetchAttachmentBytesRequestSchema
|
|
5389
5531
|
]);
|
|
5390
5532
|
var ActivityLogPayloadSchema = z11.object({
|
|
@@ -6960,10 +7102,17 @@ var SessionOutboundMessageSchema = z11.discriminatedUnion("type", [
|
|
|
6960
7102
|
GoogleFontsDownloadResponseSchema,
|
|
6961
7103
|
GetVapidPublicKeyResponseSchema,
|
|
6962
7104
|
LinkAccountResponseMessageSchema,
|
|
7105
|
+
ClaudeProfileLoginUrlMessageSchema,
|
|
7106
|
+
ClaudeProfileLoginResultMessageSchema,
|
|
7107
|
+
ClaudeProfileStatusResponseMessageSchema,
|
|
7108
|
+
ClaudeProfileRemoveResponseMessageSchema,
|
|
6963
7109
|
ListSessionUploadsResponseSchema,
|
|
6964
7110
|
DeleteSessionUploadResponseSchema,
|
|
6965
7111
|
ListSessionImagesResponseSchema,
|
|
6966
7112
|
DeleteSessionImageResponseSchema,
|
|
7113
|
+
ShareAgentWithUserResponseSchema,
|
|
7114
|
+
UnshareAgentWithUserResponseSchema,
|
|
7115
|
+
ListAgentSharedUsersResponseSchema,
|
|
6967
7116
|
FetchAttachmentBytesResponseSchema
|
|
6968
7117
|
]);
|
|
6969
7118
|
var WSPingMessageSchema = z11.object({
|
|
@@ -6981,7 +7130,11 @@ var WSHelloMessageSchema = z11.object({
|
|
|
6981
7130
|
capabilities: z11.object({
|
|
6982
7131
|
voice: z11.boolean().optional(),
|
|
6983
7132
|
pushNotifications: z11.boolean().optional()
|
|
6984
|
-
}).passthrough().optional()
|
|
7133
|
+
}).passthrough().optional(),
|
|
7134
|
+
/** Auth-server userId of the connecting user. Used for per-user Claude profile selection. */
|
|
7135
|
+
userId: z11.string().optional(),
|
|
7136
|
+
/** Display name of the connecting user (for profile dir naming). */
|
|
7137
|
+
username: z11.string().optional()
|
|
6985
7138
|
});
|
|
6986
7139
|
var WSRecordingStateMessageSchema = z11.object({
|
|
6987
7140
|
type: z11.literal("recording_state"),
|
|
@@ -7153,7 +7306,7 @@ import { exec } from "node:child_process";
|
|
|
7153
7306
|
import { promisify as promisify3 } from "util";
|
|
7154
7307
|
import { join as join14, resolve as resolve9, sep as sep2 } from "path";
|
|
7155
7308
|
import { homedir as homedir5, hostname as osHostname } from "node:os";
|
|
7156
|
-
import { z as
|
|
7309
|
+
import { z as z38 } from "zod";
|
|
7157
7310
|
|
|
7158
7311
|
// ../server/src/server/persisted-config.ts
|
|
7159
7312
|
import { existsSync as existsSync4, mkdirSync as mkdirSync4, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "node:fs";
|
|
@@ -7667,7 +7820,9 @@ function ensurePrng() {
|
|
|
7667
7820
|
const cryptoObj = globalThis.crypto;
|
|
7668
7821
|
if (cryptoObj?.getRandomValues) {
|
|
7669
7822
|
nacl.setPRNG((x, n) => {
|
|
7670
|
-
|
|
7823
|
+
const buf = new Uint8Array(n);
|
|
7824
|
+
cryptoObj.getRandomValues(buf);
|
|
7825
|
+
x.set(buf, 0);
|
|
7671
7826
|
});
|
|
7672
7827
|
prngReady = true;
|
|
7673
7828
|
return;
|
|
@@ -7778,8 +7933,8 @@ function base64ToArrayBuffer(base64) {
|
|
|
7778
7933
|
// ../relay/dist/encrypted-channel.js
|
|
7779
7934
|
var HANDSHAKE_RETRY_MS = 1e3;
|
|
7780
7935
|
var MAX_PENDING_SENDS = 200;
|
|
7781
|
-
async function createClientChannel(transport, daemonPublicKeyB64, events = {}) {
|
|
7782
|
-
const keyPair = generateKeyPair();
|
|
7936
|
+
async function createClientChannel(transport, daemonPublicKeyB64, events = {}, staticKeyPair) {
|
|
7937
|
+
const keyPair = staticKeyPair ?? generateKeyPair();
|
|
7783
7938
|
const daemonPublicKey = importPublicKey(daemonPublicKeyB64);
|
|
7784
7939
|
const sharedKey = deriveSharedKey(keyPair.secretKey, daemonPublicKey);
|
|
7785
7940
|
const channel = new EncryptedChannel(transport, sharedKey, events);
|
|
@@ -7951,6 +8106,16 @@ var EncryptedChannel = class {
|
|
|
7951
8106
|
isOpen() {
|
|
7952
8107
|
return this.state === "open";
|
|
7953
8108
|
}
|
|
8109
|
+
/**
|
|
8110
|
+
* Peer's X25519 public key (base64) captured during the daemon-side
|
|
8111
|
+
* handshake. Returns `null` on the client side or when the channel was
|
|
8112
|
+
* built without this metadata (legacy code paths). Used by the daemon's
|
|
8113
|
+
* WS-server to resolve the connecting device → owning user.
|
|
8114
|
+
*/
|
|
8115
|
+
getPeerPublicKeyB64() {
|
|
8116
|
+
const v = this.options.peerPublicKeyB64;
|
|
8117
|
+
return v && v.length > 0 ? v : null;
|
|
8118
|
+
}
|
|
7954
8119
|
onTransitionToOpen(cb) {
|
|
7955
8120
|
this.onOpenCallbacks.push(cb);
|
|
7956
8121
|
}
|
|
@@ -9410,14 +9575,14 @@ var DictationStreamManager = class {
|
|
|
9410
9575
|
PCM_CHANNELS,
|
|
9411
9576
|
PCM_BITS_PER_SAMPLE
|
|
9412
9577
|
);
|
|
9413
|
-
const
|
|
9578
|
+
const path29 = await maybePersistDictationDebugAudio(
|
|
9414
9579
|
wavBuffer,
|
|
9415
9580
|
{ sessionId: state.sessionId, dictationId: state.dictationId, format: "audio/wav" },
|
|
9416
9581
|
this.logger,
|
|
9417
9582
|
state.debugChunkWriter?.folder
|
|
9418
9583
|
);
|
|
9419
|
-
state.debugRecordingPath =
|
|
9420
|
-
return
|
|
9584
|
+
state.debugRecordingPath = path29;
|
|
9585
|
+
return path29;
|
|
9421
9586
|
}
|
|
9422
9587
|
failDictationStream(dictationId, error, retryable) {
|
|
9423
9588
|
this.emit({
|
|
@@ -9893,7 +10058,14 @@ async function ensureAgentLoaded(agentId, deps) {
|
|
|
9893
10058
|
if (!config) {
|
|
9894
10059
|
throw new Error(`Agent ${agentId} references unavailable provider '${record.provider}'`);
|
|
9895
10060
|
}
|
|
9896
|
-
snapshot = await deps.agentManager.createAgent(config, agentId, {
|
|
10061
|
+
snapshot = await deps.agentManager.createAgent(config, agentId, {
|
|
10062
|
+
labels: record.labels,
|
|
10063
|
+
// Preserve multi-tenant ownership across the no-handle rehydrate
|
|
10064
|
+
// path (records that never landed a persistence handle, e.g. very
|
|
10065
|
+
// early agents). Without this, agents would silently drop their
|
|
10066
|
+
// owner whenever they took this branch through `ensureAgentLoaded`.
|
|
10067
|
+
ownerUserId: record.ownerUserId ?? null
|
|
10068
|
+
});
|
|
9897
10069
|
deps.logger.info({ agentId, provider: record.provider }, "Agent created from stored config");
|
|
9898
10070
|
}
|
|
9899
10071
|
await deps.agentManager.hydrateTimelineFromProvider(agentId);
|
|
@@ -11208,14 +11380,14 @@ function parseDiff(diffText) {
|
|
|
11208
11380
|
const firstLine = lines[0];
|
|
11209
11381
|
const isNew = section.includes("new file mode") || section.includes("--- /dev/null");
|
|
11210
11382
|
const isDeleted = section.includes("deleted file mode") || section.includes("+++ /dev/null");
|
|
11211
|
-
let
|
|
11383
|
+
let path29 = "unknown";
|
|
11212
11384
|
const pathMatch = firstLine.match(/a\/(.*?) b\//);
|
|
11213
11385
|
if (pathMatch) {
|
|
11214
|
-
|
|
11386
|
+
path29 = pathMatch[1];
|
|
11215
11387
|
} else {
|
|
11216
11388
|
const newFileMatch = firstLine.match(/b\/(.+)$/);
|
|
11217
11389
|
if (newFileMatch) {
|
|
11218
|
-
|
|
11390
|
+
path29 = newFileMatch[1];
|
|
11219
11391
|
}
|
|
11220
11392
|
}
|
|
11221
11393
|
const hunks = [];
|
|
@@ -11259,7 +11431,7 @@ function parseDiff(diffText) {
|
|
|
11259
11431
|
if (currentHunk) {
|
|
11260
11432
|
hunks.push(currentHunk);
|
|
11261
11433
|
}
|
|
11262
|
-
files.push({ path:
|
|
11434
|
+
files.push({ path: path29, isNew, isDeleted, additions, deletions, hunks });
|
|
11263
11435
|
}
|
|
11264
11436
|
return files;
|
|
11265
11437
|
}
|
|
@@ -11315,9 +11487,9 @@ function buildTokenLookup(lineMap, highlighted) {
|
|
|
11315
11487
|
}
|
|
11316
11488
|
return lookup2;
|
|
11317
11489
|
}
|
|
11318
|
-
function buildFullFileTokenLookup(fileContent,
|
|
11490
|
+
function buildFullFileTokenLookup(fileContent, path29) {
|
|
11319
11491
|
const lookup2 = /* @__PURE__ */ new Map();
|
|
11320
|
-
const highlighted = highlightCode(fileContent,
|
|
11492
|
+
const highlighted = highlightCode(fileContent, path29);
|
|
11321
11493
|
for (let i = 0; i < highlighted.length; i++) {
|
|
11322
11494
|
lookup2.set(i + 1, highlighted[i]);
|
|
11323
11495
|
}
|
|
@@ -13018,11 +13190,11 @@ async function listCheckoutFileChanges(cwd, ref, ignoreWhitespace = false) {
|
|
|
13018
13190
|
}
|
|
13019
13191
|
continue;
|
|
13020
13192
|
}
|
|
13021
|
-
const
|
|
13022
|
-
if (!
|
|
13193
|
+
const path29 = tabParts[1];
|
|
13194
|
+
if (!path29) continue;
|
|
13023
13195
|
const code = rawStatus[0];
|
|
13024
13196
|
changes.push({
|
|
13025
|
-
path:
|
|
13197
|
+
path: path29,
|
|
13026
13198
|
status: rawStatus,
|
|
13027
13199
|
isNew: code === "A",
|
|
13028
13200
|
isDeleted: code === "D"
|
|
@@ -13057,9 +13229,9 @@ async function listCheckoutFileChanges(cwd, ref, ignoreWhitespace = false) {
|
|
|
13057
13229
|
}
|
|
13058
13230
|
return Array.from(byPath.values());
|
|
13059
13231
|
}
|
|
13060
|
-
async function readGitFileContentAtRef(cwd, ref,
|
|
13232
|
+
async function readGitFileContentAtRef(cwd, ref, path29) {
|
|
13061
13233
|
try {
|
|
13062
|
-
const { stdout } = await runGitCommand(["show", `${ref}:${
|
|
13234
|
+
const { stdout } = await runGitCommand(["show", `${ref}:${path29}`], {
|
|
13063
13235
|
cwd,
|
|
13064
13236
|
env: READ_ONLY_GIT_ENV2
|
|
13065
13237
|
});
|
|
@@ -13120,21 +13292,21 @@ async function getTrackedNumstatByPath(cwd, ref, ignoreWhitespace = false) {
|
|
|
13120
13292
|
const additionsField = parts[0] ?? "";
|
|
13121
13293
|
const deletionsField = parts[1] ?? "";
|
|
13122
13294
|
const rawPath = parts.slice(2).join(" ");
|
|
13123
|
-
const
|
|
13124
|
-
if (!
|
|
13295
|
+
const path29 = normalizeNumstatPath(rawPath);
|
|
13296
|
+
if (!path29) {
|
|
13125
13297
|
continue;
|
|
13126
13298
|
}
|
|
13127
13299
|
if (additionsField === "-" || deletionsField === "-") {
|
|
13128
|
-
stats.set(
|
|
13300
|
+
stats.set(path29, { additions: 0, deletions: 0, isBinary: true });
|
|
13129
13301
|
continue;
|
|
13130
13302
|
}
|
|
13131
13303
|
const additions = Number.parseInt(additionsField, 10);
|
|
13132
13304
|
const deletions = Number.parseInt(deletionsField, 10);
|
|
13133
13305
|
if (Number.isNaN(additions) || Number.isNaN(deletions)) {
|
|
13134
|
-
stats.set(
|
|
13306
|
+
stats.set(path29, null);
|
|
13135
13307
|
continue;
|
|
13136
13308
|
}
|
|
13137
|
-
stats.set(
|
|
13309
|
+
stats.set(path29, { additions, deletions, isBinary: false });
|
|
13138
13310
|
}
|
|
13139
13311
|
return stats;
|
|
13140
13312
|
}
|
|
@@ -13719,10 +13891,10 @@ async function listUncommittedFiles(cwd) {
|
|
|
13719
13891
|
if (dest) results.push({ path: dest, changeType: code });
|
|
13720
13892
|
continue;
|
|
13721
13893
|
}
|
|
13722
|
-
const
|
|
13723
|
-
if (!
|
|
13894
|
+
const path29 = parts[1];
|
|
13895
|
+
if (!path29) continue;
|
|
13724
13896
|
if (code === "A" || code === "M" || code === "D") {
|
|
13725
|
-
results.push({ path:
|
|
13897
|
+
results.push({ path: path29, changeType: code });
|
|
13726
13898
|
}
|
|
13727
13899
|
}
|
|
13728
13900
|
} catch {
|
|
@@ -17465,12 +17637,12 @@ function extractPlanNameFromFrontmatter(content) {
|
|
|
17465
17637
|
return null;
|
|
17466
17638
|
}
|
|
17467
17639
|
function resolvePlanFilename(options) {
|
|
17468
|
-
const { originalPath, newSlug, existsSync:
|
|
17640
|
+
const { originalPath, newSlug, existsSync: existsSync16 } = options;
|
|
17469
17641
|
const dir = path8.dirname(originalPath);
|
|
17470
17642
|
const base = `${newSlug}.md`;
|
|
17471
17643
|
let candidate = path8.join(dir, base);
|
|
17472
17644
|
let counter = 2;
|
|
17473
|
-
while (candidate !== originalPath &&
|
|
17645
|
+
while (candidate !== originalPath && existsSync16(candidate)) {
|
|
17474
17646
|
candidate = path8.join(dir, `${newSlug}-${counter}.md`);
|
|
17475
17647
|
counter += 1;
|
|
17476
17648
|
}
|
|
@@ -21707,14 +21879,14 @@ function codexApplyPatchToUnifiedDiff(text) {
|
|
|
21707
21879
|
for (const line of lines) {
|
|
21708
21880
|
const directive = parseCodexApplyPatchDirective(line);
|
|
21709
21881
|
if (directive) {
|
|
21710
|
-
const
|
|
21711
|
-
if (
|
|
21882
|
+
const path29 = normalizeDiffHeaderPath(directive.path);
|
|
21883
|
+
if (path29.length > 0) {
|
|
21712
21884
|
if (output.length > 0 && output[output.length - 1] !== "") {
|
|
21713
21885
|
output.push("");
|
|
21714
21886
|
}
|
|
21715
|
-
const left = directive.kind === "add" ? "/dev/null" : `a/${
|
|
21716
|
-
const right = directive.kind === "delete" ? "/dev/null" : `b/${
|
|
21717
|
-
output.push(`diff --git a/${
|
|
21887
|
+
const left = directive.kind === "add" ? "/dev/null" : `a/${path29}`;
|
|
21888
|
+
const right = directive.kind === "delete" ? "/dev/null" : `b/${path29}`;
|
|
21889
|
+
output.push(`diff --git a/${path29} b/${path29}`);
|
|
21718
21890
|
output.push(`--- ${left}`);
|
|
21719
21891
|
output.push(`+++ ${right}`);
|
|
21720
21892
|
sawDiffContent = true;
|
|
@@ -21784,9 +21956,9 @@ function asEditTextFields(text) {
|
|
|
21784
21956
|
function normalizeRolloutEditInput(input) {
|
|
21785
21957
|
if (typeof input === "string") {
|
|
21786
21958
|
const textFields2 = asEditTextFields(input);
|
|
21787
|
-
const
|
|
21959
|
+
const path29 = extractPatchPrimaryFilePath(input);
|
|
21788
21960
|
return {
|
|
21789
|
-
...
|
|
21961
|
+
...path29 ? { path: path29 } : {},
|
|
21790
21962
|
...textFields2.unifiedDiff ? { patch: textFields2.unifiedDiff } : {},
|
|
21791
21963
|
...textFields2.newString ? { content: textFields2.newString } : {}
|
|
21792
21964
|
};
|
|
@@ -21934,12 +22106,12 @@ function parseFileChangeDiff(entry) {
|
|
|
21934
22106
|
]);
|
|
21935
22107
|
}
|
|
21936
22108
|
function toFileChangeEntry(entry, options, fallbackPath) {
|
|
21937
|
-
const
|
|
21938
|
-
if (!
|
|
22109
|
+
const path29 = parseFileChangePath(entry, options, fallbackPath);
|
|
22110
|
+
if (!path29) {
|
|
21939
22111
|
return null;
|
|
21940
22112
|
}
|
|
21941
22113
|
return {
|
|
21942
|
-
path:
|
|
22114
|
+
path: path29,
|
|
21943
22115
|
kind: parseFileChangeKind(entry),
|
|
21944
22116
|
diff: parseFileChangeDiff(entry)
|
|
21945
22117
|
};
|
|
@@ -21961,12 +22133,12 @@ function parseFileChangeEntries(changes, options) {
|
|
|
21961
22133
|
if (singleEntry) {
|
|
21962
22134
|
return [singleEntry];
|
|
21963
22135
|
}
|
|
21964
|
-
return Object.entries(changes).map(([
|
|
22136
|
+
return Object.entries(changes).map(([path29, value]) => {
|
|
21965
22137
|
if (isRecord2(value)) {
|
|
21966
|
-
return toFileChangeEntry(value, options,
|
|
22138
|
+
return toFileChangeEntry(value, options, path29);
|
|
21967
22139
|
}
|
|
21968
22140
|
if (typeof value === "string") {
|
|
21969
|
-
const normalizedPath = normalizeCodexFilePath(
|
|
22141
|
+
const normalizedPath = normalizeCodexFilePath(path29.trim(), options?.cwd);
|
|
21970
22142
|
if (!normalizedPath) {
|
|
21971
22143
|
return null;
|
|
21972
22144
|
}
|
|
@@ -22711,16 +22883,16 @@ function isObjectSchemaNode(schema) {
|
|
|
22711
22883
|
const type = schema.type;
|
|
22712
22884
|
return isSchemaRecord(schema.properties) || type === "object" || Array.isArray(type) && type.includes("object");
|
|
22713
22885
|
}
|
|
22714
|
-
function normalizeCodexOutputSchemaNode(schema,
|
|
22886
|
+
function normalizeCodexOutputSchemaNode(schema, path29) {
|
|
22715
22887
|
if (Array.isArray(schema)) {
|
|
22716
|
-
return schema.map((entry, index) => normalizeCodexOutputSchemaNode(entry, `${
|
|
22888
|
+
return schema.map((entry, index) => normalizeCodexOutputSchemaNode(entry, `${path29}[${index}]`));
|
|
22717
22889
|
}
|
|
22718
22890
|
if (!isSchemaRecord(schema)) {
|
|
22719
22891
|
return schema;
|
|
22720
22892
|
}
|
|
22721
22893
|
const normalized = {};
|
|
22722
22894
|
for (const [key, value] of Object.entries(schema)) {
|
|
22723
|
-
normalized[key] = normalizeCodexOutputSchemaNode(value, `${
|
|
22895
|
+
normalized[key] = normalizeCodexOutputSchemaNode(value, `${path29}.${key}`);
|
|
22724
22896
|
}
|
|
22725
22897
|
if (!isObjectSchemaNode(normalized)) {
|
|
22726
22898
|
return normalized;
|
|
@@ -22729,7 +22901,7 @@ function normalizeCodexOutputSchemaNode(schema, path28) {
|
|
|
22729
22901
|
normalized.additionalProperties = false;
|
|
22730
22902
|
} else if (normalized.additionalProperties !== false) {
|
|
22731
22903
|
throw new Error(
|
|
22732
|
-
`Codex structured outputs require ${
|
|
22904
|
+
`Codex structured outputs require ${path29} to set additionalProperties to false for object schemas.`
|
|
22733
22905
|
);
|
|
22734
22906
|
}
|
|
22735
22907
|
const properties = isSchemaRecord(normalized.properties) ? normalized.properties : null;
|
|
@@ -23493,8 +23665,8 @@ function parseCodexPatchChanges(changes) {
|
|
|
23493
23665
|
}
|
|
23494
23666
|
];
|
|
23495
23667
|
}
|
|
23496
|
-
return Object.entries(recordChanges).map(([
|
|
23497
|
-
const normalizedPath =
|
|
23668
|
+
return Object.entries(recordChanges).map(([path29, value]) => {
|
|
23669
|
+
const normalizedPath = path29.trim();
|
|
23498
23670
|
if (!normalizedPath) {
|
|
23499
23671
|
return null;
|
|
23500
23672
|
}
|
|
@@ -31205,6 +31377,53 @@ function buildProviderRegistry(logger, options) {
|
|
|
31205
31377
|
);
|
|
31206
31378
|
}
|
|
31207
31379
|
|
|
31380
|
+
// ../server/src/server/claude-profile.ts
|
|
31381
|
+
import { existsSync as existsSync10, mkdirSync as mkdirSync5, symlinkSync, rmSync as rmSync2 } from "node:fs";
|
|
31382
|
+
import path13 from "node:path";
|
|
31383
|
+
import os5 from "node:os";
|
|
31384
|
+
var SHARED_ITEMS = ["settings.json", "hooks", "agents", "skills", "plugins", "keybindings.json"];
|
|
31385
|
+
function getClaudeProfileDir(username) {
|
|
31386
|
+
return path13.join(os5.homedir(), `.claude-${username}`);
|
|
31387
|
+
}
|
|
31388
|
+
function ensureClaudeProfile(username, logger) {
|
|
31389
|
+
const profileDir = getClaudeProfileDir(username);
|
|
31390
|
+
const ownerDir = path13.join(os5.homedir(), ".claude");
|
|
31391
|
+
if (!existsSync10(ownerDir)) {
|
|
31392
|
+
throw new Error(`Owner claude config dir not found: ${ownerDir}`);
|
|
31393
|
+
}
|
|
31394
|
+
if (!existsSync10(profileDir)) {
|
|
31395
|
+
mkdirSync5(profileDir, { recursive: true });
|
|
31396
|
+
logger?.info({ profileDir, username }, "created claude profile directory");
|
|
31397
|
+
}
|
|
31398
|
+
for (const item of SHARED_ITEMS) {
|
|
31399
|
+
const target = path13.join(ownerDir, item);
|
|
31400
|
+
const link = path13.join(profileDir, item);
|
|
31401
|
+
if (!existsSync10(target)) continue;
|
|
31402
|
+
if (existsSync10(link)) continue;
|
|
31403
|
+
symlinkSync(target, link);
|
|
31404
|
+
logger?.info({ item, profileDir }, "symlinked shared config item");
|
|
31405
|
+
}
|
|
31406
|
+
return profileDir;
|
|
31407
|
+
}
|
|
31408
|
+
function hasClaudeAuth(username) {
|
|
31409
|
+
const profileDir = getClaudeProfileDir(username);
|
|
31410
|
+
return existsSync10(profileDir);
|
|
31411
|
+
}
|
|
31412
|
+
function removeClaudeProfile(username, logger) {
|
|
31413
|
+
const profileDir = getClaudeProfileDir(username);
|
|
31414
|
+
if (!existsSync10(profileDir)) return;
|
|
31415
|
+
rmSync2(profileDir, { recursive: true, force: true });
|
|
31416
|
+
logger?.info({ profileDir, username }, "removed claude profile directory");
|
|
31417
|
+
}
|
|
31418
|
+
|
|
31419
|
+
// ../server/src/server/agent/agent-manager.ts
|
|
31420
|
+
import { z as z33 } from "zod";
|
|
31421
|
+
import { getSessionMessages } from "@anthropic-ai/claude-agent-sdk";
|
|
31422
|
+
|
|
31423
|
+
// ../server/src/server/agent/handoff-mcp.ts
|
|
31424
|
+
import { createSdkMcpServer, tool } from "@anthropic-ai/claude-agent-sdk";
|
|
31425
|
+
import { z as z32 } from "zod";
|
|
31426
|
+
|
|
31208
31427
|
// ../server/src/server/agent/agent-metadata-generator.ts
|
|
31209
31428
|
import { basename as basename5 } from "path";
|
|
31210
31429
|
import { z as z31 } from "zod";
|
|
@@ -31255,8 +31474,8 @@ function buildZodValidator(schema, schemaName) {
|
|
|
31255
31474
|
return { ok: true, value: result.data };
|
|
31256
31475
|
}
|
|
31257
31476
|
const errors = result.error.issues.map((issue) => {
|
|
31258
|
-
const
|
|
31259
|
-
return `${
|
|
31477
|
+
const path29 = issue.path.length > 0 ? issue.path.join(".") : "(root)";
|
|
31478
|
+
return `${path29}: ${issue.message}`;
|
|
31260
31479
|
});
|
|
31261
31480
|
return { ok: false, errors };
|
|
31262
31481
|
}
|
|
@@ -31274,9 +31493,9 @@ function buildJsonSchemaValidator(schema) {
|
|
|
31274
31493
|
return { ok: true, value };
|
|
31275
31494
|
}
|
|
31276
31495
|
const errors = (validate.errors ?? []).map((error) => {
|
|
31277
|
-
const
|
|
31496
|
+
const path29 = error.instancePath && error.instancePath.length > 0 ? error.instancePath : "(root)";
|
|
31278
31497
|
const message = error.message ?? "is invalid";
|
|
31279
|
-
return `${
|
|
31498
|
+
return `${path29}: ${message}`;
|
|
31280
31499
|
});
|
|
31281
31500
|
return { ok: false, errors };
|
|
31282
31501
|
}
|
|
@@ -31682,6 +31901,14 @@ function scheduleAgentMetadataGeneration(options) {
|
|
|
31682
31901
|
});
|
|
31683
31902
|
}
|
|
31684
31903
|
|
|
31904
|
+
// ../server/src/server/agent/agent-manager.ts
|
|
31905
|
+
var AgentIdSchema = z33.string().uuid();
|
|
31906
|
+
function canUserAccessAgent(agent, requesterUserId) {
|
|
31907
|
+
if (agent.ownerUserId === null) return true;
|
|
31908
|
+
if (agent.ownerUserId === requesterUserId) return true;
|
|
31909
|
+
return agent.sharedWithUserIds.includes(requesterUserId);
|
|
31910
|
+
}
|
|
31911
|
+
|
|
31685
31912
|
// ../server/src/server/agent/timeline-append.ts
|
|
31686
31913
|
async function appendTimelineItemIfAgentKnown(options) {
|
|
31687
31914
|
try {
|
|
@@ -32065,25 +32292,25 @@ async function buildProjectPlacementForCwd(input) {
|
|
|
32065
32292
|
}
|
|
32066
32293
|
|
|
32067
32294
|
// ../server/src/server/workspace-registry.ts
|
|
32068
|
-
import { z as
|
|
32069
|
-
var PersistedProjectRecordSchema =
|
|
32070
|
-
projectId:
|
|
32071
|
-
rootPath:
|
|
32072
|
-
kind:
|
|
32073
|
-
displayName:
|
|
32074
|
-
createdAt:
|
|
32075
|
-
updatedAt:
|
|
32076
|
-
archivedAt:
|
|
32077
|
-
});
|
|
32078
|
-
var PersistedWorkspaceRecordSchema =
|
|
32079
|
-
workspaceId:
|
|
32080
|
-
projectId:
|
|
32081
|
-
cwd:
|
|
32082
|
-
kind:
|
|
32083
|
-
displayName:
|
|
32084
|
-
createdAt:
|
|
32085
|
-
updatedAt:
|
|
32086
|
-
archivedAt:
|
|
32295
|
+
import { z as z34 } from "zod";
|
|
32296
|
+
var PersistedProjectRecordSchema = z34.object({
|
|
32297
|
+
projectId: z34.string(),
|
|
32298
|
+
rootPath: z34.string(),
|
|
32299
|
+
kind: z34.enum(["git", "non_git"]),
|
|
32300
|
+
displayName: z34.string(),
|
|
32301
|
+
createdAt: z34.string(),
|
|
32302
|
+
updatedAt: z34.string(),
|
|
32303
|
+
archivedAt: z34.string().nullable()
|
|
32304
|
+
});
|
|
32305
|
+
var PersistedWorkspaceRecordSchema = z34.object({
|
|
32306
|
+
workspaceId: z34.string(),
|
|
32307
|
+
projectId: z34.string(),
|
|
32308
|
+
cwd: z34.string(),
|
|
32309
|
+
kind: z34.enum(["local_checkout", "worktree", "directory"]),
|
|
32310
|
+
displayName: z34.string(),
|
|
32311
|
+
createdAt: z34.string(),
|
|
32312
|
+
updatedAt: z34.string(),
|
|
32313
|
+
archivedAt: z34.string().nullable()
|
|
32087
32314
|
});
|
|
32088
32315
|
function createPersistedProjectRecord(input) {
|
|
32089
32316
|
return PersistedProjectRecordSchema.parse({
|
|
@@ -32162,7 +32389,7 @@ function isVoicePermissionAllowed(request) {
|
|
|
32162
32389
|
|
|
32163
32390
|
// ../server/src/server/file-explorer/service.ts
|
|
32164
32391
|
import { promises as fs8 } from "fs";
|
|
32165
|
-
import
|
|
32392
|
+
import path14 from "path";
|
|
32166
32393
|
|
|
32167
32394
|
// ../server/src/server/path-utils.ts
|
|
32168
32395
|
import { homedir as homedir2 } from "node:os";
|
|
@@ -32216,7 +32443,7 @@ async function listDirectoryEntries({
|
|
|
32216
32443
|
const dirents = await fs8.readdir(directoryPath, { withFileTypes: true });
|
|
32217
32444
|
const entriesWithNulls = await Promise.all(
|
|
32218
32445
|
dirents.map(async (dirent) => {
|
|
32219
|
-
const targetPath =
|
|
32446
|
+
const targetPath = path14.join(directoryPath, dirent.name);
|
|
32220
32447
|
const kind = dirent.isDirectory() ? "directory" : "file";
|
|
32221
32448
|
try {
|
|
32222
32449
|
return await buildEntryPayload({
|
|
@@ -32255,7 +32482,7 @@ async function readExplorerFile({
|
|
|
32255
32482
|
if (!stats.isFile()) {
|
|
32256
32483
|
throw new Error("Requested path is not a file");
|
|
32257
32484
|
}
|
|
32258
|
-
const ext =
|
|
32485
|
+
const ext = path14.extname(filePath).toLowerCase();
|
|
32259
32486
|
const basePayload = {
|
|
32260
32487
|
path: normalizeRelativePath({ root, targetPath: filePath }),
|
|
32261
32488
|
size: stats.size,
|
|
@@ -32293,7 +32520,7 @@ async function writeTextFile({
|
|
|
32293
32520
|
relativePath,
|
|
32294
32521
|
content
|
|
32295
32522
|
}) {
|
|
32296
|
-
const ext =
|
|
32523
|
+
const ext = path14.extname(relativePath).toLowerCase();
|
|
32297
32524
|
if (ext in IMAGE_MIME_TYPES) {
|
|
32298
32525
|
throw new Error(`Refusing to write '${relativePath}': binary/image file`);
|
|
32299
32526
|
}
|
|
@@ -32303,7 +32530,7 @@ async function writeTextFile({
|
|
|
32303
32530
|
await fs8.rename(tempPath, filePath);
|
|
32304
32531
|
}
|
|
32305
32532
|
async function deleteFile({ root, relativePath }) {
|
|
32306
|
-
const ext =
|
|
32533
|
+
const ext = path14.extname(relativePath).toLowerCase();
|
|
32307
32534
|
if (ext !== ".md") {
|
|
32308
32535
|
throw new Error(`Refusing to delete '${relativePath}': only .md files allowed`);
|
|
32309
32536
|
}
|
|
@@ -32337,7 +32564,7 @@ async function getDownloadableFileInfo({ root, relativePath }) {
|
|
|
32337
32564
|
if (!stats.isFile()) {
|
|
32338
32565
|
throw new Error("Requested path is not a file");
|
|
32339
32566
|
}
|
|
32340
|
-
const ext =
|
|
32567
|
+
const ext = path14.extname(filePath).toLowerCase();
|
|
32341
32568
|
let mimeType = "application/octet-stream";
|
|
32342
32569
|
if (ext in IMAGE_MIME_TYPES) {
|
|
32343
32570
|
mimeType = IMAGE_MIME_TYPES[ext] ?? mimeType;
|
|
@@ -32359,23 +32586,23 @@ async function getDownloadableFileInfo({ root, relativePath }) {
|
|
|
32359
32586
|
return {
|
|
32360
32587
|
path: normalizeRelativePath({ root, targetPath: filePath }),
|
|
32361
32588
|
absolutePath: filePath,
|
|
32362
|
-
fileName:
|
|
32589
|
+
fileName: path14.basename(filePath),
|
|
32363
32590
|
mimeType,
|
|
32364
32591
|
size: stats.size
|
|
32365
32592
|
};
|
|
32366
32593
|
}
|
|
32367
32594
|
async function resolveScopedPath({ root, relativePath = "." }) {
|
|
32368
|
-
const normalizedRoot =
|
|
32595
|
+
const normalizedRoot = path14.resolve(root);
|
|
32369
32596
|
const requestedPath = resolvePathFromBase(normalizedRoot, relativePath);
|
|
32370
|
-
const relative =
|
|
32371
|
-
if (relative !== "" && (relative.startsWith("..") ||
|
|
32597
|
+
const relative = path14.relative(normalizedRoot, requestedPath);
|
|
32598
|
+
if (relative !== "" && (relative.startsWith("..") || path14.isAbsolute(relative))) {
|
|
32372
32599
|
throw new Error("Access outside of workspace is not allowed");
|
|
32373
32600
|
}
|
|
32374
32601
|
const realRoot = await fs8.realpath(normalizedRoot);
|
|
32375
32602
|
try {
|
|
32376
32603
|
const realPath = await fs8.realpath(requestedPath);
|
|
32377
|
-
const realRelative =
|
|
32378
|
-
if (realRelative !== "" && (realRelative.startsWith("..") ||
|
|
32604
|
+
const realRelative = path14.relative(realRoot, realPath);
|
|
32605
|
+
if (realRelative !== "" && (realRelative.startsWith("..") || path14.isAbsolute(realRelative))) {
|
|
32379
32606
|
throw new Error("Access outside of workspace is not allowed");
|
|
32380
32607
|
}
|
|
32381
32608
|
return requestedPath;
|
|
@@ -32406,10 +32633,10 @@ function isMissingEntryError(error) {
|
|
|
32406
32633
|
return code === "ENOENT" || code === "ENOTDIR" || code === "ELOOP";
|
|
32407
32634
|
}
|
|
32408
32635
|
function normalizeRelativePath({ root, targetPath }) {
|
|
32409
|
-
const normalizedRoot =
|
|
32410
|
-
const normalizedTarget =
|
|
32411
|
-
const relative =
|
|
32412
|
-
return relative === "" ? "." : relative.split(
|
|
32636
|
+
const normalizedRoot = path14.resolve(root);
|
|
32637
|
+
const normalizedTarget = path14.resolve(targetPath);
|
|
32638
|
+
const relative = path14.relative(normalizedRoot, normalizedTarget);
|
|
32639
|
+
return relative === "" ? "." : relative.split(path14.sep).join("/");
|
|
32413
32640
|
}
|
|
32414
32641
|
function textMimeTypeForExtension(ext) {
|
|
32415
32642
|
return TEXT_MIME_TYPES[ext] ?? DEFAULT_TEXT_MIME_TYPE;
|
|
@@ -32762,65 +32989,65 @@ async function getProjectIcon(projectDir) {
|
|
|
32762
32989
|
}
|
|
32763
32990
|
|
|
32764
32991
|
// ../server/src/utils/path.ts
|
|
32765
|
-
import
|
|
32766
|
-
function expandTilde(
|
|
32767
|
-
if (
|
|
32768
|
-
const homeDir3 = process.env.HOME ||
|
|
32769
|
-
return
|
|
32992
|
+
import os6 from "os";
|
|
32993
|
+
function expandTilde(path29) {
|
|
32994
|
+
if (path29.startsWith("~/")) {
|
|
32995
|
+
const homeDir3 = process.env.HOME || os6.homedir();
|
|
32996
|
+
return path29.replace("~", homeDir3);
|
|
32770
32997
|
}
|
|
32771
|
-
if (
|
|
32772
|
-
return process.env.HOME ||
|
|
32998
|
+
if (path29 === "~") {
|
|
32999
|
+
return process.env.HOME || os6.homedir();
|
|
32773
33000
|
}
|
|
32774
|
-
return
|
|
33001
|
+
return path29;
|
|
32775
33002
|
}
|
|
32776
33003
|
|
|
32777
33004
|
// ../server/src/server/skills/scanner.ts
|
|
32778
33005
|
import fs9 from "node:fs/promises";
|
|
32779
|
-
import
|
|
32780
|
-
import
|
|
33006
|
+
import os7 from "node:os";
|
|
33007
|
+
import path15 from "node:path";
|
|
32781
33008
|
var NAME_REGEX = /^[a-z0-9][a-z0-9._-]*$/i;
|
|
32782
33009
|
function homeDir() {
|
|
32783
|
-
return process.env.HOME ||
|
|
33010
|
+
return process.env.HOME || os7.homedir();
|
|
32784
33011
|
}
|
|
32785
33012
|
function codexHomeDir() {
|
|
32786
|
-
return process.env.CODEX_HOME ||
|
|
33013
|
+
return process.env.CODEX_HOME || path15.join(homeDir(), ".codex");
|
|
32787
33014
|
}
|
|
32788
33015
|
function resolveScopeDir(provider, scope, workspaceRoot) {
|
|
32789
33016
|
if (scope === "codex-prompts") {
|
|
32790
33017
|
if (provider !== "codex") {
|
|
32791
33018
|
throw new Error(`Scope "codex-prompts" is only valid for provider "codex"`);
|
|
32792
33019
|
}
|
|
32793
|
-
return
|
|
33020
|
+
return path15.join(codexHomeDir(), "prompts");
|
|
32794
33021
|
}
|
|
32795
33022
|
if (scope === "project") {
|
|
32796
33023
|
if (!workspaceRoot) {
|
|
32797
33024
|
throw new Error(`workspaceRoot is required for scope "project"`);
|
|
32798
33025
|
}
|
|
32799
33026
|
const dotDir = provider === "claude" ? ".claude" : ".codex";
|
|
32800
|
-
return
|
|
33027
|
+
return path15.join(workspaceRoot, dotDir, "skills");
|
|
32801
33028
|
}
|
|
32802
33029
|
if (provider === "claude") {
|
|
32803
|
-
return
|
|
33030
|
+
return path15.join(homeDir(), ".claude", "skills");
|
|
32804
33031
|
}
|
|
32805
|
-
return
|
|
33032
|
+
return path15.join(codexHomeDir(), "skills");
|
|
32806
33033
|
}
|
|
32807
33034
|
function allowedRoots(workspaceRoot) {
|
|
32808
33035
|
const roots = [
|
|
32809
|
-
|
|
32810
|
-
|
|
32811
|
-
|
|
33036
|
+
path15.join(homeDir(), ".claude", "skills"),
|
|
33037
|
+
path15.join(codexHomeDir(), "skills"),
|
|
33038
|
+
path15.join(codexHomeDir(), "prompts")
|
|
32812
33039
|
];
|
|
32813
33040
|
if (workspaceRoot) {
|
|
32814
|
-
roots.push(
|
|
32815
|
-
roots.push(
|
|
33041
|
+
roots.push(path15.join(workspaceRoot, ".claude", "skills"));
|
|
33042
|
+
roots.push(path15.join(workspaceRoot, ".codex", "skills"));
|
|
32816
33043
|
}
|
|
32817
|
-
return roots.map((r) =>
|
|
33044
|
+
return roots.map((r) => path15.resolve(r));
|
|
32818
33045
|
}
|
|
32819
33046
|
function isInsideAllowedRoot(absPath, workspaceRoot) {
|
|
32820
|
-
const resolved =
|
|
33047
|
+
const resolved = path15.resolve(absPath);
|
|
32821
33048
|
for (const root of allowedRoots(workspaceRoot)) {
|
|
32822
|
-
const rel =
|
|
32823
|
-
if (rel === "" || !rel.startsWith("..") && !
|
|
33049
|
+
const rel = path15.relative(root, resolved);
|
|
33050
|
+
if (rel === "" || !rel.startsWith("..") && !path15.isAbsolute(rel)) {
|
|
32824
33051
|
return true;
|
|
32825
33052
|
}
|
|
32826
33053
|
}
|
|
@@ -32951,7 +33178,7 @@ async function listSkills(args) {
|
|
|
32951
33178
|
if (!entry.name.endsWith(".md")) continue;
|
|
32952
33179
|
const name = entry.name.slice(0, -".md".length);
|
|
32953
33180
|
if (!name) continue;
|
|
32954
|
-
const fullPath =
|
|
33181
|
+
const fullPath = path15.join(dir, entry.name);
|
|
32955
33182
|
const stat5 = await safeStat(fullPath);
|
|
32956
33183
|
if (!stat5) continue;
|
|
32957
33184
|
const description = await readDescriptionSafely(fullPath);
|
|
@@ -32969,8 +33196,8 @@ async function listSkills(args) {
|
|
|
32969
33196
|
} else {
|
|
32970
33197
|
for (const entry of entries) {
|
|
32971
33198
|
if (!entry.isDirectory() && !entry.isSymbolicLink()) continue;
|
|
32972
|
-
const skillDir =
|
|
32973
|
-
const skillPath =
|
|
33199
|
+
const skillDir = path15.join(dir, entry.name);
|
|
33200
|
+
const skillPath = path15.join(skillDir, "SKILL.md");
|
|
32974
33201
|
const stat5 = await safeStat(skillPath);
|
|
32975
33202
|
if (!stat5) continue;
|
|
32976
33203
|
const description = await readDescriptionSafely(skillPath);
|
|
@@ -33017,7 +33244,7 @@ async function createSkill(args) {
|
|
|
33017
33244
|
const dir = resolveScopeDir(args.provider, args.scope, args.workspaceRoot);
|
|
33018
33245
|
await fs9.mkdir(dir, { recursive: true });
|
|
33019
33246
|
if (args.scope === "codex-prompts") {
|
|
33020
|
-
const filePath2 =
|
|
33247
|
+
const filePath2 = path15.join(dir, `${args.name}.md`);
|
|
33021
33248
|
try {
|
|
33022
33249
|
await fs9.access(filePath2);
|
|
33023
33250
|
throw new Error(`A prompt named "${args.name}" already exists at ${filePath2}`);
|
|
@@ -33033,7 +33260,7 @@ async function createSkill(args) {
|
|
|
33033
33260
|
await fs9.writeFile(filePath2, initial2, "utf8");
|
|
33034
33261
|
return { path: filePath2 };
|
|
33035
33262
|
}
|
|
33036
|
-
const skillDir =
|
|
33263
|
+
const skillDir = path15.join(dir, args.name);
|
|
33037
33264
|
let dirExists = false;
|
|
33038
33265
|
try {
|
|
33039
33266
|
const stat5 = await fs9.stat(skillDir);
|
|
@@ -33045,7 +33272,7 @@ async function createSkill(args) {
|
|
|
33045
33272
|
throw new Error(`A skill named "${args.name}" already exists at ${skillDir}`);
|
|
33046
33273
|
}
|
|
33047
33274
|
await fs9.mkdir(skillDir, { recursive: true });
|
|
33048
|
-
const filePath =
|
|
33275
|
+
const filePath = path15.join(skillDir, "SKILL.md");
|
|
33049
33276
|
const initial = buildStarterSkill(args.name);
|
|
33050
33277
|
await fs9.writeFile(filePath, initial, "utf8");
|
|
33051
33278
|
return { path: filePath };
|
|
@@ -33074,7 +33301,7 @@ Body of the prompt. Use \`$1\`, \`$2\`, ... or \`$ARGUMENTS\` for parameter expa
|
|
|
33074
33301
|
`;
|
|
33075
33302
|
}
|
|
33076
33303
|
async function writeSkillFrontmatter(args, workspaceRoot) {
|
|
33077
|
-
if (!
|
|
33304
|
+
if (!path15.isAbsolute(args.path)) {
|
|
33078
33305
|
throw new Error(`writeSkillFrontmatter expects an absolute path; got "${args.path}"`);
|
|
33079
33306
|
}
|
|
33080
33307
|
if (!isInsideAllowedRoot(args.path, workspaceRoot)) {
|
|
@@ -33100,7 +33327,7 @@ ${original}`;
|
|
|
33100
33327
|
|
|
33101
33328
|
// ../server/src/utils/directory-suggestions.ts
|
|
33102
33329
|
import { readdir as readdir2, realpath, stat as stat3 } from "node:fs/promises";
|
|
33103
|
-
import
|
|
33330
|
+
import path16 from "node:path";
|
|
33104
33331
|
var DEFAULT_LIMIT = 30;
|
|
33105
33332
|
var MAX_LIMIT = 100;
|
|
33106
33333
|
var DEFAULT_MAX_DEPTH = 6;
|
|
@@ -33186,7 +33413,7 @@ function normalizeLimit(limit) {
|
|
|
33186
33413
|
return Math.max(1, Math.min(MAX_LIMIT, bounded));
|
|
33187
33414
|
}
|
|
33188
33415
|
async function searchWithinParentDirectory(input) {
|
|
33189
|
-
const parentPath =
|
|
33416
|
+
const parentPath = path16.resolve(input.homeRoot, input.parentPart || ".");
|
|
33190
33417
|
const parentRoot = await resolveDirectory(parentPath);
|
|
33191
33418
|
if (!parentRoot || !isPathInsideRoot(input.homeRoot, parentRoot)) {
|
|
33192
33419
|
return [];
|
|
@@ -33251,7 +33478,7 @@ async function searchAcrossHomeTree(input) {
|
|
|
33251
33478
|
return dedupeAndSort(ranked).slice(0, input.limit);
|
|
33252
33479
|
}
|
|
33253
33480
|
async function searchWorkspaceWithinParentDirectory(input) {
|
|
33254
|
-
const parentPath =
|
|
33481
|
+
const parentPath = path16.resolve(input.workspaceRoot, input.parentPart || ".");
|
|
33255
33482
|
const parentRoot = await resolveDirectory(parentPath);
|
|
33256
33483
|
if (!parentRoot || !isPathInsideRoot(input.workspaceRoot, parentRoot)) {
|
|
33257
33484
|
return [];
|
|
@@ -33497,15 +33724,15 @@ function findSegmentMatchIndex(segments, predicate) {
|
|
|
33497
33724
|
return -1;
|
|
33498
33725
|
}
|
|
33499
33726
|
function normalizeRelativePath2(homeRoot, absolutePath) {
|
|
33500
|
-
const relative =
|
|
33727
|
+
const relative = path16.relative(homeRoot, absolutePath);
|
|
33501
33728
|
if (!relative) {
|
|
33502
33729
|
return ".";
|
|
33503
33730
|
}
|
|
33504
|
-
return relative.split(
|
|
33731
|
+
return relative.split(path16.sep).join("/");
|
|
33505
33732
|
}
|
|
33506
33733
|
function isPathInsideRoot(root, target) {
|
|
33507
|
-
const relative =
|
|
33508
|
-
return relative === "" || !relative.startsWith("..") && !
|
|
33734
|
+
const relative = path16.relative(root, target);
|
|
33735
|
+
return relative === "" || !relative.startsWith("..") && !path16.isAbsolute(relative);
|
|
33509
33736
|
}
|
|
33510
33737
|
function normalizeQueryParts(query2, homeRoot) {
|
|
33511
33738
|
const typedQuery = query2.trim().replace(/\\/g, "/");
|
|
@@ -33521,9 +33748,9 @@ function normalizeQueryParts(query2, homeRoot) {
|
|
|
33521
33748
|
normalized = normalized.slice(1);
|
|
33522
33749
|
}
|
|
33523
33750
|
}
|
|
33524
|
-
if (
|
|
33751
|
+
if (path16.isAbsolute(normalized)) {
|
|
33525
33752
|
isRooted = true;
|
|
33526
|
-
const absolute =
|
|
33753
|
+
const absolute = path16.resolve(normalized);
|
|
33527
33754
|
if (!isPathInsideRoot(homeRoot, absolute)) {
|
|
33528
33755
|
return null;
|
|
33529
33756
|
}
|
|
@@ -33562,8 +33789,8 @@ function normalizeQueryParts(query2, homeRoot) {
|
|
|
33562
33789
|
}
|
|
33563
33790
|
function normalizeWorkspaceQueryParts(query2, workspaceRoot) {
|
|
33564
33791
|
let normalized = query2.trim().replace(/\\/g, "/");
|
|
33565
|
-
if (
|
|
33566
|
-
const absolute =
|
|
33792
|
+
if (path16.isAbsolute(normalized)) {
|
|
33793
|
+
const absolute = path16.resolve(normalized);
|
|
33567
33794
|
if (!isPathInsideRoot(workspaceRoot, absolute)) {
|
|
33568
33795
|
return null;
|
|
33569
33796
|
}
|
|
@@ -33589,7 +33816,7 @@ function normalizeWorkspaceQueryParts(query2, workspaceRoot) {
|
|
|
33589
33816
|
}
|
|
33590
33817
|
async function resolveDirectory(inputPath) {
|
|
33591
33818
|
try {
|
|
33592
|
-
const resolved = await realpath(
|
|
33819
|
+
const resolved = await realpath(path16.resolve(inputPath));
|
|
33593
33820
|
const stats = await stat3(resolved);
|
|
33594
33821
|
if (!stats.isDirectory()) {
|
|
33595
33822
|
return null;
|
|
@@ -33616,7 +33843,7 @@ async function listChildDirectories(input) {
|
|
|
33616
33843
|
if (!dirent.isDirectory() && !dirent.isSymbolicLink()) {
|
|
33617
33844
|
continue;
|
|
33618
33845
|
}
|
|
33619
|
-
const candidatePath =
|
|
33846
|
+
const candidatePath = path16.join(input.directory, dirent.name);
|
|
33620
33847
|
const absolutePath = await resolveDirectoryCandidate({
|
|
33621
33848
|
candidatePath,
|
|
33622
33849
|
dirent,
|
|
@@ -33653,7 +33880,7 @@ async function listWorkspaceChildEntries(input) {
|
|
|
33653
33880
|
if (isIgnoredWorkspaceDirectoryName(dirent.name)) {
|
|
33654
33881
|
continue;
|
|
33655
33882
|
}
|
|
33656
|
-
const candidatePath =
|
|
33883
|
+
const candidatePath = path16.join(input.directory, dirent.name);
|
|
33657
33884
|
const entry = await resolveWorkspaceCandidate({
|
|
33658
33885
|
candidatePath,
|
|
33659
33886
|
dirent,
|
|
@@ -33676,7 +33903,7 @@ async function listWorkspaceChildEntries(input) {
|
|
|
33676
33903
|
}
|
|
33677
33904
|
async function resolveDirectoryCandidate(input) {
|
|
33678
33905
|
if (input.dirent.isDirectory()) {
|
|
33679
|
-
const resolved2 =
|
|
33906
|
+
const resolved2 = path16.resolve(input.candidatePath);
|
|
33680
33907
|
return isPathInsideRoot(input.homeRoot, resolved2) ? resolved2 : null;
|
|
33681
33908
|
}
|
|
33682
33909
|
const resolved = await resolveDirectory(input.candidatePath);
|
|
@@ -33687,14 +33914,14 @@ async function resolveDirectoryCandidate(input) {
|
|
|
33687
33914
|
}
|
|
33688
33915
|
async function resolveWorkspaceCandidate(input) {
|
|
33689
33916
|
if (input.dirent.isDirectory()) {
|
|
33690
|
-
const resolved =
|
|
33917
|
+
const resolved = path16.resolve(input.candidatePath);
|
|
33691
33918
|
if (!isPathInsideRoot(input.workspaceRoot, resolved)) {
|
|
33692
33919
|
return null;
|
|
33693
33920
|
}
|
|
33694
33921
|
return { absolutePath: resolved, kind: "directory" };
|
|
33695
33922
|
}
|
|
33696
33923
|
if (input.dirent.isFile()) {
|
|
33697
|
-
const resolved =
|
|
33924
|
+
const resolved = path16.resolve(input.candidatePath);
|
|
33698
33925
|
if (!isPathInsideRoot(input.workspaceRoot, resolved)) {
|
|
33699
33926
|
return null;
|
|
33700
33927
|
}
|
|
@@ -33774,7 +34001,7 @@ function pruneWorkspaceEntryListCache() {
|
|
|
33774
34001
|
// ../server/src/utils/directory-listing.ts
|
|
33775
34002
|
import { readdir as readdir3, stat as stat4, realpath as realpath2 } from "node:fs/promises";
|
|
33776
34003
|
import { homedir as homedir3 } from "node:os";
|
|
33777
|
-
import
|
|
34004
|
+
import path17 from "node:path";
|
|
33778
34005
|
var DEFAULT_LIMIT2 = 500;
|
|
33779
34006
|
async function listDirectoryContents(options) {
|
|
33780
34007
|
const includeFiles = options.includeFiles ?? false;
|
|
@@ -33785,7 +34012,7 @@ async function listDirectoryContents(options) {
|
|
|
33785
34012
|
const collected = [];
|
|
33786
34013
|
for (const dirent of dirents) {
|
|
33787
34014
|
if (!includeHidden && dirent.name.startsWith(".")) continue;
|
|
33788
|
-
const childPath =
|
|
34015
|
+
const childPath = path17.join(resolvedPath, dirent.name);
|
|
33789
34016
|
const kind = await classifyEntry(dirent, childPath);
|
|
33790
34017
|
if (!kind) continue;
|
|
33791
34018
|
if (kind === "file" && !includeFiles) continue;
|
|
@@ -33793,7 +34020,7 @@ async function listDirectoryContents(options) {
|
|
|
33793
34020
|
if (collected.length >= limit) break;
|
|
33794
34021
|
}
|
|
33795
34022
|
collected.sort(compareEntries);
|
|
33796
|
-
const parent =
|
|
34023
|
+
const parent = path17.dirname(resolvedPath);
|
|
33797
34024
|
return {
|
|
33798
34025
|
path: resolvedPath,
|
|
33799
34026
|
parent: parent === resolvedPath ? null : parent,
|
|
@@ -33804,12 +34031,12 @@ async function resolveAbsolutePath(rawPath) {
|
|
|
33804
34031
|
const home = process.env.HOME ?? homedir3();
|
|
33805
34032
|
const trimmed = rawPath.trim();
|
|
33806
34033
|
if (trimmed === "" || trimmed === "~") {
|
|
33807
|
-
return
|
|
34034
|
+
return path17.resolve(home);
|
|
33808
34035
|
}
|
|
33809
34036
|
if (trimmed.startsWith("~/")) {
|
|
33810
|
-
return
|
|
34037
|
+
return path17.resolve(home, trimmed.slice(2));
|
|
33811
34038
|
}
|
|
33812
|
-
if (!
|
|
34039
|
+
if (!path17.isAbsolute(trimmed)) {
|
|
33813
34040
|
throw new Error(
|
|
33814
34041
|
`list_directory requires an absolute path, an empty string, or a "~"-prefixed path; got ${JSON.stringify(rawPath)}`
|
|
33815
34042
|
);
|
|
@@ -33817,7 +34044,7 @@ async function resolveAbsolutePath(rawPath) {
|
|
|
33817
34044
|
try {
|
|
33818
34045
|
return await realpath2(trimmed);
|
|
33819
34046
|
} catch {
|
|
33820
|
-
return
|
|
34047
|
+
return path17.resolve(trimmed);
|
|
33821
34048
|
}
|
|
33822
34049
|
}
|
|
33823
34050
|
async function classifyEntry(dirent, fullPath) {
|
|
@@ -33857,10 +34084,10 @@ function resolveClientMessageId(clientMessageId, generateId = uuidv45) {
|
|
|
33857
34084
|
}
|
|
33858
34085
|
|
|
33859
34086
|
// ../server/src/server/chat/chat-service.ts
|
|
33860
|
-
import { z as
|
|
33861
|
-
var ChatStorePayloadSchema =
|
|
33862
|
-
rooms:
|
|
33863
|
-
messages:
|
|
34087
|
+
import { z as z35 } from "zod";
|
|
34088
|
+
var ChatStorePayloadSchema = z35.object({
|
|
34089
|
+
rooms: z35.array(ChatRoomSchema),
|
|
34090
|
+
messages: z35.array(ChatMessageSchema)
|
|
33864
34091
|
});
|
|
33865
34092
|
var ChatServiceError = class extends Error {
|
|
33866
34093
|
constructor(code, message) {
|
|
@@ -33951,33 +34178,33 @@ function buildChatMentionNotification(input) {
|
|
|
33951
34178
|
|
|
33952
34179
|
// ../server/src/server/roles/scanner.ts
|
|
33953
34180
|
import fs10 from "node:fs/promises";
|
|
33954
|
-
import
|
|
33955
|
-
import
|
|
34181
|
+
import os8 from "node:os";
|
|
34182
|
+
import path18 from "node:path";
|
|
33956
34183
|
var NAME_REGEX2 = /^[a-z0-9][a-z0-9._-]*$/i;
|
|
33957
34184
|
function homeDir2() {
|
|
33958
|
-
return process.env.HOME ||
|
|
34185
|
+
return process.env.HOME || os8.homedir();
|
|
33959
34186
|
}
|
|
33960
34187
|
function resolveScopeDir2(scope, workspaceRoot) {
|
|
33961
34188
|
if (scope === "project") {
|
|
33962
34189
|
if (!workspaceRoot) {
|
|
33963
34190
|
throw new Error('workspaceRoot is required for scope "project"');
|
|
33964
34191
|
}
|
|
33965
|
-
return
|
|
34192
|
+
return path18.join(workspaceRoot, ".roles");
|
|
33966
34193
|
}
|
|
33967
|
-
return
|
|
34194
|
+
return path18.join(homeDir2(), ".appostle", ".roles");
|
|
33968
34195
|
}
|
|
33969
34196
|
function allowedRoots2(workspaceRoot) {
|
|
33970
|
-
const roots = [
|
|
34197
|
+
const roots = [path18.join(homeDir2(), ".appostle", ".roles")];
|
|
33971
34198
|
if (workspaceRoot) {
|
|
33972
|
-
roots.push(
|
|
34199
|
+
roots.push(path18.join(workspaceRoot, ".roles"));
|
|
33973
34200
|
}
|
|
33974
|
-
return roots.map((r) =>
|
|
34201
|
+
return roots.map((r) => path18.resolve(r));
|
|
33975
34202
|
}
|
|
33976
34203
|
function isInsideAllowedRoot2(absPath, workspaceRoot) {
|
|
33977
|
-
const resolved =
|
|
34204
|
+
const resolved = path18.resolve(absPath);
|
|
33978
34205
|
for (const root of allowedRoots2(workspaceRoot)) {
|
|
33979
|
-
const rel =
|
|
33980
|
-
if (rel === "" || !rel.startsWith("..") && !
|
|
34206
|
+
const rel = path18.relative(root, resolved);
|
|
34207
|
+
if (rel === "" || !rel.startsWith("..") && !path18.isAbsolute(rel)) {
|
|
33981
34208
|
return true;
|
|
33982
34209
|
}
|
|
33983
34210
|
}
|
|
@@ -34175,7 +34402,7 @@ async function readRolesFromDir(scope, dir, category) {
|
|
|
34175
34402
|
if (!entry.name.endsWith(".md")) continue;
|
|
34176
34403
|
const name = entry.name.slice(0, -".md".length);
|
|
34177
34404
|
if (!name || !NAME_REGEX2.test(name)) continue;
|
|
34178
|
-
const fullPath =
|
|
34405
|
+
const fullPath = path18.join(dir, entry.name);
|
|
34179
34406
|
let stat5;
|
|
34180
34407
|
try {
|
|
34181
34408
|
const s = await fs10.stat(fullPath);
|
|
@@ -34225,7 +34452,7 @@ async function readRolesFromScopeDir(scope, scopeDir) {
|
|
|
34225
34452
|
}
|
|
34226
34453
|
const flat = await readRolesFromDir(scope, scopeDir, null);
|
|
34227
34454
|
const categoryResults = await Promise.all(
|
|
34228
|
-
topEntries.filter((e) => e.isDirectory() && NAME_REGEX2.test(e.name)).map((e) => readRolesFromDir(scope,
|
|
34455
|
+
topEntries.filter((e) => e.isDirectory() && NAME_REGEX2.test(e.name)).map((e) => readRolesFromDir(scope, path18.join(scopeDir, e.name), e.name))
|
|
34229
34456
|
);
|
|
34230
34457
|
const all = [...flat, ...categoryResults.flat()];
|
|
34231
34458
|
all.sort((a, b) => {
|
|
@@ -34265,9 +34492,9 @@ async function createRole(args) {
|
|
|
34265
34492
|
throw new Error(`Role name must not contain path separators or "..".`);
|
|
34266
34493
|
}
|
|
34267
34494
|
const scopeDir = resolveScopeDir2(args.scope, args.workspaceRoot);
|
|
34268
|
-
const dir = args.category ?
|
|
34495
|
+
const dir = args.category ? path18.join(scopeDir, args.category) : scopeDir;
|
|
34269
34496
|
await fs10.mkdir(dir, { recursive: true });
|
|
34270
|
-
const filePath =
|
|
34497
|
+
const filePath = path18.join(dir, `${args.name}.md`);
|
|
34271
34498
|
try {
|
|
34272
34499
|
await fs10.access(filePath);
|
|
34273
34500
|
throw new Error(`A role named "${args.name}" already exists at ${filePath}`);
|
|
@@ -34301,7 +34528,7 @@ the role is invoked.
|
|
|
34301
34528
|
`;
|
|
34302
34529
|
}
|
|
34303
34530
|
async function writeRoleFrontmatter(args, workspaceRoot) {
|
|
34304
|
-
if (!
|
|
34531
|
+
if (!path18.isAbsolute(args.path)) {
|
|
34305
34532
|
throw new Error(`writeRoleFrontmatter expects an absolute path; got "${args.path}"`);
|
|
34306
34533
|
}
|
|
34307
34534
|
if (!isInsideAllowedRoot2(args.path, workspaceRoot)) {
|
|
@@ -34325,20 +34552,20 @@ ${original}`;
|
|
|
34325
34552
|
await fs10.writeFile(args.path, nextContent, "utf8");
|
|
34326
34553
|
}
|
|
34327
34554
|
async function moveRole(args, workspaceRoot) {
|
|
34328
|
-
if (!
|
|
34555
|
+
if (!path18.isAbsolute(args.path)) {
|
|
34329
34556
|
throw new Error(`moveRole expects an absolute path; got "${args.path}"`);
|
|
34330
34557
|
}
|
|
34331
34558
|
if (!isInsideAllowedRoot2(args.path, workspaceRoot)) {
|
|
34332
34559
|
throw new Error(`Path "${args.path}" is not inside an allowlisted role root`);
|
|
34333
34560
|
}
|
|
34334
|
-
const oldDir =
|
|
34335
|
-
const oldFilename =
|
|
34561
|
+
const oldDir = path18.dirname(args.path);
|
|
34562
|
+
const oldFilename = path18.basename(args.path, ".md");
|
|
34336
34563
|
const roots = allowedRoots2(workspaceRoot);
|
|
34337
|
-
const rolesRoot = roots.find((r) =>
|
|
34564
|
+
const rolesRoot = roots.find((r) => path18.resolve(args.path).startsWith(r));
|
|
34338
34565
|
if (!rolesRoot) {
|
|
34339
34566
|
throw new Error(`Cannot determine roles root for "${args.path}"`);
|
|
34340
34567
|
}
|
|
34341
|
-
const relFromRoot =
|
|
34568
|
+
const relFromRoot = path18.relative(rolesRoot, path18.dirname(args.path));
|
|
34342
34569
|
const currentCategory = relFromRoot && relFromRoot !== "." ? relFromRoot : "";
|
|
34343
34570
|
const newName = args.newName ?? oldFilename;
|
|
34344
34571
|
const newCategory = args.newCategory !== void 0 ? args.newCategory : currentCategory;
|
|
@@ -34348,9 +34575,9 @@ async function moveRole(args, workspaceRoot) {
|
|
|
34348
34575
|
if (newCategory && !NAME_REGEX2.test(newCategory)) {
|
|
34349
34576
|
throw new Error(`Invalid category name: "${newCategory}"`);
|
|
34350
34577
|
}
|
|
34351
|
-
const newDir = newCategory ?
|
|
34352
|
-
const newPath =
|
|
34353
|
-
if (
|
|
34578
|
+
const newDir = newCategory ? path18.join(rolesRoot, newCategory) : rolesRoot;
|
|
34579
|
+
const newPath = path18.join(newDir, `${newName}.md`);
|
|
34580
|
+
if (path18.resolve(newPath) === path18.resolve(args.path)) {
|
|
34354
34581
|
return { path: args.path };
|
|
34355
34582
|
}
|
|
34356
34583
|
await fs10.mkdir(newDir, { recursive: true });
|
|
@@ -34388,17 +34615,17 @@ async function moveRole(args, workspaceRoot) {
|
|
|
34388
34615
|
|
|
34389
34616
|
// ../server/src/server/brands/scanner.ts
|
|
34390
34617
|
import fs11 from "node:fs/promises";
|
|
34391
|
-
import
|
|
34618
|
+
import path19 from "node:path";
|
|
34392
34619
|
var CATEGORY_REGEX = /^[a-z0-9][a-z0-9_-]*$/i;
|
|
34393
34620
|
function resolveAssetsDir(workspaceRoot, category) {
|
|
34394
|
-
const base =
|
|
34621
|
+
const base = path19.join(workspaceRoot, ".appostle", "brand", "assets");
|
|
34395
34622
|
if (!category) return base;
|
|
34396
34623
|
if (!CATEGORY_REGEX.test(category) || category.includes("..")) {
|
|
34397
34624
|
throw new Error(
|
|
34398
34625
|
`Invalid asset category "${category}". Use letters, digits, dot, underscore, dash.`
|
|
34399
34626
|
);
|
|
34400
34627
|
}
|
|
34401
|
-
return
|
|
34628
|
+
return path19.join(base, category);
|
|
34402
34629
|
}
|
|
34403
34630
|
function relativePathFor(category, fileName) {
|
|
34404
34631
|
return category ? `assets/${category}/${fileName}` : `assets/${fileName}`;
|
|
@@ -34414,9 +34641,9 @@ async function removeSiblingExtensions(dir, targetName, keepFileName) {
|
|
|
34414
34641
|
if (entry === keepFileName) continue;
|
|
34415
34642
|
if (!entry.startsWith(`${targetName}.`)) continue;
|
|
34416
34643
|
try {
|
|
34417
|
-
const stat5 = await fs11.stat(
|
|
34644
|
+
const stat5 = await fs11.stat(path19.join(dir, entry));
|
|
34418
34645
|
if (!stat5.isFile()) continue;
|
|
34419
|
-
await fs11.unlink(
|
|
34646
|
+
await fs11.unlink(path19.join(dir, entry));
|
|
34420
34647
|
} catch {
|
|
34421
34648
|
}
|
|
34422
34649
|
}
|
|
@@ -34427,7 +34654,7 @@ function convertSvgToMono(svg, color) {
|
|
|
34427
34654
|
async function runDerivations(options) {
|
|
34428
34655
|
const { primaryAbsolutePath, assetsDir, category, derive } = options;
|
|
34429
34656
|
if (derive.length === 0) return [];
|
|
34430
|
-
const ext =
|
|
34657
|
+
const ext = path19.extname(primaryAbsolutePath).toLowerCase();
|
|
34431
34658
|
const isSvg = ext === ".svg";
|
|
34432
34659
|
const results = [];
|
|
34433
34660
|
for (const spec of derive) {
|
|
@@ -34462,9 +34689,9 @@ async function runDerivations(options) {
|
|
|
34462
34689
|
const sourceText = await fs11.readFile(primaryAbsolutePath, "utf8");
|
|
34463
34690
|
const monoText = convertSvgToMono(sourceText, spec.color);
|
|
34464
34691
|
const fileName = `${spec.targetName}${ext}`;
|
|
34465
|
-
const destAbs =
|
|
34466
|
-
const rel =
|
|
34467
|
-
if (rel.startsWith("..") ||
|
|
34692
|
+
const destAbs = path19.resolve(assetsDir, fileName);
|
|
34693
|
+
const rel = path19.relative(path19.resolve(assetsDir), destAbs);
|
|
34694
|
+
if (rel.startsWith("..") || path19.isAbsolute(rel)) {
|
|
34468
34695
|
results.push({
|
|
34469
34696
|
targetName: spec.targetName,
|
|
34470
34697
|
relativePath: "",
|
|
@@ -34498,22 +34725,22 @@ function resolveScopeDir3(scope, workspaceRoot) {
|
|
|
34498
34725
|
if (!workspaceRoot) {
|
|
34499
34726
|
throw new Error('workspaceRoot is required for scope "project"');
|
|
34500
34727
|
}
|
|
34501
|
-
return
|
|
34728
|
+
return path19.join(workspaceRoot, ".appostle", "brand");
|
|
34502
34729
|
}
|
|
34503
34730
|
throw new Error(`Unknown scope: ${scope}`);
|
|
34504
34731
|
}
|
|
34505
34732
|
function allowedRoots3(workspaceRoot) {
|
|
34506
34733
|
const roots = [];
|
|
34507
34734
|
if (workspaceRoot) {
|
|
34508
|
-
roots.push(
|
|
34735
|
+
roots.push(path19.join(workspaceRoot, ".appostle", "brand"));
|
|
34509
34736
|
}
|
|
34510
|
-
return roots.map((r) =>
|
|
34737
|
+
return roots.map((r) => path19.resolve(r));
|
|
34511
34738
|
}
|
|
34512
34739
|
function isInsideAllowedRoot3(absPath, workspaceRoot) {
|
|
34513
|
-
const resolved =
|
|
34740
|
+
const resolved = path19.resolve(absPath);
|
|
34514
34741
|
for (const root of allowedRoots3(workspaceRoot)) {
|
|
34515
|
-
const rel =
|
|
34516
|
-
if (rel === "" || !rel.startsWith("..") && !
|
|
34742
|
+
const rel = path19.relative(root, resolved);
|
|
34743
|
+
if (rel === "" || !rel.startsWith("..") && !path19.isAbsolute(rel)) {
|
|
34517
34744
|
return true;
|
|
34518
34745
|
}
|
|
34519
34746
|
}
|
|
@@ -34727,7 +34954,7 @@ async function readBrandsFromDir(scope, dir) {
|
|
|
34727
34954
|
if (!entry.name.endsWith(".md")) continue;
|
|
34728
34955
|
const name = entry.name.slice(0, -".md".length);
|
|
34729
34956
|
if (!name || !NAME_REGEX3.test(name)) continue;
|
|
34730
|
-
const fullPath =
|
|
34957
|
+
const fullPath = path19.join(dir, entry.name);
|
|
34731
34958
|
let stat5;
|
|
34732
34959
|
try {
|
|
34733
34960
|
const s = await fs11.stat(fullPath);
|
|
@@ -34771,7 +34998,7 @@ async function createBrand(args) {
|
|
|
34771
34998
|
}
|
|
34772
34999
|
const dir = resolveScopeDir3("project", args.workspaceRoot);
|
|
34773
35000
|
await fs11.mkdir(dir, { recursive: true });
|
|
34774
|
-
const filePath =
|
|
35001
|
+
const filePath = path19.join(dir, `${args.name}.md`);
|
|
34775
35002
|
try {
|
|
34776
35003
|
await fs11.access(filePath);
|
|
34777
35004
|
throw new Error(`A brand named "${args.name}" already exists at ${filePath}`);
|
|
@@ -34827,7 +35054,7 @@ async function copyBrandAsset(args) {
|
|
|
34827
35054
|
if (!args.workspaceRoot) {
|
|
34828
35055
|
throw new Error("workspaceRoot is required to copy a brand asset");
|
|
34829
35056
|
}
|
|
34830
|
-
if (!args.sourcePath || !
|
|
35057
|
+
if (!args.sourcePath || !path19.isAbsolute(args.sourcePath)) {
|
|
34831
35058
|
throw new Error(`copyBrandAsset expects an absolute sourcePath; got "${args.sourcePath}"`);
|
|
34832
35059
|
}
|
|
34833
35060
|
if (!TARGET_NAME_REGEX.test(args.targetName) || args.targetName.includes("..")) {
|
|
@@ -34839,12 +35066,12 @@ async function copyBrandAsset(args) {
|
|
|
34839
35066
|
if (!stats.isFile()) {
|
|
34840
35067
|
throw new Error(`Source path is not a regular file: ${args.sourcePath}`);
|
|
34841
35068
|
}
|
|
34842
|
-
const ext =
|
|
35069
|
+
const ext = path19.extname(args.sourcePath).toLowerCase();
|
|
34843
35070
|
const fileName = `${args.targetName}${ext}`;
|
|
34844
35071
|
const assetsDir = resolveAssetsDir(args.workspaceRoot, args.category);
|
|
34845
|
-
const destAbs =
|
|
34846
|
-
const rel =
|
|
34847
|
-
if (rel.startsWith("..") ||
|
|
35072
|
+
const destAbs = path19.resolve(assetsDir, fileName);
|
|
35073
|
+
const rel = path19.relative(path19.resolve(assetsDir), destAbs);
|
|
35074
|
+
if (rel.startsWith("..") || path19.isAbsolute(rel)) {
|
|
34848
35075
|
throw new Error(`Refusing to write outside of .appostle/brand/assets: ${destAbs}`);
|
|
34849
35076
|
}
|
|
34850
35077
|
await fs11.mkdir(assetsDir, { recursive: true });
|
|
@@ -34874,13 +35101,13 @@ async function uploadBrandAsset(args) {
|
|
|
34874
35101
|
if (!args.dataBase64 || args.dataBase64.trim().length === 0) {
|
|
34875
35102
|
throw new Error("No file data provided for brand asset upload");
|
|
34876
35103
|
}
|
|
34877
|
-
const extFromSource = args.sourceName ?
|
|
35104
|
+
const extFromSource = args.sourceName ? path19.extname(args.sourceName).toLowerCase() : "";
|
|
34878
35105
|
const ext = extFromSource || ".png";
|
|
34879
35106
|
const fileName = `${args.targetName}${ext}`;
|
|
34880
35107
|
const assetsDir = resolveAssetsDir(args.workspaceRoot, args.category);
|
|
34881
|
-
const destAbs =
|
|
34882
|
-
const rel =
|
|
34883
|
-
if (rel.startsWith("..") ||
|
|
35108
|
+
const destAbs = path19.resolve(assetsDir, fileName);
|
|
35109
|
+
const rel = path19.relative(path19.resolve(assetsDir), destAbs);
|
|
35110
|
+
if (rel.startsWith("..") || path19.isAbsolute(rel)) {
|
|
34884
35111
|
throw new Error(`Refusing to write outside of .appostle/brand/assets: ${destAbs}`);
|
|
34885
35112
|
}
|
|
34886
35113
|
let data;
|
|
@@ -34908,7 +35135,7 @@ async function uploadBrandAsset(args) {
|
|
|
34908
35135
|
};
|
|
34909
35136
|
}
|
|
34910
35137
|
async function writeBrandFrontmatter(args, workspaceRoot) {
|
|
34911
|
-
if (!
|
|
35138
|
+
if (!path19.isAbsolute(args.path)) {
|
|
34912
35139
|
throw new Error(`writeBrandFrontmatter expects an absolute path; got "${args.path}"`);
|
|
34913
35140
|
}
|
|
34914
35141
|
if (!isInsideAllowedRoot3(args.path, workspaceRoot)) {
|
|
@@ -34933,10 +35160,10 @@ ${original}`;
|
|
|
34933
35160
|
}
|
|
34934
35161
|
|
|
34935
35162
|
// ../server/src/server/brand/token-generator.ts
|
|
34936
|
-
import { z as
|
|
35163
|
+
import { z as z36 } from "zod";
|
|
34937
35164
|
var HEX6 = /^#[0-9a-f]{6}$/i;
|
|
34938
|
-
var TokensResponseSchema =
|
|
34939
|
-
tokens:
|
|
35165
|
+
var TokensResponseSchema = z36.object({
|
|
35166
|
+
tokens: z36.record(z36.string(), z36.string())
|
|
34940
35167
|
});
|
|
34941
35168
|
function buildPrompt2(args) {
|
|
34942
35169
|
const baseColours = args.paletteVars.filter((v) => v.type === "color");
|
|
@@ -35154,21 +35381,21 @@ async function generateAndApplyBrandTokens(options) {
|
|
|
35154
35381
|
|
|
35155
35382
|
// ../server/src/server/brand/art-direction-generator.ts
|
|
35156
35383
|
import { promises as fs12 } from "node:fs";
|
|
35157
|
-
import
|
|
35384
|
+
import path20 from "node:path";
|
|
35158
35385
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
35159
|
-
import { z as
|
|
35386
|
+
import { z as z37 } from "zod";
|
|
35160
35387
|
var PROMPT_FILENAME = "art-direction-prompt.md";
|
|
35161
35388
|
var MAX_LOOKUP_LEVELS = 10;
|
|
35162
35389
|
async function findPromptFile() {
|
|
35163
|
-
let dir =
|
|
35390
|
+
let dir = path20.dirname(fileURLToPath2(import.meta.url));
|
|
35164
35391
|
for (let i = 0; i < MAX_LOOKUP_LEVELS; i++) {
|
|
35165
|
-
const candidate =
|
|
35392
|
+
const candidate = path20.join(dir, PROMPT_FILENAME);
|
|
35166
35393
|
try {
|
|
35167
35394
|
await fs12.access(candidate);
|
|
35168
35395
|
return candidate;
|
|
35169
35396
|
} catch {
|
|
35170
35397
|
}
|
|
35171
|
-
const parent =
|
|
35398
|
+
const parent = path20.dirname(dir);
|
|
35172
35399
|
if (parent === dir) break;
|
|
35173
35400
|
dir = parent;
|
|
35174
35401
|
}
|
|
@@ -35201,8 +35428,8 @@ var EMBEDDED_PROMPT_FALLBACK = [
|
|
|
35201
35428
|
"",
|
|
35202
35429
|
'Return ONLY JSON: { "fields": { "art-direction.intent": "...", ... } }'
|
|
35203
35430
|
].join("\n");
|
|
35204
|
-
var ArtDirectionResponseSchema =
|
|
35205
|
-
fields:
|
|
35431
|
+
var ArtDirectionResponseSchema = z37.object({
|
|
35432
|
+
fields: z37.record(z37.string(), z37.string())
|
|
35206
35433
|
});
|
|
35207
35434
|
var KNOWN_KEYS = /* @__PURE__ */ new Set([
|
|
35208
35435
|
"art-direction.intent",
|
|
@@ -35602,57 +35829,57 @@ async function fetchGitLabUsername(fetchImpl, accessToken) {
|
|
|
35602
35829
|
return null;
|
|
35603
35830
|
}
|
|
35604
35831
|
}
|
|
35605
|
-
async function readCredential(
|
|
35832
|
+
async function readCredential(path29, log2) {
|
|
35606
35833
|
try {
|
|
35607
|
-
const raw = await readFile3(
|
|
35834
|
+
const raw = await readFile3(path29, "utf8");
|
|
35608
35835
|
const parsed = JSON.parse(raw);
|
|
35609
35836
|
return parsed.gitlab ?? null;
|
|
35610
35837
|
} catch (error) {
|
|
35611
35838
|
if (isNotFound(error)) return null;
|
|
35612
|
-
log2.warn({ err: error, path:
|
|
35839
|
+
log2.warn({ err: error, path: path29 }, "oauth.credentials.read_failed");
|
|
35613
35840
|
return null;
|
|
35614
35841
|
}
|
|
35615
35842
|
}
|
|
35616
|
-
async function persistCredential(
|
|
35617
|
-
await mkdir4(dirname4(
|
|
35843
|
+
async function persistCredential(path29, credential, log2) {
|
|
35844
|
+
await mkdir4(dirname4(path29), { recursive: true });
|
|
35618
35845
|
let current = {};
|
|
35619
35846
|
try {
|
|
35620
|
-
const raw = await readFile3(
|
|
35847
|
+
const raw = await readFile3(path29, "utf8");
|
|
35621
35848
|
current = JSON.parse(raw);
|
|
35622
35849
|
} catch (error) {
|
|
35623
35850
|
if (!isNotFound(error)) {
|
|
35624
|
-
log2.warn({ err: error, path:
|
|
35851
|
+
log2.warn({ err: error, path: path29 }, "oauth.credentials.read_failed_overwriting");
|
|
35625
35852
|
}
|
|
35626
35853
|
}
|
|
35627
35854
|
const next = { ...current, gitlab: credential };
|
|
35628
|
-
const tmpPath = `${
|
|
35855
|
+
const tmpPath = `${path29}.tmp-${process.pid}-${Date.now()}`;
|
|
35629
35856
|
await writeFile4(tmpPath, JSON.stringify(next, null, 2), { mode: 384 });
|
|
35630
|
-
await rename(tmpPath,
|
|
35857
|
+
await rename(tmpPath, path29);
|
|
35631
35858
|
}
|
|
35632
|
-
async function deleteCredential(
|
|
35859
|
+
async function deleteCredential(path29, log2) {
|
|
35633
35860
|
let current = {};
|
|
35634
35861
|
try {
|
|
35635
|
-
const raw = await readFile3(
|
|
35862
|
+
const raw = await readFile3(path29, "utf8");
|
|
35636
35863
|
current = JSON.parse(raw);
|
|
35637
35864
|
} catch (error) {
|
|
35638
35865
|
if (isNotFound(error)) return;
|
|
35639
|
-
log2.warn({ err: error, path:
|
|
35866
|
+
log2.warn({ err: error, path: path29 }, "oauth.credentials.delete_read_failed");
|
|
35640
35867
|
return;
|
|
35641
35868
|
}
|
|
35642
35869
|
delete current.gitlab;
|
|
35643
35870
|
if (Object.keys(current).length === 0) {
|
|
35644
35871
|
try {
|
|
35645
|
-
await unlink(
|
|
35872
|
+
await unlink(path29);
|
|
35646
35873
|
} catch (error) {
|
|
35647
35874
|
if (!isNotFound(error)) {
|
|
35648
|
-
log2.warn({ err: error, path:
|
|
35875
|
+
log2.warn({ err: error, path: path29 }, "oauth.credentials.unlink_failed");
|
|
35649
35876
|
}
|
|
35650
35877
|
}
|
|
35651
35878
|
return;
|
|
35652
35879
|
}
|
|
35653
|
-
const tmpPath = `${
|
|
35880
|
+
const tmpPath = `${path29}.tmp-${process.pid}-${Date.now()}`;
|
|
35654
35881
|
await writeFile4(tmpPath, JSON.stringify(current, null, 2), { mode: 384 });
|
|
35655
|
-
await rename(tmpPath,
|
|
35882
|
+
await rename(tmpPath, path29);
|
|
35656
35883
|
}
|
|
35657
35884
|
function defaultGlabConfigPath() {
|
|
35658
35885
|
const home = homedir4();
|
|
@@ -35667,15 +35894,15 @@ function defaultGlabConfigPath() {
|
|
|
35667
35894
|
const xdg = process.env.XDG_CONFIG_HOME;
|
|
35668
35895
|
return join11(xdg && xdg.length > 0 ? xdg : join11(home, ".config"), "glab-cli", "config.yml");
|
|
35669
35896
|
}
|
|
35670
|
-
async function writeGlabConfig(
|
|
35671
|
-
await mkdir4(dirname4(
|
|
35897
|
+
async function writeGlabConfig(path29, credential, log2) {
|
|
35898
|
+
await mkdir4(dirname4(path29), { recursive: true });
|
|
35672
35899
|
let doc;
|
|
35673
35900
|
try {
|
|
35674
|
-
const raw = await readFile3(
|
|
35901
|
+
const raw = await readFile3(path29, "utf8");
|
|
35675
35902
|
doc = YAML.parseDocument(raw);
|
|
35676
35903
|
if (doc.errors.length > 0) {
|
|
35677
35904
|
log2.warn(
|
|
35678
|
-
{ errors: doc.errors.map((e) => e.message), path:
|
|
35905
|
+
{ errors: doc.errors.map((e) => e.message), path: path29 },
|
|
35679
35906
|
"oauth.glab.parse_errors_replacing"
|
|
35680
35907
|
);
|
|
35681
35908
|
doc = YAML.parseDocument("{}");
|
|
@@ -35684,7 +35911,7 @@ async function writeGlabConfig(path28, credential, log2) {
|
|
|
35684
35911
|
if (isNotFound(error)) {
|
|
35685
35912
|
doc = YAML.parseDocument("{}");
|
|
35686
35913
|
} else {
|
|
35687
|
-
log2.warn({ err: error, path:
|
|
35914
|
+
log2.warn({ err: error, path: path29 }, "oauth.glab.read_failed_replacing");
|
|
35688
35915
|
doc = YAML.parseDocument("{}");
|
|
35689
35916
|
}
|
|
35690
35917
|
}
|
|
@@ -35697,18 +35924,18 @@ async function writeGlabConfig(path28, credential, log2) {
|
|
|
35697
35924
|
if (credential.username) {
|
|
35698
35925
|
hostEntry.set("user", credential.username);
|
|
35699
35926
|
}
|
|
35700
|
-
const tmpPath = `${
|
|
35927
|
+
const tmpPath = `${path29}.tmp-${process.pid}-${Date.now()}`;
|
|
35701
35928
|
await writeFile4(tmpPath, doc.toString(), { mode: 384 });
|
|
35702
|
-
await rename(tmpPath,
|
|
35929
|
+
await rename(tmpPath, path29);
|
|
35703
35930
|
}
|
|
35704
|
-
async function removeGlabHost(
|
|
35931
|
+
async function removeGlabHost(path29, log2) {
|
|
35705
35932
|
let doc;
|
|
35706
35933
|
try {
|
|
35707
|
-
const raw = await readFile3(
|
|
35934
|
+
const raw = await readFile3(path29, "utf8");
|
|
35708
35935
|
doc = YAML.parseDocument(raw);
|
|
35709
35936
|
} catch (error) {
|
|
35710
35937
|
if (isNotFound(error)) return;
|
|
35711
|
-
log2.warn({ err: error, path:
|
|
35938
|
+
log2.warn({ err: error, path: path29 }, "oauth.glab.remove_read_failed");
|
|
35712
35939
|
return;
|
|
35713
35940
|
}
|
|
35714
35941
|
const hosts = doc.get("hosts");
|
|
@@ -35717,9 +35944,9 @@ async function removeGlabHost(path28, log2) {
|
|
|
35717
35944
|
if (hosts.items.length === 0) {
|
|
35718
35945
|
doc.delete("hosts");
|
|
35719
35946
|
}
|
|
35720
|
-
const tmpPath = `${
|
|
35947
|
+
const tmpPath = `${path29}.tmp-${process.pid}-${Date.now()}`;
|
|
35721
35948
|
await writeFile4(tmpPath, doc.toString(), { mode: 384 });
|
|
35722
|
-
await rename(tmpPath,
|
|
35949
|
+
await rename(tmpPath, path29);
|
|
35723
35950
|
}
|
|
35724
35951
|
function ensureMap(doc, key) {
|
|
35725
35952
|
const existing = doc.get(key);
|
|
@@ -36748,7 +36975,7 @@ var MIN_STREAMING_SEGMENT_DURATION_MS = 1e3;
|
|
|
36748
36975
|
var MIN_STREAMING_SEGMENT_BYTES = Math.round(
|
|
36749
36976
|
PCM_BYTES_PER_MS * MIN_STREAMING_SEGMENT_DURATION_MS
|
|
36750
36977
|
);
|
|
36751
|
-
var
|
|
36978
|
+
var AgentIdSchema2 = z38.string().uuid();
|
|
36752
36979
|
var VOICE_INTERRUPT_CONFIRMATION_MS = 500;
|
|
36753
36980
|
var VoiceFeatureUnavailableError = class extends Error {
|
|
36754
36981
|
constructor(context) {
|
|
@@ -36835,6 +37062,8 @@ var Session = class _Session {
|
|
|
36835
37062
|
this.nextTerminalSlot = 0;
|
|
36836
37063
|
this.inflightRequests = 0;
|
|
36837
37064
|
this.peakInflightRequests = 0;
|
|
37065
|
+
/** In-progress `claude login` processes, keyed by requestId. */
|
|
37066
|
+
this.pendingClaudeLogins = /* @__PURE__ */ new Map();
|
|
36838
37067
|
this.checkoutDiffSubscriptions = /* @__PURE__ */ new Map();
|
|
36839
37068
|
this.workspaceGitWatchTargets = /* @__PURE__ */ new Map();
|
|
36840
37069
|
this.workspaceSetupSnapshots = /* @__PURE__ */ new Map();
|
|
@@ -36852,6 +37081,8 @@ var Session = class _Session {
|
|
|
36852
37081
|
const {
|
|
36853
37082
|
clientId,
|
|
36854
37083
|
appVersion,
|
|
37084
|
+
peerPublicKeyB64,
|
|
37085
|
+
ownerUserId,
|
|
36855
37086
|
onMessage,
|
|
36856
37087
|
onBinaryMessage,
|
|
36857
37088
|
onLifecycleIntent,
|
|
@@ -36896,6 +37127,8 @@ var Session = class _Session {
|
|
|
36896
37127
|
this.clientId = clientId;
|
|
36897
37128
|
this.appVersion = appVersion ?? null;
|
|
36898
37129
|
this.sessionId = uuidv47();
|
|
37130
|
+
this.userId = options.userId ?? null;
|
|
37131
|
+
this.username = options.username ?? null;
|
|
36899
37132
|
this.onMessage = onMessage;
|
|
36900
37133
|
this.onBinaryMessage = onBinaryMessage ?? null;
|
|
36901
37134
|
this.onLifecycleIntent = onLifecycleIntent ?? null;
|
|
@@ -36912,6 +37145,8 @@ var Session = class _Session {
|
|
|
36912
37145
|
});
|
|
36913
37146
|
this.agentManager = agentManager;
|
|
36914
37147
|
this.agentStorage = agentStorage;
|
|
37148
|
+
this.peerPublicKeyB64 = peerPublicKeyB64 ?? null;
|
|
37149
|
+
this.ownerUserId = ownerUserId ?? null;
|
|
36915
37150
|
this.uploadStore = new SessionUploadStore({ logger: this.sessionLogger });
|
|
36916
37151
|
this.imageStore = new SessionImageStore({ logger: this.sessionLogger });
|
|
36917
37152
|
this.projectRegistry = projectRegistry;
|
|
@@ -36986,7 +37221,43 @@ var Session = class _Session {
|
|
|
36986
37221
|
});
|
|
36987
37222
|
void this.initializeAgentMcp();
|
|
36988
37223
|
this.subscribeToAgentEvents();
|
|
36989
|
-
this.sessionLogger.trace(
|
|
37224
|
+
this.sessionLogger.trace(
|
|
37225
|
+
{
|
|
37226
|
+
hasPeerPubkey: this.peerPublicKeyB64 !== null,
|
|
37227
|
+
// Log a fingerprint, not the full key, so the audit log stays useful
|
|
37228
|
+
// without bloating every entry with 44-char base64. First 8 chars is
|
|
37229
|
+
// unique enough for human cross-reference.
|
|
37230
|
+
peerPubkeyPrefix: this.peerPublicKeyB64 ? this.peerPublicKeyB64.slice(0, 8) : null,
|
|
37231
|
+
ownerUserId: this.ownerUserId
|
|
37232
|
+
},
|
|
37233
|
+
"Session created"
|
|
37234
|
+
);
|
|
37235
|
+
}
|
|
37236
|
+
/**
|
|
37237
|
+
* Peer device's e2ee pubkey (base64). Surfaced so the upcoming user-scope
|
|
37238
|
+
* lookup can resolve it via the auth-server allow-list. Null when unknown
|
|
37239
|
+
* (local TCP, legacy paths).
|
|
37240
|
+
*/
|
|
37241
|
+
getPeerPublicKeyB64() {
|
|
37242
|
+
return this.peerPublicKeyB64;
|
|
37243
|
+
}
|
|
37244
|
+
/**
|
|
37245
|
+
* Auth-server user-id that owns the connecting device. Null when the
|
|
37246
|
+
* daemon has no auth-server linkage, when the peer pubkey is unknown
|
|
37247
|
+
* (local TCP), or when the resolver returned no match (allow-list entry
|
|
37248
|
+
* for this pubkey hasn't been seen yet). Callers use this for per-user
|
|
37249
|
+
* agent filtering; null means "show everything" (single-tenant fallback).
|
|
37250
|
+
*/
|
|
37251
|
+
getOwnerUserId() {
|
|
37252
|
+
return this.ownerUserId;
|
|
37253
|
+
}
|
|
37254
|
+
/**
|
|
37255
|
+
* Whether this session is bound to a specific account. Equivalent to
|
|
37256
|
+
* `getOwnerUserId() !== null` but reads cleaner at call sites that gate
|
|
37257
|
+
* on "should we apply per-user filtering at all?".
|
|
37258
|
+
*/
|
|
37259
|
+
hasOwnerUserId() {
|
|
37260
|
+
return this.ownerUserId !== null;
|
|
36990
37261
|
}
|
|
36991
37262
|
updateAppVersion(appVersion) {
|
|
36992
37263
|
if (appVersion && appVersion !== this.appVersion) {
|
|
@@ -37231,6 +37502,9 @@ var Session = class _Session {
|
|
|
37231
37502
|
);
|
|
37232
37503
|
});
|
|
37233
37504
|
}
|
|
37505
|
+
if (this.ownerUserId !== null && !this.agentManager.canUserAccessAgentById(event.agentId, this.ownerUserId)) {
|
|
37506
|
+
return;
|
|
37507
|
+
}
|
|
37234
37508
|
const activity = this.clientActivity;
|
|
37235
37509
|
if (activity?.deviceType === "mobile") {
|
|
37236
37510
|
if (!activity.focusedAgentId) {
|
|
@@ -37458,6 +37732,9 @@ var Session = class _Session {
|
|
|
37458
37732
|
}
|
|
37459
37733
|
async forwardAgentUpdate(agent) {
|
|
37460
37734
|
try {
|
|
37735
|
+
if (this.ownerUserId !== null && !this.agentManager.canUserAccessAgentById(agent.id, this.ownerUserId)) {
|
|
37736
|
+
return;
|
|
37737
|
+
}
|
|
37461
37738
|
const subscription = this.agentUpdatesSubscription;
|
|
37462
37739
|
const payload = await this.buildAgentPayload(agent);
|
|
37463
37740
|
if (subscription) {
|
|
@@ -37515,6 +37792,18 @@ var Session = class _Session {
|
|
|
37515
37792
|
case "link_account_request":
|
|
37516
37793
|
await this.handleLinkAccountRequest(msg);
|
|
37517
37794
|
break;
|
|
37795
|
+
case "claude_profile_login_request":
|
|
37796
|
+
await this.handleClaudeProfileLoginRequest(msg);
|
|
37797
|
+
break;
|
|
37798
|
+
case "claude_profile_login_callback":
|
|
37799
|
+
await this.handleClaudeProfileLoginCallback(msg);
|
|
37800
|
+
break;
|
|
37801
|
+
case "claude_profile_status_request":
|
|
37802
|
+
await this.handleClaudeProfileStatusRequest(msg);
|
|
37803
|
+
break;
|
|
37804
|
+
case "claude_profile_remove_request":
|
|
37805
|
+
await this.handleClaudeProfileRemoveRequest(msg);
|
|
37806
|
+
break;
|
|
37518
37807
|
case "fetch_agents_request":
|
|
37519
37808
|
await this.handleFetchAgents(msg);
|
|
37520
37809
|
break;
|
|
@@ -37560,6 +37849,15 @@ var Session = class _Session {
|
|
|
37560
37849
|
case "delete_session_upload_request":
|
|
37561
37850
|
await this.handleDeleteSessionUploadRequest(msg);
|
|
37562
37851
|
break;
|
|
37852
|
+
case "share_agent_with_user_request":
|
|
37853
|
+
await this.handleShareAgentWithUserRequest(msg);
|
|
37854
|
+
break;
|
|
37855
|
+
case "unshare_agent_with_user_request":
|
|
37856
|
+
await this.handleUnshareAgentWithUserRequest(msg);
|
|
37857
|
+
break;
|
|
37858
|
+
case "list_agent_shared_users_request":
|
|
37859
|
+
await this.handleListAgentSharedUsersRequest(msg);
|
|
37860
|
+
break;
|
|
37563
37861
|
case "list_session_images_request":
|
|
37564
37862
|
await this.handleListSessionImagesRequest(msg);
|
|
37565
37863
|
break;
|
|
@@ -38221,6 +38519,138 @@ var Session = class _Session {
|
|
|
38221
38519
|
respond({ ok: false, error: message });
|
|
38222
38520
|
}
|
|
38223
38521
|
}
|
|
38522
|
+
// ---------------------------------------------------------------------------
|
|
38523
|
+
// Claude profile login — per-user subscription on shared hosts
|
|
38524
|
+
// ---------------------------------------------------------------------------
|
|
38525
|
+
async handleClaudeProfileLoginRequest(msg) {
|
|
38526
|
+
const { requestId, username } = msg;
|
|
38527
|
+
const log2 = this.sessionLogger.child({ handler: "claude_profile_login" });
|
|
38528
|
+
try {
|
|
38529
|
+
const profileDir = ensureClaudeProfile(username, log2);
|
|
38530
|
+
const child = spawnProcess("claude", ["auth", "login"], {
|
|
38531
|
+
env: {
|
|
38532
|
+
...process.env,
|
|
38533
|
+
CLAUDE_CONFIG_DIR: profileDir
|
|
38534
|
+
},
|
|
38535
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
38536
|
+
});
|
|
38537
|
+
this.pendingClaudeLogins.set(requestId, { process: child, username });
|
|
38538
|
+
let stdoutBuffer = "";
|
|
38539
|
+
child.stdout?.on("data", (chunk) => {
|
|
38540
|
+
stdoutBuffer += chunk.toString();
|
|
38541
|
+
const urlMatch = stdoutBuffer.match(/(https?:\/\/[^\s]+)/);
|
|
38542
|
+
if (urlMatch) {
|
|
38543
|
+
this.emit({
|
|
38544
|
+
type: "claude_profile_login_url",
|
|
38545
|
+
requestId,
|
|
38546
|
+
url: urlMatch[1]
|
|
38547
|
+
});
|
|
38548
|
+
}
|
|
38549
|
+
});
|
|
38550
|
+
child.stderr?.on("data", (chunk) => {
|
|
38551
|
+
log2.debug({ stderr: chunk.toString() }, "claude login stderr");
|
|
38552
|
+
});
|
|
38553
|
+
child.on("close", (code) => {
|
|
38554
|
+
this.pendingClaudeLogins.delete(requestId);
|
|
38555
|
+
if (code === 0) {
|
|
38556
|
+
log2.info({ username }, "claude profile login succeeded");
|
|
38557
|
+
this.emit({
|
|
38558
|
+
type: "claude_profile_login_result",
|
|
38559
|
+
requestId,
|
|
38560
|
+
ok: true
|
|
38561
|
+
});
|
|
38562
|
+
} else {
|
|
38563
|
+
log2.warn({ username, code }, "claude profile login failed");
|
|
38564
|
+
this.emit({
|
|
38565
|
+
type: "claude_profile_login_result",
|
|
38566
|
+
requestId,
|
|
38567
|
+
ok: false,
|
|
38568
|
+
error: `claude login exited with code ${code}`
|
|
38569
|
+
});
|
|
38570
|
+
}
|
|
38571
|
+
});
|
|
38572
|
+
child.on("error", (err) => {
|
|
38573
|
+
this.pendingClaudeLogins.delete(requestId);
|
|
38574
|
+
log2.error({ err }, "claude login process error");
|
|
38575
|
+
this.emit({
|
|
38576
|
+
type: "claude_profile_login_result",
|
|
38577
|
+
requestId,
|
|
38578
|
+
ok: false,
|
|
38579
|
+
error: err.message
|
|
38580
|
+
});
|
|
38581
|
+
});
|
|
38582
|
+
} catch (err) {
|
|
38583
|
+
const message = err instanceof Error ? err.message : "unknown_error";
|
|
38584
|
+
log2.error({ err }, "claude profile login request failed");
|
|
38585
|
+
this.emit({
|
|
38586
|
+
type: "claude_profile_login_result",
|
|
38587
|
+
requestId,
|
|
38588
|
+
ok: false,
|
|
38589
|
+
error: message
|
|
38590
|
+
});
|
|
38591
|
+
}
|
|
38592
|
+
}
|
|
38593
|
+
async handleClaudeProfileLoginCallback(msg) {
|
|
38594
|
+
const { requestId, callbackToken } = msg;
|
|
38595
|
+
const pending = this.pendingClaudeLogins.get(requestId);
|
|
38596
|
+
if (!pending) {
|
|
38597
|
+
this.sessionLogger.warn({ requestId }, "claude_profile_login_callback: no pending login");
|
|
38598
|
+
this.emit({
|
|
38599
|
+
type: "claude_profile_login_result",
|
|
38600
|
+
requestId,
|
|
38601
|
+
ok: false,
|
|
38602
|
+
error: "no_pending_login"
|
|
38603
|
+
});
|
|
38604
|
+
return;
|
|
38605
|
+
}
|
|
38606
|
+
try {
|
|
38607
|
+
pending.process.stdin?.write(callbackToken + "\n");
|
|
38608
|
+
} catch (err) {
|
|
38609
|
+
this.sessionLogger.error({ err }, "failed to write callback token to claude login stdin");
|
|
38610
|
+
}
|
|
38611
|
+
}
|
|
38612
|
+
async handleClaudeProfileStatusRequest(msg) {
|
|
38613
|
+
const { requestId, username } = msg;
|
|
38614
|
+
const profileExists = hasClaudeAuth(username);
|
|
38615
|
+
let isAuthenticated = false;
|
|
38616
|
+
if (profileExists) {
|
|
38617
|
+
try {
|
|
38618
|
+
const profileDir = ensureClaudeProfile(username);
|
|
38619
|
+
const result = await execCommand("claude", ["auth", "status"], {
|
|
38620
|
+
env: { ...process.env, CLAUDE_CONFIG_DIR: profileDir },
|
|
38621
|
+
timeout: 5e3
|
|
38622
|
+
});
|
|
38623
|
+
isAuthenticated = !result.stdout.toLowerCase().includes("not logged in");
|
|
38624
|
+
} catch {
|
|
38625
|
+
}
|
|
38626
|
+
}
|
|
38627
|
+
this.emit({
|
|
38628
|
+
type: "claude_profile_status_response",
|
|
38629
|
+
requestId,
|
|
38630
|
+
hasProfile: profileExists,
|
|
38631
|
+
isAuthenticated
|
|
38632
|
+
});
|
|
38633
|
+
}
|
|
38634
|
+
async handleClaudeProfileRemoveRequest(msg) {
|
|
38635
|
+
const { requestId, username } = msg;
|
|
38636
|
+
try {
|
|
38637
|
+
removeClaudeProfile(username, this.sessionLogger);
|
|
38638
|
+
this.emit({
|
|
38639
|
+
type: "claude_profile_remove_response",
|
|
38640
|
+
requestId,
|
|
38641
|
+
ok: true
|
|
38642
|
+
});
|
|
38643
|
+
} catch (err) {
|
|
38644
|
+
const message = err instanceof Error ? err.message : "unknown_error";
|
|
38645
|
+
this.sessionLogger.error({ err, username }, "claude profile remove failed");
|
|
38646
|
+
this.emit({
|
|
38647
|
+
type: "claude_profile_remove_response",
|
|
38648
|
+
requestId,
|
|
38649
|
+
ok: false,
|
|
38650
|
+
error: message
|
|
38651
|
+
});
|
|
38652
|
+
}
|
|
38653
|
+
}
|
|
38224
38654
|
async handleRestartServerRequest(requestId, reason) {
|
|
38225
38655
|
const payload = {
|
|
38226
38656
|
status: "restart_requested",
|
|
@@ -38726,7 +39156,7 @@ var Session = class _Session {
|
|
|
38726
39156
|
}
|
|
38727
39157
|
}
|
|
38728
39158
|
parseVoiceTargetAgentId(rawId, source) {
|
|
38729
|
-
const parsed =
|
|
39159
|
+
const parsed = AgentIdSchema2.safeParse(rawId.trim());
|
|
38730
39160
|
if (!parsed.success) {
|
|
38731
39161
|
throw new Error(`${source}: agentId must be a UUID`);
|
|
38732
39162
|
}
|
|
@@ -39054,7 +39484,15 @@ var Session = class _Session {
|
|
|
39054
39484
|
{
|
|
39055
39485
|
labels,
|
|
39056
39486
|
workspaceId: resolvedWorkspace.workspaceId,
|
|
39057
|
-
initialPrompt: trimmedPrompt
|
|
39487
|
+
initialPrompt: trimmedPrompt,
|
|
39488
|
+
// Stamp the agent with the user that created it. Null on single-
|
|
39489
|
+
// tenant daemons (no auth-server linkage) — agent stays globally
|
|
39490
|
+
// visible, preserving legacy behavior. This is the authoritative
|
|
39491
|
+
// owner (pubkey-derived), used for `canAccessAgent`.
|
|
39492
|
+
ownerUserId: this.ownerUserId,
|
|
39493
|
+
// Self-declared identity, used for Claude profile dir naming etc.
|
|
39494
|
+
userId: this.userId ?? void 0,
|
|
39495
|
+
username: this.username ?? void 0
|
|
39058
39496
|
}
|
|
39059
39497
|
);
|
|
39060
39498
|
await this.forwardAgentUpdate(snapshot);
|
|
@@ -39533,8 +39971,8 @@ var Session = class _Session {
|
|
|
39533
39971
|
}
|
|
39534
39972
|
async generateCommitMessage(cwd) {
|
|
39535
39973
|
const files = await listUncommittedFiles(cwd);
|
|
39536
|
-
const schema =
|
|
39537
|
-
message:
|
|
39974
|
+
const schema = z38.object({
|
|
39975
|
+
message: z38.string().min(1).max(100).describe(
|
|
39538
39976
|
"Short feature-level summary, lowercase, imperative mood, no trailing period, no filename references."
|
|
39539
39977
|
)
|
|
39540
39978
|
});
|
|
@@ -39579,9 +40017,9 @@ var Session = class _Session {
|
|
|
39579
40017
|
},
|
|
39580
40018
|
{ appostleHome: this.appostleHome }
|
|
39581
40019
|
);
|
|
39582
|
-
const schema =
|
|
39583
|
-
title:
|
|
39584
|
-
body:
|
|
40020
|
+
const schema = z38.object({
|
|
40021
|
+
title: z38.string().min(1).max(72),
|
|
40022
|
+
body: z38.string().min(1)
|
|
39585
40023
|
});
|
|
39586
40024
|
const fileList = diff.structured && diff.structured.length > 0 ? [
|
|
39587
40025
|
"Files changed:",
|
|
@@ -40522,7 +40960,7 @@ var Session = class _Session {
|
|
|
40522
40960
|
homeDir: process.env.HOME ?? homedir5(),
|
|
40523
40961
|
query: query2,
|
|
40524
40962
|
limit
|
|
40525
|
-
})).map((
|
|
40963
|
+
})).map((path29) => ({ path: path29, kind: "directory" }));
|
|
40526
40964
|
const directories = entries.filter((entry) => entry.kind === "directory").map((entry) => entry.path);
|
|
40527
40965
|
this.emit({
|
|
40528
40966
|
type: "directory_suggestions_response",
|
|
@@ -41621,13 +42059,22 @@ ${details}`.trim());
|
|
|
41621
42059
|
* Build the current agent list payload (live + persisted), optionally filtered by labels.
|
|
41622
42060
|
*/
|
|
41623
42061
|
async listAgentPayloads(filter) {
|
|
41624
|
-
const agentSnapshots = this.agentManager.
|
|
42062
|
+
const agentSnapshots = this.agentManager.listAgentsForUser(this.ownerUserId);
|
|
41625
42063
|
const liveAgents = await Promise.all(
|
|
41626
42064
|
agentSnapshots.map((agent) => this.buildAgentPayload(agent))
|
|
41627
42065
|
);
|
|
41628
42066
|
const registryRecords = await this.agentStorage.list();
|
|
42067
|
+
const requesterId = this.ownerUserId;
|
|
41629
42068
|
const liveIds = new Set(agentSnapshots.map((a) => a.id));
|
|
41630
|
-
const persistedAgents = registryRecords.filter((record) => !liveIds.has(record.id)).
|
|
42069
|
+
const persistedAgents = registryRecords.filter((record) => !liveIds.has(record.id)).filter(
|
|
42070
|
+
(record) => requesterId === null || canUserAccessAgent(
|
|
42071
|
+
{
|
|
42072
|
+
ownerUserId: record.ownerUserId ?? null,
|
|
42073
|
+
sharedWithUserIds: record.sharedWithUserIds
|
|
42074
|
+
},
|
|
42075
|
+
requesterId
|
|
42076
|
+
)
|
|
42077
|
+
).map((record) => this.buildStoredAgentPayload(record));
|
|
41631
42078
|
let agents = [...liveAgents, ...persistedAgents];
|
|
41632
42079
|
agents = agents.filter((agent) => this.isProviderVisibleToClient(agent.provider));
|
|
41633
42080
|
if (filter?.labels) {
|
|
@@ -41644,6 +42091,9 @@ ${details}`.trim());
|
|
|
41644
42091
|
return { ok: false, error: "Agent identifier cannot be empty" };
|
|
41645
42092
|
}
|
|
41646
42093
|
if (this.agentManager.getAgent(trimmed)) {
|
|
42094
|
+
if (!this.agentManager.canUserAccessAgentById(trimmed, this.ownerUserId)) {
|
|
42095
|
+
return { ok: false, error: "Agent not found" };
|
|
42096
|
+
}
|
|
41647
42097
|
return { ok: true, agentId: trimmed };
|
|
41648
42098
|
}
|
|
41649
42099
|
const exactStored = await this.agentStorage.get(trimmed);
|
|
@@ -43247,6 +43697,139 @@ ${details}`.trim());
|
|
|
43247
43697
|
}
|
|
43248
43698
|
}
|
|
43249
43699
|
// ──────────────────────────────────────────────────────────────────────
|
|
43700
|
+
// Phase 4: agent sharing — owner-only mutations of the access ACL.
|
|
43701
|
+
// The visibility predicate (Phase 2c) already honors `sharedWithUserIds`;
|
|
43702
|
+
// these handlers surface a typed user-facing path so an owner can grant /
|
|
43703
|
+
// revoke / inspect access from the app instead of editing JSON on disk.
|
|
43704
|
+
//
|
|
43705
|
+
// Authorization:
|
|
43706
|
+
// - All three handlers require the session's `ownerUserId` to equal the
|
|
43707
|
+
// agent's `ownerUserId`. Anyone else gets `unauthorized` (including
|
|
43708
|
+
// existing share-recipients — only the owner can re-share).
|
|
43709
|
+
// - `resolveAgentIdentifier` already applies `canUserAccessAgent`, so a
|
|
43710
|
+
// non-recipient even sees the agent as "not found". The owner check
|
|
43711
|
+
// here is the strictly-tighter follow-up gate for mutations.
|
|
43712
|
+
// - On a single-tenant daemon (session.ownerUserId == null) the gate
|
|
43713
|
+
// opens — no isolation to enforce, sharing is a no-op for unscoped
|
|
43714
|
+
// agents (their ownerUserId is also null).
|
|
43715
|
+
// ──────────────────────────────────────────────────────────────────────
|
|
43716
|
+
async handleShareAgentWithUserRequest(msg) {
|
|
43717
|
+
const resolved = await this.resolveAgentIdentifier(msg.agentId);
|
|
43718
|
+
if (!resolved.ok) {
|
|
43719
|
+
this.emit({
|
|
43720
|
+
type: "share_agent_with_user_response",
|
|
43721
|
+
payload: { requestId: msg.requestId, ok: false, error: resolved.error }
|
|
43722
|
+
});
|
|
43723
|
+
return;
|
|
43724
|
+
}
|
|
43725
|
+
const agent = this.agentManager.getAgent(resolved.agentId);
|
|
43726
|
+
if (!agent) {
|
|
43727
|
+
this.emit({
|
|
43728
|
+
type: "share_agent_with_user_response",
|
|
43729
|
+
payload: { requestId: msg.requestId, ok: false, error: "Agent not found" }
|
|
43730
|
+
});
|
|
43731
|
+
return;
|
|
43732
|
+
}
|
|
43733
|
+
if (this.ownerUserId !== null && agent.ownerUserId !== null && agent.ownerUserId !== this.ownerUserId) {
|
|
43734
|
+
this.emit({
|
|
43735
|
+
type: "share_agent_with_user_response",
|
|
43736
|
+
payload: { requestId: msg.requestId, ok: false, error: "unauthorized" }
|
|
43737
|
+
});
|
|
43738
|
+
return;
|
|
43739
|
+
}
|
|
43740
|
+
try {
|
|
43741
|
+
const sharedWithUserIds = await this.agentManager.shareAgentWithUser(
|
|
43742
|
+
resolved.agentId,
|
|
43743
|
+
msg.userId
|
|
43744
|
+
);
|
|
43745
|
+
this.emit({
|
|
43746
|
+
type: "share_agent_with_user_response",
|
|
43747
|
+
payload: { requestId: msg.requestId, ok: true, sharedWithUserIds }
|
|
43748
|
+
});
|
|
43749
|
+
} catch (error) {
|
|
43750
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
43751
|
+
this.emit({
|
|
43752
|
+
type: "share_agent_with_user_response",
|
|
43753
|
+
payload: { requestId: msg.requestId, ok: false, error: message }
|
|
43754
|
+
});
|
|
43755
|
+
}
|
|
43756
|
+
}
|
|
43757
|
+
async handleUnshareAgentWithUserRequest(msg) {
|
|
43758
|
+
const resolved = await this.resolveAgentIdentifier(msg.agentId);
|
|
43759
|
+
if (!resolved.ok) {
|
|
43760
|
+
this.emit({
|
|
43761
|
+
type: "unshare_agent_with_user_response",
|
|
43762
|
+
payload: { requestId: msg.requestId, ok: false, error: resolved.error }
|
|
43763
|
+
});
|
|
43764
|
+
return;
|
|
43765
|
+
}
|
|
43766
|
+
const agent = this.agentManager.getAgent(resolved.agentId);
|
|
43767
|
+
if (!agent) {
|
|
43768
|
+
this.emit({
|
|
43769
|
+
type: "unshare_agent_with_user_response",
|
|
43770
|
+
payload: { requestId: msg.requestId, ok: false, error: "Agent not found" }
|
|
43771
|
+
});
|
|
43772
|
+
return;
|
|
43773
|
+
}
|
|
43774
|
+
if (this.ownerUserId !== null && agent.ownerUserId !== null && agent.ownerUserId !== this.ownerUserId) {
|
|
43775
|
+
this.emit({
|
|
43776
|
+
type: "unshare_agent_with_user_response",
|
|
43777
|
+
payload: { requestId: msg.requestId, ok: false, error: "unauthorized" }
|
|
43778
|
+
});
|
|
43779
|
+
return;
|
|
43780
|
+
}
|
|
43781
|
+
try {
|
|
43782
|
+
const sharedWithUserIds = await this.agentManager.unshareAgentWithUser(
|
|
43783
|
+
resolved.agentId,
|
|
43784
|
+
msg.userId
|
|
43785
|
+
);
|
|
43786
|
+
this.emit({
|
|
43787
|
+
type: "unshare_agent_with_user_response",
|
|
43788
|
+
payload: { requestId: msg.requestId, ok: true, sharedWithUserIds }
|
|
43789
|
+
});
|
|
43790
|
+
} catch (error) {
|
|
43791
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
43792
|
+
this.emit({
|
|
43793
|
+
type: "unshare_agent_with_user_response",
|
|
43794
|
+
payload: { requestId: msg.requestId, ok: false, error: message }
|
|
43795
|
+
});
|
|
43796
|
+
}
|
|
43797
|
+
}
|
|
43798
|
+
async handleListAgentSharedUsersRequest(msg) {
|
|
43799
|
+
const resolved = await this.resolveAgentIdentifier(msg.agentId);
|
|
43800
|
+
if (!resolved.ok) {
|
|
43801
|
+
this.emit({
|
|
43802
|
+
type: "list_agent_shared_users_response",
|
|
43803
|
+
payload: { requestId: msg.requestId, ok: false, error: resolved.error }
|
|
43804
|
+
});
|
|
43805
|
+
return;
|
|
43806
|
+
}
|
|
43807
|
+
const agent = this.agentManager.getAgent(resolved.agentId);
|
|
43808
|
+
if (!agent) {
|
|
43809
|
+
this.emit({
|
|
43810
|
+
type: "list_agent_shared_users_response",
|
|
43811
|
+
payload: { requestId: msg.requestId, ok: false, error: "Agent not found" }
|
|
43812
|
+
});
|
|
43813
|
+
return;
|
|
43814
|
+
}
|
|
43815
|
+
if (this.ownerUserId !== null && agent.ownerUserId !== null && agent.ownerUserId !== this.ownerUserId) {
|
|
43816
|
+
this.emit({
|
|
43817
|
+
type: "list_agent_shared_users_response",
|
|
43818
|
+
payload: { requestId: msg.requestId, ok: false, error: "unauthorized" }
|
|
43819
|
+
});
|
|
43820
|
+
return;
|
|
43821
|
+
}
|
|
43822
|
+
this.emit({
|
|
43823
|
+
type: "list_agent_shared_users_response",
|
|
43824
|
+
payload: {
|
|
43825
|
+
requestId: msg.requestId,
|
|
43826
|
+
ok: true,
|
|
43827
|
+
ownerUserId: agent.ownerUserId,
|
|
43828
|
+
sharedWithUserIds: [...agent.sharedWithUserIds]
|
|
43829
|
+
}
|
|
43830
|
+
});
|
|
43831
|
+
}
|
|
43832
|
+
// ──────────────────────────────────────────────────────────────────────
|
|
43250
43833
|
// Session images — backs the "Images" tab inside the uploads modal. Same
|
|
43251
43834
|
// shape as the file handlers above; the store has no manifest, so listing
|
|
43252
43835
|
// is a directory scan and delete is `unlink` (traversal-guarded).
|
|
@@ -45421,7 +46004,7 @@ import webpush from "web-push";
|
|
|
45421
46004
|
import webpush2 from "web-push";
|
|
45422
46005
|
|
|
45423
46006
|
// ../server/src/server/speech/providers/local/sherpa/model-catalog.ts
|
|
45424
|
-
import { z as
|
|
46007
|
+
import { z as z39 } from "zod";
|
|
45425
46008
|
var SHERPA_ONNX_MODEL_CATALOG = {
|
|
45426
46009
|
"zipformer-bilingual-zh-en-2023-02-20": {
|
|
45427
46010
|
kind: "stt-online",
|
|
@@ -45514,7 +46097,7 @@ function buildAliasMap(modelIds) {
|
|
|
45514
46097
|
}
|
|
45515
46098
|
function createAliasedModelIdSchema(params) {
|
|
45516
46099
|
const validIds = new Set(params.modelIds);
|
|
45517
|
-
return
|
|
46100
|
+
return z39.string().trim().toLowerCase().refine(
|
|
45518
46101
|
(value) => validIds.has(value) || Object.prototype.hasOwnProperty.call(params.aliases, value),
|
|
45519
46102
|
{
|
|
45520
46103
|
message: "Invalid model id"
|
|
@@ -45545,20 +46128,20 @@ import { v4 as uuidv410 } from "uuid";
|
|
|
45545
46128
|
import { v4 as uuidv411 } from "uuid";
|
|
45546
46129
|
|
|
45547
46130
|
// ../server/src/server/speech/providers/openai/config.ts
|
|
45548
|
-
import { z as
|
|
46131
|
+
import { z as z40 } from "zod";
|
|
45549
46132
|
var DEFAULT_OPENAI_REALTIME_TRANSCRIPTION_MODEL = "gpt-4o-transcribe";
|
|
45550
46133
|
var DEFAULT_OPENAI_TTS_MODEL = "tts-1";
|
|
45551
|
-
var OpenAiTtsVoiceSchema =
|
|
45552
|
-
var OpenAiTtsModelSchema =
|
|
45553
|
-
var NumberLikeSchema =
|
|
45554
|
-
var OptionalFiniteNumberSchema = NumberLikeSchema.pipe(
|
|
45555
|
-
var OptionalTrimmedStringSchema =
|
|
45556
|
-
var OpenAiSpeechResolutionSchema =
|
|
46134
|
+
var OpenAiTtsVoiceSchema = z40.enum(["alloy", "echo", "fable", "onyx", "nova", "shimmer"]);
|
|
46135
|
+
var OpenAiTtsModelSchema = z40.enum(["tts-1", "tts-1-hd"]);
|
|
46136
|
+
var NumberLikeSchema = z40.union([z40.number(), z40.string().trim().min(1)]);
|
|
46137
|
+
var OptionalFiniteNumberSchema = NumberLikeSchema.pipe(z40.coerce.number().finite()).optional();
|
|
46138
|
+
var OptionalTrimmedStringSchema = z40.string().trim().optional().transform((value) => value && value.length > 0 ? value : void 0);
|
|
46139
|
+
var OpenAiSpeechResolutionSchema = z40.object({
|
|
45557
46140
|
apiKey: OptionalTrimmedStringSchema,
|
|
45558
46141
|
sttConfidenceThreshold: OptionalFiniteNumberSchema,
|
|
45559
46142
|
sttModel: OptionalTrimmedStringSchema,
|
|
45560
|
-
ttsVoice:
|
|
45561
|
-
ttsModel:
|
|
46143
|
+
ttsVoice: z40.string().trim().toLowerCase().pipe(OpenAiTtsVoiceSchema).default("alloy"),
|
|
46144
|
+
ttsModel: z40.string().trim().toLowerCase().pipe(OpenAiTtsModelSchema).default(DEFAULT_OPENAI_TTS_MODEL),
|
|
45562
46145
|
realtimeTranscriptionModel: OptionalTrimmedStringSchema.default(
|
|
45563
46146
|
DEFAULT_OPENAI_REALTIME_TRANSCRIPTION_MODEL
|
|
45564
46147
|
)
|
|
@@ -45602,17 +46185,6 @@ import { v4 } from "uuid";
|
|
|
45602
46185
|
// ../server/src/server/speech/providers/openai/tts.ts
|
|
45603
46186
|
import OpenAI2 from "openai";
|
|
45604
46187
|
|
|
45605
|
-
// ../server/src/server/agent/agent-manager.ts
|
|
45606
|
-
import { z as z40 } from "zod";
|
|
45607
|
-
import { getSessionMessages } from "@anthropic-ai/claude-agent-sdk";
|
|
45608
|
-
|
|
45609
|
-
// ../server/src/server/agent/handoff-mcp.ts
|
|
45610
|
-
import { createSdkMcpServer, tool } from "@anthropic-ai/claude-agent-sdk";
|
|
45611
|
-
import { z as z39 } from "zod";
|
|
45612
|
-
|
|
45613
|
-
// ../server/src/server/agent/agent-manager.ts
|
|
45614
|
-
var AgentIdSchema2 = z40.string().uuid();
|
|
45615
|
-
|
|
45616
46188
|
// ../server/src/server/agent/agent-storage.ts
|
|
45617
46189
|
import { z as z41 } from "zod";
|
|
45618
46190
|
var SERIALIZABLE_CONFIG_SCHEMA = z41.object({
|
|
@@ -45662,7 +46234,22 @@ var STORED_AGENT_SCHEMA = z41.object({
|
|
|
45662
46234
|
archivedAt: z41.string().nullable().optional(),
|
|
45663
46235
|
// Fork lineage (optional for backward compat with pre-fork records).
|
|
45664
46236
|
parentAgentId: z41.string().optional(),
|
|
45665
|
-
forkedFromMessageUuid: z41.string().optional()
|
|
46237
|
+
forkedFromMessageUuid: z41.string().optional(),
|
|
46238
|
+
// Multi-tenant session isolation: the auth-server user-id that created
|
|
46239
|
+
// (and therefore owns) this agent + the additive ACL of other users
|
|
46240
|
+
// granted access. Both optional/null-default for backward compatibility
|
|
46241
|
+
// with pre-Phase-2c records — those load with `null` owner and stay
|
|
46242
|
+
// visible to every connecting user (matches today's single-tenant
|
|
46243
|
+
// behavior). Set on new agents at create time via Session.ownerUserId.
|
|
46244
|
+
ownerUserId: z41.string().nullable().optional(),
|
|
46245
|
+
sharedWithUserIds: z41.array(z41.string()).default([]),
|
|
46246
|
+
// Owner's display username — needed on resume to route to the correct
|
|
46247
|
+
// `CLAUDE_CONFIG_DIR` via `ensureClaudeProfile(username)` for agents
|
|
46248
|
+
// created by a shared (non-owner) user. Without this, a resumed shared-
|
|
46249
|
+
// user agent would silently fall back to the daemon owner's Claude
|
|
46250
|
+
// profile/subscription. Optional — pre-Phase-3 records rehydrate without
|
|
46251
|
+
// per-user profile routing.
|
|
46252
|
+
ownerUsername: z41.string().optional()
|
|
45666
46253
|
});
|
|
45667
46254
|
|
|
45668
46255
|
// ../server/src/server/agent/mcp-server.ts
|
|
@@ -45863,16 +46450,16 @@ function isRelayClientWebSocketUrl(url) {
|
|
|
45863
46450
|
}
|
|
45864
46451
|
|
|
45865
46452
|
// ../server/src/server/config.ts
|
|
45866
|
-
import
|
|
46453
|
+
import path22 from "node:path";
|
|
45867
46454
|
import { z as z51 } from "zod";
|
|
45868
46455
|
|
|
45869
46456
|
// ../server/src/server/speech/speech-config-resolver.ts
|
|
45870
46457
|
import { z as z50 } from "zod";
|
|
45871
46458
|
|
|
45872
46459
|
// ../server/src/server/speech/providers/local/config.ts
|
|
45873
|
-
import
|
|
46460
|
+
import path21 from "node:path";
|
|
45874
46461
|
import { z as z48 } from "zod";
|
|
45875
|
-
var DEFAULT_LOCAL_MODELS_SUBDIR =
|
|
46462
|
+
var DEFAULT_LOCAL_MODELS_SUBDIR = path21.join("models", "local-speech");
|
|
45876
46463
|
var NumberLikeSchema2 = z48.union([z48.number(), z48.string().trim().min(1)]);
|
|
45877
46464
|
var OptionalFiniteNumberSchema2 = NumberLikeSchema2.pipe(z48.coerce.number().finite()).optional();
|
|
45878
46465
|
var OptionalIntegerSchema = NumberLikeSchema2.pipe(z48.coerce.number().int()).optional();
|
|
@@ -45899,7 +46486,7 @@ function resolveLocalSpeechConfig(params) {
|
|
|
45899
46486
|
const includeProviderConfig = shouldIncludeLocalProviderConfig(params);
|
|
45900
46487
|
const parsed = LocalSpeechResolutionSchema.parse({
|
|
45901
46488
|
includeProviderConfig,
|
|
45902
|
-
modelsDir: params.env.APPOSTLE_LOCAL_MODELS_DIR ?? params.persisted.providers?.local?.modelsDir ??
|
|
46489
|
+
modelsDir: params.env.APPOSTLE_LOCAL_MODELS_DIR ?? params.persisted.providers?.local?.modelsDir ?? path21.join(params.appostleHome, DEFAULT_LOCAL_MODELS_SUBDIR),
|
|
45903
46490
|
dictationLocalSttModel: params.env.APPOSTLE_DICTATION_LOCAL_STT_MODEL ?? persistedLocalFeatureModel(
|
|
45904
46491
|
params.providers.dictationStt.provider,
|
|
45905
46492
|
params.providers.dictationStt.enabled,
|
|
@@ -46155,7 +46742,7 @@ function loadConfig(appostleHome, options) {
|
|
|
46155
46742
|
chromeEnabled,
|
|
46156
46743
|
mcpDebug: env.MCP_DEBUG === "1",
|
|
46157
46744
|
daemonIcon,
|
|
46158
|
-
agentStoragePath:
|
|
46745
|
+
agentStoragePath: path22.join(appostleHome, "agents"),
|
|
46159
46746
|
staticDir: "public",
|
|
46160
46747
|
agentClients: {},
|
|
46161
46748
|
relayEnabled,
|
|
@@ -46346,10 +46933,10 @@ function encodeUtf8String(value) {
|
|
|
46346
46933
|
function createRelayE2eeTransportFactory(args) {
|
|
46347
46934
|
return ({ url, headers }) => {
|
|
46348
46935
|
const base = args.baseFactory({ url, headers });
|
|
46349
|
-
return createEncryptedTransport(base, args.daemonPublicKeyB64, args.logger);
|
|
46936
|
+
return createEncryptedTransport(base, args.daemonPublicKeyB64, args.logger, args.staticKeyPair);
|
|
46350
46937
|
};
|
|
46351
46938
|
}
|
|
46352
|
-
function createEncryptedTransport(base, daemonPublicKeyB64, logger) {
|
|
46939
|
+
function createEncryptedTransport(base, daemonPublicKeyB64, logger, staticKeyPair) {
|
|
46353
46940
|
let channel = null;
|
|
46354
46941
|
let opened = false;
|
|
46355
46942
|
let closed = false;
|
|
@@ -46406,12 +46993,17 @@ function createEncryptedTransport(base, daemonPublicKeyB64, logger) {
|
|
|
46406
46993
|
};
|
|
46407
46994
|
const startHandshake = async () => {
|
|
46408
46995
|
try {
|
|
46409
|
-
channel = await createClientChannel(
|
|
46410
|
-
|
|
46411
|
-
|
|
46412
|
-
|
|
46413
|
-
|
|
46414
|
-
|
|
46996
|
+
channel = await createClientChannel(
|
|
46997
|
+
relayTransport,
|
|
46998
|
+
daemonPublicKeyB64,
|
|
46999
|
+
{
|
|
47000
|
+
onopen: emitOpen,
|
|
47001
|
+
onmessage: (data) => emitMessage(data),
|
|
47002
|
+
onclose: (code, reason) => emitClose({ code, reason }),
|
|
47003
|
+
onerror: (error) => emitError(error)
|
|
47004
|
+
},
|
|
47005
|
+
staticKeyPair
|
|
47006
|
+
);
|
|
46415
47007
|
} catch (error) {
|
|
46416
47008
|
logger.warn({ err: normalizeTransportError(error) }, "relay_e2ee_handshake_failed");
|
|
46417
47009
|
emitError(error);
|
|
@@ -46774,7 +47366,8 @@ var DaemonClient = class {
|
|
|
46774
47366
|
transportFactory = createRelayE2eeTransportFactory({
|
|
46775
47367
|
baseFactory: baseTransportFactory,
|
|
46776
47368
|
daemonPublicKeyB64,
|
|
46777
|
-
logger: this.logger
|
|
47369
|
+
logger: this.logger,
|
|
47370
|
+
staticKeyPair: this.config.e2ee?.staticKeyPair
|
|
46778
47371
|
});
|
|
46779
47372
|
}
|
|
46780
47373
|
const transportUrl = this.resolveTransportUrlForAttempt();
|
|
@@ -47405,12 +47998,12 @@ var DaemonClient = class {
|
|
|
47405
47998
|
timeout: 1e4
|
|
47406
47999
|
});
|
|
47407
48000
|
}
|
|
47408
|
-
async openInEditor(
|
|
48001
|
+
async openInEditor(path29, editorId, requestId) {
|
|
47409
48002
|
return this.sendCorrelatedSessionRequest({
|
|
47410
48003
|
requestId,
|
|
47411
48004
|
message: {
|
|
47412
48005
|
type: "open_in_editor_request",
|
|
47413
|
-
path:
|
|
48006
|
+
path: path29,
|
|
47414
48007
|
editorId
|
|
47415
48008
|
},
|
|
47416
48009
|
responseType: "open_in_editor_response",
|
|
@@ -47848,6 +48441,99 @@ var DaemonClient = class {
|
|
|
47848
48441
|
throw new Error(payload.error || "Failed to delete session upload");
|
|
47849
48442
|
}
|
|
47850
48443
|
}
|
|
48444
|
+
// ──────────────────────────────────────────────────────────────────────
|
|
48445
|
+
// Phase 4 agent sharing — owner-only mutations of the per-agent ACL.
|
|
48446
|
+
// ──────────────────────────────────────────────────────────────────────
|
|
48447
|
+
/**
|
|
48448
|
+
* Grant a user access to this agent. Owner-only. Idempotent — sharing
|
|
48449
|
+
* with a user already on the ACL is a no-op. The recipient does not
|
|
48450
|
+
* need to be currently paired; access takes effect at their next
|
|
48451
|
+
* connection.
|
|
48452
|
+
*/
|
|
48453
|
+
async shareAgentWithUser(agentId, userId) {
|
|
48454
|
+
const requestId = this.createRequestId();
|
|
48455
|
+
const message = SessionInboundMessageSchema.parse({
|
|
48456
|
+
type: "share_agent_with_user_request",
|
|
48457
|
+
requestId,
|
|
48458
|
+
agentId,
|
|
48459
|
+
userId
|
|
48460
|
+
});
|
|
48461
|
+
const payload = await this.sendRequest({
|
|
48462
|
+
requestId,
|
|
48463
|
+
message,
|
|
48464
|
+
timeout: 15e3,
|
|
48465
|
+
options: { skipQueue: true },
|
|
48466
|
+
select: (msg) => {
|
|
48467
|
+
if (msg.type !== "share_agent_with_user_response") return null;
|
|
48468
|
+
if (msg.payload.requestId !== requestId) return null;
|
|
48469
|
+
return msg.payload;
|
|
48470
|
+
}
|
|
48471
|
+
});
|
|
48472
|
+
if (!payload.ok) {
|
|
48473
|
+
throw new Error(payload.error || "Failed to share agent");
|
|
48474
|
+
}
|
|
48475
|
+
return payload.sharedWithUserIds;
|
|
48476
|
+
}
|
|
48477
|
+
/**
|
|
48478
|
+
* Revoke a user's access to this agent. Owner-only. Effects are
|
|
48479
|
+
* immediate — once the auth-server allow-list propagates (and the
|
|
48480
|
+
* daemon's in-memory state updates here), the removed user's resolver
|
|
48481
|
+
* answers "Agent not found" for any further per-agent RPC.
|
|
48482
|
+
*/
|
|
48483
|
+
async unshareAgentWithUser(agentId, userId) {
|
|
48484
|
+
const requestId = this.createRequestId();
|
|
48485
|
+
const message = SessionInboundMessageSchema.parse({
|
|
48486
|
+
type: "unshare_agent_with_user_request",
|
|
48487
|
+
requestId,
|
|
48488
|
+
agentId,
|
|
48489
|
+
userId
|
|
48490
|
+
});
|
|
48491
|
+
const payload = await this.sendRequest({
|
|
48492
|
+
requestId,
|
|
48493
|
+
message,
|
|
48494
|
+
timeout: 15e3,
|
|
48495
|
+
options: { skipQueue: true },
|
|
48496
|
+
select: (msg) => {
|
|
48497
|
+
if (msg.type !== "unshare_agent_with_user_response") return null;
|
|
48498
|
+
if (msg.payload.requestId !== requestId) return null;
|
|
48499
|
+
return msg.payload;
|
|
48500
|
+
}
|
|
48501
|
+
});
|
|
48502
|
+
if (!payload.ok) {
|
|
48503
|
+
throw new Error(payload.error || "Failed to unshare agent");
|
|
48504
|
+
}
|
|
48505
|
+
return payload.sharedWithUserIds;
|
|
48506
|
+
}
|
|
48507
|
+
/**
|
|
48508
|
+
* Return the ACL — owner + the user-ids the owner has granted access
|
|
48509
|
+
* to. Owner-only: recipients can't enumerate who else has access.
|
|
48510
|
+
*/
|
|
48511
|
+
async listAgentSharedUsers(agentId) {
|
|
48512
|
+
const requestId = this.createRequestId();
|
|
48513
|
+
const message = SessionInboundMessageSchema.parse({
|
|
48514
|
+
type: "list_agent_shared_users_request",
|
|
48515
|
+
requestId,
|
|
48516
|
+
agentId
|
|
48517
|
+
});
|
|
48518
|
+
const payload = await this.sendRequest({
|
|
48519
|
+
requestId,
|
|
48520
|
+
message,
|
|
48521
|
+
timeout: 15e3,
|
|
48522
|
+
options: { skipQueue: true },
|
|
48523
|
+
select: (msg) => {
|
|
48524
|
+
if (msg.type !== "list_agent_shared_users_response") return null;
|
|
48525
|
+
if (msg.payload.requestId !== requestId) return null;
|
|
48526
|
+
return msg.payload;
|
|
48527
|
+
}
|
|
48528
|
+
});
|
|
48529
|
+
if (!payload.ok) {
|
|
48530
|
+
throw new Error(payload.error || "Failed to list agent shared users");
|
|
48531
|
+
}
|
|
48532
|
+
return {
|
|
48533
|
+
ownerUserId: payload.ownerUserId,
|
|
48534
|
+
sharedWithUserIds: payload.sharedWithUserIds
|
|
48535
|
+
};
|
|
48536
|
+
}
|
|
47851
48537
|
/**
|
|
47852
48538
|
* List the images the user has attached to this agent's chat (the "Images"
|
|
47853
48539
|
* tab in the uploads modal). Returns newest first; the daemon scans
|
|
@@ -48896,13 +49582,13 @@ var DaemonClient = class {
|
|
|
48896
49582
|
// ============================================================================
|
|
48897
49583
|
// File Explorer
|
|
48898
49584
|
// ============================================================================
|
|
48899
|
-
async exploreFileSystem(cwd,
|
|
49585
|
+
async exploreFileSystem(cwd, path29, mode = "list", requestId) {
|
|
48900
49586
|
return this.sendCorrelatedSessionRequest({
|
|
48901
49587
|
requestId,
|
|
48902
49588
|
message: {
|
|
48903
49589
|
type: "file_explorer_request",
|
|
48904
49590
|
cwd,
|
|
48905
|
-
path:
|
|
49591
|
+
path: path29,
|
|
48906
49592
|
mode
|
|
48907
49593
|
},
|
|
48908
49594
|
responseType: "file_explorer_response",
|
|
@@ -48914,13 +49600,13 @@ var DaemonClient = class {
|
|
|
48914
49600
|
* allowlists extensions (currently `.md` only) — callers don't need to
|
|
48915
49601
|
* re-check. Used by the plan-todos UI to rewrite plan-file frontmatter.
|
|
48916
49602
|
*/
|
|
48917
|
-
async writeFile(cwd,
|
|
49603
|
+
async writeFile(cwd, path29, content, requestId) {
|
|
48918
49604
|
return this.sendCorrelatedSessionRequest({
|
|
48919
49605
|
requestId,
|
|
48920
49606
|
message: {
|
|
48921
49607
|
type: "file_write_request",
|
|
48922
49608
|
cwd,
|
|
48923
|
-
path:
|
|
49609
|
+
path: path29,
|
|
48924
49610
|
content
|
|
48925
49611
|
},
|
|
48926
49612
|
responseType: "file_write_response",
|
|
@@ -48933,42 +49619,42 @@ var DaemonClient = class {
|
|
|
48933
49619
|
* action is the only consumer). Returns the daemon's structured response
|
|
48934
49620
|
* so callers can surface the error in the UI.
|
|
48935
49621
|
*/
|
|
48936
|
-
async deleteFile(cwd,
|
|
49622
|
+
async deleteFile(cwd, path29, requestId) {
|
|
48937
49623
|
return this.sendCorrelatedSessionRequest({
|
|
48938
49624
|
requestId,
|
|
48939
49625
|
message: {
|
|
48940
49626
|
type: "file_delete_request",
|
|
48941
49627
|
cwd,
|
|
48942
|
-
path:
|
|
49628
|
+
path: path29
|
|
48943
49629
|
},
|
|
48944
49630
|
responseType: "file_delete_response",
|
|
48945
49631
|
timeout: 1e4
|
|
48946
49632
|
});
|
|
48947
49633
|
}
|
|
48948
|
-
async requestDownloadToken(cwd,
|
|
49634
|
+
async requestDownloadToken(cwd, path29, requestId) {
|
|
48949
49635
|
return this.sendCorrelatedSessionRequest({
|
|
48950
49636
|
requestId,
|
|
48951
49637
|
message: {
|
|
48952
49638
|
type: "file_download_token_request",
|
|
48953
49639
|
cwd,
|
|
48954
|
-
path:
|
|
49640
|
+
path: path29
|
|
48955
49641
|
},
|
|
48956
49642
|
responseType: "file_download_token_response",
|
|
48957
49643
|
timeout: 1e4
|
|
48958
49644
|
});
|
|
48959
49645
|
}
|
|
48960
|
-
async explorerDeleteEntry(cwd,
|
|
49646
|
+
async explorerDeleteEntry(cwd, path29, requestId) {
|
|
48961
49647
|
return this.sendCorrelatedSessionRequest({
|
|
48962
49648
|
requestId,
|
|
48963
|
-
message: { type: "file_explorer_delete_request", cwd, path:
|
|
49649
|
+
message: { type: "file_explorer_delete_request", cwd, path: path29 },
|
|
48964
49650
|
responseType: "file_explorer_delete_response",
|
|
48965
49651
|
timeout: 1e4
|
|
48966
49652
|
});
|
|
48967
49653
|
}
|
|
48968
|
-
async explorerMkdir(cwd,
|
|
49654
|
+
async explorerMkdir(cwd, path29, requestId) {
|
|
48969
49655
|
return this.sendCorrelatedSessionRequest({
|
|
48970
49656
|
requestId,
|
|
48971
|
-
message: { type: "file_mkdir_request", cwd, path:
|
|
49657
|
+
message: { type: "file_mkdir_request", cwd, path: path29 },
|
|
48972
49658
|
responseType: "file_mkdir_response",
|
|
48973
49659
|
timeout: 1e4
|
|
48974
49660
|
});
|
|
@@ -49998,7 +50684,9 @@ var DaemonClient = class {
|
|
|
49998
50684
|
clientId: this.config.clientId,
|
|
49999
50685
|
clientType: this.config.clientType ?? "cli",
|
|
50000
50686
|
protocolVersion: 1,
|
|
50001
|
-
...this.config.appVersion ? { appVersion: this.config.appVersion } : {}
|
|
50687
|
+
...this.config.appVersion ? { appVersion: this.config.appVersion } : {},
|
|
50688
|
+
...this.config.userId ? { userId: this.config.userId } : {},
|
|
50689
|
+
...this.config.username ? { username: this.config.username } : {}
|
|
50002
50690
|
})
|
|
50003
50691
|
);
|
|
50004
50692
|
} catch (error) {
|
|
@@ -50394,7 +51082,7 @@ function resolveAgentConfig(options) {
|
|
|
50394
51082
|
}
|
|
50395
51083
|
|
|
50396
51084
|
// ../cli/src/utils/client.ts
|
|
50397
|
-
import
|
|
51085
|
+
import path23 from "node:path";
|
|
50398
51086
|
import WebSocket3 from "ws";
|
|
50399
51087
|
|
|
50400
51088
|
// ../cli/src/utils/client-id.ts
|
|
@@ -50470,8 +51158,8 @@ function isTcpDaemonHost(host) {
|
|
|
50470
51158
|
return host !== null && !isIpcDaemonHost(host);
|
|
50471
51159
|
}
|
|
50472
51160
|
function readPidSocketTarget(appostleHome) {
|
|
50473
|
-
const pidPath =
|
|
50474
|
-
if (!
|
|
51161
|
+
const pidPath = path23.join(appostleHome, PID_FILENAME);
|
|
51162
|
+
if (!existsSync12(pidPath)) {
|
|
50475
51163
|
return null;
|
|
50476
51164
|
}
|
|
50477
51165
|
try {
|
|
@@ -50939,12 +51627,12 @@ function relativeTime(date) {
|
|
|
50939
51627
|
if (seconds < 86400) return `${Math.floor(seconds / 3600)} hours ago`;
|
|
50940
51628
|
return `${Math.floor(seconds / 86400)} days ago`;
|
|
50941
51629
|
}
|
|
50942
|
-
function shortenPath(
|
|
51630
|
+
function shortenPath(path29) {
|
|
50943
51631
|
const home = process.env.HOME;
|
|
50944
|
-
if (home &&
|
|
50945
|
-
return "~" +
|
|
51632
|
+
if (home && path29.startsWith(home)) {
|
|
51633
|
+
return "~" + path29.slice(home.length);
|
|
50946
51634
|
}
|
|
50947
|
-
return
|
|
51635
|
+
return path29;
|
|
50948
51636
|
}
|
|
50949
51637
|
function normalizeModelId(modelId) {
|
|
50950
51638
|
if (typeof modelId !== "string") return null;
|
|
@@ -51801,10 +52489,10 @@ function addSendOptions(cmd) {
|
|
|
51801
52489
|
}
|
|
51802
52490
|
async function readImageFiles(imagePaths) {
|
|
51803
52491
|
const images = [];
|
|
51804
|
-
for (const
|
|
52492
|
+
for (const path29 of imagePaths) {
|
|
51805
52493
|
try {
|
|
51806
|
-
const buffer = await readFile5(
|
|
51807
|
-
const ext = extname5(
|
|
52494
|
+
const buffer = await readFile5(path29);
|
|
52495
|
+
const ext = extname5(path29).toLowerCase();
|
|
51808
52496
|
let mimeType = "image/jpeg";
|
|
51809
52497
|
switch (ext) {
|
|
51810
52498
|
case ".png":
|
|
@@ -51832,7 +52520,7 @@ async function readImageFiles(imagePaths) {
|
|
|
51832
52520
|
const message = err instanceof Error ? err.message : String(err);
|
|
51833
52521
|
const error = {
|
|
51834
52522
|
code: "IMAGE_READ_ERROR",
|
|
51835
|
-
message: `Failed to read image file: ${
|
|
52523
|
+
message: `Failed to read image file: ${path29}`,
|
|
51836
52524
|
details: message
|
|
51837
52525
|
};
|
|
51838
52526
|
throw error;
|
|
@@ -52005,12 +52693,12 @@ function createInspectSchema(agent) {
|
|
|
52005
52693
|
serialize: (_item) => agent
|
|
52006
52694
|
};
|
|
52007
52695
|
}
|
|
52008
|
-
function shortenPath2(
|
|
52696
|
+
function shortenPath2(path29) {
|
|
52009
52697
|
const home = process.env.HOME;
|
|
52010
|
-
if (home &&
|
|
52011
|
-
return "~" +
|
|
52698
|
+
if (home && path29.startsWith(home)) {
|
|
52699
|
+
return "~" + path29.slice(home.length);
|
|
52012
52700
|
}
|
|
52013
|
-
return
|
|
52701
|
+
return path29;
|
|
52014
52702
|
}
|
|
52015
52703
|
function formatCost(costUsd) {
|
|
52016
52704
|
if (costUsd === 0) return "$0.00";
|
|
@@ -52976,9 +53664,9 @@ import chalk3 from "chalk";
|
|
|
52976
53664
|
|
|
52977
53665
|
// ../cli/src/commands/daemon/local-daemon.ts
|
|
52978
53666
|
import { spawn as spawn7, spawnSync } from "node:child_process";
|
|
52979
|
-
import { existsSync as
|
|
53667
|
+
import { existsSync as existsSync13, readFileSync as readFileSync9 } from "node:fs";
|
|
52980
53668
|
import { createRequire as createRequire3 } from "node:module";
|
|
52981
|
-
import
|
|
53669
|
+
import path24 from "node:path";
|
|
52982
53670
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
52983
53671
|
var DETACHED_STARTUP_GRACE_MS = 1200;
|
|
52984
53672
|
var PID_POLL_INTERVAL_MS = 100;
|
|
@@ -53029,8 +53717,8 @@ function buildChildEnv(options) {
|
|
|
53029
53717
|
function resolveDaemonRunnerEntry() {
|
|
53030
53718
|
try {
|
|
53031
53719
|
const here = fileURLToPath3(import.meta.url);
|
|
53032
|
-
const sibling =
|
|
53033
|
-
if (
|
|
53720
|
+
const sibling = path24.join(path24.dirname(here), "supervisor-entrypoint.js");
|
|
53721
|
+
if (existsSync13(sibling)) {
|
|
53034
53722
|
return sibling;
|
|
53035
53723
|
}
|
|
53036
53724
|
} catch {
|
|
@@ -53043,23 +53731,23 @@ function resolveDaemonRunnerEntry() {
|
|
|
53043
53731
|
"Unable to resolve @appostle/server package root for daemon runner (and no sibling supervisor-entrypoint.js was bundled)"
|
|
53044
53732
|
);
|
|
53045
53733
|
}
|
|
53046
|
-
let currentDir =
|
|
53734
|
+
let currentDir = path24.dirname(serverExportPath);
|
|
53047
53735
|
while (true) {
|
|
53048
|
-
const packageJsonPath =
|
|
53049
|
-
if (
|
|
53736
|
+
const packageJsonPath = path24.join(currentDir, "package.json");
|
|
53737
|
+
if (existsSync13(packageJsonPath)) {
|
|
53050
53738
|
try {
|
|
53051
53739
|
const packageJson = JSON.parse(readFileSync9(packageJsonPath, "utf-8"));
|
|
53052
53740
|
if (packageJson.name === "@appostle/server") {
|
|
53053
|
-
const distRunner =
|
|
53054
|
-
if (
|
|
53741
|
+
const distRunner = path24.join(currentDir, "dist", "scripts", "supervisor-entrypoint.js");
|
|
53742
|
+
if (existsSync13(distRunner)) {
|
|
53055
53743
|
return distRunner;
|
|
53056
53744
|
}
|
|
53057
|
-
return
|
|
53745
|
+
return path24.join(currentDir, "scripts", "supervisor-entrypoint.ts");
|
|
53058
53746
|
}
|
|
53059
53747
|
} catch {
|
|
53060
53748
|
}
|
|
53061
53749
|
}
|
|
53062
|
-
const parentDir =
|
|
53750
|
+
const parentDir = path24.dirname(currentDir);
|
|
53063
53751
|
if (parentDir === currentDir) {
|
|
53064
53752
|
break;
|
|
53065
53753
|
}
|
|
@@ -53068,7 +53756,7 @@ function resolveDaemonRunnerEntry() {
|
|
|
53068
53756
|
throw new Error("Unable to resolve @appostle/server package root for daemon runner");
|
|
53069
53757
|
}
|
|
53070
53758
|
function pidFilePath(appostleHome) {
|
|
53071
|
-
return
|
|
53759
|
+
return path24.join(appostleHome, DAEMON_PID_FILENAME);
|
|
53072
53760
|
}
|
|
53073
53761
|
function readPidFile(pidPath) {
|
|
53074
53762
|
try {
|
|
@@ -53210,8 +53898,8 @@ function resolveLocalDaemonState(options = {}) {
|
|
|
53210
53898
|
const home = resolveAppostleHome(env);
|
|
53211
53899
|
const config = loadConfig(home, { env });
|
|
53212
53900
|
const pidPath = pidFilePath(home);
|
|
53213
|
-
const logPath =
|
|
53214
|
-
const pidInfo =
|
|
53901
|
+
const logPath = path24.join(home, DAEMON_LOG_FILENAME);
|
|
53902
|
+
const pidInfo = existsSync13(pidPath) ? readPidFile(pidPath) : null;
|
|
53215
53903
|
const running = pidInfo ? isProcessRunning(pidInfo.pid) : false;
|
|
53216
53904
|
const listen = pidInfo?.listen ?? config.listen;
|
|
53217
53905
|
return {
|
|
@@ -53225,7 +53913,7 @@ function resolveLocalDaemonState(options = {}) {
|
|
|
53225
53913
|
};
|
|
53226
53914
|
}
|
|
53227
53915
|
function tailDaemonLog(home, lines = 30) {
|
|
53228
|
-
const logPath =
|
|
53916
|
+
const logPath = path24.join(resolveLocalAppostleHome(home), DAEMON_LOG_FILENAME);
|
|
53229
53917
|
return tailFile(logPath, lines);
|
|
53230
53918
|
}
|
|
53231
53919
|
async function startLocalDaemonDetached(options) {
|
|
@@ -53234,7 +53922,7 @@ async function startLocalDaemonDetached(options) {
|
|
|
53234
53922
|
}
|
|
53235
53923
|
const childEnv = buildChildEnv(options);
|
|
53236
53924
|
const appostleHome = resolveAppostleHome(childEnv);
|
|
53237
|
-
const logPath =
|
|
53925
|
+
const logPath = path24.join(appostleHome, DAEMON_LOG_FILENAME);
|
|
53238
53926
|
const daemonRunnerEntry = resolveDaemonRunnerEntry();
|
|
53239
53927
|
const child = spawn7(
|
|
53240
53928
|
process.execPath,
|
|
@@ -55960,15 +56648,15 @@ import { Command as Command13 } from "commander";
|
|
|
55960
56648
|
// ../cli/src/commands/worktree/ls.ts
|
|
55961
56649
|
import { homedir as homedir7 } from "node:os";
|
|
55962
56650
|
import { basename as basename7, join as join16, sep as sep3 } from "node:path";
|
|
55963
|
-
function shortenPath3(
|
|
56651
|
+
function shortenPath3(path29) {
|
|
55964
56652
|
const home = process.env.HOME;
|
|
55965
|
-
if (home &&
|
|
55966
|
-
return "~" +
|
|
56653
|
+
if (home && path29.startsWith(home)) {
|
|
56654
|
+
return "~" + path29.slice(home.length);
|
|
55967
56655
|
}
|
|
55968
|
-
return
|
|
56656
|
+
return path29;
|
|
55969
56657
|
}
|
|
55970
|
-
function extractWorktreeName(
|
|
55971
|
-
return basename7(
|
|
56658
|
+
function extractWorktreeName(path29) {
|
|
56659
|
+
return basename7(path29);
|
|
55972
56660
|
}
|
|
55973
56661
|
function resolveAppostleHomePath() {
|
|
55974
56662
|
return process.env.APPOSTLE_HOME ?? join16(homedir7(), ".appostle");
|
|
@@ -56048,7 +56736,7 @@ async function runLsCommand7(options, _command) {
|
|
|
56048
56736
|
}
|
|
56049
56737
|
|
|
56050
56738
|
// ../cli/src/commands/worktree/archive.ts
|
|
56051
|
-
import
|
|
56739
|
+
import path25 from "path";
|
|
56052
56740
|
var archiveSchema2 = {
|
|
56053
56741
|
idField: "name",
|
|
56054
56742
|
columns: [
|
|
@@ -56092,7 +56780,7 @@ async function runArchiveCommand2(nameArg, options, _command) {
|
|
|
56092
56780
|
throw error;
|
|
56093
56781
|
}
|
|
56094
56782
|
const worktree = listResponse.worktrees.find((wt) => {
|
|
56095
|
-
const name =
|
|
56783
|
+
const name = path25.basename(wt.worktreePath);
|
|
56096
56784
|
return name === nameArg || wt.branchName === nameArg;
|
|
56097
56785
|
});
|
|
56098
56786
|
if (!worktree) {
|
|
@@ -56114,7 +56802,7 @@ async function runArchiveCommand2(nameArg, options, _command) {
|
|
|
56114
56802
|
};
|
|
56115
56803
|
throw error;
|
|
56116
56804
|
}
|
|
56117
|
-
const worktreeName =
|
|
56805
|
+
const worktreeName = path25.basename(worktree.worktreePath) || nameArg;
|
|
56118
56806
|
return {
|
|
56119
56807
|
type: "single",
|
|
56120
56808
|
data: {
|
|
@@ -56155,7 +56843,7 @@ function createWorktreeCommand() {
|
|
|
56155
56843
|
import { cancel, confirm, intro, isCancel, log, note, outro, spinner } from "@clack/prompts";
|
|
56156
56844
|
import { Command as Command14, Option as Option4 } from "commander";
|
|
56157
56845
|
import { writeFileSync as writeFileSync5 } from "node:fs";
|
|
56158
|
-
import
|
|
56846
|
+
import path26 from "node:path";
|
|
56159
56847
|
var DEFAULT_READY_TIMEOUT_MS = 10 * 60 * 1e3;
|
|
56160
56848
|
var OnboardCancelledError = class extends Error {
|
|
56161
56849
|
};
|
|
@@ -56198,7 +56886,7 @@ function toCliOverrides(options) {
|
|
|
56198
56886
|
return cliOverrides;
|
|
56199
56887
|
}
|
|
56200
56888
|
function savePersistedConfig2(appostleHome, config) {
|
|
56201
|
-
const configPath =
|
|
56889
|
+
const configPath = path26.join(appostleHome, "config.json");
|
|
56202
56890
|
writeFileSync5(configPath, `${JSON.stringify(config, null, 2)}
|
|
56203
56891
|
`);
|
|
56204
56892
|
}
|
|
@@ -56319,7 +57007,7 @@ ${recentLogs}` : null
|
|
|
56319
57007
|
);
|
|
56320
57008
|
}
|
|
56321
57009
|
function printNextSteps(pairingUrl, appostleHome, richUi) {
|
|
56322
|
-
const daemonLogPath =
|
|
57010
|
+
const daemonLogPath = path26.join(appostleHome, "daemon.log");
|
|
56323
57011
|
const nextStepsLines = [
|
|
56324
57012
|
pairingUrl ? "1. Open Appostle and scan the QR code above, or paste the pairing link." : "1. Open Appostle and connect to your daemon.",
|
|
56325
57013
|
"2. Web app: https://appostle.app",
|
|
@@ -56571,21 +57259,21 @@ function createCli() {
|
|
|
56571
57259
|
}
|
|
56572
57260
|
|
|
56573
57261
|
// ../cli/src/classify.ts
|
|
56574
|
-
import { existsSync as
|
|
57262
|
+
import { existsSync as existsSync14, statSync as statSync3 } from "node:fs";
|
|
56575
57263
|
import { homedir as homedir8 } from "node:os";
|
|
56576
|
-
import
|
|
57264
|
+
import path27 from "node:path";
|
|
56577
57265
|
function expandUserPath2(inputPath) {
|
|
56578
57266
|
if (inputPath === "~") {
|
|
56579
57267
|
return homedir8();
|
|
56580
57268
|
}
|
|
56581
57269
|
if (inputPath.startsWith("~/")) {
|
|
56582
|
-
return
|
|
57270
|
+
return path27.join(homedir8(), inputPath.slice(2));
|
|
56583
57271
|
}
|
|
56584
57272
|
return inputPath;
|
|
56585
57273
|
}
|
|
56586
57274
|
function isExistingDirectory(input) {
|
|
56587
|
-
const resolvedPath =
|
|
56588
|
-
if (!
|
|
57275
|
+
const resolvedPath = path27.resolve(input.cwd, expandUserPath2(input.pathArg));
|
|
57276
|
+
if (!existsSync14(resolvedPath)) {
|
|
56589
57277
|
return false;
|
|
56590
57278
|
}
|
|
56591
57279
|
return statSync3(resolvedPath).isDirectory();
|
|
@@ -56604,25 +57292,25 @@ function classifyInvocation(input) {
|
|
|
56604
57292
|
if (isExistingDirectory({ pathArg: firstArg, cwd: input.cwd })) {
|
|
56605
57293
|
return {
|
|
56606
57294
|
kind: "open-project",
|
|
56607
|
-
resolvedPath:
|
|
57295
|
+
resolvedPath: path27.resolve(input.cwd, expandUserPath2(firstArg))
|
|
56608
57296
|
};
|
|
56609
57297
|
}
|
|
56610
57298
|
return { kind: "cli", argv: input.argv };
|
|
56611
57299
|
}
|
|
56612
57300
|
|
|
56613
57301
|
// ../cli/src/commands/open.ts
|
|
56614
|
-
import { existsSync as
|
|
57302
|
+
import { existsSync as existsSync15 } from "node:fs";
|
|
56615
57303
|
import { spawn as spawn8 } from "node:child_process";
|
|
56616
57304
|
import { homedir as homedir9 } from "node:os";
|
|
56617
|
-
import
|
|
57305
|
+
import path28 from "node:path";
|
|
56618
57306
|
function findDesktopApp() {
|
|
56619
57307
|
if (process.platform === "darwin") {
|
|
56620
57308
|
const candidates = [
|
|
56621
57309
|
"/Applications/Appostle.app",
|
|
56622
|
-
|
|
57310
|
+
path28.join(homedir9(), "Applications", "Appostle.app")
|
|
56623
57311
|
];
|
|
56624
57312
|
for (const candidate of candidates) {
|
|
56625
|
-
if (
|
|
57313
|
+
if (existsSync15(candidate)) {
|
|
56626
57314
|
return candidate;
|
|
56627
57315
|
}
|
|
56628
57316
|
}
|
|
@@ -56632,10 +57320,10 @@ function findDesktopApp() {
|
|
|
56632
57320
|
const candidates = [
|
|
56633
57321
|
"/usr/bin/Appostle",
|
|
56634
57322
|
"/opt/Appostle/Appostle",
|
|
56635
|
-
|
|
57323
|
+
path28.join(homedir9(), "Applications", "Appostle.AppImage")
|
|
56636
57324
|
];
|
|
56637
57325
|
for (const candidate of candidates) {
|
|
56638
|
-
if (
|
|
57326
|
+
if (existsSync15(candidate)) {
|
|
56639
57327
|
return candidate;
|
|
56640
57328
|
}
|
|
56641
57329
|
}
|
|
@@ -56646,8 +57334,8 @@ function findDesktopApp() {
|
|
|
56646
57334
|
if (!localAppData) {
|
|
56647
57335
|
return null;
|
|
56648
57336
|
}
|
|
56649
|
-
const candidate =
|
|
56650
|
-
return
|
|
57337
|
+
const candidate = path28.join(localAppData, "Programs", "Appostle", "Appostle.exe");
|
|
57338
|
+
return existsSync15(candidate) ? candidate : null;
|
|
56651
57339
|
}
|
|
56652
57340
|
return null;
|
|
56653
57341
|
}
|