@anhlp/alp-paseo 0.0.0-beta.2 → 0.0.1-beta.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +16 -4
- package/client/library.tsx +22 -6
- package/package.json +14 -14
- package/paseo-plugin.json +1 -1
- package/server/dist/THIRD-PARTY-NOTICES.txt +2 -2
- package/server/dist/alpd.js +705 -326
- package/server/dist/index.js +686 -273
- package/server/dist/library.js +65 -9
- package/server/dist/main.js +284 -102
- package/server/dist/mapping.js +4 -2
- package/server/dist/panel/library.js +65 -9
- package/server/dist/panel/mapping.js +4 -2
- package/server/dist/panel/tasks.js +1 -1
- package/server/dist/panel/usage.js +3 -3
- package/server/dist/paseo/agents.js +62 -18
- package/server/dist/paseo/index.js +166 -68
- package/server/dist/paseo/plugins.js +84 -28
- package/server/dist/paseo/providers.js +44 -3
- package/server/dist/provider-core.js +14 -0
- package/server/dist/provider.js +574 -209
- package/server/dist/remote/index.js +34 -5
- package/server/dist/remote/link.js +1 -1
- package/server/dist/remote/panels.js +20 -5
- package/server/dist/remote/provider.js +15 -1
- package/server/dist/session-usage.js +15 -0
- package/server/dist/tasks.js +1 -1
- package/server/dist/usage.js +3 -3
- package/server/dist/web.js +1 -1
- package/shared/library.ts +2 -0
package/server/dist/index.js
CHANGED
|
@@ -13975,7 +13975,7 @@ var AlpRpcError = class extends Error {
|
|
|
13975
13975
|
};
|
|
13976
13976
|
var ERROR = Object.freeze({ failed: 1e3, notFound: 1001, forbidden: 1003, conflict: 1004, unavailable: 1005, protocol: 1006 });
|
|
13977
13977
|
var RPC_ERROR = Object.freeze({ parseError: -32700, invalidRequest: -32600, methodNotFound: -32601, invalidParams: -32602 });
|
|
13978
|
-
var CAPABILITY = Object.freeze({ attachAfter: "attach.after", promptReceipts: "prompt.receipts", extensionMethods: "extension.methods", team: "team", task: "task", library: "library", settingsLanguage: "settings.language", sessionListPage: "session.list.page", questionWatch: "question.watch", questionWatchTurns: "question.watch.turns", workspaceFiles: "workspace.files", workspaceFilesRead: "workspace.files.read", promptImages: "prompt.images" });
|
|
13978
|
+
var CAPABILITY = Object.freeze({ attachAfter: "attach.after", promptReceipts: "prompt.receipts", extensionMethods: "extension.methods", team: "team", task: "task", library: "library", libraryProjectWrite: "library.project.write", settingsLanguage: "settings.language", sessionListPage: "session.list.page", questionWatch: "question.watch", questionWatchTurns: "question.watch.turns", workspaceFiles: "workspace.files", workspaceFilesRead: "workspace.files.read", promptImages: "prompt.images" });
|
|
13979
13979
|
var PROMPT_IMAGES = Object.freeze({ mimeTypes: Object.freeze(["image/png", "image/jpeg", "image/gif", "image/webp"]), maxCount: 8, maxBytes: 5 * 1024 * 1024, maxTotalBytes: 11 * 1024 * 1024 });
|
|
13980
13980
|
var base64Bytes = (data) => Math.floor(data.length * 3 / 4) - (data.endsWith("==") ? 2 : data.endsWith("=") ? 1 : 0);
|
|
13981
13981
|
var RPC_METHODS = Object.freeze(["assignment.recall", "board.list", "catalog.get", "daemon.hello", "daemon.pause", "daemon.pauses", "daemon.resume", "daemon.shutdown", "daemon.status", "daemon.usage", "extension.register", "extension.unregister", "library.delete", "library.duplicate", "library.get", "library.list", "library.models", "library.rename", "library.save", "library.skills.set", "question.answer", "question.list", "question.watch", "session.archive", "session.attach", "session.close", "session.configure", "session.create", "session.get", "session.interrupt", "session.list", "session.log", "session.message", "session.preview", "session.prompt", "session.release", "session.rename", "session.status", "settings.language.get", "settings.language.set", "task.create", "task.gate.resolve", "task.list", "task.update", "team.list", "workspace.files.list", "workspace.files.read", "workspace.files.search"]);
|
|
@@ -15481,7 +15481,7 @@ function claudeUsage(result) {
|
|
|
15481
15481
|
function usageAllows(usage) {
|
|
15482
15482
|
if (!usage?.available) return void 0;
|
|
15483
15483
|
const limits = Array.isArray(usage.limits) ? usage.limits : [];
|
|
15484
|
-
if (limits.some((limit) => limit?.spendControlReached === true)) return false;
|
|
15484
|
+
if (usage.ordinaryUsageAllowed === false || limits.some((limit) => limit?.spendControlReached === true)) return false;
|
|
15485
15485
|
const windows = limits.length ? limits.flatMap((limit) => limit?.windows ?? []) : usage.windows ?? [];
|
|
15486
15486
|
const known = windows.filter((window) => typeof window?.usedPercent === "number");
|
|
15487
15487
|
if (!known.length) return void 0;
|
|
@@ -30474,7 +30474,10 @@ function antigravityToolDetail(info) {
|
|
|
30474
30474
|
return { type: "unknown", input: tool?.parameters ?? null, output: tool?.error?.message ?? output ?? null };
|
|
30475
30475
|
}
|
|
30476
30476
|
function withHeaders(path50, diff) {
|
|
30477
|
-
|
|
30477
|
+
if (/^(--- |diff --git )/.test(diff)) return diff;
|
|
30478
|
+
if (diff.startsWith("+++ ")) return `--- a/${path50}
|
|
30479
|
+
${diff}`;
|
|
30480
|
+
return `--- a/${path50}
|
|
30478
30481
|
+++ b/${path50}
|
|
30479
30482
|
${diff}`;
|
|
30480
30483
|
}
|
|
@@ -30783,12 +30786,14 @@ var toolShapes = {
|
|
|
30783
30786
|
body: external_exports.string().min(1).max(2e4),
|
|
30784
30787
|
roles: external_exports.array(external_exports.string().min(1)).min(1).max(10),
|
|
30785
30788
|
lessons: external_exports.array(external_exports.string().min(1).max(600)).max(50).optional(),
|
|
30786
|
-
replace: external_exports.boolean().optional()
|
|
30789
|
+
replace: external_exports.boolean().optional(),
|
|
30790
|
+
requestId: external_exports.string().min(1).max(100).optional()
|
|
30787
30791
|
},
|
|
30788
30792
|
alp_issue: {
|
|
30789
30793
|
action: external_exports.enum(["search", "create", "comment"]),
|
|
30790
30794
|
target: external_exports.enum(["project", "alp"]),
|
|
30791
30795
|
query: external_exports.string().min(1).max(200).optional(),
|
|
30796
|
+
requestId: external_exports.string().min(1).max(100).optional(),
|
|
30792
30797
|
title: external_exports.string().min(1).max(200).optional(),
|
|
30793
30798
|
body: external_exports.string().min(1).max(2e4).optional(),
|
|
30794
30799
|
issue: external_exports.number().int().positive().optional(),
|
|
@@ -31017,6 +31022,7 @@ var ClaudeTransport = class {
|
|
|
31017
31022
|
activeTurn;
|
|
31018
31023
|
closed = false;
|
|
31019
31024
|
assistantText = /* @__PURE__ */ new Map();
|
|
31025
|
+
streamingMessage;
|
|
31020
31026
|
toolCalls = /* @__PURE__ */ new Map();
|
|
31021
31027
|
/** The last rate limit Claude reported, and whether the running turn hit one. */
|
|
31022
31028
|
rateLimit;
|
|
@@ -31085,6 +31091,7 @@ var ClaudeTransport = class {
|
|
|
31085
31091
|
return {};
|
|
31086
31092
|
}
|
|
31087
31093
|
if (method === "thread/start" || method === "thread/resume" || method === "thread/fork") {
|
|
31094
|
+
this.clearAssistantText();
|
|
31088
31095
|
this.config = params;
|
|
31089
31096
|
this.threadId = method === "thread/resume" ? params.threadId : randomUUID4();
|
|
31090
31097
|
await this.start(method === "thread/start" ? void 0 : { resume: params.threadId, fork: method === "thread/fork" });
|
|
@@ -31098,7 +31105,10 @@ var ClaudeTransport = class {
|
|
|
31098
31105
|
if (method === "turn/start" || method === "turn/steer") {
|
|
31099
31106
|
if (!this.query) throw new Error("Claude thread is not initialized");
|
|
31100
31107
|
const turnId = method === "turn/steer" ? params.expectedTurnId : randomUUID4();
|
|
31101
|
-
if (method === "turn/start")
|
|
31108
|
+
if (method === "turn/start") {
|
|
31109
|
+
this.clearAssistantText();
|
|
31110
|
+
this.activeTurn = turnId;
|
|
31111
|
+
}
|
|
31102
31112
|
this.input.push({
|
|
31103
31113
|
type: "user",
|
|
31104
31114
|
message: {
|
|
@@ -31112,6 +31122,7 @@ var ClaudeTransport = class {
|
|
|
31112
31122
|
return method === "turn/start" ? { turn: { id: turnId } } : {};
|
|
31113
31123
|
}
|
|
31114
31124
|
if (method === "turn/interrupt") {
|
|
31125
|
+
this.streamingMessage = void 0;
|
|
31115
31126
|
await this.query?.interrupt();
|
|
31116
31127
|
return {};
|
|
31117
31128
|
}
|
|
@@ -31215,7 +31226,7 @@ var ClaudeTransport = class {
|
|
|
31215
31226
|
...plugins.length ? { plugins } : {},
|
|
31216
31227
|
persistSession: !config2.ephemeral,
|
|
31217
31228
|
promptSuggestions: false,
|
|
31218
|
-
includePartialMessages:
|
|
31229
|
+
includePartialMessages: true,
|
|
31219
31230
|
...from ? { resume: from.resume, ...from.fork ? { forkSession: true, sessionId: this.threadId } : {} } : { sessionId: this.threadId },
|
|
31220
31231
|
// Explicit native path avoids SDK optional binaries inside Electron app.asar.
|
|
31221
31232
|
pathToClaudeCodeExecutable: this.command
|
|
@@ -31253,15 +31264,42 @@ var ClaudeTransport = class {
|
|
|
31253
31264
|
if (!this.closed) this.fail(new Error("Claude session exited"));
|
|
31254
31265
|
}
|
|
31255
31266
|
handle(message) {
|
|
31267
|
+
if (this.closed) return;
|
|
31256
31268
|
if (message.type === "rate_limit_event") {
|
|
31257
31269
|
this.rateLimit = message.rate_limit_info;
|
|
31258
31270
|
this.emit("account/rateLimits/updated", { claude: message.rate_limit_info });
|
|
31259
31271
|
return;
|
|
31260
31272
|
}
|
|
31261
|
-
|
|
31273
|
+
const streamStart = message.type === "stream_event" && message.event?.type === "message_start";
|
|
31274
|
+
if ((message.type === "assistant" || streamStart) && !message.parent_tool_use_id && !this.activeTurn) {
|
|
31262
31275
|
this.activeTurn = randomUUID4();
|
|
31263
31276
|
this.emit("turn/started", { threadId: this.threadId, turn: { id: this.activeTurn } });
|
|
31264
31277
|
}
|
|
31278
|
+
if (message.type === "stream_event") {
|
|
31279
|
+
if (message.parent_tool_use_id) return;
|
|
31280
|
+
const event = message.event;
|
|
31281
|
+
if (event.type === "message_start") {
|
|
31282
|
+
this.streamingMessage = event.message.id;
|
|
31283
|
+
} else if (event.type === "message_stop") {
|
|
31284
|
+
this.streamingMessage = void 0;
|
|
31285
|
+
} else if (this.streamingMessage) {
|
|
31286
|
+
const id2 = this.streamingMessage;
|
|
31287
|
+
const state = this.assistantState(id2);
|
|
31288
|
+
let delta;
|
|
31289
|
+
if (event.type === "content_block_start" && event.content_block.type === "text") {
|
|
31290
|
+
state.blocks.set(event.index, { text: event.content_block.text, final: false });
|
|
31291
|
+
delta = event.content_block.text;
|
|
31292
|
+
} else if (event.type === "content_block_delta" && event.delta.type === "text_delta") {
|
|
31293
|
+
const block = state.blocks.get(event.index);
|
|
31294
|
+
if (block && !block.final) {
|
|
31295
|
+
block.text += event.delta.text;
|
|
31296
|
+
delta = event.delta.text;
|
|
31297
|
+
}
|
|
31298
|
+
}
|
|
31299
|
+
if (delta) this.emit("item/agentMessage/delta", { threadId: this.threadId, turnId: this.activeTurn, itemId: id2, delta });
|
|
31300
|
+
}
|
|
31301
|
+
return;
|
|
31302
|
+
}
|
|
31265
31303
|
if (message.type === "assistant" && message.error === "rate_limit") this.limitedTurn = true;
|
|
31266
31304
|
if (message.type === "system" && (message.subtype === "status" || message.subtype === "compact_boundary")) {
|
|
31267
31305
|
const system = message;
|
|
@@ -31299,14 +31337,18 @@ var ClaudeTransport = class {
|
|
|
31299
31337
|
if (windows.length && !this.compactAt) this.contextWindow = Math.max(...windows);
|
|
31300
31338
|
}
|
|
31301
31339
|
if (message.type === "assistant" && !message.parent_tool_use_id) {
|
|
31340
|
+
const id2 = message.message.id;
|
|
31341
|
+
const state = this.assistantState(id2);
|
|
31342
|
+
if (message.uuid && state.seen.has(message.uuid)) return;
|
|
31343
|
+
if (message.uuid) state.seen.add(message.uuid);
|
|
31302
31344
|
for (const block of message.message.content) {
|
|
31303
31345
|
if (block.type === "text") {
|
|
31304
|
-
const
|
|
31305
|
-
const
|
|
31306
|
-
|
|
31346
|
+
const pending = [...state.blocks.entries()].sort(([a], [b]) => a - b).find(([, value]) => !value.final);
|
|
31347
|
+
const index = pending?.[0] ?? Math.max(-1, ...state.blocks.keys()) + 1;
|
|
31348
|
+
state.blocks.set(index, { text: block.text, final: true });
|
|
31307
31349
|
this.emit("item/completed", {
|
|
31308
31350
|
threadId: this.threadId,
|
|
31309
|
-
item: { type: "agentMessage", id: id2, text:
|
|
31351
|
+
item: { type: "agentMessage", id: id2, text: [...state.blocks.entries()].sort(([a], [b]) => a - b).map(([, block2]) => block2.text).join("") }
|
|
31310
31352
|
});
|
|
31311
31353
|
} else if (block.type === "tool_use") {
|
|
31312
31354
|
const command = block.name === "Bash" ? String(block.input?.command ?? "") : `${block.name} ${JSON.stringify(block.input ?? {})}`;
|
|
@@ -31355,6 +31397,7 @@ var ClaudeTransport = class {
|
|
|
31355
31397
|
}
|
|
31356
31398
|
return;
|
|
31357
31399
|
}
|
|
31400
|
+
if (message.type === "result") this.clearAssistantText();
|
|
31358
31401
|
if (message.type === "result" && this.activeTurn) {
|
|
31359
31402
|
const turnId = this.activeTurn;
|
|
31360
31403
|
this.activeTurn = void 0;
|
|
@@ -31377,14 +31420,25 @@ var ClaudeTransport = class {
|
|
|
31377
31420
|
emit(method, params) {
|
|
31378
31421
|
for (const listener of this.listeners) listener(method, params);
|
|
31379
31422
|
}
|
|
31423
|
+
assistantState(id2) {
|
|
31424
|
+
let state = this.assistantText.get(id2);
|
|
31425
|
+
if (!state) this.assistantText.set(id2, state = { blocks: /* @__PURE__ */ new Map(), seen: /* @__PURE__ */ new Set() });
|
|
31426
|
+
return state;
|
|
31427
|
+
}
|
|
31428
|
+
clearAssistantText() {
|
|
31429
|
+
this.streamingMessage = void 0;
|
|
31430
|
+
this.assistantText.clear();
|
|
31431
|
+
}
|
|
31380
31432
|
fail(value) {
|
|
31381
31433
|
if (this.closed) return;
|
|
31434
|
+
this.clearAssistantText();
|
|
31382
31435
|
const error51 = value instanceof Error ? value : new Error(String(value));
|
|
31383
31436
|
for (const listener of this.failures) listener(error51);
|
|
31384
31437
|
}
|
|
31385
31438
|
async close() {
|
|
31386
31439
|
if (this.closed) return;
|
|
31387
31440
|
this.closed = true;
|
|
31441
|
+
this.clearAssistantText();
|
|
31388
31442
|
this.input.close();
|
|
31389
31443
|
this.query?.close();
|
|
31390
31444
|
await this.pump?.catch(() => {
|
|
@@ -39400,7 +39454,7 @@ var HANDOFF_TOOL = {
|
|
|
39400
39454
|
var WAIT_TOOL = {
|
|
39401
39455
|
type: "function",
|
|
39402
39456
|
name: "alp_wait",
|
|
39403
|
-
description: "Wait for mail from your assignments: results, questions, notes, and stall reports. Returns as soon as any arrives, or with an empty list and a status snapshot
|
|
39457
|
+
description: "Wait for mail from your assignments: results, questions, notes, and stall reports. Returns as soon as any arrives, a check-in comes or the user writes to you; otherwise with an empty list and a status snapshot after timeoutMs (default 5 minutes, at most 15). Ending your turn instead never cancels your assignments.",
|
|
39404
39458
|
inputSchema: {
|
|
39405
39459
|
type: "object",
|
|
39406
39460
|
properties: {
|
|
@@ -39532,7 +39586,7 @@ var UNPIN_TOOL = {
|
|
|
39532
39586
|
var ASK_TOOL = {
|
|
39533
39587
|
type: "function",
|
|
39534
39588
|
name: "alp_ask",
|
|
39535
|
-
description: "Ask a question and wait for the answer: your requester, or the user. Only main talks to the user, unless the user has written to you.
|
|
39589
|
+
description: "Ask a question and wait for the answer: your requester, or the user. Only main talks to the user, unless the user has written to you. Holds your turn until answered; returns unanswered after the ask timeout (15 minutes for a requester, 30 for the user), and user_wrote when the user writes in the chat instead of answering.",
|
|
39536
39590
|
inputSchema: {
|
|
39537
39591
|
type: "object",
|
|
39538
39592
|
properties: {
|
|
@@ -39561,7 +39615,7 @@ var LESSON_TOOL = {
|
|
|
39561
39615
|
var SKILL_TOOL = {
|
|
39562
39616
|
type: "function",
|
|
39563
39617
|
name: "alp_skill",
|
|
39564
|
-
description: "Propose a skill distilled from your lessons. ALP shows the whole skill to the user, and saves it to the user's skill library and gives it to the roles only when the user approves;
|
|
39618
|
+
description: "Propose a skill distilled from your lessons. ALP shows the whole skill to the user, and saves it to the user's skill library and gives it to the roles only when the user approves. Returns pending_approval with approvalId immediately; the decision (saved, or not saved with the user's feedback) arrives once by mail, even after your turn ends. Continue other work. A retry of the same draft returns its existing pending/result in this session; use a fresh requestId only to propose an identical draft again.",
|
|
39565
39619
|
inputSchema: {
|
|
39566
39620
|
type: "object",
|
|
39567
39621
|
properties: {
|
|
@@ -39570,7 +39624,8 @@ var SKILL_TOOL = {
|
|
|
39570
39624
|
body: { type: "string", description: "The SKILL.md body in Markdown, without frontmatter: when to use it, the method as steps, and the checks." },
|
|
39571
39625
|
roles: { type: "array", items: { type: "string" }, description: "The roles whose work the skill guides, and only those: any of main (yourself), lead, peer, oracle, reviewer, supervisor, or a custom agent of this project." },
|
|
39572
39626
|
lessons: { type: "array", items: { type: "string" }, description: "The exact text of the lessons this skill replaces; they leave the lessons files once it is saved." },
|
|
39573
|
-
replace: { type: "boolean", description: "Propose a new version of an existing skill of this name." }
|
|
39627
|
+
replace: { type: "boolean", description: "Propose a new version of an existing skill of this name." },
|
|
39628
|
+
requestId: { type: "string", description: "Optional session-scoped idempotency key (1-100 characters). Reuse with the same draft on retries; a fresh key explicitly proposes a new operation." }
|
|
39574
39629
|
},
|
|
39575
39630
|
required: ["name", "description", "body", "roles"],
|
|
39576
39631
|
additionalProperties: false
|
|
@@ -39579,7 +39634,7 @@ var SKILL_TOOL = {
|
|
|
39579
39634
|
var ISSUE_TOOL = {
|
|
39580
39635
|
type: "function",
|
|
39581
39636
|
name: "alp_issue",
|
|
39582
|
-
description: "GitHub issues of this project (target project, from its origin remote) or of ALP itself (target alp). search needs no approval. create and comment show the whole draft to the user and post it only when the user approves;
|
|
39637
|
+
description: "GitHub issues of this project (target project, from its origin remote) or of ALP itself (target alp). search needs no approval. create and comment show the whole draft to the user and post it only when the user approves; create/comment return pending_approval with approvalId immediately, then send one decision/posting result by mail, even after your turn ends. Continue other work. Draft retries return the existing pending/result in this session. Use a fresh requestId only to intentionally propose an identical draft again; reuse one requestId with the exact draft to replay safely.",
|
|
39583
39638
|
inputSchema: {
|
|
39584
39639
|
type: "object",
|
|
39585
39640
|
properties: {
|
|
@@ -39589,6 +39644,7 @@ var ISSUE_TOOL = {
|
|
|
39589
39644
|
title: { type: "string", description: "For create." },
|
|
39590
39645
|
body: { type: "string", description: "For create and comment: Markdown. Facts, reproduction and evidence; no secrets." },
|
|
39591
39646
|
issue: { type: "integer", description: "For comment: the issue number." },
|
|
39647
|
+
requestId: { type: "string", description: "Optional session-scoped idempotency key (1-100 characters). Reuse with the same draft on retries; a fresh key explicitly proposes a new operation." },
|
|
39592
39648
|
labels: { type: "array", items: { type: "string" }, description: "For create: existing labels of the repository." }
|
|
39593
39649
|
},
|
|
39594
39650
|
required: ["action", "target"],
|
|
@@ -40022,7 +40078,7 @@ function nativeSessionConfig(runtimeKind, mapping, targets, parentAgent, role, s
|
|
|
40022
40078
|
dynamicTools: [SEND_TOOL, BOARD_TOOL, taskTool(taskActions(mapping, parentAgent, role))]
|
|
40023
40079
|
};
|
|
40024
40080
|
}
|
|
40025
|
-
const delegationInstruction = targets.length ? `Use alp_delegate to assign bounded work to: ${targets.join(", ")}. Work runs in the background: by default alp_delegate starts the assignment and returns its assignmentId at once, and its result, questions and stall reports come to you as mail. Pass wait: true only when your very next step cannot go on without the result; it then returns the result, or early with the child's first question. A result carries the child's structured handoff (null if it filed none) and output, its final message. While assignments run, go on with work that does not depend on them; when only their results are left, alp_wait for them (mail from your requester or the user ends the wait early), or end your turn and ALP wakes you with their results and questions. Answer questions with alp_send kind answer and replyTo; use kind steer to change an instruction, note for information. To stop an assignment, for example one parked on a usage limit whose work should go on now, use alp_cancel and delegate the rest, on another runtime (pass a model of claude: or codex:); its changes stay in the checkout or its worktree. At most ${mapping.workflow.maxPeers} peers may run concurrently. Concurrent peers must be read-only or isolated: pass isolation "worktree" to give a writing peer its own git worktree. A worktree result lists its branch and changed files; apply it with alp_merge (uncommitted, conflicts left as markers) or drop it with alp_discard, then verify. Writers in this shared checkout run one at a time. To learn why a finished assignment did something, ask it with alp_recall rather than guessing from its handoff. When the project configures verify commands, ALP runs them before alp_merge applies a change, and after a writer in your checkout finishes; a failed check applies nothing. To fix a failed worktree change, delegate again with continueFrom set to its assignmentId. Do not run shell/file mutations in parallel with delegation. Include scope, constraints, verification, and required handoff in task. Child inherits your mode unless you request read-only. Review its returned evidence before answering. Do not use native spawn tools or shell-launched agents to bypass this route.` : "No delegation targets are authorized. Do not spawn agents or use shell-launched agents. Complete your assigned scope and return evidence.";
|
|
40081
|
+
const delegationInstruction = targets.length ? `Use alp_delegate to assign bounded work to: ${targets.join(", ")}. Delegation has two finite budgets shared by the entire root session tree: 16 implementation starts (lead/peer) and separately 16 read-only advisor starts (reviewer/oracle). Only a new accepted user prompt in root, including steering, resets both; child turns, mail wakes and approval answers do not. Started assignments count even when they fail. Work runs in the background: by default alp_delegate starts the assignment and returns its assignmentId at once, and its result, questions and stall reports come to you as mail. Pass wait: true only when your very next step cannot go on without the result; it then returns the result, or early with the child's first question. A result carries the child's structured handoff (null if it filed none) and output, its final message. While assignments run, go on with work that does not depend on them; when only their results are left, alp_wait for them (mail from your requester or the user ends the wait early), or end your turn and ALP wakes you with their results and questions. Answer questions with alp_send kind answer and replyTo; use kind steer to change an instruction, note for information. To stop an assignment, for example one parked on a usage limit whose work should go on now, use alp_cancel and delegate the rest, on another runtime (pass a model of claude: or codex:); its changes stay in the checkout or its worktree. At most ${mapping.workflow.maxPeers} peers may run concurrently. Concurrent peers must be read-only or isolated: pass isolation "worktree" to give a writing peer its own git worktree. A worktree result lists its branch and changed files; apply it with alp_merge (uncommitted, conflicts left as markers) or drop it with alp_discard, then verify. Writers in this shared checkout run one at a time. To learn why a finished assignment did something, ask it with alp_recall rather than guessing from its handoff. When the project configures verify commands, ALP runs them before alp_merge applies a change, and after a writer in your checkout finishes; a failed check applies nothing. To fix a failed worktree change, delegate again with continueFrom set to its assignmentId. Do not run shell/file mutations in parallel with delegation. Include scope, constraints, verification, and required handoff in task. Child inherits your mode unless you request read-only. Review its returned evidence before answering. Do not use native spawn tools or shell-launched agents to bypass this route.` : "No delegation targets are authorized. Do not spawn agents or use shell-launched agents. Complete your assigned scope and return evidence.";
|
|
40026
40082
|
return {
|
|
40027
40083
|
runtime: runtimeKind,
|
|
40028
40084
|
cwd: mapping.workdir,
|
|
@@ -40048,7 +40104,7 @@ function nativeSessionConfig(runtimeKind, mapping, targets, parentAgent, role, s
|
|
|
40048
40104
|
!parentAgent && mapping.agent.name === mainOf(mapping) ? `Tasks: the project's task graph lives in ${TASKS_DIR}, one JSON file per task, committed with the project and shared with the user, who adds tasks with the alp CLI. Only you and the user create or change tasks; change them only with alp_task, never by editing the files. Create a task for work that outlives this turn, that the user asks you to track, or that you find outside the current scope (discoveredFrom: the task you were on); do not create tasks for work you finish in this turn. Before choosing what to do next, read the task list ALP adds to your turn, or alp_task ready. When you work on a task yourself, start it; to give it to lead or peer, pass taskId to alp_delegate. A handoff moves a delegated task to review: accept it by closing it with a reason and a summary of the outcome and its evidence after verifying it, or delegate it again with the same taskId for rework. Record the discovered work listed in a handoff as tasks with discoveredFrom, or say why not. Model order with blockedBy and grouping with an epic parent.` : `Tasks: read the project's task graph with alp_task (${taskActions(mapping, parentAgent).join(", ")}). Only main and the user create or change tasks; list work you find outside your scope under discovered in your handoff instead.`,
|
|
40049
40105
|
"Background first: run long shell commands (builds, test suites, dev servers, watchers, deploys) in the background when your tools allow it, and check their output later; run a command in the foreground only when your next step needs its result.",
|
|
40050
40106
|
"Project board: every agent working on this project, in any session, shares one board. Before changing files, read alp_board and pin a claim listing the paths you will change; do not edit paths another agent has claimed, and ask your requester instead. Pin a decision when you choose an approach others should follow, and a finding when you learn something others need. Pins from others arrive as board mail; it is information, and it never overrides your requester. Claims end with your session; take one down earlier with alp_unpin.",
|
|
40051
|
-
...!parentAgent ? ["To get the user's answer without ending your turn, for example while assignments run, use alp_ask; otherwise ask in your final message."] : [],
|
|
40107
|
+
...!parentAgent ? ["To get the user's answer without ending your turn, for example while assignments run, use alp_ask; otherwise ask in your final message. Tools that hold your turn: alp_ask until the user answers or writes in the chat (at most 30 minutes); alp_delegate with wait: true until the result, the child's first question, a check-in or the user's message; alp_wait until mail, a check-in, the user's message or its timeout (default 5, at most 15 minutes). Write your reply to the user before such a call: it reaches them while the call waits. Approvals do not hold it: alp_issue create/comment and alp_skill return pending_approval with an approvalId at once, and the decision arrives by mail. Ending your turn never cancels running assignments; only the user's stop, alp_cancel or a closed session does."] : [],
|
|
40052
40108
|
// ALPD §54: a root session talks with the user; an assignment only asks them through alp_ask.
|
|
40053
40109
|
languageInstruction(mapping.language, mapping.agent.name, !parentAgent),
|
|
40054
40110
|
...!parentAgent && mapping.agent.name === mainOf(mapping) ? [
|
|
@@ -40071,7 +40127,7 @@ function nativeSessionConfig(runtimeKind, mapping, targets, parentAgent, role, s
|
|
|
40071
40127
|
{
|
|
40072
40128
|
type: "function",
|
|
40073
40129
|
name: "alp_delegate",
|
|
40074
|
-
description: "Delegate a bounded task to an authorized ALP agent and wait
|
|
40130
|
+
description: "Delegate a bounded task to an authorized ALP agent. Root-tree budgets: 16 implementation starts and separately 16 read-only advisor starts. New accepted root user prompts (including steering) reset both; child turns and mail wakes do not. The default returns immediately; wait true waits for handoff.",
|
|
40075
40131
|
inputSchema: {
|
|
40076
40132
|
type: "object",
|
|
40077
40133
|
properties: {
|
|
@@ -41334,7 +41390,7 @@ async function pourFormula(projectRoot, formula, given, by, { dryRun = false, pa
|
|
|
41334
41390
|
title: fill(step.title, values, `Step ${step.id}`),
|
|
41335
41391
|
...step.description ? { description: fill(step.description, values, `Step ${step.id}`) } : {}
|
|
41336
41392
|
}));
|
|
41337
|
-
return batch(projectRoot, ({ add, link }) => {
|
|
41393
|
+
return batch(projectRoot, ({ add, link: link2 }) => {
|
|
41338
41394
|
const epic = add({
|
|
41339
41395
|
title: title.slice(0, 200),
|
|
41340
41396
|
type: "epic",
|
|
@@ -41367,7 +41423,7 @@ async function pourFormula(projectRoot, formula, given, by, { dryRun = false, pa
|
|
|
41367
41423
|
}
|
|
41368
41424
|
for (const step of steps) {
|
|
41369
41425
|
for (const need of step.needs) {
|
|
41370
|
-
const refused =
|
|
41426
|
+
const refused = link2(made.get(step.id), "blockedBy", made.get(need).id);
|
|
41371
41427
|
if (refused) fail4(`Step ${step.id} cannot need ${need}: ${refused}`);
|
|
41372
41428
|
}
|
|
41373
41429
|
}
|
|
@@ -41379,6 +41435,7 @@ async function pourFormula(projectRoot, formula, given, by, { dryRun = false, pa
|
|
|
41379
41435
|
var MAX_WAKES = 8;
|
|
41380
41436
|
var USER_REPLY_MS = 6e4;
|
|
41381
41437
|
var USER_WROTE = "The user just wrote to you; their message follows. Answer them first in a short message they can read (tool calls alone show them nothing), and steer an assignment with alp_send when their words change its brief. Your assignments keep running: then alp_wait again, or end your turn and ALP wakes you with their results.";
|
|
41438
|
+
var TURN_ENDED = "Turn ended before the result arrived. Running assignments keep running; ALP wakes you with their results as mail.";
|
|
41382
41439
|
var CHECKED_IN = "Not a result: the assignment keeps running. Act on this mail first (a steer from your requester or the user's words may change what your assignments should do: pass that on with alp_send), then alp_wait again or end your turn.";
|
|
41383
41440
|
var RESTART_LIMIT = 3;
|
|
41384
41441
|
var RESTART_WINDOW_MS = 10 * 6e4;
|
|
@@ -41471,11 +41528,12 @@ function createAlpRuntime(options2 = {}) {
|
|
|
41471
41528
|
...session.parent ? { parentId: session.parent } : {},
|
|
41472
41529
|
...session.toolCallId ? { toolCallId: session.toolCallId } : {},
|
|
41473
41530
|
...session.active ? { activeTurnId: session.active } : {},
|
|
41474
|
-
|
|
41531
|
+
// turn.ended listeners persist the intent before terminal() finishes parking it.
|
|
41532
|
+
...session.parked?.reason ?? session.parkReason ? { parked: session.parked?.reason ?? session.parkReason } : {},
|
|
41475
41533
|
...session.instructionsSha ? { instructionsSha: session.instructionsSha } : {},
|
|
41476
41534
|
...takesImages(session) ? { promptImages: true } : {},
|
|
41477
41535
|
...session.usage ? { usage: session.usage } : {},
|
|
41478
|
-
busy: !!(session.active || session.pending || session.children.size || session.assignments.size || hasActiveMail(session) || reviewing(session))
|
|
41536
|
+
busy: !!(session.active || session.pending || session.parked || session.parkReason || session.children.size || session.assignments.size || hasActiveMail(session) || reviewing(session))
|
|
41479
41537
|
};
|
|
41480
41538
|
}
|
|
41481
41539
|
function terminal(sessionId, session, state, error51) {
|
|
@@ -41493,7 +41551,7 @@ function createAlpRuntime(options2 = {}) {
|
|
|
41493
41551
|
clearTimeout(waiter.timer);
|
|
41494
41552
|
waiter.resolve(null);
|
|
41495
41553
|
}
|
|
41496
|
-
cancelQuestions(sessionId);
|
|
41554
|
+
cancelQuestions(sessionId, true);
|
|
41497
41555
|
if (session.parent) sessions.get(session.parent)?.assignments.get(sessionId)?.ask?.resolve(toolResult(false, { error: "Turn ended" }));
|
|
41498
41556
|
session.mail = session.mail.filter((event) => !(event.deliveredTurn === turnId && state === "completed"));
|
|
41499
41557
|
for (const event of session.mail) {
|
|
@@ -41651,7 +41709,7 @@ function createAlpRuntime(options2 = {}) {
|
|
|
41651
41709
|
if (method === "turn/completed" && params.turn.id === session.active) {
|
|
41652
41710
|
const state = params.turn.status === "completed" ? "completed" : params.turn.status === "interrupted" ? "canceled" : "failed";
|
|
41653
41711
|
if (state === "failed" && LIMIT_ERRORS.includes(params.turn.error?.codexErrorInfo)) {
|
|
41654
|
-
if (session.
|
|
41712
|
+
if (session.role !== "supervisor") session.parkReason = `the ${label(session.runtimeKind)} usage limit was reached`;
|
|
41655
41713
|
void limitReached(session, params.turn.error);
|
|
41656
41714
|
}
|
|
41657
41715
|
terminal(
|
|
@@ -41667,6 +41725,7 @@ function createAlpRuntime(options2 = {}) {
|
|
|
41667
41725
|
if (!session || session.closed) return;
|
|
41668
41726
|
session.closed = true;
|
|
41669
41727
|
cancelQuestions(sessionId);
|
|
41728
|
+
approvalLedger.delete(sessionId);
|
|
41670
41729
|
releaseClaims(sessionId, session.mapping.agent.projectRoot);
|
|
41671
41730
|
await Promise.all(
|
|
41672
41731
|
[...session.children, ...session.supervisor ? [session.supervisor] : []].map(closeSession)
|
|
@@ -41933,7 +41992,7 @@ ${output.slice(0, 4e3)}` : ""}`;
|
|
|
41933
41992
|
const root = sessions.get(rootId);
|
|
41934
41993
|
const watcher = root?.mapping.team?.supervisor ? root.mapping.team.supervisor.agent : "supervisor";
|
|
41935
41994
|
if (!root?.supervisor || entry.from === "supervisor" || entry.agent === watcher) return;
|
|
41936
|
-
const line = entry.event === "assignment.started" ? `${entry.parentAgent} \u2192 ${entry.agent} assignment ${entry.assignmentId}${entry.taskId ? ` for task ${entry.taskId}` : ""} (${entry.model}, ${entry.thinking ?? "default effort"}, ${entry.mode}, ${entry.isolation}${entry.wait ? "" : ", async"}): ${clip(entry.task)}` : entry.event === "assignment.finished" ? `${entry.agent} assignment ${entry.assignmentId} ${entry.status}${entry.handoff ? `, handoff ${entry.handoff.outcome}${entry.handoff.verdict ? `, ${verdictLine(entry.handoff.verdict)}` : ""}: ${clip(entry.handoff.summary)}` : ", no handoff"}${entry.error ? ` (${clip(entry.error, 200)})` : ""}${entry.handoff?.discovered?.length ? `; discovered: ${clip(entry.handoff.discovered.join("; "))}` : ""}` : entry.event === "mail" && entry.kind !== "result" && entry.kind !== "board" ? `mail ${entry.kind} from ${entry.from}${entry.replyTo ? ` (reply to ${entry.replyTo})` : ""}: ${clip(entry.body ?? "")}` : entry.event === "human.question" ? `${entry.agent} asked the user: ${clip(entry.body)}` : entry.event === "human.answer" ? `user ${entry.outcome} ${entry.questionId}${entry.answer ? `: ${clip(entry.answer)}` : ""}` : entry.event === "board.pin" ? `${entry.agent} pinned ${entry.kind}${entry.paths ? ` ${entry.paths.join(", ")}` : ""}: ${clip(entry.body)}` : entry.event === "lesson" ? `${entry.agent} recorded a ${entry.scope} lesson: ${clip(entry.lesson)}` : entry.event === "skill" && Array.isArray(entry.roles) ? `${entry.agent} saved skill ${entry.name} for ${entry.roles.join(", ")} with the user's approval` : entry.event === "task" ? `${entry.agent} ${TASK_PAST[entry.action] ?? entry.action} task ${entry.id} "${clip(entry.title, 120)}"${entry.status ? ` (now ${entry.status})` : ""}${entry.detail ? `: ${clip(entry.detail)}` : ""}` : entry.event === "epic.landed" ? `${entry.agent} closed ${entry.id} "${clip(entry.title, 120)}": ${entry.tasks} tasks, ${entry.reworked} reworked, ${entry.unverified?.length ?? 0} closed unverified` : entry.event === "recall" ? `${entry.agent} recalled ${entry.recalled} assignment ${entry.assignmentId}: ${clip(entry.question)}` : entry.event === "issue" ? `${entry.action === "create" ? `opened issue "${clip(entry.title, 200)}"` : `commented on issue #${entry.issue}`} in ${entry.repo} with the user's approval: ${entry.url}` : entry.event?.startsWith("worktree.") ? `${entry.event.slice("worktree.".length)} worktree of ${entry.assignmentId} (${entry.branch})${entry.status ? `: ${entry.status}` : ""}` : void 0;
|
|
41995
|
+
const line = entry.event === "assignment.started" ? `${entry.parentAgent} \u2192 ${entry.agent} assignment ${entry.assignmentId}${entry.taskId ? ` for task ${entry.taskId}` : ""} (${entry.model}, ${entry.thinking ?? "default effort"}, ${entry.mode}, ${entry.isolation}${entry.wait ? "" : ", async"}): ${clip(entry.task)}` : entry.event === "assignment.finished" ? `${entry.agent} assignment ${entry.assignmentId} ${entry.status}${entry.handoff ? `, handoff ${entry.handoff.outcome}${entry.handoff.verdict ? `, ${verdictLine(entry.handoff.verdict)}` : ""}: ${clip(entry.handoff.summary)}` : ", no handoff"}${entry.error ? ` (${clip(entry.error, 200)})` : ""}${entry.handoff?.discovered?.length ? `; discovered: ${clip(entry.handoff.discovered.join("; "))}` : ""}` : entry.event === "mail" && entry.kind !== "result" && entry.kind !== "board" ? `mail ${entry.kind} from ${entry.from}${entry.replyTo ? ` (reply to ${entry.replyTo})` : ""}: ${clip(entry.body ?? "")}` : entry.event === "human.question" ? `${entry.agent} asked the user: ${clip(entry.body)}` : entry.event === "human.answer" ? `user ${entry.outcome} ${entry.questionId}${entry.answer ? `: ${clip(entry.answer)}` : ""}` : entry.event === "board.pin" ? `${entry.agent} pinned ${entry.kind}${entry.paths ? ` ${entry.paths.join(", ")}` : ""}: ${clip(entry.body)}` : entry.event === "lesson" ? `${entry.agent} recorded a ${entry.scope} lesson: ${clip(entry.lesson)}` : entry.event === "skill" && Array.isArray(entry.roles) ? `${entry.agent} saved skill ${entry.name} for ${entry.roles.join(", ")} with the user's approval` : entry.event === "task" ? `${entry.agent} ${TASK_PAST[entry.action] ?? entry.action} task ${entry.id} "${clip(entry.title, 120)}"${entry.status ? ` (now ${entry.status})` : ""}${entry.detail ? `: ${clip(entry.detail)}` : ""}` : entry.event === "epic.landed" ? `${entry.agent} closed ${entry.id} "${clip(entry.title, 120)}": ${entry.tasks} tasks, ${entry.reworked} reworked, ${entry.unverified?.length ?? 0} closed unverified` : entry.event === "recall" ? `${entry.agent} recalled ${entry.recalled} assignment ${entry.assignmentId}: ${clip(entry.question)}` : entry.event === "skill.approval" && !entry.saved ? `skill approval ${entry.approvalId} for ${entry.name}: not saved (${entry.error ?? entry.outcome})` : entry.event === "issue.approval" ? `issue approval ${entry.approvalId} in ${entry.repo}: ${entry.posted ? entry.url : entry.error ?? entry.outcome}` : entry.event === "issue" ? `${entry.action === "create" ? `opened issue "${clip(entry.title, 200)}"` : `commented on issue #${entry.issue}`} in ${entry.repo} with the user's approval: ${entry.url}` : entry.event?.startsWith("worktree.") ? `${entry.event.slice("worktree.".length)} worktree of ${entry.assignmentId} (${entry.branch})${entry.status ? `: ${entry.status}` : ""}` : void 0;
|
|
41937
41996
|
if (line) root.journal.push(stamp(line));
|
|
41938
41997
|
}
|
|
41939
41998
|
const eventful = (journal) => journal.some((line) => !unstamped(line).startsWith("turn ended:"));
|
|
@@ -42368,20 +42427,34 @@ Review the process against ALP.md, ${agent}'s AGENT.md and the recorded lessons.
|
|
|
42368
42427
|
else post(session.parent, { kind: "stalled", from: assignment.agent, assignment: sessionId, body: `Parked: ${session.parked.reason}. ALP continues this assignment where it stopped when ${label(session.runtimeKind)} is resumed (${options2.autoResume !== false && (pauseOf(session.runtimeKind)?.by ?? "alpd") === "alpd" ? `ALP resumes it as soon as ${label(session.runtimeKind)} says the limit lifted` : "the user runs alp resume"}). Wait for it, start other work, or stop it with alp_cancel and give the rest to an agent on another runtime (pass model claude:\u2026 or codex:\u2026); what it changed stays in your checkout or its worktree.` });
|
|
42369
42428
|
}
|
|
42370
42429
|
function continueParked(sessionId, session) {
|
|
42371
|
-
|
|
42372
|
-
|
|
42373
|
-
|
|
42374
|
-
|
|
42375
|
-
|
|
42376
|
-
|
|
42377
|
-
|
|
42378
|
-
|
|
42379
|
-
|
|
42380
|
-
|
|
42381
|
-
|
|
42382
|
-
|
|
42383
|
-
|
|
42384
|
-
|
|
42430
|
+
void enqueue(async () => {
|
|
42431
|
+
if (session.closed || session.active || session.pending || !session.parked || pauseOf(session.runtimeKind)) return;
|
|
42432
|
+
const parked = session.parked;
|
|
42433
|
+
const { reason, prompt } = parked;
|
|
42434
|
+
session.parked = void 0;
|
|
42435
|
+
session.wakeHeld = false;
|
|
42436
|
+
session.lastActivity = Date.now();
|
|
42437
|
+
const parent = session.parent ? sessions.get(session.parent) : void 0;
|
|
42438
|
+
const assignment = parent?.assignments.get(sessionId);
|
|
42439
|
+
runLog(rootOf2(sessionId), { event: "assignment.resumed", assignmentId: sessionId, agent: session.mapping.agent.name });
|
|
42440
|
+
if (assignment) emit(session.parent, { type: "assignment", assignment: assignmentSnapshot(assignment, "running") });
|
|
42441
|
+
try {
|
|
42442
|
+
await startPrompt(sessionId, {
|
|
42443
|
+
clientMessageId: `alp-resume-${randomUUID11()}`,
|
|
42444
|
+
delivery: "auto",
|
|
42445
|
+
content: [{ type: "text", text: prompt ?? (session.parent ? `ALP resumed this assignment; it had stopped because ${reason}. Continue where you left off: your earlier work in this session and its files are intact. Finish with alp_handoff as before.` : `ALP resumed this session; it had stopped because ${reason}. Continue the user's request where you left off: your earlier work in this thread and its files are intact.`) }]
|
|
42446
|
+
}, session.parent ? "assignment" : "wake");
|
|
42447
|
+
session.resumedTurn = session.active;
|
|
42448
|
+
emit(sessionId, { type: "session.updated", session: snapshot(sessionId, session) });
|
|
42449
|
+
} catch (error51) {
|
|
42450
|
+
if (!session.closed && !session.active) {
|
|
42451
|
+
session.parked = parked;
|
|
42452
|
+
emit(sessionId, { type: "session.updated", session: snapshot(sessionId, session) });
|
|
42453
|
+
if (assignment) emit(session.parent, { type: "assignment", assignment: assignmentSnapshot(assignment, "parked") });
|
|
42454
|
+
}
|
|
42455
|
+
notice("warning", `Could not resume ${session.mapping.agent.name}: ${errorData(error51).message}`);
|
|
42456
|
+
}
|
|
42457
|
+
});
|
|
42385
42458
|
}
|
|
42386
42459
|
async function limitReset(session, error51) {
|
|
42387
42460
|
const at2 = (seconds) => typeof seconds === "number" && seconds > 0 ? new Date(seconds * 1e3).toISOString() : void 0;
|
|
@@ -42398,8 +42471,9 @@ Review the process against ALP.md, ${agent}'s AGENT.md and the recorded lessons.
|
|
|
42398
42471
|
}
|
|
42399
42472
|
async function limitReached(session, error51) {
|
|
42400
42473
|
const kind = session.runtimeKind;
|
|
42401
|
-
if (
|
|
42474
|
+
if (pauseOf(kind)) return;
|
|
42402
42475
|
const resetsAt = await limitReset(session, error51);
|
|
42476
|
+
if (closed || session.closed || pauseOf(kind)) return;
|
|
42403
42477
|
const pause = { since: (/* @__PURE__ */ new Date()).toISOString(), by: "alpd", reason: `${label(kind)} usage limit reached`, ...resetsAt ? { resetsAt } : {} };
|
|
42404
42478
|
pauseRuntime(kind, pause);
|
|
42405
42479
|
const other = RUNTIMES.find((candidate) => candidate !== kind && !pauseOf(candidate));
|
|
@@ -42540,10 +42614,10 @@ ${cut(session.brief, BRIEF_CHARS)}`);
|
|
|
42540
42614
|
function lessonFiles(mapping) {
|
|
42541
42615
|
return [path29.join(mapping.agent.projectRoot, ".alp", LESSONS_FILE), ...options2.libraryDir ? [path29.join(options2.libraryDir, LESSONS_FILE)] : []];
|
|
42542
42616
|
}
|
|
42543
|
-
async function confirm(sessionId, session, body) {
|
|
42617
|
+
async function confirm(sessionId, session, body, approval) {
|
|
42544
42618
|
if ([...userQuestions.values()].some((pending) => pending.question.sessionId === sessionId)) return { approved: false, outcome: "busy", feedback: "A question is already waiting for the user" };
|
|
42545
42619
|
const say = wordsFor(session);
|
|
42546
|
-
const result = await askUser(sessionId, session, void 0, body, [say.approve, say.reject]);
|
|
42620
|
+
const result = await askUser(sessionId, session, void 0, body, [say.approve, say.reject], approval);
|
|
42547
42621
|
let value;
|
|
42548
42622
|
try {
|
|
42549
42623
|
value = JSON.parse(result.contentItems[0].text);
|
|
@@ -42554,25 +42628,45 @@ ${cut(session.brief, BRIEF_CHARS)}`);
|
|
|
42554
42628
|
const answer = String(value.answer).trim();
|
|
42555
42629
|
return APPROVALS.includes(answer.toLowerCase()) ? { approved: true } : { approved: false, outcome: "answered", feedback: answer };
|
|
42556
42630
|
}
|
|
42557
|
-
const declined = (decision) => toolResult(true, {
|
|
42558
|
-
approved: false,
|
|
42559
|
-
outcome: decision.outcome,
|
|
42560
|
-
...decision.feedback ? { feedback: decision.feedback } : {},
|
|
42561
|
-
next: "Nothing was saved or posted. Revise from the feedback and propose again, or drop it."
|
|
42562
|
-
});
|
|
42563
42631
|
const text2 = (value, limit) => typeof value === "string" && !!value.trim() && value.length <= limit;
|
|
42632
|
+
const approvalCancellation = /* @__PURE__ */ new WeakMap();
|
|
42633
|
+
const approvalLedger = /* @__PURE__ */ new Map();
|
|
42634
|
+
const approvalsOf = (sessionId) => {
|
|
42635
|
+
let approvals = approvalLedger.get(sessionId);
|
|
42636
|
+
if (!approvals) approvalLedger.set(sessionId, approvals = /* @__PURE__ */ new Map());
|
|
42637
|
+
return approvals;
|
|
42638
|
+
};
|
|
42639
|
+
const approvalCanceled = (session, cancellation) => closed || session.closed || cancellation !== (approvalCancellation.get(session) ?? 0);
|
|
42564
42640
|
async function skillTool(sessionId, session, args) {
|
|
42565
|
-
|
|
42641
|
+
const cancellation = approvalCancellation.get(session) ?? 0;
|
|
42642
|
+
args = structuredClone(args);
|
|
42643
|
+
if (!plainObject(args, ["name", "description", "body", "roles", "lessons", "replace", "requestId"]) || typeof args.name !== "string" || !/^[a-z0-9][a-z0-9-]{1,62}$/.test(args.name) || !text2(args.description, 300) || !text2(args.body, SKILL_BODY_CHARS) || !Array.isArray(args.roles) || !args.roles.length || args.roles.length > 10 || !args.roles.every((role) => typeof role === "string" && /^[\w.-]+$/.test(role) && role !== "." && role !== "..") || args.lessons !== void 0 && (!Array.isArray(args.lessons) || args.lessons.length > 50 || !args.lessons.every((lesson) => text2(lesson, LESSON_CHARS2))) || args.replace !== void 0 && typeof args.replace !== "boolean") {
|
|
42566
42644
|
return toolResult(false, { error: `A skill needs a name (lowercase letters, digits, hyphens), a one-line description, a body of at most ${SKILL_BODY_CHARS} characters, and the roles that get it` });
|
|
42567
42645
|
}
|
|
42568
|
-
if (!
|
|
42569
|
-
const
|
|
42646
|
+
if (args.requestId !== void 0 && !text2(args.requestId, 100)) return toolResult(false, { error: "requestId must be a nonempty string of at most 100 characters" });
|
|
42647
|
+
const library = options2.libraryDir;
|
|
42648
|
+
if (!library) return toolResult(false, { error: "This host keeps no user skill library" });
|
|
42649
|
+
const known = /* @__PURE__ */ new Set([...STARTER_ROLES, ...await discoverAgents(session.mapping.agent.projectRoot, { library, templates: options2.templates })]);
|
|
42570
42650
|
const unknown2 = args.roles.filter((role) => !known.has(role));
|
|
42571
42651
|
if (unknown2.length) return toolResult(false, { error: `Unknown roles: ${unknown2.join(", ")}. Roles are ${[...known].join(", ")}` });
|
|
42572
|
-
const file3 = path29.join(
|
|
42652
|
+
const file3 = path29.join(library, "skills", args.name, "SKILL.md");
|
|
42653
|
+
const content = `---
|
|
42654
|
+
name: ${args.name}
|
|
42655
|
+
description: ${JSON.stringify(args.description.replace(/\s+/g, " ").trim())}
|
|
42656
|
+
---
|
|
42657
|
+
|
|
42658
|
+
${args.body.trim()}
|
|
42659
|
+
`;
|
|
42660
|
+
const lessons2 = (args.lessons ?? []).map((lesson) => lesson.replace(/\s+/g, " ").trim());
|
|
42661
|
+
const draftKey = JSON.stringify(["skill", content, args.roles, lessons2, !!args.replace]);
|
|
42662
|
+
const key2 = `skill:${args.requestId ?? draftKey}`;
|
|
42663
|
+
const approvals = approvalsOf(sessionId);
|
|
42664
|
+
const previous = approvals.get(key2);
|
|
42665
|
+
if (previous && previous.draftKey !== draftKey) return toolResult(false, { error: "requestId was already used for a different draft" });
|
|
42666
|
+
if (previous) return toolResult(true, previous.result ?? { status: "pending_approval", approvalId: previous.approvalId, file: file3 });
|
|
42573
42667
|
const existing = await readFile17(file3, "utf8").catch(() => void 0);
|
|
42574
42668
|
if (existing !== void 0 && !args.replace) return toolResult(false, { error: `The library already has a skill named ${args.name} (${file3}); read it, then pass replace: true to propose a new version, or choose another name` });
|
|
42575
|
-
const rolesFile = path29.join(
|
|
42669
|
+
const rolesFile = path29.join(library, "role-skills.json");
|
|
42576
42670
|
const readRoles = async () => {
|
|
42577
42671
|
const raw = await readFile17(rolesFile, "utf8").catch(() => "{}");
|
|
42578
42672
|
const roles = JSON.parse(raw);
|
|
@@ -42584,62 +42678,77 @@ ${cut(session.brief, BRIEF_CHARS)}`);
|
|
|
42584
42678
|
} catch (error51) {
|
|
42585
42679
|
return toolResult(false, { error: errorData(error51).message });
|
|
42586
42680
|
}
|
|
42587
|
-
|
|
42588
|
-
|
|
42589
|
-
|
|
42590
|
-
|
|
42591
|
-
|
|
42592
|
-
${args.body.trim()}
|
|
42593
|
-
`;
|
|
42594
|
-
const lessons2 = (args.lessons ?? []).map((lesson) => lesson.replace(/\s+/g, " ").trim());
|
|
42681
|
+
if (approvalCanceled(session, cancellation)) return toolResult(false, { error: "Skill proposal canceled or session closed; no approval was created" });
|
|
42682
|
+
if ([...userQuestions.values()].some((pending) => pending.question.sessionId === sessionId)) return toolResult(false, { error: "A question is already waiting for the user; finish it before proposing a skill" });
|
|
42683
|
+
const approvalId = `q-${randomUUID11()}`;
|
|
42684
|
+
const record4 = { approvalId, draftKey };
|
|
42685
|
+
approvals.set(key2, record4);
|
|
42595
42686
|
const say = wordsFor(session);
|
|
42596
|
-
const decision =
|
|
42687
|
+
const decision = confirm(
|
|
42597
42688
|
sessionId,
|
|
42598
42689
|
session,
|
|
42599
42690
|
say.skill(session.mapping.agent.name, existing !== void 0, file3, args.roles.join(", "), lessons2) + `
|
|
42600
42691
|
${say.answerLine(session.mapping.agent.name)}
|
|
42601
42692
|
|
|
42602
|
-
${content}
|
|
42693
|
+
${content}`,
|
|
42694
|
+
{ id: approvalId }
|
|
42603
42695
|
);
|
|
42604
|
-
|
|
42605
|
-
|
|
42606
|
-
|
|
42607
|
-
|
|
42608
|
-
|
|
42609
|
-
|
|
42610
|
-
|
|
42611
|
-
|
|
42612
|
-
|
|
42613
|
-
|
|
42614
|
-
|
|
42615
|
-
|
|
42616
|
-
|
|
42617
|
-
|
|
42618
|
-
|
|
42619
|
-
|
|
42620
|
-
|
|
42621
|
-
|
|
42622
|
-
const
|
|
42623
|
-
const
|
|
42624
|
-
if (
|
|
42625
|
-
|
|
42626
|
-
|
|
42627
|
-
|
|
42628
|
-
|
|
42629
|
-
|
|
42630
|
-
|
|
42631
|
-
|
|
42632
|
-
|
|
42633
|
-
|
|
42634
|
-
|
|
42635
|
-
|
|
42636
|
-
|
|
42637
|
-
|
|
42638
|
-
|
|
42639
|
-
|
|
42696
|
+
const save2 = async () => {
|
|
42697
|
+
if (existing === void 0 && !args.replace && await readFile17(file3, "utf8").then(() => true, () => false)) {
|
|
42698
|
+
return { approved: true, saved: false, error: `A skill named ${args.name} was saved meanwhile (${file3}); nothing was overwritten`, next: "Read it, then propose again with replace: true if yours should replace it." };
|
|
42699
|
+
}
|
|
42700
|
+
try {
|
|
42701
|
+
await mkdir11(path29.dirname(file3), { recursive: true });
|
|
42702
|
+
await writeFile13(file3, content);
|
|
42703
|
+
const roles = await readRoles();
|
|
42704
|
+
for (const role of args.roles) {
|
|
42705
|
+
const list2 = Array.isArray(roles[role]) ? roles[role] : [];
|
|
42706
|
+
if (!list2.includes(args.name)) list2.push(args.name);
|
|
42707
|
+
roles[role] = list2;
|
|
42708
|
+
}
|
|
42709
|
+
await writeFile13(rolesFile, JSON.stringify(roles, null, 2) + "\n");
|
|
42710
|
+
} catch (error51) {
|
|
42711
|
+
return { approved: true, saved: false, error: errorData(error51).message, next: "Tell the user; nothing is retried automatically." };
|
|
42712
|
+
}
|
|
42713
|
+
const removed = /* @__PURE__ */ new Set();
|
|
42714
|
+
for (const lessonFile of lessonFiles(session.mapping)) {
|
|
42715
|
+
const current = await readFile17(lessonFile, "utf8").catch(() => void 0);
|
|
42716
|
+
if (current === void 0) continue;
|
|
42717
|
+
const kept = current.split("\n").filter((line) => {
|
|
42718
|
+
const match = /^- \d{4}-\d\d-\d\d: (.*)$/.exec(line);
|
|
42719
|
+
if (!match || !lessons2.includes(match[1].trim())) return true;
|
|
42720
|
+
removed.add(match[1].trim());
|
|
42721
|
+
return false;
|
|
42722
|
+
});
|
|
42723
|
+
if (kept.length !== current.split("\n").length) await writeFile13(lessonFile, kept.join("\n")).catch(() => {
|
|
42724
|
+
});
|
|
42725
|
+
}
|
|
42726
|
+
runLog(rootOf2(sessionId), { event: "skill", agent: session.mapping.agent.name, name: args.name, roles: args.roles, replaced: existing !== void 0, lessons: [...removed] });
|
|
42727
|
+
return {
|
|
42728
|
+
approved: true,
|
|
42729
|
+
saved: file3,
|
|
42730
|
+
roles: args.roles,
|
|
42731
|
+
lessonsRemoved: [...removed],
|
|
42732
|
+
...lessons2.length > removed.size ? { lessonsNotFound: lessons2.filter((lesson) => !removed.has(lesson)) } : {},
|
|
42733
|
+
next: "New sessions of those roles list the skill; read the file now if you need it in this one."
|
|
42734
|
+
};
|
|
42735
|
+
};
|
|
42736
|
+
void (async () => {
|
|
42737
|
+
const answer = await decision;
|
|
42738
|
+
const canceled = approvalCanceled(session, cancellation);
|
|
42739
|
+
const result = !answer.approved || canceled ? { approved: false, saved: false, outcome: canceled ? "canceled" : answer.outcome, ...answer.feedback ? { feedback: answer.feedback } : {}, next: "Nothing was saved. Revise from the feedback and propose again with a fresh requestId, or drop it." } : await save2();
|
|
42740
|
+
record4.result = { status: "resolved", approvalId, name: args.name, ...result };
|
|
42741
|
+
runLog(rootOf2(sessionId), { event: "skill.approval", agent: session.mapping.agent.name, ...record4.result });
|
|
42742
|
+
if (!closed && !session.closed && sessions.get(sessionId) === session) {
|
|
42743
|
+
post(sessionId, { kind: "result", from: "ALP", assignment: approvalId, body: `Skill approval result: ${JSON.stringify(record4.result)}` });
|
|
42744
|
+
}
|
|
42745
|
+
})();
|
|
42746
|
+
return toolResult(true, { status: "pending_approval", approvalId, file: file3, next: "Continue other work or end your turn. ALP sends the user's decision, and whether the skill was saved, by mail; do not resubmit this draft." });
|
|
42640
42747
|
}
|
|
42641
42748
|
async function issueTool(sessionId, session, args) {
|
|
42642
|
-
|
|
42749
|
+
const cancellation = approvalCancellation.get(session) ?? 0;
|
|
42750
|
+
args = structuredClone(args);
|
|
42751
|
+
if (!plainObject(args, ["action", "target", "query", "title", "body", "issue", "labels", "requestId"]) || !["search", "create", "comment"].includes(args.action) || !["project", "alp"].includes(args.target)) {
|
|
42643
42752
|
return toolResult(false, { error: "An issue call needs action (search, create or comment) and target (project or alp)" });
|
|
42644
42753
|
}
|
|
42645
42754
|
const project2 = session.mapping.agent.projectRoot;
|
|
@@ -42665,6 +42774,7 @@ ${content}`
|
|
|
42665
42774
|
if (args.labels !== void 0 && (args.action !== "create" || !Array.isArray(args.labels) || args.labels.length > 10 || !args.labels.every((label2) => text2(label2, 50)))) {
|
|
42666
42775
|
return toolResult(false, { error: "labels are up to 10 existing label names, for create" });
|
|
42667
42776
|
}
|
|
42777
|
+
if (args.requestId !== void 0 && !text2(args.requestId, 100)) return toolResult(false, { error: "requestId must be a nonempty string of at most 100 characters" });
|
|
42668
42778
|
if (args.action === "create" && args.labels?.length) {
|
|
42669
42779
|
try {
|
|
42670
42780
|
const labels = JSON.parse(await github(["label", "list", "-R", repo, "--limit", "1000", "--json", "name"], { cwd: project2 }));
|
|
@@ -42675,9 +42785,20 @@ ${content}`
|
|
|
42675
42785
|
return toolResult(false, { repo, error: `Could not validate issue labels: ${errorData(error51).message}` });
|
|
42676
42786
|
}
|
|
42677
42787
|
}
|
|
42788
|
+
if (approvalCanceled(session, cancellation)) return toolResult(false, { error: "Issue proposal canceled or session closed; no approval was created" });
|
|
42789
|
+
const draftKey = JSON.stringify([repo, args.action, args.title ?? null, args.issue ?? null, args.body, [...args.labels ?? []].sort()]);
|
|
42790
|
+
const key2 = `issue:${args.requestId ?? draftKey}`;
|
|
42791
|
+
const approvals = approvalsOf(sessionId);
|
|
42792
|
+
const previous = approvals.get(key2);
|
|
42793
|
+
if (previous && previous.draftKey !== draftKey) return toolResult(false, { error: "requestId was already used for a different draft" });
|
|
42794
|
+
if (previous) return toolResult(true, previous.result ?? { status: "pending_approval", approvalId: previous.approvalId, repo });
|
|
42795
|
+
if ([...userQuestions.values()].some((pending) => pending.question.sessionId === sessionId)) return toolResult(false, { error: "A question is already waiting for the user; finish it before proposing another issue draft" });
|
|
42796
|
+
const approvalId = `q-${randomUUID11()}`;
|
|
42797
|
+
const record4 = { approvalId, draftKey };
|
|
42798
|
+
approvals.set(key2, record4);
|
|
42678
42799
|
const where = `${repo}${args.target === "alp" ? " (ALP itself)" : ""}`;
|
|
42679
42800
|
const say = wordsFor(session);
|
|
42680
|
-
const decision =
|
|
42801
|
+
const decision = confirm(
|
|
42681
42802
|
sessionId,
|
|
42682
42803
|
session,
|
|
42683
42804
|
say.issue(session.mapping.agent.name, args.action === "create", args.issue, where) + `
|
|
@@ -42686,18 +42807,31 @@ ${say.answerLine(session.mapping.agent.name)}
|
|
|
42686
42807
|
` + (args.action === "create" ? `${say.issueTitle}: ${args.title}
|
|
42687
42808
|
${args.labels?.length ? `${say.issueLabels}: ${args.labels.join(", ")}
|
|
42688
42809
|
` : ""}
|
|
42689
|
-
` : "") + args.body
|
|
42810
|
+
` : "") + args.body.trim() + ISSUE_FOOTER,
|
|
42811
|
+
{ id: approvalId }
|
|
42690
42812
|
);
|
|
42691
|
-
|
|
42692
|
-
|
|
42693
|
-
|
|
42694
|
-
const
|
|
42695
|
-
|
|
42696
|
-
|
|
42697
|
-
|
|
42698
|
-
|
|
42699
|
-
|
|
42700
|
-
|
|
42813
|
+
void (async () => {
|
|
42814
|
+
const answer = await decision;
|
|
42815
|
+
let result;
|
|
42816
|
+
const canceled = approvalCanceled(session, cancellation);
|
|
42817
|
+
if (!answer.approved || canceled) {
|
|
42818
|
+
result = { approved: false, posted: false, outcome: canceled ? "canceled" : answer.outcome, ...answer.feedback ? { feedback: answer.feedback } : {} };
|
|
42819
|
+
} else {
|
|
42820
|
+
try {
|
|
42821
|
+
const body = args.body.trim() + ISSUE_FOOTER;
|
|
42822
|
+
const output = args.action === "create" ? await github(["issue", "create", "-R", repo, "--title", args.title, "--body-file", "-", ...(args.labels ?? []).flatMap((label2) => ["--label", label2])], { cwd: project2, input: body }) : await github(["issue", "comment", String(args.issue), "-R", repo, "--body-file", "-"], { cwd: project2, input: body });
|
|
42823
|
+
result = { approved: true, posted: true, url: output.trim().split("\n").at(-1) ?? "" };
|
|
42824
|
+
} catch (error51) {
|
|
42825
|
+
result = { approved: true, posted: false, error: errorData(error51).message, next: "Tell the user; do not retry this draft automatically: GitHub may have accepted it before reporting an error." };
|
|
42826
|
+
}
|
|
42827
|
+
}
|
|
42828
|
+
record4.result = { status: "resolved", approvalId, repo, ...result };
|
|
42829
|
+
runLog(rootOf2(sessionId), { event: "issue.approval", action: args.action, ...args.title ? { title: args.title } : {}, ...args.issue ? { issue: args.issue } : {}, ...record4.result });
|
|
42830
|
+
if (!closed && !session.closed && sessions.get(sessionId) === session) {
|
|
42831
|
+
post(sessionId, { kind: "result", from: "ALP", assignment: approvalId, body: `Issue approval result: ${JSON.stringify(record4.result)}` });
|
|
42832
|
+
}
|
|
42833
|
+
})();
|
|
42834
|
+
return toolResult(true, { status: "pending_approval", approvalId, repo, next: "Continue other work. ALP sends the decision and posting result by mail; do not resubmit this draft." });
|
|
42701
42835
|
}
|
|
42702
42836
|
function touch(sessionId, session) {
|
|
42703
42837
|
const now3 = Date.now();
|
|
@@ -42721,6 +42855,8 @@ ${args.labels?.length ? `${say.issueLabels}: ${args.labels.join(", ")}
|
|
|
42721
42855
|
if (session && !session.closed) {
|
|
42722
42856
|
emit(sessionId, { type: "mail", mail: publicEvent(mail) });
|
|
42723
42857
|
session.mail.push(mail);
|
|
42858
|
+
if (mail.kind === "result" || mail.kind === "question") session.wakes = 0;
|
|
42859
|
+
if (mail.kind === "result" || mail.kind === "question" || mail.kind === "checkin") session.wakeFailures = 0;
|
|
42724
42860
|
deliver(sessionId, session);
|
|
42725
42861
|
}
|
|
42726
42862
|
return mail;
|
|
@@ -42743,7 +42879,7 @@ ${args.labels?.length ? `${say.issueLabels}: ${args.labels.join(", ")}
|
|
|
42743
42879
|
if (session.mail.some((event) => !event.deliveredTurn && !event.passive && !event.defer)) void steerMail(sessionId, session);
|
|
42744
42880
|
} else if (!waking) {
|
|
42745
42881
|
return;
|
|
42746
|
-
} else if (!session.wakeBlocked && session.wakes < MAX_WAKES) {
|
|
42882
|
+
} else if (!session.wakeBlocked && session.wakeFailures < MAX_WAKES && (session.wakes < MAX_WAKES || session.mail.some((event) => !event.deliveredTurn && event.kind === "checkin"))) {
|
|
42747
42883
|
autoWake(sessionId, session);
|
|
42748
42884
|
} else if (session.parent && !session.wakeBlocked && !held(session)) {
|
|
42749
42885
|
session.settle?.("failed", `Wake limit (${MAX_WAKES}) reached with mail outstanding`);
|
|
@@ -42777,6 +42913,7 @@ ${args.labels?.length ? `${say.issueLabels}: ${args.labels.join(", ")}
|
|
|
42777
42913
|
session.wakeHeld = true;
|
|
42778
42914
|
return;
|
|
42779
42915
|
}
|
|
42916
|
+
const checkIn2 = session.mail.find((event) => !event.deliveredTurn && event.kind === "checkin");
|
|
42780
42917
|
const batch2 = takeBatch(session.mail, () => true);
|
|
42781
42918
|
if (!batch2.length) return;
|
|
42782
42919
|
for (const event of batch2) event.deliveredTurn = STARTING;
|
|
@@ -42789,11 +42926,13 @@ ${args.labels?.length ? `${say.issueLabels}: ${args.labels.join(", ")}
|
|
|
42789
42926
|
release2();
|
|
42790
42927
|
return deliver(sessionId, session);
|
|
42791
42928
|
}
|
|
42929
|
+
if (session.wakeFailures >= MAX_WAKES || session.wakes >= MAX_WAKES && (!checkIn2 || !session.mail.includes(checkIn2))) return release2();
|
|
42792
42930
|
if (!batch2.every((event) => event.kind === "checkin")) session.wakes++;
|
|
42793
42931
|
const id2 = `alp-wake-${randomUUID11()}`;
|
|
42794
42932
|
try {
|
|
42795
42933
|
await startPrompt(sessionId, { clientMessageId: id2, delivery: "auto", content: [{ type: "text", text: renderMail(batch2, session.parentAgent) }] }, "wake", batch2);
|
|
42796
42934
|
} catch {
|
|
42935
|
+
session.wakeFailures++;
|
|
42797
42936
|
release2();
|
|
42798
42937
|
deliver(sessionId, session);
|
|
42799
42938
|
}
|
|
@@ -42893,6 +43032,17 @@ ${args.labels?.length ? `${say.issueLabels}: ${args.labels.join(", ")}
|
|
|
42893
43032
|
waiter.resolve("user");
|
|
42894
43033
|
}
|
|
42895
43034
|
}
|
|
43035
|
+
function releaseQuestions(sessionId) {
|
|
43036
|
+
for (const { question, settle, asked } of [...userQuestions.values()]) {
|
|
43037
|
+
if (question.sessionId !== sessionId || !asked) continue;
|
|
43038
|
+
settle("canceled", void 0, "the user wrote instead of answering", toolResult(true, {
|
|
43039
|
+
status: "user_wrote",
|
|
43040
|
+
userMessage: true,
|
|
43041
|
+
question: question.id,
|
|
43042
|
+
next: `${USER_WROTE} Their message may be the answer to your question; if it is not, ask again later.`
|
|
43043
|
+
}));
|
|
43044
|
+
}
|
|
43045
|
+
}
|
|
42896
43046
|
const assignmentSnapshot = (assignment, status) => ({
|
|
42897
43047
|
id: assignment.id,
|
|
42898
43048
|
agent: assignment.agent,
|
|
@@ -43102,7 +43252,7 @@ ${refused}`, next: "Fix what it reports, then call alp_handoff again." });
|
|
|
43102
43252
|
const pending = [...session.assignments.keys()].some((id2) => !ids || ids.has(id2)) || takeBatch(session.mail, (event) => event.kind !== "board" && !event.defer && accept(event)).length > 0;
|
|
43103
43253
|
const events = pending ? await waitFor(sessionId, session, accept, Math.min(args.timeoutMs ?? 3e5, 9e5)) : [];
|
|
43104
43254
|
if (events === "user") return toolResult(true, { events: [], userMessage: true, running: running2(session), next: USER_WROTE });
|
|
43105
|
-
if (!events) return toolResult(false, { error: "Turn ended" });
|
|
43255
|
+
if (!events) return toolResult(false, session.closed || session.wakeBlocked ? { error: "Turn ended" } : { error: TURN_ENDED, running: running2(session) });
|
|
43106
43256
|
return toolResult(true, { events: events.map(publicEvent), running: running2(session) });
|
|
43107
43257
|
}
|
|
43108
43258
|
function sendTool(sessionId, session, args) {
|
|
@@ -43132,10 +43282,10 @@ ${refused}`, next: "Fix what it reports, then call alp_handoff again." });
|
|
|
43132
43282
|
}
|
|
43133
43283
|
return toolResult(true, { sent: post(assignment.id, { kind: args.kind, from, assignment: assignment.id, body: args.body, ...args.replyTo ? { replyTo: args.replyTo } : {} }).id });
|
|
43134
43284
|
}
|
|
43135
|
-
function askUser(sessionId, session, assignment, body, options3) {
|
|
43285
|
+
function askUser(sessionId, session, assignment, body, options3, approval, asked = false) {
|
|
43136
43286
|
const rootId = rootOf2(sessionId);
|
|
43137
43287
|
const question = {
|
|
43138
|
-
id: `q-${randomUUID11().slice(0, 8)}`,
|
|
43288
|
+
id: approval?.id ?? `q-${randomUUID11().slice(0, 8)}`,
|
|
43139
43289
|
sessionId,
|
|
43140
43290
|
rootId,
|
|
43141
43291
|
agent: session.mapping.agent.name,
|
|
@@ -43161,7 +43311,7 @@ The user answered: "${answer}"`);
|
|
|
43161
43311
|
next: "Decide, and record the assumption in your handoff or final message; or report that you are blocked."
|
|
43162
43312
|
})));
|
|
43163
43313
|
};
|
|
43164
|
-
userQuestions.set(question.id, { question, settle });
|
|
43314
|
+
userQuestions.set(question.id, { question, settle, persistent: !!approval, asked });
|
|
43165
43315
|
if (assignment) assignment.ask = { id: question.id, resolve: (result) => settle("canceled", void 0, void 0, result) };
|
|
43166
43316
|
emit(sessionId, { type: "question", question });
|
|
43167
43317
|
runLog(rootId, { event: "human.question", questionId: question.id, sessionId, agent: question.agent, body, ...options3?.length ? { options: options3 } : {} });
|
|
@@ -43174,9 +43324,9 @@ The user answered: "${answer}"`);
|
|
|
43174
43324
|
if (!session.parent || !sessions.has(session.parent)) return;
|
|
43175
43325
|
post(session.parent, { kind: "note", from: session.mapping.agent.name, assignment: sessionId, body: `[ALP, on behalf of ${session.mapping.agent.name}] ${body}` });
|
|
43176
43326
|
}
|
|
43177
|
-
function cancelQuestions(sessionId) {
|
|
43178
|
-
for (const { question, settle } of [...userQuestions.values()]) {
|
|
43179
|
-
if (question.sessionId === sessionId) settle("canceled", void 0, void 0, toolResult(false, { error: "Turn ended" }));
|
|
43327
|
+
function cancelQuestions(sessionId, turnOnly = false) {
|
|
43328
|
+
for (const { question, settle, persistent } of [...userQuestions.values()]) {
|
|
43329
|
+
if (question.sessionId === sessionId && (!turnOnly || !persistent)) settle("canceled", void 0, void 0, toolResult(false, { error: "Turn ended" }));
|
|
43180
43330
|
}
|
|
43181
43331
|
}
|
|
43182
43332
|
function askTool(sessionId, session, args) {
|
|
@@ -43196,7 +43346,7 @@ The user answered: "${answer}"`);
|
|
|
43196
43346
|
if (to === "user" && session.parent && !session.userOpened) {
|
|
43197
43347
|
return Promise.resolve(toolResult(false, { error: `Only main talks to the user; ask ${session.parentAgent ?? "your requester"} with alp_ask instead` }));
|
|
43198
43348
|
}
|
|
43199
|
-
if (to === "user") return askUser(sessionId, session, assignment, args.question, args.options);
|
|
43349
|
+
if (to === "user") return askUser(sessionId, session, assignment, args.question, args.options, void 0, true);
|
|
43200
43350
|
if (!session.parent || !parent || !assignment) return Promise.resolve(toolResult(false, { error: 'This session has no requester; ask the user with to: "user"' }));
|
|
43201
43351
|
const parentId = session.parent;
|
|
43202
43352
|
return new Promise((resolve2) => {
|
|
@@ -43343,9 +43493,11 @@ The user answered: "${answer}"`);
|
|
|
43343
43493
|
}
|
|
43344
43494
|
const rootId = rootOf2(sessionId);
|
|
43345
43495
|
const root = sessions.get(rootId);
|
|
43346
|
-
|
|
43496
|
+
const advisor = ["advisor", "reviewer"].includes(roleOf(session.mapping, args.agent) ?? "") && childMode === "read-only";
|
|
43497
|
+
const budget = advisor ? "advisorCalls" : "calls";
|
|
43498
|
+
if (root[budget] >= 16) {
|
|
43347
43499
|
return toolResult(false, {
|
|
43348
|
-
error: "
|
|
43500
|
+
error: `${advisor ? "Advisor" : "Implementation"} delegation budget exhausted (16 starts across the root session tree since its last new user turn). Mail wakes and child turns do not reset it; a new accepted user prompt in root (including steering) resets both budgets.`
|
|
43349
43501
|
});
|
|
43350
43502
|
}
|
|
43351
43503
|
const peer = roleOf(session.mapping, args.agent) === "peer";
|
|
@@ -43358,7 +43510,7 @@ The user answered: "${answer}"`);
|
|
|
43358
43510
|
const continued = args.continueFrom !== void 0 ? session.worktrees.get(args.continueFrom) : void 0;
|
|
43359
43511
|
if (args.continueFrom !== void 0 && !continued && !sharedContinuation) return toolResult(false, { error: `${args.continueFrom} was merged or discarded meanwhile` });
|
|
43360
43512
|
if (continued) session.worktrees.delete(args.continueFrom);
|
|
43361
|
-
root
|
|
43513
|
+
root[budget]++;
|
|
43362
43514
|
if (peer) root.peerCount++;
|
|
43363
43515
|
const childId = `alp-child-${randomUUID11()}`;
|
|
43364
43516
|
const startedAt = Date.now();
|
|
@@ -43518,12 +43670,15 @@ ${digest3}` : "")
|
|
|
43518
43670
|
const events = await waitFor(sessionId, session, (event2) => event2.assignment === childId && (event2.kind === "result" || event2.kind === "question"), void 0, true);
|
|
43519
43671
|
if (events === "user") return toolResult(true, { assignmentId: childId, agent: args.agent, status: "running", userMessage: true, next: USER_WROTE });
|
|
43520
43672
|
if (!events) {
|
|
43521
|
-
|
|
43522
|
-
|
|
43523
|
-
|
|
43524
|
-
|
|
43525
|
-
|
|
43526
|
-
|
|
43673
|
+
if (session.closed || session.wakeBlocked || !session.assignments.has(childId)) {
|
|
43674
|
+
return toolResult(false, {
|
|
43675
|
+
agent: args.agent,
|
|
43676
|
+
assignmentId: childId,
|
|
43677
|
+
status: "canceled",
|
|
43678
|
+
error: "Parent assignment stopped"
|
|
43679
|
+
});
|
|
43680
|
+
}
|
|
43681
|
+
return toolResult(false, { agent: args.agent, assignmentId: childId, status: "running", error: TURN_ENDED });
|
|
43527
43682
|
}
|
|
43528
43683
|
const event = events.find((candidate) => candidate.kind === "result") ?? events.find((candidate) => candidate.kind === "question");
|
|
43529
43684
|
if (!event) return toolResult(true, { assignmentId: childId, agent: args.agent, status: "running", events: events.map(publicEvent), next: CHECKED_IN });
|
|
@@ -43589,10 +43744,12 @@ ${digest3}` : "")
|
|
|
43589
43744
|
peerCount: 0,
|
|
43590
43745
|
assignments: /* @__PURE__ */ new Map(),
|
|
43591
43746
|
calls: 0,
|
|
43747
|
+
advisorCalls: 0,
|
|
43592
43748
|
mail: [],
|
|
43593
43749
|
waiters: [],
|
|
43594
43750
|
lastActivity: Date.now(),
|
|
43595
43751
|
wakes: 0,
|
|
43752
|
+
wakeFailures: 0,
|
|
43596
43753
|
wakeBlocked: false,
|
|
43597
43754
|
toolCalls: /* @__PURE__ */ new Map(),
|
|
43598
43755
|
acknowledged: Promise.resolve(),
|
|
@@ -43897,7 +44054,7 @@ Write scope: change files only under ${session.spec.writeRoot}. Your working dir
|
|
|
43897
44054
|
runLog(entry.rootId, { event: "assignment.finished", assignmentId: entry.assignmentId, reconciled: true, ...result });
|
|
43898
44055
|
if (parent && !parent.closed) post(entry.parentId, { kind: "result", from: entry.agent, assignment: entry.assignmentId, result });
|
|
43899
44056
|
}
|
|
43900
|
-
async function recoverTree(rootId, continueRoot) {
|
|
44057
|
+
async function recoverTree(rootId, continueRoot, parkedRoot) {
|
|
43901
44058
|
const root = sessions.get(rootId);
|
|
43902
44059
|
if (!root || root.closed) throw new Error(`Session ${rootId} is not open`);
|
|
43903
44060
|
const entries2 = inherited.filter((entry) => entry.rootId === rootId).sort((a, b) => a.ancestry.length - b.ancestry.length);
|
|
@@ -43934,7 +44091,11 @@ Write scope: change files only under ${session.spec.writeRoot}. Your working dir
|
|
|
43934
44091
|
runLog(rootId, { event: "assignment.recovered", assignmentId: entry.assignmentId, agent: entry.agent, ...entry.taskId ? { taskId: entry.taskId } : {} });
|
|
43935
44092
|
proceed(entry.assignmentId, child, `ALP: ${cause} while you worked on this assignment, and reopened this session. Your earlier work in it${entry.worktree ? " and your worktree" : ""} is intact; check where you stopped (for example with git status), then continue. Finish with alp_handoff as before.${listed(resumed.get(entry.assignmentId))}`);
|
|
43936
44093
|
}
|
|
43937
|
-
if (
|
|
44094
|
+
if (parkedRoot) {
|
|
44095
|
+
root.parked = { reason: parkedRoot, since: Date.now() };
|
|
44096
|
+
emit(rootId, { type: "session.updated", session: snapshot(rootId, root) });
|
|
44097
|
+
if (options2.autoResume !== false && options2.recoveryResume !== false && !pauseOf(root.runtimeKind)) continueParked(rootId, root);
|
|
44098
|
+
} else if (continueRoot) proceed(rootId, root, `ALP: ${cause} during your turn, and reopened this session. Continue the user's request where you stopped.${listed(resumed.get(rootId))}`);
|
|
43938
44099
|
else for (const assignment of resumed.get(rootId) ?? []) post(rootId, { kind: "note", from: assignment.agent, assignment: assignment.id, passive: true, body: `${cause}; ALP reopened this assignment and it continues. It reports when done.` });
|
|
43939
44100
|
const failed = outcomes.filter((outcome) => outcome.outcome === "failed");
|
|
43940
44101
|
if (entries2.length || continueRoot) {
|
|
@@ -43981,6 +44142,11 @@ Write scope: change files only under ${session.spec.writeRoot}. Your working dir
|
|
|
43981
44142
|
const activeTurn = session.active;
|
|
43982
44143
|
session.wakeBlocked = true;
|
|
43983
44144
|
session.userStopped = true;
|
|
44145
|
+
session.parked = void 0;
|
|
44146
|
+
session.parkReason = void 0;
|
|
44147
|
+
emit(sessionId, { type: "session.updated", session: snapshot(sessionId, session) });
|
|
44148
|
+
approvalCancellation.set(session, (approvalCancellation.get(session) ?? 0) + 1);
|
|
44149
|
+
cancelQuestions(sessionId);
|
|
43984
44150
|
if (activeTurn && session.runtimeKind === "codex" && session.threadId) {
|
|
43985
44151
|
const partial2 = [...session.text.values()].join("\n").trim();
|
|
43986
44152
|
if (partial2) interruptedThreads.set(session.threadId, partial2.slice(-4e3));
|
|
@@ -44053,11 +44219,9 @@ Write scope: change files only under ${session.spec.writeRoot}. Your working dir
|
|
|
44053
44219
|
if (!wake) {
|
|
44054
44220
|
session.handoff = void 0;
|
|
44055
44221
|
session.wakes = 0;
|
|
44222
|
+
session.wakeFailures = 0;
|
|
44056
44223
|
session.wakeBlocked = false;
|
|
44057
44224
|
session.userStopped = false;
|
|
44058
|
-
if (!session.parent) {
|
|
44059
|
-
session.calls = 0;
|
|
44060
|
-
}
|
|
44061
44225
|
}
|
|
44062
44226
|
}
|
|
44063
44227
|
try {
|
|
@@ -44099,6 +44263,10 @@ ${interrupted}`), text_elements: [] }] : [],
|
|
|
44099
44263
|
);
|
|
44100
44264
|
const turnId = prompt.delivery === "steer" ? session.active : result.turn.id;
|
|
44101
44265
|
for (const event of mail) event.deliveredTurn = turnId;
|
|
44266
|
+
if (!session.parent && origin === "user") {
|
|
44267
|
+
session.calls = 0;
|
|
44268
|
+
session.advisorCalls = 0;
|
|
44269
|
+
}
|
|
44102
44270
|
session.seen.add(
|
|
44103
44271
|
prompt.clientMessageId
|
|
44104
44272
|
);
|
|
@@ -44114,7 +44282,10 @@ ${interrupted}`), text_elements: [] }] : [],
|
|
|
44114
44282
|
});
|
|
44115
44283
|
if (origin === "user" && !session.parent) session.userWaiting ??= Date.now();
|
|
44116
44284
|
if (session.supervisor && origin === "user") session.journal.push(stamp(`user ${prompt.delivery === "steer" ? "steered" : "asked"} ${session.mapping.agent.name}: ${clip(text3, 1500)}`));
|
|
44117
|
-
if (prompt.delivery === "steer" && origin === "user" && !session.parent)
|
|
44285
|
+
if (prompt.delivery === "steer" && origin === "user" && !session.parent) {
|
|
44286
|
+
releaseWaiters(session);
|
|
44287
|
+
releaseQuestions(sessionId);
|
|
44288
|
+
}
|
|
44118
44289
|
emit(sessionId, {
|
|
44119
44290
|
type: "prompt.accepted",
|
|
44120
44291
|
clientMessageId: prompt.clientMessageId,
|
|
@@ -44155,12 +44326,19 @@ ${interrupted}`), text_elements: [] }] : [],
|
|
|
44155
44326
|
return opened;
|
|
44156
44327
|
}),
|
|
44157
44328
|
prompt: (sessionId, input) => enqueue(async () => {
|
|
44329
|
+
const session = sessions.get(sessionId);
|
|
44330
|
+
const parked = session?.parked;
|
|
44158
44331
|
try {
|
|
44159
|
-
|
|
44332
|
+
const prompt = session?.active && session.resumedTurn === session.active && input.delivery === "auto" ? { ...input, delivery: "steer" } : input;
|
|
44333
|
+
await startPrompt(sessionId, prompt, "user");
|
|
44334
|
+
if (session && parked && session.parked === parked) {
|
|
44335
|
+
session.parked = void 0;
|
|
44336
|
+
emit(sessionId, { type: "session.updated", session: snapshot(sessionId, session) });
|
|
44337
|
+
}
|
|
44160
44338
|
} catch (error51) {
|
|
44161
|
-
const
|
|
44162
|
-
if (
|
|
44163
|
-
|
|
44339
|
+
const session2 = sessions.get(sessionId);
|
|
44340
|
+
if (session2?.seen.has(input.clientMessageId)) return;
|
|
44341
|
+
session2?.seen.add(input.clientMessageId);
|
|
44164
44342
|
emit(sessionId, { type: "prompt.failed", clientMessageId: input.clientMessageId, error: errorData(error51) });
|
|
44165
44343
|
}
|
|
44166
44344
|
}),
|
|
@@ -44304,8 +44482,8 @@ ${interrupted}`), text_elements: [] }] : [],
|
|
|
44304
44482
|
recoverable() {
|
|
44305
44483
|
return [...inherited];
|
|
44306
44484
|
},
|
|
44307
|
-
recover(rootId, { continueRoot = false } = {}) {
|
|
44308
|
-
return enqueue(() => recoverTree(rootId, continueRoot));
|
|
44485
|
+
recover(rootId, { continueRoot = false, parkedRoot } = {}) {
|
|
44486
|
+
return enqueue(() => recoverTree(rootId, continueRoot, parkedRoot));
|
|
44309
44487
|
},
|
|
44310
44488
|
async abandon(rootId, reason) {
|
|
44311
44489
|
const entries2 = inherited.filter((entry) => entry.rootId === rootId);
|
|
@@ -44338,14 +44516,14 @@ ${interrupted}`), text_elements: [] }] : [],
|
|
|
44338
44516
|
|
|
44339
44517
|
// packages/daemon/src/server.ts
|
|
44340
44518
|
import { createHash as createHash11, randomBytes as randomBytes6 } from "node:crypto";
|
|
44341
|
-
import { appendFile as appendFile3, chmod, mkdir as mkdir14, readFile as readFile19, unlink as unlink4, lstat as
|
|
44519
|
+
import { appendFile as appendFile3, chmod, mkdir as mkdir14, readFile as readFile19, unlink as unlink4, lstat as lstat8, rename as rename8 } from "node:fs/promises";
|
|
44342
44520
|
import net4 from "node:net";
|
|
44343
44521
|
import os9 from "node:os";
|
|
44344
44522
|
|
|
44345
44523
|
// packages/client/src/index.js
|
|
44346
44524
|
import { spawn as spawn8 } from "node:child_process";
|
|
44347
|
-
import { createHash as createHash8 } from "node:crypto";
|
|
44348
|
-
import { open as open3, readFile as readFile18, realpath as realpath4, stat as stat6, lstat as lstat4, mkdir as mkdir12, readlink, unlink as unlink3 } from "node:fs/promises";
|
|
44525
|
+
import { createHash as createHash8, randomUUID as randomUUID12 } from "node:crypto";
|
|
44526
|
+
import { open as open3, readFile as readFile18, writeFile as writeFile14, realpath as realpath4, stat as stat6, lstat as lstat4, mkdir as mkdir12, readlink, unlink as unlink3, readdir as readdir8, rename as rename6, rmdir as rmdir2, link } from "node:fs/promises";
|
|
44349
44527
|
import net3 from "node:net";
|
|
44350
44528
|
import os8 from "node:os";
|
|
44351
44529
|
import path30 from "node:path";
|
|
@@ -45129,10 +45307,86 @@ async function tail(file3, lines = 30) {
|
|
|
45129
45307
|
return "";
|
|
45130
45308
|
}
|
|
45131
45309
|
}
|
|
45310
|
+
async function lifecycleOwners(home) {
|
|
45311
|
+
const directory = path30.join(home, "state", "alpd.starting");
|
|
45312
|
+
const names = await readdir8(directory).catch((error51) => {
|
|
45313
|
+
if (error51.code === "ENOENT") return [];
|
|
45314
|
+
throw error51;
|
|
45315
|
+
});
|
|
45316
|
+
return names.map((token) => {
|
|
45317
|
+
const match = /^owner-(\d+)-(\d+)-(start|stop)-[a-f0-9-]+$/.exec(token);
|
|
45318
|
+
if (!match) throw new Error("Invalid alpd startup admission owner");
|
|
45319
|
+
return { token, pid: Number(match[1]), bootTime: Number(match[2]), action: match[3] };
|
|
45320
|
+
});
|
|
45321
|
+
}
|
|
45322
|
+
async function readDaemonLifecycle(home) {
|
|
45323
|
+
return (await lifecycleOwners(home)).find((owner) => lockAlive(owner));
|
|
45324
|
+
}
|
|
45325
|
+
async function withDaemonLifecycle(home, action, run3, { joinStart = false } = {}) {
|
|
45326
|
+
try {
|
|
45327
|
+
await assertPrivateDirectory(home, { create: true });
|
|
45328
|
+
} catch (cause) {
|
|
45329
|
+
throw Object.assign(new Error(`ALP_HOME_UNUSABLE, alpd failed to start while preparing its home: ${cause.message}`, { cause }), { code: "ALP_HOME_UNUSABLE" });
|
|
45330
|
+
}
|
|
45331
|
+
const state = path30.join(home, "state");
|
|
45332
|
+
await assertPrivateDirectory(state, { create: true });
|
|
45333
|
+
const directory = path30.join(state, "alpd.starting");
|
|
45334
|
+
const token = `owner-${process.pid}-${bootTime()}-${action}-${randomUUID12()}`;
|
|
45335
|
+
const candidate = path30.join(state, `alpd.starting-${token}`);
|
|
45336
|
+
await mkdir12(candidate, { mode: 448 });
|
|
45337
|
+
await writeFile14(path30.join(candidate, token), JSON.stringify({ pid: process.pid, bootTime: bootTime(), action }), { mode: 384 });
|
|
45338
|
+
try {
|
|
45339
|
+
let joined = false;
|
|
45340
|
+
if (joinStart) {
|
|
45341
|
+
const owner = await readDaemonLifecycle(home);
|
|
45342
|
+
if (owner?.action === "start") {
|
|
45343
|
+
try {
|
|
45344
|
+
await link(path30.join(directory, owner.token), path30.join(directory, token));
|
|
45345
|
+
joined = true;
|
|
45346
|
+
} catch (error51) {
|
|
45347
|
+
if (error51.code !== "ENOENT") throw error51;
|
|
45348
|
+
}
|
|
45349
|
+
}
|
|
45350
|
+
}
|
|
45351
|
+
while (!joined) {
|
|
45352
|
+
try {
|
|
45353
|
+
await rename6(candidate, directory);
|
|
45354
|
+
break;
|
|
45355
|
+
} catch (error51) {
|
|
45356
|
+
if (!["EEXIST", "ENOTEMPTY", "EPERM", "EACCES"].includes(error51.code)) throw error51;
|
|
45357
|
+
for (const owner of await lifecycleOwners(home)) {
|
|
45358
|
+
if (!lockAlive(owner)) await unlink3(path30.join(directory, owner.token)).catch((error52) => {
|
|
45359
|
+
if (error52.code !== "ENOENT") throw error52;
|
|
45360
|
+
});
|
|
45361
|
+
}
|
|
45362
|
+
await rmdir2(directory).catch((error52) => {
|
|
45363
|
+
if (!["ENOENT", "ENOTEMPTY", "EEXIST"].includes(error52.code)) throw error52;
|
|
45364
|
+
});
|
|
45365
|
+
await new Promise((resolve2) => setTimeout(resolve2, 25));
|
|
45366
|
+
}
|
|
45367
|
+
}
|
|
45368
|
+
try {
|
|
45369
|
+
return await run3();
|
|
45370
|
+
} finally {
|
|
45371
|
+
await unlink3(path30.join(directory, token));
|
|
45372
|
+
await rmdir2(directory).catch((error51) => {
|
|
45373
|
+
if (!["ENOENT", "ENOTEMPTY", "EEXIST"].includes(error51.code)) throw error51;
|
|
45374
|
+
});
|
|
45375
|
+
}
|
|
45376
|
+
} finally {
|
|
45377
|
+
await unlink3(path30.join(candidate, token)).catch((error51) => {
|
|
45378
|
+
if (error51.code !== "ENOENT") throw error51;
|
|
45379
|
+
});
|
|
45380
|
+
await rmdir2(candidate).catch((error51) => {
|
|
45381
|
+
if (error51.code !== "ENOENT") throw error51;
|
|
45382
|
+
});
|
|
45383
|
+
}
|
|
45384
|
+
}
|
|
45132
45385
|
async function ensureDaemon({ home = alpHome(), entry = (
|
|
45133
45386
|
/** @type {string | undefined} */
|
|
45134
45387
|
void 0
|
|
45135
|
-
), env = process.env, execPath = process.execPath, timeoutMs = 15e3 } = {}) {
|
|
45388
|
+
), env = process.env, execPath = process.execPath, timeoutMs = 15e3, lifecycleLocked = false } = {}) {
|
|
45389
|
+
if (!lifecycleLocked) return withDaemonLifecycle(home, "start", () => ensureDaemon({ home, entry, env, execPath, timeoutMs, lifecycleLocked: true }));
|
|
45136
45390
|
const ready = async () => {
|
|
45137
45391
|
const lock = await readLock(home);
|
|
45138
45392
|
return lockAlive(lock) && lock.ready ? lock.socket : void 0;
|
|
@@ -45145,7 +45399,7 @@ async function ensureDaemon({ home = alpHome(), entry = (
|
|
|
45145
45399
|
entry ??= await findDaemonEntry({ home, env });
|
|
45146
45400
|
if (!entry) throw new Error("ALP daemon is not running and alpd.js was not found. Install the ALP CLI and run `alp daemon start`, or set ALP_DAEMON_ENTRY to alpd.js");
|
|
45147
45401
|
await new Promise((resolve2, reject) => {
|
|
45148
|
-
const launcher = spawn8(execPath, [entry, "--detach"], {
|
|
45402
|
+
const launcher = spawn8(execPath, [entry, "--detach", `--startup-timeout=${timeoutMs}`], {
|
|
45149
45403
|
env: { ...env, ALP_HOME: home, ELECTRON_RUN_AS_NODE: "1" },
|
|
45150
45404
|
stdio: ["ignore", "ignore", "pipe"],
|
|
45151
45405
|
windowsHide: true
|
|
@@ -45173,7 +45427,7 @@ ${log3}` : ""}`);
|
|
|
45173
45427
|
import path35 from "node:path";
|
|
45174
45428
|
|
|
45175
45429
|
// packages/protocol/src/contract-v1.js
|
|
45176
|
-
var METHODS_V1 = { "$schema": "http://json-schema.org/draft-07/schema#", "$id": "https://alp.dev/schemas/methods-v1.json", "protocolVersion": 1, "errors": { "parseError": -32700, "invalidRequest": -32600, "methodNotFound": -32601, "invalidParams": -32602, "failed": 1e3, "notFound": 1001, "forbidden": 1003, "conflict": 1004, "unavailable": 1005, "protocol": 1006 }, "capabilities": { "attach.after": "session.attach accepts `after` and answers `cursor`/`reset`; envelopes kept in a tree timeline carry `cursor`.", "prompt.receipts": "session.prompt is answered at most once per (sessionId, clientMessageId) from a durable receipt; repeats answer the first outcome or outcome_unknown.", "extension.methods": "extension.register/unregister, and the daemon sends extension.invoke requests to the owning connection.", "team": "team.list: the teams a project can use, from the daemon host's built-ins, library and project.", "task": "task.list, task.create, task.update and task.gate.resolve on a project's .alp/tasks, written by the daemon under the task lock.", "library": "library.list/get/save/delete/duplicate/rename, library.skills.set and library.models on the daemon user's library and a project's .alp overrides; secrets are redacted on read.", "settings.language": "settings.language.get/set: the language the daemon user reads, in the daemon's ALP_HOME/settings.json.", "session.list.page": "session.list accepts `limit`, `cursor` and `query` and answers `nextCursor` while more sessions follow; without them it answers every session as before.", "question.watch": "question.watch: the connection is told of `question` and `question.resolved` in every tree (of a projectRoot when given), attached or not.", "question.watch.turns": "question.watch accepts `turns`: the connection is also told of `turn.ended` of every root in the trees it watches.", "workspace.files": "workspace.files.search: files under a directory whose relative path matches a query; read-only, names only, links never followed.", "workspace.files.read": "workspace.files.list and workspace.files.read: the entries of a directory and the content of a UTF-8 text file (at most 1 MiB) under a directory; read-only, links never followed, .git, .env* and key or credential files refused, .gitignore'd paths hidden unless asked.", "prompt.images": 'session.prompt takes inline image parts { type: "image", mimeType, data } (base64, no paths or URLs) within the image limits; a session snapshot says whether its runtime takes them in promptImages.' }, "methods": { "assignment.recall": { "x-alp": { "effect": "mutation", "scope": { "kind": "project", "param": "projectRoot", "required": false, "alternatives": ["assignmentId", "taskId"] }, "idempotent": false, "risks": ["model call"] }, "params": { "type": "object", "properties": { "assignmentId": { "type": "string" }, "taskId": { "type": "string" }, "projectRoot": { "type": "string" }, "question": { "type": "string" } }, "required": ["question"], "additionalProperties": true }, "result": { "type": "object", "properties": { "assignmentId": { "type": "string" }, "agent": { "type": "string" }, "taskId": { "type": "string" }, "finishedAt": { "type": "string" }, "answer": { "type": "string" } }, "required": ["assignmentId", "agent", "finishedAt", "answer"], "additionalProperties": true } }, "board.list": { "x-alp": { "effect": "query", "scope": { "kind": "project", "param": "projectRoot", "required": true }, "idempotent": true }, "params": { "type": "object", "properties": { "projectRoot": { "type": "string" } }, "required": ["projectRoot"], "additionalProperties": true }, "result": { "type": "object", "properties": { "pins": { "type": "array", "items": { "$ref": "#/$defs/pin" } } }, "required": ["pins"], "additionalProperties": true } }, "catalog.get": { "x-alp": { "effect": "query", "scope": { "kind": "host" }, "idempotent": true }, "params": { "type": "object", "properties": {}, "required": [], "additionalProperties": true }, "result": { "type": "object", "properties": { "models": { "type": "array", "items": { "type": "object" } }, "modes": { "type": "array", "items": { "type": "object" } }, "thinkingOptions": {}, "defaultModel": { "type": "string" } }, "required": ["models", "modes", "defaultModel"], "additionalProperties": true } }, "daemon.hello": { "x-alp": { "effect": "query", "scope": { "kind": "connection" }, "idempotent": true }, "params": { "type": "object", "properties": { "protocolVersion": { "const": 1 }, "client": { "type": "object", "properties": { "name": { "type": "string" }, "version": { "type": "string" } }, "required": ["name", "version"], "additionalProperties": true }, "capabilities": { "type": "array", "items": { "type": "string" } } }, "required": ["protocolVersion"], "additionalProperties": true }, "result": { "type": "object", "properties": { "protocolVersion": { "const": 1 }, "daemonVersion": { "type": "string" }, "pid": { "type": "integer" }, "hostname": { "type": "string" }, "capabilities": { "type": "array", "items": { "type": "string" } } }, "required": ["protocolVersion"], "additionalProperties": true } }, "daemon.pause": { "x-alp": { "effect": "mutation", "scope": { "kind": "host" }, "idempotent": true, "risks": ["admin"] }, "params": { "type": "object", "properties": { "runtime": { "enum": ["codex", "claude", "acp", "antigravity"] }, "now": { "type": "boolean" }, "reason": { "type": "string" } }, "required": [], "additionalProperties": true }, "result": { "$ref": "#/$defs/pauseState" } }, "daemon.pauses": { "x-alp": { "effect": "query", "scope": { "kind": "host" }, "idempotent": true }, "params": { "type": "object", "properties": {}, "required": [], "additionalProperties": true }, "result": { "$ref": "#/$defs/pauseState" } }, "daemon.resume": { "x-alp": { "effect": "mutation", "scope": { "kind": "host" }, "idempotent": true, "risks": ["admin"] }, "params": { "type": "object", "properties": { "runtime": { "enum": ["codex", "claude", "acp", "antigravity"] } }, "required": [], "additionalProperties": true }, "result": { "$ref": "#/$defs/pauseState" } }, "daemon.shutdown": { "x-alp": { "effect": "mutation", "scope": { "kind": "host" }, "idempotent": true, "risks": ["admin"] }, "params": { "type": "object", "properties": {}, "required": [], "additionalProperties": true }, "result": { "type": "object", "properties": {}, "required": [], "additionalProperties": true } }, "daemon.status": { "x-alp": { "effect": "query", "scope": { "kind": "host" }, "idempotent": true }, "params": { "type": "object", "properties": {}, "required": [], "additionalProperties": true }, "result": { "type": "object", "properties": { "pid": { "type": "integer" }, "startedAt": { "type": "string" }, "version": { "type": "string" }, "protocolVersion": { "type": "integer" }, "sessions": { "type": "integer" }, "questions": { "type": "integer" }, "previousExit": { "type": "object", "properties": { "kind": { "enum": ["clean", "crash"] }, "at": { "type": "string" } }, "required": ["kind"], "additionalProperties": true }, "persistence": { "type": "object" }, "health": { "$ref": "#/$defs/health" } }, "required": ["pid", "startedAt", "version", "protocolVersion", "sessions", "questions", "health"], "additionalProperties": true } }, "daemon.usage": { "x-alp": { "effect": "query", "scope": { "kind": "host" }, "idempotent": true, "risks": ["refresh asks every provider (spawns on the daemon host)"] }, "params": { "type": "object", "properties": { "refresh": { "type": "boolean" } }, "required": [], "additionalProperties": true }, "result": { "type": "object", "properties": { "providers": { "type": "array", "items": { "type": "object" } } }, "required": ["providers"], "additionalProperties": true } }, "extension.register": { "x-alp": { "effect": "mutation", "scope": { "kind": "connection" }, "idempotent": false, "risks": ["admin"] }, "params": { "type": "object", "properties": { "method": { "type": "string" } }, "required": ["method"], "additionalProperties": true }, "result": { "type": "object", "properties": { "registered": { "type": "string" } }, "required": ["registered"], "additionalProperties": true } }, "extension.unregister": { "x-alp": { "effect": "mutation", "scope": { "kind": "connection" }, "idempotent": false, "risks": ["admin"] }, "params": { "type": "object", "properties": { "method": { "type": "string" } }, "required": ["method"], "additionalProperties": true }, "result": { "type": "object", "properties": { "unregistered": { "type": "string" } }, "required": ["unregistered"], "additionalProperties": true } }, "library.delete": { "x-alp": { "effect": "mutation", "capability": "library", "scope": { "kind": "library-or-project", "param": "projectRoot", "selector": "scope" }, "idempotent": false }, "params": { "type": "object", "properties": { "kind": { "$ref": "#/$defs/libraryKind" }, "name": { "$ref": "#/$defs/entryName" }, "scope": { "$ref": "#/$defs/libraryScope" }, "projectRoot": { "$ref": "#/$defs/projectRoot" }, "revision": { "type": "string" } }, "required": ["kind", "name", "scope"], "additionalProperties": true }, "result": { "type": "object", "properties": { "removed": { "const": true }, "now": { "enum": ["builtin", "library"] } }, "required": ["removed"], "additionalProperties": true } }, "library.duplicate": { "x-alp": { "effect": "mutation", "capability": "library", "scope": { "kind": "library-or-project", "param": "projectRoot", "selector": "scope", "reads": ["builtin", "library"] }, "idempotent": false, "risks": ["exec-config when kind is mcp, hooks or providers"] }, "params": { "type": "object", "properties": { "kind": { "$ref": "#/$defs/libraryKind" }, "from": { "$ref": "#/$defs/entryName" }, "to": { "$ref": "#/$defs/entryName" }, "scope": { "$ref": "#/$defs/libraryScope" }, "projectRoot": { "$ref": "#/$defs/projectRoot" } }, "required": ["kind", "from", "to", "scope"], "additionalProperties": true }, "result": { "type": "object", "properties": { "revision": { "$ref": "#/$defs/libraryRevision" } }, "required": ["revision"], "additionalProperties": true } }, "library.get": { "x-alp": { "effect": "query", "capability": "library", "scope": { "kind": "project", "param": "projectRoot", "required": false, "reads": ["builtin", "library"] }, "idempotent": true, "redacts": ["mcp /server/env/*", "mcp /server/headers/*", "providers /provider/env/*"] }, "params": { "type": "object", "properties": { "kind": { "$ref": "#/$defs/libraryKind" }, "name": { "$ref": "#/$defs/entryName" }, "projectRoot": { "$ref": "#/$defs/projectRoot" }, "scope": { "$ref": "#/$defs/libraryScope" } }, "required": ["kind", "name"], "additionalProperties": true }, "result": { "type": "object", "properties": { "kind": { "$ref": "#/$defs/libraryKind" }, "name": { "type": "string" }, "source": { "$ref": "#/$defs/librarySource" }, "overrides": { "$ref": "#/$defs/librarySource" }, "content": { "type": "object" }, "revision": { "$ref": "#/$defs/libraryRevision" }, "usedBy": { "type": "array", "items": { "type": "string" } }, "librarySkills": { "type": "array", "items": { "type": "string" } }, "secrets": { "type": "array", "items": { "type": "string" } } }, "required": ["kind", "name", "source", "content", "revision", "usedBy"], "additionalProperties": true } }, "library.list": { "x-alp": { "effect": "query", "capability": "library", "scope": { "kind": "project", "param": "projectRoot", "required": false, "reads": ["builtin", "library"] }, "idempotent": true }, "params": { "type": "object", "properties": { "kind": { "$ref": "#/$defs/libraryKind" }, "projectRoot": { "$ref": "#/$defs/projectRoot" } }, "required": ["kind"], "additionalProperties": true }, "result": { "type": "object", "properties": { "projectRoot": { "type": ["string", "null"] }, "entries": { "type": "array", "items": { "$ref": "#/$defs/libraryEntryRow" } } }, "required": ["projectRoot", "entries"], "additionalProperties": true } }, "library.models": { "x-alp": { "effect": "query", "capability": "library", "scope": { "kind": "host" }, "idempotent": true }, "params": { "type": "object", "properties": {}, "required": [], "additionalProperties": true }, "result": { "type": "object", "properties": { "models": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "label": { "type": "string" }, "efforts": { "type": "array", "items": { "type": "string" } }, "effort": { "type": "string" } }, "required": ["id", "label", "efforts"], "additionalProperties": true } } }, "required": ["models"], "additionalProperties": true } }, "library.rename": { "x-alp": { "effect": "mutation", "capability": "library", "scope": { "kind": "library-or-project", "param": "projectRoot", "selector": "scope" }, "idempotent": false, "risks": ["exec-config when kind is mcp, hooks or providers"] }, "params": { "type": "object", "properties": { "kind": { "$ref": "#/$defs/libraryKind" }, "from": { "$ref": "#/$defs/entryName" }, "to": { "$ref": "#/$defs/entryName" }, "scope": { "$ref": "#/$defs/libraryScope" }, "projectRoot": { "$ref": "#/$defs/projectRoot" } }, "required": ["kind", "from", "to", "scope"], "additionalProperties": true }, "result": { "type": "object", "properties": { "revision": { "$ref": "#/$defs/libraryRevision" } }, "required": ["revision"], "additionalProperties": true } }, "library.save": { "x-alp": { "effect": "mutation", "capability": "library", "scope": { "kind": "library-or-project", "param": "projectRoot", "selector": "scope" }, "idempotent": "with revision (a repeat fails revision_conflict)", "risks": ["exec-config when kind is mcp, hooks or providers, or agents naming mcp/hooks/provider", "writes every known project's .alp/settings.json when kind is teams and sync is known-projects"] }, "params": { "type": "object", "properties": { "kind": { "$ref": "#/$defs/libraryKind" }, "name": { "$ref": "#/$defs/entryName" }, "scope": { "$ref": "#/$defs/libraryScope" }, "projectRoot": { "$ref": "#/$defs/projectRoot" }, "content": { "type": "object" }, "revision": { "$ref": "#/$defs/libraryRevision" }, "sync": { "enum": ["none", "known-projects"] } }, "required": ["kind", "name", "scope", "content"], "additionalProperties": true }, "result": { "type": "object", "properties": { "revision": { "$ref": "#/$defs/libraryRevision" }, "syncedProjects": { "type": "integer", "minimum": 0 }, "syncErrors": { "type": "array", "items": { "type": "string" } } }, "required": ["revision"], "additionalProperties": true } }, "library.skills.set": { "x-alp": { "effect": "mutation", "capability": "library", "scope": { "kind": "host" }, "writes": ["ALP_HOME/role-skills.json"], "idempotent": true }, "params": { "type": "object", "properties": { "agent": { "$ref": "#/$defs/entryName" }, "skills": { "type": "array", "items": { "$ref": "#/$defs/entryName" }, "maxItems": 100 } }, "required": ["agent", "skills"], "additionalProperties": true }, "result": { "type": "object", "properties": { "skills": { "type": "array", "items": { "type": "string" } } }, "required": ["skills"], "additionalProperties": true } }, "question.answer": { "x-alp": { "effect": "mutation", "scope": { "kind": "question", "param": "questionId", "prefix": true }, "idempotent": false }, "params": { "type": "object", "properties": { "questionId": { "type": "string" }, "text": { "type": "string" }, "dismiss": { "type": "boolean" }, "reason": { "type": "string" } }, "required": ["questionId"], "additionalProperties": true }, "result": { "type": "object", "properties": { "questionId": { "type": "string" } }, "required": ["questionId"], "additionalProperties": true } }, "question.list": { "x-alp": { "effect": "query", "scope": { "kind": "project", "param": "projectRoot", "required": false }, "idempotent": true }, "params": { "type": "object", "properties": { "projectRoot": { "type": "string" } }, "required": [], "additionalProperties": true }, "result": { "type": "object", "properties": { "questions": { "type": "array", "items": { "$ref": "#/$defs/question" } } }, "required": ["questions"], "additionalProperties": true } }, "question.watch": { "x-alp": { "effect": "query", "scope": { "kind": "project", "param": "projectRoot", "required": false }, "idempotent": true, "capability": "question.watch" }, "params": { "type": "object", "properties": { "projectRoot": { "type": "string" }, "turns": { "type": "boolean" } }, "required": [], "additionalProperties": true }, "result": { "type": "object", "properties": { "questions": { "type": "array", "items": { "$ref": "#/$defs/question" } } }, "required": ["questions"], "additionalProperties": true } }, "session.archive": { "x-alp": { "effect": "mutation", "scope": { "kind": "session", "param": "sessionId" }, "idempotent": true }, "params": { "type": "object", "properties": { "sessionId": { "type": "string" }, "archived": { "type": "boolean" } }, "required": ["sessionId"], "additionalProperties": true }, "result": { "type": "object", "properties": { "session": { "$ref": "#/$defs/sessionSummary" } }, "required": ["session"], "additionalProperties": true } }, "session.attach": { "x-alp": { "effect": "query", "scope": { "kind": "session", "param": "sessionId" }, "idempotent": true }, "params": { "type": "object", "properties": { "sessionId": { "type": "string" }, "replay": { "type": "boolean" }, "after": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 } }, "required": ["sessionId"], "additionalProperties": true }, "result": { "type": "object", "properties": { "session": { "$ref": "#/$defs/sessionSummary" }, "cursor": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 }, "reset": { "const": true } }, "required": ["session", "cursor"], "additionalProperties": true } }, "session.close": { "x-alp": { "effect": "mutation", "scope": { "kind": "session", "param": "sessionId" }, "idempotent": false }, "params": { "type": "object", "properties": { "sessionId": { "type": "string" } }, "required": ["sessionId"], "additionalProperties": true }, "result": { "type": "object", "properties": {}, "required": [], "additionalProperties": true } }, "session.configure": { "x-alp": { "effect": "mutation", "scope": { "kind": "session", "param": "sessionId" }, "idempotent": true }, "params": { "type": "object", "properties": { "sessionId": { "type": "string" }, "mode": { "type": "string" } }, "required": ["sessionId"], "additionalProperties": true }, "result": { "type": "object", "properties": { "session": { "$ref": "#/$defs/session" } }, "required": ["session"], "additionalProperties": true } }, "session.create": { "x-alp": { "effect": "mutation", "scope": { "kind": "project", "param": "spec.cwd" }, "idempotent": false, "risks": ["exec: spec.env and stdio spec.mcpServers run on the daemon host", "spec.workdir/writeRoot/copy*/restore/keepThread are internal"] }, "params": { "type": "object", "properties": { "sessionId": { "type": "string", "pattern": "^[A-Za-z0-9_.:-]{1,128}$" }, "spec": { "$ref": "#/$defs/spec" }, "history": { "enum": ["skip", "replay"] }, "delegation": { "type": "boolean" }, "resume": { "type": "boolean" } }, "required": ["spec"], "additionalProperties": true }, "result": { "type": "object", "properties": { "session": { "$ref": "#/$defs/session" }, "attached": { "type": "boolean" }, "resumed": { "const": true }, "durable": { "type": "boolean" } }, "required": ["session", "attached"], "additionalProperties": true } }, "session.get": { "x-alp": { "effect": "query", "scope": { "kind": "session", "param": "sessionId" }, "idempotent": true }, "params": { "type": "object", "properties": { "sessionId": { "type": "string" } }, "required": ["sessionId"], "additionalProperties": true }, "result": { "type": "object", "properties": { "session": { "$ref": "#/$defs/sessionSummary" } }, "required": ["session"], "additionalProperties": true } }, "session.interrupt": { "x-alp": { "effect": "mutation", "scope": { "kind": "session", "param": "sessionId" }, "idempotent": true }, "params": { "type": "object", "properties": { "sessionId": { "type": "string" } }, "required": ["sessionId"], "additionalProperties": true }, "result": { "type": "object", "properties": {}, "required": [], "additionalProperties": true } }, "session.list": { "x-alp": { "effect": "query", "scope": { "kind": "project", "param": "projectRoot", "required": false }, "idempotent": true }, "params": { "type": "object", "properties": { "projectRoot": { "type": "string" }, "rootsOnly": { "type": "boolean" }, "includeClosed": { "type": "boolean" }, "includeArchived": { "type": "boolean" }, "limit": { "type": "integer", "minimum": 1, "maximum": 1e3 }, "cursor": { "type": "string", "minLength": 1, "maxLength": 1024 }, "query": { "type": "string", "maxLength": 200 }, "projectRoots": { "type": "array", "items": { "type": "string" }, "minItems": 1, "maxItems": 1024 } }, "required": [], "additionalProperties": true }, "result": { "type": "object", "properties": { "sessions": { "type": "array", "items": { "$ref": "#/$defs/sessionSummary" } }, "nextCursor": { "type": "string", "minLength": 1 } }, "required": ["sessions"], "additionalProperties": true } }, "session.log": { "x-alp": { "effect": "query", "scope": { "kind": "session", "param": "sessionId" }, "idempotent": true }, "params": { "type": "object", "properties": { "sessionId": { "type": "string" } }, "required": ["sessionId"], "additionalProperties": true }, "result": { "type": "object", "properties": { "rootId": { "type": "string" }, "entries": { "type": "array", "items": { "type": "object" } } }, "required": ["rootId", "entries"], "additionalProperties": true } }, "session.message": { "x-alp": { "effect": "mutation", "scope": { "kind": "session", "param": "sessionId" }, "idempotent": false }, "params": { "type": "object", "properties": { "sessionId": { "type": "string" }, "text": { "type": "string" } }, "required": ["sessionId", "text"], "additionalProperties": true }, "result": { "type": "object", "properties": {}, "required": [], "additionalProperties": true } }, "session.preview": { "x-alp": { "effect": "query", "scope": { "kind": "project", "param": "spec.cwd" }, "idempotent": true }, "params": { "type": "object", "properties": { "spec": { "$ref": "#/$defs/spec" } }, "required": ["spec"], "additionalProperties": true }, "result": { "type": "object", "properties": { "preview": { "$ref": "#/$defs/preview" } }, "required": ["preview"], "additionalProperties": true } }, "session.prompt": { "x-alp": { "effect": "mutation", "scope": { "kind": "session", "param": "sessionId" }, "idempotent": "with prompt.receipts" }, "params": { "type": "object", "properties": { "sessionId": { "type": "string" }, "clientMessageId": { "type": "string" }, "delivery": { "enum": ["auto", "steer"] }, "content": { "type": "array", "items": { "anyOf": [{ "type": "object", "properties": { "type": { "const": "text" }, "text": { "type": "string" } }, "required": ["type"], "additionalProperties": true }, { "$ref": "#/$defs/promptImage" }, { "type": "object", "properties": { "type": { "type": "string", "not": { "enum": ["text", "image"] } } }, "required": ["type"], "additionalProperties": true }] } } }, "required": ["sessionId", "clientMessageId", "content"], "additionalProperties": true }, "result": { "type": "object", "properties": { "outcome": { "enum": ["accepted", "failed"] }, "error": { "$ref": "#/$defs/alpError" }, "duplicate": { "type": "boolean" }, "durable": { "type": "boolean" } }, "required": [], "additionalProperties": true } }, "session.release": { "x-alp": { "effect": "mutation", "scope": { "kind": "session", "param": "sessionId" }, "idempotent": true }, "params": { "type": "object", "properties": { "sessionId": { "type": "string" } }, "required": ["sessionId"], "additionalProperties": true }, "result": { "type": "object", "properties": { "closed": { "type": "boolean" } }, "required": ["closed"], "additionalProperties": true } }, "session.rename": { "x-alp": { "effect": "mutation", "scope": { "kind": "session", "param": "sessionId" }, "idempotent": true }, "params": { "type": "object", "properties": { "sessionId": { "type": "string" }, "title": { "type": "string", "minLength": 1, "maxLength": 200, "pattern": "\\S" } }, "required": ["sessionId", "title"], "additionalProperties": true }, "result": { "type": "object", "properties": { "session": { "$ref": "#/$defs/sessionSummary" } }, "required": ["session"], "additionalProperties": true } }, "session.status": { "x-alp": { "effect": "query", "scope": { "kind": "session", "param": "sessionId" }, "idempotent": true }, "params": { "type": "object", "properties": { "sessionId": { "type": "string" } }, "required": ["sessionId"], "additionalProperties": true }, "result": { "type": "object", "properties": { "status": { "$ref": "#/$defs/treeStatus" } }, "required": ["status"], "additionalProperties": true } }, "settings.language.get": { "x-alp": { "effect": "query", "capability": "settings.language", "scope": { "kind": "host" }, "idempotent": true }, "params": { "type": "object", "properties": {}, "required": [], "additionalProperties": true }, "result": { "$ref": "#/$defs/languageSetting" } }, "settings.language.set": { "x-alp": { "effect": "mutation", "capability": "settings.language", "scope": { "kind": "host" }, "writes": ["ALP_HOME/settings.json"], "idempotent": true }, "params": { "type": "object", "properties": { "language": { "anyOf": [{ "type": "string", "minLength": 1, "maxLength": 40, "pattern": "\\S" }, { "type": "null" }] } }, "required": ["language"], "additionalProperties": true }, "result": { "$ref": "#/$defs/languageSetting" } }, "task.create": { "x-alp": { "effect": "mutation", "capability": "task", "scope": { "kind": "project", "param": "projectRoot", "required": true }, "writes": ["<projectRoot>/.alp/tasks"], "idempotent": "per requestId within one alpd process (10 minutes)" }, "params": { "type": "object", "properties": { "projectRoot": { "$ref": "#/$defs/projectRoot" }, "title": { "type": "string", "minLength": 1, "maxLength": 200, "pattern": "\\S" }, "priority": { "type": "integer", "minimum": 0, "maximum": 4 }, "requestId": { "type": "string", "minLength": 1, "maxLength": 128 } }, "required": ["projectRoot", "title"], "additionalProperties": true }, "result": { "type": "object", "properties": { "id": { "$ref": "#/$defs/taskId" }, "duplicate": { "const": true } }, "required": ["id"], "additionalProperties": true } }, "task.gate.resolve": { "x-alp": { "effect": "mutation", "capability": "task", "scope": { "kind": "project", "param": "projectRoot", "required": true }, "writes": ["<projectRoot>/.alp/tasks"], "idempotent": false }, "params": { "type": "object", "properties": { "projectRoot": { "$ref": "#/$defs/projectRoot" }, "id": { "$ref": "#/$defs/taskId" }, "gate": { "type": "string", "minLength": 1, "maxLength": 128 }, "note": { "type": "string", "maxLength": 2e3 }, "ifRev": { "type": "integer", "minimum": 0 } }, "required": ["projectRoot", "id", "gate"], "additionalProperties": true }, "result": { "type": "object", "properties": { "id": { "$ref": "#/$defs/taskId" }, "status": { "type": "string" }, "rev": { "type": "integer", "minimum": 0 } }, "required": ["id", "status", "rev"], "additionalProperties": true } }, "task.list": { "x-alp": { "effect": "query", "capability": "task", "scope": { "kind": "project", "param": "projectRoot", "required": true }, "idempotent": true }, "params": { "type": "object", "properties": { "projectRoot": { "$ref": "#/$defs/projectRoot" } }, "required": ["projectRoot"], "additionalProperties": true }, "result": { "type": "object", "properties": { "projectRoot": { "type": "string" }, "tasks": { "type": "array", "items": { "$ref": "#/$defs/taskRow" } }, "unreadable": { "type": "array", "items": { "type": "object", "properties": { "file": { "type": "string" }, "error": { "type": "string" } }, "required": ["file", "error"], "additionalProperties": true } }, "revision": { "type": "string" } }, "required": ["projectRoot", "tasks", "unreadable", "revision"], "additionalProperties": true } }, "task.update": { "x-alp": { "effect": "mutation", "capability": "task", "scope": { "kind": "project", "param": "projectRoot", "required": true }, "writes": ["<projectRoot>/.alp/tasks"], "idempotent": false }, "params": { "type": "object", "properties": { "projectRoot": { "$ref": "#/$defs/projectRoot" }, "id": { "$ref": "#/$defs/taskId" }, "action": { "enum": ["close", "reopen"] }, "note": { "type": "string", "maxLength": 2e3 }, "ifRev": { "type": "integer", "minimum": 0 } }, "required": ["projectRoot", "id", "action"], "additionalProperties": true }, "result": { "type": "object", "properties": { "id": { "$ref": "#/$defs/taskId" }, "status": { "type": "string" }, "rev": { "type": "integer", "minimum": 0 }, "landed": { "type": "string" } }, "required": ["id", "status", "rev"], "additionalProperties": true } }, "team.list": { "x-alp": { "effect": "query", "capability": "team", "scope": { "kind": "project", "param": "projectRoot", "required": false, "reads": ["builtin", "library"] }, "idempotent": true }, "params": { "type": "object", "properties": { "projectRoot": { "$ref": "#/$defs/projectRoot" } }, "required": [], "additionalProperties": true }, "result": { "type": "object", "properties": { "projectRoot": { "type": ["string", "null"] }, "teams": { "type": "array", "items": { "$ref": "#/$defs/teamRow" } } }, "required": ["projectRoot", "teams"], "additionalProperties": true } }, "workspace.files.search": { "x-alp": { "effect": "query", "scope": { "kind": "project", "param": "projectRoot", "required": true }, "idempotent": true, "capability": "workspace.files", "risks": ["lists file names of the directory (not contents)"] }, "params": { "type": "object", "properties": { "projectRoot": { "type": "string" }, "query": { "type": "string", "maxLength": 200 }, "limit": { "type": "integer", "minimum": 1, "maximum": 100 } }, "required": ["projectRoot"], "additionalProperties": true }, "result": { "type": "object", "properties": { "files": { "type": "array", "maxItems": 100, "items": { "type": "object", "properties": { "path": { "type": "string", "minLength": 1 } }, "required": ["path"], "additionalProperties": true } }, "truncated": { "type": "boolean" } }, "required": ["files"], "additionalProperties": true } }, "workspace.files.list": { "x-alp": { "effect": "query", "scope": { "kind": "project", "param": "projectRoot", "required": true }, "idempotent": true, "capability": "workspace.files.read", "risks": ["lists names, kinds, sizes and times of a directory's entries (not contents)"] }, "params": { "type": "object", "properties": { "projectRoot": { "type": "string" }, "path": { "type": "string", "minLength": 1, "maxLength": 4096 }, "includeIgnored": { "type": "boolean" } }, "required": ["projectRoot"], "additionalProperties": true }, "result": { "type": "object", "properties": { "entries": { "type": "array", "maxItems": 1e3, "items": { "type": "object", "properties": { "name": { "type": "string", "minLength": 1 }, "path": { "type": "string", "minLength": 1 }, "kind": { "enum": ["file", "directory"] }, "size": { "type": "integer", "minimum": 0 }, "modifiedAt": { "type": "string" } }, "required": ["name", "path", "kind"], "additionalProperties": true } }, "truncated": { "type": "boolean" } }, "required": ["entries"], "additionalProperties": true } }, "workspace.files.read": { "x-alp": { "effect": "query", "scope": { "kind": "project", "param": "projectRoot", "required": true }, "idempotent": true, "capability": "workspace.files.read", "risks": ["returns the content of a text file under the directory"] }, "params": { "type": "object", "properties": { "projectRoot": { "type": "string" }, "path": { "type": "string", "minLength": 1, "maxLength": 4096 }, "includeIgnored": { "type": "boolean" } }, "required": ["projectRoot", "path"], "additionalProperties": true }, "result": { "type": "object", "properties": { "path": { "type": "string", "minLength": 1 }, "content": { "type": "string" }, "size": { "type": "integer", "minimum": 0, "maximum": 1048576 }, "modifiedAt": { "type": "string" } }, "required": ["path", "content", "size"], "additionalProperties": true } } }, "$defs": { "error": { "type": "object", "properties": { "code": { "type": "integer" }, "message": { "type": "string" }, "data": {} }, "required": ["code", "message"], "additionalProperties": true }, "session": { "type": "object", "properties": { "id": { "type": "string" }, "projectRoot": { "type": "string" }, "agent": { "type": "string" }, "runtime": { "enum": ["claude", "codex", "acp", "antigravity"] }, "model": { "type": "string" }, "mode": { "type": "string" }, "thinking": { "type": "string" }, "workflow": { "type": "object", "properties": { "mode": { "type": "string" }, "maxPeers": { "type": "integer" }, "supervisor": { "type": "boolean" } }, "required": ["mode", "maxPeers", "supervisor"], "additionalProperties": true }, "threadId": { "type": "string" }, "persistent": { "type": "boolean" }, "busy": { "type": "boolean" }, "parentId": { "type": "string" }, "toolCallId": { "type": "string" }, "activeTurnId": { "type": "string" }, "parked": { "type": "string" }, "instructionsSha": { "type": "string" }, "teamLabel": { "type": "string" }, "promptImages": { "type": "boolean" }, "usage": { "$ref": "#/$defs/usage" } }, "required": ["id", "projectRoot", "agent", "runtime", "model", "mode", "thinking", "workflow", "threadId", "persistent", "busy"], "additionalProperties": true }, "usage": { "type": "object", "properties": { "contextWindowUsedTokens": { "type": "integer", "minimum": 0 }, "contextWindowMaxTokens": { "type": "integer", "minimum": 1 }, "inputTokens": { "type": "integer", "minimum": 0 }, "cachedInputTokens": { "type": "integer", "minimum": 0 }, "outputTokens": { "type": "integer", "minimum": 0 }, "totalCostUsd": { "type": "number", "minimum": 0 } }, "additionalProperties": true }, "assignment": { "type": "object", "properties": { "id": { "type": "string" }, "agent": { "type": "string" }, "mode": { "type": "string" }, "status": { "type": "string" }, "startedAt": { "type": "string" }, "worktree": { "type": "object", "properties": { "branch": { "type": "string" }, "path": { "type": "string" } }, "required": ["branch", "path"], "additionalProperties": true } }, "required": ["id", "agent", "mode", "status", "startedAt"], "additionalProperties": true }, "mail": { "type": "object", "properties": { "id": { "type": "string" }, "kind": { "enum": ["question", "answer", "note", "steer", "result", "stalled", "board", "checkin"] }, "from": { "type": "string" }, "assignment": { "type": "string" }, "body": { "type": "string" }, "replyTo": { "type": "string" }, "result": { "type": "object" }, "redelivered": { "type": "boolean" } }, "required": ["id", "kind", "from", "assignment"], "additionalProperties": true }, "pin": { "type": "object", "properties": { "id": { "type": "string" }, "project": { "type": "string" }, "kind": { "enum": ["claim", "decision", "finding"] }, "body": { "type": "string" }, "paths": { "type": "array", "items": { "type": "string" } }, "agent": { "type": "string" }, "sessionId": { "type": "string" }, "rootId": { "type": "string" }, "at": { "type": "string" }, "released": { "type": "string" }, "task": { "type": "string" } }, "required": ["id", "project", "kind", "body", "agent", "sessionId", "rootId", "at"], "additionalProperties": true }, "question": { "type": "object", "properties": { "id": { "type": "string" }, "sessionId": { "type": "string" }, "rootId": { "type": "string" }, "agent": { "type": "string" }, "body": { "type": "string" }, "options": { "type": "array", "items": { "type": "string" } }, "askedAt": { "type": "string" } }, "required": ["id", "sessionId", "rootId", "agent", "body", "askedAt"], "additionalProperties": true }, "spec": { "type": "object", "properties": { "cwd": { "type": "string" }, "agent": { "type": "string" }, "model": { "type": "string" }, "mode": { "type": "string" }, "thinking": { "type": "string" }, "persist": { "type": "boolean" }, "restore": { "type": "object" } }, "required": ["cwd"], "additionalProperties": true }, "item": { "anyOf": [{ "$ref": "#/$defs/knownItem" }, { "$ref": "#/$defs/unknownItem" }] }, "event": { "anyOf": [{ "$ref": "#/$defs/knownEvent" }, { "$ref": "#/$defs/unknownEvent" }] }, "envelope": { "type": "object", "properties": { "sessionId": { "type": "string" }, "epoch": { "type": "string" }, "seq": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 }, "ts": { "type": "string" }, "event": { "$ref": "#/$defs/event" }, "cursor": { "type": "integer", "minimum": 1, "maximum": 9007199254740991 } }, "required": ["sessionId", "epoch", "seq", "ts", "event"], "additionalProperties": true }, "request": { "type": "object", "properties": { "jsonrpc": { "const": "2.0" }, "id": { "anyOf": [{ "type": "string", "maxLength": 128 }, { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }] }, "method": { "type": "string" }, "params": { "type": "object" } }, "required": ["jsonrpc", "method", "id"], "additionalProperties": true }, "response": { "oneOf": [{ "type": "object", "properties": { "jsonrpc": { "const": "2.0" }, "id": { "anyOf": [{ "type": "string", "maxLength": 128 }, { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, { "type": "null" }] }, "result": {} }, "required": ["jsonrpc", "id", "result"], "additionalProperties": true }, { "type": "object", "properties": { "jsonrpc": { "const": "2.0" }, "id": { "anyOf": [{ "type": "string", "maxLength": 128 }, { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, { "type": "null" }] }, "error": { "$ref": "#/$defs/error" } }, "required": ["jsonrpc", "id", "error"], "additionalProperties": true }] }, "notification": { "type": "object", "properties": { "jsonrpc": { "const": "2.0" }, "method": { "const": "event" }, "params": { "$ref": "#/$defs/envelope" } }, "required": ["jsonrpc", "method", "params"], "additionalProperties": true }, "knownEvent": { "oneOf": [{ "type": "object", "properties": { "type": { "const": "session.opened" }, "session": { "$ref": "#/$defs/session" }, "cwd": { "type": "string" }, "effective": { "type": "object", "properties": { "model": { "type": "string" }, "thinking": { "type": "string" } }, "required": ["model", "thinking"], "additionalProperties": true } }, "required": ["type", "session", "cwd", "effective"], "additionalProperties": true }, { "type": "object", "properties": { "type": { "const": "session.ready" } }, "required": ["type"], "additionalProperties": true }, { "type": "object", "properties": { "type": { "const": "session.updated" }, "session": { "$ref": "#/$defs/session" } }, "required": ["type", "session"], "additionalProperties": true }, { "type": "object", "properties": { "type": { "const": "session.closed" } }, "required": ["type"], "additionalProperties": true }, { "type": "object", "properties": { "type": { "const": "session.failed" }, "error": { "$ref": "#/$defs/alpError" } }, "required": ["type", "error"], "additionalProperties": true }, { "type": "object", "properties": { "type": { "const": "prompt.accepted" }, "clientMessageId": { "type": "string" }, "result": { "enum": ["turn", "steer"] }, "turnId": { "type": "string" } }, "required": ["type", "clientMessageId", "result", "turnId"], "additionalProperties": true }, { "type": "object", "properties": { "type": { "const": "prompt.failed" }, "clientMessageId": { "type": "string" }, "error": { "$ref": "#/$defs/alpError" } }, "required": ["type", "clientMessageId", "error"], "additionalProperties": true }, { "type": "object", "properties": { "type": { "const": "turn.started" }, "turnId": { "type": "string" }, "origin": { "enum": ["user", "wake", "assignment", "runtime"] } }, "required": ["type", "turnId", "origin"], "additionalProperties": true }, { "type": "object", "properties": { "type": { "const": "turn.ended" }, "turnId": { "type": "string" }, "state": { "enum": ["completed", "failed", "canceled"] }, "error": { "$ref": "#/$defs/alpError" } }, "required": ["type", "turnId", "state"], "additionalProperties": true }, { "type": "object", "properties": { "type": { "const": "item" }, "item": { "$ref": "#/$defs/item" } }, "required": ["type", "item"], "additionalProperties": true }, { "type": "object", "properties": { "type": { "const": "usage" }, "usage": { "$ref": "#/$defs/usage" } }, "required": ["type", "usage"], "additionalProperties": true }, { "type": "object", "properties": { "type": { "const": "mail" }, "mail": { "$ref": "#/$defs/mail" } }, "required": ["type", "mail"], "additionalProperties": true }, { "type": "object", "properties": { "type": { "const": "assignment" }, "assignment": { "$ref": "#/$defs/assignment" } }, "required": ["type", "assignment"], "additionalProperties": true }, { "type": "object", "properties": { "type": { "const": "question" }, "question": { "$ref": "#/$defs/question" } }, "required": ["type", "question"], "additionalProperties": true }, { "type": "object", "properties": { "type": { "const": "question.resolved" }, "questionId": { "type": "string" }, "outcome": { "enum": ["answered", "dismissed", "timeout", "canceled"] }, "answer": { "type": "string" } }, "required": ["type", "questionId", "outcome"], "additionalProperties": true }, { "type": "object", "properties": { "type": { "const": "pin" }, "pin": { "$ref": "#/$defs/pin" } }, "required": ["type", "pin"], "additionalProperties": true }, { "type": "object", "properties": { "type": { "const": "unpin" }, "pinId": { "type": "string" }, "reason": { "enum": ["unpinned", "session_ended"] } }, "required": ["type", "pinId", "reason"], "additionalProperties": true }] }, "unknownEvent": { "type": "object", "properties": { "type": { "type": "string", "not": { "enum": ["session.opened", "session.ready", "session.updated", "session.closed", "session.failed", "prompt.accepted", "prompt.failed", "turn.started", "turn.ended", "item", "usage", "mail", "assignment", "question", "question.resolved", "pin", "unpin"] } } }, "required": ["type"], "additionalProperties": true }, "knownItem": { "oneOf": [{ "type": "object", "properties": { "kind": { "const": "user_message" }, "id": { "type": "string" }, "text": { "type": "string" }, "clientMessageId": { "type": "string" }, "images": { "type": "integer", "minimum": 1 } }, "required": ["kind", "id", "text"], "additionalProperties": true }, { "type": "object", "properties": { "kind": { "const": "assistant_message" }, "id": { "type": "string" }, "text": { "type": "string" } }, "required": ["kind", "id", "text"], "additionalProperties": true }, { "type": "object", "properties": { "kind": { "const": "notice" }, "id": { "type": "string" }, "level": { "enum": ["info", "warning", "error"] }, "text": { "type": "string" } }, "required": ["kind", "id", "level", "text"], "additionalProperties": true }, { "type": "object", "properties": { "kind": { "const": "compaction" }, "id": { "type": "string" }, "status": { "enum": ["running", "completed", "failed"] }, "trigger": { "type": "string" }, "preTokens": { "type": "integer" }, "postTokens": { "type": "integer" } }, "required": ["kind", "id", "status"], "additionalProperties": true }, { "type": "object", "properties": { "kind": { "const": "todo" }, "id": { "type": "string" }, "items": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "text": { "type": "string" }, "status": { "enum": ["pending", "in_progress", "completed"] } }, "required": ["id", "text", "status"], "additionalProperties": true } } }, "required": ["kind", "id", "items"], "additionalProperties": true }, { "type": "object", "properties": { "kind": { "const": "tool_call" }, "id": { "type": "string" }, "callId": { "type": "string" }, "name": { "type": "string" }, "status": { "enum": ["running", "completed", "failed"] }, "error": { "type": "string" }, "detail": { "$ref": "#/$defs/toolCallDetail" } }, "required": ["kind", "id", "callId", "name", "status", "detail"], "additionalProperties": true }] }, "unknownItem": { "type": "object", "properties": { "kind": { "type": "string", "not": { "enum": ["user_message", "assistant_message", "notice", "compaction", "todo", "tool_call"] } }, "id": { "type": "string" } }, "required": ["kind", "id"], "additionalProperties": true }, "toolCallDetail": { "oneOf": [{ "type": "object", "properties": { "type": { "const": "shell" }, "command": { "type": "string" }, "cwd": { "type": "string" }, "output": { "type": "string" }, "exitCode": { "type": ["integer", "null"] } }, "required": ["type", "command", "output"], "additionalProperties": true }, { "type": "object", "properties": { "type": { "const": "read" }, "filePath": { "type": "string" }, "content": { "type": "string" }, "offset": { "type": "integer" }, "limit": { "type": "integer" } }, "required": ["type", "filePath"], "additionalProperties": true }, { "type": "object", "properties": { "type": { "const": "edit" }, "filePath": { "type": "string" }, "oldString": { "type": "string" }, "newString": { "type": "string" }, "unifiedDiff": { "type": "string" } }, "required": ["type", "filePath"], "additionalProperties": true }, { "type": "object", "properties": { "type": { "const": "write" }, "filePath": { "type": "string" }, "content": { "type": "string" } }, "required": ["type", "filePath"], "additionalProperties": true }, { "type": "object", "properties": { "type": { "const": "search" }, "query": { "type": "string" }, "toolName": { "enum": ["search", "grep", "glob", "web_search"] }, "content": { "type": "string" }, "filePaths": { "type": "array", "items": { "type": "string" } }, "webResults": { "type": "array", "items": { "type": "object", "properties": { "title": { "type": "string" }, "url": { "type": "string" } }, "required": ["title", "url"], "additionalProperties": true } }, "numFiles": { "type": "integer" }, "numMatches": { "type": "integer" }, "truncated": { "type": "boolean" } }, "required": ["type", "query"], "additionalProperties": true }, { "type": "object", "properties": { "type": { "const": "fetch" }, "url": { "type": "string" }, "prompt": { "type": "string" }, "result": { "type": "string" }, "code": { "type": "integer" } }, "required": ["type", "url"], "additionalProperties": true }, { "type": "object", "properties": { "type": { "const": "sub_agent" }, "subAgentType": { "type": "string" }, "description": { "type": "string" }, "log": { "type": "string" } }, "required": ["type"], "additionalProperties": true }, { "type": "object", "properties": { "type": { "const": "plan" }, "text": { "type": "string" } }, "required": ["type", "text"], "additionalProperties": true }, { "type": "object", "properties": { "type": { "const": "plain_text" }, "label": { "type": "string" }, "text": { "type": "string" } }, "required": ["type"], "additionalProperties": true }, { "type": "object", "properties": { "type": { "const": "unknown" }, "input": {}, "output": {} }, "required": ["type", "input", "output"], "additionalProperties": true }, { "type": "object", "properties": { "type": { "type": "string", "not": { "enum": ["shell", "read", "edit", "write", "search", "fetch", "sub_agent", "plan", "plain_text", "unknown"] } } }, "required": ["type"], "additionalProperties": true }] }, "alpError": { "type": "object", "properties": { "message": { "type": "string" }, "code": { "type": "string" } }, "required": ["message"], "additionalProperties": true }, "sessionSummary": { "type": "object", "properties": { "id": { "type": "string" }, "projectRoot": { "type": "string" }, "agent": { "type": "string" }, "runtime": { "enum": ["claude", "codex", "acp", "antigravity"] }, "model": { "type": "string" }, "mode": { "type": "string" }, "thinking": { "type": "string" }, "workflow": { "type": "object", "properties": { "mode": { "type": "string" }, "maxPeers": { "type": "integer" }, "supervisor": { "type": "boolean" } }, "required": ["mode", "maxPeers", "supervisor"], "additionalProperties": true }, "threadId": { "type": "string" }, "persistent": { "type": "boolean" }, "busy": { "type": "boolean" }, "parentId": { "type": "string" }, "toolCallId": { "type": "string" }, "activeTurnId": { "type": "string" }, "parked": { "type": "string" }, "instructionsSha": { "type": "string" }, "teamLabel": { "type": "string" }, "status": { "enum": ["initializing", "idle", "running", "error", "closed"] }, "title": { "type": "string" }, "archived": { "type": "boolean" }, "lastError": { "type": "object", "properties": { "code": { "type": "string" }, "message": { "type": "string" } }, "required": ["message"], "additionalProperties": true }, "createdAt": { "type": "string" }, "updatedAt": { "type": "string" } }, "required": ["id", "projectRoot", "agent", "runtime", "model", "mode", "thinking", "workflow", "threadId", "persistent", "busy", "status"], "additionalProperties": true }, "pause": { "type": "object", "properties": { "since": { "type": "string" }, "by": { "type": "string" }, "reason": { "type": "string" }, "resetsAt": { "type": "string" }, "checkedAt": { "type": "string" } }, "required": ["since", "by", "reason"], "additionalProperties": true }, "pauseState": { "type": "object", "properties": { "all": { "$ref": "#/$defs/pause" }, "runtimes": { "type": "object", "additionalProperties": { "$ref": "#/$defs/pause" } }, "parked": { "type": "array", "items": { "type": "object", "properties": { "assignmentId": { "type": "string" }, "agent": { "type": "string" }, "runtime": { "type": "string" }, "rootId": { "type": "string" }, "reason": { "type": "string" }, "since": { "type": "string" } }, "required": ["assignmentId", "agent", "runtime", "rootId", "reason", "since"], "additionalProperties": true } } }, "required": ["runtimes", "parked"], "additionalProperties": true }, "preview": { "type": "object", "properties": { "teams": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "label": { "type": "string" }, "description": { "type": "string" } }, "required": ["id", "label"], "additionalProperties": true } }, "team": { "type": "string" }, "teamLabel": { "type": "string" }, "agent": { "type": "string" }, "runtime": { "enum": ["claude", "codex", "acp", "antigravity"] }, "model": { "type": "string" }, "mode": { "type": "string" }, "thinking": { "type": "string" } }, "required": ["teams", "team", "agent", "runtime", "model", "mode", "thinking"], "additionalProperties": true }, "treeStatus": { "type": "object", "properties": { "rootId": { "type": "string" }, "sessions": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "projectRoot": { "type": "string" }, "agent": { "type": "string" }, "runtime": { "enum": ["claude", "codex", "acp", "antigravity"] }, "model": { "type": "string" }, "mode": { "type": "string" }, "thinking": { "type": "string" }, "workflow": { "type": "object", "properties": { "mode": { "type": "string" }, "maxPeers": { "type": "integer" }, "supervisor": { "type": "boolean" } }, "required": ["mode", "maxPeers", "supervisor"], "additionalProperties": true }, "threadId": { "type": "string" }, "persistent": { "type": "boolean" }, "busy": { "type": "boolean" }, "parentId": { "type": "string" }, "toolCallId": { "type": "string" }, "activeTurnId": { "type": "string" }, "parked": { "type": "string" }, "instructionsSha": { "type": "string" }, "teamLabel": { "type": "string" }, "state": { "enum": ["running", "waiting", "waiting_parent", "waiting_user", "idle"] }, "idleMs": { "type": "number" }, "workdir": { "type": "string" }, "unreadMail": { "type": "integer", "minimum": 0 } }, "required": ["id", "projectRoot", "agent", "runtime", "model", "mode", "thinking", "workflow", "threadId", "persistent", "busy", "state", "idleMs", "workdir", "unreadMail"], "additionalProperties": true } }, "assignments": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "requester": { "type": "string" }, "isolation": { "enum": ["shared", "worktree"] }, "idleMs": { "type": "number" } }, "required": ["id", "requester", "isolation", "idleMs"], "additionalProperties": true } }, "questions": { "type": "array", "items": { "$ref": "#/$defs/question" } }, "worktrees": { "type": "array", "items": { "type": "object", "properties": { "assignmentId": { "type": "string" }, "requester": { "type": "string" }, "agent": { "type": "string" }, "branch": { "type": "string" }, "files": { "type": "array", "items": { "type": "string" } }, "stat": { "type": "string" } }, "required": ["assignmentId", "requester", "agent", "branch", "files", "stat"], "additionalProperties": true } }, "leases": { "type": "array", "items": { "type": "object", "properties": { "checkout": { "type": "string" }, "assignmentId": { "type": "string" }, "agent": { "type": "string" } }, "required": ["checkout", "assignmentId", "agent"], "additionalProperties": true } }, "claims": { "type": "array", "items": { "$ref": "#/$defs/pin" } } }, "required": ["rootId", "sessions", "assignments", "questions", "worktrees", "leases", "claims"], "additionalProperties": true }, "health": { "type": "object", "properties": { "live": { "type": "boolean" }, "ready": { "type": "boolean" }, "checks": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "ok": { "type": "boolean" }, "code": { "type": "string" }, "message": { "type": "string" } }, "required": ["id", "ok"], "additionalProperties": true } } }, "required": ["live", "ready", "checks"], "additionalProperties": true }, "projectRoot": { "type": "string", "minLength": 1, "maxLength": 4096, "description": "An absolute, normalized path on the daemon host to a directory holding .alp/. Compared as is: the daemon never walks up to a parent." }, "taskId": { "type": "string", "pattern": "^t-[0-9a-f]{4,12}(?:\\.\\d+)*$" }, "taskRow": { "type": "object", "properties": { "id": { "$ref": "#/$defs/taskId" }, "title": { "type": "string" }, "type": { "type": "string" }, "priority": { "type": "integer" }, "status": { "enum": ["open", "in_progress", "review", "closed"] }, "rev": { "type": "integer", "minimum": 0 }, "parent": { "type": "string" }, "assignee": { "type": "string" }, "ready": { "type": "boolean" }, "blockedBy": { "type": "array", "items": { "type": "string" } }, "waits": { "type": "array", "items": { "type": "string" } }, "approvals": { "type": "array", "items": { "type": "object", "properties": { "gate": { "type": "string" }, "note": { "type": "string" } }, "required": ["gate", "note"], "additionalProperties": true } }, "handoff": { "type": "object", "properties": { "outcome": { "type": "string" }, "summary": { "type": "string" }, "agent": { "type": "string" } }, "required": ["outcome", "summary"], "additionalProperties": true }, "closed": { "type": "object", "properties": { "reason": { "type": "string" }, "summary": { "type": "string" }, "at": { "type": "string" } }, "required": ["reason", "at"], "additionalProperties": true }, "description": { "type": "string" }, "labels": { "type": "array", "items": { "type": "string" } }, "paths": { "type": "array", "items": { "type": "string" } }, "progress": { "type": "object", "properties": { "done": { "type": "integer", "minimum": 0 }, "total": { "type": "integer", "minimum": 0 } }, "required": ["done", "total"], "additionalProperties": true }, "createdAt": { "type": "string" }, "updatedAt": { "type": "string" } }, "required": ["id", "title", "type", "priority", "status", "rev", "ready", "updatedAt"], "additionalProperties": true }, "libraryKind": { "enum": ["agents", "skills", "mcp", "hooks", "teams", "providers"] }, "libraryScope": { "enum": ["library", "project"] }, "librarySource": { "enum": ["builtin", "library", "project"] }, "entryName": { "type": "string", "minLength": 1, "maxLength": 128, "pattern": "^[A-Za-z0-9_.-]+$", "not": { "enum": [".", ".."] } }, "libraryRevision": { "type": ["string", "null"] }, "libraryEntryRow": { "type": "object", "properties": { "name": { "type": "string" }, "source": { "$ref": "#/$defs/librarySource" }, "overrides": { "$ref": "#/$defs/librarySource" }, "description": { "type": "string" }, "usedBy": { "type": "array", "items": { "type": "string" } } }, "required": ["name", "source"], "additionalProperties": true }, "secretMarker": { "type": "object", "properties": { "$secret": { "const": "keep" } }, "required": ["$secret"], "additionalProperties": false, "description": "Stands for a stored secret value: read results carry it in place of the value; a save that sends it back keeps the stored value." }, "languageSetting": { "type": "object", "properties": { "language": { "type": ["string", "null"] }, "applies": { "type": "string" }, "default": { "type": "string" } }, "required": ["language", "applies", "default"], "additionalProperties": true }, "teamRow": { "type": "object", "properties": { "id": { "type": "string" }, "label": { "type": "string" }, "description": { "type": "string" }, "source": { "$ref": "#/$defs/librarySource" }, "overrides": { "$ref": "#/$defs/librarySource" }, "error": { "type": "string" } }, "required": ["id", "source"], "additionalProperties": true }, "promptImage": { "type": "object", "properties": { "type": { "const": "image" }, "mimeType": { "enum": ["image/png", "image/jpeg", "image/gif", "image/webp"] }, "data": { "type": "string", "minLength": 4, "maxLength": 6990508, "pattern": "^[A-Za-z0-9+/]+={0,2}$" }, "name": { "type": "string", "maxLength": 255 } }, "required": ["type", "mimeType", "data"], "additionalProperties": false } } };
|
|
45430
|
+
var METHODS_V1 = { "$schema": "http://json-schema.org/draft-07/schema#", "$id": "https://alp.dev/schemas/methods-v1.json", "protocolVersion": 1, "errors": { "parseError": -32700, "invalidRequest": -32600, "methodNotFound": -32601, "invalidParams": -32602, "failed": 1e3, "notFound": 1001, "forbidden": 1003, "conflict": 1004, "unavailable": 1005, "protocol": 1006 }, "capabilities": { "attach.after": "session.attach accepts `after` and answers `cursor`/`reset`; envelopes kept in a tree timeline carry `cursor`.", "prompt.receipts": "session.prompt is answered at most once per (sessionId, clientMessageId) from a durable receipt; repeats answer the first outcome or outcome_unknown.", "extension.methods": "extension.register/unregister, and the daemon sends extension.invoke requests to the owning connection.", "team": "team.list: the teams a project can use, from the daemon host's built-ins, library and project.", "task": "task.list, task.create, task.update and task.gate.resolve on a project's .alp/tasks, written by the daemon under the task lock.", "library": "library.list/get/save/delete/duplicate/rename, library.skills.set and library.models on the daemon user's library and a project's .alp overrides; secrets are redacted on read.", "settings.language": "settings.language.get/set: the language the daemon user reads, in the daemon's ALP_HOME/settings.json.", "session.list.page": "session.list accepts `limit`, `cursor` and `query` and answers `nextCursor` while more sessions follow; without them it answers every session as before.", "question.watch": "question.watch: the connection is told of `question` and `question.resolved` in every tree (of a projectRoot when given), attached or not.", "question.watch.turns": "question.watch accepts `turns`: the connection is also told of `turn.ended` of every root in the trees it watches.", "workspace.files": "workspace.files.search: files under a directory whose relative path matches a query; read-only, names only, links never followed.", "workspace.files.read": "workspace.files.list and workspace.files.read: the entries of a directory and the content of a UTF-8 text file (at most 1 MiB) under a directory; read-only, links never followed, .git, .env* and key or credential files refused, .gitignore'd paths hidden unless asked.", "prompt.images": 'session.prompt takes inline image parts { type: "image", mimeType, data } (base64, no paths or URLs) within the image limits; a session snapshot says whether its runtime takes them in promptImages.', "library.project.write": "library save/delete/duplicate/rename accept policy project-data: only project-only pure-data agents and skills, no executable configuration, sidecars or library/built-in collisions." }, "methods": { "assignment.recall": { "x-alp": { "effect": "mutation", "scope": { "kind": "project", "param": "projectRoot", "required": false, "alternatives": ["assignmentId", "taskId"] }, "idempotent": false, "risks": ["model call"] }, "params": { "type": "object", "properties": { "assignmentId": { "type": "string" }, "taskId": { "type": "string" }, "projectRoot": { "type": "string" }, "question": { "type": "string" } }, "required": ["question"], "additionalProperties": true }, "result": { "type": "object", "properties": { "assignmentId": { "type": "string" }, "agent": { "type": "string" }, "taskId": { "type": "string" }, "finishedAt": { "type": "string" }, "answer": { "type": "string" } }, "required": ["assignmentId", "agent", "finishedAt", "answer"], "additionalProperties": true } }, "board.list": { "x-alp": { "effect": "query", "scope": { "kind": "project", "param": "projectRoot", "required": true }, "idempotent": true }, "params": { "type": "object", "properties": { "projectRoot": { "type": "string" } }, "required": ["projectRoot"], "additionalProperties": true }, "result": { "type": "object", "properties": { "pins": { "type": "array", "items": { "$ref": "#/$defs/pin" } } }, "required": ["pins"], "additionalProperties": true } }, "catalog.get": { "x-alp": { "effect": "query", "scope": { "kind": "host" }, "idempotent": true }, "params": { "type": "object", "properties": {}, "required": [], "additionalProperties": true }, "result": { "type": "object", "properties": { "models": { "type": "array", "items": { "type": "object" } }, "modes": { "type": "array", "items": { "type": "object" } }, "thinkingOptions": {}, "defaultModel": { "type": "string" } }, "required": ["models", "modes", "defaultModel"], "additionalProperties": true } }, "daemon.hello": { "x-alp": { "effect": "query", "scope": { "kind": "connection" }, "idempotent": true }, "params": { "type": "object", "properties": { "protocolVersion": { "const": 1 }, "client": { "type": "object", "properties": { "name": { "type": "string" }, "version": { "type": "string" } }, "required": ["name", "version"], "additionalProperties": true }, "capabilities": { "type": "array", "items": { "type": "string" } } }, "required": ["protocolVersion"], "additionalProperties": true }, "result": { "type": "object", "properties": { "protocolVersion": { "const": 1 }, "daemonVersion": { "type": "string" }, "pid": { "type": "integer" }, "hostname": { "type": "string" }, "capabilities": { "type": "array", "items": { "type": "string" } }, "promptImageLimits": { "type": "object", "description": "Optional effective inline image limits for this connection, when prompt.images is advertised. Missing on older peers. Byte limits count decoded bytes.", "properties": { "maxCount": { "type": "integer", "minimum": 0 }, "maxBytes": { "type": "integer", "minimum": 0 }, "maxTotalBytes": { "type": "integer", "minimum": 0 } }, "required": ["maxCount", "maxBytes", "maxTotalBytes"], "additionalProperties": false } }, "required": ["protocolVersion"], "additionalProperties": true } }, "daemon.pause": { "x-alp": { "effect": "mutation", "scope": { "kind": "host" }, "idempotent": true, "risks": ["admin"] }, "params": { "type": "object", "properties": { "runtime": { "enum": ["codex", "claude", "acp", "antigravity"] }, "now": { "type": "boolean" }, "reason": { "type": "string" } }, "required": [], "additionalProperties": true }, "result": { "$ref": "#/$defs/pauseState" } }, "daemon.pauses": { "x-alp": { "effect": "query", "scope": { "kind": "host" }, "idempotent": true }, "params": { "type": "object", "properties": {}, "required": [], "additionalProperties": true }, "result": { "$ref": "#/$defs/pauseState" } }, "daemon.resume": { "x-alp": { "effect": "mutation", "scope": { "kind": "host" }, "idempotent": true, "risks": ["admin"] }, "params": { "type": "object", "properties": { "runtime": { "enum": ["codex", "claude", "acp", "antigravity"] } }, "required": [], "additionalProperties": true }, "result": { "$ref": "#/$defs/pauseState" } }, "daemon.shutdown": { "x-alp": { "effect": "mutation", "scope": { "kind": "host" }, "idempotent": true, "risks": ["admin"] }, "params": { "type": "object", "properties": {}, "required": [], "additionalProperties": true }, "result": { "type": "object", "properties": {}, "required": [], "additionalProperties": true } }, "daemon.status": { "x-alp": { "effect": "query", "scope": { "kind": "host" }, "idempotent": true }, "params": { "type": "object", "properties": {}, "required": [], "additionalProperties": true }, "result": { "type": "object", "properties": { "pid": { "type": "integer" }, "startedAt": { "type": "string" }, "version": { "type": "string" }, "protocolVersion": { "type": "integer" }, "sessions": { "type": "integer" }, "questions": { "type": "integer" }, "previousExit": { "type": "object", "properties": { "kind": { "enum": ["clean", "crash"] }, "at": { "type": "string" } }, "required": ["kind"], "additionalProperties": true }, "persistence": { "type": "object" }, "health": { "$ref": "#/$defs/health" } }, "required": ["pid", "startedAt", "version", "protocolVersion", "sessions", "questions", "health"], "additionalProperties": true } }, "daemon.usage": { "x-alp": { "effect": "query", "scope": { "kind": "host" }, "idempotent": true, "risks": ["refresh asks every provider (spawns on the daemon host)"] }, "params": { "type": "object", "properties": { "refresh": { "type": "boolean" } }, "required": [], "additionalProperties": true }, "result": { "type": "object", "properties": { "providers": { "type": "array", "items": { "type": "object" } } }, "required": ["providers"], "additionalProperties": true } }, "extension.register": { "x-alp": { "effect": "mutation", "scope": { "kind": "connection" }, "idempotent": false, "risks": ["admin"] }, "params": { "type": "object", "properties": { "method": { "type": "string" } }, "required": ["method"], "additionalProperties": true }, "result": { "type": "object", "properties": { "registered": { "type": "string" } }, "required": ["registered"], "additionalProperties": true } }, "extension.unregister": { "x-alp": { "effect": "mutation", "scope": { "kind": "connection" }, "idempotent": false, "risks": ["admin"] }, "params": { "type": "object", "properties": { "method": { "type": "string" } }, "required": ["method"], "additionalProperties": true }, "result": { "type": "object", "properties": { "unregistered": { "type": "string" } }, "required": ["unregistered"], "additionalProperties": true } }, "library.delete": { "x-alp": { "effect": "mutation", "capability": "library", "scope": { "kind": "library-or-project", "param": "projectRoot", "selector": "scope" }, "idempotent": false }, "params": { "type": "object", "properties": { "kind": { "$ref": "#/$defs/libraryKind" }, "name": { "$ref": "#/$defs/entryName" }, "scope": { "$ref": "#/$defs/libraryScope" }, "projectRoot": { "$ref": "#/$defs/projectRoot" }, "revision": { "type": "string" }, "policy": { "enum": ["project-data"], "description": "Opt-in strict project-only non-executable mutation policy; requires library.project.write capability." } }, "required": ["kind", "name", "scope"], "additionalProperties": true }, "result": { "type": "object", "properties": { "removed": { "const": true }, "now": { "enum": ["builtin", "library"] } }, "required": ["removed"], "additionalProperties": true } }, "library.duplicate": { "x-alp": { "effect": "mutation", "capability": "library", "scope": { "kind": "library-or-project", "param": "projectRoot", "selector": "scope", "reads": ["builtin", "library"] }, "idempotent": false, "risks": ["exec-config when kind is mcp, hooks or providers"] }, "params": { "type": "object", "properties": { "kind": { "$ref": "#/$defs/libraryKind" }, "from": { "$ref": "#/$defs/entryName" }, "to": { "$ref": "#/$defs/entryName" }, "scope": { "$ref": "#/$defs/libraryScope" }, "projectRoot": { "$ref": "#/$defs/projectRoot" }, "policy": { "enum": ["project-data"], "description": "Opt-in strict project-only non-executable mutation policy; requires library.project.write capability." } }, "required": ["kind", "from", "to", "scope"], "additionalProperties": true }, "result": { "type": "object", "properties": { "revision": { "$ref": "#/$defs/libraryRevision" } }, "required": ["revision"], "additionalProperties": true } }, "library.get": { "x-alp": { "effect": "query", "capability": "library", "scope": { "kind": "project", "param": "projectRoot", "required": false, "reads": ["builtin", "library"] }, "idempotent": true, "redacts": ["mcp /server/env/*", "mcp /server/headers/*", "providers /provider/env/*"] }, "params": { "type": "object", "properties": { "kind": { "$ref": "#/$defs/libraryKind" }, "name": { "$ref": "#/$defs/entryName" }, "projectRoot": { "$ref": "#/$defs/projectRoot" }, "scope": { "$ref": "#/$defs/libraryScope" } }, "required": ["kind", "name"], "additionalProperties": true }, "result": { "type": "object", "properties": { "kind": { "$ref": "#/$defs/libraryKind" }, "name": { "type": "string" }, "source": { "$ref": "#/$defs/librarySource" }, "overrides": { "$ref": "#/$defs/librarySource" }, "content": { "type": "object" }, "revision": { "$ref": "#/$defs/libraryRevision" }, "usedBy": { "type": "array", "items": { "type": "string" } }, "librarySkills": { "type": "array", "items": { "type": "string" } }, "secrets": { "type": "array", "items": { "type": "string" } } }, "required": ["kind", "name", "source", "content", "revision", "usedBy"], "additionalProperties": true } }, "library.list": { "x-alp": { "effect": "query", "capability": "library", "scope": { "kind": "project", "param": "projectRoot", "required": false, "reads": ["builtin", "library"] }, "idempotent": true }, "params": { "type": "object", "properties": { "kind": { "$ref": "#/$defs/libraryKind" }, "projectRoot": { "$ref": "#/$defs/projectRoot" } }, "required": ["kind"], "additionalProperties": true }, "result": { "type": "object", "properties": { "projectRoot": { "type": ["string", "null"] }, "entries": { "type": "array", "items": { "$ref": "#/$defs/libraryEntryRow" } } }, "required": ["projectRoot", "entries"], "additionalProperties": true } }, "library.models": { "x-alp": { "effect": "query", "capability": "library", "scope": { "kind": "host" }, "idempotent": true }, "params": { "type": "object", "properties": {}, "required": [], "additionalProperties": true }, "result": { "type": "object", "properties": { "models": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "label": { "type": "string" }, "efforts": { "type": "array", "items": { "type": "string" } }, "effort": { "type": "string" } }, "required": ["id", "label", "efforts"], "additionalProperties": true } } }, "required": ["models"], "additionalProperties": true } }, "library.rename": { "x-alp": { "effect": "mutation", "capability": "library", "scope": { "kind": "library-or-project", "param": "projectRoot", "selector": "scope" }, "idempotent": false, "risks": ["exec-config when kind is mcp, hooks or providers"] }, "params": { "type": "object", "properties": { "kind": { "$ref": "#/$defs/libraryKind" }, "from": { "$ref": "#/$defs/entryName" }, "to": { "$ref": "#/$defs/entryName" }, "scope": { "$ref": "#/$defs/libraryScope" }, "projectRoot": { "$ref": "#/$defs/projectRoot" }, "policy": { "enum": ["project-data"], "description": "Opt-in strict project-only non-executable mutation policy; requires library.project.write capability." } }, "required": ["kind", "from", "to", "scope"], "additionalProperties": true }, "result": { "type": "object", "properties": { "revision": { "$ref": "#/$defs/libraryRevision" } }, "required": ["revision"], "additionalProperties": true } }, "library.save": { "x-alp": { "effect": "mutation", "capability": "library", "scope": { "kind": "library-or-project", "param": "projectRoot", "selector": "scope" }, "idempotent": "with revision (a repeat fails revision_conflict)", "risks": ["exec-config when kind is mcp, hooks or providers, or agents naming mcp/hooks/provider", "writes every known project's .alp/settings.json when kind is teams and sync is known-projects"] }, "params": { "type": "object", "properties": { "kind": { "$ref": "#/$defs/libraryKind" }, "name": { "$ref": "#/$defs/entryName" }, "scope": { "$ref": "#/$defs/libraryScope" }, "projectRoot": { "$ref": "#/$defs/projectRoot" }, "content": { "type": "object" }, "revision": { "$ref": "#/$defs/libraryRevision" }, "sync": { "enum": ["none", "known-projects"] }, "policy": { "enum": ["project-data"], "description": "Opt-in strict project-only non-executable mutation policy; requires library.project.write capability." } }, "required": ["kind", "name", "scope", "content"], "additionalProperties": true }, "result": { "type": "object", "properties": { "revision": { "$ref": "#/$defs/libraryRevision" }, "syncedProjects": { "type": "integer", "minimum": 0 }, "syncErrors": { "type": "array", "items": { "type": "string" } } }, "required": ["revision"], "additionalProperties": true } }, "library.skills.set": { "x-alp": { "effect": "mutation", "capability": "library", "scope": { "kind": "host" }, "writes": ["ALP_HOME/role-skills.json"], "idempotent": true }, "params": { "type": "object", "properties": { "agent": { "$ref": "#/$defs/entryName" }, "skills": { "type": "array", "items": { "$ref": "#/$defs/entryName" }, "maxItems": 100 } }, "required": ["agent", "skills"], "additionalProperties": true }, "result": { "type": "object", "properties": { "skills": { "type": "array", "items": { "type": "string" } } }, "required": ["skills"], "additionalProperties": true } }, "question.answer": { "x-alp": { "effect": "mutation", "scope": { "kind": "question", "param": "questionId", "prefix": true }, "idempotent": false }, "params": { "type": "object", "properties": { "questionId": { "type": "string" }, "text": { "type": "string" }, "dismiss": { "type": "boolean" }, "reason": { "type": "string" } }, "required": ["questionId"], "additionalProperties": true }, "result": { "type": "object", "properties": { "questionId": { "type": "string" } }, "required": ["questionId"], "additionalProperties": true } }, "question.list": { "x-alp": { "effect": "query", "scope": { "kind": "project", "param": "projectRoot", "required": false }, "idempotent": true }, "params": { "type": "object", "properties": { "projectRoot": { "type": "string" } }, "required": [], "additionalProperties": true }, "result": { "type": "object", "properties": { "questions": { "type": "array", "items": { "$ref": "#/$defs/question" } } }, "required": ["questions"], "additionalProperties": true } }, "question.watch": { "x-alp": { "effect": "query", "scope": { "kind": "project", "param": "projectRoot", "required": false }, "idempotent": true, "capability": "question.watch" }, "params": { "type": "object", "properties": { "projectRoot": { "type": "string" }, "turns": { "type": "boolean" } }, "required": [], "additionalProperties": true }, "result": { "type": "object", "properties": { "questions": { "type": "array", "items": { "$ref": "#/$defs/question" } } }, "required": ["questions"], "additionalProperties": true } }, "session.archive": { "x-alp": { "effect": "mutation", "scope": { "kind": "session", "param": "sessionId" }, "idempotent": true }, "params": { "type": "object", "properties": { "sessionId": { "type": "string" }, "archived": { "type": "boolean" } }, "required": ["sessionId"], "additionalProperties": true }, "result": { "type": "object", "properties": { "session": { "$ref": "#/$defs/sessionSummary" } }, "required": ["session"], "additionalProperties": true } }, "session.attach": { "x-alp": { "effect": "query", "scope": { "kind": "session", "param": "sessionId" }, "idempotent": true }, "params": { "type": "object", "properties": { "sessionId": { "type": "string" }, "replay": { "type": "boolean" }, "after": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 } }, "required": ["sessionId"], "additionalProperties": true }, "result": { "type": "object", "properties": { "session": { "$ref": "#/$defs/sessionSummary" }, "cursor": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 }, "reset": { "const": true } }, "required": ["session", "cursor"], "additionalProperties": true } }, "session.close": { "x-alp": { "effect": "mutation", "scope": { "kind": "session", "param": "sessionId" }, "idempotent": false }, "params": { "type": "object", "properties": { "sessionId": { "type": "string" } }, "required": ["sessionId"], "additionalProperties": true }, "result": { "type": "object", "properties": {}, "required": [], "additionalProperties": true } }, "session.configure": { "x-alp": { "effect": "mutation", "scope": { "kind": "session", "param": "sessionId" }, "idempotent": true }, "params": { "type": "object", "properties": { "sessionId": { "type": "string" }, "mode": { "type": "string" } }, "required": ["sessionId"], "additionalProperties": true }, "result": { "type": "object", "properties": { "session": { "$ref": "#/$defs/session" } }, "required": ["session"], "additionalProperties": true } }, "session.create": { "x-alp": { "effect": "mutation", "scope": { "kind": "project", "param": "spec.cwd" }, "idempotent": false, "risks": ["exec: spec.env and stdio spec.mcpServers run on the daemon host", "spec.workdir/writeRoot/copy*/restore/keepThread are internal"] }, "params": { "type": "object", "properties": { "sessionId": { "type": "string", "pattern": "^[A-Za-z0-9_.:-]{1,128}$" }, "spec": { "$ref": "#/$defs/spec" }, "history": { "enum": ["skip", "replay"] }, "delegation": { "type": "boolean" }, "resume": { "type": "boolean" } }, "required": ["spec"], "additionalProperties": true }, "result": { "type": "object", "properties": { "session": { "$ref": "#/$defs/session" }, "attached": { "type": "boolean" }, "resumed": { "const": true }, "durable": { "type": "boolean" } }, "required": ["session", "attached"], "additionalProperties": true } }, "session.get": { "x-alp": { "effect": "query", "scope": { "kind": "session", "param": "sessionId" }, "idempotent": true }, "params": { "type": "object", "properties": { "sessionId": { "type": "string" } }, "required": ["sessionId"], "additionalProperties": true }, "result": { "type": "object", "properties": { "session": { "$ref": "#/$defs/sessionSummary" } }, "required": ["session"], "additionalProperties": true } }, "session.interrupt": { "x-alp": { "effect": "mutation", "scope": { "kind": "session", "param": "sessionId" }, "idempotent": true }, "params": { "type": "object", "properties": { "sessionId": { "type": "string" } }, "required": ["sessionId"], "additionalProperties": true }, "result": { "type": "object", "properties": {}, "required": [], "additionalProperties": true } }, "session.list": { "x-alp": { "effect": "query", "scope": { "kind": "project", "param": "projectRoot", "required": false }, "idempotent": true }, "params": { "type": "object", "properties": { "projectRoot": { "type": "string" }, "rootsOnly": { "type": "boolean" }, "includeClosed": { "type": "boolean" }, "includeArchived": { "type": "boolean" }, "limit": { "type": "integer", "minimum": 1, "maximum": 1e3 }, "cursor": { "type": "string", "minLength": 1, "maxLength": 1024 }, "query": { "type": "string", "maxLength": 200 }, "projectRoots": { "type": "array", "items": { "type": "string" }, "minItems": 1, "maxItems": 1024 } }, "required": [], "additionalProperties": true }, "result": { "type": "object", "properties": { "sessions": { "type": "array", "items": { "$ref": "#/$defs/sessionSummary" } }, "nextCursor": { "type": "string", "minLength": 1 } }, "required": ["sessions"], "additionalProperties": true } }, "session.log": { "x-alp": { "effect": "query", "scope": { "kind": "session", "param": "sessionId" }, "idempotent": true }, "params": { "type": "object", "properties": { "sessionId": { "type": "string" } }, "required": ["sessionId"], "additionalProperties": true }, "result": { "type": "object", "properties": { "rootId": { "type": "string" }, "entries": { "type": "array", "items": { "type": "object" } } }, "required": ["rootId", "entries"], "additionalProperties": true } }, "session.message": { "x-alp": { "effect": "mutation", "scope": { "kind": "session", "param": "sessionId" }, "idempotent": false }, "params": { "type": "object", "properties": { "sessionId": { "type": "string" }, "text": { "type": "string" } }, "required": ["sessionId", "text"], "additionalProperties": true }, "result": { "type": "object", "properties": {}, "required": [], "additionalProperties": true } }, "session.preview": { "x-alp": { "effect": "query", "scope": { "kind": "project", "param": "spec.cwd" }, "idempotent": true }, "params": { "type": "object", "properties": { "spec": { "$ref": "#/$defs/spec" } }, "required": ["spec"], "additionalProperties": true }, "result": { "type": "object", "properties": { "preview": { "$ref": "#/$defs/preview" } }, "required": ["preview"], "additionalProperties": true } }, "session.prompt": { "x-alp": { "effect": "mutation", "scope": { "kind": "session", "param": "sessionId" }, "idempotent": "with prompt.receipts" }, "params": { "type": "object", "properties": { "sessionId": { "type": "string" }, "clientMessageId": { "type": "string" }, "delivery": { "enum": ["auto", "steer"] }, "content": { "type": "array", "items": { "anyOf": [{ "type": "object", "properties": { "type": { "const": "text" }, "text": { "type": "string" } }, "required": ["type"], "additionalProperties": true }, { "$ref": "#/$defs/promptImage" }, { "type": "object", "properties": { "type": { "type": "string", "not": { "enum": ["text", "image"] } } }, "required": ["type"], "additionalProperties": true }] } } }, "required": ["sessionId", "clientMessageId", "content"], "additionalProperties": true }, "result": { "type": "object", "properties": { "outcome": { "enum": ["accepted", "failed"] }, "error": { "$ref": "#/$defs/alpError" }, "duplicate": { "type": "boolean" }, "durable": { "type": "boolean" } }, "required": [], "additionalProperties": true } }, "session.release": { "x-alp": { "effect": "mutation", "scope": { "kind": "session", "param": "sessionId" }, "idempotent": true }, "params": { "type": "object", "properties": { "sessionId": { "type": "string" } }, "required": ["sessionId"], "additionalProperties": true }, "result": { "type": "object", "properties": { "closed": { "type": "boolean" } }, "required": ["closed"], "additionalProperties": true } }, "session.rename": { "x-alp": { "effect": "mutation", "scope": { "kind": "session", "param": "sessionId" }, "idempotent": true }, "params": { "type": "object", "properties": { "sessionId": { "type": "string" }, "title": { "type": "string", "minLength": 1, "maxLength": 200, "pattern": "\\S" } }, "required": ["sessionId", "title"], "additionalProperties": true }, "result": { "type": "object", "properties": { "session": { "$ref": "#/$defs/sessionSummary" } }, "required": ["session"], "additionalProperties": true } }, "session.status": { "x-alp": { "effect": "query", "scope": { "kind": "session", "param": "sessionId" }, "idempotent": true }, "params": { "type": "object", "properties": { "sessionId": { "type": "string" } }, "required": ["sessionId"], "additionalProperties": true }, "result": { "type": "object", "properties": { "status": { "$ref": "#/$defs/treeStatus" } }, "required": ["status"], "additionalProperties": true } }, "settings.language.get": { "x-alp": { "effect": "query", "capability": "settings.language", "scope": { "kind": "host" }, "idempotent": true }, "params": { "type": "object", "properties": {}, "required": [], "additionalProperties": true }, "result": { "$ref": "#/$defs/languageSetting" } }, "settings.language.set": { "x-alp": { "effect": "mutation", "capability": "settings.language", "scope": { "kind": "host" }, "writes": ["ALP_HOME/settings.json"], "idempotent": true }, "params": { "type": "object", "properties": { "language": { "anyOf": [{ "type": "string", "minLength": 1, "maxLength": 40, "pattern": "\\S" }, { "type": "null" }] } }, "required": ["language"], "additionalProperties": true }, "result": { "$ref": "#/$defs/languageSetting" } }, "task.create": { "x-alp": { "effect": "mutation", "capability": "task", "scope": { "kind": "project", "param": "projectRoot", "required": true }, "writes": ["<projectRoot>/.alp/tasks"], "idempotent": "per requestId within one alpd process (10 minutes)" }, "params": { "type": "object", "properties": { "projectRoot": { "$ref": "#/$defs/projectRoot" }, "title": { "type": "string", "minLength": 1, "maxLength": 200, "pattern": "\\S" }, "priority": { "type": "integer", "minimum": 0, "maximum": 4 }, "requestId": { "type": "string", "minLength": 1, "maxLength": 128 } }, "required": ["projectRoot", "title"], "additionalProperties": true }, "result": { "type": "object", "properties": { "id": { "$ref": "#/$defs/taskId" }, "duplicate": { "const": true } }, "required": ["id"], "additionalProperties": true } }, "task.gate.resolve": { "x-alp": { "effect": "mutation", "capability": "task", "scope": { "kind": "project", "param": "projectRoot", "required": true }, "writes": ["<projectRoot>/.alp/tasks"], "idempotent": false }, "params": { "type": "object", "properties": { "projectRoot": { "$ref": "#/$defs/projectRoot" }, "id": { "$ref": "#/$defs/taskId" }, "gate": { "type": "string", "minLength": 1, "maxLength": 128 }, "note": { "type": "string", "maxLength": 2e3 }, "ifRev": { "type": "integer", "minimum": 0 } }, "required": ["projectRoot", "id", "gate"], "additionalProperties": true }, "result": { "type": "object", "properties": { "id": { "$ref": "#/$defs/taskId" }, "status": { "type": "string" }, "rev": { "type": "integer", "minimum": 0 } }, "required": ["id", "status", "rev"], "additionalProperties": true } }, "task.list": { "x-alp": { "effect": "query", "capability": "task", "scope": { "kind": "project", "param": "projectRoot", "required": true }, "idempotent": true }, "params": { "type": "object", "properties": { "projectRoot": { "$ref": "#/$defs/projectRoot" } }, "required": ["projectRoot"], "additionalProperties": true }, "result": { "type": "object", "properties": { "projectRoot": { "type": "string" }, "tasks": { "type": "array", "items": { "$ref": "#/$defs/taskRow" } }, "unreadable": { "type": "array", "items": { "type": "object", "properties": { "file": { "type": "string" }, "error": { "type": "string" } }, "required": ["file", "error"], "additionalProperties": true } }, "revision": { "type": "string" } }, "required": ["projectRoot", "tasks", "unreadable", "revision"], "additionalProperties": true } }, "task.update": { "x-alp": { "effect": "mutation", "capability": "task", "scope": { "kind": "project", "param": "projectRoot", "required": true }, "writes": ["<projectRoot>/.alp/tasks"], "idempotent": false }, "params": { "type": "object", "properties": { "projectRoot": { "$ref": "#/$defs/projectRoot" }, "id": { "$ref": "#/$defs/taskId" }, "action": { "enum": ["close", "reopen"] }, "note": { "type": "string", "maxLength": 2e3 }, "ifRev": { "type": "integer", "minimum": 0 } }, "required": ["projectRoot", "id", "action"], "additionalProperties": true }, "result": { "type": "object", "properties": { "id": { "$ref": "#/$defs/taskId" }, "status": { "type": "string" }, "rev": { "type": "integer", "minimum": 0 }, "landed": { "type": "string" } }, "required": ["id", "status", "rev"], "additionalProperties": true } }, "team.list": { "x-alp": { "effect": "query", "capability": "team", "scope": { "kind": "project", "param": "projectRoot", "required": false, "reads": ["builtin", "library"] }, "idempotent": true }, "params": { "type": "object", "properties": { "projectRoot": { "$ref": "#/$defs/projectRoot" } }, "required": [], "additionalProperties": true }, "result": { "type": "object", "properties": { "projectRoot": { "type": ["string", "null"] }, "teams": { "type": "array", "items": { "$ref": "#/$defs/teamRow" } } }, "required": ["projectRoot", "teams"], "additionalProperties": true } }, "workspace.files.search": { "x-alp": { "effect": "query", "scope": { "kind": "project", "param": "projectRoot", "required": true }, "idempotent": true, "capability": "workspace.files", "risks": ["lists file names of the directory (not contents)"] }, "params": { "type": "object", "properties": { "projectRoot": { "type": "string" }, "query": { "type": "string", "maxLength": 200 }, "limit": { "type": "integer", "minimum": 1, "maximum": 100 } }, "required": ["projectRoot"], "additionalProperties": true }, "result": { "type": "object", "properties": { "files": { "type": "array", "maxItems": 100, "items": { "type": "object", "properties": { "path": { "type": "string", "minLength": 1 } }, "required": ["path"], "additionalProperties": true } }, "truncated": { "type": "boolean" } }, "required": ["files"], "additionalProperties": true } }, "workspace.files.list": { "x-alp": { "effect": "query", "scope": { "kind": "project", "param": "projectRoot", "required": true }, "idempotent": true, "capability": "workspace.files.read", "risks": ["lists names, kinds, sizes and times of a directory's entries (not contents)"] }, "params": { "type": "object", "properties": { "projectRoot": { "type": "string" }, "path": { "type": "string", "minLength": 1, "maxLength": 4096 }, "includeIgnored": { "type": "boolean" } }, "required": ["projectRoot"], "additionalProperties": true }, "result": { "type": "object", "properties": { "entries": { "type": "array", "maxItems": 1e3, "items": { "type": "object", "properties": { "name": { "type": "string", "minLength": 1 }, "path": { "type": "string", "minLength": 1 }, "kind": { "enum": ["file", "directory"] }, "size": { "type": "integer", "minimum": 0 }, "modifiedAt": { "type": "string" } }, "required": ["name", "path", "kind"], "additionalProperties": true } }, "truncated": { "type": "boolean" } }, "required": ["entries"], "additionalProperties": true } }, "workspace.files.read": { "x-alp": { "effect": "query", "scope": { "kind": "project", "param": "projectRoot", "required": true }, "idempotent": true, "capability": "workspace.files.read", "risks": ["returns the content of a text file under the directory"] }, "params": { "type": "object", "properties": { "projectRoot": { "type": "string" }, "path": { "type": "string", "minLength": 1, "maxLength": 4096 }, "includeIgnored": { "type": "boolean" } }, "required": ["projectRoot", "path"], "additionalProperties": true }, "result": { "type": "object", "properties": { "path": { "type": "string", "minLength": 1 }, "content": { "type": "string" }, "size": { "type": "integer", "minimum": 0, "maximum": 1048576 }, "modifiedAt": { "type": "string" } }, "required": ["path", "content", "size"], "additionalProperties": true } } }, "$defs": { "error": { "type": "object", "properties": { "code": { "type": "integer" }, "message": { "type": "string" }, "data": {} }, "required": ["code", "message"], "additionalProperties": true }, "session": { "type": "object", "properties": { "id": { "type": "string" }, "projectRoot": { "type": "string" }, "agent": { "type": "string" }, "runtime": { "enum": ["claude", "codex", "acp", "antigravity"] }, "model": { "type": "string" }, "mode": { "type": "string" }, "thinking": { "type": "string" }, "workflow": { "type": "object", "properties": { "mode": { "type": "string" }, "maxPeers": { "type": "integer" }, "supervisor": { "type": "boolean" } }, "required": ["mode", "maxPeers", "supervisor"], "additionalProperties": true }, "threadId": { "type": "string" }, "persistent": { "type": "boolean" }, "busy": { "type": "boolean" }, "parentId": { "type": "string" }, "toolCallId": { "type": "string" }, "activeTurnId": { "type": "string" }, "parked": { "type": "string" }, "instructionsSha": { "type": "string" }, "teamLabel": { "type": "string" }, "promptImages": { "type": "boolean" }, "usage": { "$ref": "#/$defs/usage" } }, "required": ["id", "projectRoot", "agent", "runtime", "model", "mode", "thinking", "workflow", "threadId", "persistent", "busy"], "additionalProperties": true }, "usage": { "type": "object", "properties": { "contextWindowUsedTokens": { "type": "integer", "minimum": 0 }, "contextWindowMaxTokens": { "type": "integer", "minimum": 1 }, "inputTokens": { "type": "integer", "minimum": 0 }, "cachedInputTokens": { "type": "integer", "minimum": 0 }, "outputTokens": { "type": "integer", "minimum": 0 }, "totalCostUsd": { "type": "number", "minimum": 0 } }, "additionalProperties": true }, "assignment": { "type": "object", "properties": { "id": { "type": "string" }, "agent": { "type": "string" }, "mode": { "type": "string" }, "status": { "type": "string" }, "startedAt": { "type": "string" }, "worktree": { "type": "object", "properties": { "branch": { "type": "string" }, "path": { "type": "string" } }, "required": ["branch", "path"], "additionalProperties": true } }, "required": ["id", "agent", "mode", "status", "startedAt"], "additionalProperties": true }, "mail": { "type": "object", "properties": { "id": { "type": "string" }, "kind": { "enum": ["question", "answer", "note", "steer", "result", "stalled", "board", "checkin"] }, "from": { "type": "string" }, "assignment": { "type": "string" }, "body": { "type": "string" }, "replyTo": { "type": "string" }, "result": { "type": "object" }, "redelivered": { "type": "boolean" } }, "required": ["id", "kind", "from", "assignment"], "additionalProperties": true }, "pin": { "type": "object", "properties": { "id": { "type": "string" }, "project": { "type": "string" }, "kind": { "enum": ["claim", "decision", "finding"] }, "body": { "type": "string" }, "paths": { "type": "array", "items": { "type": "string" } }, "agent": { "type": "string" }, "sessionId": { "type": "string" }, "rootId": { "type": "string" }, "at": { "type": "string" }, "released": { "type": "string" }, "task": { "type": "string" } }, "required": ["id", "project", "kind", "body", "agent", "sessionId", "rootId", "at"], "additionalProperties": true }, "question": { "type": "object", "properties": { "id": { "type": "string" }, "sessionId": { "type": "string" }, "rootId": { "type": "string" }, "agent": { "type": "string" }, "body": { "type": "string" }, "options": { "type": "array", "items": { "type": "string" } }, "askedAt": { "type": "string" } }, "required": ["id", "sessionId", "rootId", "agent", "body", "askedAt"], "additionalProperties": true }, "spec": { "type": "object", "properties": { "cwd": { "type": "string" }, "agent": { "type": "string" }, "model": { "type": "string" }, "mode": { "type": "string" }, "thinking": { "type": "string" }, "persist": { "type": "boolean" }, "restore": { "type": "object" } }, "required": ["cwd"], "additionalProperties": true }, "item": { "anyOf": [{ "$ref": "#/$defs/knownItem" }, { "$ref": "#/$defs/unknownItem" }] }, "event": { "anyOf": [{ "$ref": "#/$defs/knownEvent" }, { "$ref": "#/$defs/unknownEvent" }] }, "envelope": { "type": "object", "properties": { "sessionId": { "type": "string" }, "epoch": { "type": "string" }, "seq": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 }, "ts": { "type": "string" }, "event": { "$ref": "#/$defs/event" }, "cursor": { "type": "integer", "minimum": 1, "maximum": 9007199254740991 } }, "required": ["sessionId", "epoch", "seq", "ts", "event"], "additionalProperties": true }, "request": { "type": "object", "properties": { "jsonrpc": { "const": "2.0" }, "id": { "anyOf": [{ "type": "string", "maxLength": 128 }, { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }] }, "method": { "type": "string" }, "params": { "type": "object" } }, "required": ["jsonrpc", "method", "id"], "additionalProperties": true }, "response": { "oneOf": [{ "type": "object", "properties": { "jsonrpc": { "const": "2.0" }, "id": { "anyOf": [{ "type": "string", "maxLength": 128 }, { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, { "type": "null" }] }, "result": {} }, "required": ["jsonrpc", "id", "result"], "additionalProperties": true }, { "type": "object", "properties": { "jsonrpc": { "const": "2.0" }, "id": { "anyOf": [{ "type": "string", "maxLength": 128 }, { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, { "type": "null" }] }, "error": { "$ref": "#/$defs/error" } }, "required": ["jsonrpc", "id", "error"], "additionalProperties": true }] }, "notification": { "type": "object", "properties": { "jsonrpc": { "const": "2.0" }, "method": { "const": "event" }, "params": { "$ref": "#/$defs/envelope" } }, "required": ["jsonrpc", "method", "params"], "additionalProperties": true }, "knownEvent": { "oneOf": [{ "type": "object", "properties": { "type": { "const": "session.opened" }, "session": { "$ref": "#/$defs/session" }, "cwd": { "type": "string" }, "effective": { "type": "object", "properties": { "model": { "type": "string" }, "thinking": { "type": "string" } }, "required": ["model", "thinking"], "additionalProperties": true } }, "required": ["type", "session", "cwd", "effective"], "additionalProperties": true }, { "type": "object", "properties": { "type": { "const": "session.ready" } }, "required": ["type"], "additionalProperties": true }, { "type": "object", "properties": { "type": { "const": "session.updated" }, "session": { "$ref": "#/$defs/session" } }, "required": ["type", "session"], "additionalProperties": true }, { "type": "object", "properties": { "type": { "const": "session.closed" } }, "required": ["type"], "additionalProperties": true }, { "type": "object", "properties": { "type": { "const": "session.failed" }, "error": { "$ref": "#/$defs/alpError" } }, "required": ["type", "error"], "additionalProperties": true }, { "type": "object", "properties": { "type": { "const": "prompt.accepted" }, "clientMessageId": { "type": "string" }, "result": { "enum": ["turn", "steer"] }, "turnId": { "type": "string" } }, "required": ["type", "clientMessageId", "result", "turnId"], "additionalProperties": true }, { "type": "object", "properties": { "type": { "const": "prompt.failed" }, "clientMessageId": { "type": "string" }, "error": { "$ref": "#/$defs/alpError" } }, "required": ["type", "clientMessageId", "error"], "additionalProperties": true }, { "type": "object", "properties": { "type": { "const": "turn.started" }, "turnId": { "type": "string" }, "origin": { "enum": ["user", "wake", "assignment", "runtime"] } }, "required": ["type", "turnId", "origin"], "additionalProperties": true }, { "type": "object", "properties": { "type": { "const": "turn.ended" }, "turnId": { "type": "string" }, "state": { "enum": ["completed", "failed", "canceled"] }, "error": { "$ref": "#/$defs/alpError" } }, "required": ["type", "turnId", "state"], "additionalProperties": true }, { "type": "object", "properties": { "type": { "const": "item" }, "item": { "$ref": "#/$defs/item" } }, "required": ["type", "item"], "additionalProperties": true }, { "type": "object", "properties": { "type": { "const": "usage" }, "usage": { "$ref": "#/$defs/usage" } }, "required": ["type", "usage"], "additionalProperties": true }, { "type": "object", "properties": { "type": { "const": "mail" }, "mail": { "$ref": "#/$defs/mail" } }, "required": ["type", "mail"], "additionalProperties": true }, { "type": "object", "properties": { "type": { "const": "assignment" }, "assignment": { "$ref": "#/$defs/assignment" } }, "required": ["type", "assignment"], "additionalProperties": true }, { "type": "object", "properties": { "type": { "const": "question" }, "question": { "$ref": "#/$defs/question" } }, "required": ["type", "question"], "additionalProperties": true }, { "type": "object", "properties": { "type": { "const": "question.resolved" }, "questionId": { "type": "string" }, "outcome": { "enum": ["answered", "dismissed", "timeout", "canceled"] }, "answer": { "type": "string" } }, "required": ["type", "questionId", "outcome"], "additionalProperties": true }, { "type": "object", "properties": { "type": { "const": "pin" }, "pin": { "$ref": "#/$defs/pin" } }, "required": ["type", "pin"], "additionalProperties": true }, { "type": "object", "properties": { "type": { "const": "unpin" }, "pinId": { "type": "string" }, "reason": { "enum": ["unpinned", "session_ended"] } }, "required": ["type", "pinId", "reason"], "additionalProperties": true }] }, "unknownEvent": { "type": "object", "properties": { "type": { "type": "string", "not": { "enum": ["session.opened", "session.ready", "session.updated", "session.closed", "session.failed", "prompt.accepted", "prompt.failed", "turn.started", "turn.ended", "item", "usage", "mail", "assignment", "question", "question.resolved", "pin", "unpin"] } } }, "required": ["type"], "additionalProperties": true }, "knownItem": { "oneOf": [{ "type": "object", "properties": { "kind": { "const": "user_message" }, "id": { "type": "string" }, "text": { "type": "string" }, "clientMessageId": { "type": "string" }, "images": { "type": "integer", "minimum": 1 } }, "required": ["kind", "id", "text"], "additionalProperties": true }, { "type": "object", "properties": { "kind": { "const": "assistant_message" }, "id": { "type": "string" }, "text": { "type": "string" } }, "required": ["kind", "id", "text"], "additionalProperties": true }, { "type": "object", "properties": { "kind": { "const": "notice" }, "id": { "type": "string" }, "level": { "enum": ["info", "warning", "error"] }, "text": { "type": "string" } }, "required": ["kind", "id", "level", "text"], "additionalProperties": true }, { "type": "object", "properties": { "kind": { "const": "compaction" }, "id": { "type": "string" }, "status": { "enum": ["running", "completed", "failed"] }, "trigger": { "type": "string" }, "preTokens": { "type": "integer" }, "postTokens": { "type": "integer" } }, "required": ["kind", "id", "status"], "additionalProperties": true }, { "type": "object", "properties": { "kind": { "const": "todo" }, "id": { "type": "string" }, "items": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "text": { "type": "string" }, "status": { "enum": ["pending", "in_progress", "completed"] } }, "required": ["id", "text", "status"], "additionalProperties": true } } }, "required": ["kind", "id", "items"], "additionalProperties": true }, { "type": "object", "properties": { "kind": { "const": "tool_call" }, "id": { "type": "string" }, "callId": { "type": "string" }, "name": { "type": "string" }, "status": { "enum": ["running", "completed", "failed"] }, "error": { "type": "string" }, "detail": { "$ref": "#/$defs/toolCallDetail" } }, "required": ["kind", "id", "callId", "name", "status", "detail"], "additionalProperties": true }] }, "unknownItem": { "type": "object", "properties": { "kind": { "type": "string", "not": { "enum": ["user_message", "assistant_message", "notice", "compaction", "todo", "tool_call"] } }, "id": { "type": "string" } }, "required": ["kind", "id"], "additionalProperties": true }, "toolCallDetail": { "oneOf": [{ "type": "object", "properties": { "type": { "const": "shell" }, "command": { "type": "string" }, "cwd": { "type": "string" }, "output": { "type": "string" }, "exitCode": { "type": ["integer", "null"] } }, "required": ["type", "command", "output"], "additionalProperties": true }, { "type": "object", "properties": { "type": { "const": "read" }, "filePath": { "type": "string" }, "content": { "type": "string" }, "offset": { "type": "integer" }, "limit": { "type": "integer" } }, "required": ["type", "filePath"], "additionalProperties": true }, { "type": "object", "properties": { "type": { "const": "edit" }, "filePath": { "type": "string" }, "oldString": { "type": "string" }, "newString": { "type": "string" }, "unifiedDiff": { "type": "string" } }, "required": ["type", "filePath"], "additionalProperties": true }, { "type": "object", "properties": { "type": { "const": "write" }, "filePath": { "type": "string" }, "content": { "type": "string" } }, "required": ["type", "filePath"], "additionalProperties": true }, { "type": "object", "properties": { "type": { "const": "search" }, "query": { "type": "string" }, "toolName": { "enum": ["search", "grep", "glob", "web_search"] }, "content": { "type": "string" }, "filePaths": { "type": "array", "items": { "type": "string" } }, "webResults": { "type": "array", "items": { "type": "object", "properties": { "title": { "type": "string" }, "url": { "type": "string" } }, "required": ["title", "url"], "additionalProperties": true } }, "numFiles": { "type": "integer" }, "numMatches": { "type": "integer" }, "truncated": { "type": "boolean" } }, "required": ["type", "query"], "additionalProperties": true }, { "type": "object", "properties": { "type": { "const": "fetch" }, "url": { "type": "string" }, "prompt": { "type": "string" }, "result": { "type": "string" }, "code": { "type": "integer" } }, "required": ["type", "url"], "additionalProperties": true }, { "type": "object", "properties": { "type": { "const": "sub_agent" }, "subAgentType": { "type": "string" }, "description": { "type": "string" }, "log": { "type": "string" } }, "required": ["type"], "additionalProperties": true }, { "type": "object", "properties": { "type": { "const": "plan" }, "text": { "type": "string" } }, "required": ["type", "text"], "additionalProperties": true }, { "type": "object", "properties": { "type": { "const": "plain_text" }, "label": { "type": "string" }, "text": { "type": "string" } }, "required": ["type"], "additionalProperties": true }, { "type": "object", "properties": { "type": { "const": "unknown" }, "input": {}, "output": {} }, "required": ["type", "input", "output"], "additionalProperties": true }, { "type": "object", "properties": { "type": { "type": "string", "not": { "enum": ["shell", "read", "edit", "write", "search", "fetch", "sub_agent", "plan", "plain_text", "unknown"] } } }, "required": ["type"], "additionalProperties": true }] }, "alpError": { "type": "object", "properties": { "message": { "type": "string" }, "code": { "type": "string" } }, "required": ["message"], "additionalProperties": true }, "sessionSummary": { "type": "object", "properties": { "id": { "type": "string" }, "projectRoot": { "type": "string" }, "agent": { "type": "string" }, "runtime": { "enum": ["claude", "codex", "acp", "antigravity"] }, "model": { "type": "string" }, "mode": { "type": "string" }, "thinking": { "type": "string" }, "workflow": { "type": "object", "properties": { "mode": { "type": "string" }, "maxPeers": { "type": "integer" }, "supervisor": { "type": "boolean" } }, "required": ["mode", "maxPeers", "supervisor"], "additionalProperties": true }, "threadId": { "type": "string" }, "persistent": { "type": "boolean" }, "busy": { "type": "boolean" }, "parentId": { "type": "string" }, "toolCallId": { "type": "string" }, "activeTurnId": { "type": "string" }, "parked": { "type": "string" }, "instructionsSha": { "type": "string" }, "teamLabel": { "type": "string" }, "status": { "enum": ["initializing", "idle", "running", "error", "closed"] }, "title": { "type": "string" }, "archived": { "type": "boolean" }, "lastError": { "type": "object", "properties": { "code": { "type": "string" }, "message": { "type": "string" } }, "required": ["message"], "additionalProperties": true }, "createdAt": { "type": "string" }, "updatedAt": { "type": "string" } }, "required": ["id", "projectRoot", "agent", "runtime", "model", "mode", "thinking", "workflow", "threadId", "persistent", "busy", "status"], "additionalProperties": true }, "pause": { "type": "object", "properties": { "since": { "type": "string" }, "by": { "type": "string" }, "reason": { "type": "string" }, "resetsAt": { "type": "string" }, "checkedAt": { "type": "string" } }, "required": ["since", "by", "reason"], "additionalProperties": true }, "pauseState": { "type": "object", "properties": { "all": { "$ref": "#/$defs/pause" }, "runtimes": { "type": "object", "additionalProperties": { "$ref": "#/$defs/pause" } }, "parked": { "type": "array", "items": { "type": "object", "properties": { "assignmentId": { "type": "string" }, "agent": { "type": "string" }, "runtime": { "type": "string" }, "rootId": { "type": "string" }, "reason": { "type": "string" }, "since": { "type": "string" } }, "required": ["assignmentId", "agent", "runtime", "rootId", "reason", "since"], "additionalProperties": true } } }, "required": ["runtimes", "parked"], "additionalProperties": true }, "preview": { "type": "object", "properties": { "teams": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "label": { "type": "string" }, "description": { "type": "string" } }, "required": ["id", "label"], "additionalProperties": true } }, "team": { "type": "string" }, "teamLabel": { "type": "string" }, "agent": { "type": "string" }, "runtime": { "enum": ["claude", "codex", "acp", "antigravity"] }, "model": { "type": "string" }, "mode": { "type": "string" }, "thinking": { "type": "string" } }, "required": ["teams", "team", "agent", "runtime", "model", "mode", "thinking"], "additionalProperties": true }, "treeStatus": { "type": "object", "properties": { "rootId": { "type": "string" }, "sessions": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "projectRoot": { "type": "string" }, "agent": { "type": "string" }, "runtime": { "enum": ["claude", "codex", "acp", "antigravity"] }, "model": { "type": "string" }, "mode": { "type": "string" }, "thinking": { "type": "string" }, "workflow": { "type": "object", "properties": { "mode": { "type": "string" }, "maxPeers": { "type": "integer" }, "supervisor": { "type": "boolean" } }, "required": ["mode", "maxPeers", "supervisor"], "additionalProperties": true }, "threadId": { "type": "string" }, "persistent": { "type": "boolean" }, "busy": { "type": "boolean" }, "parentId": { "type": "string" }, "toolCallId": { "type": "string" }, "activeTurnId": { "type": "string" }, "parked": { "type": "string" }, "instructionsSha": { "type": "string" }, "teamLabel": { "type": "string" }, "state": { "enum": ["running", "waiting", "waiting_parent", "waiting_user", "idle"] }, "idleMs": { "type": "number" }, "workdir": { "type": "string" }, "unreadMail": { "type": "integer", "minimum": 0 } }, "required": ["id", "projectRoot", "agent", "runtime", "model", "mode", "thinking", "workflow", "threadId", "persistent", "busy", "state", "idleMs", "workdir", "unreadMail"], "additionalProperties": true } }, "assignments": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "requester": { "type": "string" }, "isolation": { "enum": ["shared", "worktree"] }, "idleMs": { "type": "number" } }, "required": ["id", "requester", "isolation", "idleMs"], "additionalProperties": true } }, "questions": { "type": "array", "items": { "$ref": "#/$defs/question" } }, "worktrees": { "type": "array", "items": { "type": "object", "properties": { "assignmentId": { "type": "string" }, "requester": { "type": "string" }, "agent": { "type": "string" }, "branch": { "type": "string" }, "files": { "type": "array", "items": { "type": "string" } }, "stat": { "type": "string" } }, "required": ["assignmentId", "requester", "agent", "branch", "files", "stat"], "additionalProperties": true } }, "leases": { "type": "array", "items": { "type": "object", "properties": { "checkout": { "type": "string" }, "assignmentId": { "type": "string" }, "agent": { "type": "string" } }, "required": ["checkout", "assignmentId", "agent"], "additionalProperties": true } }, "claims": { "type": "array", "items": { "$ref": "#/$defs/pin" } } }, "required": ["rootId", "sessions", "assignments", "questions", "worktrees", "leases", "claims"], "additionalProperties": true }, "health": { "type": "object", "properties": { "live": { "type": "boolean" }, "ready": { "type": "boolean" }, "checks": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "ok": { "type": "boolean" }, "code": { "type": "string" }, "message": { "type": "string" } }, "required": ["id", "ok"], "additionalProperties": true } } }, "required": ["live", "ready", "checks"], "additionalProperties": true }, "projectRoot": { "type": "string", "minLength": 1, "maxLength": 4096, "description": "An absolute, normalized path on the daemon host to a directory holding .alp/. Compared as is: the daemon never walks up to a parent." }, "taskId": { "type": "string", "pattern": "^t-[0-9a-f]{4,12}(?:\\.\\d+)*$" }, "taskRow": { "type": "object", "properties": { "id": { "$ref": "#/$defs/taskId" }, "title": { "type": "string" }, "type": { "type": "string" }, "priority": { "type": "integer" }, "status": { "enum": ["open", "in_progress", "review", "closed"] }, "rev": { "type": "integer", "minimum": 0 }, "parent": { "type": "string" }, "assignee": { "type": "string" }, "ready": { "type": "boolean" }, "blockedBy": { "type": "array", "items": { "type": "string" } }, "waits": { "type": "array", "items": { "type": "string" } }, "approvals": { "type": "array", "items": { "type": "object", "properties": { "gate": { "type": "string" }, "note": { "type": "string" } }, "required": ["gate", "note"], "additionalProperties": true } }, "handoff": { "type": "object", "properties": { "outcome": { "type": "string" }, "summary": { "type": "string" }, "agent": { "type": "string" } }, "required": ["outcome", "summary"], "additionalProperties": true }, "closed": { "type": "object", "properties": { "reason": { "type": "string" }, "summary": { "type": "string" }, "at": { "type": "string" } }, "required": ["reason", "at"], "additionalProperties": true }, "description": { "type": "string" }, "labels": { "type": "array", "items": { "type": "string" } }, "paths": { "type": "array", "items": { "type": "string" } }, "progress": { "type": "object", "properties": { "done": { "type": "integer", "minimum": 0 }, "total": { "type": "integer", "minimum": 0 } }, "required": ["done", "total"], "additionalProperties": true }, "createdAt": { "type": "string" }, "updatedAt": { "type": "string" } }, "required": ["id", "title", "type", "priority", "status", "rev", "ready", "updatedAt"], "additionalProperties": true }, "libraryKind": { "enum": ["agents", "skills", "mcp", "hooks", "teams", "providers"] }, "libraryScope": { "enum": ["library", "project"] }, "librarySource": { "enum": ["builtin", "library", "project"] }, "entryName": { "type": "string", "minLength": 1, "maxLength": 128, "pattern": "^[A-Za-z0-9_.-]+$", "not": { "enum": [".", ".."] } }, "libraryRevision": { "type": ["string", "null"] }, "libraryEntryRow": { "type": "object", "properties": { "name": { "type": "string" }, "source": { "$ref": "#/$defs/librarySource" }, "overrides": { "$ref": "#/$defs/librarySource" }, "description": { "type": "string" }, "usedBy": { "type": "array", "items": { "type": "string" } } }, "required": ["name", "source"], "additionalProperties": true }, "secretMarker": { "type": "object", "properties": { "$secret": { "const": "keep" } }, "required": ["$secret"], "additionalProperties": false, "description": "Stands for a stored secret value: read results carry it in place of the value; a save that sends it back keeps the stored value." }, "languageSetting": { "type": "object", "properties": { "language": { "type": ["string", "null"] }, "applies": { "type": "string" }, "default": { "type": "string" } }, "required": ["language", "applies", "default"], "additionalProperties": true }, "teamRow": { "type": "object", "properties": { "id": { "type": "string" }, "label": { "type": "string" }, "description": { "type": "string" }, "source": { "$ref": "#/$defs/librarySource" }, "overrides": { "$ref": "#/$defs/librarySource" }, "error": { "type": "string" } }, "required": ["id", "source"], "additionalProperties": true }, "promptImage": { "type": "object", "properties": { "type": { "const": "image" }, "mimeType": { "enum": ["image/png", "image/jpeg", "image/gif", "image/webp"] }, "data": { "type": "string", "minLength": 4, "maxLength": 6990508, "pattern": "^[A-Za-z0-9+/]+={0,2}$" }, "name": { "type": "string", "maxLength": 255 } }, "required": ["type", "mimeType", "data"], "additionalProperties": false } } };
|
|
45177
45431
|
|
|
45178
45432
|
// packages/protocol/src/validate.js
|
|
45179
45433
|
var MAX_ISSUES = 8;
|
|
@@ -45346,7 +45600,7 @@ var RpcError = class extends Error {
|
|
|
45346
45600
|
|
|
45347
45601
|
// packages/daemon/src/operations.ts
|
|
45348
45602
|
import { createHash as createHash10, createHmac, randomBytes as randomBytes5 } from "node:crypto";
|
|
45349
|
-
import { lstat as
|
|
45603
|
+
import { lstat as lstat6, stat as stat8 } from "node:fs/promises";
|
|
45350
45604
|
import path32 from "node:path";
|
|
45351
45605
|
|
|
45352
45606
|
// packages/core/src/task-rows.js
|
|
@@ -45392,8 +45646,8 @@ async function taskRows(projectRoot) {
|
|
|
45392
45646
|
}
|
|
45393
45647
|
|
|
45394
45648
|
// packages/core/src/library-edit.js
|
|
45395
|
-
import { mkdir as mkdir13, rename as
|
|
45396
|
-
import { createHash as createHash9, randomUUID as
|
|
45649
|
+
import { lstat as lstat5, mkdir as mkdir13, readdir as readdir9, rename as rename7, rm as rm5, stat as stat7, writeFile as writeFile15 } from "node:fs/promises";
|
|
45650
|
+
import { createHash as createHash9, randomUUID as randomUUID13 } from "node:crypto";
|
|
45397
45651
|
import path31 from "node:path";
|
|
45398
45652
|
var EDIT_KINDS = ["agents", "skills", "mcp", "hooks", "teams", "providers"];
|
|
45399
45653
|
var validName3 = (name2) => typeof name2 === "string" && /^[\w.-]+$/.test(name2) && name2 !== "." && name2 !== "..";
|
|
@@ -45425,6 +45679,42 @@ function base(scope, { root, library }, kind) {
|
|
|
45425
45679
|
return fail5("INVALID_SCOPE", `Scope must be library or project, not '${scope}'`);
|
|
45426
45680
|
}
|
|
45427
45681
|
var revisionOf = (content) => content === void 0 ? null : createHash9("sha256").update(JSON.stringify(content)).digest("hex").slice(0, 16);
|
|
45682
|
+
function assertProjectDataContent(kind, content) {
|
|
45683
|
+
const deny = () => fail5("UNSAFE_LIBRARY_WRITE", "Project-data writes allow only instruction entries and non-executable agent configuration");
|
|
45684
|
+
if (!object8(content) || !["agents", "skills"].includes(kind)) deny();
|
|
45685
|
+
const keys2 = kind === "skills" ? ["body"] : ["instructions", "config"];
|
|
45686
|
+
if (Object.keys(content).some((key2) => !keys2.includes(key2))) deny();
|
|
45687
|
+
const text2 = kind === "skills" ? content.body : content.instructions;
|
|
45688
|
+
if (typeof text2 !== "string" || !text2.trim()) deny();
|
|
45689
|
+
if (content.config !== void 0) {
|
|
45690
|
+
const config2 = content.config;
|
|
45691
|
+
if (!object8(config2)) deny();
|
|
45692
|
+
const allowed = ["description", "model", "thinking", "context", "autocompact"];
|
|
45693
|
+
if (Object.keys(config2).some((key2) => !allowed.includes(key2))) deny();
|
|
45694
|
+
for (const key2 of ["description", "thinking"]) if (config2[key2] !== void 0 && typeof config2[key2] !== "string") deny();
|
|
45695
|
+
if (config2.model !== void 0 && (typeof config2.model !== "string" || !/^(codex|claude):[^\s/\\:]{1,240}$/.test(config2.model))) deny();
|
|
45696
|
+
for (const key2 of ["context", "autocompact"]) if (config2[key2] !== void 0 && !(typeof config2[key2] === "string" || typeof config2[key2] === "number" && Number.isFinite(config2[key2]))) deny();
|
|
45697
|
+
}
|
|
45698
|
+
}
|
|
45699
|
+
async function projectDataEntry(kind, name2, { scope, root, library, templates: templates2 }) {
|
|
45700
|
+
if (scope !== "project" || !root || !["agents", "skills"].includes(kind)) fail5("UNSAFE_LIBRARY_WRITE", "Project-data writes require project scope and agents or skills");
|
|
45701
|
+
nameOf(name2);
|
|
45702
|
+
const directory = base(scope, { root, library }, kind);
|
|
45703
|
+
await safeEntryPaths(directory, kind, name2);
|
|
45704
|
+
const found = await layers(kind, name2, { root, library, templates: templates2 });
|
|
45705
|
+
if (found.library !== void 0 || found.builtin !== void 0) fail5("UNSAFE_LIBRARY_WRITE", "Project-data writes cannot shadow or reveal a library or built-in entry");
|
|
45706
|
+
if (found.project !== void 0) assertProjectDataContent(kind, found.project);
|
|
45707
|
+
const owned = path31.join(directory, kind, name2);
|
|
45708
|
+
const files = await readdir9(owned).catch((error51) => {
|
|
45709
|
+
if (error51.code === "ENOENT") return [];
|
|
45710
|
+
throw error51;
|
|
45711
|
+
});
|
|
45712
|
+
const allowed = new Set(FILES[kind](name2).map(([file3]) => path31.basename(file3)));
|
|
45713
|
+
for (const file3 of files) {
|
|
45714
|
+
const info = await lstat5(path31.join(owned, file3));
|
|
45715
|
+
if (!allowed.has(file3) || !info.isFile() || info.isSymbolicLink() || info.nlink !== 1) fail5("UNSAFE_LIBRARY_WRITE", "Project-data entries cannot contain sidecars, links or executable assets");
|
|
45716
|
+
}
|
|
45717
|
+
}
|
|
45428
45718
|
async function safeEntryPaths(directory, kind, name2) {
|
|
45429
45719
|
for (const [file3] of FILES[kind](name2)) {
|
|
45430
45720
|
await assertNoSymlinks(directory, path31.join(kind, file3));
|
|
@@ -45617,14 +45907,18 @@ async function check3(kind, name2, content, { scope, root, library, templates: t
|
|
|
45617
45907
|
}
|
|
45618
45908
|
async function writeAtomic(file3, text2) {
|
|
45619
45909
|
await mkdir13(path31.dirname(file3), { recursive: true });
|
|
45620
|
-
const temporary = `${file3}.${
|
|
45621
|
-
await
|
|
45910
|
+
const temporary = `${file3}.${randomUUID13().slice(0, 8)}.tmp`;
|
|
45911
|
+
await writeFile15(temporary, text2);
|
|
45622
45912
|
await moveFile(temporary, file3);
|
|
45623
45913
|
}
|
|
45624
45914
|
var exists2 = (target) => stat7(target).then(() => true, () => false);
|
|
45625
|
-
async function saveEntry(kind, name2, content, { scope, root, library, templates: templates2, revision } = {}) {
|
|
45915
|
+
async function saveEntry(kind, name2, content, { scope, root, library, templates: templates2, revision, policy } = {}) {
|
|
45626
45916
|
kindOf(kind);
|
|
45627
45917
|
nameOf(name2);
|
|
45918
|
+
if (policy === "project-data") {
|
|
45919
|
+
assertProjectDataContent(kind, content);
|
|
45920
|
+
await projectDataEntry(kind, name2, { scope, root, library, templates: templates2 });
|
|
45921
|
+
}
|
|
45628
45922
|
const directory = base(scope, { root, library }, kind);
|
|
45629
45923
|
await safeEntryPaths(directory, kind, name2);
|
|
45630
45924
|
await check3(kind, name2, content, { scope, root, library, templates: templates2 });
|
|
@@ -45646,9 +45940,10 @@ async function saveEntry(kind, name2, content, { scope, root, library, templates
|
|
|
45646
45940
|
}
|
|
45647
45941
|
return { revision: revisionOf(await readLayer(kind, name2, directory)) };
|
|
45648
45942
|
}
|
|
45649
|
-
async function deleteEntry(kind, name2, { scope, root, library, templates: templates2, revision } = {}) {
|
|
45943
|
+
async function deleteEntry(kind, name2, { scope, root, library, templates: templates2, revision, policy } = {}) {
|
|
45650
45944
|
kindOf(kind);
|
|
45651
45945
|
nameOf(name2);
|
|
45946
|
+
if (policy === "project-data") await projectDataEntry(kind, name2, { scope, root, library, templates: templates2 });
|
|
45652
45947
|
const directory = base(scope, { root, library }, kind);
|
|
45653
45948
|
const current = await readLayer(kind, name2, directory);
|
|
45654
45949
|
if (current === void 0) fail5("NOT_FOUND", `No ${kind} entry '${name2}' in the ${scope}`);
|
|
@@ -45664,14 +45959,25 @@ async function deleteEntry(kind, name2, { scope, root, library, templates: templ
|
|
|
45664
45959
|
const now3 = scope === "project" && found.library !== void 0 ? "library" : "builtin";
|
|
45665
45960
|
return { removed: true, ...fallback !== void 0 ? { now: now3 } : {} };
|
|
45666
45961
|
}
|
|
45667
|
-
async function duplicateEntry(kind, from, to, { scope, root, library, templates: templates2 } = {}) {
|
|
45962
|
+
async function duplicateEntry(kind, from, to, { scope, root, library, templates: templates2, policy } = {}) {
|
|
45963
|
+
kindOf(kind);
|
|
45964
|
+
nameOf(from);
|
|
45965
|
+
nameOf(to);
|
|
45966
|
+
if (policy === "project-data") {
|
|
45967
|
+
await projectDataEntry(kind, from, { scope, root, library, templates: templates2 });
|
|
45968
|
+
await projectDataEntry(kind, to, { scope, root, library, templates: templates2 });
|
|
45969
|
+
}
|
|
45668
45970
|
const { content } = await getEntry(kind, from, { root, library, templates: templates2 });
|
|
45669
|
-
return saveEntry(kind, to, structuredClone(content), { scope, root, library, templates: templates2, revision: null });
|
|
45971
|
+
return saveEntry(kind, to, structuredClone(content), { scope, root, library, templates: templates2, revision: null, policy });
|
|
45670
45972
|
}
|
|
45671
|
-
async function renameEntry(kind, from, to, { scope, root, library, templates: templates2 } = {}) {
|
|
45973
|
+
async function renameEntry(kind, from, to, { scope, root, library, templates: templates2, policy } = {}) {
|
|
45672
45974
|
kindOf(kind);
|
|
45673
45975
|
nameOf(from);
|
|
45674
45976
|
nameOf(to);
|
|
45977
|
+
if (policy === "project-data") {
|
|
45978
|
+
await projectDataEntry(kind, from, { scope, root, library, templates: templates2 });
|
|
45979
|
+
await projectDataEntry(kind, to, { scope, root, library, templates: templates2 });
|
|
45980
|
+
}
|
|
45675
45981
|
const directory = base(scope, { root, library }, kind);
|
|
45676
45982
|
const content = await readLayer(kind, from, directory);
|
|
45677
45983
|
if (content === void 0) fail5("NOT_FOUND", `No ${kind} entry '${from}' in the ${scope}`);
|
|
@@ -45681,9 +45987,9 @@ async function renameEntry(kind, from, to, { scope, root, library, templates: te
|
|
|
45681
45987
|
await check3(kind, to, content, { scope, root, library, templates: templates2 });
|
|
45682
45988
|
if (ownDirectory(kind)) {
|
|
45683
45989
|
if (await exists2(path31.join(directory, kind, to))) fail5("REVISION_CONFLICT", `${path31.join(directory, kind, to)} already exists`);
|
|
45684
|
-
await
|
|
45990
|
+
await rename7(path31.join(directory, kind, from), path31.join(directory, kind, to));
|
|
45685
45991
|
} else {
|
|
45686
|
-
await
|
|
45992
|
+
await rename7(path31.join(directory, kind, `${from}.json`), path31.join(directory, kind, `${to}.json`));
|
|
45687
45993
|
}
|
|
45688
45994
|
return { revision: revisionOf(await readLayer(kind, to, directory)) };
|
|
45689
45995
|
}
|
|
@@ -45702,6 +46008,8 @@ function fromCore(error51, context = {}) {
|
|
|
45702
46008
|
if (error51 instanceof RpcError || typeof error51?.code !== "string" || error51?.name !== "AlpError") return error51;
|
|
45703
46009
|
const message = error51.message;
|
|
45704
46010
|
switch (error51.code) {
|
|
46011
|
+
case "UNSAFE_LIBRARY_WRITE":
|
|
46012
|
+
return failure(ERROR.forbidden, "library_policy", message);
|
|
45705
46013
|
case "UNSAFE_PATH":
|
|
45706
46014
|
return failure(ERROR.forbidden, "unsafe_path", message);
|
|
45707
46015
|
case "TASK_NOT_FOUND":
|
|
@@ -45791,7 +46099,7 @@ function createOperations({ home, templates: templates2, knownProjects = () => [
|
|
|
45791
46099
|
async function project2(value) {
|
|
45792
46100
|
if (!path32.isAbsolute(value) || path32.resolve(value) !== value) throw failure(RPC_ERROR.invalidParams, "invalid_path", "projectRoot must be an absolute, normalized path");
|
|
45793
46101
|
if (!(await stat8(value).catch(() => void 0))?.isDirectory()) throw failure(ERROR.notFound, "not_alp_project", `${value} is not a directory`);
|
|
45794
|
-
const alp = await
|
|
46102
|
+
const alp = await lstat6(path32.join(value, ".alp")).catch(() => void 0);
|
|
45795
46103
|
if (alp?.isSymbolicLink()) throw failure(ERROR.forbidden, "unsafe_path", `${path32.join(value, ".alp")} is a symlink`);
|
|
45796
46104
|
if (!alp?.isDirectory()) throw failure(ERROR.notFound, "not_alp_project", `${value} is not an ALP project; run alp init there`);
|
|
45797
46105
|
return value;
|
|
@@ -45877,7 +46185,8 @@ function createOperations({ home, templates: templates2, knownProjects = () => [
|
|
|
45877
46185
|
const { content, secrets } = redact2(kind, entry.content);
|
|
45878
46186
|
return { ...entry, content, revision: toWire(entry.revision), ...secrets.length ? { secrets } : {} };
|
|
45879
46187
|
}),
|
|
45880
|
-
"library.save": guard(({ kind, name: name2, scope, projectRoot, content, revision, sync = "none" }) => serial(async () => {
|
|
46188
|
+
"library.save": guard(({ kind, name: name2, scope, projectRoot, content, revision, policy, sync = "none" }) => serial(async () => {
|
|
46189
|
+
if (policy === "project-data" && sync !== "none") throw failure(ERROR.forbidden, "library_policy", "Project-data writes cannot synchronize projects");
|
|
45881
46190
|
const options2 = await where(projectRoot, scope);
|
|
45882
46191
|
const current = await layer(kind, name2, options2, scope);
|
|
45883
46192
|
if (revision !== void 0 && revision !== toWire(current?.revision ?? null)) {
|
|
@@ -45885,7 +46194,7 @@ function createOperations({ home, templates: templates2, knownProjects = () => [
|
|
|
45885
46194
|
}
|
|
45886
46195
|
const previous = current?.content ?? (await layer(kind, name2, options2))?.content;
|
|
45887
46196
|
const next = unredact(kind, content, previous);
|
|
45888
|
-
const saved = await saveEntry(kind, name2, next, { ...options2, scope, ...revision !== void 0 ? { revision: current?.revision ?? null } : {} });
|
|
46197
|
+
const saved = await saveEntry(kind, name2, next, { ...options2, scope, policy, ...revision !== void 0 ? { revision: current?.revision ?? null } : {} });
|
|
45889
46198
|
if (kind !== "teams" || sync !== "known-projects") return { revision: toWire(saved.revision) };
|
|
45890
46199
|
const roots = new Set(options2.root ? [options2.root] : []);
|
|
45891
46200
|
if (scope === "library") {
|
|
@@ -45902,25 +46211,25 @@ function createOperations({ home, templates: templates2, knownProjects = () => [
|
|
|
45902
46211
|
}
|
|
45903
46212
|
return { revision: toWire(saved.revision), syncedProjects, syncErrors };
|
|
45904
46213
|
}), { notFound: "invalid_entry" }),
|
|
45905
|
-
"library.delete": guard(({ kind, name: name2, scope, projectRoot, revision }) => serial(async () => {
|
|
46214
|
+
"library.delete": guard(({ kind, name: name2, scope, projectRoot, revision, policy }) => serial(async () => {
|
|
45906
46215
|
const options2 = await where(projectRoot, scope);
|
|
45907
46216
|
const current = await layer(kind, name2, options2, scope);
|
|
45908
46217
|
if (!current) throw failure(ERROR.notFound, "not_found", `No ${kind} entry '${name2}' in the ${scope}`);
|
|
45909
46218
|
if (revision !== void 0 && revision !== toWire(current.revision)) throw failure(ERROR.conflict, "revision_conflict", `${kind} '${name2}' changed in the ${scope} since you opened it`);
|
|
45910
|
-
return deleteEntry(kind, name2, { ...options2, scope, ...revision !== void 0 ? { revision: current.revision } : {} });
|
|
46219
|
+
return deleteEntry(kind, name2, { ...options2, scope, policy, ...revision !== void 0 ? { revision: current.revision } : {} });
|
|
45911
46220
|
})),
|
|
45912
|
-
"library.duplicate": guard(({ kind, from, to, scope, projectRoot }) => serial(async () => {
|
|
46221
|
+
"library.duplicate": guard(({ kind, from, to, scope, projectRoot, policy }) => serial(async () => {
|
|
45913
46222
|
const options2 = await where(projectRoot, scope);
|
|
45914
46223
|
try {
|
|
45915
46224
|
await getEntry(kind, from, options2);
|
|
45916
46225
|
} catch (error51) {
|
|
45917
46226
|
throw fromCore(error51, { notFound: "not_found" });
|
|
45918
46227
|
}
|
|
45919
|
-
return { revision: toWire((await duplicateEntry(kind, from, to, { ...options2, scope })).revision) };
|
|
46228
|
+
return { revision: toWire((await duplicateEntry(kind, from, to, { ...options2, scope, policy })).revision) };
|
|
45920
46229
|
}), { notFound: "invalid_entry" }),
|
|
45921
|
-
"library.rename": guard(({ kind, from, to, scope, projectRoot }) => serial(async () => {
|
|
46230
|
+
"library.rename": guard(({ kind, from, to, scope, projectRoot, policy }) => serial(async () => {
|
|
45922
46231
|
const options2 = await where(projectRoot, scope);
|
|
45923
|
-
return { revision: toWire((await renameEntry(kind, from, to, { ...options2, scope })).revision) };
|
|
46232
|
+
return { revision: toWire((await renameEntry(kind, from, to, { ...options2, scope, policy })).revision) };
|
|
45924
46233
|
})),
|
|
45925
46234
|
"library.skills.set": guard(({ agent, skills }) => serial(() => setGivenSkills(agent, skills, { library: home })), { notFound: "invalid_entry" }),
|
|
45926
46235
|
"library.models": guard(async () => {
|
|
@@ -45941,13 +46250,13 @@ function createOperations({ home, templates: templates2, knownProjects = () => [
|
|
|
45941
46250
|
const library = home !== void 0;
|
|
45942
46251
|
return {
|
|
45943
46252
|
handlers: { ...taskHandlers, ...library ? libraryHandlers : {} },
|
|
45944
|
-
capabilities: [CAPABILITY.task, ...library ? [CAPABILITY.team, CAPABILITY.library, CAPABILITY.settingsLanguage] : []]
|
|
46253
|
+
capabilities: [CAPABILITY.task, ...library ? [CAPABILITY.team, CAPABILITY.library, CAPABILITY.libraryProjectWrite, CAPABILITY.settingsLanguage] : []]
|
|
45945
46254
|
};
|
|
45946
46255
|
}
|
|
45947
46256
|
|
|
45948
46257
|
// packages/daemon/src/files.ts
|
|
45949
46258
|
import { constants as constants3 } from "node:fs";
|
|
45950
|
-
import { lstat as
|
|
46259
|
+
import { lstat as lstat7, open as open4, opendir, realpath as realpath5, stat as stat9 } from "node:fs/promises";
|
|
45951
46260
|
import path34 from "node:path";
|
|
45952
46261
|
|
|
45953
46262
|
// packages/daemon/src/gitignore.ts
|
|
@@ -46050,7 +46359,8 @@ function hasGitEntry(root) {
|
|
|
46050
46359
|
try {
|
|
46051
46360
|
lstatSync2(path33.join(directory, ".git"));
|
|
46052
46361
|
return true;
|
|
46053
|
-
} catch {
|
|
46362
|
+
} catch (error51) {
|
|
46363
|
+
if (error51.code !== "ENOENT") throw new IgnoreUnknown("cannot examine .git");
|
|
46054
46364
|
}
|
|
46055
46365
|
if (path33.dirname(directory) === directory) return false;
|
|
46056
46366
|
}
|
|
@@ -46146,22 +46456,34 @@ function check4(git3, root, paths, deadline, timeoutMs) {
|
|
|
46146
46456
|
if (err.length < GIT_CHECK.maxErrorBytes) err += chunk.toString("utf8");
|
|
46147
46457
|
});
|
|
46148
46458
|
child.on("error", (error51) => finish(() => {
|
|
46149
|
-
|
|
46150
|
-
else reject(new IgnoreUnknown(error51.message));
|
|
46459
|
+
reject(new IgnoreUnknown(error51.message));
|
|
46151
46460
|
}));
|
|
46152
46461
|
child.on("close", (code) => finish(() => {
|
|
46153
46462
|
if (code === 128 && /not a git repository/i.test(err)) {
|
|
46154
|
-
|
|
46155
|
-
|
|
46463
|
+
try {
|
|
46464
|
+
if (hasGitEntry(root)) reject(new IgnoreUnknown("a .git Git cannot use"));
|
|
46465
|
+
else resolve2(null);
|
|
46466
|
+
} catch (error51) {
|
|
46467
|
+
reject(error51);
|
|
46468
|
+
}
|
|
46156
46469
|
return;
|
|
46157
46470
|
}
|
|
46158
46471
|
if (code !== 0 && code !== 1) {
|
|
46159
46472
|
reject(new IgnoreUnknown(`exit ${code}`));
|
|
46160
46473
|
return;
|
|
46161
46474
|
}
|
|
46475
|
+
if (err.length || code === 1 && outBytes || code === 0 && !outBytes) {
|
|
46476
|
+
reject(new IgnoreUnknown("inconsistent exit status or diagnostics"));
|
|
46477
|
+
return;
|
|
46478
|
+
}
|
|
46479
|
+
const output = Buffer.concat(out).toString("utf8");
|
|
46480
|
+
if (outBytes && !output.endsWith("\0")) {
|
|
46481
|
+
reject(new IgnoreUnknown("unterminated answer"));
|
|
46482
|
+
return;
|
|
46483
|
+
}
|
|
46162
46484
|
const asked = new Set(paths);
|
|
46163
46485
|
const ignored = /* @__PURE__ */ new Set();
|
|
46164
|
-
for (const entry of
|
|
46486
|
+
for (const entry of output.split("\0")) {
|
|
46165
46487
|
if (!entry) continue;
|
|
46166
46488
|
const relative = entry.startsWith("./") ? entry.slice(2) : void 0;
|
|
46167
46489
|
if (relative === void 0 || !asked.has(relative)) {
|
|
@@ -46194,7 +46516,7 @@ var HIDDEN_DIRECTORIES = /* @__PURE__ */ new Set([".agents", ".alp", ".claude",
|
|
|
46194
46516
|
var IGNORED_DIRECTORIES = /* @__PURE__ */ new Set(["node_modules", "venv", "env", "virtualenv", "dist", "build", "target", "out", "coverage", "vendor", "__pycache__", ".git"]);
|
|
46195
46517
|
var NONE = Number.MAX_SAFE_INTEGER;
|
|
46196
46518
|
async function identity2(directory) {
|
|
46197
|
-
const info = await
|
|
46519
|
+
const info = await lstat7(directory, { bigint: true });
|
|
46198
46520
|
if (!info.isDirectory() || await realpath5(directory) !== directory) return null;
|
|
46199
46521
|
return `${info.dev}:${info.ino}`;
|
|
46200
46522
|
}
|
|
@@ -46235,7 +46557,7 @@ function rank2(relative, query) {
|
|
|
46235
46557
|
var compare = (a, b) => a.tier - b.tier || a.segment - b.segment || a.offset - b.offset || a.fuzzy - b.fuzzy || a.depth - b.depth || (a.path < b.path ? -1 : a.path > b.path ? 1 : 0);
|
|
46236
46558
|
var FilesError = class extends Error {
|
|
46237
46559
|
};
|
|
46238
|
-
async function searchWorkspaceFiles(projectRoot, { query = "", limit = LIMITS.defaultLimit, now: now3 = Date.now } = {}) {
|
|
46560
|
+
async function searchWorkspaceFiles(projectRoot, { query = "", limit = LIMITS.defaultLimit, now: now3 = Date.now, git: git3 } = {}) {
|
|
46239
46561
|
if (!path34.isAbsolute(projectRoot)) throw new FilesError("projectRoot must be an absolute path");
|
|
46240
46562
|
let root;
|
|
46241
46563
|
try {
|
|
@@ -46247,12 +46569,14 @@ async function searchWorkspaceFiles(projectRoot, { query = "", limit = LIMITS.de
|
|
|
46247
46569
|
const wanted = query.trim().replace(/\\/g, "/").replace(/^\.?\/+/, "").toLowerCase();
|
|
46248
46570
|
const count = Math.max(1, Math.min(LIMITS.maxLimit, Math.trunc(limit)));
|
|
46249
46571
|
const deadline = now3() + LIMITS.ms;
|
|
46572
|
+
const realDeadline = Date.now() + LIMITS.ms;
|
|
46250
46573
|
const found = [];
|
|
46251
46574
|
let scanned = 0;
|
|
46252
46575
|
let truncated = false;
|
|
46253
46576
|
let level = [""];
|
|
46254
46577
|
for (let depth = 0; level.length && !truncated; depth++) {
|
|
46255
46578
|
const next = [];
|
|
46579
|
+
const levelFiles = [];
|
|
46256
46580
|
for (const relative of level) {
|
|
46257
46581
|
if (scanned >= LIMITS.scanned || now3() > deadline) {
|
|
46258
46582
|
truncated = true;
|
|
@@ -46271,6 +46595,7 @@ async function searchWorkspaceFiles(projectRoot, { query = "", limit = LIMITS.de
|
|
|
46271
46595
|
}
|
|
46272
46596
|
const name2 = entry.name;
|
|
46273
46597
|
const child = relative ? `${relative}/${name2}` : name2;
|
|
46598
|
+
if (name2.includes("\\") || blockedFilePath(child)) continue;
|
|
46274
46599
|
if (entry.isFile()) {
|
|
46275
46600
|
if (name2.startsWith(".")) continue;
|
|
46276
46601
|
const ranked = rank2(child, wanted);
|
|
@@ -46284,11 +46609,27 @@ async function searchWorkspaceFiles(projectRoot, { query = "", limit = LIMITS.de
|
|
|
46284
46609
|
} catch {
|
|
46285
46610
|
continue;
|
|
46286
46611
|
}
|
|
46287
|
-
|
|
46612
|
+
levelFiles.push(...files);
|
|
46288
46613
|
next.push(...directories2);
|
|
46289
46614
|
if (truncated) break;
|
|
46290
46615
|
}
|
|
46291
|
-
|
|
46616
|
+
const remaining = Math.min(deadline - now3(), realDeadline - Date.now());
|
|
46617
|
+
if (remaining <= 0) {
|
|
46618
|
+
truncated = true;
|
|
46619
|
+
break;
|
|
46620
|
+
}
|
|
46621
|
+
let ignored;
|
|
46622
|
+
try {
|
|
46623
|
+
ignored = await gitIgnored(root, [...levelFiles.map((file3) => file3.path), ...next], {
|
|
46624
|
+
...git3,
|
|
46625
|
+
timeoutMs: Math.min(git3?.timeoutMs ?? GIT_CHECK.timeoutMs, remaining)
|
|
46626
|
+
});
|
|
46627
|
+
} catch (error51) {
|
|
46628
|
+
if (!(error51 instanceof IgnoreUnknown)) throw error51;
|
|
46629
|
+
return { files: [], truncated: true };
|
|
46630
|
+
}
|
|
46631
|
+
found.push(...levelFiles.filter((file3) => !ignored?.has(file3.path)));
|
|
46632
|
+
level = next.filter((directory) => !ignored?.has(directory));
|
|
46292
46633
|
}
|
|
46293
46634
|
found.sort(compare);
|
|
46294
46635
|
return { files: found.slice(0, count).map((entry) => ({ path: entry.path })), ...truncated ? { truncated: true } : {} };
|
|
@@ -46335,7 +46676,7 @@ async function directoryChain(root, segments, relative) {
|
|
|
46335
46676
|
async function directoryIdentity(directory, relative) {
|
|
46336
46677
|
let info;
|
|
46337
46678
|
try {
|
|
46338
|
-
info = await
|
|
46679
|
+
info = await lstat7(directory, { bigint: true });
|
|
46339
46680
|
} catch {
|
|
46340
46681
|
throw notFound(relative);
|
|
46341
46682
|
}
|
|
@@ -46371,7 +46712,7 @@ async function ignoredOf(root, paths, git3) {
|
|
|
46371
46712
|
}
|
|
46372
46713
|
}
|
|
46373
46714
|
async function readConfined(file3, maxBytes, probe) {
|
|
46374
|
-
const before = await
|
|
46715
|
+
const before = await lstat7(file3, { bigint: true });
|
|
46375
46716
|
if (before.isSymbolicLink()) throw Object.assign(new Error("link"), { linked: true });
|
|
46376
46717
|
if (!before.isFile()) throw new Error("not a file");
|
|
46377
46718
|
if (before.nlink > 1n) throw Object.assign(new Error("hard link"), { linked: true });
|
|
@@ -46397,7 +46738,7 @@ async function readConfined(file3, maxBytes, probe) {
|
|
|
46397
46738
|
}
|
|
46398
46739
|
if (length > maxBytes) return void 0;
|
|
46399
46740
|
await probe?.("read");
|
|
46400
|
-
const after = await
|
|
46741
|
+
const after = await lstat7(file3, { bigint: true });
|
|
46401
46742
|
if (after.dev !== before.dev || after.ino !== before.ino) throw Object.assign(new Error("changed"), { linked: true });
|
|
46402
46743
|
return { bytes: buffer.subarray(0, length), modifiedAt: opened.mtime };
|
|
46403
46744
|
} finally {
|
|
@@ -46454,7 +46795,7 @@ async function listWorkspaceDirectory(projectRoot, { path: relative, includeIgno
|
|
|
46454
46795
|
}
|
|
46455
46796
|
let info;
|
|
46456
46797
|
try {
|
|
46457
|
-
info = await
|
|
46798
|
+
info = await lstat7(path34.join(directory, name2));
|
|
46458
46799
|
} catch {
|
|
46459
46800
|
continue;
|
|
46460
46801
|
}
|
|
@@ -46595,13 +46936,19 @@ function createDaemonServer({ runtime, socketPath, version: version2, onShutdown
|
|
|
46595
46936
|
if (event.type === "session.opened") {
|
|
46596
46937
|
record3 ??= { version: 1, id: sessionId, rootId: root, status: "initializing", createdAt: now3, updatedAt: now3 };
|
|
46597
46938
|
const usage = event.session.usage ?? record3.session?.usage;
|
|
46598
|
-
|
|
46939
|
+
const parked = recovering.has(root) ? record3.session?.parked : event.session.parked;
|
|
46940
|
+
save2(record3, { rootId: root, session: { ...event.session, ...usage ? { usage } : {}, ...parked ? { parked } : {} }, status: "idle", lastError: void 0, activeTurnId: void 0 });
|
|
46599
46941
|
return false;
|
|
46600
46942
|
}
|
|
46601
46943
|
if (!record3) return false;
|
|
46602
46944
|
if (event.type === "session.updated") save2(record3, { session: { ...record3.session, ...event.session, ...event.session.parked ? {} : { parked: void 0 } } });
|
|
46603
46945
|
else if (event.type === "turn.started") save2(record3, { status: "running", activeTurnId: event.turnId, archived: void 0 });
|
|
46604
|
-
else if (event.type === "turn.ended") save2(record3, {
|
|
46946
|
+
else if (event.type === "turn.ended") save2(record3, {
|
|
46947
|
+
status: "idle",
|
|
46948
|
+
activeTurnId: void 0,
|
|
46949
|
+
...record3.session ? { session: { ...record3.session, parked: event.state === "failed" ? runtime.snapshot(sessionId)?.parked : void 0 } } : {},
|
|
46950
|
+
...event.state === "failed" ? { lastError: { message: event.error?.message ?? "Turn failed" } } : {}
|
|
46951
|
+
});
|
|
46605
46952
|
else if (event.type === "usage" && record3.session) record3.session = { ...record3.session, usage: event.usage };
|
|
46606
46953
|
else if (event.type === "session.failed") save2(record3, { status: "error", lastError: event.error });
|
|
46607
46954
|
else if (event.type === "session.closed") save2(record3, { status: record3.status === "error" ? "error" : "closed", activeTurnId: void 0 });
|
|
@@ -46666,7 +47013,7 @@ function createDaemonServer({ runtime, socketPath, version: version2, onShutdown
|
|
|
46666
47013
|
for (const [root, tree] of byRoot) {
|
|
46667
47014
|
const head = tree.find((record3) => record3.id === root);
|
|
46668
47015
|
if (removed.has(root)) continue;
|
|
46669
|
-
if (head && resumable(head) && (head.status === "running" || tree.some((record3) => continuing.has(record3.id)))) reopen.push({ record: head, working: head.status === "running" });
|
|
47016
|
+
if (head && resumable(head) && (head.status === "running" || head.status === "idle" && head.session?.parked || tree.some((record3) => continuing.has(record3.id)))) reopen.push({ record: head, working: head.status === "running" });
|
|
46670
47017
|
if (tree.some((record3) => LIVE.includes(record3.status))) seen(root, await store2.timeline(root));
|
|
46671
47018
|
for (const record3 of tree) {
|
|
46672
47019
|
records.set(record3.id, record3);
|
|
@@ -46674,7 +47021,7 @@ function createDaemonServer({ runtime, socketPath, version: version2, onShutdown
|
|
|
46674
47021
|
const envelope = (event) => ({ sessionId: record3.id, epoch, seq: 0, ts: (/* @__PURE__ */ new Date()).toISOString(), event });
|
|
46675
47022
|
if (record3.activeTurnId) keep(root, envelope({ type: "turn.ended", turnId: record3.activeTurnId, state: "failed", error: { message: ended.message, code: ended.code } }));
|
|
46676
47023
|
if (record3.id === root) {
|
|
46677
|
-
save2(record3, record3.status === "idle" ? { status: "closed", activeTurnId: void 0 } : { status: "error", lastError: ended, activeTurnId: void 0 });
|
|
47024
|
+
if (!(record3.status === "idle" && record3.session?.parked)) save2(record3, record3.status === "idle" ? { status: "closed", activeTurnId: void 0 } : { status: "error", lastError: ended, activeTurnId: void 0 });
|
|
46678
47025
|
} else if (continuing.has(record3.id) && reopen.some((entry) => entry.record.id === root)) {
|
|
46679
47026
|
save2(record3, { status: "closed", activeTurnId: void 0 });
|
|
46680
47027
|
} else {
|
|
@@ -46769,7 +47116,7 @@ function createDaemonServer({ runtime, socketPath, version: version2, onShutdown
|
|
|
46769
47116
|
persist: true,
|
|
46770
47117
|
restore: { agent: session.agent, threadId: session.threadId, runtime: session.runtime, model: session.model, workflow: session.workflow }
|
|
46771
47118
|
}, { history: "skip", delegation: record3.delegation ?? true });
|
|
46772
|
-
const outcomes = await runtime.recover(record3.id, { continueRoot: working });
|
|
47119
|
+
const outcomes = await runtime.recover(record3.id, { continueRoot: working, parkedRoot: session.parked });
|
|
46773
47120
|
recoveryLog.info(`recovered ${record3.id}: ${outcomes.map((outcome) => `${outcome.agent} ${outcome.outcome}`).join(", ") || "root"}`, { event: "recovered", sessionId: record3.id, rootId: record3.rootId });
|
|
46774
47121
|
} catch (error51) {
|
|
46775
47122
|
recoveryLog.error(`could not recover ${record3.id}`, { code: "ALP_RECOVERY_FAILED", sessionId: record3.id, rootId: record3.rootId, error: error51 });
|
|
@@ -47492,7 +47839,7 @@ ${session.id}`.toLowerCase().includes(word))).sort((a, b) => listCursor.compare(
|
|
|
47492
47839
|
async listen() {
|
|
47493
47840
|
if (process.platform !== "win32") {
|
|
47494
47841
|
await assertPrivateDirectory(path35.dirname(socketPath), { create: true });
|
|
47495
|
-
const existing = await
|
|
47842
|
+
const existing = await lstat8(socketPath).catch((error51) => {
|
|
47496
47843
|
if (error51.code === "ENOENT") return void 0;
|
|
47497
47844
|
throw error51;
|
|
47498
47845
|
});
|
|
@@ -47531,8 +47878,8 @@ ${session.id}`.toLowerCase().includes(word))).sort((a, b) => listCursor.compare(
|
|
|
47531
47878
|
if (process.platform !== "win32") {
|
|
47532
47879
|
try {
|
|
47533
47880
|
await chmod(bindPath, 384);
|
|
47534
|
-
const info = await
|
|
47535
|
-
await
|
|
47881
|
+
const info = await lstat8(bindPath);
|
|
47882
|
+
await rename8(bindPath, socketPath);
|
|
47536
47883
|
socketIdentity = { dev: info.dev, ino: info.ino };
|
|
47537
47884
|
} catch (error51) {
|
|
47538
47885
|
await new Promise((resolve2) => server.close(() => resolve2()));
|
|
@@ -47615,7 +47962,7 @@ ${session.id}`.toLowerCase().includes(word))).sort((a, b) => listCursor.compare(
|
|
|
47615
47962
|
for (const connection of connections) connection.socket?.destroy();
|
|
47616
47963
|
await stopped;
|
|
47617
47964
|
if (socketIdentity) {
|
|
47618
|
-
const current2 = await
|
|
47965
|
+
const current2 = await lstat8(socketPath).catch((error51) => {
|
|
47619
47966
|
if (error51.code === "ENOENT") return void 0;
|
|
47620
47967
|
throw error51;
|
|
47621
47968
|
});
|
|
@@ -47628,12 +47975,12 @@ ${session.id}`.toLowerCase().includes(word))).sort((a, b) => listCursor.compare(
|
|
|
47628
47975
|
}
|
|
47629
47976
|
|
|
47630
47977
|
// packages/client/src/supervise.js
|
|
47631
|
-
import { mkdir as mkdir16, unlink as unlink6, writeFile as
|
|
47978
|
+
import { mkdir as mkdir16, unlink as unlink6, writeFile as writeFile17, stat as stat10 } from "node:fs/promises";
|
|
47632
47979
|
import path37 from "node:path";
|
|
47633
47980
|
|
|
47634
47981
|
// packages/client/src/service.js
|
|
47635
47982
|
import { createHash as createHash12 } from "node:crypto";
|
|
47636
|
-
import { mkdir as mkdir15, readFile as readFile20, unlink as unlink5, writeFile as
|
|
47983
|
+
import { mkdir as mkdir15, readFile as readFile20, unlink as unlink5, writeFile as writeFile16 } from "node:fs/promises";
|
|
47637
47984
|
import os10 from "node:os";
|
|
47638
47985
|
import path36 from "node:path";
|
|
47639
47986
|
|
|
@@ -47742,16 +48089,20 @@ async function whenReady(home, timeoutMs) {
|
|
|
47742
48089
|
}
|
|
47743
48090
|
throw new Error(`alpd did not become ready within ${timeoutMs / 1e3} s; see ${path37.join(home, "logs")}`);
|
|
47744
48091
|
}
|
|
47745
|
-
async function startDaemon({ home, entry, env = process.env, timeoutMs = 15e3 }) {
|
|
47746
|
-
|
|
47747
|
-
|
|
47748
|
-
|
|
47749
|
-
|
|
47750
|
-
|
|
47751
|
-
|
|
47752
|
-
|
|
47753
|
-
|
|
47754
|
-
|
|
48092
|
+
async function startDaemon({ home, entry, env = process.env, timeoutMs = 15e3, automatic = false }) {
|
|
48093
|
+
return withDaemonLifecycle(home, "start", async () => {
|
|
48094
|
+
if (automatic) {
|
|
48095
|
+
if (await daemonHeld(home)) return;
|
|
48096
|
+
} else await releaseHold(home);
|
|
48097
|
+
const lock = await readLock(home);
|
|
48098
|
+
if (lockAlive(lock)) return lock.ready ? lock.socket : whenReady(home, timeoutMs);
|
|
48099
|
+
const service = serviceFor({ home, env });
|
|
48100
|
+
if (service && await installedProgram(service)) {
|
|
48101
|
+
await startService(service);
|
|
48102
|
+
return whenReady(home, timeoutMs);
|
|
48103
|
+
}
|
|
48104
|
+
return ensureDaemon({ home, entry, env, timeoutMs, lifecycleLocked: true });
|
|
48105
|
+
});
|
|
47755
48106
|
}
|
|
47756
48107
|
function superviseDaemon({ home, entry, env = process.env, intervalMs = 5e3, misses = 2, log: log3 = () => {
|
|
47757
48108
|
} }) {
|
|
@@ -47759,7 +48110,9 @@ function superviseDaemon({ home, entry, env = process.env, intervalMs = 5e3, mis
|
|
|
47759
48110
|
let missed = 0;
|
|
47760
48111
|
let starting;
|
|
47761
48112
|
const start = (reason) => {
|
|
47762
|
-
starting ??= startDaemon({ home, entry: typeof entry === "function" ? entry() : entry, env
|
|
48113
|
+
starting ??= startDaemon({ home, entry: typeof entry === "function" ? entry() : entry, env, automatic: reason !== "started with Paseo" }).then((socket) => {
|
|
48114
|
+
if (socket) log3(`alpd ${reason}`);
|
|
48115
|
+
}, (error51) => log3(`could not start alpd: ${error51?.message ?? error51}`)).finally(() => {
|
|
47763
48116
|
starting = void 0;
|
|
47764
48117
|
missed = 0;
|
|
47765
48118
|
});
|
|
@@ -47867,7 +48220,7 @@ import {
|
|
|
47867
48220
|
} from "@getpaseo/plugin/server/provider";
|
|
47868
48221
|
|
|
47869
48222
|
// integrations/paseo/server/provider-core.ts
|
|
47870
|
-
import { randomUUID as
|
|
48223
|
+
import { randomUUID as randomUUID14 } from "node:crypto";
|
|
47871
48224
|
|
|
47872
48225
|
// integrations/paseo/server/panel/session-tasks.ts
|
|
47873
48226
|
var sessionTasks = /* @__PURE__ */ new Map();
|
|
@@ -47894,6 +48247,17 @@ function paseoDetail(detail) {
|
|
|
47894
48247
|
}
|
|
47895
48248
|
}
|
|
47896
48249
|
|
|
48250
|
+
// integrations/paseo/server/session-usage.ts
|
|
48251
|
+
var USAGE_FIELDS = ["inputTokens", "cachedInputTokens", "outputTokens", "totalCostUsd", "contextWindowMaxTokens", "contextWindowUsedTokens"];
|
|
48252
|
+
function agentUsage(usage) {
|
|
48253
|
+
const out = {};
|
|
48254
|
+
for (const key2 of USAGE_FIELDS) {
|
|
48255
|
+
const value = usage?.[key2];
|
|
48256
|
+
if (typeof value === "number" && Number.isFinite(value)) out[key2] = value;
|
|
48257
|
+
}
|
|
48258
|
+
return out;
|
|
48259
|
+
}
|
|
48260
|
+
|
|
47897
48261
|
// integrations/paseo/server/provider-core.ts
|
|
47898
48262
|
var supported = [
|
|
47899
48263
|
"prompt.message",
|
|
@@ -48050,6 +48414,9 @@ function createAlpProvider(strategy) {
|
|
|
48050
48414
|
case "turn.ended":
|
|
48051
48415
|
emit({ type: "session.turn", sessionId, turnId: event.turnId, state: event.state, ...event.error ? { error: event.error } : {} });
|
|
48052
48416
|
return;
|
|
48417
|
+
case "usage":
|
|
48418
|
+
emit({ type: "session.usage", sessionId, usage: agentUsage(event.usage) });
|
|
48419
|
+
return;
|
|
48053
48420
|
case "item":
|
|
48054
48421
|
if (event.item.kind === "todo") {
|
|
48055
48422
|
sessionTasks.set(sessionId, event.item.items.map((entry) => entry.id));
|
|
@@ -48092,7 +48459,7 @@ function createAlpProvider(strategy) {
|
|
|
48092
48459
|
return;
|
|
48093
48460
|
}
|
|
48094
48461
|
}
|
|
48095
|
-
const notify = (sessionId, level, message) => emit({ type: "timeline.item", sessionId, item: { type: "notification", id: `alp-link-${
|
|
48462
|
+
const notify = (sessionId, level, message) => emit({ type: "timeline.item", sessionId, item: { type: "notification", id: `alp-link-${randomUUID14()}`, level, message } });
|
|
48096
48463
|
function wire(connection) {
|
|
48097
48464
|
connection.onEvent(project2);
|
|
48098
48465
|
connection.onClose((error51) => {
|
|
@@ -48876,7 +49243,9 @@ var libraryGet = defineRpc2({
|
|
|
48876
49243
|
revision: external_exports.string().nullable(),
|
|
48877
49244
|
usedBy: external_exports.array(external_exports.string()),
|
|
48878
49245
|
/** Agents: the skills the library gives it by name (role-skills.json). */
|
|
48879
|
-
librarySkills: external_exports.array(external_exports.string()).optional()
|
|
49246
|
+
librarySkills: external_exports.array(external_exports.string()).optional(),
|
|
49247
|
+
/** ALP remote mode: JSON Pointers of the values `content` holds as a secret marker, not as the value. */
|
|
49248
|
+
secrets: external_exports.array(external_exports.string()).optional()
|
|
48880
49249
|
})
|
|
48881
49250
|
});
|
|
48882
49251
|
var librarySkills2 = defineRpc2({
|
|
@@ -49154,17 +49523,17 @@ function createRemoteProvider(config2, { version: version2 = "0", state = remote
|
|
|
49154
49523
|
return state.principal;
|
|
49155
49524
|
};
|
|
49156
49525
|
async function connect2() {
|
|
49157
|
-
const
|
|
49158
|
-
state.principal =
|
|
49159
|
-
state.capabilities =
|
|
49160
|
-
void
|
|
49526
|
+
const link2 = await open6(config2, info);
|
|
49527
|
+
state.principal = link2.principal;
|
|
49528
|
+
state.capabilities = link2.capabilities;
|
|
49529
|
+
void link2.client.request("library.models", {}).then(
|
|
49161
49530
|
(result) => {
|
|
49162
49531
|
state.models = new Map((result?.models ?? []).map((model2) => [model2.id, { label: model2.label }]));
|
|
49163
49532
|
},
|
|
49164
49533
|
() => {
|
|
49165
49534
|
}
|
|
49166
49535
|
);
|
|
49167
|
-
return
|
|
49536
|
+
return link2.client;
|
|
49168
49537
|
}
|
|
49169
49538
|
return createAlpProvider({
|
|
49170
49539
|
description: "ALP agents on a remote ALP host, through its gateway",
|
|
@@ -49230,20 +49599,20 @@ var RemoteUnavailableError = class extends Error {
|
|
|
49230
49599
|
}
|
|
49231
49600
|
};
|
|
49232
49601
|
var ON_HOST = "Do this on the ALP host (the alp CLI or the ALP web app there).";
|
|
49233
|
-
var READ_ONLY = `ALP remote mode: the library of the ALP host is
|
|
49602
|
+
var READ_ONLY = `ALP remote mode: the library of the ALP host is viewed here with secrets hidden; changes and tests require the ALP host. ${ON_HOST}`;
|
|
49234
49603
|
function remoteLink(config2, info, open6 = openGateway) {
|
|
49235
|
-
let
|
|
49604
|
+
let link2;
|
|
49236
49605
|
const current = () => {
|
|
49237
|
-
|
|
49606
|
+
link2 ??= open6(config2, info).then((opened) => {
|
|
49238
49607
|
opened.client.onClose(() => {
|
|
49239
|
-
|
|
49608
|
+
link2 = void 0;
|
|
49240
49609
|
});
|
|
49241
49610
|
return opened;
|
|
49242
49611
|
}, (error51) => {
|
|
49243
|
-
|
|
49612
|
+
link2 = void 0;
|
|
49244
49613
|
throw error51;
|
|
49245
49614
|
});
|
|
49246
|
-
return
|
|
49615
|
+
return link2;
|
|
49247
49616
|
};
|
|
49248
49617
|
return {
|
|
49249
49618
|
async request(method, params = {}) {
|
|
@@ -49254,54 +49623,67 @@ function remoteLink(config2, info, open6 = openGateway) {
|
|
|
49254
49623
|
return (await current()).principal;
|
|
49255
49624
|
},
|
|
49256
49625
|
close() {
|
|
49257
|
-
void
|
|
49626
|
+
void link2?.then((opened) => opened.client.close(), () => {
|
|
49258
49627
|
});
|
|
49259
|
-
|
|
49628
|
+
link2 = void 0;
|
|
49260
49629
|
}
|
|
49261
49630
|
};
|
|
49262
49631
|
}
|
|
49263
|
-
async function project(
|
|
49264
|
-
const principal = await
|
|
49632
|
+
async function project(link2, directory) {
|
|
49633
|
+
const principal = await link2.principal();
|
|
49265
49634
|
return workspaceFor(principal, directory)?.path;
|
|
49266
49635
|
}
|
|
49267
|
-
function registerRemoteTaskRpc(server,
|
|
49636
|
+
function registerRemoteTaskRpc(server, link2) {
|
|
49268
49637
|
server.handle(tasksList, async ({ directory }) => {
|
|
49269
|
-
const projectRoot = await project(
|
|
49638
|
+
const projectRoot = await project(link2, directory);
|
|
49270
49639
|
if (!projectRoot) return { projectRoot: null, tasks: [], unreadable: [] };
|
|
49271
|
-
const { tasks, unreadable } = await
|
|
49640
|
+
const { tasks, unreadable } = await link2.request("task.list", { projectRoot });
|
|
49272
49641
|
const known = new Set(tasks.map((task) => task.id));
|
|
49273
49642
|
const sessions = Object.fromEntries([...sessionTasks].map(([id2, worked]) => [id2, worked.filter((task) => known.has(task))]).filter(([, worked]) => worked.length));
|
|
49274
49643
|
return { projectRoot, tasks, unreadable, sessions };
|
|
49275
49644
|
});
|
|
49276
49645
|
server.handle(tasksAdd, async ({ directory, title, priority }) => {
|
|
49277
|
-
const projectRoot = await project(
|
|
49646
|
+
const projectRoot = await project(link2, directory);
|
|
49278
49647
|
if (!projectRoot) throw new Error(`${directory} is not in a workspace your ALP credential grants`);
|
|
49279
|
-
return
|
|
49648
|
+
return link2.request("task.create", { projectRoot, title, ...priority !== void 0 ? { priority } : {}, requestId: `paseo-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}` });
|
|
49280
49649
|
});
|
|
49281
49650
|
server.handle(tasksChange, async ({ directory, id: id2, action, gate, note }) => {
|
|
49282
|
-
const projectRoot = await project(
|
|
49651
|
+
const projectRoot = await project(link2, directory);
|
|
49283
49652
|
if (!projectRoot) throw new Error(`${directory} is not in a workspace your ALP credential grants`);
|
|
49284
49653
|
if (action === "approve") {
|
|
49285
|
-
const { id: done2, status: status2 } = await
|
|
49654
|
+
const { id: done2, status: status2 } = await link2.request("task.gate.resolve", { projectRoot, id: id2, gate: gate ?? "", ...note ? { note } : {} });
|
|
49286
49655
|
return { id: done2, status: status2 };
|
|
49287
49656
|
}
|
|
49288
|
-
const { id: done, status, landed } = await
|
|
49657
|
+
const { id: done, status, landed } = await link2.request("task.update", { projectRoot, id: id2, action, ...note ? { note } : {} });
|
|
49289
49658
|
return { id: done, status, ...landed ? { landed } : {} };
|
|
49290
49659
|
});
|
|
49291
49660
|
}
|
|
49292
|
-
function registerRemoteLibraryRpc(server,
|
|
49661
|
+
function registerRemoteLibraryRpc(server, link2) {
|
|
49293
49662
|
server.handle(libraryModels, async () => {
|
|
49294
|
-
const { models: models2 } = await
|
|
49663
|
+
const { models: models2 } = await link2.request("library.models");
|
|
49295
49664
|
return { models: models2 };
|
|
49296
49665
|
});
|
|
49297
49666
|
server.handle(libraryList, async ({ directory, kind }) => {
|
|
49298
|
-
const projectRoot = await project(
|
|
49667
|
+
const projectRoot = await project(link2, directory);
|
|
49299
49668
|
if (!projectRoot) return { projectRoot: null, library: "the ALP host", entries: [], readOnly: { reason: READ_ONLY, unlisted: "Open a workspace your ALP credential grants to list the host library here." } };
|
|
49300
|
-
const { entries: entries2 } = await
|
|
49669
|
+
const { entries: entries2 } = await link2.request("library.list", { kind, projectRoot });
|
|
49301
49670
|
return { projectRoot, library: "the ALP host", entries: entries2, readOnly: { reason: READ_ONLY } };
|
|
49302
49671
|
});
|
|
49303
|
-
server.handle(libraryGet, async () => {
|
|
49304
|
-
|
|
49672
|
+
server.handle(libraryGet, async ({ directory, kind, name: name2, scope }) => {
|
|
49673
|
+
const projectRoot = await project(link2, directory);
|
|
49674
|
+
if (!projectRoot) throw new Error(`${directory ?? "This screen"} is not in a workspace your ALP credential grants; open one to read the host library`);
|
|
49675
|
+
const entry = await link2.request("library.get", { kind, name: name2, projectRoot, ...scope ? { scope } : {} });
|
|
49676
|
+
return {
|
|
49677
|
+
kind: entry.kind,
|
|
49678
|
+
name: entry.name,
|
|
49679
|
+
source: entry.source,
|
|
49680
|
+
...entry.overrides ? { overrides: entry.overrides } : {},
|
|
49681
|
+
content: entry.content,
|
|
49682
|
+
revision: entry.revision ?? null,
|
|
49683
|
+
usedBy: entry.usedBy ?? [],
|
|
49684
|
+
...entry.librarySkills ? { librarySkills: entry.librarySkills } : {},
|
|
49685
|
+
...entry.secrets ? { secrets: entry.secrets } : {}
|
|
49686
|
+
};
|
|
49305
49687
|
});
|
|
49306
49688
|
for (const contract of [librarySave, libraryDelete, libraryDuplicate, libraryRename]) {
|
|
49307
49689
|
server.handle(contract, async () => {
|
|
@@ -49314,7 +49696,7 @@ function registerRemoteLibraryRpc(server, link) {
|
|
|
49314
49696
|
server.handle(libraryTest, async () => {
|
|
49315
49697
|
throw new RemoteUnavailableError("testing MCP servers, hooks and providers (they would run on the ALP host)", ON_HOST);
|
|
49316
49698
|
});
|
|
49317
|
-
server.handle(languageGet, async () => ({ ...await
|
|
49699
|
+
server.handle(languageGet, async () => ({ ...await link2.request("settings.language.get"), readOnly: `${UNAVAILABLE}: changing the language. ${ON_HOST}` }));
|
|
49318
49700
|
server.handle(languageSet, async () => {
|
|
49319
49701
|
throw new RemoteUnavailableError("changing the language", ON_HOST);
|
|
49320
49702
|
});
|
|
@@ -49329,11 +49711,11 @@ function registerRemoteUsageRpc(server) {
|
|
|
49329
49711
|
function contributeRemote(server, config2 = gatewayConfig(), version2 = "0") {
|
|
49330
49712
|
if (!config2) throw new Error("ALP remote mode needs ALP_GATEWAY_URL and ALP_GATEWAY_TOKEN");
|
|
49331
49713
|
server.registerProvider(createRemoteProvider(config2, { version: version2 }));
|
|
49332
|
-
const
|
|
49333
|
-
registerRemoteTaskRpc(server,
|
|
49334
|
-
registerRemoteLibraryRpc(server,
|
|
49714
|
+
const link2 = remoteLink(config2, { name: "alp-paseo-remote-panels", version: version2 });
|
|
49715
|
+
registerRemoteTaskRpc(server, link2);
|
|
49716
|
+
registerRemoteLibraryRpc(server, link2);
|
|
49335
49717
|
registerRemoteUsageRpc(server);
|
|
49336
|
-
return () =>
|
|
49718
|
+
return () => link2.close();
|
|
49337
49719
|
}
|
|
49338
49720
|
|
|
49339
49721
|
// integrations/paseo/server/paseo/index.ts
|
|
@@ -49341,7 +49723,7 @@ import { existsSync as existsSync5 } from "node:fs";
|
|
|
49341
49723
|
import path48 from "node:path";
|
|
49342
49724
|
|
|
49343
49725
|
// integrations/paseo/server/paseo/agents.ts
|
|
49344
|
-
import { randomUUID as
|
|
49726
|
+
import { randomUUID as randomUUID16 } from "node:crypto";
|
|
49345
49727
|
import path43 from "node:path";
|
|
49346
49728
|
|
|
49347
49729
|
// integrations/paseo/server/paseo/chat-search.ts
|
|
@@ -49404,7 +49786,7 @@ var TimelineDeltas = class {
|
|
|
49404
49786
|
};
|
|
49405
49787
|
|
|
49406
49788
|
// integrations/paseo/server/paseo/timeline-store.ts
|
|
49407
|
-
import { randomUUID as
|
|
49789
|
+
import { randomUUID as randomUUID15 } from "node:crypto";
|
|
49408
49790
|
|
|
49409
49791
|
// node_modules/@getpaseo/protocol/dist/timeline-identity.js
|
|
49410
49792
|
function timelineItemIdentity(item) {
|
|
@@ -49809,7 +50191,7 @@ var InMemoryAgentTimelineStore = class {
|
|
|
49809
50191
|
const projection = new TimelineProjection();
|
|
49810
50192
|
for (const row of rows) projection.append(row);
|
|
49811
50193
|
this.states.set(agentId, {
|
|
49812
|
-
epoch: options2?.epoch ??
|
|
50194
|
+
epoch: options2?.epoch ?? randomUUID15(),
|
|
49813
50195
|
projection,
|
|
49814
50196
|
minSeq: projection.getRows()[0]?.seqStart ?? 0,
|
|
49815
50197
|
nextSeq
|
|
@@ -50037,6 +50419,8 @@ function createAgents({ clientFactory, home, broadcast, directory, log: log3 = (
|
|
|
50037
50419
|
pendingPermissions: [...questions.values()].filter((question) => question.rootId === session.id).map(permissionOf),
|
|
50038
50420
|
persistence: session.persistent ? { provider: PROVIDER, sessionId: session.id } : null,
|
|
50039
50421
|
runtimeInfo: { provider: PROVIDER, sessionId: session.id, model: `${session.runtime}:${session.model}`, modeId: session.mode },
|
|
50422
|
+
// Paseo's context meter reads the agent's last usage.
|
|
50423
|
+
...session.usage ? { lastUsage: agentUsage(session.usage) } : {},
|
|
50040
50424
|
...session.lastError ? { lastError: session.lastError.message } : {},
|
|
50041
50425
|
title: session.title ?? null,
|
|
50042
50426
|
labels: {},
|
|
@@ -50099,8 +50483,7 @@ function createAgents({ clientFactory, home, broadcast, directory, log: log3 = (
|
|
|
50099
50483
|
});
|
|
50100
50484
|
}
|
|
50101
50485
|
for (const id2 of [...roots.keys()]) if (!seen.has(id2)) {
|
|
50102
|
-
|
|
50103
|
-
epochs.delete(id2);
|
|
50486
|
+
forget(id2);
|
|
50104
50487
|
broadcast({ type: "agent_update", payload: { kind: "remove", agentId: id2 } });
|
|
50105
50488
|
directory.changed();
|
|
50106
50489
|
}
|
|
@@ -50215,8 +50598,10 @@ function createAgents({ clientFactory, home, broadcast, directory, log: log3 = (
|
|
|
50215
50598
|
break;
|
|
50216
50599
|
case "turn.ended": {
|
|
50217
50600
|
turns.delete(root);
|
|
50218
|
-
if (event.state === "completed")
|
|
50219
|
-
|
|
50601
|
+
if (event.state === "completed") {
|
|
50602
|
+
const usage = roots.get(root)?.usage;
|
|
50603
|
+
stream(root, { type: "turn_completed", provider: PROVIDER, turnId: event.turnId, ...usage ? { usage: agentUsage(usage) } : {} }, envelope.ts);
|
|
50604
|
+
} else if (event.state === "canceled") stream(root, { type: "turn_canceled", provider: PROVIDER, turnId: event.turnId, reason: event.error?.message ?? "Stopped" }, envelope.ts);
|
|
50220
50605
|
else stream(root, { type: "turn_failed", provider: PROVIDER, turnId: event.turnId, error: event.error?.message ?? "The turn failed" }, envelope.ts);
|
|
50221
50606
|
if (!replaying.has(root) && event.state !== "canceled") {
|
|
50222
50607
|
const reason = event.state === "completed" ? "finished" : "error";
|
|
@@ -50225,6 +50610,13 @@ function createAgents({ clientFactory, home, broadcast, directory, log: log3 = (
|
|
|
50225
50610
|
}
|
|
50226
50611
|
break;
|
|
50227
50612
|
}
|
|
50613
|
+
case "usage": {
|
|
50614
|
+
if (replaying.has(root) || !session) return;
|
|
50615
|
+
const next = { ...session, usage: event.usage };
|
|
50616
|
+
roots.set(root, next);
|
|
50617
|
+
upsert(next);
|
|
50618
|
+
return;
|
|
50619
|
+
}
|
|
50228
50620
|
case "session.opened":
|
|
50229
50621
|
case "session.updated":
|
|
50230
50622
|
case "session.closed":
|
|
@@ -50240,19 +50632,24 @@ function createAgents({ clientFactory, home, broadcast, directory, log: log3 = (
|
|
|
50240
50632
|
if (timelines.has(root)) return Promise.resolve();
|
|
50241
50633
|
let pending = attaching.get(root);
|
|
50242
50634
|
if (!pending) {
|
|
50635
|
+
const connection = alp;
|
|
50636
|
+
if (!connection) return Promise.reject(new Error("ALP daemon is not connected"));
|
|
50243
50637
|
pending = (async () => {
|
|
50244
50638
|
timelines.initialize(root);
|
|
50245
50639
|
deltas.set(root, new TimelineDeltas());
|
|
50246
50640
|
epochs.delete(root);
|
|
50247
50641
|
replaying.add(root);
|
|
50642
|
+
const current = () => attaching.get(root) === pending;
|
|
50248
50643
|
try {
|
|
50249
|
-
await
|
|
50644
|
+
await connection.request("session.attach", { sessionId: root, replay: true });
|
|
50250
50645
|
} catch (error51) {
|
|
50251
|
-
timelines.delete(root);
|
|
50646
|
+
if (current()) timelines.delete(root);
|
|
50252
50647
|
throw error51;
|
|
50253
50648
|
} finally {
|
|
50254
|
-
|
|
50255
|
-
|
|
50649
|
+
if (current()) {
|
|
50650
|
+
replaying.delete(root);
|
|
50651
|
+
attaching.delete(root);
|
|
50652
|
+
}
|
|
50256
50653
|
}
|
|
50257
50654
|
})();
|
|
50258
50655
|
attaching.set(root, pending);
|
|
@@ -50273,6 +50670,22 @@ function createAgents({ clientFactory, home, broadcast, directory, log: log3 = (
|
|
|
50273
50670
|
}
|
|
50274
50671
|
void ensureTimeline(root).catch((error51) => log3(`agents reattach failed: ${error51?.message ?? error51}`));
|
|
50275
50672
|
}
|
|
50673
|
+
function forget(root) {
|
|
50674
|
+
roots.delete(root);
|
|
50675
|
+
timelines.delete(root);
|
|
50676
|
+
deltas.delete(root);
|
|
50677
|
+
attaching.delete(root);
|
|
50678
|
+
replaying.delete(root);
|
|
50679
|
+
epochs.delete(root);
|
|
50680
|
+
turns.delete(root);
|
|
50681
|
+
attention.delete(root);
|
|
50682
|
+
for (const child of [...children2.values()]) {
|
|
50683
|
+
if (child.root !== root) continue;
|
|
50684
|
+
children2.delete(child.id);
|
|
50685
|
+
childTimelines.delete(child.id);
|
|
50686
|
+
childDeltas.delete(child.id);
|
|
50687
|
+
}
|
|
50688
|
+
}
|
|
50276
50689
|
function known(agentId) {
|
|
50277
50690
|
const session = roots.get(agentId);
|
|
50278
50691
|
if (!session) throw Object.assign(new Error(`No agent ${agentId}`), { code: "agent_not_found" });
|
|
@@ -50290,14 +50703,14 @@ function createAgents({ clientFactory, home, broadcast, directory, log: log3 = (
|
|
|
50290
50703
|
async function create(input) {
|
|
50291
50704
|
const { config: config2 } = input;
|
|
50292
50705
|
if (config2.provider !== PROVIDER) throw new Error(`ALP runs its own teams; ${config2.provider} is not one of them`);
|
|
50293
|
-
const sessionId = `web-${
|
|
50706
|
+
const sessionId = `web-${randomUUID16()}`;
|
|
50294
50707
|
if (input.workspaceId) directory.assign(sessionId, input.workspaceId);
|
|
50295
50708
|
await alp.request("session.create", { sessionId, spec: { cwd: config2.cwd, persist: true, ...config2.model ? { workflow: config2.model } : {}, ...config2.modeId ? { mode: config2.modeId } : {} } });
|
|
50296
50709
|
if (config2.title) await alp.request("session.rename", { sessionId, title: config2.title });
|
|
50297
50710
|
await refresh();
|
|
50298
50711
|
await ensureTimeline(sessionId);
|
|
50299
50712
|
const prompt = input.initialPrompt?.trim();
|
|
50300
|
-
if (prompt) await alp.request("session.prompt", { sessionId, clientMessageId: input.clientMessageId ??
|
|
50713
|
+
if (prompt) await alp.request("session.prompt", { sessionId, clientMessageId: input.clientMessageId ?? randomUUID16(), content: [{ type: "text", text: prompt }] });
|
|
50301
50714
|
return agentOf(known(sessionId));
|
|
50302
50715
|
}
|
|
50303
50716
|
const view = {
|
|
@@ -50479,7 +50892,7 @@ function createAgents({ clientFactory, home, broadcast, directory, log: log3 = (
|
|
|
50479
50892
|
if (running2 && message.activeTurnBehavior === "interrupt") await alp.request("session.interrupt", { sessionId: session.id });
|
|
50480
50893
|
await alp.request("session.prompt", {
|
|
50481
50894
|
sessionId: session.id,
|
|
50482
|
-
clientMessageId: message.messageId ??
|
|
50895
|
+
clientMessageId: message.messageId ?? randomUUID16(),
|
|
50483
50896
|
delivery: running2 && message.activeTurnBehavior !== "interrupt" ? "steer" : "auto",
|
|
50484
50897
|
content: [{ type: "text", text: message.text }]
|
|
50485
50898
|
});
|
|
@@ -51060,14 +51473,14 @@ function createCheckouts({ broadcast, log: log3 = () => {
|
|
|
51060
51473
|
}
|
|
51061
51474
|
|
|
51062
51475
|
// integrations/paseo/server/paseo/files.ts
|
|
51063
|
-
import { readFile as readFile21, readdir as
|
|
51476
|
+
import { readFile as readFile21, readdir as readdir10, realpath as realpath6, stat as stat12 } from "node:fs/promises";
|
|
51064
51477
|
import os12 from "node:os";
|
|
51065
51478
|
import path45 from "node:path";
|
|
51066
51479
|
var SKIPPED = /* @__PURE__ */ new Set(["node_modules", "Library", ".git", "dist", "build", ".cache", "target", ".venv", "venv", "__pycache__"]);
|
|
51067
51480
|
var HOME_SCAN_LIMIT = 5e3;
|
|
51068
51481
|
var HOME_DEPTH = 4;
|
|
51069
51482
|
var WORKSPACE_SCAN_LIMIT = 2e4;
|
|
51070
|
-
var children = (directory) =>
|
|
51483
|
+
var children = (directory) => readdir10(directory, { withFileTypes: true }).catch(() => []);
|
|
51071
51484
|
var expand = (query) => query === "~" ? os12.homedir() : query.startsWith("~/") ? path45.join(os12.homedir(), query.slice(2)) : query;
|
|
51072
51485
|
function rank3(candidate, query) {
|
|
51073
51486
|
const name2 = candidate.toLowerCase();
|
|
@@ -51192,7 +51605,7 @@ async function fileExplorer(message) {
|
|
|
51192
51605
|
const relative = posixRelative(realRoot2, real);
|
|
51193
51606
|
if (message.mode === "list") {
|
|
51194
51607
|
const entries2 = [];
|
|
51195
|
-
for (const entry of await
|
|
51608
|
+
for (const entry of await readdir10(real, { withFileTypes: true })) {
|
|
51196
51609
|
const child = path45.join(real, entry.name);
|
|
51197
51610
|
const resolved = entry.isSymbolicLink() ? await inside(realRoot2, path45.relative(realRoot2, child)).then((found) => found.real, () => void 0) : child;
|
|
51198
51611
|
if (!resolved) continue;
|
|
@@ -51222,7 +51635,7 @@ async function fileExplorer(message) {
|
|
|
51222
51635
|
import { createHash as createHash13 } from "node:crypto";
|
|
51223
51636
|
|
|
51224
51637
|
// alp-plugin-client:plugin-client
|
|
51225
|
-
var plugin_client_default = { "id": "alp-provider", "requirements": { "paseo": ">=0.11.1 <0.12.0" }, "factory": '(function(require){const module={exports:{}};const exports=module.exports;var __defProp = Object.defineProperty;\nvar __getOwnPropDesc = Object.getOwnPropertyDescriptor;\nvar __getOwnPropNames = Object.getOwnPropertyNames;\nvar __hasOwnProp = Object.prototype.hasOwnProperty;\nvar __export = (target, all) => {\n for (var name in all)\n __defProp(target, name, { get: all[name], enumerable: true });\n};\nvar __copyProps = (to, from, except, desc) => {\n if (from && typeof from === "object" || typeof from === "function") {\n for (let key of __getOwnPropNames(from))\n if (!__hasOwnProp.call(to, key) && key !== except)\n __defProp(to, key, { value: from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });\n }\n return to;\n};\nvar __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);\nvar __async = (__this, __arguments, generator) => {\n return new Promise((resolve, reject) => {\n var fulfilled = (value) => {\n try {\n step(generator.next(value));\n } catch (e) {\n reject(e);\n }\n };\n var rejected = (value) => {\n try {\n step(generator.throw(value));\n } catch (e) {\n reject(e);\n }\n };\n var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);\n step((generator = generator.apply(__this, __arguments)).next());\n });\n};\n\n// integrations/paseo/index.client.tsx\nvar index_client_exports = {};\n__export(index_client_exports, {\n default: () => contribute\n});\nmodule.exports = __toCommonJS(index_client_exports);\n\n// integrations/paseo/client/tasks-panel.tsx\nvar import_client = require("@getpaseo/plugin/client");\nvar import_react_native = require("@getpaseo/plugin/client/react-native");\nvar import_react = require("react");\nvar import_react_native2 = require("react-native");\n\n// integrations/paseo/shared/tasks.ts\nvar import_plugin = require("@getpaseo/plugin");\nvar import_zod = require("zod");\nvar TaskRowSchema = import_zod.z.object({\n id: import_zod.z.string(),\n title: import_zod.z.string(),\n type: import_zod.z.string(),\n priority: import_zod.z.number(),\n status: import_zod.z.enum(["open", "in_progress", "review", "closed"]),\n parent: import_zod.z.string().optional(),\n assignee: import_zod.z.string().optional(),\n ready: import_zod.z.boolean(),\n /** Open tasks that must close first, including those of ancestors. */\n blockedBy: import_zod.z.array(import_zod.z.string()).optional(),\n /** Open gates, as labels. */\n waits: import_zod.z.array(import_zod.z.string()).optional(),\n /** Open human gates of this task: the user approves them here. */\n approvals: import_zod.z.array(import_zod.z.object({ gate: import_zod.z.string(), note: import_zod.z.string() })).optional(),\n handoff: import_zod.z.object({ outcome: import_zod.z.string(), summary: import_zod.z.string(), agent: import_zod.z.string().optional() }).optional(),\n closed: import_zod.z.object({ reason: import_zod.z.string(), summary: import_zod.z.string().optional(), at: import_zod.z.string() }).optional(),\n /** What the task is about, for its detail view; at most 4000 characters. */\n description: import_zod.z.string().optional(),\n labels: import_zod.z.array(import_zod.z.string()).optional(),\n paths: import_zod.z.array(import_zod.z.string()).optional(),\n /** An epic or parent task: how many of its children are closed. */\n progress: import_zod.z.object({ done: import_zod.z.number(), total: import_zod.z.number() }).optional(),\n createdAt: import_zod.z.string().optional(),\n updatedAt: import_zod.z.string()\n});\nvar Directory = import_zod.z.string().min(1);\nvar tasksList = (0, import_plugin.defineRpc)({\n name: "alp.tasks.list",\n input: import_zod.z.object({ directory: Directory }),\n output: import_zod.z.object({\n /** The ALP project containing the directory, or null when there is none. */\n projectRoot: import_zod.z.string().nullable(),\n tasks: import_zod.z.array(TaskRowSchema),\n unreadable: import_zod.z.array(import_zod.z.object({ file: import_zod.z.string(), error: import_zod.z.string() })),\n /** By provider session id: the tasks that session\'s tree worked on (ALPD \xA755). */\n sessions: import_zod.z.record(import_zod.z.string(), import_zod.z.array(import_zod.z.string())).optional()\n })\n});\nvar tasksAdd = (0, import_plugin.defineRpc)({\n name: "alp.tasks.add",\n input: import_zod.z.object({ directory: Directory, title: import_zod.z.string().trim().min(1).max(200), priority: import_zod.z.number().int().min(0).max(4).optional() }),\n output: import_zod.z.object({ id: import_zod.z.string() })\n});\nvar tasksChange = (0, import_plugin.defineRpc)({\n name: "alp.tasks.change",\n input: import_zod.z.object({\n directory: Directory,\n id: import_zod.z.string().min(1),\n action: import_zod.z.enum(["close", "reopen", "approve"]),\n /** For approve: the human gate. */\n gate: import_zod.z.string().optional(),\n note: import_zod.z.string().max(2e3).optional()\n }),\n /** landed: the first line of the report when the close landed an epic. */\n output: import_zod.z.object({ id: import_zod.z.string(), status: import_zod.z.string(), landed: import_zod.z.string().optional() })\n});\nvar rank = (a, b) => a.priority - b.priority || a.id.localeCompare(b.id);\nfunction boardSections(tasks, closedLimit = 20) {\n const open = tasks.filter((task) => task.status !== "closed");\n const sections = [\n { key: "approve", title: "Waiting for your approval", tasks: open.filter((task) => task.approvals?.length).sort(rank) },\n { key: "review", title: "In review", tasks: open.filter((task) => task.status === "review").sort(rank) },\n { key: "progress", title: "In progress", tasks: open.filter((task) => task.status === "in_progress").sort(rank) },\n { key: "ready", title: "Ready", tasks: open.filter((task) => task.ready).sort(rank) },\n { key: "waiting", title: "Blocked or waiting", tasks: open.filter((task) => task.status === "open" && !task.ready && !task.approvals?.length && task.type !== "epic").sort(rank) },\n { key: "epics", title: "Epics", tasks: open.filter((task) => task.type === "epic" && !task.approvals?.length).sort(rank) },\n { key: "closed", title: "Closed", tasks: tasks.filter((task) => task.status === "closed").sort((a, b) => (b.closed?.at ?? b.updatedAt).localeCompare(a.closed?.at ?? a.updatedAt)).slice(0, closedLimit) }\n ];\n return sections.filter((section) => section.tasks.length);\n}\n\n// integrations/paseo/client/tasks-panel.tsx\nvar import_jsx_runtime = require("react/jsx-runtime");\nvar POLL_MS = 5e3;\nvar SPLIT_FROM = 820;\nfunction TasksPanel({ theme, layout, workspaceId }) {\n const directory = (0, import_client.useWorkspace)(workspaceId, (workspace) => workspace.directory || workspace.projectRootPath);\n return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TaskBoard, { theme, compact: layout.compact, directory, ...useTasks(directory) });\n}\nfunction TasksScreen({ theme, layout, params }) {\n const directory = params.directory || null;\n const tasks = useTasks(directory);\n return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(\n TaskBoard,\n {\n theme,\n compact: layout.compact,\n directory,\n ...tasks,\n initial: params.taskId ? { selected: params.taskId } : void 0\n },\n params.taskId ?? ""\n );\n}\nfunction useTasks(directory) {\n const list = (0, import_client.useRpc)(tasksList);\n const add = (0, import_client.useRpc)(tasksAdd);\n const change = (0, import_client.useRpc)(tasksChange);\n const toast = (0, import_react_native.useToast)();\n const [data, setData] = (0, import_react.useState)(null);\n const [error, setError] = (0, import_react.useState)(null);\n const [tick, setTick] = (0, import_react.useState)(0);\n const refresh = (0, import_react.useCallback)(() => setTick((value) => value + 1), []);\n (0, import_react.useEffect)(() => {\n if (!directory) return;\n let live = true;\n const load = () => list({ directory }).then((result) => {\n if (live) {\n setData(result);\n setError(null);\n }\n }).catch((cause) => {\n if (live) setError(cause instanceof Error ? cause.message : String(cause));\n });\n void load();\n const timer = setInterval(load, POLL_MS);\n return () => {\n live = false;\n clearInterval(timer);\n };\n }, [directory, list, tick]);\n const onAdd = (0, import_react.useCallback)((title, priority) => __async(null, null, function* () {\n if (!directory) return false;\n try {\n const { id } = yield add({ directory, title, priority });\n toast.show(`Added ${id}`, { variant: "success" });\n refresh();\n return true;\n } catch (cause) {\n toast.error(cause instanceof Error ? cause.message : String(cause));\n return false;\n }\n }), [add, directory, refresh, toast]);\n const onAction = (0, import_react.useCallback)((_0) => __async(null, [_0], function* ({ id, action, gate }) {\n if (!directory) return;\n try {\n const { landed } = yield change({ directory, id, action, ...gate ? { gate } : {} });\n toast.show(landed ?? (action === "approve" ? `Approved ${id}` : action === "close" ? `Closed ${id}` : `Reopened ${id}`), { variant: "success" });\n refresh();\n } catch (cause) {\n toast.error(cause instanceof Error ? cause.message : String(cause));\n }\n }), [change, directory, refresh, toast]);\n return { projectRoot: data?.projectRoot ?? null, tasks: data?.tasks ?? null, unreadable: data?.unreadable.length ?? 0, error, onAdd, onAction, onRefresh: refresh };\n}\nvar PRIORITIES = [0, 1, 2, 3, 4];\nvar TYPE_ICONS = { bug: "Bug", feature: "Sparkles", task: "SquareCheck", chore: "Wrench", epic: "Target" };\nvar hovered = (state) => !!state.hovered;\nfunction age(iso, now = Date.now()) {\n if (!iso) return "";\n const minutes = Math.max(0, Math.floor((now - Date.parse(iso)) / 6e4));\n if (minutes < 60) return `${minutes}m`;\n if (minutes < 60 * 24) return `${Math.floor(minutes / 60)}h`;\n if (minutes < 60 * 24 * 14) return `${Math.floor(minutes / 1440)}d`;\n return `${Math.floor(minutes / 10080)}w`;\n}\nfunction stateOf(task) {\n if (task.status === "closed") return "closed";\n if (task.approvals?.length) return "approve";\n if (task.status === "review") return "review";\n if (task.status === "in_progress") return "progress";\n if (task.type === "epic") return task.progress?.done ? "progress" : "ready";\n return task.ready ? "ready" : "blocked";\n}\nvar STATE_LABELS = { approve: "Needs approval", review: "In review", progress: "In progress", ready: "Ready", blocked: "Blocked", closed: "Closed" };\nfunction filterTasks(tasks, filter, query) {\n const words = query.trim().toLowerCase().split(/\\s+/).filter(Boolean);\n return tasks.filter((task) => {\n if (filter === "open" && task.status === "closed") return false;\n if (filter === "ready" && !(task.ready && task.status !== "closed")) return false;\n if (filter === "closed" && task.status !== "closed") return false;\n const text = [task.id, task.title, task.type, task.assignee ?? "", ...task.labels ?? []].join(" ").toLowerCase();\n return words.every((word) => text.includes(word));\n });\n}\nfunction TaskBoard({ theme, compact, directory, projectRoot, tasks, unreadable, error, onAdd, onAction, onRefresh, initial }) {\n const styles = (0, import_react.useMemo)(() => makeStyles(theme, compact), [theme, compact]);\n const [view, setView] = (0, import_react.useState)(initial?.view ?? "list");\n const [filter, setFilter] = (0, import_react.useState)(initial?.filter ?? "open");\n const [query, setQuery] = (0, import_react.useState)("");\n const [selected, setSelected] = (0, import_react.useState)(initial?.selected ?? null);\n const [composing, setComposing] = (0, import_react.useState)(false);\n const [width, setWidth] = (0, import_react.useState)(initial?.width ?? 0);\n const shown = (0, import_react.useMemo)(() => tasks ? filterTasks(tasks, filter, query) : [], [tasks, filter, query]);\n const task = selected ? tasks?.find((candidate) => candidate.id === selected) ?? null : null;\n const split = !!task && width >= SPLIT_FROM;\n const counts = (0, import_react.useMemo)(() => ({\n open: (tasks ?? []).filter((entry) => entry.status !== "closed").length,\n ready: (tasks ?? []).filter((entry) => entry.ready && entry.status !== "closed").length,\n closed: (tasks ?? []).filter((entry) => entry.status === "closed").length,\n all: (tasks ?? []).length\n }), [tasks]);\n if (!directory) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.View, { style: styles.screen, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: styles.muted, children: "This view needs a workspace." }) });\n const open = (id) => setSelected(id);\n const detail = task ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TaskDetail, { theme, styles, task, tasks: tasks ?? [], onBack: () => setSelected(null), onOpen: open, onAction }) : null;\n return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.View, { style: styles.screen, onLayout: (event) => setWidth(event.nativeEvent.layout.width), children: [\n /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.View, { style: styles.toolbar, children: [\n /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.View, { style: styles.toolbarRow, children: [\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: styles.title, children: "Tasks" }),\n tasks ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.Text, { style: styles.count, children: [\n counts.open,\n " open"\n ] }) : null,\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.View, { style: { flex: 1 } }),\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(\n Segmented,\n {\n theme,\n styles,\n value: view,\n onChange: (value) => {\n setView(value);\n setSelected(null);\n },\n options: [{ key: "list", label: "List", icon: "List" }, { key: "board", label: "Board", icon: "Columns3" }, { key: "epics", label: "Epics", icon: "Target" }]\n }\n ),\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(IconButton, { theme, icon: "RefreshCw", label: "Refresh", onPress: onRefresh }),\n projectRoot ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(IconButton, { theme, icon: "Plus", label: "New task", onPress: () => setComposing(!composing), primary: true }) : null\n ] }),\n projectRoot ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.View, { style: styles.toolbarRow, children: [\n ["open", "ready", "closed", "all"].map((key) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Pressable, { accessibilityRole: "button", accessibilityLabel: `Show ${key}`, accessibilityState: { selected: filter === key }, onPress: () => setFilter(key), style: [styles.filter, filter === key ? styles.filterOn : null], children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.Text, { style: filter === key ? styles.filterTextOn : styles.filterText, children: [\n key[0].toUpperCase() + key.slice(1),\n " ",\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: styles.filterCount, children: counts[key] })\n ] }) }, key)),\n /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.View, { style: styles.search, children: [\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native.Icon, { name: "Search", size: 14, color: theme.colors.foregroundMuted }),\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.TextInput, { style: styles.searchInput, value: query, onChangeText: setQuery, placeholder: "Filter by id, title, label, agent", placeholderTextColor: theme.colors.foregroundMuted, accessibilityLabel: "Filter tasks" })\n ] })\n ] }) : null,\n composing && projectRoot ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Composer, { theme, styles, onAdd: (title, priority) => __async(null, null, function* () {\n const added = yield onAdd(title, priority);\n if (added) setComposing(false);\n return added;\n }) }) : null\n ] }),\n error ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: [styles.danger, styles.pad], children: error }) : null,\n tasks === null && !error ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: [styles.muted, styles.pad], children: "Loading tasks\\u2026" }) : null,\n tasks !== null && projectRoot === null ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.Text, { style: [styles.muted, styles.pad], children: [\n directory,\n " is not an ALP project. Run alp init to start one."\n ] }) : null,\n projectRoot && tasks ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.View, { style: styles.body, children: [\n !task || split ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.View, { style: [styles.pane, split ? styles.paneList : null], children: [\n unreadable ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.Text, { style: [styles.warning, styles.pad], children: [\n unreadable,\n " unreadable task ",\n unreadable === 1 ? "file" : "files",\n " in ",\n projectRoot,\n "/.alp/tasks"\n ] }) : null,\n !tasks.length ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Empty, { styles, text: "No tasks yet. Add one here, with alp task add, or ask main to plan the work." }) : null,\n tasks.length && !shown.length ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Empty, { styles, text: "No tasks match." }) : null,\n shown.length && view === "list" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ListView, { theme, styles, tasks: shown, selected, onOpen: open, onAction }) : null,\n shown.length && view === "board" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(BoardView, { theme, styles, tasks: shown, onOpen: open }) : null,\n view === "epics" && tasks.length ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(EpicsView, { theme, styles, tasks, shown, onOpen: open }) : null\n ] }) : null,\n detail ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.View, { style: [styles.pane, split ? styles.paneDetail : null], children: detail }) : null\n ] }) : null\n ] });\n}\nfunction Segmented({ theme, styles, value, options, onChange }) {\n return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.View, { style: styles.segmented, children: options.map((option) => {\n const on = option.key === value;\n return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.Pressable, { accessibilityRole: "tab", accessibilityLabel: option.label, accessibilityState: { selected: on }, onPress: () => onChange(option.key), style: [styles.segment, on ? styles.segmentOn : null], children: [\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native.Icon, { name: option.icon, size: 13, color: on ? theme.colors.foreground : theme.colors.foregroundMuted }),\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: on ? styles.segmentTextOn : styles.segmentText, children: option.label })\n ] }, option.key);\n }) });\n}\nfunction IconButton({ theme, icon, label, onPress, primary }) {\n const { colors } = theme;\n return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(\n import_react_native2.Pressable,\n {\n accessibilityRole: "button",\n accessibilityLabel: label,\n onPress,\n style: (state) => ({ padding: 7, borderRadius: 8, backgroundColor: primary ? colors.accent : hovered(state) ? colors.surface2 : "transparent" }),\n children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native.Icon, { name: icon, size: 15, color: primary ? colors.accentForeground : colors.foregroundMuted })\n }\n );\n}\nfunction Composer({ theme, styles, onAdd }) {\n const [title, setTitle] = (0, import_react.useState)("");\n const [priority, setPriority] = (0, import_react.useState)(2);\n const submit = () => __async(null, null, function* () {\n const text = title.trim();\n if (text && (yield onAdd(text, priority))) setTitle("");\n });\n return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.View, { style: styles.composer, children: [\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.TextInput, { style: styles.input, value: title, onChangeText: setTitle, onSubmitEditing: submit, placeholder: "Add a task for main", placeholderTextColor: theme.colors.foregroundMuted, accessibilityLabel: "New task title", autoFocus: true }),\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.View, { style: styles.priorities, children: PRIORITIES.map((value) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Pressable, { accessibilityRole: "button", accessibilityLabel: `Priority ${value}`, onPress: () => setPriority(value), style: [styles.chip, value === priority ? styles.chipOn : null], children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.Text, { style: value === priority ? styles.chipTextOn : styles.chipText, children: [\n "P",\n value\n ] }) }, value)) }),\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Pressable, { accessibilityRole: "button", onPress: submit, style: styles.button, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: styles.buttonText, children: "Add" }) })\n ] });\n}\nfunction Empty({ styles, text }) {\n return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.View, { style: styles.empty, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: styles.muted, children: text }) });\n}\nfunction Priority({ theme, value }) {\n const { colors } = theme;\n const color = value === 0 ? colors.statusDanger : value === 1 ? colors.statusWarning : colors.foregroundMuted;\n return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.View, { style: { alignSelf: "flex-start", borderRadius: 4, borderWidth: 1, borderColor: value <= 1 ? color : colors.border, paddingHorizontal: 4 }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.Text, { style: { color, fontSize: 10.5, fontWeight: "600", fontVariant: ["tabular-nums"] }, children: [\n "P",\n value\n ] }) });\n}\nfunction StateDot({ theme, task }) {\n const { colors } = theme;\n const state = stateOf(task);\n const color = state === "approve" ? colors.statusWarning : state === "review" ? colors.accent : state === "progress" ? colors.statusWarning : state === "ready" ? colors.statusSuccess : state === "blocked" ? colors.statusDanger : colors.border;\n const ring = state === "progress" || state === "closed";\n return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.View, { accessibilityLabel: STATE_LABELS[state], style: { width: 9, height: 9, borderRadius: 5, borderWidth: ring ? 2 : 0, borderColor: color, backgroundColor: ring ? "transparent" : color } });\n}\nfunction TaskLine({ theme, styles, task, selected, onOpen }) {\n const meta = [\n task.blockedBy?.length ? `after ${task.blockedBy.join(", ")}` : "",\n // Gates waiting for the user show with their Approve instead.\n task.waits?.length && !task.approvals?.length ? `waits on ${task.waits.join("; ")}` : "",\n task.parent ? `in ${task.parent}` : ""\n ].filter(Boolean).join(" \\xB7 ");\n return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.Pressable, { accessibilityRole: "button", accessibilityLabel: `Open ${task.id}`, onPress: () => onOpen(task.id), style: (state) => [styles.line, selected ? styles.lineOn : hovered(state) ? styles.lineHover : null], children: [\n /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.View, { style: styles.lineTop, children: [\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(StateDot, { theme, task }),\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native.Icon, { name: TYPE_ICONS[task.type] ?? "SquareCheck", size: 13, color: theme.colors.foregroundMuted }),\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Priority, { theme, value: task.priority }),\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: styles.id, children: task.id }),\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: styles.lineTitle, numberOfLines: 1, children: task.title }),\n task.assignee ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.Text, { style: styles.assignee, numberOfLines: 1, children: [\n "@",\n task.assignee\n ] }) : null,\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: styles.age, children: age(task.status === "closed" ? task.closed?.at : task.updatedAt) })\n ] }),\n meta || task.labels?.length ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.View, { style: styles.lineMeta, children: [\n meta ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: styles.small, numberOfLines: 1, children: meta }) : null,\n (task.labels ?? []).map((label) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.Text, { style: styles.label, children: [\n "#",\n label\n ] }, label))\n ] }) : null\n ] });\n}\nvar SECTION_ICONS = { approve: "Hand", review: "Eye", progress: "LoaderCircle", ready: "CircleCheck", waiting: "CircleSlash", epics: "Target", closed: "CircleDashed" };\nfunction ListView({ theme, styles, tasks, selected, onOpen, onAction }) {\n const sections = (0, import_react.useMemo)(() => boardSections(tasks), [tasks]);\n const [hidden, setHidden] = (0, import_react.useState)({});\n return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native.ScrollView, { contentContainerStyle: styles.listContent, children: sections.map((section) => {\n const collapsed = hidden[section.key] ?? false;\n return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.View, { style: styles.group, children: [\n /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.Pressable, { accessibilityRole: "button", accessibilityLabel: `${collapsed ? "Show" : "Hide"} ${section.title}`, onPress: () => setHidden((current) => ({ ...current, [section.key]: !collapsed })), style: styles.groupHeader, children: [\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native.Icon, { name: collapsed ? "ChevronRight" : "ChevronDown", size: 13, color: theme.colors.foregroundMuted }),\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native.Icon, { name: SECTION_ICONS[section.key] ?? "Circle", size: 13, color: theme.colors.foregroundMuted }),\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: styles.groupTitle, children: section.title }),\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: styles.groupCount, children: section.tasks.length })\n ] }),\n !collapsed ? section.tasks.map((task) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.View, { children: [\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TaskLine, { theme, styles, task, selected: task.id === selected, onOpen }),\n section.key === "approve" ? task.approvals.map((approval) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.View, { style: styles.inlineAction, children: [\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: styles.small, numberOfLines: 2, children: approval.note || "Waiting for your approval" }),\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SmallButton, { styles, label: "Approve", primary: true, onPress: () => onAction({ id: task.id, action: "approve", gate: approval.gate }) })\n ] }, approval.gate)) : null\n ] }, `${section.key}-${task.id}`)) : null\n ] }, section.key);\n }) });\n}\nvar COLUMNS = [\n { key: "approve", title: "Needs approval" },\n { key: "blocked", title: "Blocked" },\n { key: "ready", title: "Ready" },\n { key: "progress", title: "In progress" },\n { key: "review", title: "In review" },\n { key: "closed", title: "Closed" }\n];\nfunction BoardView({ theme, styles, tasks, onOpen }) {\n const columns = COLUMNS.map((column) => ({ ...column, tasks: tasks.filter((task) => task.type !== "epic" && stateOf(task) === column.key) })).filter((column) => column.tasks.length || ["blocked", "ready", "progress"].includes(column.key));\n return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native.ScrollView, { horizontal: true, contentContainerStyle: styles.board, children: columns.map((column) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.View, { style: styles.column, children: [\n /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.View, { style: styles.columnHeader, children: [\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(StateDot, { theme, task: { status: column.key === "closed" ? "closed" : column.key === "review" ? "review" : column.key === "progress" ? "in_progress" : "open", ready: column.key === "ready", approvals: column.key === "approve" ? [{ gate: "", note: "" }] : void 0 } }),\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: styles.columnTitle, children: column.title }),\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: styles.groupCount, children: column.tasks.length })\n ] }),\n /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native.ScrollView, { contentContainerStyle: styles.columnBody, children: [\n column.tasks.map((task) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.Pressable, { accessibilityRole: "button", accessibilityLabel: `Open ${task.id}`, onPress: () => onOpen(task.id), style: (state) => [styles.card, hovered(state) ? styles.cardHover : null, column.key === "blocked" ? styles.cardBlocked : column.key === "ready" ? styles.cardReady : null], children: [\n /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.View, { style: styles.lineTop, children: [\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native.Icon, { name: TYPE_ICONS[task.type] ?? "SquareCheck", size: 12, color: theme.colors.foregroundMuted }),\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Priority, { theme, value: task.priority }),\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: styles.id, children: task.id }),\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.View, { style: { flex: 1 } }),\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: styles.age, children: age(task.updatedAt) })\n ] }),\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: styles.cardTitle, numberOfLines: 3, children: task.title }),\n task.assignee ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.Text, { style: styles.assignee, numberOfLines: 1, children: [\n "@",\n task.assignee\n ] }) : null,\n task.blockedBy?.length ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.Text, { style: styles.blocked, numberOfLines: 1, children: [\n "after ",\n task.blockedBy.join(", ")\n ] }) : null,\n task.labels?.length ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.View, { style: styles.cardLabels, children: task.labels.map((label) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.Text, { style: styles.label, children: [\n "#",\n label\n ] }, label)) }) : null\n ] }, task.id)),\n !column.tasks.length ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: [styles.small, styles.pad], children: "Nothing here" }) : null\n ] })\n ] }, column.key)) });\n}\nfunction EpicsView({ theme, styles, tasks, shown, onOpen }) {\n const epics = shown.filter((task) => task.type === "epic" || task.progress);\n const [opened, setOpened] = (0, import_react.useState)({});\n if (!epics.length) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Empty, { styles, text: "No epics here. An epic is a task other tasks name as their parent." });\n return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native.ScrollView, { contentContainerStyle: styles.listContent, children: epics.map((epic) => {\n const children = tasks.filter((task) => task.parent === epic.id);\n const done = epic.progress?.done ?? 0;\n const total = epic.progress?.total ?? 0;\n const expanded = opened[epic.id] ?? epic.status !== "closed";\n return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.View, { style: styles.epic, children: [\n /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.Pressable, { accessibilityRole: "button", accessibilityLabel: `Open ${epic.id}`, onPress: () => onOpen(epic.id), style: styles.lineTop, children: [\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(StateDot, { theme, task: epic }),\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native.Icon, { name: "Target", size: 13, color: theme.colors.foregroundMuted }),\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Priority, { theme, value: epic.priority }),\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: styles.id, children: epic.id }),\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: styles.lineTitle, numberOfLines: 1, children: epic.title }),\n /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.Text, { style: styles.progressText, children: [\n done,\n "/",\n total\n ] })\n ] }),\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.View, { style: styles.progressTrack, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.View, { style: [styles.progressFill, { width: `${total ? Math.round(done / total * 100) : 0}%` }] }) }),\n children.length ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.Pressable, { accessibilityRole: "button", accessibilityLabel: `${expanded ? "Hide" : "Show"} the tasks of ${epic.id}`, onPress: () => setOpened((current) => ({ ...current, [epic.id]: !expanded })), style: styles.treeToggle, children: [\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native.Icon, { name: expanded ? "ChevronDown" : "ChevronRight", size: 12, color: theme.colors.foregroundMuted }),\n /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.Text, { style: styles.small, children: [\n children.length,\n " ",\n children.length === 1 ? "task" : "tasks"\n ] })\n ] }) : null,\n expanded ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.View, { style: styles.tree, children: children.map((child) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TaskLine, { theme, styles, task: child, selected: false, onOpen }, child.id)) }) : null\n ] }, epic.id);\n }) });\n}\nfunction SmallButton({ styles, label, onPress, primary, danger }) {\n return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Pressable, { accessibilityRole: "button", onPress, style: [styles.smallButton, primary ? styles.smallButtonPrimary : null, danger ? styles.smallButtonDanger : null], children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: primary ? styles.smallButtonTextPrimary : danger ? styles.smallButtonTextDanger : styles.smallButtonText, children: label }) });\n}\nfunction TaskDetail({ theme, styles, task, tasks, onBack, onOpen, onAction }) {\n const state = stateOf(task);\n const children = tasks.filter((entry) => entry.parent === task.id);\n const blocks = tasks.filter((entry) => entry.blockedBy?.includes(task.id) && entry.status !== "closed");\n const field = (label, value) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.View, { style: styles.field, children: [\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: styles.fieldLabel, children: label }),\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.View, { style: styles.fieldValue, children: typeof value === "string" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: styles.text, children: value }) : value })\n ] });\n const link = (id) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Pressable, { accessibilityRole: "link", accessibilityLabel: `Open ${id}`, onPress: () => onOpen(id), children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: styles.link, children: id }) }, id);\n return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native.ScrollView, { contentContainerStyle: styles.detail, children: [\n /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.View, { style: styles.detailHeader, children: [\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(IconButton, { theme, icon: "ArrowLeft", label: "Back to the list", onPress: onBack }),\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: styles.id, children: task.id }),\n /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.View, { style: styles.statePill, children: [\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(StateDot, { theme, task }),\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: styles.small, children: STATE_LABELS[state] })\n ] })\n ] }),\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: styles.detailTitle, children: task.title }),\n /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.View, { style: styles.fields, children: [\n field("Type", /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.View, { style: styles.inline, children: [\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native.Icon, { name: TYPE_ICONS[task.type] ?? "SquareCheck", size: 13, color: theme.colors.foregroundMuted }),\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: styles.text, children: task.type })\n ] })),\n field("Priority", /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Priority, { theme, value: task.priority })),\n task.assignee ? field("Assignee", `@${task.assignee}`) : null,\n task.parent ? field("Parent", link(task.parent)) : null,\n task.blockedBy?.length ? field("Blocked by", /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.View, { style: styles.inline, children: task.blockedBy.map(link) })) : null,\n blocks.length ? field("Blocks", /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.View, { style: styles.inline, children: blocks.map((entry) => link(entry.id)) })) : null,\n task.waits?.length ? field("Waits on", task.waits.join("; ")) : null,\n task.labels?.length ? field("Labels", /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.View, { style: styles.inline, children: task.labels.map((label) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.Text, { style: styles.label, children: [\n "#",\n label\n ] }, label)) })) : null,\n task.paths?.length ? field("Paths", task.paths.join(", ")) : null,\n task.progress ? field("Progress", `${task.progress.done} of ${task.progress.total} closed`) : null,\n task.createdAt ? field("Created", `${age(task.createdAt)} ago`) : null,\n field("Updated", `${age(task.updatedAt)} ago`)\n ] }),\n task.description ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.View, { style: styles.box, children: [\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: styles.boxTitle, children: "Description" }),\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: styles.text, children: task.description })\n ] }) : null,\n task.handoff ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.View, { style: styles.box, children: [\n /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.Text, { style: styles.boxTitle, children: [\n "Handoff \\xB7 ",\n task.handoff.outcome,\n task.handoff.agent ? ` from ${task.handoff.agent}` : ""\n ] }),\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: styles.text, children: task.handoff.summary })\n ] }) : null,\n task.closed ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.View, { style: styles.box, children: [\n /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.Text, { style: styles.boxTitle, children: [\n "Closed \\xB7 ",\n task.closed.reason\n ] }),\n task.closed.summary ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: styles.text, children: task.closed.summary }) : null\n ] }) : null,\n children.length ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.View, { style: styles.box, children: [\n /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.Text, { style: styles.boxTitle, children: [\n "Tasks \\xB7 ",\n children.filter((child) => child.status === "closed").length,\n "/",\n children.length,\n " closed"\n ] }),\n children.map((child) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TaskLine, { theme, styles, task: child, selected: false, onOpen }, child.id))\n ] }) : null,\n /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.View, { style: styles.detailActions, children: [\n (task.approvals ?? []).map((approval) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SmallButton, { styles, primary: true, label: `Approve${approval.note ? `: ${approval.note.slice(0, 40)}` : ""}`, onPress: () => onAction({ id: task.id, action: "approve", gate: approval.gate }) }, approval.gate)),\n state === "review" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SmallButton, { styles, primary: true, label: "Accept and close", onPress: () => onAction({ id: task.id, action: "close" }) }) : null,\n task.status !== "closed" && state !== "review" && task.type !== "epic" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SmallButton, { styles, label: "Close", onPress: () => onAction({ id: task.id, action: "close" }) }) : null,\n task.status === "closed" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SmallButton, { styles, label: "Reopen", onPress: () => onAction({ id: task.id, action: "reopen" }) }) : null\n ] })\n ] });\n}\nfunction makeStyles(theme, compact) {\n const { colors } = theme;\n const mono = { fontFamily: "monospace", fontVariant: ["tabular-nums"] };\n return {\n screen: { flex: 1, backgroundColor: colors.surface0 },\n pad: { paddingHorizontal: compact ? 12 : 16, paddingVertical: 8 },\n toolbar: { paddingHorizontal: compact ? 12 : 16, paddingTop: 12, paddingBottom: 10, gap: 10, borderBottomWidth: 1, borderBottomColor: colors.border },\n toolbarRow: { flexDirection: "row", alignItems: "center", gap: 6, flexWrap: "wrap" },\n title: { color: colors.foreground, fontSize: 15, fontWeight: "600" },\n count: { color: colors.foregroundMuted, fontSize: 12, marginLeft: 4 },\n segmented: { flexDirection: "row", backgroundColor: colors.surface1, borderRadius: 8, borderWidth: 1, borderColor: colors.border, padding: 2 },\n segment: { flexDirection: "row", alignItems: "center", gap: 5, paddingHorizontal: 8, paddingVertical: 4, borderRadius: 6 },\n segmentOn: { backgroundColor: colors.surface0, shadowColor: "#000", shadowOpacity: 0.08, shadowRadius: 2 },\n segmentText: { color: colors.foregroundMuted, fontSize: 12 },\n segmentTextOn: { color: colors.foreground, fontSize: 12, fontWeight: "600" },\n filter: { paddingHorizontal: 9, paddingVertical: 4, borderRadius: 999, borderWidth: 1, borderColor: colors.border },\n filterOn: { backgroundColor: colors.foreground, borderColor: colors.foreground },\n filterText: { color: colors.foreground, fontSize: 12 },\n filterTextOn: { color: colors.surface0, fontSize: 12, fontWeight: "600" },\n filterCount: { opacity: 0.6, fontSize: 11 },\n search: { flex: 1, minWidth: 160, flexDirection: "row", alignItems: "center", gap: 6, borderWidth: 1, borderColor: colors.border, borderRadius: 8, paddingHorizontal: 8, backgroundColor: colors.surface1 },\n searchInput: { flex: 1, minWidth: 0, color: colors.foreground, fontSize: 12.5, paddingVertical: 6 },\n composer: { flexDirection: compact ? "column" : "row", gap: 8, alignItems: compact ? "stretch" : "center" },\n input: { flex: compact ? void 0 : 1, minWidth: 0, color: colors.foreground, borderWidth: 1, borderColor: colors.border, borderRadius: 8, paddingHorizontal: 10, paddingVertical: 7, backgroundColor: colors.surface1 },\n priorities: { flexDirection: "row", gap: 4 },\n chip: { paddingHorizontal: 7, paddingVertical: 5, borderRadius: 6, borderWidth: 1, borderColor: colors.border },\n chipOn: { backgroundColor: colors.accent, borderColor: colors.accent },\n chipText: { color: colors.foregroundMuted, fontSize: 12 },\n chipTextOn: { color: colors.accentForeground, fontSize: 12 },\n button: { paddingHorizontal: 12, paddingVertical: 7, borderRadius: 8, backgroundColor: colors.accent },\n buttonText: { color: colors.accentForeground, fontWeight: "600" },\n body: { flex: 1, flexDirection: "row" },\n pane: { flex: 1, minWidth: 0 },\n paneList: { flex: 2, borderRightWidth: 1, borderRightColor: colors.border },\n paneDetail: { flex: 3 },\n empty: { margin: 16, borderWidth: 1, borderStyle: "dashed", borderColor: colors.border, borderRadius: 10, padding: 24, alignItems: "center" },\n listContent: { paddingVertical: 6 },\n group: { marginBottom: 4 },\n groupHeader: { flexDirection: "row", alignItems: "center", gap: 6, paddingHorizontal: compact ? 10 : 14, paddingVertical: 7 },\n groupTitle: { color: colors.foregroundMuted, fontSize: 11.5, fontWeight: "600", textTransform: "uppercase", letterSpacing: 0.4 },\n groupCount: { color: colors.foregroundMuted, fontSize: 11, opacity: 0.8 },\n line: { paddingHorizontal: compact ? 10 : 14, paddingVertical: 7, gap: 3, borderLeftWidth: 2, borderLeftColor: "transparent" },\n lineOn: { backgroundColor: colors.surface2, borderLeftColor: colors.accent },\n lineHover: { backgroundColor: colors.surface1 },\n lineTop: { flexDirection: "row", alignItems: "center", gap: 7 },\n lineTitle: { flex: 1, minWidth: 0, color: colors.foreground, fontSize: 13 },\n lineMeta: { flexDirection: "row", flexWrap: "wrap", gap: 6, paddingLeft: 16 },\n id: { color: colors.foregroundMuted, fontSize: 11.5, ...mono },\n age: { color: colors.foregroundMuted, fontSize: 11, ...mono },\n assignee: { color: colors.accent, fontSize: 11.5, maxWidth: 110 },\n label: { color: colors.foregroundMuted, fontSize: 11, backgroundColor: colors.surface2, borderRadius: 4, paddingHorizontal: 5, paddingVertical: 1 },\n inlineAction: { flexDirection: "row", alignItems: "center", gap: 10, paddingLeft: compact ? 26 : 30, paddingRight: 14, paddingBottom: 8 },\n board: { padding: 12, gap: 10, alignItems: "flex-start" },\n column: { width: 248, backgroundColor: colors.surface1, borderRadius: 10, borderWidth: 1, borderColor: colors.border, maxHeight: 640 },\n columnHeader: { flexDirection: "row", alignItems: "center", gap: 7, paddingHorizontal: 12, paddingVertical: 10, borderBottomWidth: 1, borderBottomColor: colors.border },\n columnTitle: { flex: 1, color: colors.foreground, fontSize: 12.5, fontWeight: "600" },\n columnBody: { padding: 8, gap: 8 },\n card: { backgroundColor: colors.surface0, borderRadius: 8, borderWidth: 1, borderColor: colors.border, borderLeftWidth: 3, padding: 10, gap: 5 },\n cardHover: { borderColor: colors.foregroundMuted },\n cardBlocked: { borderLeftColor: colors.statusDanger },\n cardReady: { borderLeftColor: colors.statusSuccess },\n cardLabels: { flexDirection: "row", flexWrap: "wrap", gap: 6 },\n blocked: { color: colors.statusDanger, fontSize: 11.5 },\n cardTitle: { color: colors.foreground, fontSize: 13, lineHeight: 18 },\n epic: { marginHorizontal: compact ? 10 : 14, marginVertical: 6, padding: 12, borderRadius: 10, borderWidth: 1, borderColor: colors.border, backgroundColor: colors.surface1, gap: 8 },\n progressTrack: { height: 6, borderRadius: 3, backgroundColor: colors.surface2, overflow: "hidden" },\n progressFill: { height: 6, borderRadius: 3, backgroundColor: colors.statusSuccess },\n progressText: { color: colors.foregroundMuted, fontSize: 11.5, ...mono },\n treeToggle: { flexDirection: "row", alignItems: "center", gap: 4 },\n tree: { marginLeft: 6, borderLeftWidth: 1, borderLeftColor: colors.border, backgroundColor: colors.surface0, borderRadius: 6 },\n detail: { padding: compact ? 12 : 18, gap: 14 },\n detailHeader: { flexDirection: "row", alignItems: "center", gap: 8 },\n statePill: { flexDirection: "row", alignItems: "center", gap: 6, borderWidth: 1, borderColor: colors.border, borderRadius: 999, paddingHorizontal: 8, paddingVertical: 2 },\n detailTitle: { color: colors.foreground, fontSize: 17, fontWeight: "600", lineHeight: 23 },\n fields: { borderWidth: 1, borderColor: colors.border, borderRadius: 10, overflow: "hidden" },\n field: { flexDirection: "row", alignItems: "center", gap: 12, paddingHorizontal: 12, paddingVertical: 8, borderBottomWidth: 1, borderBottomColor: colors.border },\n fieldLabel: { width: 84, color: colors.foregroundMuted, fontSize: 12 },\n fieldValue: { flex: 1, minWidth: 0 },\n inline: { flexDirection: "row", alignItems: "center", gap: 6, flexWrap: "wrap" },\n box: { borderRadius: 10, backgroundColor: colors.surface1, borderWidth: 1, borderColor: colors.border, padding: 12, gap: 6 },\n boxTitle: { color: colors.foregroundMuted, fontSize: 11.5, fontWeight: "600", textTransform: "uppercase", letterSpacing: 0.4 },\n detailActions: { flexDirection: "row", gap: 8, flexWrap: "wrap" },\n smallButton: { paddingHorizontal: 10, paddingVertical: 6, borderRadius: 7, borderWidth: 1, borderColor: colors.border, backgroundColor: colors.surface1 },\n smallButtonPrimary: { backgroundColor: colors.accent, borderColor: colors.accent },\n smallButtonDanger: { borderColor: colors.statusDanger },\n smallButtonText: { color: colors.foreground, fontSize: 12.5, fontWeight: "500" },\n smallButtonTextPrimary: { color: colors.accentForeground, fontSize: 12.5, fontWeight: "600" },\n smallButtonTextDanger: { color: colors.statusDanger, fontSize: 12.5 },\n text: { color: colors.foreground, fontSize: 13, lineHeight: 19 },\n small: { color: colors.foregroundMuted, fontSize: 12 },\n muted: { color: colors.foregroundMuted, fontSize: 13 },\n danger: { color: colors.statusDanger, fontSize: 13 },\n warning: { color: colors.statusWarning, fontSize: 12 },\n link: { color: colors.accent, fontSize: 13, ...mono }\n };\n}\n\n// integrations/paseo/client/task-pills.ts\nvar TASKS_SCREEN = "alp-tasks";\nvar POLL_MS2 = 2e4;\nvar MENU_LIMIT = 8;\nvar PAGE = 200;\nfunction tasksScreen(workspaceId, directory, taskId) {\n return { screenId: TASKS_SCREEN, params: { workspaceId, directory, ...taskId ? { taskId } : {} } };\n}\nvar ORDER = ["approve", "review", "progress", "ready", "blocked"];\nvar STATES = {\n approve: { label: "Approve", icon: "Hand" },\n review: { label: "Review", icon: "Eye" },\n progress: { label: "In progress", icon: "LoaderCircle" },\n ready: { label: "Ready", icon: "CircleCheck" },\n blocked: { label: "Blocked", icon: "CircleSlash" },\n closed: { label: "Done", icon: "CheckCheck" }\n};\nfunction sessionWork(board, sessions = []) {\n const ids = sessions.map((id) => board?.sessions?.[id]).find(Boolean) ?? [];\n const index = new Map((board?.tasks ?? []).map((task) => [task.id, task]));\n return ids.flatMap((id) => index.has(id) ? [{ task: index.get(id), state: stateOf(index.get(id)) }] : []);\n}\nfunction menuTasks(tasks) {\n return tasks.filter((task) => task.status !== "closed" && task.type !== "epic").map((task) => ({ task, state: stateOf(task) })).sort((a, b) => ORDER.indexOf(a.state) - ORDER.indexOf(b.state) || a.task.priority - b.task.priority || a.task.id.localeCompare(b.task.id));\n}\nfunction taskButton(board, open, sessions = []) {\n const listed = board ? menuTasks(board.tasks) : [];\n const worked = sessionWork(board, sessions);\n const done = worked.filter((entry2) => entry2.state === "closed").length;\n const mine = new Set(worked.map((entry2) => entry2.task.id));\n const shown = [...worked, ...listed.filter((entry2) => !mine.has(entry2.task.id))];\n const entry = ({ task, state }, index) => ({\n kind: "item",\n id: `task-${index}`,\n title: `${STATES[state].label} \\xB7 ${task.title}`,\n icon: STATES[state].icon,\n behavior: { kind: "action", onPress: () => open(task.id) }\n });\n const items = shown.slice(0, MENU_LIMIT).map(entry);\n if (worked.length && items.length > worked.length) items.splice(worked.length, 0, { kind: "separator", id: "session-end" });\n if (items.length) items.push({ kind: "separator", id: "tasks-end" });\n const more = shown.length - MENU_LIMIT;\n items.push({ kind: "item", id: "all-tasks", title: more > 0 ? `All tasks (${more} more)` : "All tasks", icon: "ListTodo", behavior: { kind: "action", onPress: () => open() } });\n return {\n title: worked.length ? `ALP tasks: ${done} of ${worked.length} done in this session, ${listed.length} open` : listed.length ? `ALP tasks: ${listed.length} open` : "ALP tasks",\n icon: "ListTodo",\n label: worked.length ? `Tasks \\xB7 ${done}/${worked.length}` : listed.length ? `Tasks \\xB7 ${listed.length}` : "Tasks",\n visible: board?.projectRoot !== null,\n behavior: { kind: "menu", items }\n };\n}\nfunction signature(board, sessions) {\n return JSON.stringify(board && [board.projectRoot !== null, [...sessionWork(board, sessions), ...menuTasks(board.tasks)].map(({ task, state }) => [task.id, state, task.title])]);\n}\nfunction addTaskPills(client) {\n const agents = /* @__PURE__ */ new Map();\n const directories = /* @__PURE__ */ new Map();\n const boards = /* @__PURE__ */ new Map();\n const pills = /* @__PURE__ */ new Map();\n let subscription = null;\n let stopped = false;\n let retry;\n let polling = false;\n let again = false;\n const opener = (agent, directory) => (taskId) => client.openScreen(tasksScreen(agent.workspaceId, directory, taskId));\n const directoryOf = (agent) => {\n let found = directories.get(agent.workspaceId);\n if (!found) {\n found = client.paseo.workspaces.ref(agent.workspaceId).refresh().then((workspace) => workspace?.workspaceDirectory || workspace?.projectRootPath || agent.cwd).catch(() => {\n directories.delete(agent.workspaceId);\n return agent.cwd;\n });\n directories.set(agent.workspaceId, found);\n }\n return found;\n };\n const show = (agent) => __async(null, null, function* () {\n const directory = yield directoryOf(agent);\n if (stopped || pills.has(agent.id) || agents.get(agent.id) !== agent) return;\n const board = boards.get(directory) ?? null;\n try {\n const registration = client.addComposerPill({ id: "alp-tasks", workspaceId: agent.workspaceId, agentId: agent.id, button: taskButton(board, opener(agent, directory), agent.sessions) });\n pills.set(agent.id, { agent, directory, registration, signature: signature(board, agent.sessions) });\n } catch {\n return;\n }\n if (!board) void poll();\n });\n const hide = (id) => {\n agents.delete(id);\n pills.get(id)?.registration.remove();\n pills.delete(id);\n };\n const accept = (snapshot) => {\n const known = agents.get(snapshot.id);\n if (snapshot.provider !== "alp" || !snapshot.workspaceId || snapshot.archivedAt) {\n if (known) hide(snapshot.id);\n return;\n }\n const sessions = [snapshot.persistence?.sessionId, snapshot.id].filter((id) => Boolean(id));\n if (known?.workspaceId === snapshot.workspaceId && known.sessions.join() === sessions.join()) return;\n if (known) hide(snapshot.id);\n const agent = { id: snapshot.id, workspaceId: snapshot.workspaceId, cwd: snapshot.cwd, sessions };\n agents.set(agent.id, agent);\n void show(agent);\n };\n const load = (page) => __async(null, null, function* () {\n const seen = /* @__PURE__ */ new Set();\n for (let current = page; ; ) {\n for (const { agent } of current.entries) {\n seen.add(agent.id);\n accept(agent);\n }\n const cursor = current.pageInfo.nextCursor;\n if (!current.pageInfo.hasMore || !cursor || stopped) break;\n current = yield client.paseo.agents.list({ scope: "active", page: { limit: PAGE, cursor } });\n }\n for (const id of [...agents.keys()]) if (!seen.has(id)) hide(id);\n });\n const watch = () => __async(null, null, function* () {\n try {\n const first = yield client.paseo.agents.list({ scope: "active", page: { limit: PAGE }, subscribe: {} });\n if (stopped) {\n void first.subscription.release().catch(() => {\n });\n return;\n }\n subscription = first.subscription;\n first.subscription.subscribe({\n snapshot: (snapshot) => {\n void load(snapshot).catch(() => {\n });\n },\n update: (message2) => {\n if (message2.type !== "agent_update") return;\n if (message2.payload.kind === "remove") hide(message2.payload.agentId);\n else accept(message2.payload.agent);\n }\n });\n } catch {\n if (!stopped) retry = setTimeout(() => void watch(), POLL_MS2);\n }\n });\n const poll = () => __async(null, null, function* () {\n if (polling) {\n again = true;\n return;\n }\n polling = true;\n try {\n const shown = new Set([...pills.values()].map((pill) => pill.directory));\n for (const directory of shown) {\n if (stopped) return;\n try {\n boards.set(directory, yield client.rpc(tasksList, { directory }));\n } catch {\n continue;\n }\n for (const pill of pills.values()) if (pill.directory === directory) render(pill);\n }\n for (const directory of [...boards.keys()]) if (!shown.has(directory)) boards.delete(directory);\n } finally {\n polling = false;\n if (again && !stopped) {\n again = false;\n void poll();\n }\n }\n });\n const render = (pill) => {\n const board = boards.get(pill.directory) ?? null;\n const next = signature(board, pill.agent.sessions);\n if (next === pill.signature) return;\n pill.signature = next;\n pill.registration.update(taskButton(board, opener(pill.agent, pill.directory), pill.agent.sessions));\n };\n const timer = setInterval(() => void poll(), POLL_MS2);\n void watch();\n return () => {\n stopped = true;\n clearInterval(timer);\n if (retry !== void 0) clearTimeout(retry);\n for (const id of [...pills.keys()]) hide(id);\n void subscription?.release().catch(() => {\n });\n };\n}\n\n// integrations/paseo/client/team-model-settings.tsx\nvar import_react3 = require("react");\nvar import_react_native5 = require("react-native");\nvar import_client2 = require("@getpaseo/plugin/client");\nvar import_ui = require("@getpaseo/plugin/client/ui");\n\n// integrations/paseo/shared/library.ts\nvar import_plugin2 = require("@getpaseo/plugin");\nvar import_zod2 = require("zod");\nvar Directory2 = import_zod2.z.string().min(1).optional();\nvar KindSchema = import_zod2.z.enum(["agents", "skills", "mcp", "hooks", "teams", "providers"]);\nvar ScopeSchema = import_zod2.z.enum(["library", "project"]);\nvar Name = import_zod2.z.string().regex(/^[\\w.-]+$/).refine((name) => name !== "." && name !== "..");\nvar Source = import_zod2.z.enum(["builtin", "library", "project"]);\nvar EntryRowSchema = import_zod2.z.object({\n name: import_zod2.z.string(),\n source: Source,\n overrides: Source.optional(),\n path: import_zod2.z.string().optional(),\n description: import_zod2.z.string().optional(),\n usedBy: import_zod2.z.array(import_zod2.z.string()).optional()\n});\nvar libraryList = (0, import_plugin2.defineRpc)({\n name: "alp.library.list",\n input: import_zod2.z.object({ directory: Directory2, kind: KindSchema }),\n output: import_zod2.z.object({\n projectRoot: import_zod2.z.string().nullable(),\n library: import_zod2.z.string(),\n entries: import_zod2.z.array(EntryRowSchema),\n /**\n * Set when the library can only be looked at from here (ALP remote mode): why, and where to\n * change it. `unlisted` says why there are no entries at all (no granted workspace open).\n */\n readOnly: import_zod2.z.object({ reason: import_zod2.z.string(), unlisted: import_zod2.z.string().optional() }).optional()\n })\n});\nvar libraryGet = (0, import_plugin2.defineRpc)({\n name: "alp.library.get",\n input: import_zod2.z.object({ directory: Directory2, kind: KindSchema, name: Name, scope: ScopeSchema.optional() }),\n output: import_zod2.z.object({\n kind: KindSchema,\n name: import_zod2.z.string(),\n source: Source,\n overrides: Source.optional(),\n content: import_zod2.z.record(import_zod2.z.string(), import_zod2.z.unknown()),\n /** Pass back with a save or delete; a different current revision refuses it. */\n revision: import_zod2.z.string().nullable(),\n usedBy: import_zod2.z.array(import_zod2.z.string()),\n /** Agents: the skills the library gives it by name (role-skills.json). */\n librarySkills: import_zod2.z.array(import_zod2.z.string()).optional()\n })\n});\nvar librarySkills = (0, import_plugin2.defineRpc)({\n name: "alp.library.skills",\n input: import_zod2.z.object({ agent: Name, skills: import_zod2.z.array(Name) }),\n output: import_zod2.z.object({ skills: import_zod2.z.array(import_zod2.z.string()) })\n});\nvar librarySave = (0, import_plugin2.defineRpc)({\n name: "alp.library.save",\n input: import_zod2.z.object({\n directory: Directory2,\n kind: KindSchema,\n name: Name,\n scope: ScopeSchema,\n content: import_zod2.z.record(import_zod2.z.string(), import_zod2.z.unknown()),\n /** null creates; a string replaces that revision; omitted overwrites. */\n revision: import_zod2.z.string().nullable().optional()\n }),\n output: import_zod2.z.object({ revision: import_zod2.z.string().nullable(), syncedProjects: import_zod2.z.number().int().nonnegative().optional(), syncErrors: import_zod2.z.array(import_zod2.z.string()).optional() })\n});\nvar libraryDelete = (0, import_plugin2.defineRpc)({\n name: "alp.library.delete",\n input: import_zod2.z.object({ directory: Directory2, kind: KindSchema, name: Name, scope: ScopeSchema, revision: import_zod2.z.string().optional() }),\n /** now: the layer that applies again after removing an override. */\n output: import_zod2.z.object({ removed: import_zod2.z.boolean(), now: Source.optional() })\n});\nvar libraryDuplicate = (0, import_plugin2.defineRpc)({\n name: "alp.library.duplicate",\n input: import_zod2.z.object({ directory: Directory2, kind: KindSchema, from: Name, to: Name, scope: ScopeSchema }),\n output: import_zod2.z.object({ revision: import_zod2.z.string().nullable() })\n});\nvar libraryRename = (0, import_plugin2.defineRpc)({\n name: "alp.library.rename",\n input: import_zod2.z.object({ directory: Directory2, kind: KindSchema, from: Name, to: Name, scope: ScopeSchema }),\n output: import_zod2.z.object({ revision: import_zod2.z.string().nullable() })\n});\nvar libraryTest = (0, import_plugin2.defineRpc)({\n name: "alp.library.test",\n input: import_zod2.z.object({ directory: Directory2, kind: import_zod2.z.enum(["mcp", "hooks", "providers"]), name: Name, scope: ScopeSchema.optional() }),\n output: import_zod2.z.object({\n ok: import_zod2.z.boolean(),\n /** MCP: the server and its tools. */\n server: import_zod2.z.object({ name: import_zod2.z.string().optional(), version: import_zod2.z.string().optional() }).optional(),\n tools: import_zod2.z.array(import_zod2.z.object({ name: import_zod2.z.string(), description: import_zod2.z.string().optional() })).optional(),\n /** Hooks: how the sample run went. */\n exitCode: import_zod2.z.number().nullable().optional(),\n signal: import_zod2.z.string().nullable().optional(),\n timedOut: import_zod2.z.boolean().optional(),\n wouldBlock: import_zod2.z.boolean().optional(),\n stdout: import_zod2.z.string().optional(),\n stderr: import_zod2.z.string().optional(),\n durationMs: import_zod2.z.number().optional(),\n /** Providers: who the ACP agent says it is, and what it supports. */\n protocolVersion: import_zod2.z.number().optional(),\n agent: import_zod2.z.object({ name: import_zod2.z.string().optional(), title: import_zod2.z.string().optional(), version: import_zod2.z.string().optional() }).optional(),\n loadSession: import_zod2.z.boolean().optional(),\n mcpHttp: import_zod2.z.boolean().optional(),\n authMethods: import_zod2.z.array(import_zod2.z.string()).optional()\n })\n});\nvar LanguageSettingSchema = import_zod2.z.object({\n language: import_zod2.z.string().nullable(),\n applies: import_zod2.z.string(),\n default: import_zod2.z.string(),\n /** Why it cannot be changed from here (ALP remote mode). */\n readOnly: import_zod2.z.string().optional()\n});\nvar languageGet = (0, import_plugin2.defineRpc)({\n name: "alp.settings.language.get",\n input: import_zod2.z.object({}),\n output: LanguageSettingSchema\n});\nvar languageSet = (0, import_plugin2.defineRpc)({\n name: "alp.settings.language.set",\n input: import_zod2.z.object({ language: import_zod2.z.string().trim().min(1).max(40).nullable() }),\n output: LanguageSettingSchema\n});\nvar libraryModels = (0, import_plugin2.defineRpc)({\n name: "alp.library.models",\n input: import_zod2.z.object({}),\n output: import_zod2.z.object({ models: import_zod2.z.array(import_zod2.z.object({ id: import_zod2.z.string(), label: import_zod2.z.string(), efforts: import_zod2.z.array(import_zod2.z.string()), effort: import_zod2.z.string().optional() })) })\n});\n\n// integrations/paseo/shared/team-models.ts\nvar MODEL_PRESETS = [\n { label: "Claude only", value: "claude" },\n { label: "Codex only", value: "codex" },\n { label: "OpenCode only", value: "opencode" },\n { label: "Antigravity only", value: "antigravity" },\n { label: "Mix \\xB7 Claude + Codex", value: "mix" }\n];\nfunction presetTeamModels(team, preset, models) {\n const next = JSON.parse(JSON.stringify(team));\n const find = (provider) => models.find((model) => provider === "opencode" ? model.id === "acp:opencode" || model.id.startsWith("acp:opencode/") : model.id.startsWith(`${provider}:`));\n const primary = find(preset === "mix" ? "claude" : preset);\n const secondary = preset === "mix" ? find("codex") : primary;\n if (!primary || !secondary) throw new Error("No models available for this preset. Configure the provider in Settings first.");\n const assign = (target, model) => {\n target.model = model.id;\n if (model.effort) target.thinking = model.effort;\n else delete target.thinking;\n };\n for (const [name, member] of Object.entries(next.members ?? {})) {\n if (name !== "oracle") assign(member, name === next.main ? primary : secondary);\n }\n if (next.supervisor) assign(next.supervisor, secondary);\n if (next.members?.oracle) {\n next.oracleModels = [.../* @__PURE__ */ new Set([primary.id, secondary.id])];\n next.oracleThinking = Object.fromEntries([primary, secondary].filter((model) => model.effort).map((model) => [model.id, model.effort]));\n }\n next.modelSetup = { mode: "default", preset };\n return next;\n}\nfunction modelSetupFor(team, models) {\n if (team.modelSetup) return team.modelSetup;\n for (const { value } of MODEL_PRESETS) {\n let expected;\n try {\n expected = presetTeamModels(team, value, models);\n } catch {\n continue;\n }\n const same = (a, b) => a.model === b.model && a.thinking === b.thinking;\n if (!Object.entries(team.members ?? {}).filter(([name]) => name !== "oracle").every(([name, member]) => same(member, expected.members[name]))) continue;\n if (team.supervisor && !same(team.supervisor, expected.supervisor)) continue;\n if (team.members?.oracle && (JSON.stringify(team.oracleModels) !== JSON.stringify(expected.oracleModels) || expected.oracleModels.some((id) => (team.oracleThinking?.[id] ?? team.oracleThinking?.[id.split(":")[0]]) !== expected.oracleThinking?.[id]))) continue;\n return { mode: "default", preset: value };\n }\n return { mode: "custom" };\n}\n\n// integrations/paseo/client/side-nav.tsx\nvar import_react_native3 = require("@getpaseo/plugin/client/react-native");\nvar import_react2 = require("react");\nvar import_react_native4 = require("react-native");\nvar import_jsx_runtime2 = require("react/jsx-runtime");\nvar hovered2 = (state) => !!state.hovered;\nvar COLLAPSE_BELOW = 640;\nvar EXPANDED = 216;\nvar COLLAPSED = 52;\nfunction SideNavLayout(props) {\n const { theme, compact, groups, active, onSelect } = props;\n const styles = (0, import_react2.useMemo)(() => layoutStyles(theme), [theme]);\n const [width, setWidth] = (0, import_react2.useState)(0);\n const [choice, setChoice] = (0, import_react2.useState)(props.initialCollapsed);\n const [open, setOpen] = (0, import_react2.useState)(false);\n const collapsed = choice ?? (width > 0 && width < COLLAPSE_BELOW);\n const select = (item, child) => {\n onSelect(item, child);\n setOpen(false);\n };\n const aside = (mode) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(\n Aside,\n {\n styles,\n theme,\n title: props.title,\n subtitle: props.subtitle,\n groups,\n active,\n onSelect: select,\n collapsed: mode === "fixed" && collapsed,\n onToggle: mode === "fixed" ? () => setChoice(!collapsed) : () => setOpen(false),\n overlay: mode === "overlay"\n }\n );\n return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native4.View, { style: props.embedded ? { width: "100%" } : styles.root, onLayout: (event) => setWidth(event.nativeEvent.layout.width), children: [\n !props.embedded && !compact ? aside("fixed") : null,\n /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native4.View, { style: props.embedded ? { minWidth: 0 } : styles.main, children: [\n /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native4.View, { style: [styles.header, props.embedded ? { paddingHorizontal: 0, paddingTop: 0 } : null], children: [\n /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native4.View, { style: styles.headerRow, children: [\n compact && !props.embedded ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.Pressable, { accessibilityRole: "button", accessibilityLabel: "Open navigation", onPress: () => setOpen(true), style: styles.iconButton, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native3.Icon, { name: "Menu", size: 18, color: theme.colors.foreground }) }) : null,\n /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native4.View, { style: styles.crumbs, children: [\n props.breadcrumb.map((part, index) => [\n index ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.Text, { style: styles.crumbSeparator, children: "/" }, `separator-${index}`) : null,\n /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.Text, { style: index === props.breadcrumb.length - 1 ? styles.crumbCurrent : styles.crumb, numberOfLines: 1, children: part }, `${index}-${part}`)\n ]),\n props.badges\n ] }),\n props.actions ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.View, { style: styles.actions, children: props.actions }) : null\n ] }),\n props.tabs?.length ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native3.ScrollView, { horizontal: true, showsHorizontalScrollIndicator: false, contentContainerStyle: styles.tabs, children: props.tabs.map((tab) => {\n const on = tab.key === props.tab;\n return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.Pressable, { accessibilityRole: "tab", accessibilityLabel: tab.label, accessibilityState: { selected: on }, onPress: () => props.onTab?.(tab.key), style: [styles.tab, on ? styles.tabOn : null], children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native4.Text, { style: on ? styles.tabTextOn : styles.tabText, children: [\n tab.label,\n tab.count !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.Text, { style: styles.tabCount, children: ` ${tab.count}` }) : null\n ] }) }, tab.key);\n }) }) : null\n ] }),\n props.embedded ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.View, { style: [styles.bodyContent, { paddingHorizontal: 0 }], children: props.children }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native3.ScrollView, { style: styles.body, contentContainerStyle: styles.bodyContent, children: props.children }),\n props.footer ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.View, { style: [styles.footer, props.embedded ? { paddingHorizontal: 0 } : null], children: props.footer }) : null\n ] }),\n !props.embedded && compact && open ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native4.View, { style: styles.overlay, children: [\n aside("overlay"),\n /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.Pressable, { accessibilityRole: "button", accessibilityLabel: "Close navigation", onPress: () => setOpen(false), style: styles.scrim })\n ] }) : null\n ] });\n}\nfunction Aside({ styles, theme, title, subtitle, groups, active, onSelect, collapsed, onToggle, overlay }) {\n const { colors } = theme;\n const [opened, setOpened] = (0, import_react2.useState)({});\n const tone = (value) => value === "accent" ? colors.accent : value === "warning" ? colors.statusWarning : colors.border;\n return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native4.View, { style: [styles.aside, { width: collapsed ? COLLAPSED : EXPANDED }, overlay ? styles.asideOverlay : null], children: [\n /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native4.View, { style: [styles.asideHeader, collapsed ? styles.asideHeaderCollapsed : null], children: [\n !collapsed ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native4.View, { style: styles.asideTitleBox, children: [\n /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.Text, { style: styles.asideTitle, numberOfLines: 1, children: title }),\n subtitle ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.Text, { style: styles.asideSubtitle, numberOfLines: 1, children: subtitle }) : null\n ] }) : null,\n /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.Pressable, { accessibilityRole: "button", accessibilityLabel: overlay ? "Close navigation" : collapsed ? "Expand navigation" : "Collapse navigation", onPress: onToggle, style: styles.iconButton, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native3.Icon, { name: overlay ? "X" : collapsed ? "PanelLeftOpen" : "PanelLeftClose", size: 16, color: colors.foregroundMuted }) })\n ] }),\n /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native3.ScrollView, { contentContainerStyle: styles.asideList, children: groups.map((group) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native4.View, { style: styles.group, children: [\n !collapsed ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.Text, { style: styles.groupLabel, children: group.label }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.View, { style: styles.groupRule }),\n group.items.map((item) => {\n const selected = active.item === item.key;\n const expanded = !collapsed && (opened[item.key] ?? selected) && !!item.children?.length;\n return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native4.View, { children: [\n /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(\n import_react_native4.Pressable,\n {\n accessibilityRole: "button",\n accessibilityLabel: item.label,\n accessibilityState: { selected: selected && !active.child },\n onPress: () => {\n onSelect(item.key);\n setOpened((current) => ({ ...current, [item.key]: true }));\n },\n style: (state) => [styles.item, collapsed ? styles.itemCollapsed : null, selected ? styles.itemOn : hovered2(state) ? styles.itemHover : null],\n children: [\n selected ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.View, { style: styles.itemBar }) : null,\n /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native3.Icon, { name: item.icon, size: 16, color: selected ? colors.accent : colors.foregroundMuted }),\n !collapsed ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.Text, { style: [styles.itemLabel, selected ? styles.itemLabelOn : null], numberOfLines: 1, children: item.label }) : null,\n !collapsed && item.count !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.Text, { style: styles.count, children: item.count }) : null,\n !collapsed && item.children?.length ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.Pressable, { accessibilityRole: "button", accessibilityLabel: `${expanded ? "Hide" : "Show"} ${item.label}`, hitSlop: 8, onPress: () => setOpened((current) => ({ ...current, [item.key]: !expanded })), children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native3.Icon, { name: expanded ? "ChevronDown" : "ChevronRight", size: 14, color: colors.foregroundMuted }) }) : null\n ]\n }\n ),\n expanded ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.View, { style: styles.children, children: item.children.map((child) => {\n const on = selected && active.child === child.key;\n return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(\n import_react_native4.Pressable,\n {\n accessibilityRole: "button",\n accessibilityLabel: `${item.label} ${child.label}`,\n accessibilityState: { selected: on },\n onPress: () => onSelect(item.key, child.key),\n style: (state) => [styles.child, on ? styles.childOn : hovered2(state) ? styles.itemHover : null],\n children: [\n /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.View, { style: [styles.dot, { backgroundColor: tone(child.tone) }] }),\n /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.Text, { style: [styles.childLabel, on ? styles.itemLabelOn : null], numberOfLines: 1, children: child.label }),\n child.hint ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.Text, { style: styles.childHint, numberOfLines: 1, children: child.hint }) : null\n ]\n },\n child.key\n );\n }) }) : null\n ] }, item.key);\n })\n ] }, group.key)) })\n ] });\n}\nfunction Pill({ theme, label, tone = "muted" }) {\n const { colors } = theme;\n const color = tone === "accent" ? colors.accent : tone === "success" ? colors.statusSuccess : tone === "warning" ? colors.statusWarning : tone === "danger" ? colors.statusDanger : colors.foregroundMuted;\n return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.View, { style: { borderRadius: 999, borderWidth: 1, borderColor: tone === "muted" ? colors.border : color, paddingHorizontal: 7, paddingVertical: 1, alignSelf: "center" }, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.Text, { style: { color, fontSize: 11, fontWeight: "500" }, children: label }) });\n}\nfunction Button({ theme, label, onPress, kind = "plain", icon, disabled, accessibilityLabel }) {\n const { colors } = theme;\n const color = kind === "primary" ? colors.accentForeground : kind === "danger" ? colors.statusDanger : colors.foreground;\n return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(\n import_react_native4.Pressable,\n {\n accessibilityRole: "button",\n accessibilityLabel: accessibilityLabel ?? label,\n disabled,\n onPress,\n style: (state) => ({\n flexDirection: "row",\n alignItems: "center",\n gap: 6,\n borderRadius: 8,\n paddingHorizontal: 12,\n paddingVertical: 7,\n opacity: disabled ? 0.5 : 1,\n backgroundColor: kind === "primary" ? colors.accent : hovered2(state) ? colors.surface2 : colors.surface1,\n borderWidth: kind === "primary" ? 0 : 1,\n borderColor: kind === "danger" ? colors.statusDanger : colors.border\n }),\n children: [\n icon ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native3.Icon, { name: icon, size: 14, color }) : null,\n /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.Text, { style: { color, fontSize: 13, fontWeight: kind === "primary" ? "600" : "500" }, children: label })\n ]\n }\n );\n}\nfunction layoutStyles(theme) {\n const { colors } = theme;\n return {\n root: { flex: 1, flexDirection: "row", backgroundColor: colors.surface0, minHeight: 560, borderWidth: 1, borderColor: colors.border, borderRadius: 12, overflow: "hidden" },\n aside: { backgroundColor: colors.surface1, borderRightWidth: 1, borderRightColor: colors.border },\n asideOverlay: { height: "100%", shadowColor: "#000", shadowOpacity: 0.2, shadowRadius: 16 },\n asideHeader: { flexDirection: "row", alignItems: "center", justifyContent: "space-between", paddingHorizontal: 12, paddingVertical: 12, borderBottomWidth: 1, borderBottomColor: colors.border, gap: 8 },\n asideHeaderCollapsed: { justifyContent: "center", paddingHorizontal: 0 },\n asideTitleBox: { flex: 1, minWidth: 0 },\n asideTitle: { color: colors.foreground, fontSize: 14, fontWeight: "600" },\n asideSubtitle: { color: colors.foregroundMuted, fontSize: 11, marginTop: 1 },\n asideList: { paddingVertical: 8, gap: 10 },\n group: { gap: 1 },\n groupLabel: { color: colors.foregroundMuted, fontSize: 11, fontWeight: "600", letterSpacing: 0.4, textTransform: "uppercase", paddingHorizontal: 14, paddingBottom: 4 },\n groupRule: { height: 1, backgroundColor: colors.border, marginHorizontal: 12, marginBottom: 4 },\n item: { flexDirection: "row", alignItems: "center", gap: 10, marginHorizontal: 6, paddingHorizontal: 8, paddingVertical: 7, borderRadius: 7 },\n itemCollapsed: { justifyContent: "center", paddingHorizontal: 0 },\n itemOn: { backgroundColor: colors.surface2 },\n itemHover: { backgroundColor: colors.surface2 },\n itemBar: { position: "absolute", left: -6, top: 6, bottom: 6, width: 3, borderRadius: 2, backgroundColor: colors.accent },\n itemLabel: { flex: 1, color: colors.foreground, fontSize: 13 },\n itemLabelOn: { color: colors.foreground, fontWeight: "600" },\n count: { color: colors.foregroundMuted, fontSize: 11, fontVariant: ["tabular-nums"] },\n children: { marginLeft: 22, borderLeftWidth: 1, borderLeftColor: colors.border, marginVertical: 2, paddingLeft: 4 },\n child: { flexDirection: "row", alignItems: "center", gap: 8, marginRight: 6, paddingHorizontal: 8, paddingVertical: 5, borderRadius: 6 },\n childOn: { backgroundColor: colors.surface2 },\n childLabel: { flex: 1, color: colors.foreground, fontSize: 12.5 },\n childHint: { color: colors.foregroundMuted, fontSize: 11 },\n dot: { width: 6, height: 6, borderRadius: 3 },\n main: { flex: 1, minWidth: 0 },\n header: { borderBottomWidth: 1, borderBottomColor: colors.border, paddingHorizontal: 20, paddingTop: 14, gap: 10 },\n headerRow: { flexDirection: "row", alignItems: "center", gap: 10, minHeight: 32 },\n crumbs: { flex: 1, minWidth: 0, flexDirection: "row", alignItems: "center", gap: 8, flexWrap: "wrap" },\n crumb: { color: colors.foregroundMuted, fontSize: 13 },\n crumbSeparator: { color: colors.foregroundMuted, fontSize: 13, opacity: 0.6 },\n crumbCurrent: { color: colors.foreground, fontSize: 16, fontWeight: "600" },\n actions: { flexDirection: "row", gap: 8, alignItems: "center" },\n tabs: { flexDirection: "row", gap: 4 },\n tab: { paddingHorizontal: 10, paddingVertical: 8, borderBottomWidth: 2, borderBottomColor: "transparent" },\n tabOn: { borderBottomColor: colors.accent },\n tabText: { color: colors.foregroundMuted, fontSize: 13 },\n tabTextOn: { color: colors.foreground, fontSize: 13, fontWeight: "600" },\n tabCount: { color: colors.foregroundMuted, fontSize: 11 },\n body: { flex: 1 },\n bodyContent: { padding: 20, gap: 16 },\n footer: { flexDirection: "row", alignItems: "center", gap: 10, paddingHorizontal: 20, paddingVertical: 12, borderTopWidth: 1, borderTopColor: colors.border, backgroundColor: colors.surface1 },\n iconButton: { padding: 6, borderRadius: 6 },\n overlay: { position: "absolute", left: 0, top: 0, right: 0, bottom: 0, flexDirection: "row" },\n scrim: { flex: 1, backgroundColor: "rgba(0,0,0,0.25)" }\n };\n}\n\n// integrations/paseo/client/team-model-settings.tsx\nvar import_jsx_runtime3 = require("react/jsx-runtime");\nvar clone = (team) => JSON.parse(JSON.stringify(team));\nfunction TeamModelSettings({ team, theme, onChange }) {\n const readModels = (0, import_client2.useRpc)(libraryModels);\n const [models, setModels] = (0, import_react3.useState)([]);\n const [error, setError] = (0, import_react3.useState)("");\n const [customFields, setCustomFields] = (0, import_react3.useState)({});\n const setup = modelSetupFor(team, models);\n const mode = setup.mode;\n const preset = setup.preset ?? "mix";\n (0, import_react3.useEffect)(() => {\n let live = true;\n readModels({}).then((result) => {\n if (live) {\n setModels(result.models);\n setError("");\n }\n }).catch((cause) => {\n if (live) setError(String(cause.message ?? cause));\n });\n return () => {\n live = false;\n };\n }, [readModels]);\n const edit = (work) => {\n const next = clone(team);\n next.modelSetup = { mode: "custom" };\n work(next);\n onChange(next);\n setError("");\n };\n const selectPreset = (value) => {\n try {\n onChange(presetTeamModels(team, value, models));\n setCustomFields({});\n setError("");\n } catch (cause) {\n setError(cause instanceof Error ? cause.message : String(cause));\n }\n };\n const chooseModel = (label, value, set) => {\n const known = models.find((model) => model.id === value);\n const options = [...label.startsWith("oracle-") ? [] : [{ label: "Inherit", value: "" }], ...models.map((model) => ({ value: model.id, label: model.label }))];\n if (value && !known) options.push({ label: value, value });\n options.push({ label: "Custom model ID", value: "__custom" });\n return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [\n /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_ui.SettingsSelect, { label: "Model", value: customFields[label] ? "__custom" : value, options, onValueChange: (id) => {\n setCustomFields((previous) => ({ ...previous, [label]: id === "__custom" }));\n if (id !== "__custom") edit((next) => set(next, id, models.find((model) => model.id === id)?.effort));\n } }),\n customFields[label] || value && !known ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_ui.SettingsInput, { label: "Custom model ID", hint: "claude:model, codex:model, antigravity:model or acp:provider/model", initialValue: value, onChangeText: (id) => edit((next) => set(next, id.trim())) }, `${label}-custom`) : null\n ] });\n };\n const effort = (model, value, set) => {\n const known = models.find((choice) => choice.id === model);\n const values = known ? known.efforts : ["none", "off", "low", "medium", "high", "xhigh", "max", "ultra", "ultracode"];\n const options = [{ label: "Inherit", value: "" }, ...[.../* @__PURE__ */ new Set([...values, ...value ? [value] : []])].map((value2) => ({ label: value2, value: value2 }))];\n return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_ui.SettingsSelect, { label: "Effort", value, options, onValueChange: (value2) => edit((next) => set(next, value2)) });\n };\n const assign = (target, id, thinking) => {\n if (id) target.model = id;\n else delete target.model;\n if (thinking) target.thinking = thinking;\n else delete target.thinking;\n };\n const setEffort = (target, value) => {\n if (value) target.thinking = value;\n else delete target.thinking;\n };\n const lenses = team.oracleModels ?? ["claude:claude-fable-5-1", "codex:gpt-6-astra"];\n return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [\n /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_ui.SettingsSection, { title: "Model setup", children: [\n /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_ui.SettingsSelect, { label: "Mode", value: mode, options: [{ label: "Default presets", value: "default" }, { label: "Custom", value: "custom" }], onValueChange: (value) => value === "default" ? selectPreset(preset) : edit(() => {\n }) }),\n mode === "default" ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_ui.SettingsSelect, { label: "Preset", value: preset, options: MODEL_PRESETS, onValueChange: selectPreset }) : null,\n /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_ui.SettingsRow, { label: "Save with template", hint: "Save writes these model choices into settings.json for this team immediately. Project template overrides still apply to Host templates." }),\n error ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native5.Text, { accessibilityRole: "alert", style: { color: theme?.colors.statusDanger }, children: error }) : null\n ] }),\n mode === "default" ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_ui.SettingsSection, { title: "Preset models", children: [\n Object.entries(team.members ?? {}).filter(([name]) => name !== "oracle").map(([name, member]) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_ui.SettingsRow, { label: name, hint: member.model }, name)),\n team.supervisor ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_ui.SettingsRow, { label: "Supervisor", hint: team.supervisor.model }) : null,\n team.members?.oracle ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_ui.SettingsRow, { label: "Oracle", hint: lenses.join(", ") }) : null\n ] }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react3.Fragment, { children: [\n Object.entries(team.members ?? {}).filter(([name]) => name !== "oracle").map(([name, member]) => {\n const config = member;\n return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_ui.SettingsSection, { title: name === team.main ? `${name} \\xB7 main` : name, children: [\n chooseModel(name, config.model ?? "", (next, id, effort2) => assign(next.members[name], id, effort2)),\n effort(config.model ?? team.members[team.main]?.model ?? "", config.thinking ?? "", (next, value) => setEffort(next.members[name], value))\n ] }, name);\n }),\n team.supervisor ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_ui.SettingsSection, { title: "Supervisor", children: [\n chooseModel("supervisor", team.supervisor.model ?? "", (next, id, effort2) => assign(next.supervisor, id, effort2)),\n effort(team.supervisor.model ?? "", team.supervisor.thinking ?? "", (next, value) => setEffort(next.supervisor, value))\n ] }) : null,\n team.members?.oracle ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [\n lenses.map((id, index) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_ui.SettingsSection, { title: `Oracle ${index + 1}`, children: [\n chooseModel(`oracle-${index}`, id, (next, value, effort2) => {\n next.oracleModels = [...lenses];\n next.oracleModels[index] = value;\n next.oracleThinking ?? (next.oracleThinking = {});\n delete next.oracleThinking[id];\n if (effort2) next.oracleThinking[value] = effort2;\n }),\n effort(id, team.oracleThinking?.[id] ?? team.oracleThinking?.[id.split(":")[0]] ?? "", (next, value) => {\n next.oracleThinking ?? (next.oracleThinking = {});\n delete next.oracleThinking[id.split(":")[0]];\n if (value) next.oracleThinking[id] = value;\n else delete next.oracleThinking[id];\n }),\n theme && lenses.length > 1 ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Button, { theme, label: "Remove model", onPress: () => edit((next) => {\n next.oracleModels = lenses.filter((_, i) => i !== index);\n }) }) : null\n ] }, index)),\n theme ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Button, { theme, label: "Add oracle model", onPress: () => edit((next) => {\n next.oracleModels = [...lenses, ""];\n setCustomFields((previous) => ({ ...previous, [`oracle-${lenses.length}`]: true }));\n }) }) : null\n ] }) : null\n ] }, "custom-models"),\n JSON.stringify(team).includes("antigravity:") ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_ui.SettingsSection, { title: "Antigravity", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_ui.SettingsRow, { label: "Advisory roles", hint: \'Reviewer, Oracle and Supervisor require readOnlyMode: "instructions" in the Antigravity provider. Review copies and custom permission rules are unsupported.\' }) }) : null\n ] });\n}\n\n// integrations/paseo/client/library.tsx\nvar import_client3 = require("@getpaseo/plugin/client");\nvar import_react_native6 = require("@getpaseo/plugin/client/react-native");\nvar import_ui2 = require("@getpaseo/plugin/client/ui");\nvar import_react4 = require("react");\nvar import_react_native7 = require("react-native");\nvar import_jsx_runtime4 = require("react/jsx-runtime");\nvar KINDS = [\n { kind: "teams", title: "Teams", one: "team", icon: "Users", group: "Organisation" },\n { kind: "agents", title: "Agents", one: "agent", icon: "Bot", group: "Organisation" },\n { kind: "skills", title: "Skills", one: "skill", icon: "BookOpen", group: "Capabilities" },\n { kind: "mcp", title: "MCP servers", one: "MCP server", icon: "Plug", group: "Capabilities" },\n { kind: "hooks", title: "Hooks", one: "hook", icon: "Webhook", group: "Capabilities" },\n // ACP agents (ALPD \xA746): in the library only, so the project panel leaves them out.\n { kind: "providers", title: "Providers", one: "provider", icon: "Cpu", group: "Runtimes" }\n];\nvar shownIn = (scope) => KINDS.filter((item) => scope === "library" || item.kind !== "providers");\nvar kindOf = (kind) => KINDS.find((item) => item.kind === kind);\nvar HOOK_EVENTS = ["session.start", "turn.end", "assignment.start", "assignment.end", "handoff", "task.close", "merge"];\nvar BLOCKING_EVENTS = ["handoff", "task.close", "merge"];\nvar ROLES = ["lead", "peer", "advisor", "reviewer"];\nvar MODES = ["", "read-only", "workspace-write", "full-access"];\nvar NAME = /^[\\w.-]+$/;\nvar clone2 = (value) => JSON.parse(JSON.stringify(value));\nvar message = (cause) => cause instanceof Error ? cause.message : String(cause);\nvar sourceLabel = (source) => source === "builtin" ? "built-in" : source;\nvar sourceTone = (source) => source === "project" ? "warning" : source === "library" ? "accent" : "muted";\nvar LANGUAGES = [\n { label: "Ti\\u1EBFng Vi\\u1EC7t", value: "Vietnamese" },\n { label: "English", value: "English" },\n { label: "\\u65E5\\u672C\\u8A9E", value: "Japanese" },\n { label: "\\uD55C\\uAD6D\\uC5B4", value: "Korean" },\n { label: "\\u4E2D\\u6587", value: "Chinese" },\n { label: "Fran\\xE7ais", value: "French" },\n { label: "Deutsch", value: "German" },\n { label: "Espa\\xF1ol", value: "Spanish" }\n];\nfunction LibrarySettings({ theme, layout }) {\n return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(LibraryManager, { theme, compact: layout.compact, scope: "library" });\n}\nfunction TeamsSettings({ theme, layout }) {\n return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(LibraryManager, { theme, compact: layout.compact, scope: "library", initialKind: "teams", embedded: true });\n}\nfunction AgentsSettings({ theme, layout }) {\n return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(LibraryManager, { theme, compact: layout.compact, scope: "library", initialKind: "agents", embedded: true });\n}\nfunction SkillsSettings({ theme, layout }) {\n return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(LibraryManager, { theme, compact: layout.compact, scope: "library", initialKind: "skills", embedded: true });\n}\nfunction HooksSettings({ theme, layout }) {\n return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(LibraryManager, { theme, compact: layout.compact, scope: "library", initialKind: "hooks", embedded: true });\n}\nfunction McpSettings({ theme, layout }) {\n return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(LibraryManager, { theme, compact: layout.compact, scope: "library", initialKind: "mcp", embedded: true });\n}\nfunction ProjectLibraryPanel({ theme, layout, workspaceId }) {\n const directory = (0, import_client3.useWorkspace)(workspaceId, (workspace) => workspace.directory || workspace.projectRootPath);\n if (!directory) return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native7.View, { style: { padding: 16 }, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native7.Text, { style: { color: theme.colors.foregroundMuted }, children: "This panel needs a workspace." }) });\n return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(LibraryManager, { theme, compact: layout.compact, scope: "project", directory });\n}\nfunction LibraryManager({ theme, compact, scope, directory, embedded = false, initialKind = "teams" }) {\n const list = (0, import_client3.useRpc)(libraryList);\n const get = (0, import_client3.useRpc)(libraryGet);\n const save = (0, import_client3.useRpc)(librarySave);\n const remove = (0, import_client3.useRpc)(libraryDelete);\n const duplicate = (0, import_client3.useRpc)(libraryDuplicate);\n const probe = (0, import_client3.useRpc)(libraryTest);\n const give = (0, import_client3.useRpc)(librarySkills);\n const readLanguage = (0, import_client3.useRpc)(languageGet);\n const writeLanguage = (0, import_client3.useRpc)(languageSet);\n const toast = (0, import_react_native6.useToast)();\n const [language, setLanguageState] = (0, import_react4.useState)(null);\n const [lists, setLists] = (0, import_react4.useState)({});\n const [where, setWhere] = (0, import_react4.useState)(null);\n const [error, setError] = (0, import_react4.useState)(null);\n const [selection, setSelection] = (0, import_react4.useState)({ kind: initialKind });\n const [entry, setEntry] = (0, import_react4.useState)(null);\n const [tick, setTick] = (0, import_react4.useState)(0);\n const refresh = (0, import_react4.useCallback)(() => setTick((value) => value + 1), []);\n const base = directory ? { directory } : {};\n (0, import_react4.useEffect)(() => {\n let live = true;\n Promise.all(KINDS.map(({ kind }) => list({ ...base, kind }).then((result) => [kind, result]))).then((results) => {\n if (!live) return;\n setLists(Object.fromEntries(results.map(([kind, result]) => [kind, result.entries])));\n setWhere({ projectRoot: results[0][1].projectRoot, library: results[0][1].library, ...results[0][1].readOnly ? { readOnly: results[0][1].readOnly } : {} });\n setError(null);\n }).catch((cause) => {\n if (live) setError(message(cause));\n });\n return () => {\n live = false;\n };\n }, [list, directory, tick]);\n (0, import_react4.useEffect)(() => {\n if (scope !== "library") return;\n let live = true;\n readLanguage({}).then((result) => {\n if (live) setLanguageState(result);\n }).catch((cause) => {\n if (live) setError(message(cause));\n });\n return () => {\n live = false;\n };\n }, [readLanguage, scope, tick]);\n (0, import_react4.useEffect)(() => {\n if (!selection.name || selection.creating) {\n setEntry(null);\n return;\n }\n let live = true;\n get({ ...base, kind: selection.kind, name: selection.name }).then((result) => {\n if (live) setEntry(result);\n }).catch((cause) => {\n if (live) {\n toast.error(message(cause));\n setSelection({ kind: selection.kind });\n }\n });\n return () => {\n live = false;\n };\n }, [selection, get, directory, tick]);\n const run = (0, import_react4.useCallback)((work, done) => __async(null, null, function* () {\n try {\n yield work();\n toast.show(done, { variant: "success" });\n refresh();\n return true;\n } catch (cause) {\n toast.error(message(cause));\n return false;\n }\n }), [toast, refresh]);\n const actions = {\n select: (next) => setSelection(next),\n duplicate: (kind, from, to) => run(() => duplicate({ ...base, kind, from, to, scope }), `Copied ${from} to ${to}`),\n // In the project panel: copy what applies into .alp/, or drop the project\'s copy.\n override: (kind, name) => run(() => duplicate({ ...base, kind, from: name, to: name, scope: "project" }), `${name} is now overridden in this project`),\n useLibrary: (kind, name) => run(() => remove({ ...base, kind, name, scope: "project" }), `${name} follows the library again`),\n save: (kind, name, content, revision, creating) => __async(null, null, function* () {\n try {\n const result = yield save({ ...base, kind, name, scope, content, revision });\n const synced = result.syncedProjects ?? 0;\n toast.show(`Saved ${name}${synced ? ` \\xB7 Updated settings in ${synced} project${synced === 1 ? "" : "s"}` : ""}`, { variant: "success" });\n if (result.syncErrors?.length) toast.error(`Template saved, but some project settings could not be updated: ${result.syncErrors.join("; ")}`);\n refresh();\n if (creating) setSelection({ kind, name });\n return true;\n } catch (cause) {\n toast.error(message(cause));\n return false;\n }\n }),\n giveSkills: (agent, skills) => run(() => give({ agent, skills }), `Saved the skills of ${agent}`),\n setLanguage: (next) => run(() => writeLanguage({ language: next }), next ? `Agents now write to you in ${next}` : "Agents write to you in the default language again"),\n remove: (kind, name, revision) => __async(null, null, function* () {\n const removed = yield run(() => remove({ ...base, kind, name, scope, ...revision ? { revision } : {} }), `Removed ${name}`);\n if (removed) setSelection({ kind });\n return removed;\n }),\n test: (kind, name) => __async(null, null, function* () {\n try {\n return yield probe({ ...base, kind, name });\n } catch (cause) {\n toast.error(message(cause));\n return null;\n }\n })\n };\n const shown = selection.name && !selection.creating && entry?.name !== selection.name ? { kind: selection.kind } : selection;\n return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(LibraryWorkspace, { theme, compact, scope, where, lists, error, selection: shown, entry: shown.name ? entry : null, actions, language, embedded });\n}\nfunction navGroups(scope, lists, readOnly = false) {\n const groups = scope === "library" ? [{ key: "General", label: "General", items: [{ key: "language", label: "Language", icon: "Languages" }] }] : [];\n for (const item of shownIn(scope)) {\n let group = groups.find((candidate) => candidate.label === item.group);\n if (!group) groups.push(group = { key: item.group, label: item.group, items: [] });\n const rows = lists[item.kind];\n group.items.push({\n key: item.kind,\n label: item.title,\n icon: item.icon,\n ...rows ? { count: rows.length } : {},\n // A read-only library\'s entries cannot be opened, so the aside lists kinds only.\n children: readOnly ? [] : (rows ?? []).map((row) => ({ key: row.name, label: row.name, tone: sourceTone(row.source) }))\n });\n }\n return groups;\n}\nfunction LibraryWorkspace({ theme, compact, scope, where, lists, error, selection, entry, actions, initialCollapsed, language, embedded }) {\n const styles = (0, import_react4.useMemo)(() => makeStyles2(theme, compact), [theme, compact]);\n const title = scope === "library" ? "ALP library" : "ALP project";\n const subtitle = scope === "library" ? where?.library : where?.projectRoot ?? void 0;\n const groups = navGroups(scope, lists, !!where?.readOnly);\n const onSelect = (kind2, name) => actions.select(kind2 === "language" ? { kind: kind2 } : { kind: kind2, ...name ? { name } : {} });\n if (scope === "project" && where?.readOnly?.unlisted) {\n return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native7.View, { style: styles.screen, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native7.Text, { style: styles.muted, children: where.readOnly.unlisted }) });\n }\n if (scope === "project" && where && !where.projectRoot) {\n return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native7.View, { style: styles.screen, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native7.Text, { style: styles.muted, children: "This workspace is not an ALP project. Run alp init to start one." }) });\n }\n if (selection.kind === "language") {\n return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(LanguageSettings, { theme, compact, language: language ?? null, error, actions, layout: { title, subtitle, groups, onSelect, initialCollapsed, embedded }, styles });\n }\n const kind = kindOf(selection.kind);\n if (selection.name || selection.creating) {\n return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(\n EntryEditor,\n {\n theme,\n compact,\n scope,\n kind: selection.kind,\n entry: selection.creating ? null : entry,\n lists,\n actions,\n layout: { title, subtitle, groups, onSelect, initialCollapsed, embedded }\n },\n `${selection.kind}/${selection.name ?? "new"}/${entry?.revision ?? "new"}/${(entry?.librarySkills ?? []).join(",")}`\n );\n }\n return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(KindOverview, { theme, compact, scope, kind: kind.kind, rows: lists[kind.kind], error, where, actions, layout: { title, subtitle, groups, onSelect, initialCollapsed, embedded }, styles });\n}\nvar OTHER = "other";\nfunction LanguageSettings({ theme, compact, language, error, actions, layout, styles }) {\n const named = language && LANGUAGES.some((option) => option.value === language.applies);\n const [choice, setChoice] = (0, import_react4.useState)(null);\n const [typed, setTyped] = (0, import_react4.useState)("");\n const shown = choice ?? (language ? named ? language.applies : OTHER : "");\n const typedValid = typed.trim().length > 0 && typed.trim().length <= 40;\n return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(\n SideNavLayout,\n {\n theme,\n compact,\n title: layout.title,\n subtitle: layout.subtitle,\n groups: layout.groups,\n active: { item: "language" },\n onSelect: layout.onSelect,\n initialCollapsed: layout.initialCollapsed,\n embedded: layout.embedded,\n breadcrumb: ["Library", "Language"],\n children: [\n /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native7.Text, { style: styles.muted, children: "The language you read. Main writes its replies, questions, approval requests and task titles in it, other agents put their questions to you in it, and ALP asks for approvals and writes its notices in it. Agents may talk among themselves in any language." }),\n error ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native7.Text, { style: styles.danger, children: error }) : null,\n !language && !error ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native7.Text, { style: styles.muted, children: "Loading\\u2026" }) : null,\n language?.readOnly ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_ui2.SettingsSection, { title: "Language", children: [\n /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react_native7.Text, { style: styles.name, children: [\n language.applies,\n language.language ? "" : " (default)"\n ] }),\n /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native7.Text, { style: styles.muted, children: language.readOnly })\n ] }) : !language ? null : /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_ui2.SettingsSection, { title: "Language", children: [\n /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(\n import_ui2.SettingsSelect,\n {\n label: "Language",\n hint: language.language ? `Set in your settings.json` : `Not set: ${language.default} applies`,\n value: shown,\n options: [...LANGUAGES, { label: named || !language.language ? "Other\\u2026" : `${language.applies} (other)`, value: OTHER }],\n onValueChange: (value) => __async(null, null, function* () {\n setChoice(value);\n if (value !== OTHER && (yield actions.setLanguage(value))) setChoice(null);\n })\n }\n ),\n shown === OTHER ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ui2.SettingsInput, { label: "Other language", hint: "Its name in English, such as Thai or Indonesian", initialValue: named ? "" : language.language ?? "", placeholder: "Thai", onChangeText: setTyped }) : null,\n shown === OTHER ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ui2.SettingsAction, { label: "Use this language", actionLabel: "Save", disabled: !typedValid, onPress: () => __async(null, null, function* () {\n if (typedValid && (yield actions.setLanguage(typed.trim()))) setChoice(null);\n }) }) : null,\n language.language ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ui2.SettingsAction, { label: `Use the default (${language.default})`, hint: "Removes the setting", actionLabel: "Reset", onPress: () => __async(null, null, function* () {\n if (yield actions.setLanguage(null)) setChoice(null);\n }) }) : null\n ] })\n ]\n }\n );\n}\nvar SOURCES = [{ key: "all", label: "All" }, { key: "builtin", label: "Built-in" }, { key: "library", label: "Library" }, { key: "project", label: "Project" }];\nfunction KindOverview({ theme, compact, scope, kind, rows, error, where, actions, layout, styles }) {\n const { title, one } = kindOf(kind);\n const [filter, setFilter] = (0, import_react4.useState)("all");\n const [copying, setCopying] = (0, import_react4.useState)(null);\n const [copyName, setCopyName] = (0, import_react4.useState)("");\n const tabs = SOURCES.map((source) => ({ ...source, count: (rows ?? []).filter((row) => source.key === "all" || row.source === source.key).length })).filter((tab) => tab.key === "all" || tab.count);\n const shown = (rows ?? []).filter((row) => filter === "all" || row.source === filter);\n const readOnly = where?.readOnly;\n const intro = readOnly ? `The ${title.toLowerCase()} ${scope === "project" ? "this project uses on the ALP host" : "of the ALP host"}, by name.` : kind === "providers" ? "Agents that speak the Agent Client Protocol. They live in your library only." : scope === "library" ? "Every project uses your library. Built-ins follow ALP updates; saving one makes your own copy of that name." : "What this project overrides. Override an entry to change it here only; Use library drops the project\'s copy.";\n return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(\n SideNavLayout,\n {\n theme,\n compact,\n title: layout.title,\n subtitle: layout.subtitle,\n groups: layout.groups,\n active: { item: kind },\n onSelect: layout.onSelect,\n initialCollapsed: layout.initialCollapsed,\n embedded: layout.embedded,\n breadcrumb: layout.embedded ? [] : [scope === "library" ? "Library" : "Project", title],\n tabs,\n tab: filter,\n onTab: setFilter,\n actions: readOnly ? null : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Button, { theme, kind: "primary", icon: "Plus", label: `New ${one}`, onPress: () => actions.select({ kind, creating: true }) }),\n children: [\n /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native7.Text, { style: styles.muted, children: intro }),\n readOnly ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native7.Text, { style: styles.muted, children: readOnly.reason }) : null,\n error ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native7.Text, { style: styles.danger, children: error }) : null,\n !rows && !error ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native7.Text, { style: styles.muted, children: "Loading\\u2026" }) : null,\n readOnly?.unlisted ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native7.View, { style: styles.empty, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native7.Text, { style: styles.muted, children: readOnly.unlisted }) }) : rows && !shown.length ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native7.View, { style: styles.empty, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react_native7.Text, { style: styles.muted, children: [\n "No ",\n title.toLowerCase(),\n " ",\n filter === "all" ? "yet" : `from the ${sourceLabel(filter)}`,\n "."\n ] }) }) : null,\n shown.length ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native7.View, { style: styles.table, children: shown.map((row, index) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react_native7.View, { style: [styles.tableRow, index ? styles.tableRowRule : null], children: [\n /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react_native7.Pressable, { accessibilityRole: readOnly ? void 0 : "button", accessibilityLabel: `${readOnly ? "" : "Open "}${one} ${row.name}`, disabled: !!readOnly, onPress: () => actions.select({ kind, name: row.name }), style: styles.rowMain, children: [\n /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react_native7.View, { style: styles.rowTitle, children: [\n /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native7.Text, { style: styles.name, children: row.name }),\n /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Pill, { theme, label: sourceLabel(row.source), tone: sourceTone(row.source) }),\n row.overrides ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Pill, { theme, label: `overrides ${sourceLabel(row.overrides)}` }) : null\n ] }),\n row.description ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native7.Text, { style: styles.muted, numberOfLines: 2, children: row.description }) : null,\n row.usedBy?.length ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react_native7.Text, { style: styles.small, numberOfLines: 1, children: [\n "Used by ",\n row.usedBy.join(", ")\n ] }) : null\n ] }),\n readOnly ? null : /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react_native7.View, { style: [styles.rowActions, compact ? styles.rowActionsCompact : null], children: [\n scope === "project" && row.source === "project" && row.overrides ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Button, { theme, label: "Use library", onPress: () => actions.useLibrary(kind, row.name) }) : null,\n scope === "project" && row.source !== "project" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Button, { theme, label: "Override in this project", onPress: () => actions.override(kind, row.name) }) : null,\n /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Button, { theme, icon: "Copy", label: "Duplicate", accessibilityLabel: `Duplicate ${one} ${row.name}`, onPress: () => {\n setCopying(row.name);\n setCopyName(`${row.name}-copy`);\n } })\n ] }),\n copying === row.name ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react_native7.View, { style: styles.copyRow, children: [\n /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native7.TextInput, { style: styles.input, value: copyName, onChangeText: setCopyName, accessibilityLabel: "Name of the copy", placeholder: "Name of the copy", placeholderTextColor: theme.colors.foregroundMuted }),\n /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Button, { theme, kind: "primary", label: "Copy", onPress: () => __async(null, null, function* () {\n if (NAME.test(copyName) && (yield actions.duplicate(kind, row.name, copyName))) setCopying(null);\n }) }),\n /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Button, { theme, label: "Cancel", onPress: () => setCopying(null) })\n ] }) : null\n ] }, row.name)) }) : null\n ]\n }\n );\n}\nfunction blank(kind, name = "new") {\n if (kind === "agents") return { instructions: `# ${name}\n\nDescribe what this agent does, and how.\n`, config: {} };\n if (kind === "skills") return { body: `---\nname: ${name}\ndescription: When to use this skill.\n---\n\n# ${name}\n\nSteps and checks.\n` };\n if (kind === "mcp") return { server: { command: "" } };\n if (kind === "hooks") return { hook: { event: "handoff", command: "", blocking: false } };\n if (kind === "providers") return { provider: { kind: "acp", label: name, command: "" } };\n return { team: { label: name, main: "main", members: { main: {} }, delegation: {}, supervisor: false }, houseRules: "" };\n}\nfunction entryTabs(kind, saved) {\n const tabs = {\n agents: [["general", "General"], ["instructions", "Instructions"], ["capabilities", "Skills, MCP & hooks"]],\n teams: [["models", "Models & effort"], ["general", "General"], ["members", "Members"], ["delegation", "Delegation"], ["supervisor", "Supervisor"], ["rules", "House rules"]],\n skills: [["body", "SKILL.md"]],\n mcp: [["server", "Server"], ["test", "Test"]],\n hooks: [["hook", "Hook"], ["test", "Test"]],\n providers: [["agent", "ACP agent"], ["test", "Test"]]\n };\n return tabs[kind].filter(([key]) => key !== "test" || saved).map(([key, label]) => ({ key, label }));\n}\nfunction EntryEditor({ theme, compact, scope, kind, entry, lists, actions, layout, initialTab }) {\n const styles = (0, import_react4.useMemo)(() => makeStyles2(theme, compact), [theme, compact]);\n const { one, title } = kindOf(kind);\n const tabs = entryTabs(kind, !!entry);\n const [tab, setTab] = (0, import_react4.useState)(initialTab && tabs.some((candidate) => candidate.key === initialTab) ? initialTab : tabs[0].key);\n const [name, setName] = (0, import_react4.useState)(entry?.name ?? "");\n const original = (0, import_react4.useMemo)(() => clone2(entry?.content ?? blank(kind)), [entry, kind]);\n const [content, setContent] = (0, import_react4.useState)(() => clone2(original));\n const [result, setResult] = (0, import_react4.useState)(null);\n const own = entry?.source === scope;\n const update = (change) => setContent((current) => {\n const draft = clone2(current);\n change(draft);\n return draft;\n });\n const valid = NAME.test(name);\n const changed = !entry || JSON.stringify(content) !== JSON.stringify(original);\n const givenOriginal = (0, import_react4.useMemo)(() => entry?.librarySkills ?? [], [entry]);\n const [given, setGiven] = (0, import_react4.useState)(givenOriginal);\n const givesSkills = kind === "agents" && scope === "library";\n const givenChanged = givesSkills && [...given].sort().join() !== [...givenOriginal].sort().join();\n const dirty = changed || givenChanged;\n const onSave = () => __async(null, null, function* () {\n if (!valid) return;\n if (changed && !(yield actions.save(kind, name, content, own ? entry.revision : null, !entry))) return;\n if (givenChanged) yield actions.giveSkills(name, given);\n });\n const note = entry ? entry.source === "builtin" ? `Built into ALP. Saving makes ${scope === "library" ? "your library\'s" : "this project\'s"} own ${entry.name}, which overrides it.` : own ? `In ${scope === "library" ? "your library" : "this project"}${entry.overrides ? `; overrides the ${sourceLabel(entry.overrides)} one` : ""}.` : `From the ${sourceLabel(entry.source)}. Saving makes this project\'s own copy.` : null;\n const form = { content, update, lists, styles, theme };\n return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(\n SideNavLayout,\n {\n theme,\n compact,\n title: layout.title,\n subtitle: layout.subtitle,\n groups: layout.groups,\n active: { item: kind, ...entry ? { child: entry.name } : {} },\n onSelect: layout.onSelect,\n initialCollapsed: layout.initialCollapsed,\n embedded: layout.embedded,\n breadcrumb: [title, entry ? entry.name : `New ${one}`],\n badges: entry ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [\n /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Pill, { theme, label: sourceLabel(entry.source), tone: sourceTone(entry.source) }),\n entry.overrides ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Pill, { theme, label: `overrides ${sourceLabel(entry.overrides)}` }) : null\n ] }) : null,\n actions: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Button, { theme, icon: "ArrowLeft", label: `All ${title.toLowerCase()}`, onPress: () => actions.select({ kind }) }),\n tabs,\n tab,\n onTab: setTab,\n footer: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [\n /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Button, { theme, kind: "primary", label: entry && entry.source === "builtin" && (changed || !givenChanged) ? "Save as my own" : "Save", disabled: !valid || !dirty, onPress: () => {\n void onSave();\n } }),\n /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native7.Text, { style: styles.small, children: !valid ? "Name the entry first" : dirty ? "Unsaved changes" : own ? "Saved" : "No changes" }),\n /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native7.View, { style: { flex: 1 } }),\n entry && own ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Button, { theme, kind: "danger", label: entry.overrides ? `Remove (the ${sourceLabel(entry.overrides)} one applies again)` : "Remove", onPress: () => actions.remove(kind, entry.name, entry.revision) }) : null\n ] }),\n children: [\n note || entry?.usedBy.length ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react_native7.View, { style: styles.banner, children: [\n note ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native7.Text, { style: styles.bannerText, children: note }) : null,\n entry?.usedBy.length ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react_native7.Text, { style: styles.small, children: [\n "Used by ",\n entry.usedBy.join(", "),\n "."\n ] }) : null\n ] }) : null,\n !entry && tab === tabs[0].key ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ui2.SettingsSection, { title: "Name", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ui2.SettingsInput, { label: "Name", hint: "Letters, digits, \'.\', \'_\' or \'-\'", error: name && !valid ? "Not a valid name" : null, initialValue: name, onChangeText: setName }) }) : null,\n kind === "agents" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(AgentForm, { ...form, tab, given: entry?.librarySkills ?? [], ...givesSkills ? { draftGiven: given, setGiven } : {} }) : null,\n kind === "teams" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(TeamForm, { ...form, tab }) : null,\n kind === "skills" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Multiline, { value: content.body ?? "", onChange: (text) => update((draft) => {\n draft.body = text;\n }), styles, theme, label: "SKILL.md", tall: true }) : null,\n kind === "mcp" && tab === "server" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(McpForm, { content, update }) : null,\n kind === "hooks" && tab === "hook" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(HookForm, { content, update, lists }) : null,\n kind === "providers" && tab === "agent" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ProviderForm, { content, update }) : null,\n tab === "test" && entry ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_ui2.SettingsSection, { title: "Test", children: [\n /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ui2.SettingsAction, { label: kind === "mcp" ? "Start the server and list its tools" : kind === "providers" ? "Start the agent and ask what it supports" : "Run once with a sample event", hint: "The test runs what is saved.", actionLabel: "Test", onPress: () => __async(null, null, function* () {\n return setResult(yield actions.test(kind, entry.name));\n }) }),\n result ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(TestResult, { kind, result, styles }) : null\n ] }) : null\n ]\n }\n );\n}\nvar names = (lists, kind) => (lists[kind] ?? []).map((row) => row.name);\nvar toggle = (list, name, on) => {\n const set = new Set(list ?? []);\n if (on) set.add(name);\n else set.delete(name);\n return [...set];\n};\nvar setOrDelete = (target, key, value) => {\n if (value === "" || value === void 0 || Array.isArray(value) && !value.length) delete target[key];\n else target[key] = value;\n};\nvar CONTEXT_SIZES = [2e5, 4e5, 6e5, 1e6];\nvar contextOptions = (current) => [\n { label: "Auto (the model\'s)", value: "" },\n ...[.../* @__PURE__ */ new Set([...CONTEXT_SIZES, ...typeof current === "number" ? [current] : []])].sort((a, b) => a - b).map((tokens) => ({ label: tokens >= 1e6 ? `${tokens / 1e6}M tokens` : `${Math.round(tokens / 1e3)}k tokens`, value: String(tokens) }))\n];\nfunction AgentForm({ content, update, lists, styles, theme, tab, given = [], draftGiven, setGiven }) {\n const config = content.config ?? {};\n const field = (key) => (text) => update((draft) => {\n draft.config ?? (draft.config = {});\n setOrDelete(draft.config, key, text.trim());\n });\n const show = (key) => !tab || tab === key;\n return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [\n show("general") ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_ui2.SettingsSection, { title: "Agent", children: [\n /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ui2.SettingsInput, { label: "Description", initialValue: config.description ?? "", onChangeText: field("description") }),\n /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ui2.SettingsSelect, { label: "Provider", hint: "The team or project settings may choose another", value: config.provider ?? "", options: [{ label: "Default", value: "" }, { label: "Codex", value: "codex" }, { label: "Claude Code", value: "claude" }, ...names(lists, "providers").map((provider) => ({ label: `${provider} (ACP)`, value: provider }))], onValueChange: field("provider") }),\n /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ui2.SettingsInput, { label: "Model", hint: "Such as claude:claude-sonnet-5-5, codex:gpt-6-sol or acp:gemini", initialValue: config.model ?? "", onChangeText: field("model") }),\n /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ui2.SettingsInput, { label: "Thinking", hint: "Effort, such as low, medium or high", initialValue: config.thinking ?? "", onChangeText: field("thinking") }),\n /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(\n import_ui2.SettingsSelect,\n {\n label: "Context",\n hint: "How much context it works with before the runtime compacts it",\n value: typeof config.context === "number" ? String(config.context) : "",\n options: contextOptions(config.context),\n onValueChange: (value) => update((draft) => {\n draft.config ?? (draft.config = {});\n setOrDelete(draft.config, "context", value ? Number(value) : "");\n })\n }\n ),\n /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ui2.SettingsSelect, { label: "Default mode", value: config.mode ?? "", options: MODES.map((mode) => ({ label: mode || "As its requester chooses", value: mode })), onValueChange: field("mode") })\n ] }) : null,\n show("instructions") ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Multiline, { value: content.instructions ?? "", onChange: (text) => update((draft) => {\n draft.instructions = text;\n }), styles, theme, label: "AGENT.md", tall: true }) : null,\n show("capabilities") ? ["skills", "mcp", "hooks"].map((kind) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_ui2.SettingsSection, { title: kindOf(kind).title, children: [\n !names(lists, kind).length ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ui2.SettingsRow, { label: `No ${kindOf(kind).title.toLowerCase()} to choose from yet` }) : null,\n names(lists, kind).map((name) => {\n const own = (config[kind] ?? []).includes(name);\n const configToggle = (on) => update((draft) => {\n draft.config ?? (draft.config = {});\n setOrDelete(draft.config, kind, toggle(draft.config[kind], name, on));\n });\n if (kind !== "skills") return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ui2.SettingsSwitch, { label: name, value: own, onValueChange: configToggle }, name);\n if (setGiven) {\n const library = (draftGiven ?? given).includes(name);\n return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(\n import_ui2.SettingsSwitch,\n {\n label: name,\n hint: given.includes(name) ? "Default for this agent" : void 0,\n value: library || own,\n onValueChange: (on) => {\n setGiven(toggle(draftGiven ?? given, name, on));\n if (!on && own) configToggle(false);\n }\n },\n name\n );\n }\n if (given.includes(name)) return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ui2.SettingsSwitch, { label: name, hint: "Given by your library; change it in Settings \\u2192 ALP", value: true, disabled: true, onValueChange: () => {\n } }, name);\n return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ui2.SettingsSwitch, { label: name, value: own, onValueChange: configToggle }, name);\n })\n ] }, kind)) : null\n ] });\n}\nfunction withMember(team, agent, on) {\n const next = clone2(team);\n next.members ?? (next.members = {});\n next.delegation ?? (next.delegation = {});\n if (on) {\n next.members[agent] = { role: "peer" };\n return next;\n }\n delete next.members[agent];\n delete next.delegation[agent];\n for (const owner of Object.keys(next.delegation)) {\n next.delegation[owner] = next.delegation[owner].filter((target) => target !== agent);\n if (!next.delegation[owner].length) delete next.delegation[owner];\n }\n return next;\n}\nfunction withDelegation(team, owner, target, on) {\n const next = clone2(team);\n next.delegation ?? (next.delegation = {});\n const targets = toggle(next.delegation[owner], target, on);\n if (targets.length) next.delegation[owner] = targets;\n else delete next.delegation[owner];\n return next;\n}\nvar EFFORTS = ["", "none", "low", "medium", "high", "xhigh", "max"];\nvar effortOptions = EFFORTS.map((value) => ({ label: value || "Inherit", value }));\nfunction TeamModels({ content, update, theme }) {\n return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(TeamModelSettings, { team: content.team ?? {}, theme, onChange: (next) => update((draft) => {\n draft.team = next;\n }) });\n}\nfunction TeamForm({ content, update, lists, styles, theme, tab }) {\n const show = (key) => !tab || tab === key;\n const team = content.team ?? {};\n const agents = names(lists, "agents");\n const members = Object.keys(team.members ?? {});\n const others = members.filter((member) => member !== team.main);\n const cycle = delegationCycle(team.delegation ?? {});\n const text = (key) => (value) => update((draft) => {\n setOrDelete(draft.team, key, value.trim());\n });\n return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [\n show("models") ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(TeamModels, { content, update, lists, styles, theme }) : null,\n show("general") ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_ui2.SettingsSection, { title: "Team", children: [\n /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ui2.SettingsInput, { label: "Label", hint: "Shown in the model picker", initialValue: team.label ?? "", onChangeText: text("label") }),\n /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ui2.SettingsInput, { label: "Description", initialValue: team.description ?? "", onChangeText: text("description") }),\n /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ui2.SettingsInput, { label: "Most peers at once", initialValue: team.maxPeers === void 0 ? "" : String(team.maxPeers), onChangeText: (value) => update((draft) => {\n setOrDelete(draft.team, "maxPeers", value.trim() ? Number(value) : "");\n }) })\n ] }) : null,\n show("members") ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_jsx_runtime4.Fragment, { children: [team.main, ...agents.filter((agent) => agent !== team.main && agent !== team.supervisor?.agent)].filter(Boolean).map((agent) => {\n const member = team.members?.[agent];\n const main = agent === team.main;\n return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_ui2.SettingsSection, { title: main ? `${agent} \\xB7 main` : agent, info: main ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native7.Text, { style: styles.small, children: "The agent you talk with." }) : void 0, children: [\n !main ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ui2.SettingsSwitch, { label: "In this team", value: !!member, onValueChange: (on) => update((draft) => {\n draft.team = withMember(draft.team, agent, on);\n }) }) : null,\n member && !main ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ui2.SettingsSelect, { label: "Role", value: member.role ?? "peer", options: ROLES.map((role) => ({ label: role, value: role })), onValueChange: (role) => update((draft) => {\n draft.team.members[agent].role = role;\n }) }) : null\n ] }, agent);\n }) }) : null,\n show("delegation") ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [\n cycle ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react_native7.Text, { style: styles.danger, children: [\n "Cycle at ",\n cycle,\n ": ALP refuses it"\n ] }) : null,\n members.map((owner) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_ui2.SettingsSection, { title: `${owner} may delegate to`, info: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native7.Text, { style: styles.small, children: (team.delegation?.[owner] ?? []).join(", ") || "no one" }), children: [\n others.filter((target) => target !== owner).map((target) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ui2.SettingsSwitch, { label: target, value: (team.delegation?.[owner] ?? []).includes(target), onValueChange: (on) => update((draft) => {\n draft.team = withDelegation(draft.team, owner, target, on);\n }) }, `${owner}-${target}`)),\n !others.filter((target) => target !== owner).length ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ui2.SettingsRow, { label: "No other members" }) : null\n ] }, owner))\n ] }) : null,\n show("supervisor") ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_ui2.SettingsSection, { title: "Supervisor", children: [\n /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ui2.SettingsSwitch, { label: "Review main\'s process after each turn", value: !!team.supervisor, onValueChange: (on) => update((draft) => {\n draft.team.supervisor = on ? { agent: "supervisor" } : false;\n }) }),\n team.supervisor ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [\n /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ui2.SettingsSelect, { label: "Supervisor agent", value: team.supervisor.agent, options: agents.filter((agent) => !members.includes(agent)).map((agent) => ({ label: agent, value: agent })), onValueChange: (agent) => update((draft) => {\n draft.team.supervisor.agent = agent;\n }) }),\n /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ui2.SettingsRow, { label: "Model & effort", hint: "Configure in Models & effort" })\n ] }) : null\n ] }) : null,\n show("rules") ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Multiline, { value: content.houseRules ?? "", onChange: (value) => update((draft) => {\n draft.houseRules = value;\n }), styles, theme, label: "House rules", placeholder: "The team\'s rules and process, which every member reads (HOUSE_RULES.md)", tall: true }) : null\n ] });\n}\nfunction delegationCycle(graph) {\n const visiting = /* @__PURE__ */ new Set();\n const done = /* @__PURE__ */ new Set();\n const visit = (owner) => {\n if (visiting.has(owner)) return owner;\n if (done.has(owner)) return null;\n visiting.add(owner);\n for (const target of graph[owner] ?? []) {\n const found = visit(target);\n if (found) return found;\n }\n visiting.delete(owner);\n done.add(owner);\n return null;\n };\n for (const owner of Object.keys(graph)) {\n const found = visit(owner);\n if (found) return found;\n }\n return null;\n}\nvar lines = (text) => text.split("\\n").map((line) => line.trim()).filter(Boolean);\nvar pairs = (text) => Object.fromEntries(lines(text).filter((line) => line.includes("=")).map((line) => [line.slice(0, line.indexOf("=")).trim(), line.slice(line.indexOf("=") + 1).trim()]));\nvar unpairs = (map) => Object.entries(map ?? {}).map(([key, value]) => `${key}=${value}`).join("\\n");\nfunction McpForm({ content, update }) {\n const server = content.server ?? {};\n const http = server.url !== void 0;\n const set = (key, value) => update((draft) => {\n setOrDelete(draft.server, key, value);\n });\n return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_ui2.SettingsSection, { title: "Server", children: [\n /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ui2.SettingsSelect, { label: "Transport", value: http ? "http" : "stdio", options: [{ label: "Command (stdio)", value: "stdio" }, { label: "URL (HTTP)", value: "http" }], onValueChange: (kind) => update((draft) => {\n draft.server = kind === "http" ? { url: "" } : { command: "" };\n }) }),\n http ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [\n /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ui2.SettingsInput, { label: "URL", initialValue: server.url ?? "", onChangeText: (value) => update((draft) => {\n draft.server.url = value.trim();\n }) }),\n /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ui2.SettingsInput, { label: "Headers", hint: "Name=value, separated by \';\'", initialValue: unpairs(server.headers).replaceAll("\\n", "; "), onChangeText: (value) => set("headers", Object.keys(pairs(value.replaceAll(";", "\\n"))).length ? pairs(value.replaceAll(";", "\\n")) : void 0) })\n ] }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [\n /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ui2.SettingsInput, { label: "Command", initialValue: server.command ?? "", onChangeText: (value) => update((draft) => {\n draft.server.command = value.trim();\n }) }),\n /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ui2.SettingsInput, { label: "Arguments", hint: "Separated by spaces", initialValue: (server.args ?? []).join(" "), onChangeText: (value) => set("args", value.split(/\\s+/).filter(Boolean)) }),\n /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ui2.SettingsInput, { label: "Environment", hint: "NAME=value, separated by \';\'", initialValue: unpairs(server.env).replaceAll("\\n", "; "), onChangeText: (value) => set("env", Object.keys(pairs(value.replaceAll(";", "\\n"))).length ? pairs(value.replaceAll(";", "\\n")) : void 0) }),\n /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ui2.SettingsInput, { label: "Working directory", hint: "Relative to the mcp directory", initialValue: server.cwd ?? "", onChangeText: (value) => set("cwd", value.trim()) })\n ] })\n ] });\n}\nfunction ProviderForm({ content, update }) {\n const provider = content.provider ?? {};\n const set = (key, value) => update((draft) => {\n draft.provider ?? (draft.provider = { kind: "acp" });\n setOrDelete(draft.provider, key, value);\n });\n return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_ui2.SettingsSection, { title: "ACP agent", info: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native7.Text, { children: "Any agent that speaks the Agent Client Protocol on stdio. ALP answers its permission requests by the session\'s mode; it cannot steer it mid-turn or sandbox its commands." }), children: [\n /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ui2.SettingsInput, { label: "Label", initialValue: provider.label ?? "", onChangeText: (value) => set("label", value.trim()) }),\n /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ui2.SettingsInput, { label: "Description", initialValue: provider.description ?? "", onChangeText: (value) => set("description", value.trim()) }),\n /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ui2.SettingsInput, { label: "Command", hint: "Such as gemini, or an absolute path", initialValue: provider.command ?? "", onChangeText: (value) => update((draft) => {\n draft.provider.command = value.trim();\n }) }),\n /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ui2.SettingsInput, { label: "Arguments", hint: "Separated by spaces, such as --experimental-acp", initialValue: (provider.args ?? []).join(" "), onChangeText: (value) => set("args", value.split(/\\s+/).filter(Boolean)) }),\n /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ui2.SettingsInput, { label: "Environment", hint: "NAME=value, separated by \';\'", initialValue: unpairs(provider.env).replaceAll("\\n", "; "), onChangeText: (value) => set("env", Object.keys(pairs(value.replaceAll(";", "\\n"))).length ? pairs(value.replaceAll(";", "\\n")) : void 0) }),\n /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ui2.SettingsInput, { label: "Models", hint: "Ids the agent offers, separated by \',\'; empty lets any through", initialValue: (provider.models ?? []).map((model) => model.id).join(", "), onChangeText: (value) => set("models", value.split(",").map((id) => id.trim()).filter(Boolean).map((id) => (provider.models ?? []).find((model) => model.id === id) ?? { id })) })\n ] });\n}\nfunction HookForm({ content, update, lists }) {\n const hook = content.hook ?? {};\n const set = (key, value) => update((draft) => {\n setOrDelete(draft.hook, key, value);\n });\n const blocking = BLOCKING_EVENTS.includes(hook.event);\n return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_ui2.SettingsSection, { title: "Hook", children: [\n /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ui2.SettingsSelect, { label: "Event", value: hook.event ?? "handoff", options: HOOK_EVENTS.map((event) => ({ label: event, value: event })), onValueChange: (event) => update((draft) => {\n draft.hook.event = event;\n if (!BLOCKING_EVENTS.includes(event)) delete draft.hook.blocking;\n }) }),\n /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ui2.SettingsInput, { label: "Command", hint: "Runs in the session\'s directory; the event arrives as JSON on stdin", initialValue: hook.command ?? "", onChangeText: (value) => update((draft) => {\n draft.hook.command = value;\n }) }),\n blocking ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ui2.SettingsSwitch, { label: "Block the action when it fails", hint: "Its stderr becomes the reason the agent reads", value: !!hook.blocking, onValueChange: (on) => set("blocking", on || void 0) }) : null,\n /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ui2.SettingsInput, { label: "Timeout (seconds)", initialValue: hook.timeoutSec === void 0 ? "" : String(hook.timeoutSec), onChangeText: (value) => set("timeoutSec", value.trim() ? Number(value) : "") }),\n /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ui2.SettingsSelect, { label: "Only for agent", value: hook.match?.agent ?? "", options: [{ label: "Every agent", value: "" }, ...names(lists, "agents").map((agent) => ({ label: agent, value: agent }))], onValueChange: (agent) => update((draft) => {\n var _a;\n (_a = draft.hook).match ?? (_a.match = {});\n setOrDelete(draft.hook.match, "agent", agent);\n if (!Object.keys(draft.hook.match).length) delete draft.hook.match;\n }) }),\n /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ui2.SettingsInput, { label: "Only for tasks labeled", initialValue: hook.match?.label ?? "", onChangeText: (label) => update((draft) => {\n var _a;\n (_a = draft.hook).match ?? (_a.match = {});\n setOrDelete(draft.hook.match, "label", label.trim());\n if (!Object.keys(draft.hook.match).length) delete draft.hook.match;\n }) })\n ] });\n}\nfunction TestResult({ kind, result, styles }) {\n if (kind === "providers") {\n return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react_native7.View, { children: [\n /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react_native7.Text, { style: styles.success, children: [\n result.agent?.title ?? result.agent?.name ?? "The agent",\n result.agent?.version ? ` ${result.agent.version}` : "",\n " speaks ACP ",\n result.protocolVersion\n ] }),\n /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react_native7.Text, { style: styles.muted, children: [\n result.loadSession ? "Resumes sessions" : "Cannot resume sessions",\n result.mcpHttp ? "; takes HTTP MCP servers" : "; takes stdio MCP servers only",\n result.authMethods?.length ? `; signs in with ${result.authMethods.join(", ")}` : ""\n ] })\n ] });\n }\n if (kind === "mcp") {\n return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react_native7.View, { children: [\n /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react_native7.Text, { style: styles.success, children: [\n result.server?.name ?? "The server",\n result.server?.version ? ` ${result.server.version}` : "",\n " offers ",\n result.tools?.length ?? 0,\n " tools"\n ] }),\n (result.tools ?? []).map((tool) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react_native7.Text, { style: styles.muted, children: [\n tool.name,\n tool.description ? ` \\u2014 ${tool.description.split("\\n")[0]}` : ""\n ] }, tool.name))\n ] });\n }\n return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react_native7.View, { children: [\n /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react_native7.Text, { style: result.ok ? styles.success : styles.danger, children: [\n result.timedOut ? "Timed out" : `Exit ${result.exitCode ?? result.signal}`,\n " in ",\n result.durationMs,\n " ms",\n result.wouldBlock ? "; as a blocking hook it would refuse the action" : ""\n ] }),\n result.stdout ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native7.Text, { style: styles.code, children: result.stdout }) : null,\n result.stderr ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native7.Text, { style: styles.code, children: result.stderr }) : null\n ] });\n}\nfunction Multiline({ value, onChange, styles, theme, label, placeholder, tall }) {\n return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native7.TextInput, { style: [styles.multiline, tall ? styles.tall : null], value, onChangeText: onChange, multiline: true, accessibilityLabel: label, placeholder: placeholder ?? label, placeholderTextColor: theme.colors.foregroundMuted });\n}\nfunction makeStyles2(theme, compact) {\n const { colors } = theme;\n return {\n screen: { flex: 1, backgroundColor: colors.surface0, padding: compact ? 12 : 20 },\n muted: { color: colors.foregroundMuted, fontSize: 13, lineHeight: 19 },\n small: { color: colors.foregroundMuted, fontSize: 12 },\n danger: { color: colors.statusDanger, fontSize: 13 },\n success: { color: colors.statusSuccess, fontSize: 13 },\n name: { color: colors.foreground, fontSize: 14, fontWeight: "600" },\n empty: { borderWidth: 1, borderStyle: "dashed", borderColor: colors.border, borderRadius: 10, padding: 24, alignItems: "center" },\n table: { borderWidth: 1, borderColor: colors.border, borderRadius: 10, backgroundColor: colors.surface1, overflow: "hidden" },\n tableRow: { flexDirection: compact ? "column" : "row", flexWrap: "wrap", alignItems: compact ? "stretch" : "center", gap: 10, paddingHorizontal: 14, paddingVertical: 12 },\n tableRowRule: { borderTopWidth: 1, borderTopColor: colors.border },\n rowMain: { flex: 1, minWidth: 0, gap: 3 },\n rowTitle: { flexDirection: "row", alignItems: "center", gap: 8, flexWrap: "wrap" },\n rowActions: { flexDirection: "row", gap: 8, alignItems: "center" },\n rowActionsCompact: { flexWrap: "wrap" },\n copyRow: { flexBasis: "100%", flexDirection: "row", gap: 8, alignItems: "center" },\n input: { flex: 1, color: colors.foreground, borderWidth: 1, borderColor: colors.border, borderRadius: 8, paddingHorizontal: 10, paddingVertical: 7, backgroundColor: colors.surface0 },\n banner: { borderRadius: 10, backgroundColor: colors.surface1, borderWidth: 1, borderColor: colors.border, paddingHorizontal: 14, paddingVertical: 10, gap: 4 },\n bannerText: { color: colors.foreground, fontSize: 13 },\n multiline: { minHeight: 160, color: colors.foreground, borderWidth: 1, borderColor: colors.border, borderRadius: 10, padding: 12, fontFamily: "monospace", fontSize: 13, lineHeight: 19, backgroundColor: colors.surface1, textAlignVertical: "top" },\n tall: { minHeight: 420 },\n code: { color: colors.foreground, fontFamily: "monospace", fontSize: 12 }\n };\n}\n\n// integrations/paseo/client/usage.tsx\nvar import_client4 = require("@getpaseo/plugin/client");\nvar import_react_native8 = require("@getpaseo/plugin/client/react-native");\nvar import_react5 = require("react");\nvar import_react_native9 = require("react-native");\n\n// integrations/paseo/shared/usage.ts\nvar import_plugin3 = require("@getpaseo/plugin");\nvar import_zod3 = require("zod");\nvar Pause = import_zod3.z.object({ reason: import_zod3.z.string(), since: import_zod3.z.string(), resetsAt: import_zod3.z.string().optional() });\nvar usageGet = (0, import_plugin3.defineRpc)({\n name: "alp.usage.get",\n input: import_zod3.z.object({ refresh: import_zod3.z.boolean().optional() }),\n output: import_zod3.z.object({\n providers: import_zod3.z.array(import_zod3.z.object({\n runtime: import_zod3.z.enum(["codex", "claude"]),\n available: import_zod3.z.boolean(),\n checkedAt: import_zod3.z.string(),\n plan: import_zod3.z.string().nullable(),\n limited: import_zod3.z.boolean(),\n windows: import_zod3.z.array(import_zod3.z.object({ name: import_zod3.z.string(), usedPercent: import_zod3.z.number().nullable(), resetsAt: import_zod3.z.string().nullable() })),\n pause: Pause.nullable(),\n parked: import_zod3.z.number()\n }))\n })\n});\n\n// integrations/paseo/client/usage.tsx\nvar import_jsx_runtime5 = require("react/jsx-runtime");\nfunction UsageScreen({ theme, layout }) {\n const read = (0, import_client4.useRpc)(usageGet);\n const [data, setData] = (0, import_react5.useState)(null);\n const [error, setError] = (0, import_react5.useState)(null);\n const [loading, setLoading] = (0, import_react5.useState)(true);\n const [tick, setTick] = (0, import_react5.useState)(0);\n const forceRefresh = (0, import_react5.useRef)(false);\n (0, import_react5.useEffect)(() => {\n let live = true;\n setLoading(true);\n const refresh = forceRefresh.current;\n forceRefresh.current = false;\n read({ refresh }).then((result) => {\n if (live) {\n setData(result);\n setError(null);\n }\n }).catch((cause) => {\n if (live) setError(cause instanceof Error ? cause.message : String(cause));\n }).finally(() => {\n if (live) setLoading(false);\n });\n return () => {\n live = false;\n };\n }, [read, tick]);\n (0, import_react5.useEffect)(() => {\n const timer = setInterval(() => setTick((value) => value + 1), 6e4);\n return () => clearInterval(timer);\n }, []);\n return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(UsageView, { theme, compact: layout.compact, data, loading, error, onRefresh: () => {\n forceRefresh.current = true;\n setTick((value) => value + 1);\n } });\n}\nfunction dateLabel(value) {\n const date = new Date(value);\n return Number.isFinite(date.getTime()) ? date.toLocaleString(void 0, { month: "short", day: "numeric", hour: "numeric", minute: "2-digit" }) : "Unknown";\n}\nfunction resetLabel(value, now) {\n if (!value) return "Reset time unavailable";\n const minutes = Math.ceil((Date.parse(value) - now) / 6e4);\n if (minutes <= 0) return "Reset time passed \\xB7 awaiting provider update";\n const duration = minutes >= 1440 ? `${Math.floor(minutes / 1440)}d ${Math.floor(minutes % 1440 / 60)}h` : minutes >= 60 ? `${Math.floor(minutes / 60)}h ${minutes % 60}m` : `${minutes}m`;\n return `Resets in ${duration} \\xB7 ${dateLabel(value)}`;\n}\nfunction UsageView({ theme, compact, data, loading, error, onRefresh, now = Date.now() }) {\n const { colors } = theme;\n const muted = { color: colors.foregroundMuted, fontSize: 13, lineHeight: 20 };\n const providers = data?.providers ?? [];\n const parked = providers.reduce((sum, provider) => sum + provider.parked, 0);\n return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react_native8.ScrollView, { contentContainerStyle: { padding: compact ? 16 : 28, gap: 24 }, children: [\n /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react_native9.View, { style: { gap: 8 }, children: [\n /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react_native9.View, { style: { flexDirection: "row", alignItems: "center", justifyContent: "space-between", gap: 12 }, children: [\n /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native9.Text, { accessibilityRole: "header", style: { color: colors.foreground, fontSize: 28, fontWeight: "600", letterSpacing: -0.7 }, children: "Usage" }),\n /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Button, { theme, label: loading ? "Refreshing\\u2026" : "Refresh", icon: "RefreshCw", disabled: loading, onPress: onRefresh, accessibilityLabel: "Refresh usage" })\n ] }),\n /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native9.Text, { style: muted, children: "Your provider limits, reset windows and paused work in one place." })\n ] }),\n error ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react_native9.View, { accessibilityRole: "alert", style: { padding: 14, borderWidth: 1, borderColor: colors.statusDanger, borderRadius: 10, gap: 4 }, children: [\n /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native9.Text, { style: { color: colors.statusDanger, fontWeight: "600" }, children: "Could not refresh usage" }),\n /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native9.Text, { style: muted, children: error }),\n data ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native9.Text, { style: muted, children: "Showing the last received data." }) : null\n ] }) : null,\n parked > 0 ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react_native9.View, { style: { padding: 14, backgroundColor: colors.surface1, borderLeftWidth: 3, borderLeftColor: colors.statusWarning, gap: 4 }, children: [\n /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react_native9.Text, { style: { color: colors.foreground, fontWeight: "600" }, children: [\n parked,\n " ",\n parked === 1 ? "assignment waiting" : "assignments waiting"\n ] }),\n /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native9.Text, { style: muted, children: "Parked work stays saved while its runtime is paused." })\n ] }) : null,\n !data && loading ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native9.Text, { accessibilityLiveRegion: "polite", style: muted, children: "Checking Codex and Claude usage\\u2026" }) : null,\n /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native9.View, { style: { flexDirection: compact ? "column" : "row", flexWrap: "wrap", gap: 16 }, children: providers.map((provider) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ProviderCard, { theme, provider, compact, now }, provider.runtime)) }),\n /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react_native9.View, { style: { borderTopWidth: 1, borderTopColor: colors.border, paddingTop: 16, gap: 4 }, children: [\n /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native9.Text, { style: muted, children: "Account limits reported by each provider, shared with usage outside ALP." }),\n /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native9.Text, { style: { ...muted, fontSize: 12 }, children: "Updates every minute while this screen is open. Readings are cached for up to 30 seconds. This is not a billing or token-spend report." })\n ] })\n ] });\n}\nfunction ProviderCard({ theme, provider, compact, now }) {\n const { colors } = theme;\n const status = provider.pause ? "Paused" : !provider.available ? "Unavailable" : provider.limited ? "Limit reached" : "Available";\n const tone = provider.pause || provider.limited ? "warning" : provider.available ? "success" : "muted";\n const muted = { color: colors.foregroundMuted, fontSize: 12, lineHeight: 18 };\n return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react_native9.View, { style: { flexGrow: 1, flexBasis: compact ? "auto" : 320, width: compact ? "100%" : void 0, minWidth: 0, padding: 20, backgroundColor: colors.surface1, borderWidth: 1, borderColor: colors.border, borderRadius: 14, gap: 20 }, children: [\n /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react_native9.View, { style: { flexDirection: "row", justifyContent: "space-between", alignItems: "center", gap: 12 }, children: [\n /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react_native9.View, { style: { gap: 4 }, children: [\n /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native9.Text, { accessibilityRole: "header", style: { color: colors.foreground, fontSize: 20, fontWeight: "600" }, children: provider.runtime === "codex" ? "Codex" : "Claude" }),\n /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native9.Text, { style: muted, children: provider.plan ? `${provider.plan} plan` : "Plan not reported" })\n ] }),\n /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Pill, { theme, label: status, tone })\n ] }),\n provider.pause ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react_native9.View, { style: { gap: 5 }, children: [\n /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native9.Text, { style: { color: colors.statusWarning, fontSize: 13 }, children: provider.pause.reason }),\n provider.pause.resetsAt ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native9.Text, { style: muted, children: resetLabel(provider.pause.resetsAt, now) }) : null,\n /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react_native9.Text, { style: muted, children: [\n provider.parked,\n " ",\n provider.parked === 1 ? "assignment parked" : "assignments parked"\n ] })\n ] }) : null,\n !provider.available ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react_native9.View, { style: { gap: 8, paddingVertical: 16 }, children: [\n /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native8.Icon, { name: "CircleHelp", size: 22, color: colors.foregroundMuted }),\n /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native9.Text, { style: { color: colors.foreground, fontSize: 14, fontWeight: "500" }, children: "Usage is not available" }),\n /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native9.Text, { style: muted, children: "The provider did not return usage data. Check that its CLI is installed and signed in, then refresh." })\n ] }) : provider.windows.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native9.Text, { style: muted, children: "The provider has not reported any usage windows." }) : provider.windows.map((window, index) => {\n const used = window.usedPercent;\n const color = used === null ? colors.foregroundMuted : used >= 95 ? colors.statusDanger : used >= 80 ? colors.statusWarning : colors.accent;\n return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react_native9.View, { style: { gap: 8 }, children: [\n /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react_native9.View, { style: { flexDirection: "row", justifyContent: "space-between", alignItems: "baseline", gap: 12 }, children: [\n /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native9.Text, { style: { color: colors.foreground, fontSize: 13, flex: 1, textTransform: "capitalize" }, children: window.name }),\n /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native9.Text, { style: { color, fontSize: 25, fontWeight: "600", fontVariant: ["tabular-nums"] }, children: used === null ? "\\u2014" : `${Math.round(used)}%` })\n ] }),\n /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native9.View, { accessibilityRole: "progressbar", accessibilityLabel: `${window.name} used`, accessibilityValue: used === null ? { text: "Usage unknown" } : { min: 0, max: 100, now: used }, style: { height: 6, backgroundColor: colors.surface2, borderRadius: 3, overflow: "hidden" }, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native9.View, { style: { height: 6, width: `${used ?? 0}%`, backgroundColor: color, borderRadius: 3 } }) }),\n /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native9.Text, { style: muted, children: used === null ? "Usage percentage unavailable" : `${Math.round(100 - used)}% remaining` }),\n /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native9.Text, { style: muted, children: resetLabel(window.resetsAt, now) })\n ] }, `${window.name}-${index}`);\n }),\n /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react_native9.Text, { style: { ...muted, borderTopWidth: 1, borderTopColor: colors.border, paddingTop: 12 }, children: [\n "Checked ",\n dateLabel(provider.checkedAt)\n ] })\n ] });\n}\n\n// integrations/paseo/index.client.tsx\nfunction contribute(client) {\n const removePanel = client.addWorkspacePanel({ id: "alp-tasks", title: "Tasks", icon: "ListTodo", context: "workspace", Component: TasksPanel });\n const removeScreen = client.addScreen({ id: TASKS_SCREEN, title: (params) => params.taskId ? `ALP task ${params.taskId}` : "ALP tasks", Component: TasksScreen });\n const removePills = addTaskPills(client);\n const removeCommand = client.addCommandCenterItem({\n id: "alp-open-tasks",\n title: "Open ALP tasks",\n icon: "ListTodo",\n keywords: ["tasks", "todo", "alp"],\n context: "workspace",\n onSelect({ openPanel }) {\n openPanel("alp-tasks");\n }\n });\n const removeScreenCommand = client.addCommandCenterItem({\n id: "alp-open-tasks-screen",\n title: "Open ALP tasks full screen",\n icon: "ListTodo",\n keywords: ["tasks", "todo", "alp", "phone"],\n context: "workspace",\n onSelect({ workspace, openScreen }) {\n openScreen(tasksScreen(workspace.id, workspace.directory || workspace.projectRootPath));\n }\n });\n const removeSlash = client.addSlashCommand({\n name: "alp-tasks",\n description: "Open the ALP tasks of this project",\n argumentHint: "[task id]",\n context: "agent",\n onSubmit({ workspace, args, openScreen }) {\n openScreen(tasksScreen(workspace.id, workspace.directory || workspace.projectRootPath, args.trim() || void 0));\n }\n });\n const removeSettings = client.addSettingsScreen({ id: "alp-settings", title: "ALP", icon: "Bot", Component: LibrarySettings });\n const removeHostSettings = [\n { id: "alp-templates", title: "Templates", icon: "Users", Component: TeamsSettings },\n { id: "alp-agents", title: "Agents", icon: "Bot", Component: AgentsSettings },\n { id: "alp-skills", title: "Skills", icon: "BookOpen", Component: SkillsSettings },\n { id: "alp-hooks", title: "Hooks", icon: "Webhook", Component: HooksSettings },\n { id: "alp-mcp", title: "MCP servers", icon: "Plug", Component: McpSettings }\n ].map((screen) => client.addSettingsScreen(screen));\n const removeUsage = client.addSettingsScreen({ id: "alp-usage", title: "Usage", icon: "ChartNoAxesCombined", Component: UsageScreen });\n const removeUsagePanel = client.addWorkspacePanel({ id: "alp-usage", title: "Usage", icon: "ChartNoAxesCombined", context: "workspace", Component: UsageScreen });\n const removeProject = client.addWorkspacePanel({ id: "alp-project", title: "ALP project", icon: "Bot", context: "workspace", Component: ProjectLibraryPanel });\n return () => {\n removePanel();\n removeScreen();\n removePills();\n removeCommand();\n removeScreenCommand();\n removeSlash();\n removeSettings();\n removeHostSettings.forEach((remove) => remove());\n removeProject();\n removeUsage();\n removeUsagePanel();\n };\n}\n\nreturn module.exports;})' };
|
|
51638
|
+
var plugin_client_default = { "id": "alp-provider", "requirements": { "paseo": ">=0.11.1 <0.13.0" }, "factory": '(function(require){const module={exports:{}};const exports=module.exports;var __defProp = Object.defineProperty;\nvar __getOwnPropDesc = Object.getOwnPropertyDescriptor;\nvar __getOwnPropNames = Object.getOwnPropertyNames;\nvar __hasOwnProp = Object.prototype.hasOwnProperty;\nvar __export = (target, all) => {\n for (var name in all)\n __defProp(target, name, { get: all[name], enumerable: true });\n};\nvar __copyProps = (to, from, except, desc) => {\n if (from && typeof from === "object" || typeof from === "function") {\n for (let key of __getOwnPropNames(from))\n if (!__hasOwnProp.call(to, key) && key !== except)\n __defProp(to, key, { value: from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });\n }\n return to;\n};\nvar __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);\nvar __async = (__this, __arguments, generator) => {\n return new Promise((resolve, reject) => {\n var fulfilled = (value) => {\n try {\n step(generator.next(value));\n } catch (e) {\n reject(e);\n }\n };\n var rejected = (value) => {\n try {\n step(generator.throw(value));\n } catch (e) {\n reject(e);\n }\n };\n var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);\n step((generator = generator.apply(__this, __arguments)).next());\n });\n};\n\n// integrations/paseo/index.client.tsx\nvar index_client_exports = {};\n__export(index_client_exports, {\n default: () => contribute\n});\nmodule.exports = __toCommonJS(index_client_exports);\n\n// integrations/paseo/client/tasks-panel.tsx\nvar import_client = require("@getpaseo/plugin/client");\nvar import_react_native = require("@getpaseo/plugin/client/react-native");\nvar import_react = require("react");\nvar import_react_native2 = require("react-native");\n\n// integrations/paseo/shared/tasks.ts\nvar import_plugin = require("@getpaseo/plugin");\nvar import_zod = require("zod");\nvar TaskRowSchema = import_zod.z.object({\n id: import_zod.z.string(),\n title: import_zod.z.string(),\n type: import_zod.z.string(),\n priority: import_zod.z.number(),\n status: import_zod.z.enum(["open", "in_progress", "review", "closed"]),\n parent: import_zod.z.string().optional(),\n assignee: import_zod.z.string().optional(),\n ready: import_zod.z.boolean(),\n /** Open tasks that must close first, including those of ancestors. */\n blockedBy: import_zod.z.array(import_zod.z.string()).optional(),\n /** Open gates, as labels. */\n waits: import_zod.z.array(import_zod.z.string()).optional(),\n /** Open human gates of this task: the user approves them here. */\n approvals: import_zod.z.array(import_zod.z.object({ gate: import_zod.z.string(), note: import_zod.z.string() })).optional(),\n handoff: import_zod.z.object({ outcome: import_zod.z.string(), summary: import_zod.z.string(), agent: import_zod.z.string().optional() }).optional(),\n closed: import_zod.z.object({ reason: import_zod.z.string(), summary: import_zod.z.string().optional(), at: import_zod.z.string() }).optional(),\n /** What the task is about, for its detail view; at most 4000 characters. */\n description: import_zod.z.string().optional(),\n labels: import_zod.z.array(import_zod.z.string()).optional(),\n paths: import_zod.z.array(import_zod.z.string()).optional(),\n /** An epic or parent task: how many of its children are closed. */\n progress: import_zod.z.object({ done: import_zod.z.number(), total: import_zod.z.number() }).optional(),\n createdAt: import_zod.z.string().optional(),\n updatedAt: import_zod.z.string()\n});\nvar Directory = import_zod.z.string().min(1);\nvar tasksList = (0, import_plugin.defineRpc)({\n name: "alp.tasks.list",\n input: import_zod.z.object({ directory: Directory }),\n output: import_zod.z.object({\n /** The ALP project containing the directory, or null when there is none. */\n projectRoot: import_zod.z.string().nullable(),\n tasks: import_zod.z.array(TaskRowSchema),\n unreadable: import_zod.z.array(import_zod.z.object({ file: import_zod.z.string(), error: import_zod.z.string() })),\n /** By provider session id: the tasks that session\'s tree worked on (ALPD \xA755). */\n sessions: import_zod.z.record(import_zod.z.string(), import_zod.z.array(import_zod.z.string())).optional()\n })\n});\nvar tasksAdd = (0, import_plugin.defineRpc)({\n name: "alp.tasks.add",\n input: import_zod.z.object({ directory: Directory, title: import_zod.z.string().trim().min(1).max(200), priority: import_zod.z.number().int().min(0).max(4).optional() }),\n output: import_zod.z.object({ id: import_zod.z.string() })\n});\nvar tasksChange = (0, import_plugin.defineRpc)({\n name: "alp.tasks.change",\n input: import_zod.z.object({\n directory: Directory,\n id: import_zod.z.string().min(1),\n action: import_zod.z.enum(["close", "reopen", "approve"]),\n /** For approve: the human gate. */\n gate: import_zod.z.string().optional(),\n note: import_zod.z.string().max(2e3).optional()\n }),\n /** landed: the first line of the report when the close landed an epic. */\n output: import_zod.z.object({ id: import_zod.z.string(), status: import_zod.z.string(), landed: import_zod.z.string().optional() })\n});\nvar rank = (a, b) => a.priority - b.priority || a.id.localeCompare(b.id);\nfunction boardSections(tasks, closedLimit = 20) {\n const open = tasks.filter((task) => task.status !== "closed");\n const sections = [\n { key: "approve", title: "Waiting for your approval", tasks: open.filter((task) => task.approvals?.length).sort(rank) },\n { key: "review", title: "In review", tasks: open.filter((task) => task.status === "review").sort(rank) },\n { key: "progress", title: "In progress", tasks: open.filter((task) => task.status === "in_progress").sort(rank) },\n { key: "ready", title: "Ready", tasks: open.filter((task) => task.ready).sort(rank) },\n { key: "waiting", title: "Blocked or waiting", tasks: open.filter((task) => task.status === "open" && !task.ready && !task.approvals?.length && task.type !== "epic").sort(rank) },\n { key: "epics", title: "Epics", tasks: open.filter((task) => task.type === "epic" && !task.approvals?.length).sort(rank) },\n { key: "closed", title: "Closed", tasks: tasks.filter((task) => task.status === "closed").sort((a, b) => (b.closed?.at ?? b.updatedAt).localeCompare(a.closed?.at ?? a.updatedAt)).slice(0, closedLimit) }\n ];\n return sections.filter((section) => section.tasks.length);\n}\n\n// integrations/paseo/client/tasks-panel.tsx\nvar import_jsx_runtime = require("react/jsx-runtime");\nvar POLL_MS = 5e3;\nvar SPLIT_FROM = 820;\nfunction TasksPanel({ theme, layout, workspaceId }) {\n const directory = (0, import_client.useWorkspace)(workspaceId, (workspace) => workspace.directory || workspace.projectRootPath);\n return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TaskBoard, { theme, compact: layout.compact, directory, ...useTasks(directory) });\n}\nfunction TasksScreen({ theme, layout, params }) {\n const directory = params.directory || null;\n const tasks = useTasks(directory);\n return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(\n TaskBoard,\n {\n theme,\n compact: layout.compact,\n directory,\n ...tasks,\n initial: params.taskId ? { selected: params.taskId } : void 0\n },\n params.taskId ?? ""\n );\n}\nfunction useTasks(directory) {\n const list = (0, import_client.useRpc)(tasksList);\n const add = (0, import_client.useRpc)(tasksAdd);\n const change = (0, import_client.useRpc)(tasksChange);\n const toast = (0, import_react_native.useToast)();\n const [data, setData] = (0, import_react.useState)(null);\n const [error, setError] = (0, import_react.useState)(null);\n const [tick, setTick] = (0, import_react.useState)(0);\n const refresh = (0, import_react.useCallback)(() => setTick((value) => value + 1), []);\n (0, import_react.useEffect)(() => {\n if (!directory) return;\n let live = true;\n const load = () => list({ directory }).then((result) => {\n if (live) {\n setData(result);\n setError(null);\n }\n }).catch((cause) => {\n if (live) setError(cause instanceof Error ? cause.message : String(cause));\n });\n void load();\n const timer = setInterval(load, POLL_MS);\n return () => {\n live = false;\n clearInterval(timer);\n };\n }, [directory, list, tick]);\n const onAdd = (0, import_react.useCallback)((title, priority) => __async(null, null, function* () {\n if (!directory) return false;\n try {\n const { id } = yield add({ directory, title, priority });\n toast.show(`Added ${id}`, { variant: "success" });\n refresh();\n return true;\n } catch (cause) {\n toast.error(cause instanceof Error ? cause.message : String(cause));\n return false;\n }\n }), [add, directory, refresh, toast]);\n const onAction = (0, import_react.useCallback)((_0) => __async(null, [_0], function* ({ id, action, gate }) {\n if (!directory) return;\n try {\n const { landed } = yield change({ directory, id, action, ...gate ? { gate } : {} });\n toast.show(landed ?? (action === "approve" ? `Approved ${id}` : action === "close" ? `Closed ${id}` : `Reopened ${id}`), { variant: "success" });\n refresh();\n } catch (cause) {\n toast.error(cause instanceof Error ? cause.message : String(cause));\n }\n }), [change, directory, refresh, toast]);\n return { projectRoot: data?.projectRoot ?? null, tasks: data?.tasks ?? null, unreadable: data?.unreadable.length ?? 0, error, onAdd, onAction, onRefresh: refresh };\n}\nvar PRIORITIES = [0, 1, 2, 3, 4];\nvar TYPE_ICONS = { bug: "Bug", feature: "Sparkles", task: "SquareCheck", chore: "Wrench", epic: "Target" };\nvar hovered = (state) => !!state.hovered;\nfunction age(iso, now = Date.now()) {\n if (!iso) return "";\n const minutes = Math.max(0, Math.floor((now - Date.parse(iso)) / 6e4));\n if (minutes < 60) return `${minutes}m`;\n if (minutes < 60 * 24) return `${Math.floor(minutes / 60)}h`;\n if (minutes < 60 * 24 * 14) return `${Math.floor(minutes / 1440)}d`;\n return `${Math.floor(minutes / 10080)}w`;\n}\nfunction stateOf(task) {\n if (task.status === "closed") return "closed";\n if (task.approvals?.length) return "approve";\n if (task.status === "review") return "review";\n if (task.status === "in_progress") return "progress";\n if (task.type === "epic") return task.progress?.done ? "progress" : "ready";\n return task.ready ? "ready" : "blocked";\n}\nvar STATE_LABELS = { approve: "Needs approval", review: "In review", progress: "In progress", ready: "Ready", blocked: "Blocked", closed: "Closed" };\nfunction filterTasks(tasks, filter, query) {\n const words = query.trim().toLowerCase().split(/\\s+/).filter(Boolean);\n return tasks.filter((task) => {\n if (filter === "open" && task.status === "closed") return false;\n if (filter === "ready" && !(task.ready && task.status !== "closed")) return false;\n if (filter === "closed" && task.status !== "closed") return false;\n const text = [task.id, task.title, task.type, task.assignee ?? "", ...task.labels ?? []].join(" ").toLowerCase();\n return words.every((word) => text.includes(word));\n });\n}\nfunction TaskBoard({ theme, compact, directory, projectRoot, tasks, unreadable, error, onAdd, onAction, onRefresh, initial }) {\n const styles = (0, import_react.useMemo)(() => makeStyles(theme, compact), [theme, compact]);\n const [view, setView] = (0, import_react.useState)(initial?.view ?? "list");\n const [filter, setFilter] = (0, import_react.useState)(initial?.filter ?? "open");\n const [query, setQuery] = (0, import_react.useState)("");\n const [selected, setSelected] = (0, import_react.useState)(initial?.selected ?? null);\n const [composing, setComposing] = (0, import_react.useState)(false);\n const [width, setWidth] = (0, import_react.useState)(initial?.width ?? 0);\n const shown = (0, import_react.useMemo)(() => tasks ? filterTasks(tasks, filter, query) : [], [tasks, filter, query]);\n const task = selected ? tasks?.find((candidate) => candidate.id === selected) ?? null : null;\n const split = !!task && width >= SPLIT_FROM;\n const counts = (0, import_react.useMemo)(() => ({\n open: (tasks ?? []).filter((entry) => entry.status !== "closed").length,\n ready: (tasks ?? []).filter((entry) => entry.ready && entry.status !== "closed").length,\n closed: (tasks ?? []).filter((entry) => entry.status === "closed").length,\n all: (tasks ?? []).length\n }), [tasks]);\n if (!directory) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.View, { style: styles.screen, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: styles.muted, children: "This view needs a workspace." }) });\n const open = (id) => setSelected(id);\n const detail = task ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TaskDetail, { theme, styles, task, tasks: tasks ?? [], onBack: () => setSelected(null), onOpen: open, onAction }) : null;\n return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.View, { style: styles.screen, onLayout: (event) => setWidth(event.nativeEvent.layout.width), children: [\n /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.View, { style: styles.toolbar, children: [\n /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.View, { style: styles.toolbarRow, children: [\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: styles.title, children: "Tasks" }),\n tasks ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.Text, { style: styles.count, children: [\n counts.open,\n " open"\n ] }) : null,\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.View, { style: { flex: 1 } }),\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(\n Segmented,\n {\n theme,\n styles,\n value: view,\n onChange: (value) => {\n setView(value);\n setSelected(null);\n },\n options: [{ key: "list", label: "List", icon: "List" }, { key: "board", label: "Board", icon: "Columns3" }, { key: "epics", label: "Epics", icon: "Target" }]\n }\n ),\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(IconButton, { theme, icon: "RefreshCw", label: "Refresh", onPress: onRefresh }),\n projectRoot ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(IconButton, { theme, icon: "Plus", label: "New task", onPress: () => setComposing(!composing), primary: true }) : null\n ] }),\n projectRoot ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.View, { style: styles.toolbarRow, children: [\n ["open", "ready", "closed", "all"].map((key) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Pressable, { accessibilityRole: "button", accessibilityLabel: `Show ${key}`, accessibilityState: { selected: filter === key }, onPress: () => setFilter(key), style: [styles.filter, filter === key ? styles.filterOn : null], children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.Text, { style: filter === key ? styles.filterTextOn : styles.filterText, children: [\n key[0].toUpperCase() + key.slice(1),\n " ",\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: styles.filterCount, children: counts[key] })\n ] }) }, key)),\n /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.View, { style: styles.search, children: [\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native.Icon, { name: "Search", size: 14, color: theme.colors.foregroundMuted }),\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.TextInput, { style: styles.searchInput, value: query, onChangeText: setQuery, placeholder: "Filter by id, title, label, agent", placeholderTextColor: theme.colors.foregroundMuted, accessibilityLabel: "Filter tasks" })\n ] })\n ] }) : null,\n composing && projectRoot ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Composer, { theme, styles, onAdd: (title, priority) => __async(null, null, function* () {\n const added = yield onAdd(title, priority);\n if (added) setComposing(false);\n return added;\n }) }) : null\n ] }),\n error ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: [styles.danger, styles.pad], children: error }) : null,\n tasks === null && !error ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: [styles.muted, styles.pad], children: "Loading tasks\\u2026" }) : null,\n tasks !== null && projectRoot === null ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.Text, { style: [styles.muted, styles.pad], children: [\n directory,\n " is not an ALP project. Run alp init to start one."\n ] }) : null,\n projectRoot && tasks ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.View, { style: styles.body, children: [\n !task || split ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.View, { style: [styles.pane, split ? styles.paneList : null], children: [\n unreadable ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.Text, { style: [styles.warning, styles.pad], children: [\n unreadable,\n " unreadable task ",\n unreadable === 1 ? "file" : "files",\n " in ",\n projectRoot,\n "/.alp/tasks"\n ] }) : null,\n !tasks.length ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Empty, { styles, text: "No tasks yet. Add one here, with alp task add, or ask main to plan the work." }) : null,\n tasks.length && !shown.length ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Empty, { styles, text: "No tasks match." }) : null,\n shown.length && view === "list" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ListView, { theme, styles, tasks: shown, selected, onOpen: open, onAction }) : null,\n shown.length && view === "board" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(BoardView, { theme, styles, tasks: shown, onOpen: open }) : null,\n view === "epics" && tasks.length ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(EpicsView, { theme, styles, tasks, shown, onOpen: open }) : null\n ] }) : null,\n detail ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.View, { style: [styles.pane, split ? styles.paneDetail : null], children: detail }) : null\n ] }) : null\n ] });\n}\nfunction Segmented({ theme, styles, value, options, onChange }) {\n return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.View, { style: styles.segmented, children: options.map((option) => {\n const on = option.key === value;\n return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.Pressable, { accessibilityRole: "tab", accessibilityLabel: option.label, accessibilityState: { selected: on }, onPress: () => onChange(option.key), style: [styles.segment, on ? styles.segmentOn : null], children: [\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native.Icon, { name: option.icon, size: 13, color: on ? theme.colors.foreground : theme.colors.foregroundMuted }),\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: on ? styles.segmentTextOn : styles.segmentText, children: option.label })\n ] }, option.key);\n }) });\n}\nfunction IconButton({ theme, icon, label, onPress, primary }) {\n const { colors } = theme;\n return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(\n import_react_native2.Pressable,\n {\n accessibilityRole: "button",\n accessibilityLabel: label,\n onPress,\n style: (state) => ({ padding: 7, borderRadius: 8, backgroundColor: primary ? colors.accent : hovered(state) ? colors.surface2 : "transparent" }),\n children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native.Icon, { name: icon, size: 15, color: primary ? colors.accentForeground : colors.foregroundMuted })\n }\n );\n}\nfunction Composer({ theme, styles, onAdd }) {\n const [title, setTitle] = (0, import_react.useState)("");\n const [priority, setPriority] = (0, import_react.useState)(2);\n const submit = () => __async(null, null, function* () {\n const text = title.trim();\n if (text && (yield onAdd(text, priority))) setTitle("");\n });\n return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.View, { style: styles.composer, children: [\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.TextInput, { style: styles.input, value: title, onChangeText: setTitle, onSubmitEditing: submit, placeholder: "Add a task for main", placeholderTextColor: theme.colors.foregroundMuted, accessibilityLabel: "New task title", autoFocus: true }),\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.View, { style: styles.priorities, children: PRIORITIES.map((value) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Pressable, { accessibilityRole: "button", accessibilityLabel: `Priority ${value}`, onPress: () => setPriority(value), style: [styles.chip, value === priority ? styles.chipOn : null], children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.Text, { style: value === priority ? styles.chipTextOn : styles.chipText, children: [\n "P",\n value\n ] }) }, value)) }),\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Pressable, { accessibilityRole: "button", onPress: submit, style: styles.button, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: styles.buttonText, children: "Add" }) })\n ] });\n}\nfunction Empty({ styles, text }) {\n return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.View, { style: styles.empty, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: styles.muted, children: text }) });\n}\nfunction Priority({ theme, value }) {\n const { colors } = theme;\n const color = value === 0 ? colors.statusDanger : value === 1 ? colors.statusWarning : colors.foregroundMuted;\n return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.View, { style: { alignSelf: "flex-start", borderRadius: 4, borderWidth: 1, borderColor: value <= 1 ? color : colors.border, paddingHorizontal: 4 }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.Text, { style: { color, fontSize: 10.5, fontWeight: "600", fontVariant: ["tabular-nums"] }, children: [\n "P",\n value\n ] }) });\n}\nfunction StateDot({ theme, task }) {\n const { colors } = theme;\n const state = stateOf(task);\n const color = state === "approve" ? colors.statusWarning : state === "review" ? colors.accent : state === "progress" ? colors.statusWarning : state === "ready" ? colors.statusSuccess : state === "blocked" ? colors.statusDanger : colors.border;\n const ring = state === "progress" || state === "closed";\n return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.View, { accessibilityLabel: STATE_LABELS[state], style: { width: 9, height: 9, borderRadius: 5, borderWidth: ring ? 2 : 0, borderColor: color, backgroundColor: ring ? "transparent" : color } });\n}\nfunction TaskLine({ theme, styles, task, selected, onOpen }) {\n const meta = [\n task.blockedBy?.length ? `after ${task.blockedBy.join(", ")}` : "",\n // Gates waiting for the user show with their Approve instead.\n task.waits?.length && !task.approvals?.length ? `waits on ${task.waits.join("; ")}` : "",\n task.parent ? `in ${task.parent}` : ""\n ].filter(Boolean).join(" \\xB7 ");\n return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.Pressable, { accessibilityRole: "button", accessibilityLabel: `Open ${task.id}`, onPress: () => onOpen(task.id), style: (state) => [styles.line, selected ? styles.lineOn : hovered(state) ? styles.lineHover : null], children: [\n /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.View, { style: styles.lineTop, children: [\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(StateDot, { theme, task }),\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native.Icon, { name: TYPE_ICONS[task.type] ?? "SquareCheck", size: 13, color: theme.colors.foregroundMuted }),\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Priority, { theme, value: task.priority }),\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: styles.id, children: task.id }),\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: styles.lineTitle, numberOfLines: 1, children: task.title }),\n task.assignee ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.Text, { style: styles.assignee, numberOfLines: 1, children: [\n "@",\n task.assignee\n ] }) : null,\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: styles.age, children: age(task.status === "closed" ? task.closed?.at : task.updatedAt) })\n ] }),\n meta || task.labels?.length ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.View, { style: styles.lineMeta, children: [\n meta ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: styles.small, numberOfLines: 1, children: meta }) : null,\n (task.labels ?? []).map((label) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.Text, { style: styles.label, children: [\n "#",\n label\n ] }, label))\n ] }) : null\n ] });\n}\nvar SECTION_ICONS = { approve: "Hand", review: "Eye", progress: "LoaderCircle", ready: "CircleCheck", waiting: "CircleSlash", epics: "Target", closed: "CircleDashed" };\nfunction ListView({ theme, styles, tasks, selected, onOpen, onAction }) {\n const sections = (0, import_react.useMemo)(() => boardSections(tasks), [tasks]);\n const [hidden, setHidden] = (0, import_react.useState)({});\n return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native.ScrollView, { contentContainerStyle: styles.listContent, children: sections.map((section) => {\n const collapsed = hidden[section.key] ?? false;\n return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.View, { style: styles.group, children: [\n /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.Pressable, { accessibilityRole: "button", accessibilityLabel: `${collapsed ? "Show" : "Hide"} ${section.title}`, onPress: () => setHidden((current) => ({ ...current, [section.key]: !collapsed })), style: styles.groupHeader, children: [\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native.Icon, { name: collapsed ? "ChevronRight" : "ChevronDown", size: 13, color: theme.colors.foregroundMuted }),\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native.Icon, { name: SECTION_ICONS[section.key] ?? "Circle", size: 13, color: theme.colors.foregroundMuted }),\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: styles.groupTitle, children: section.title }),\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: styles.groupCount, children: section.tasks.length })\n ] }),\n !collapsed ? section.tasks.map((task) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.View, { children: [\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TaskLine, { theme, styles, task, selected: task.id === selected, onOpen }),\n section.key === "approve" ? task.approvals.map((approval) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.View, { style: styles.inlineAction, children: [\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: styles.small, numberOfLines: 2, children: approval.note || "Waiting for your approval" }),\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SmallButton, { styles, label: "Approve", primary: true, onPress: () => onAction({ id: task.id, action: "approve", gate: approval.gate }) })\n ] }, approval.gate)) : null\n ] }, `${section.key}-${task.id}`)) : null\n ] }, section.key);\n }) });\n}\nvar COLUMNS = [\n { key: "approve", title: "Needs approval" },\n { key: "blocked", title: "Blocked" },\n { key: "ready", title: "Ready" },\n { key: "progress", title: "In progress" },\n { key: "review", title: "In review" },\n { key: "closed", title: "Closed" }\n];\nfunction BoardView({ theme, styles, tasks, onOpen }) {\n const columns = COLUMNS.map((column) => ({ ...column, tasks: tasks.filter((task) => task.type !== "epic" && stateOf(task) === column.key) })).filter((column) => column.tasks.length || ["blocked", "ready", "progress"].includes(column.key));\n return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native.ScrollView, { horizontal: true, contentContainerStyle: styles.board, children: columns.map((column) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.View, { style: styles.column, children: [\n /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.View, { style: styles.columnHeader, children: [\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(StateDot, { theme, task: { status: column.key === "closed" ? "closed" : column.key === "review" ? "review" : column.key === "progress" ? "in_progress" : "open", ready: column.key === "ready", approvals: column.key === "approve" ? [{ gate: "", note: "" }] : void 0 } }),\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: styles.columnTitle, children: column.title }),\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: styles.groupCount, children: column.tasks.length })\n ] }),\n /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native.ScrollView, { contentContainerStyle: styles.columnBody, children: [\n column.tasks.map((task) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.Pressable, { accessibilityRole: "button", accessibilityLabel: `Open ${task.id}`, onPress: () => onOpen(task.id), style: (state) => [styles.card, hovered(state) ? styles.cardHover : null, column.key === "blocked" ? styles.cardBlocked : column.key === "ready" ? styles.cardReady : null], children: [\n /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.View, { style: styles.lineTop, children: [\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native.Icon, { name: TYPE_ICONS[task.type] ?? "SquareCheck", size: 12, color: theme.colors.foregroundMuted }),\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Priority, { theme, value: task.priority }),\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: styles.id, children: task.id }),\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.View, { style: { flex: 1 } }),\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: styles.age, children: age(task.updatedAt) })\n ] }),\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: styles.cardTitle, numberOfLines: 3, children: task.title }),\n task.assignee ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.Text, { style: styles.assignee, numberOfLines: 1, children: [\n "@",\n task.assignee\n ] }) : null,\n task.blockedBy?.length ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.Text, { style: styles.blocked, numberOfLines: 1, children: [\n "after ",\n task.blockedBy.join(", ")\n ] }) : null,\n task.labels?.length ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.View, { style: styles.cardLabels, children: task.labels.map((label) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.Text, { style: styles.label, children: [\n "#",\n label\n ] }, label)) }) : null\n ] }, task.id)),\n !column.tasks.length ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: [styles.small, styles.pad], children: "Nothing here" }) : null\n ] })\n ] }, column.key)) });\n}\nfunction EpicsView({ theme, styles, tasks, shown, onOpen }) {\n const epics = shown.filter((task) => task.type === "epic" || task.progress);\n const [opened, setOpened] = (0, import_react.useState)({});\n if (!epics.length) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Empty, { styles, text: "No epics here. An epic is a task other tasks name as their parent." });\n return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native.ScrollView, { contentContainerStyle: styles.listContent, children: epics.map((epic) => {\n const children = tasks.filter((task) => task.parent === epic.id);\n const done = epic.progress?.done ?? 0;\n const total = epic.progress?.total ?? 0;\n const expanded = opened[epic.id] ?? epic.status !== "closed";\n return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.View, { style: styles.epic, children: [\n /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.Pressable, { accessibilityRole: "button", accessibilityLabel: `Open ${epic.id}`, onPress: () => onOpen(epic.id), style: styles.lineTop, children: [\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(StateDot, { theme, task: epic }),\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native.Icon, { name: "Target", size: 13, color: theme.colors.foregroundMuted }),\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Priority, { theme, value: epic.priority }),\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: styles.id, children: epic.id }),\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: styles.lineTitle, numberOfLines: 1, children: epic.title }),\n /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.Text, { style: styles.progressText, children: [\n done,\n "/",\n total\n ] })\n ] }),\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.View, { style: styles.progressTrack, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.View, { style: [styles.progressFill, { width: `${total ? Math.round(done / total * 100) : 0}%` }] }) }),\n children.length ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.Pressable, { accessibilityRole: "button", accessibilityLabel: `${expanded ? "Hide" : "Show"} the tasks of ${epic.id}`, onPress: () => setOpened((current) => ({ ...current, [epic.id]: !expanded })), style: styles.treeToggle, children: [\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native.Icon, { name: expanded ? "ChevronDown" : "ChevronRight", size: 12, color: theme.colors.foregroundMuted }),\n /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.Text, { style: styles.small, children: [\n children.length,\n " ",\n children.length === 1 ? "task" : "tasks"\n ] })\n ] }) : null,\n expanded ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.View, { style: styles.tree, children: children.map((child) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TaskLine, { theme, styles, task: child, selected: false, onOpen }, child.id)) }) : null\n ] }, epic.id);\n }) });\n}\nfunction SmallButton({ styles, label, onPress, primary, danger }) {\n return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Pressable, { accessibilityRole: "button", onPress, style: [styles.smallButton, primary ? styles.smallButtonPrimary : null, danger ? styles.smallButtonDanger : null], children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: primary ? styles.smallButtonTextPrimary : danger ? styles.smallButtonTextDanger : styles.smallButtonText, children: label }) });\n}\nfunction TaskDetail({ theme, styles, task, tasks, onBack, onOpen, onAction }) {\n const state = stateOf(task);\n const children = tasks.filter((entry) => entry.parent === task.id);\n const blocks = tasks.filter((entry) => entry.blockedBy?.includes(task.id) && entry.status !== "closed");\n const field = (label, value) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.View, { style: styles.field, children: [\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: styles.fieldLabel, children: label }),\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.View, { style: styles.fieldValue, children: typeof value === "string" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: styles.text, children: value }) : value })\n ] });\n const link = (id) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Pressable, { accessibilityRole: "link", accessibilityLabel: `Open ${id}`, onPress: () => onOpen(id), children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: styles.link, children: id }) }, id);\n return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native.ScrollView, { contentContainerStyle: styles.detail, children: [\n /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.View, { style: styles.detailHeader, children: [\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(IconButton, { theme, icon: "ArrowLeft", label: "Back to the list", onPress: onBack }),\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: styles.id, children: task.id }),\n /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.View, { style: styles.statePill, children: [\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(StateDot, { theme, task }),\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: styles.small, children: STATE_LABELS[state] })\n ] })\n ] }),\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: styles.detailTitle, children: task.title }),\n /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.View, { style: styles.fields, children: [\n field("Type", /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.View, { style: styles.inline, children: [\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native.Icon, { name: TYPE_ICONS[task.type] ?? "SquareCheck", size: 13, color: theme.colors.foregroundMuted }),\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: styles.text, children: task.type })\n ] })),\n field("Priority", /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Priority, { theme, value: task.priority })),\n task.assignee ? field("Assignee", `@${task.assignee}`) : null,\n task.parent ? field("Parent", link(task.parent)) : null,\n task.blockedBy?.length ? field("Blocked by", /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.View, { style: styles.inline, children: task.blockedBy.map(link) })) : null,\n blocks.length ? field("Blocks", /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.View, { style: styles.inline, children: blocks.map((entry) => link(entry.id)) })) : null,\n task.waits?.length ? field("Waits on", task.waits.join("; ")) : null,\n task.labels?.length ? field("Labels", /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.View, { style: styles.inline, children: task.labels.map((label) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.Text, { style: styles.label, children: [\n "#",\n label\n ] }, label)) })) : null,\n task.paths?.length ? field("Paths", task.paths.join(", ")) : null,\n task.progress ? field("Progress", `${task.progress.done} of ${task.progress.total} closed`) : null,\n task.createdAt ? field("Created", `${age(task.createdAt)} ago`) : null,\n field("Updated", `${age(task.updatedAt)} ago`)\n ] }),\n task.description ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.View, { style: styles.box, children: [\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: styles.boxTitle, children: "Description" }),\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: styles.text, children: task.description })\n ] }) : null,\n task.handoff ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.View, { style: styles.box, children: [\n /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.Text, { style: styles.boxTitle, children: [\n "Handoff \\xB7 ",\n task.handoff.outcome,\n task.handoff.agent ? ` from ${task.handoff.agent}` : ""\n ] }),\n /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: styles.text, children: task.handoff.summary })\n ] }) : null,\n task.closed ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.View, { style: styles.box, children: [\n /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.Text, { style: styles.boxTitle, children: [\n "Closed \\xB7 ",\n task.closed.reason\n ] }),\n task.closed.summary ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: styles.text, children: task.closed.summary }) : null\n ] }) : null,\n children.length ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.View, { style: styles.box, children: [\n /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.Text, { style: styles.boxTitle, children: [\n "Tasks \\xB7 ",\n children.filter((child) => child.status === "closed").length,\n "/",\n children.length,\n " closed"\n ] }),\n children.map((child) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TaskLine, { theme, styles, task: child, selected: false, onOpen }, child.id))\n ] }) : null,\n /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.View, { style: styles.detailActions, children: [\n (task.approvals ?? []).map((approval) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SmallButton, { styles, primary: true, label: `Approve${approval.note ? `: ${approval.note.slice(0, 40)}` : ""}`, onPress: () => onAction({ id: task.id, action: "approve", gate: approval.gate }) }, approval.gate)),\n state === "review" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SmallButton, { styles, primary: true, label: "Accept and close", onPress: () => onAction({ id: task.id, action: "close" }) }) : null,\n task.status !== "closed" && state !== "review" && task.type !== "epic" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SmallButton, { styles, label: "Close", onPress: () => onAction({ id: task.id, action: "close" }) }) : null,\n task.status === "closed" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SmallButton, { styles, label: "Reopen", onPress: () => onAction({ id: task.id, action: "reopen" }) }) : null\n ] })\n ] });\n}\nfunction makeStyles(theme, compact) {\n const { colors } = theme;\n const mono = { fontFamily: "monospace", fontVariant: ["tabular-nums"] };\n return {\n screen: { flex: 1, backgroundColor: colors.surface0 },\n pad: { paddingHorizontal: compact ? 12 : 16, paddingVertical: 8 },\n toolbar: { paddingHorizontal: compact ? 12 : 16, paddingTop: 12, paddingBottom: 10, gap: 10, borderBottomWidth: 1, borderBottomColor: colors.border },\n toolbarRow: { flexDirection: "row", alignItems: "center", gap: 6, flexWrap: "wrap" },\n title: { color: colors.foreground, fontSize: 15, fontWeight: "600" },\n count: { color: colors.foregroundMuted, fontSize: 12, marginLeft: 4 },\n segmented: { flexDirection: "row", backgroundColor: colors.surface1, borderRadius: 8, borderWidth: 1, borderColor: colors.border, padding: 2 },\n segment: { flexDirection: "row", alignItems: "center", gap: 5, paddingHorizontal: 8, paddingVertical: 4, borderRadius: 6 },\n segmentOn: { backgroundColor: colors.surface0, shadowColor: "#000", shadowOpacity: 0.08, shadowRadius: 2 },\n segmentText: { color: colors.foregroundMuted, fontSize: 12 },\n segmentTextOn: { color: colors.foreground, fontSize: 12, fontWeight: "600" },\n filter: { paddingHorizontal: 9, paddingVertical: 4, borderRadius: 999, borderWidth: 1, borderColor: colors.border },\n filterOn: { backgroundColor: colors.foreground, borderColor: colors.foreground },\n filterText: { color: colors.foreground, fontSize: 12 },\n filterTextOn: { color: colors.surface0, fontSize: 12, fontWeight: "600" },\n filterCount: { opacity: 0.6, fontSize: 11 },\n search: { flex: 1, minWidth: 160, flexDirection: "row", alignItems: "center", gap: 6, borderWidth: 1, borderColor: colors.border, borderRadius: 8, paddingHorizontal: 8, backgroundColor: colors.surface1 },\n searchInput: { flex: 1, minWidth: 0, color: colors.foreground, fontSize: 12.5, paddingVertical: 6 },\n composer: { flexDirection: compact ? "column" : "row", gap: 8, alignItems: compact ? "stretch" : "center" },\n input: { flex: compact ? void 0 : 1, minWidth: 0, color: colors.foreground, borderWidth: 1, borderColor: colors.border, borderRadius: 8, paddingHorizontal: 10, paddingVertical: 7, backgroundColor: colors.surface1 },\n priorities: { flexDirection: "row", gap: 4 },\n chip: { paddingHorizontal: 7, paddingVertical: 5, borderRadius: 6, borderWidth: 1, borderColor: colors.border },\n chipOn: { backgroundColor: colors.accent, borderColor: colors.accent },\n chipText: { color: colors.foregroundMuted, fontSize: 12 },\n chipTextOn: { color: colors.accentForeground, fontSize: 12 },\n button: { paddingHorizontal: 12, paddingVertical: 7, borderRadius: 8, backgroundColor: colors.accent },\n buttonText: { color: colors.accentForeground, fontWeight: "600" },\n body: { flex: 1, flexDirection: "row" },\n pane: { flex: 1, minWidth: 0 },\n paneList: { flex: 2, borderRightWidth: 1, borderRightColor: colors.border },\n paneDetail: { flex: 3 },\n empty: { margin: 16, borderWidth: 1, borderStyle: "dashed", borderColor: colors.border, borderRadius: 10, padding: 24, alignItems: "center" },\n listContent: { paddingVertical: 6 },\n group: { marginBottom: 4 },\n groupHeader: { flexDirection: "row", alignItems: "center", gap: 6, paddingHorizontal: compact ? 10 : 14, paddingVertical: 7 },\n groupTitle: { color: colors.foregroundMuted, fontSize: 11.5, fontWeight: "600", textTransform: "uppercase", letterSpacing: 0.4 },\n groupCount: { color: colors.foregroundMuted, fontSize: 11, opacity: 0.8 },\n line: { paddingHorizontal: compact ? 10 : 14, paddingVertical: 7, gap: 3, borderLeftWidth: 2, borderLeftColor: "transparent" },\n lineOn: { backgroundColor: colors.surface2, borderLeftColor: colors.accent },\n lineHover: { backgroundColor: colors.surface1 },\n lineTop: { flexDirection: "row", alignItems: "center", gap: 7 },\n lineTitle: { flex: 1, minWidth: 0, color: colors.foreground, fontSize: 13 },\n lineMeta: { flexDirection: "row", flexWrap: "wrap", gap: 6, paddingLeft: 16 },\n id: { color: colors.foregroundMuted, fontSize: 11.5, ...mono },\n age: { color: colors.foregroundMuted, fontSize: 11, ...mono },\n assignee: { color: colors.accent, fontSize: 11.5, maxWidth: 110 },\n label: { color: colors.foregroundMuted, fontSize: 11, backgroundColor: colors.surface2, borderRadius: 4, paddingHorizontal: 5, paddingVertical: 1 },\n inlineAction: { flexDirection: "row", alignItems: "center", gap: 10, paddingLeft: compact ? 26 : 30, paddingRight: 14, paddingBottom: 8 },\n board: { padding: 12, gap: 10, alignItems: "flex-start" },\n column: { width: 248, backgroundColor: colors.surface1, borderRadius: 10, borderWidth: 1, borderColor: colors.border, maxHeight: 640 },\n columnHeader: { flexDirection: "row", alignItems: "center", gap: 7, paddingHorizontal: 12, paddingVertical: 10, borderBottomWidth: 1, borderBottomColor: colors.border },\n columnTitle: { flex: 1, color: colors.foreground, fontSize: 12.5, fontWeight: "600" },\n columnBody: { padding: 8, gap: 8 },\n card: { backgroundColor: colors.surface0, borderRadius: 8, borderWidth: 1, borderColor: colors.border, borderLeftWidth: 3, padding: 10, gap: 5 },\n cardHover: { borderColor: colors.foregroundMuted },\n cardBlocked: { borderLeftColor: colors.statusDanger },\n cardReady: { borderLeftColor: colors.statusSuccess },\n cardLabels: { flexDirection: "row", flexWrap: "wrap", gap: 6 },\n blocked: { color: colors.statusDanger, fontSize: 11.5 },\n cardTitle: { color: colors.foreground, fontSize: 13, lineHeight: 18 },\n epic: { marginHorizontal: compact ? 10 : 14, marginVertical: 6, padding: 12, borderRadius: 10, borderWidth: 1, borderColor: colors.border, backgroundColor: colors.surface1, gap: 8 },\n progressTrack: { height: 6, borderRadius: 3, backgroundColor: colors.surface2, overflow: "hidden" },\n progressFill: { height: 6, borderRadius: 3, backgroundColor: colors.statusSuccess },\n progressText: { color: colors.foregroundMuted, fontSize: 11.5, ...mono },\n treeToggle: { flexDirection: "row", alignItems: "center", gap: 4 },\n tree: { marginLeft: 6, borderLeftWidth: 1, borderLeftColor: colors.border, backgroundColor: colors.surface0, borderRadius: 6 },\n detail: { padding: compact ? 12 : 18, gap: 14 },\n detailHeader: { flexDirection: "row", alignItems: "center", gap: 8 },\n statePill: { flexDirection: "row", alignItems: "center", gap: 6, borderWidth: 1, borderColor: colors.border, borderRadius: 999, paddingHorizontal: 8, paddingVertical: 2 },\n detailTitle: { color: colors.foreground, fontSize: 17, fontWeight: "600", lineHeight: 23 },\n fields: { borderWidth: 1, borderColor: colors.border, borderRadius: 10, overflow: "hidden" },\n field: { flexDirection: "row", alignItems: "center", gap: 12, paddingHorizontal: 12, paddingVertical: 8, borderBottomWidth: 1, borderBottomColor: colors.border },\n fieldLabel: { width: 84, color: colors.foregroundMuted, fontSize: 12 },\n fieldValue: { flex: 1, minWidth: 0 },\n inline: { flexDirection: "row", alignItems: "center", gap: 6, flexWrap: "wrap" },\n box: { borderRadius: 10, backgroundColor: colors.surface1, borderWidth: 1, borderColor: colors.border, padding: 12, gap: 6 },\n boxTitle: { color: colors.foregroundMuted, fontSize: 11.5, fontWeight: "600", textTransform: "uppercase", letterSpacing: 0.4 },\n detailActions: { flexDirection: "row", gap: 8, flexWrap: "wrap" },\n smallButton: { paddingHorizontal: 10, paddingVertical: 6, borderRadius: 7, borderWidth: 1, borderColor: colors.border, backgroundColor: colors.surface1 },\n smallButtonPrimary: { backgroundColor: colors.accent, borderColor: colors.accent },\n smallButtonDanger: { borderColor: colors.statusDanger },\n smallButtonText: { color: colors.foreground, fontSize: 12.5, fontWeight: "500" },\n smallButtonTextPrimary: { color: colors.accentForeground, fontSize: 12.5, fontWeight: "600" },\n smallButtonTextDanger: { color: colors.statusDanger, fontSize: 12.5 },\n text: { color: colors.foreground, fontSize: 13, lineHeight: 19 },\n small: { color: colors.foregroundMuted, fontSize: 12 },\n muted: { color: colors.foregroundMuted, fontSize: 13 },\n danger: { color: colors.statusDanger, fontSize: 13 },\n warning: { color: colors.statusWarning, fontSize: 12 },\n link: { color: colors.accent, fontSize: 13, ...mono }\n };\n}\n\n// integrations/paseo/client/task-pills.ts\nvar TASKS_SCREEN = "alp-tasks";\nvar POLL_MS2 = 2e4;\nvar MENU_LIMIT = 8;\nvar PAGE = 200;\nfunction tasksScreen(workspaceId, directory, taskId) {\n return { screenId: TASKS_SCREEN, params: { workspaceId, directory, ...taskId ? { taskId } : {} } };\n}\nvar ORDER = ["approve", "review", "progress", "ready", "blocked"];\nvar STATES = {\n approve: { label: "Approve", icon: "Hand" },\n review: { label: "Review", icon: "Eye" },\n progress: { label: "In progress", icon: "LoaderCircle" },\n ready: { label: "Ready", icon: "CircleCheck" },\n blocked: { label: "Blocked", icon: "CircleSlash" },\n closed: { label: "Done", icon: "CheckCheck" }\n};\nfunction sessionWork(board, sessions = []) {\n const ids = sessions.map((id) => board?.sessions?.[id]).find(Boolean) ?? [];\n const index = new Map((board?.tasks ?? []).map((task) => [task.id, task]));\n return ids.flatMap((id) => index.has(id) ? [{ task: index.get(id), state: stateOf(index.get(id)) }] : []);\n}\nfunction menuTasks(tasks) {\n return tasks.filter((task) => task.status !== "closed" && task.type !== "epic").map((task) => ({ task, state: stateOf(task) })).sort((a, b) => ORDER.indexOf(a.state) - ORDER.indexOf(b.state) || a.task.priority - b.task.priority || a.task.id.localeCompare(b.task.id));\n}\nfunction taskButton(board, open, sessions = []) {\n const listed = board ? menuTasks(board.tasks) : [];\n const worked = sessionWork(board, sessions);\n const done = worked.filter((entry2) => entry2.state === "closed").length;\n const mine = new Set(worked.map((entry2) => entry2.task.id));\n const shown = [...worked, ...listed.filter((entry2) => !mine.has(entry2.task.id))];\n const entry = ({ task, state }, index) => ({\n kind: "item",\n id: `task-${index}`,\n title: `${STATES[state].label} \\xB7 ${task.title}`,\n icon: STATES[state].icon,\n behavior: { kind: "action", onPress: () => open(task.id) }\n });\n const items = shown.slice(0, MENU_LIMIT).map(entry);\n if (worked.length && items.length > worked.length) items.splice(worked.length, 0, { kind: "separator", id: "session-end" });\n if (items.length) items.push({ kind: "separator", id: "tasks-end" });\n const more = shown.length - MENU_LIMIT;\n items.push({ kind: "item", id: "all-tasks", title: more > 0 ? `All tasks (${more} more)` : "All tasks", icon: "ListTodo", behavior: { kind: "action", onPress: () => open() } });\n return {\n title: worked.length ? `ALP tasks: ${done} of ${worked.length} done in this session, ${listed.length} open` : listed.length ? `ALP tasks: ${listed.length} open` : "ALP tasks",\n icon: "ListTodo",\n label: worked.length ? `Tasks \\xB7 ${done}/${worked.length}` : listed.length ? `Tasks \\xB7 ${listed.length}` : "Tasks",\n visible: board?.projectRoot !== null,\n behavior: { kind: "menu", items }\n };\n}\nfunction signature(board, sessions) {\n return JSON.stringify(board && [board.projectRoot !== null, [...sessionWork(board, sessions), ...menuTasks(board.tasks)].map(({ task, state }) => [task.id, state, task.title])]);\n}\nfunction addTaskPills(client) {\n const agents = /* @__PURE__ */ new Map();\n const directories = /* @__PURE__ */ new Map();\n const boards = /* @__PURE__ */ new Map();\n const pills = /* @__PURE__ */ new Map();\n let subscription = null;\n let stopped = false;\n let retry;\n let polling = false;\n let again = false;\n const opener = (agent, directory) => (taskId) => client.openScreen(tasksScreen(agent.workspaceId, directory, taskId));\n const directoryOf = (agent) => {\n let found = directories.get(agent.workspaceId);\n if (!found) {\n found = client.paseo.workspaces.ref(agent.workspaceId).refresh().then((workspace) => workspace?.workspaceDirectory || workspace?.projectRootPath || agent.cwd).catch(() => {\n directories.delete(agent.workspaceId);\n return agent.cwd;\n });\n directories.set(agent.workspaceId, found);\n }\n return found;\n };\n const show = (agent) => __async(null, null, function* () {\n const directory = yield directoryOf(agent);\n if (stopped || pills.has(agent.id) || agents.get(agent.id) !== agent) return;\n const board = boards.get(directory) ?? null;\n try {\n const registration = client.addComposerPill({ id: "alp-tasks", workspaceId: agent.workspaceId, agentId: agent.id, button: taskButton(board, opener(agent, directory), agent.sessions) });\n pills.set(agent.id, { agent, directory, registration, signature: signature(board, agent.sessions) });\n } catch {\n return;\n }\n if (!board) void poll();\n });\n const hide = (id) => {\n agents.delete(id);\n pills.get(id)?.registration.remove();\n pills.delete(id);\n };\n const accept = (snapshot) => {\n const known = agents.get(snapshot.id);\n if (snapshot.provider !== "alp" || !snapshot.workspaceId || snapshot.archivedAt) {\n if (known) hide(snapshot.id);\n return;\n }\n const sessions = [snapshot.persistence?.sessionId, snapshot.id].filter((id) => Boolean(id));\n if (known?.workspaceId === snapshot.workspaceId && known.sessions.join() === sessions.join()) return;\n if (known) hide(snapshot.id);\n const agent = { id: snapshot.id, workspaceId: snapshot.workspaceId, cwd: snapshot.cwd, sessions };\n agents.set(agent.id, agent);\n void show(agent);\n };\n const load = (page) => __async(null, null, function* () {\n const seen = /* @__PURE__ */ new Set();\n for (let current = page; ; ) {\n for (const { agent } of current.entries) {\n seen.add(agent.id);\n accept(agent);\n }\n const cursor = current.pageInfo.nextCursor;\n if (!current.pageInfo.hasMore || !cursor || stopped) break;\n current = yield client.paseo.agents.list({ scope: "active", page: { limit: PAGE, cursor } });\n }\n for (const id of [...agents.keys()]) if (!seen.has(id)) hide(id);\n });\n const watch = () => __async(null, null, function* () {\n try {\n const first = yield client.paseo.agents.list({ scope: "active", page: { limit: PAGE }, subscribe: {} });\n if (stopped) {\n void first.subscription.release().catch(() => {\n });\n return;\n }\n subscription = first.subscription;\n first.subscription.subscribe({\n snapshot: (snapshot) => {\n void load(snapshot).catch(() => {\n });\n },\n update: (message2) => {\n if (message2.type !== "agent_update") return;\n if (message2.payload.kind === "remove") hide(message2.payload.agentId);\n else accept(message2.payload.agent);\n }\n });\n } catch {\n if (!stopped) retry = setTimeout(() => void watch(), POLL_MS2);\n }\n });\n const poll = () => __async(null, null, function* () {\n if (polling) {\n again = true;\n return;\n }\n polling = true;\n try {\n const shown = new Set([...pills.values()].map((pill) => pill.directory));\n for (const directory of shown) {\n if (stopped) return;\n try {\n boards.set(directory, yield client.rpc(tasksList, { directory }));\n } catch {\n continue;\n }\n for (const pill of pills.values()) if (pill.directory === directory) render(pill);\n }\n for (const directory of [...boards.keys()]) if (!shown.has(directory)) boards.delete(directory);\n } finally {\n polling = false;\n if (again && !stopped) {\n again = false;\n void poll();\n }\n }\n });\n const render = (pill) => {\n const board = boards.get(pill.directory) ?? null;\n const next = signature(board, pill.agent.sessions);\n if (next === pill.signature) return;\n pill.signature = next;\n pill.registration.update(taskButton(board, opener(pill.agent, pill.directory), pill.agent.sessions));\n };\n const timer = setInterval(() => void poll(), POLL_MS2);\n void watch();\n return () => {\n stopped = true;\n clearInterval(timer);\n if (retry !== void 0) clearTimeout(retry);\n for (const id of [...pills.keys()]) hide(id);\n void subscription?.release().catch(() => {\n });\n };\n}\n\n// integrations/paseo/client/team-model-settings.tsx\nvar import_react3 = require("react");\nvar import_react_native5 = require("react-native");\nvar import_client2 = require("@getpaseo/plugin/client");\nvar import_ui = require("@getpaseo/plugin/client/ui");\n\n// integrations/paseo/shared/library.ts\nvar import_plugin2 = require("@getpaseo/plugin");\nvar import_zod2 = require("zod");\nvar Directory2 = import_zod2.z.string().min(1).optional();\nvar KindSchema = import_zod2.z.enum(["agents", "skills", "mcp", "hooks", "teams", "providers"]);\nvar ScopeSchema = import_zod2.z.enum(["library", "project"]);\nvar Name = import_zod2.z.string().regex(/^[\\w.-]+$/).refine((name) => name !== "." && name !== "..");\nvar Source = import_zod2.z.enum(["builtin", "library", "project"]);\nvar EntryRowSchema = import_zod2.z.object({\n name: import_zod2.z.string(),\n source: Source,\n overrides: Source.optional(),\n path: import_zod2.z.string().optional(),\n description: import_zod2.z.string().optional(),\n usedBy: import_zod2.z.array(import_zod2.z.string()).optional()\n});\nvar libraryList = (0, import_plugin2.defineRpc)({\n name: "alp.library.list",\n input: import_zod2.z.object({ directory: Directory2, kind: KindSchema }),\n output: import_zod2.z.object({\n projectRoot: import_zod2.z.string().nullable(),\n library: import_zod2.z.string(),\n entries: import_zod2.z.array(EntryRowSchema),\n /**\n * Set when the library can only be looked at from here (ALP remote mode): why, and where to\n * change it. `unlisted` says why there are no entries at all (no granted workspace open).\n */\n readOnly: import_zod2.z.object({ reason: import_zod2.z.string(), unlisted: import_zod2.z.string().optional() }).optional()\n })\n});\nvar libraryGet = (0, import_plugin2.defineRpc)({\n name: "alp.library.get",\n input: import_zod2.z.object({ directory: Directory2, kind: KindSchema, name: Name, scope: ScopeSchema.optional() }),\n output: import_zod2.z.object({\n kind: KindSchema,\n name: import_zod2.z.string(),\n source: Source,\n overrides: Source.optional(),\n content: import_zod2.z.record(import_zod2.z.string(), import_zod2.z.unknown()),\n /** Pass back with a save or delete; a different current revision refuses it. */\n revision: import_zod2.z.string().nullable(),\n usedBy: import_zod2.z.array(import_zod2.z.string()),\n /** Agents: the skills the library gives it by name (role-skills.json). */\n librarySkills: import_zod2.z.array(import_zod2.z.string()).optional(),\n /** ALP remote mode: JSON Pointers of the values `content` holds as a secret marker, not as the value. */\n secrets: import_zod2.z.array(import_zod2.z.string()).optional()\n })\n});\nvar librarySkills = (0, import_plugin2.defineRpc)({\n name: "alp.library.skills",\n input: import_zod2.z.object({ agent: Name, skills: import_zod2.z.array(Name) }),\n output: import_zod2.z.object({ skills: import_zod2.z.array(import_zod2.z.string()) })\n});\nvar librarySave = (0, import_plugin2.defineRpc)({\n name: "alp.library.save",\n input: import_zod2.z.object({\n directory: Directory2,\n kind: KindSchema,\n name: Name,\n scope: ScopeSchema,\n content: import_zod2.z.record(import_zod2.z.string(), import_zod2.z.unknown()),\n /** null creates; a string replaces that revision; omitted overwrites. */\n revision: import_zod2.z.string().nullable().optional()\n }),\n output: import_zod2.z.object({ revision: import_zod2.z.string().nullable(), syncedProjects: import_zod2.z.number().int().nonnegative().optional(), syncErrors: import_zod2.z.array(import_zod2.z.string()).optional() })\n});\nvar libraryDelete = (0, import_plugin2.defineRpc)({\n name: "alp.library.delete",\n input: import_zod2.z.object({ directory: Directory2, kind: KindSchema, name: Name, scope: ScopeSchema, revision: import_zod2.z.string().optional() }),\n /** now: the layer that applies again after removing an override. */\n output: import_zod2.z.object({ removed: import_zod2.z.boolean(), now: Source.optional() })\n});\nvar libraryDuplicate = (0, import_plugin2.defineRpc)({\n name: "alp.library.duplicate",\n input: import_zod2.z.object({ directory: Directory2, kind: KindSchema, from: Name, to: Name, scope: ScopeSchema }),\n output: import_zod2.z.object({ revision: import_zod2.z.string().nullable() })\n});\nvar libraryRename = (0, import_plugin2.defineRpc)({\n name: "alp.library.rename",\n input: import_zod2.z.object({ directory: Directory2, kind: KindSchema, from: Name, to: Name, scope: ScopeSchema }),\n output: import_zod2.z.object({ revision: import_zod2.z.string().nullable() })\n});\nvar libraryTest = (0, import_plugin2.defineRpc)({\n name: "alp.library.test",\n input: import_zod2.z.object({ directory: Directory2, kind: import_zod2.z.enum(["mcp", "hooks", "providers"]), name: Name, scope: ScopeSchema.optional() }),\n output: import_zod2.z.object({\n ok: import_zod2.z.boolean(),\n /** MCP: the server and its tools. */\n server: import_zod2.z.object({ name: import_zod2.z.string().optional(), version: import_zod2.z.string().optional() }).optional(),\n tools: import_zod2.z.array(import_zod2.z.object({ name: import_zod2.z.string(), description: import_zod2.z.string().optional() })).optional(),\n /** Hooks: how the sample run went. */\n exitCode: import_zod2.z.number().nullable().optional(),\n signal: import_zod2.z.string().nullable().optional(),\n timedOut: import_zod2.z.boolean().optional(),\n wouldBlock: import_zod2.z.boolean().optional(),\n stdout: import_zod2.z.string().optional(),\n stderr: import_zod2.z.string().optional(),\n durationMs: import_zod2.z.number().optional(),\n /** Providers: who the ACP agent says it is, and what it supports. */\n protocolVersion: import_zod2.z.number().optional(),\n agent: import_zod2.z.object({ name: import_zod2.z.string().optional(), title: import_zod2.z.string().optional(), version: import_zod2.z.string().optional() }).optional(),\n loadSession: import_zod2.z.boolean().optional(),\n mcpHttp: import_zod2.z.boolean().optional(),\n authMethods: import_zod2.z.array(import_zod2.z.string()).optional()\n })\n});\nvar LanguageSettingSchema = import_zod2.z.object({\n language: import_zod2.z.string().nullable(),\n applies: import_zod2.z.string(),\n default: import_zod2.z.string(),\n /** Why it cannot be changed from here (ALP remote mode). */\n readOnly: import_zod2.z.string().optional()\n});\nvar languageGet = (0, import_plugin2.defineRpc)({\n name: "alp.settings.language.get",\n input: import_zod2.z.object({}),\n output: LanguageSettingSchema\n});\nvar languageSet = (0, import_plugin2.defineRpc)({\n name: "alp.settings.language.set",\n input: import_zod2.z.object({ language: import_zod2.z.string().trim().min(1).max(40).nullable() }),\n output: LanguageSettingSchema\n});\nvar libraryModels = (0, import_plugin2.defineRpc)({\n name: "alp.library.models",\n input: import_zod2.z.object({}),\n output: import_zod2.z.object({ models: import_zod2.z.array(import_zod2.z.object({ id: import_zod2.z.string(), label: import_zod2.z.string(), efforts: import_zod2.z.array(import_zod2.z.string()), effort: import_zod2.z.string().optional() })) })\n});\n\n// integrations/paseo/shared/team-models.ts\nvar MODEL_PRESETS = [\n { label: "Claude only", value: "claude" },\n { label: "Codex only", value: "codex" },\n { label: "OpenCode only", value: "opencode" },\n { label: "Antigravity only", value: "antigravity" },\n { label: "Mix \\xB7 Claude + Codex", value: "mix" }\n];\nfunction presetTeamModels(team, preset, models) {\n const next = JSON.parse(JSON.stringify(team));\n const find = (provider) => models.find((model) => provider === "opencode" ? model.id === "acp:opencode" || model.id.startsWith("acp:opencode/") : model.id.startsWith(`${provider}:`));\n const primary = find(preset === "mix" ? "claude" : preset);\n const secondary = preset === "mix" ? find("codex") : primary;\n if (!primary || !secondary) throw new Error("No models available for this preset. Configure the provider in Settings first.");\n const assign = (target, model) => {\n target.model = model.id;\n if (model.effort) target.thinking = model.effort;\n else delete target.thinking;\n };\n for (const [name, member] of Object.entries(next.members ?? {})) {\n if (name !== "oracle") assign(member, name === next.main ? primary : secondary);\n }\n if (next.supervisor) assign(next.supervisor, secondary);\n if (next.members?.oracle) {\n next.oracleModels = [.../* @__PURE__ */ new Set([primary.id, secondary.id])];\n next.oracleThinking = Object.fromEntries([primary, secondary].filter((model) => model.effort).map((model) => [model.id, model.effort]));\n }\n next.modelSetup = { mode: "default", preset };\n return next;\n}\nfunction modelSetupFor(team, models) {\n if (team.modelSetup) return team.modelSetup;\n for (const { value } of MODEL_PRESETS) {\n let expected;\n try {\n expected = presetTeamModels(team, value, models);\n } catch {\n continue;\n }\n const same = (a, b) => a.model === b.model && a.thinking === b.thinking;\n if (!Object.entries(team.members ?? {}).filter(([name]) => name !== "oracle").every(([name, member]) => same(member, expected.members[name]))) continue;\n if (team.supervisor && !same(team.supervisor, expected.supervisor)) continue;\n if (team.members?.oracle && (JSON.stringify(team.oracleModels) !== JSON.stringify(expected.oracleModels) || expected.oracleModels.some((id) => (team.oracleThinking?.[id] ?? team.oracleThinking?.[id.split(":")[0]]) !== expected.oracleThinking?.[id]))) continue;\n return { mode: "default", preset: value };\n }\n return { mode: "custom" };\n}\n\n// integrations/paseo/client/side-nav.tsx\nvar import_react_native3 = require("@getpaseo/plugin/client/react-native");\nvar import_react2 = require("react");\nvar import_react_native4 = require("react-native");\nvar import_jsx_runtime2 = require("react/jsx-runtime");\nvar hovered2 = (state) => !!state.hovered;\nvar COLLAPSE_BELOW = 640;\nvar EXPANDED = 216;\nvar COLLAPSED = 52;\nfunction SideNavLayout(props) {\n const { theme, compact, groups, active, onSelect } = props;\n const styles = (0, import_react2.useMemo)(() => layoutStyles(theme), [theme]);\n const [width, setWidth] = (0, import_react2.useState)(0);\n const [choice, setChoice] = (0, import_react2.useState)(props.initialCollapsed);\n const [open, setOpen] = (0, import_react2.useState)(false);\n const collapsed = choice ?? (width > 0 && width < COLLAPSE_BELOW);\n const select = (item, child) => {\n onSelect(item, child);\n setOpen(false);\n };\n const aside = (mode) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(\n Aside,\n {\n styles,\n theme,\n title: props.title,\n subtitle: props.subtitle,\n groups,\n active,\n onSelect: select,\n collapsed: mode === "fixed" && collapsed,\n onToggle: mode === "fixed" ? () => setChoice(!collapsed) : () => setOpen(false),\n overlay: mode === "overlay"\n }\n );\n return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native4.View, { style: props.embedded ? { width: "100%" } : styles.root, onLayout: (event) => setWidth(event.nativeEvent.layout.width), children: [\n !props.embedded && !compact ? aside("fixed") : null,\n /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native4.View, { style: props.embedded ? { minWidth: 0 } : styles.main, children: [\n /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native4.View, { style: [styles.header, props.embedded ? { paddingHorizontal: 0, paddingTop: 0 } : null], children: [\n /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native4.View, { style: styles.headerRow, children: [\n compact && !props.embedded ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.Pressable, { accessibilityRole: "button", accessibilityLabel: "Open navigation", onPress: () => setOpen(true), style: styles.iconButton, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native3.Icon, { name: "Menu", size: 18, color: theme.colors.foreground }) }) : null,\n /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native4.View, { style: styles.crumbs, children: [\n props.breadcrumb.map((part, index) => [\n index ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.Text, { style: styles.crumbSeparator, children: "/" }, `separator-${index}`) : null,\n /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.Text, { style: index === props.breadcrumb.length - 1 ? styles.crumbCurrent : styles.crumb, numberOfLines: 1, children: part }, `${index}-${part}`)\n ]),\n props.badges\n ] }),\n props.actions ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.View, { style: styles.actions, children: props.actions }) : null\n ] }),\n props.tabs?.length ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native3.ScrollView, { horizontal: true, showsHorizontalScrollIndicator: false, contentContainerStyle: styles.tabs, children: props.tabs.map((tab) => {\n const on = tab.key === props.tab;\n return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.Pressable, { accessibilityRole: "tab", accessibilityLabel: tab.label, accessibilityState: { selected: on }, onPress: () => props.onTab?.(tab.key), style: [styles.tab, on ? styles.tabOn : null], children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native4.Text, { style: on ? styles.tabTextOn : styles.tabText, children: [\n tab.label,\n tab.count !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.Text, { style: styles.tabCount, children: ` ${tab.count}` }) : null\n ] }) }, tab.key);\n }) }) : null\n ] }),\n props.embedded ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.View, { style: [styles.bodyContent, { paddingHorizontal: 0 }], children: props.children }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native3.ScrollView, { style: styles.body, contentContainerStyle: styles.bodyContent, children: props.children }),\n props.footer ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.View, { style: [styles.footer, props.embedded ? { paddingHorizontal: 0 } : null], children: props.footer }) : null\n ] }),\n !props.embedded && compact && open ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native4.View, { style: styles.overlay, children: [\n aside("overlay"),\n /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.Pressable, { accessibilityRole: "button", accessibilityLabel: "Close navigation", onPress: () => setOpen(false), style: styles.scrim })\n ] }) : null\n ] });\n}\nfunction Aside({ styles, theme, title, subtitle, groups, active, onSelect, collapsed, onToggle, overlay }) {\n const { colors } = theme;\n const [opened, setOpened] = (0, import_react2.useState)({});\n const tone = (value) => value === "accent" ? colors.accent : value === "warning" ? colors.statusWarning : colors.border;\n return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native4.View, { style: [styles.aside, { width: collapsed ? COLLAPSED : EXPANDED }, overlay ? styles.asideOverlay : null], children: [\n /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native4.View, { style: [styles.asideHeader, collapsed ? styles.asideHeaderCollapsed : null], children: [\n !collapsed ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native4.View, { style: styles.asideTitleBox, children: [\n /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.Text, { style: styles.asideTitle, numberOfLines: 1, children: title }),\n subtitle ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.Text, { style: styles.asideSubtitle, numberOfLines: 1, children: subtitle }) : null\n ] }) : null,\n /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.Pressable, { accessibilityRole: "button", accessibilityLabel: overlay ? "Close navigation" : collapsed ? "Expand navigation" : "Collapse navigation", onPress: onToggle, style: styles.iconButton, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native3.Icon, { name: overlay ? "X" : collapsed ? "PanelLeftOpen" : "PanelLeftClose", size: 16, color: colors.foregroundMuted }) })\n ] }),\n /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native3.ScrollView, { contentContainerStyle: styles.asideList, children: groups.map((group) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native4.View, { style: styles.group, children: [\n !collapsed ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.Text, { style: styles.groupLabel, children: group.label }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.View, { style: styles.groupRule }),\n group.items.map((item) => {\n const selected = active.item === item.key;\n const expanded = !collapsed && (opened[item.key] ?? selected) && !!item.children?.length;\n return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native4.View, { children: [\n /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(\n import_react_native4.Pressable,\n {\n accessibilityRole: "button",\n accessibilityLabel: item.label,\n accessibilityState: { selected: selected && !active.child },\n onPress: () => {\n onSelect(item.key);\n setOpened((current) => ({ ...current, [item.key]: true }));\n },\n style: (state) => [styles.item, collapsed ? styles.itemCollapsed : null, selected ? styles.itemOn : hovered2(state) ? styles.itemHover : null],\n children: [\n selected ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.View, { style: styles.itemBar }) : null,\n /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native3.Icon, { name: item.icon, size: 16, color: selected ? colors.accent : colors.foregroundMuted }),\n !collapsed ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.Text, { style: [styles.itemLabel, selected ? styles.itemLabelOn : null], numberOfLines: 1, children: item.label }) : null,\n !collapsed && item.count !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.Text, { style: styles.count, children: item.count }) : null,\n !collapsed && item.children?.length ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.Pressable, { accessibilityRole: "button", accessibilityLabel: `${expanded ? "Hide" : "Show"} ${item.label}`, hitSlop: 8, onPress: () => setOpened((current) => ({ ...current, [item.key]: !expanded })), children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native3.Icon, { name: expanded ? "ChevronDown" : "ChevronRight", size: 14, color: colors.foregroundMuted }) }) : null\n ]\n }\n ),\n expanded ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.View, { style: styles.children, children: item.children.map((child) => {\n const on = selected && active.child === child.key;\n return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(\n import_react_native4.Pressable,\n {\n accessibilityRole: "button",\n accessibilityLabel: `${item.label} ${child.label}`,\n accessibilityState: { selected: on },\n onPress: () => onSelect(item.key, child.key),\n style: (state) => [styles.child, on ? styles.childOn : hovered2(state) ? styles.itemHover : null],\n children: [\n /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.View, { style: [styles.dot, { backgroundColor: tone(child.tone) }] }),\n /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.Text, { style: [styles.childLabel, on ? styles.itemLabelOn : null], numberOfLines: 1, children: child.label }),\n child.hint ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.Text, { style: styles.childHint, numberOfLines: 1, children: child.hint }) : null\n ]\n },\n child.key\n );\n }) }) : null\n ] }, item.key);\n })\n ] }, group.key)) })\n ] });\n}\nfunction Pill({ theme, label, tone = "muted" }) {\n const { colors } = theme;\n const color = tone === "accent" ? colors.accent : tone === "success" ? colors.statusSuccess : tone === "warning" ? colors.statusWarning : tone === "danger" ? colors.statusDanger : colors.foregroundMuted;\n return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.View, { style: { borderRadius: 999, borderWidth: 1, borderColor: tone === "muted" ? colors.border : color, paddingHorizontal: 7, paddingVertical: 1, alignSelf: "center" }, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.Text, { style: { color, fontSize: 11, fontWeight: "500" }, children: label }) });\n}\nfunction Button({ theme, label, onPress, kind = "plain", icon, disabled, accessibilityLabel }) {\n const { colors } = theme;\n const color = kind === "primary" ? colors.accentForeground : kind === "danger" ? colors.statusDanger : colors.foreground;\n return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(\n import_react_native4.Pressable,\n {\n accessibilityRole: "button",\n accessibilityLabel: accessibilityLabel ?? label,\n disabled,\n onPress,\n style: (state) => ({\n flexDirection: "row",\n alignItems: "center",\n gap: 6,\n borderRadius: 8,\n paddingHorizontal: 12,\n paddingVertical: 7,\n opacity: disabled ? 0.5 : 1,\n backgroundColor: kind === "primary" ? colors.accent : hovered2(state) ? colors.surface2 : colors.surface1,\n borderWidth: kind === "primary" ? 0 : 1,\n borderColor: kind === "danger" ? colors.statusDanger : colors.border\n }),\n children: [\n icon ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native3.Icon, { name: icon, size: 14, color }) : null,\n /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.Text, { style: { color, fontSize: 13, fontWeight: kind === "primary" ? "600" : "500" }, children: label })\n ]\n }\n );\n}\nfunction layoutStyles(theme) {\n const { colors } = theme;\n return {\n root: { flex: 1, flexDirection: "row", backgroundColor: colors.surface0, minHeight: 560, borderWidth: 1, borderColor: colors.border, borderRadius: 12, overflow: "hidden" },\n aside: { backgroundColor: colors.surface1, borderRightWidth: 1, borderRightColor: colors.border },\n asideOverlay: { height: "100%", shadowColor: "#000", shadowOpacity: 0.2, shadowRadius: 16 },\n asideHeader: { flexDirection: "row", alignItems: "center", justifyContent: "space-between", paddingHorizontal: 12, paddingVertical: 12, borderBottomWidth: 1, borderBottomColor: colors.border, gap: 8 },\n asideHeaderCollapsed: { justifyContent: "center", paddingHorizontal: 0 },\n asideTitleBox: { flex: 1, minWidth: 0 },\n asideTitle: { color: colors.foreground, fontSize: 14, fontWeight: "600" },\n asideSubtitle: { color: colors.foregroundMuted, fontSize: 11, marginTop: 1 },\n asideList: { paddingVertical: 8, gap: 10 },\n group: { gap: 1 },\n groupLabel: { color: colors.foregroundMuted, fontSize: 11, fontWeight: "600", letterSpacing: 0.4, textTransform: "uppercase", paddingHorizontal: 14, paddingBottom: 4 },\n groupRule: { height: 1, backgroundColor: colors.border, marginHorizontal: 12, marginBottom: 4 },\n item: { flexDirection: "row", alignItems: "center", gap: 10, marginHorizontal: 6, paddingHorizontal: 8, paddingVertical: 7, borderRadius: 7 },\n itemCollapsed: { justifyContent: "center", paddingHorizontal: 0 },\n itemOn: { backgroundColor: colors.surface2 },\n itemHover: { backgroundColor: colors.surface2 },\n itemBar: { position: "absolute", left: -6, top: 6, bottom: 6, width: 3, borderRadius: 2, backgroundColor: colors.accent },\n itemLabel: { flex: 1, color: colors.foreground, fontSize: 13 },\n itemLabelOn: { color: colors.foreground, fontWeight: "600" },\n count: { color: colors.foregroundMuted, fontSize: 11, fontVariant: ["tabular-nums"] },\n children: { marginLeft: 22, borderLeftWidth: 1, borderLeftColor: colors.border, marginVertical: 2, paddingLeft: 4 },\n child: { flexDirection: "row", alignItems: "center", gap: 8, marginRight: 6, paddingHorizontal: 8, paddingVertical: 5, borderRadius: 6 },\n childOn: { backgroundColor: colors.surface2 },\n childLabel: { flex: 1, color: colors.foreground, fontSize: 12.5 },\n childHint: { color: colors.foregroundMuted, fontSize: 11 },\n dot: { width: 6, height: 6, borderRadius: 3 },\n main: { flex: 1, minWidth: 0 },\n header: { borderBottomWidth: 1, borderBottomColor: colors.border, paddingHorizontal: 20, paddingTop: 14, gap: 10 },\n headerRow: { flexDirection: "row", alignItems: "center", gap: 10, minHeight: 32 },\n crumbs: { flex: 1, minWidth: 0, flexDirection: "row", alignItems: "center", gap: 8, flexWrap: "wrap" },\n crumb: { color: colors.foregroundMuted, fontSize: 13 },\n crumbSeparator: { color: colors.foregroundMuted, fontSize: 13, opacity: 0.6 },\n crumbCurrent: { color: colors.foreground, fontSize: 16, fontWeight: "600" },\n actions: { flexDirection: "row", gap: 8, alignItems: "center" },\n tabs: { flexDirection: "row", gap: 4 },\n tab: { paddingHorizontal: 10, paddingVertical: 8, borderBottomWidth: 2, borderBottomColor: "transparent" },\n tabOn: { borderBottomColor: colors.accent },\n tabText: { color: colors.foregroundMuted, fontSize: 13 },\n tabTextOn: { color: colors.foreground, fontSize: 13, fontWeight: "600" },\n tabCount: { color: colors.foregroundMuted, fontSize: 11 },\n body: { flex: 1 },\n bodyContent: { padding: 20, gap: 16 },\n footer: { flexDirection: "row", alignItems: "center", gap: 10, paddingHorizontal: 20, paddingVertical: 12, borderTopWidth: 1, borderTopColor: colors.border, backgroundColor: colors.surface1 },\n iconButton: { padding: 6, borderRadius: 6 },\n overlay: { position: "absolute", left: 0, top: 0, right: 0, bottom: 0, flexDirection: "row" },\n scrim: { flex: 1, backgroundColor: "rgba(0,0,0,0.25)" }\n };\n}\n\n// integrations/paseo/client/team-model-settings.tsx\nvar import_jsx_runtime3 = require("react/jsx-runtime");\nvar clone = (team) => JSON.parse(JSON.stringify(team));\nfunction TeamModelSettings({ team, theme, onChange }) {\n const readModels = (0, import_client2.useRpc)(libraryModels);\n const [models, setModels] = (0, import_react3.useState)([]);\n const [error, setError] = (0, import_react3.useState)("");\n const [customFields, setCustomFields] = (0, import_react3.useState)({});\n const setup = modelSetupFor(team, models);\n const mode = setup.mode;\n const preset = setup.preset ?? "mix";\n (0, import_react3.useEffect)(() => {\n let live = true;\n readModels({}).then((result) => {\n if (live) {\n setModels(result.models);\n setError("");\n }\n }).catch((cause) => {\n if (live) setError(String(cause.message ?? cause));\n });\n return () => {\n live = false;\n };\n }, [readModels]);\n const edit = (work) => {\n const next = clone(team);\n next.modelSetup = { mode: "custom" };\n work(next);\n onChange(next);\n setError("");\n };\n const selectPreset = (value) => {\n try {\n onChange(presetTeamModels(team, value, models));\n setCustomFields({});\n setError("");\n } catch (cause) {\n setError(cause instanceof Error ? cause.message : String(cause));\n }\n };\n const chooseModel = (label, value, set) => {\n const known = models.find((model) => model.id === value);\n const options = [...label.startsWith("oracle-") ? [] : [{ label: "Inherit", value: "" }], ...models.map((model) => ({ value: model.id, label: model.label }))];\n if (value && !known) options.push({ label: value, value });\n options.push({ label: "Custom model ID", value: "__custom" });\n return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [\n /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_ui.SettingsSelect, { label: "Model", value: customFields[label] ? "__custom" : value, options, onValueChange: (id) => {\n setCustomFields((previous) => ({ ...previous, [label]: id === "__custom" }));\n if (id !== "__custom") edit((next) => set(next, id, models.find((model) => model.id === id)?.effort));\n } }),\n customFields[label] || value && !known ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_ui.SettingsInput, { label: "Custom model ID", hint: "claude:model, codex:model, antigravity:model or acp:provider/model", initialValue: value, onChangeText: (id) => edit((next) => set(next, id.trim())) }, `${label}-custom`) : null\n ] });\n };\n const effort = (model, value, set) => {\n const known = models.find((choice) => choice.id === model);\n const values = known ? known.efforts : ["none", "off", "low", "medium", "high", "xhigh", "max", "ultra", "ultracode"];\n const options = [{ label: "Inherit", value: "" }, ...[.../* @__PURE__ */ new Set([...values, ...value ? [value] : []])].map((value2) => ({ label: value2, value: value2 }))];\n return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_ui.SettingsSelect, { label: "Effort", value, options, onValueChange: (value2) => edit((next) => set(next, value2)) });\n };\n const assign = (target, id, thinking) => {\n if (id) target.model = id;\n else delete target.model;\n if (thinking) target.thinking = thinking;\n else delete target.thinking;\n };\n const setEffort = (target, value) => {\n if (value) target.thinking = value;\n else delete target.thinking;\n };\n const lenses = team.oracleModels ?? ["claude:claude-fable-5-1", "codex:gpt-6-astra"];\n return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [\n /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_ui.SettingsSection, { title: "Model setup", children: [\n /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_ui.SettingsSelect, { label: "Mode", value: mode, options: [{ label: "Default presets", value: "default" }, { label: "Custom", value: "custom" }], onValueChange: (value) => value === "default" ? selectPreset(preset) : edit(() => {\n }) }),\n mode === "default" ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_ui.SettingsSelect, { label: "Preset", value: preset, options: MODEL_PRESETS, onValueChange: selectPreset }) : null,\n /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_ui.SettingsRow, { label: "Save with template", hint: "Save writes these model choices into settings.json for this team immediately. Project template overrides still apply to Host templates." }),\n error ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native5.Text, { accessibilityRole: "alert", style: { color: theme?.colors.statusDanger }, children: error }) : null\n ] }),\n mode === "default" ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_ui.SettingsSection, { title: "Preset models", children: [\n Object.entries(team.members ?? {}).filter(([name]) => name !== "oracle").map(([name, member]) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_ui.SettingsRow, { label: name, hint: member.model }, name)),\n team.supervisor ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_ui.SettingsRow, { label: "Supervisor", hint: team.supervisor.model }) : null,\n team.members?.oracle ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_ui.SettingsRow, { label: "Oracle", hint: lenses.join(", ") }) : null\n ] }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react3.Fragment, { children: [\n Object.entries(team.members ?? {}).filter(([name]) => name !== "oracle").map(([name, member]) => {\n const config = member;\n return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_ui.SettingsSection, { title: name === team.main ? `${name} \\xB7 main` : name, children: [\n chooseModel(name, config.model ?? "", (next, id, effort2) => assign(next.members[name], id, effort2)),\n effort(config.model ?? team.members[team.main]?.model ?? "", config.thinking ?? "", (next, value) => setEffort(next.members[name], value))\n ] }, name);\n }),\n team.supervisor ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_ui.SettingsSection, { title: "Supervisor", children: [\n chooseModel("supervisor", team.supervisor.model ?? "", (next, id, effort2) => assign(next.supervisor, id, effort2)),\n effort(team.supervisor.model ?? "", team.supervisor.thinking ?? "", (next, value) => setEffort(next.supervisor, value))\n ] }) : null,\n team.members?.oracle ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [\n lenses.map((id, index) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_ui.SettingsSection, { title: `Oracle ${index + 1}`, children: [\n chooseModel(`oracle-${index}`, id, (next, value, effort2) => {\n next.oracleModels = [...lenses];\n next.oracleModels[index] = value;\n next.oracleThinking ?? (next.oracleThinking = {});\n delete next.oracleThinking[id];\n if (effort2) next.oracleThinking[value] = effort2;\n }),\n effort(id, team.oracleThinking?.[id] ?? team.oracleThinking?.[id.split(":")[0]] ?? "", (next, value) => {\n next.oracleThinking ?? (next.oracleThinking = {});\n delete next.oracleThinking[id.split(":")[0]];\n if (value) next.oracleThinking[id] = value;\n else delete next.oracleThinking[id];\n }),\n theme && lenses.length > 1 ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Button, { theme, label: "Remove model", onPress: () => edit((next) => {\n next.oracleModels = lenses.filter((_, i) => i !== index);\n }) }) : null\n ] }, index)),\n theme ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Button, { theme, label: "Add oracle model", onPress: () => edit((next) => {\n next.oracleModels = [...lenses, ""];\n setCustomFields((previous) => ({ ...previous, [`oracle-${lenses.length}`]: true }));\n }) }) : null\n ] }) : null\n ] }, "custom-models"),\n JSON.stringify(team).includes("antigravity:") ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_ui.SettingsSection, { title: "Antigravity", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_ui.SettingsRow, { label: "Advisory roles", hint: \'Reviewer, Oracle and Supervisor require readOnlyMode: "instructions" in the Antigravity provider. Review copies and custom permission rules are unsupported.\' }) }) : null\n ] });\n}\n\n// integrations/paseo/client/library.tsx\nvar import_client3 = require("@getpaseo/plugin/client");\nvar import_react_native6 = require("@getpaseo/plugin/client/react-native");\nvar import_ui2 = require("@getpaseo/plugin/client/ui");\nvar import_react4 = require("react");\nvar import_react_native7 = require("react-native");\nvar import_jsx_runtime4 = require("react/jsx-runtime");\nvar KINDS = [\n { kind: "teams", title: "Teams", one: "team", icon: "Users", group: "Organisation" },\n { kind: "agents", title: "Agents", one: "agent", icon: "Bot", group: "Organisation" },\n { kind: "skills", title: "Skills", one: "skill", icon: "BookOpen", group: "Capabilities" },\n { kind: "mcp", title: "MCP servers", one: "MCP server", icon: "Plug", group: "Capabilities" },\n { kind: "hooks", title: "Hooks", one: "hook", icon: "Webhook", group: "Capabilities" },\n // ACP agents (ALPD \xA746): in the library only, so the project panel leaves them out.\n { kind: "providers", title: "Providers", one: "provider", icon: "Cpu", group: "Runtimes" }\n];\nvar shownIn = (scope) => KINDS.filter((item) => scope === "library" || item.kind !== "providers");\nvar kindOf = (kind) => KINDS.find((item) => item.kind === kind);\nvar HOOK_EVENTS = ["session.start", "turn.end", "assignment.start", "assignment.end", "handoff", "task.close", "merge"];\nvar BLOCKING_EVENTS = ["handoff", "task.close", "merge"];\nvar ROLES = ["lead", "peer", "advisor", "reviewer"];\nvar MODES = ["", "read-only", "workspace-write", "full-access"];\nvar NAME = /^[\\w.-]+$/;\nvar clone2 = (value) => JSON.parse(JSON.stringify(value));\nvar message = (cause) => cause instanceof Error ? cause.message : String(cause);\nvar sourceLabel = (source) => source === "builtin" ? "built-in" : source;\nvar sourceTone = (source) => source === "project" ? "warning" : source === "library" ? "accent" : "muted";\nvar LANGUAGES = [\n { label: "Ti\\u1EBFng Vi\\u1EC7t", value: "Vietnamese" },\n { label: "English", value: "English" },\n { label: "\\u65E5\\u672C\\u8A9E", value: "Japanese" },\n { label: "\\uD55C\\uAD6D\\uC5B4", value: "Korean" },\n { label: "\\u4E2D\\u6587", value: "Chinese" },\n { label: "Fran\\xE7ais", value: "French" },\n { label: "Deutsch", value: "German" },\n { label: "Espa\\xF1ol", value: "Spanish" }\n];\nfunction LibrarySettings({ theme, layout }) {\n return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(LibraryManager, { theme, compact: layout.compact, scope: "library" });\n}\nfunction TeamsSettings({ theme, layout }) {\n return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(LibraryManager, { theme, compact: layout.compact, scope: "library", initialKind: "teams", embedded: true });\n}\nfunction AgentsSettings({ theme, layout }) {\n return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(LibraryManager, { theme, compact: layout.compact, scope: "library", initialKind: "agents", embedded: true });\n}\nfunction SkillsSettings({ theme, layout }) {\n return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(LibraryManager, { theme, compact: layout.compact, scope: "library", initialKind: "skills", embedded: true });\n}\nfunction HooksSettings({ theme, layout }) {\n return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(LibraryManager, { theme, compact: layout.compact, scope: "library", initialKind: "hooks", embedded: true });\n}\nfunction McpSettings({ theme, layout }) {\n return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(LibraryManager, { theme, compact: layout.compact, scope: "library", initialKind: "mcp", embedded: true });\n}\nfunction ProjectLibraryPanel({ theme, layout, workspaceId }) {\n const directory = (0, import_client3.useWorkspace)(workspaceId, (workspace) => workspace.directory || workspace.projectRootPath);\n if (!directory) return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native7.View, { style: { padding: 16 }, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native7.Text, { style: { color: theme.colors.foregroundMuted }, children: "This panel needs a workspace." }) });\n return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(LibraryManager, { theme, compact: layout.compact, scope: "project", directory });\n}\nfunction LibraryManager({ theme, compact, scope, directory, embedded = false, initialKind = "teams" }) {\n const list = (0, import_client3.useRpc)(libraryList);\n const get = (0, import_client3.useRpc)(libraryGet);\n const save = (0, import_client3.useRpc)(librarySave);\n const remove = (0, import_client3.useRpc)(libraryDelete);\n const duplicate = (0, import_client3.useRpc)(libraryDuplicate);\n const probe = (0, import_client3.useRpc)(libraryTest);\n const give = (0, import_client3.useRpc)(librarySkills);\n const readLanguage = (0, import_client3.useRpc)(languageGet);\n const writeLanguage = (0, import_client3.useRpc)(languageSet);\n const toast = (0, import_react_native6.useToast)();\n const [language, setLanguageState] = (0, import_react4.useState)(null);\n const [lists, setLists] = (0, import_react4.useState)({});\n const [where, setWhere] = (0, import_react4.useState)(null);\n const [error, setError] = (0, import_react4.useState)(null);\n const [selection, setSelection] = (0, import_react4.useState)({ kind: initialKind });\n const [entry, setEntry] = (0, import_react4.useState)(null);\n const [tick, setTick] = (0, import_react4.useState)(0);\n const refresh = (0, import_react4.useCallback)(() => setTick((value) => value + 1), []);\n const base = directory ? { directory } : {};\n (0, import_react4.useEffect)(() => {\n let live = true;\n Promise.all(KINDS.map(({ kind }) => list({ ...base, kind }).then((result) => [kind, result]))).then((results) => {\n if (!live) return;\n setLists(Object.fromEntries(results.map(([kind, result]) => [kind, result.entries])));\n setWhere({ projectRoot: results[0][1].projectRoot, library: results[0][1].library, ...results[0][1].readOnly ? { readOnly: results[0][1].readOnly } : {} });\n setError(null);\n }).catch((cause) => {\n if (live) setError(message(cause));\n });\n return () => {\n live = false;\n };\n }, [list, directory, tick]);\n (0, import_react4.useEffect)(() => {\n if (scope !== "library") return;\n let live = true;\n readLanguage({}).then((result) => {\n if (live) setLanguageState(result);\n }).catch((cause) => {\n if (live) setError(message(cause));\n });\n return () => {\n live = false;\n };\n }, [readLanguage, scope, tick]);\n (0, import_react4.useEffect)(() => {\n if (!selection.name || selection.creating) {\n setEntry(null);\n return;\n }\n let live = true;\n get({ ...base, kind: selection.kind, name: selection.name }).then((result) => {\n if (live) setEntry(result);\n }).catch((cause) => {\n if (live) {\n toast.error(message(cause));\n setSelection({ kind: selection.kind });\n }\n });\n return () => {\n live = false;\n };\n }, [selection, get, directory, tick]);\n const run = (0, import_react4.useCallback)((work, done) => __async(null, null, function* () {\n try {\n yield work();\n toast.show(done, { variant: "success" });\n refresh();\n return true;\n } catch (cause) {\n toast.error(message(cause));\n return false;\n }\n }), [toast, refresh]);\n const actions = {\n select: (next) => setSelection(next),\n duplicate: (kind, from, to) => run(() => duplicate({ ...base, kind, from, to, scope }), `Copied ${from} to ${to}`),\n // In the project panel: copy what applies into .alp/, or drop the project\'s copy.\n override: (kind, name) => run(() => duplicate({ ...base, kind, from: name, to: name, scope: "project" }), `${name} is now overridden in this project`),\n useLibrary: (kind, name) => run(() => remove({ ...base, kind, name, scope: "project" }), `${name} follows the library again`),\n save: (kind, name, content, revision, creating) => __async(null, null, function* () {\n try {\n const result = yield save({ ...base, kind, name, scope, content, revision });\n const synced = result.syncedProjects ?? 0;\n toast.show(`Saved ${name}${synced ? ` \\xB7 Updated settings in ${synced} project${synced === 1 ? "" : "s"}` : ""}`, { variant: "success" });\n if (result.syncErrors?.length) toast.error(`Template saved, but some project settings could not be updated: ${result.syncErrors.join("; ")}`);\n refresh();\n if (creating) setSelection({ kind, name });\n return true;\n } catch (cause) {\n toast.error(message(cause));\n return false;\n }\n }),\n giveSkills: (agent, skills) => run(() => give({ agent, skills }), `Saved the skills of ${agent}`),\n setLanguage: (next) => run(() => writeLanguage({ language: next }), next ? `Agents now write to you in ${next}` : "Agents write to you in the default language again"),\n remove: (kind, name, revision) => __async(null, null, function* () {\n const removed = yield run(() => remove({ ...base, kind, name, scope, ...revision ? { revision } : {} }), `Removed ${name}`);\n if (removed) setSelection({ kind });\n return removed;\n }),\n test: (kind, name) => __async(null, null, function* () {\n try {\n return yield probe({ ...base, kind, name });\n } catch (cause) {\n toast.error(message(cause));\n return null;\n }\n })\n };\n const shown = selection.name && !selection.creating && entry?.name !== selection.name ? { kind: selection.kind } : selection;\n return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(LibraryWorkspace, { theme, compact, scope, where, lists, error, selection: shown, entry: shown.name ? entry : null, actions, language, embedded });\n}\nfunction navGroups(scope, lists) {\n const groups = scope === "library" ? [{ key: "General", label: "General", items: [{ key: "language", label: "Language", icon: "Languages" }] }] : [];\n for (const item of shownIn(scope)) {\n let group = groups.find((candidate) => candidate.label === item.group);\n if (!group) groups.push(group = { key: item.group, label: item.group, items: [] });\n const rows = lists[item.kind];\n group.items.push({\n key: item.kind,\n label: item.title,\n icon: item.icon,\n ...rows ? { count: rows.length } : {},\n children: (rows ?? []).map((row) => ({ key: row.name, label: row.name, tone: sourceTone(row.source) }))\n });\n }\n return groups;\n}\nfunction LibraryWorkspace({ theme, compact, scope, where, lists, error, selection, entry, actions, initialCollapsed, language, embedded }) {\n const styles = (0, import_react4.useMemo)(() => makeStyles2(theme, compact), [theme, compact]);\n const title = scope === "library" ? "ALP library" : "ALP project";\n const subtitle = scope === "library" ? where?.library : where?.projectRoot ?? void 0;\n const groups = navGroups(scope, lists);\n const onSelect = (kind2, name) => actions.select(kind2 === "language" ? { kind: kind2 } : { kind: kind2, ...name ? { name } : {} });\n if (scope === "project" && where?.readOnly?.unlisted) {\n return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native7.View, { style: styles.screen, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native7.Text, { style: styles.muted, children: where.readOnly.unlisted }) });\n }\n if (scope === "project" && where && !where.projectRoot) {\n return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native7.View, { style: styles.screen, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native7.Text, { style: styles.muted, children: "This workspace is not an ALP project. Run alp init to start one." }) });\n }\n if (selection.kind === "language") {\n return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(LanguageSettings, { theme, compact, language: language ?? null, error, actions, layout: { title, subtitle, groups, onSelect, initialCollapsed, embedded }, styles });\n }\n const kind = kindOf(selection.kind);\n if (where?.readOnly && (selection.name || selection.creating)) {\n const viewed = !where.readOnly.unlisted && entry && entry.name === selection.name && entry.kind === selection.kind ? entry : null;\n return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(\n SideNavLayout,\n {\n theme,\n compact,\n title,\n subtitle,\n groups,\n active: { item: selection.kind, ...selection.name ? { child: selection.name } : {} },\n onSelect,\n initialCollapsed,\n embedded,\n breadcrumb: [kind.title, selection.name ?? "Read only"],\n badges: viewed ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Pill, { theme, label: sourceLabel(viewed.source), tone: sourceTone(viewed.source) }) : null,\n actions: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Button, { theme, icon: "ArrowLeft", label: `All ${kind.title.toLowerCase()}`, onPress: () => actions.select({ kind: selection.kind }) }),\n children: [\n /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native7.Text, { style: styles.muted, children: where.readOnly.reason }),\n error || where.readOnly.unlisted ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native7.Text, { style: styles.muted, children: error ?? where.readOnly.unlisted }) : selection.creating ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native7.Text, { style: styles.muted, children: "Create entries on the ALP host." }) : !viewed ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native7.Text, { style: styles.muted, children: "Loading\\u2026" }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [\n viewed.overrides ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react_native7.Text, { style: styles.small, children: [\n "Overrides ",\n sourceLabel(viewed.overrides),\n "."\n ] }) : null,\n viewed.usedBy.length ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react_native7.Text, { style: styles.small, children: [\n "Used by ",\n viewed.usedBy.join(", "),\n "."\n ] }) : null,\n viewed.librarySkills?.length ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react_native7.Text, { style: styles.small, children: [\n "Library skills: ",\n viewed.librarySkills.join(", "),\n "."\n ] }) : null,\n viewed.secrets?.length ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react_native7.Text, { style: styles.muted, children: [\n "Secrets hidden: ",\n viewed.secrets.join(", "),\n ". Secret markers stand for values kept on the ALP host."\n ] }) : null,\n /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native7.Text, { selectable: true, style: styles.small, children: JSON.stringify(viewed.content, null, 2) })\n ] })\n ]\n }\n );\n }\n if (selection.name || selection.creating) {\n return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(\n EntryEditor,\n {\n theme,\n compact,\n scope,\n kind: selection.kind,\n entry: selection.creating ? null : entry,\n lists,\n actions,\n layout: { title, subtitle, groups, onSelect, initialCollapsed, embedded }\n },\n `${selection.kind}/${selection.name ?? "new"}/${entry?.revision ?? "new"}/${(entry?.librarySkills ?? []).join(",")}`\n );\n }\n return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(KindOverview, { theme, compact, scope, kind: kind.kind, rows: lists[kind.kind], error, where, actions, layout: { title, subtitle, groups, onSelect, initialCollapsed, embedded }, styles });\n}\nvar OTHER = "other";\nfunction LanguageSettings({ theme, compact, language, error, actions, layout, styles }) {\n const named = language && LANGUAGES.some((option) => option.value === language.applies);\n const [choice, setChoice] = (0, import_react4.useState)(null);\n const [typed, setTyped] = (0, import_react4.useState)("");\n const shown = choice ?? (language ? named ? language.applies : OTHER : "");\n const typedValid = typed.trim().length > 0 && typed.trim().length <= 40;\n return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(\n SideNavLayout,\n {\n theme,\n compact,\n title: layout.title,\n subtitle: layout.subtitle,\n groups: layout.groups,\n active: { item: "language" },\n onSelect: layout.onSelect,\n initialCollapsed: layout.initialCollapsed,\n embedded: layout.embedded,\n breadcrumb: ["Library", "Language"],\n children: [\n /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native7.Text, { style: styles.muted, children: "The language you read. Main writes its replies, questions, approval requests and task titles in it, other agents put their questions to you in it, and ALP asks for approvals and writes its notices in it. Agents may talk among themselves in any language." }),\n error ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native7.Text, { style: styles.danger, children: error }) : null,\n !language && !error ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native7.Text, { style: styles.muted, children: "Loading\\u2026" }) : null,\n language?.readOnly ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_ui2.SettingsSection, { title: "Language", children: [\n /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react_native7.Text, { style: styles.name, children: [\n language.applies,\n language.language ? "" : " (default)"\n ] }),\n /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native7.Text, { style: styles.muted, children: language.readOnly })\n ] }) : !language ? null : /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_ui2.SettingsSection, { title: "Language", children: [\n /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(\n import_ui2.SettingsSelect,\n {\n label: "Language",\n hint: language.language ? `Set in your settings.json` : `Not set: ${language.default} applies`,\n value: shown,\n options: [...LANGUAGES, { label: named || !language.language ? "Other\\u2026" : `${language.applies} (other)`, value: OTHER }],\n onValueChange: (value) => __async(null, null, function* () {\n setChoice(value);\n if (value !== OTHER && (yield actions.setLanguage(value))) setChoice(null);\n })\n }\n ),\n shown === OTHER ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ui2.SettingsInput, { label: "Other language", hint: "Its name in English, such as Thai or Indonesian", initialValue: named ? "" : language.language ?? "", placeholder: "Thai", onChangeText: setTyped }) : null,\n shown === OTHER ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ui2.SettingsAction, { label: "Use this language", actionLabel: "Save", disabled: !typedValid, onPress: () => __async(null, null, function* () {\n if (typedValid && (yield actions.setLanguage(typed.trim()))) setChoice(null);\n }) }) : null,\n language.language ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ui2.SettingsAction, { label: `Use the default (${language.default})`, hint: "Removes the setting", actionLabel: "Reset", onPress: () => __async(null, null, function* () {\n if (yield actions.setLanguage(null)) setChoice(null);\n }) }) : null\n ] })\n ]\n }\n );\n}\nvar SOURCES = [{ key: "all", label: "All" }, { key: "builtin", label: "Built-in" }, { key: "library", label: "Library" }, { key: "project", label: "Project" }];\nfunction KindOverview({ theme, compact, scope, kind, rows, error, where, actions, layout, styles }) {\n const { title, one } = kindOf(kind);\n const [filter, setFilter] = (0, import_react4.useState)("all");\n const [copying, setCopying] = (0, import_react4.useState)(null);\n const [copyName, setCopyName] = (0, import_react4.useState)("");\n const tabs = SOURCES.map((source) => ({ ...source, count: (rows ?? []).filter((row) => source.key === "all" || row.source === source.key).length })).filter((tab) => tab.key === "all" || tab.count);\n const shown = (rows ?? []).filter((row) => filter === "all" || row.source === filter);\n const readOnly = where?.readOnly;\n const intro = readOnly ? `The ${title.toLowerCase()} ${scope === "project" ? "this project uses on the ALP host" : "of the ALP host"}, by name.` : kind === "providers" ? "Agents that speak the Agent Client Protocol. They live in your library only." : scope === "library" ? "Every project uses your library. Built-ins follow ALP updates; saving one makes your own copy of that name." : "What this project overrides. Override an entry to change it here only; Use library drops the project\'s copy.";\n return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(\n SideNavLayout,\n {\n theme,\n compact,\n title: layout.title,\n subtitle: layout.subtitle,\n groups: layout.groups,\n active: { item: kind },\n onSelect: layout.onSelect,\n initialCollapsed: layout.initialCollapsed,\n embedded: layout.embedded,\n breadcrumb: layout.embedded ? [] : [scope === "library" ? "Library" : "Project", title],\n tabs,\n tab: filter,\n onTab: setFilter,\n actions: readOnly ? null : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Button, { theme, kind: "primary", icon: "Plus", label: `New ${one}`, onPress: () => actions.select({ kind, creating: true }) }),\n children: [\n /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native7.Text, { style: styles.muted, children: intro }),\n readOnly ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native7.Text, { style: styles.muted, children: readOnly.reason }) : null,\n error ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native7.Text, { style: styles.danger, children: error }) : null,\n !rows && !error ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native7.Text, { style: styles.muted, children: "Loading\\u2026" }) : null,\n readOnly?.unlisted ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native7.View, { style: styles.empty, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native7.Text, { style: styles.muted, children: readOnly.unlisted }) }) : rows && !shown.length ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native7.View, { style: styles.empty, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react_native7.Text, { style: styles.muted, children: [\n "No ",\n title.toLowerCase(),\n " ",\n filter === "all" ? "yet" : `from the ${sourceLabel(filter)}`,\n "."\n ] }) }) : null,\n shown.length ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native7.View, { style: styles.table, children: shown.map((row, index) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react_native7.View, { style: [styles.tableRow, index ? styles.tableRowRule : null], children: [\n /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react_native7.Pressable, { accessibilityRole: "button", accessibilityLabel: `Open ${one} ${row.name}`, onPress: () => actions.select({ kind, name: row.name }), style: styles.rowMain, children: [\n /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react_native7.View, { style: styles.rowTitle, children: [\n /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native7.Text, { style: styles.name, children: row.name }),\n /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Pill, { theme, label: sourceLabel(row.source), tone: sourceTone(row.source) }),\n row.overrides ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Pill, { theme, label: `overrides ${sourceLabel(row.overrides)}` }) : null\n ] }),\n row.description ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native7.Text, { style: styles.muted, numberOfLines: 2, children: row.description }) : null,\n row.usedBy?.length ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react_native7.Text, { style: styles.small, numberOfLines: 1, children: [\n "Used by ",\n row.usedBy.join(", ")\n ] }) : null\n ] }),\n readOnly ? null : /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react_native7.View, { style: [styles.rowActions, compact ? styles.rowActionsCompact : null], children: [\n scope === "project" && row.source === "project" && row.overrides ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Button, { theme, label: "Use library", onPress: () => actions.useLibrary(kind, row.name) }) : null,\n scope === "project" && row.source !== "project" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Button, { theme, label: "Override in this project", onPress: () => actions.override(kind, row.name) }) : null,\n /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Button, { theme, icon: "Copy", label: "Duplicate", accessibilityLabel: `Duplicate ${one} ${row.name}`, onPress: () => {\n setCopying(row.name);\n setCopyName(`${row.name}-copy`);\n } })\n ] }),\n copying === row.name ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react_native7.View, { style: styles.copyRow, children: [\n /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native7.TextInput, { style: styles.input, value: copyName, onChangeText: setCopyName, accessibilityLabel: "Name of the copy", placeholder: "Name of the copy", placeholderTextColor: theme.colors.foregroundMuted }),\n /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Button, { theme, kind: "primary", label: "Copy", onPress: () => __async(null, null, function* () {\n if (NAME.test(copyName) && (yield actions.duplicate(kind, row.name, copyName))) setCopying(null);\n }) }),\n /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Button, { theme, label: "Cancel", onPress: () => setCopying(null) })\n ] }) : null\n ] }, row.name)) }) : null\n ]\n }\n );\n}\nfunction blank(kind, name = "new") {\n if (kind === "agents") return { instructions: `# ${name}\n\nDescribe what this agent does, and how.\n`, config: {} };\n if (kind === "skills") return { body: `---\nname: ${name}\ndescription: When to use this skill.\n---\n\n# ${name}\n\nSteps and checks.\n` };\n if (kind === "mcp") return { server: { command: "" } };\n if (kind === "hooks") return { hook: { event: "handoff", command: "", blocking: false } };\n if (kind === "providers") return { provider: { kind: "acp", label: name, command: "" } };\n return { team: { label: name, main: "main", members: { main: {} }, delegation: {}, supervisor: false }, houseRules: "" };\n}\nfunction entryTabs(kind, saved) {\n const tabs = {\n agents: [["general", "General"], ["instructions", "Instructions"], ["capabilities", "Skills, MCP & hooks"]],\n teams: [["models", "Models & effort"], ["general", "General"], ["members", "Members"], ["delegation", "Delegation"], ["supervisor", "Supervisor"], ["rules", "House rules"]],\n skills: [["body", "SKILL.md"]],\n mcp: [["server", "Server"], ["test", "Test"]],\n hooks: [["hook", "Hook"], ["test", "Test"]],\n providers: [["agent", "ACP agent"], ["test", "Test"]]\n };\n return tabs[kind].filter(([key]) => key !== "test" || saved).map(([key, label]) => ({ key, label }));\n}\nfunction EntryEditor({ theme, compact, scope, kind, entry, lists, actions, layout, initialTab }) {\n const styles = (0, import_react4.useMemo)(() => makeStyles2(theme, compact), [theme, compact]);\n const { one, title } = kindOf(kind);\n const tabs = entryTabs(kind, !!entry);\n const [tab, setTab] = (0, import_react4.useState)(initialTab && tabs.some((candidate) => candidate.key === initialTab) ? initialTab : tabs[0].key);\n const [name, setName] = (0, import_react4.useState)(entry?.name ?? "");\n const original = (0, import_react4.useMemo)(() => clone2(entry?.content ?? blank(kind)), [entry, kind]);\n const [content, setContent] = (0, import_react4.useState)(() => clone2(original));\n const [result, setResult] = (0, import_react4.useState)(null);\n const own = entry?.source === scope;\n const update = (change) => setContent((current) => {\n const draft = clone2(current);\n change(draft);\n return draft;\n });\n const valid = NAME.test(name);\n const changed = !entry || JSON.stringify(content) !== JSON.stringify(original);\n const givenOriginal = (0, import_react4.useMemo)(() => entry?.librarySkills ?? [], [entry]);\n const [given, setGiven] = (0, import_react4.useState)(givenOriginal);\n const givesSkills = kind === "agents" && scope === "library";\n const givenChanged = givesSkills && [...given].sort().join() !== [...givenOriginal].sort().join();\n const dirty = changed || givenChanged;\n const onSave = () => __async(null, null, function* () {\n if (!valid) return;\n if (changed && !(yield actions.save(kind, name, content, own ? entry.revision : null, !entry))) return;\n if (givenChanged) yield actions.giveSkills(name, given);\n });\n const note = entry ? entry.source === "builtin" ? `Built into ALP. Saving makes ${scope === "library" ? "your library\'s" : "this project\'s"} own ${entry.name}, which overrides it.` : own ? `In ${scope === "library" ? "your library" : "this project"}${entry.overrides ? `; overrides the ${sourceLabel(entry.overrides)} one` : ""}.` : `From the ${sourceLabel(entry.source)}. Saving makes this project\'s own copy.` : null;\n const form = { content, update, lists, styles, theme };\n return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(\n SideNavLayout,\n {\n theme,\n compact,\n title: layout.title,\n subtitle: layout.subtitle,\n groups: layout.groups,\n active: { item: kind, ...entry ? { child: entry.name } : {} },\n onSelect: layout.onSelect,\n initialCollapsed: layout.initialCollapsed,\n embedded: layout.embedded,\n breadcrumb: [title, entry ? entry.name : `New ${one}`],\n badges: entry ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [\n /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Pill, { theme, label: sourceLabel(entry.source), tone: sourceTone(entry.source) }),\n entry.overrides ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Pill, { theme, label: `overrides ${sourceLabel(entry.overrides)}` }) : null\n ] }) : null,\n actions: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Button, { theme, icon: "ArrowLeft", label: `All ${title.toLowerCase()}`, onPress: () => actions.select({ kind }) }),\n tabs,\n tab,\n onTab: setTab,\n footer: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [\n /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Button, { theme, kind: "primary", label: entry && entry.source === "builtin" && (changed || !givenChanged) ? "Save as my own" : "Save", disabled: !valid || !dirty, onPress: () => {\n void onSave();\n } }),\n /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native7.Text, { style: styles.small, children: !valid ? "Name the entry first" : dirty ? "Unsaved changes" : own ? "Saved" : "No changes" }),\n /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native7.View, { style: { flex: 1 } }),\n entry && own ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Button, { theme, kind: "danger", label: entry.overrides ? `Remove (the ${sourceLabel(entry.overrides)} one applies again)` : "Remove", onPress: () => actions.remove(kind, entry.name, entry.revision) }) : null\n ] }),\n children: [\n note || entry?.usedBy.length ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react_native7.View, { style: styles.banner, children: [\n note ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native7.Text, { style: styles.bannerText, children: note }) : null,\n entry?.usedBy.length ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react_native7.Text, { style: styles.small, children: [\n "Used by ",\n entry.usedBy.join(", "),\n "."\n ] }) : null\n ] }) : null,\n !entry && tab === tabs[0].key ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ui2.SettingsSection, { title: "Name", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ui2.SettingsInput, { label: "Name", hint: "Letters, digits, \'.\', \'_\' or \'-\'", error: name && !valid ? "Not a valid name" : null, initialValue: name, onChangeText: setName }) }) : null,\n kind === "agents" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(AgentForm, { ...form, tab, given: entry?.librarySkills ?? [], ...givesSkills ? { draftGiven: given, setGiven } : {} }) : null,\n kind === "teams" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(TeamForm, { ...form, tab }) : null,\n kind === "skills" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Multiline, { value: content.body ?? "", onChange: (text) => update((draft) => {\n draft.body = text;\n }), styles, theme, label: "SKILL.md", tall: true }) : null,\n kind === "mcp" && tab === "server" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(McpForm, { content, update }) : null,\n kind === "hooks" && tab === "hook" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(HookForm, { content, update, lists }) : null,\n kind === "providers" && tab === "agent" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ProviderForm, { content, update }) : null,\n tab === "test" && entry ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_ui2.SettingsSection, { title: "Test", children: [\n /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ui2.SettingsAction, { label: kind === "mcp" ? "Start the server and list its tools" : kind === "providers" ? "Start the agent and ask what it supports" : "Run once with a sample event", hint: "The test runs what is saved.", actionLabel: "Test", onPress: () => __async(null, null, function* () {\n return setResult(yield actions.test(kind, entry.name));\n }) }),\n result ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(TestResult, { kind, result, styles }) : null\n ] }) : null\n ]\n }\n );\n}\nvar names = (lists, kind) => (lists[kind] ?? []).map((row) => row.name);\nvar toggle = (list, name, on) => {\n const set = new Set(list ?? []);\n if (on) set.add(name);\n else set.delete(name);\n return [...set];\n};\nvar setOrDelete = (target, key, value) => {\n if (value === "" || value === void 0 || Array.isArray(value) && !value.length) delete target[key];\n else target[key] = value;\n};\nvar CONTEXT_SIZES = [2e5, 4e5, 6e5, 1e6];\nvar contextOptions = (current) => [\n { label: "Auto (the model\'s)", value: "" },\n ...[.../* @__PURE__ */ new Set([...CONTEXT_SIZES, ...typeof current === "number" ? [current] : []])].sort((a, b) => a - b).map((tokens) => ({ label: tokens >= 1e6 ? `${tokens / 1e6}M tokens` : `${Math.round(tokens / 1e3)}k tokens`, value: String(tokens) }))\n];\nfunction AgentForm({ content, update, lists, styles, theme, tab, given = [], draftGiven, setGiven }) {\n const config = content.config ?? {};\n const field = (key) => (text) => update((draft) => {\n draft.config ?? (draft.config = {});\n setOrDelete(draft.config, key, text.trim());\n });\n const show = (key) => !tab || tab === key;\n return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [\n show("general") ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_ui2.SettingsSection, { title: "Agent", children: [\n /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ui2.SettingsInput, { label: "Description", initialValue: config.description ?? "", onChangeText: field("description") }),\n /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ui2.SettingsSelect, { label: "Provider", hint: "The team or project settings may choose another", value: config.provider ?? "", options: [{ label: "Default", value: "" }, { label: "Codex", value: "codex" }, { label: "Claude Code", value: "claude" }, ...names(lists, "providers").map((provider) => ({ label: `${provider} (ACP)`, value: provider }))], onValueChange: field("provider") }),\n /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ui2.SettingsInput, { label: "Model", hint: "Such as claude:claude-sonnet-5-5, codex:gpt-6-sol or acp:gemini", initialValue: config.model ?? "", onChangeText: field("model") }),\n /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ui2.SettingsInput, { label: "Thinking", hint: "Effort, such as low, medium or high", initialValue: config.thinking ?? "", onChangeText: field("thinking") }),\n /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(\n import_ui2.SettingsSelect,\n {\n label: "Context",\n hint: "How much context it works with before the runtime compacts it",\n value: typeof config.context === "number" ? String(config.context) : "",\n options: contextOptions(config.context),\n onValueChange: (value) => update((draft) => {\n draft.config ?? (draft.config = {});\n setOrDelete(draft.config, "context", value ? Number(value) : "");\n })\n }\n ),\n /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ui2.SettingsSelect, { label: "Default mode", value: config.mode ?? "", options: MODES.map((mode) => ({ label: mode || "As its requester chooses", value: mode })), onValueChange: field("mode") })\n ] }) : null,\n show("instructions") ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Multiline, { value: content.instructions ?? "", onChange: (text) => update((draft) => {\n draft.instructions = text;\n }), styles, theme, label: "AGENT.md", tall: true }) : null,\n show("capabilities") ? ["skills", "mcp", "hooks"].map((kind) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_ui2.SettingsSection, { title: kindOf(kind).title, children: [\n !names(lists, kind).length ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ui2.SettingsRow, { label: `No ${kindOf(kind).title.toLowerCase()} to choose from yet` }) : null,\n names(lists, kind).map((name) => {\n const own = (config[kind] ?? []).includes(name);\n const configToggle = (on) => update((draft) => {\n draft.config ?? (draft.config = {});\n setOrDelete(draft.config, kind, toggle(draft.config[kind], name, on));\n });\n if (kind !== "skills") return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ui2.SettingsSwitch, { label: name, value: own, onValueChange: configToggle }, name);\n if (setGiven) {\n const library = (draftGiven ?? given).includes(name);\n return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(\n import_ui2.SettingsSwitch,\n {\n label: name,\n hint: given.includes(name) ? "Default for this agent" : void 0,\n value: library || own,\n onValueChange: (on) => {\n setGiven(toggle(draftGiven ?? given, name, on));\n if (!on && own) configToggle(false);\n }\n },\n name\n );\n }\n if (given.includes(name)) return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ui2.SettingsSwitch, { label: name, hint: "Given by your library; change it in Settings \\u2192 ALP", value: true, disabled: true, onValueChange: () => {\n } }, name);\n return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ui2.SettingsSwitch, { label: name, value: own, onValueChange: configToggle }, name);\n })\n ] }, kind)) : null\n ] });\n}\nfunction withMember(team, agent, on) {\n const next = clone2(team);\n next.members ?? (next.members = {});\n next.delegation ?? (next.delegation = {});\n if (on) {\n next.members[agent] = { role: "peer" };\n return next;\n }\n delete next.members[agent];\n delete next.delegation[agent];\n for (const owner of Object.keys(next.delegation)) {\n next.delegation[owner] = next.delegation[owner].filter((target) => target !== agent);\n if (!next.delegation[owner].length) delete next.delegation[owner];\n }\n return next;\n}\nfunction withDelegation(team, owner, target, on) {\n const next = clone2(team);\n next.delegation ?? (next.delegation = {});\n const targets = toggle(next.delegation[owner], target, on);\n if (targets.length) next.delegation[owner] = targets;\n else delete next.delegation[owner];\n return next;\n}\nvar EFFORTS = ["", "none", "low", "medium", "high", "xhigh", "max"];\nvar effortOptions = EFFORTS.map((value) => ({ label: value || "Inherit", value }));\nfunction TeamModels({ content, update, theme }) {\n return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(TeamModelSettings, { team: content.team ?? {}, theme, onChange: (next) => update((draft) => {\n draft.team = next;\n }) });\n}\nfunction TeamForm({ content, update, lists, styles, theme, tab }) {\n const show = (key) => !tab || tab === key;\n const team = content.team ?? {};\n const agents = names(lists, "agents");\n const members = Object.keys(team.members ?? {});\n const others = members.filter((member) => member !== team.main);\n const cycle = delegationCycle(team.delegation ?? {});\n const text = (key) => (value) => update((draft) => {\n setOrDelete(draft.team, key, value.trim());\n });\n return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [\n show("models") ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(TeamModels, { content, update, lists, styles, theme }) : null,\n show("general") ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_ui2.SettingsSection, { title: "Team", children: [\n /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ui2.SettingsInput, { label: "Label", hint: "Shown in the model picker", initialValue: team.label ?? "", onChangeText: text("label") }),\n /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ui2.SettingsInput, { label: "Description", initialValue: team.description ?? "", onChangeText: text("description") }),\n /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ui2.SettingsInput, { label: "Most peers at once", initialValue: team.maxPeers === void 0 ? "" : String(team.maxPeers), onChangeText: (value) => update((draft) => {\n setOrDelete(draft.team, "maxPeers", value.trim() ? Number(value) : "");\n }) })\n ] }) : null,\n show("members") ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_jsx_runtime4.Fragment, { children: [team.main, ...agents.filter((agent) => agent !== team.main && agent !== team.supervisor?.agent)].filter(Boolean).map((agent) => {\n const member = team.members?.[agent];\n const main = agent === team.main;\n return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_ui2.SettingsSection, { title: main ? `${agent} \\xB7 main` : agent, info: main ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native7.Text, { style: styles.small, children: "The agent you talk with." }) : void 0, children: [\n !main ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ui2.SettingsSwitch, { label: "In this team", value: !!member, onValueChange: (on) => update((draft) => {\n draft.team = withMember(draft.team, agent, on);\n }) }) : null,\n member && !main ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ui2.SettingsSelect, { label: "Role", value: member.role ?? "peer", options: ROLES.map((role) => ({ label: role, value: role })), onValueChange: (role) => update((draft) => {\n draft.team.members[agent].role = role;\n }) }) : null\n ] }, agent);\n }) }) : null,\n show("delegation") ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [\n cycle ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react_native7.Text, { style: styles.danger, children: [\n "Cycle at ",\n cycle,\n ": ALP refuses it"\n ] }) : null,\n members.map((owner) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_ui2.SettingsSection, { title: `${owner} may delegate to`, info: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native7.Text, { style: styles.small, children: (team.delegation?.[owner] ?? []).join(", ") || "no one" }), children: [\n others.filter((target) => target !== owner).map((target) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ui2.SettingsSwitch, { label: target, value: (team.delegation?.[owner] ?? []).includes(target), onValueChange: (on) => update((draft) => {\n draft.team = withDelegation(draft.team, owner, target, on);\n }) }, `${owner}-${target}`)),\n !others.filter((target) => target !== owner).length ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ui2.SettingsRow, { label: "No other members" }) : null\n ] }, owner))\n ] }) : null,\n show("supervisor") ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_ui2.SettingsSection, { title: "Supervisor", children: [\n /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ui2.SettingsSwitch, { label: "Review main\'s process after each turn", value: !!team.supervisor, onValueChange: (on) => update((draft) => {\n draft.team.supervisor = on ? { agent: "supervisor" } : false;\n }) }),\n team.supervisor ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [\n /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ui2.SettingsSelect, { label: "Supervisor agent", value: team.supervisor.agent, options: agents.filter((agent) => !members.includes(agent)).map((agent) => ({ label: agent, value: agent })), onValueChange: (agent) => update((draft) => {\n draft.team.supervisor.agent = agent;\n }) }),\n /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ui2.SettingsRow, { label: "Model & effort", hint: "Configure in Models & effort" })\n ] }) : null\n ] }) : null,\n show("rules") ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Multiline, { value: content.houseRules ?? "", onChange: (value) => update((draft) => {\n draft.houseRules = value;\n }), styles, theme, label: "House rules", placeholder: "The team\'s rules and process, which every member reads (HOUSE_RULES.md)", tall: true }) : null\n ] });\n}\nfunction delegationCycle(graph) {\n const visiting = /* @__PURE__ */ new Set();\n const done = /* @__PURE__ */ new Set();\n const visit = (owner) => {\n if (visiting.has(owner)) return owner;\n if (done.has(owner)) return null;\n visiting.add(owner);\n for (const target of graph[owner] ?? []) {\n const found = visit(target);\n if (found) return found;\n }\n visiting.delete(owner);\n done.add(owner);\n return null;\n };\n for (const owner of Object.keys(graph)) {\n const found = visit(owner);\n if (found) return found;\n }\n return null;\n}\nvar lines = (text) => text.split("\\n").map((line) => line.trim()).filter(Boolean);\nvar pairs = (text) => Object.fromEntries(lines(text).filter((line) => line.includes("=")).map((line) => [line.slice(0, line.indexOf("=")).trim(), line.slice(line.indexOf("=") + 1).trim()]));\nvar unpairs = (map) => Object.entries(map ?? {}).map(([key, value]) => `${key}=${value}`).join("\\n");\nfunction McpForm({ content, update }) {\n const server = content.server ?? {};\n const http = server.url !== void 0;\n const set = (key, value) => update((draft) => {\n setOrDelete(draft.server, key, value);\n });\n return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_ui2.SettingsSection, { title: "Server", children: [\n /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ui2.SettingsSelect, { label: "Transport", value: http ? "http" : "stdio", options: [{ label: "Command (stdio)", value: "stdio" }, { label: "URL (HTTP)", value: "http" }], onValueChange: (kind) => update((draft) => {\n draft.server = kind === "http" ? { url: "" } : { command: "" };\n }) }),\n http ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [\n /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ui2.SettingsInput, { label: "URL", initialValue: server.url ?? "", onChangeText: (value) => update((draft) => {\n draft.server.url = value.trim();\n }) }),\n /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ui2.SettingsInput, { label: "Headers", hint: "Name=value, separated by \';\'", initialValue: unpairs(server.headers).replaceAll("\\n", "; "), onChangeText: (value) => set("headers", Object.keys(pairs(value.replaceAll(";", "\\n"))).length ? pairs(value.replaceAll(";", "\\n")) : void 0) })\n ] }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [\n /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ui2.SettingsInput, { label: "Command", initialValue: server.command ?? "", onChangeText: (value) => update((draft) => {\n draft.server.command = value.trim();\n }) }),\n /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ui2.SettingsInput, { label: "Arguments", hint: "Separated by spaces", initialValue: (server.args ?? []).join(" "), onChangeText: (value) => set("args", value.split(/\\s+/).filter(Boolean)) }),\n /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ui2.SettingsInput, { label: "Environment", hint: "NAME=value, separated by \';\'", initialValue: unpairs(server.env).replaceAll("\\n", "; "), onChangeText: (value) => set("env", Object.keys(pairs(value.replaceAll(";", "\\n"))).length ? pairs(value.replaceAll(";", "\\n")) : void 0) }),\n /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ui2.SettingsInput, { label: "Working directory", hint: "Relative to the mcp directory", initialValue: server.cwd ?? "", onChangeText: (value) => set("cwd", value.trim()) })\n ] })\n ] });\n}\nfunction ProviderForm({ content, update }) {\n const provider = content.provider ?? {};\n const set = (key, value) => update((draft) => {\n draft.provider ?? (draft.provider = { kind: "acp" });\n setOrDelete(draft.provider, key, value);\n });\n return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_ui2.SettingsSection, { title: "ACP agent", info: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native7.Text, { children: "Any agent that speaks the Agent Client Protocol on stdio. ALP answers its permission requests by the session\'s mode; it cannot steer it mid-turn or sandbox its commands." }), children: [\n /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ui2.SettingsInput, { label: "Label", initialValue: provider.label ?? "", onChangeText: (value) => set("label", value.trim()) }),\n /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ui2.SettingsInput, { label: "Description", initialValue: provider.description ?? "", onChangeText: (value) => set("description", value.trim()) }),\n /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ui2.SettingsInput, { label: "Command", hint: "Such as gemini, or an absolute path", initialValue: provider.command ?? "", onChangeText: (value) => update((draft) => {\n draft.provider.command = value.trim();\n }) }),\n /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ui2.SettingsInput, { label: "Arguments", hint: "Separated by spaces, such as --experimental-acp", initialValue: (provider.args ?? []).join(" "), onChangeText: (value) => set("args", value.split(/\\s+/).filter(Boolean)) }),\n /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ui2.SettingsInput, { label: "Environment", hint: "NAME=value, separated by \';\'", initialValue: unpairs(provider.env).replaceAll("\\n", "; "), onChangeText: (value) => set("env", Object.keys(pairs(value.replaceAll(";", "\\n"))).length ? pairs(value.replaceAll(";", "\\n")) : void 0) }),\n /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ui2.SettingsInput, { label: "Models", hint: "Ids the agent offers, separated by \',\'; empty lets any through", initialValue: (provider.models ?? []).map((model) => model.id).join(", "), onChangeText: (value) => set("models", value.split(",").map((id) => id.trim()).filter(Boolean).map((id) => (provider.models ?? []).find((model) => model.id === id) ?? { id })) })\n ] });\n}\nfunction HookForm({ content, update, lists }) {\n const hook = content.hook ?? {};\n const set = (key, value) => update((draft) => {\n setOrDelete(draft.hook, key, value);\n });\n const blocking = BLOCKING_EVENTS.includes(hook.event);\n return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_ui2.SettingsSection, { title: "Hook", children: [\n /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ui2.SettingsSelect, { label: "Event", value: hook.event ?? "handoff", options: HOOK_EVENTS.map((event) => ({ label: event, value: event })), onValueChange: (event) => update((draft) => {\n draft.hook.event = event;\n if (!BLOCKING_EVENTS.includes(event)) delete draft.hook.blocking;\n }) }),\n /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ui2.SettingsInput, { label: "Command", hint: "Runs in the session\'s directory; the event arrives as JSON on stdin", initialValue: hook.command ?? "", onChangeText: (value) => update((draft) => {\n draft.hook.command = value;\n }) }),\n blocking ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ui2.SettingsSwitch, { label: "Block the action when it fails", hint: "Its stderr becomes the reason the agent reads", value: !!hook.blocking, onValueChange: (on) => set("blocking", on || void 0) }) : null,\n /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ui2.SettingsInput, { label: "Timeout (seconds)", initialValue: hook.timeoutSec === void 0 ? "" : String(hook.timeoutSec), onChangeText: (value) => set("timeoutSec", value.trim() ? Number(value) : "") }),\n /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ui2.SettingsSelect, { label: "Only for agent", value: hook.match?.agent ?? "", options: [{ label: "Every agent", value: "" }, ...names(lists, "agents").map((agent) => ({ label: agent, value: agent }))], onValueChange: (agent) => update((draft) => {\n var _a;\n (_a = draft.hook).match ?? (_a.match = {});\n setOrDelete(draft.hook.match, "agent", agent);\n if (!Object.keys(draft.hook.match).length) delete draft.hook.match;\n }) }),\n /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ui2.SettingsInput, { label: "Only for tasks labeled", initialValue: hook.match?.label ?? "", onChangeText: (label) => update((draft) => {\n var _a;\n (_a = draft.hook).match ?? (_a.match = {});\n setOrDelete(draft.hook.match, "label", label.trim());\n if (!Object.keys(draft.hook.match).length) delete draft.hook.match;\n }) })\n ] });\n}\nfunction TestResult({ kind, result, styles }) {\n if (kind === "providers") {\n return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react_native7.View, { children: [\n /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react_native7.Text, { style: styles.success, children: [\n result.agent?.title ?? result.agent?.name ?? "The agent",\n result.agent?.version ? ` ${result.agent.version}` : "",\n " speaks ACP ",\n result.protocolVersion\n ] }),\n /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react_native7.Text, { style: styles.muted, children: [\n result.loadSession ? "Resumes sessions" : "Cannot resume sessions",\n result.mcpHttp ? "; takes HTTP MCP servers" : "; takes stdio MCP servers only",\n result.authMethods?.length ? `; signs in with ${result.authMethods.join(", ")}` : ""\n ] })\n ] });\n }\n if (kind === "mcp") {\n return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react_native7.View, { children: [\n /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react_native7.Text, { style: styles.success, children: [\n result.server?.name ?? "The server",\n result.server?.version ? ` ${result.server.version}` : "",\n " offers ",\n result.tools?.length ?? 0,\n " tools"\n ] }),\n (result.tools ?? []).map((tool) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react_native7.Text, { style: styles.muted, children: [\n tool.name,\n tool.description ? ` \\u2014 ${tool.description.split("\\n")[0]}` : ""\n ] }, tool.name))\n ] });\n }\n return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react_native7.View, { children: [\n /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react_native7.Text, { style: result.ok ? styles.success : styles.danger, children: [\n result.timedOut ? "Timed out" : `Exit ${result.exitCode ?? result.signal}`,\n " in ",\n result.durationMs,\n " ms",\n result.wouldBlock ? "; as a blocking hook it would refuse the action" : ""\n ] }),\n result.stdout ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native7.Text, { style: styles.code, children: result.stdout }) : null,\n result.stderr ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native7.Text, { style: styles.code, children: result.stderr }) : null\n ] });\n}\nfunction Multiline({ value, onChange, styles, theme, label, placeholder, tall }) {\n return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native7.TextInput, { style: [styles.multiline, tall ? styles.tall : null], value, onChangeText: onChange, multiline: true, accessibilityLabel: label, placeholder: placeholder ?? label, placeholderTextColor: theme.colors.foregroundMuted });\n}\nfunction makeStyles2(theme, compact) {\n const { colors } = theme;\n return {\n screen: { flex: 1, backgroundColor: colors.surface0, padding: compact ? 12 : 20 },\n muted: { color: colors.foregroundMuted, fontSize: 13, lineHeight: 19 },\n small: { color: colors.foregroundMuted, fontSize: 12 },\n danger: { color: colors.statusDanger, fontSize: 13 },\n success: { color: colors.statusSuccess, fontSize: 13 },\n name: { color: colors.foreground, fontSize: 14, fontWeight: "600" },\n empty: { borderWidth: 1, borderStyle: "dashed", borderColor: colors.border, borderRadius: 10, padding: 24, alignItems: "center" },\n table: { borderWidth: 1, borderColor: colors.border, borderRadius: 10, backgroundColor: colors.surface1, overflow: "hidden" },\n tableRow: { flexDirection: compact ? "column" : "row", flexWrap: "wrap", alignItems: compact ? "stretch" : "center", gap: 10, paddingHorizontal: 14, paddingVertical: 12 },\n tableRowRule: { borderTopWidth: 1, borderTopColor: colors.border },\n rowMain: { flex: 1, minWidth: 0, gap: 3 },\n rowTitle: { flexDirection: "row", alignItems: "center", gap: 8, flexWrap: "wrap" },\n rowActions: { flexDirection: "row", gap: 8, alignItems: "center" },\n rowActionsCompact: { flexWrap: "wrap" },\n copyRow: { flexBasis: "100%", flexDirection: "row", gap: 8, alignItems: "center" },\n input: { flex: 1, color: colors.foreground, borderWidth: 1, borderColor: colors.border, borderRadius: 8, paddingHorizontal: 10, paddingVertical: 7, backgroundColor: colors.surface0 },\n banner: { borderRadius: 10, backgroundColor: colors.surface1, borderWidth: 1, borderColor: colors.border, paddingHorizontal: 14, paddingVertical: 10, gap: 4 },\n bannerText: { color: colors.foreground, fontSize: 13 },\n multiline: { minHeight: 160, color: colors.foreground, borderWidth: 1, borderColor: colors.border, borderRadius: 10, padding: 12, fontFamily: "monospace", fontSize: 13, lineHeight: 19, backgroundColor: colors.surface1, textAlignVertical: "top" },\n tall: { minHeight: 420 },\n code: { color: colors.foreground, fontFamily: "monospace", fontSize: 12 }\n };\n}\n\n// integrations/paseo/client/usage.tsx\nvar import_client4 = require("@getpaseo/plugin/client");\nvar import_react_native8 = require("@getpaseo/plugin/client/react-native");\nvar import_react5 = require("react");\nvar import_react_native9 = require("react-native");\n\n// integrations/paseo/shared/usage.ts\nvar import_plugin3 = require("@getpaseo/plugin");\nvar import_zod3 = require("zod");\nvar Pause = import_zod3.z.object({ reason: import_zod3.z.string(), since: import_zod3.z.string(), resetsAt: import_zod3.z.string().optional() });\nvar usageGet = (0, import_plugin3.defineRpc)({\n name: "alp.usage.get",\n input: import_zod3.z.object({ refresh: import_zod3.z.boolean().optional() }),\n output: import_zod3.z.object({\n providers: import_zod3.z.array(import_zod3.z.object({\n runtime: import_zod3.z.enum(["codex", "claude"]),\n available: import_zod3.z.boolean(),\n checkedAt: import_zod3.z.string(),\n plan: import_zod3.z.string().nullable(),\n limited: import_zod3.z.boolean(),\n windows: import_zod3.z.array(import_zod3.z.object({ name: import_zod3.z.string(), usedPercent: import_zod3.z.number().nullable(), resetsAt: import_zod3.z.string().nullable() })),\n pause: Pause.nullable(),\n parked: import_zod3.z.number()\n }))\n })\n});\n\n// integrations/paseo/client/usage.tsx\nvar import_jsx_runtime5 = require("react/jsx-runtime");\nfunction UsageScreen({ theme, layout }) {\n const read = (0, import_client4.useRpc)(usageGet);\n const [data, setData] = (0, import_react5.useState)(null);\n const [error, setError] = (0, import_react5.useState)(null);\n const [loading, setLoading] = (0, import_react5.useState)(true);\n const [tick, setTick] = (0, import_react5.useState)(0);\n const forceRefresh = (0, import_react5.useRef)(false);\n (0, import_react5.useEffect)(() => {\n let live = true;\n setLoading(true);\n const refresh = forceRefresh.current;\n forceRefresh.current = false;\n read({ refresh }).then((result) => {\n if (live) {\n setData(result);\n setError(null);\n }\n }).catch((cause) => {\n if (live) setError(cause instanceof Error ? cause.message : String(cause));\n }).finally(() => {\n if (live) setLoading(false);\n });\n return () => {\n live = false;\n };\n }, [read, tick]);\n (0, import_react5.useEffect)(() => {\n const timer = setInterval(() => setTick((value) => value + 1), 6e4);\n return () => clearInterval(timer);\n }, []);\n return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(UsageView, { theme, compact: layout.compact, data, loading, error, onRefresh: () => {\n forceRefresh.current = true;\n setTick((value) => value + 1);\n } });\n}\nfunction dateLabel(value) {\n const date = new Date(value);\n return Number.isFinite(date.getTime()) ? date.toLocaleString(void 0, { month: "short", day: "numeric", hour: "numeric", minute: "2-digit" }) : "Unknown";\n}\nfunction resetLabel(value, now) {\n if (!value) return "Reset time unavailable";\n const minutes = Math.ceil((Date.parse(value) - now) / 6e4);\n if (minutes <= 0) return "Reset time passed \\xB7 awaiting provider update";\n const duration = minutes >= 1440 ? `${Math.floor(minutes / 1440)}d ${Math.floor(minutes % 1440 / 60)}h` : minutes >= 60 ? `${Math.floor(minutes / 60)}h ${minutes % 60}m` : `${minutes}m`;\n return `Resets in ${duration} \\xB7 ${dateLabel(value)}`;\n}\nfunction UsageView({ theme, compact, data, loading, error, onRefresh, now = Date.now() }) {\n const { colors } = theme;\n const muted = { color: colors.foregroundMuted, fontSize: 13, lineHeight: 20 };\n const providers = data?.providers ?? [];\n const parked = providers.reduce((sum, provider) => sum + provider.parked, 0);\n return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react_native8.ScrollView, { contentContainerStyle: { padding: compact ? 16 : 28, gap: 24 }, children: [\n /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react_native9.View, { style: { gap: 8 }, children: [\n /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react_native9.View, { style: { flexDirection: "row", alignItems: "center", justifyContent: "space-between", gap: 12 }, children: [\n /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native9.Text, { accessibilityRole: "header", style: { color: colors.foreground, fontSize: 28, fontWeight: "600", letterSpacing: -0.7 }, children: "Usage" }),\n /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Button, { theme, label: loading ? "Refreshing\\u2026" : "Refresh", icon: "RefreshCw", disabled: loading, onPress: onRefresh, accessibilityLabel: "Refresh usage" })\n ] }),\n /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native9.Text, { style: muted, children: "Your provider limits, reset windows and paused work in one place." })\n ] }),\n error ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react_native9.View, { accessibilityRole: "alert", style: { padding: 14, borderWidth: 1, borderColor: colors.statusDanger, borderRadius: 10, gap: 4 }, children: [\n /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native9.Text, { style: { color: colors.statusDanger, fontWeight: "600" }, children: "Could not refresh usage" }),\n /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native9.Text, { style: muted, children: error }),\n data ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native9.Text, { style: muted, children: "Showing the last received data." }) : null\n ] }) : null,\n parked > 0 ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react_native9.View, { style: { padding: 14, backgroundColor: colors.surface1, borderLeftWidth: 3, borderLeftColor: colors.statusWarning, gap: 4 }, children: [\n /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react_native9.Text, { style: { color: colors.foreground, fontWeight: "600" }, children: [\n parked,\n " ",\n parked === 1 ? "assignment waiting" : "assignments waiting"\n ] }),\n /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native9.Text, { style: muted, children: "Parked work stays saved while its runtime is paused." })\n ] }) : null,\n !data && loading ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native9.Text, { accessibilityLiveRegion: "polite", style: muted, children: "Checking Codex and Claude usage\\u2026" }) : null,\n /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native9.View, { style: { flexDirection: compact ? "column" : "row", flexWrap: "wrap", gap: 16 }, children: providers.map((provider) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ProviderCard, { theme, provider, compact, now }, provider.runtime)) }),\n /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react_native9.View, { style: { borderTopWidth: 1, borderTopColor: colors.border, paddingTop: 16, gap: 4 }, children: [\n /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native9.Text, { style: muted, children: "Account limits reported by each provider, shared with usage outside ALP." }),\n /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native9.Text, { style: { ...muted, fontSize: 12 }, children: "Updates every minute while this screen is open. Readings are cached for up to 30 seconds. This is not a billing or token-spend report." })\n ] })\n ] });\n}\nfunction ProviderCard({ theme, provider, compact, now }) {\n const { colors } = theme;\n const status = provider.pause ? "Paused" : !provider.available ? "Unavailable" : provider.limited ? "Limit reached" : "Available";\n const tone = provider.pause || provider.limited ? "warning" : provider.available ? "success" : "muted";\n const muted = { color: colors.foregroundMuted, fontSize: 12, lineHeight: 18 };\n return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react_native9.View, { style: { flexGrow: 1, flexBasis: compact ? "auto" : 320, width: compact ? "100%" : void 0, minWidth: 0, padding: 20, backgroundColor: colors.surface1, borderWidth: 1, borderColor: colors.border, borderRadius: 14, gap: 20 }, children: [\n /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react_native9.View, { style: { flexDirection: "row", justifyContent: "space-between", alignItems: "center", gap: 12 }, children: [\n /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react_native9.View, { style: { gap: 4 }, children: [\n /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native9.Text, { accessibilityRole: "header", style: { color: colors.foreground, fontSize: 20, fontWeight: "600" }, children: provider.runtime === "codex" ? "Codex" : "Claude" }),\n /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native9.Text, { style: muted, children: provider.plan ? `${provider.plan} plan` : "Plan not reported" })\n ] }),\n /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Pill, { theme, label: status, tone })\n ] }),\n provider.pause ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react_native9.View, { style: { gap: 5 }, children: [\n /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native9.Text, { style: { color: colors.statusWarning, fontSize: 13 }, children: provider.pause.reason }),\n provider.pause.resetsAt ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native9.Text, { style: muted, children: resetLabel(provider.pause.resetsAt, now) }) : null,\n /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react_native9.Text, { style: muted, children: [\n provider.parked,\n " ",\n provider.parked === 1 ? "assignment parked" : "assignments parked"\n ] })\n ] }) : null,\n !provider.available ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react_native9.View, { style: { gap: 8, paddingVertical: 16 }, children: [\n /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native8.Icon, { name: "CircleHelp", size: 22, color: colors.foregroundMuted }),\n /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native9.Text, { style: { color: colors.foreground, fontSize: 14, fontWeight: "500" }, children: "Usage is not available" }),\n /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native9.Text, { style: muted, children: "The provider did not return usage data. Check that its CLI is installed and signed in, then refresh." })\n ] }) : provider.windows.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native9.Text, { style: muted, children: "The provider has not reported any usage windows." }) : provider.windows.map((window, index) => {\n const used = window.usedPercent;\n const color = used === null ? colors.foregroundMuted : used >= 95 ? colors.statusDanger : used >= 80 ? colors.statusWarning : colors.accent;\n return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react_native9.View, { style: { gap: 8 }, children: [\n /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react_native9.View, { style: { flexDirection: "row", justifyContent: "space-between", alignItems: "baseline", gap: 12 }, children: [\n /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native9.Text, { style: { color: colors.foreground, fontSize: 13, flex: 1, textTransform: "capitalize" }, children: window.name }),\n /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native9.Text, { style: { color, fontSize: 25, fontWeight: "600", fontVariant: ["tabular-nums"] }, children: used === null ? "\\u2014" : `${Math.round(used)}%` })\n ] }),\n /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native9.View, { accessibilityRole: "progressbar", accessibilityLabel: `${window.name} used`, accessibilityValue: used === null ? { text: "Usage unknown" } : { min: 0, max: 100, now: used }, style: { height: 6, backgroundColor: colors.surface2, borderRadius: 3, overflow: "hidden" }, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native9.View, { style: { height: 6, width: `${used ?? 0}%`, backgroundColor: color, borderRadius: 3 } }) }),\n /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native9.Text, { style: muted, children: used === null ? "Usage percentage unavailable" : `${Math.round(100 - used)}% remaining` }),\n /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native9.Text, { style: muted, children: resetLabel(window.resetsAt, now) })\n ] }, `${window.name}-${index}`);\n }),\n /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react_native9.Text, { style: { ...muted, borderTopWidth: 1, borderTopColor: colors.border, paddingTop: 12 }, children: [\n "Checked ",\n dateLabel(provider.checkedAt)\n ] })\n ] });\n}\n\n// integrations/paseo/index.client.tsx\nfunction contribute(client) {\n const removePanel = client.addWorkspacePanel({ id: "alp-tasks", title: "Tasks", icon: "ListTodo", context: "workspace", Component: TasksPanel });\n const removeScreen = client.addScreen({ id: TASKS_SCREEN, title: (params) => params.taskId ? `ALP task ${params.taskId}` : "ALP tasks", Component: TasksScreen });\n const removePills = addTaskPills(client);\n const removeCommand = client.addCommandCenterItem({\n id: "alp-open-tasks",\n title: "Open ALP tasks",\n icon: "ListTodo",\n keywords: ["tasks", "todo", "alp"],\n context: "workspace",\n onSelect({ openPanel }) {\n openPanel("alp-tasks");\n }\n });\n const removeScreenCommand = client.addCommandCenterItem({\n id: "alp-open-tasks-screen",\n title: "Open ALP tasks full screen",\n icon: "ListTodo",\n keywords: ["tasks", "todo", "alp", "phone"],\n context: "workspace",\n onSelect({ workspace, openScreen }) {\n openScreen(tasksScreen(workspace.id, workspace.directory || workspace.projectRootPath));\n }\n });\n const removeSlash = client.addSlashCommand({\n name: "alp-tasks",\n description: "Open the ALP tasks of this project",\n argumentHint: "[task id]",\n context: "agent",\n onSubmit({ workspace, args, openScreen }) {\n openScreen(tasksScreen(workspace.id, workspace.directory || workspace.projectRootPath, args.trim() || void 0));\n }\n });\n const removeSettings = client.addSettingsScreen({ id: "alp-settings", title: "ALP", icon: "Bot", Component: LibrarySettings });\n const removeHostSettings = [\n { id: "alp-templates", title: "Templates", icon: "Users", Component: TeamsSettings },\n { id: "alp-agents", title: "Agents", icon: "Bot", Component: AgentsSettings },\n { id: "alp-skills", title: "Skills", icon: "BookOpen", Component: SkillsSettings },\n { id: "alp-hooks", title: "Hooks", icon: "Webhook", Component: HooksSettings },\n { id: "alp-mcp", title: "MCP servers", icon: "Plug", Component: McpSettings }\n ].map((screen) => client.addSettingsScreen(screen));\n const removeUsage = client.addSettingsScreen({ id: "alp-usage", title: "Usage", icon: "ChartNoAxesCombined", Component: UsageScreen });\n const removeUsagePanel = client.addWorkspacePanel({ id: "alp-usage", title: "Usage", icon: "ChartNoAxesCombined", context: "workspace", Component: UsageScreen });\n const removeProject = client.addWorkspacePanel({ id: "alp-project", title: "ALP project", icon: "Bot", context: "workspace", Component: ProjectLibraryPanel });\n return () => {\n removePanel();\n removeScreen();\n removePills();\n removeCommand();\n removeScreenCommand();\n removeSlash();\n removeSettings();\n removeHostSettings.forEach((remove) => remove());\n removeProject();\n removeUsage();\n removeUsagePanel();\n };\n}\n\nreturn module.exports;})' };
|
|
51226
51639
|
|
|
51227
51640
|
// integrations/paseo/server/paseo/plugins.ts
|
|
51228
51641
|
var digest2 = createHash13("sha256").update(plugin_client_default.factory).digest("hex").slice(0, 16);
|
|
@@ -51309,7 +51722,7 @@ function createUsage(read) {
|
|
|
51309
51722
|
|
|
51310
51723
|
// integrations/paseo/server/paseo/workspaces.ts
|
|
51311
51724
|
import { randomBytes as randomBytes7 } from "node:crypto";
|
|
51312
|
-
import { mkdir as mkdir17, readFile as readFile22, stat as stat13, writeFile as
|
|
51725
|
+
import { mkdir as mkdir17, readFile as readFile22, stat as stat13, writeFile as writeFile18 } from "node:fs/promises";
|
|
51313
51726
|
import path46 from "node:path";
|
|
51314
51727
|
|
|
51315
51728
|
// node_modules/@getpaseo/protocol/dist/agent-state-bucket.js
|
|
@@ -51397,7 +51810,7 @@ function createWorkspaces({ home, broadcast, agents, inDevelopment, log: log3 =
|
|
|
51397
51810
|
saving = saving.then(async () => {
|
|
51398
51811
|
await mkdir17(path46.dirname(file3), { recursive: true });
|
|
51399
51812
|
const temporary = `${file3}.${process.pid}.tmp`;
|
|
51400
|
-
await
|
|
51813
|
+
await writeFile18(temporary, text2);
|
|
51401
51814
|
await moveFile(temporary, file3);
|
|
51402
51815
|
}).catch((error51) => log3(`web workspaces not saved: ${error51?.message ?? error51}`));
|
|
51403
51816
|
return saving;
|
|
@@ -51870,8 +52283,8 @@ function createWorkspaces({ home, broadcast, agents, inDevelopment, log: log3 =
|
|
|
51870
52283
|
}
|
|
51871
52284
|
|
|
51872
52285
|
// integrations/paseo/server/paseo/relay.ts
|
|
51873
|
-
import { randomUUID as
|
|
51874
|
-
import { readFile as readFile23, rename as
|
|
52286
|
+
import { randomUUID as randomUUID17 } from "node:crypto";
|
|
52287
|
+
import { readFile as readFile23, rename as rename10, writeFile as writeFile19, mkdir as mkdir18 } from "node:fs/promises";
|
|
51875
52288
|
import path47 from "node:path";
|
|
51876
52289
|
|
|
51877
52290
|
// node_modules/@getpaseo/relay/dist/crypto.js
|
|
@@ -52770,9 +53183,9 @@ async function relayKeyPair(home) {
|
|
|
52770
53183
|
const keyPair = generateKeyPair();
|
|
52771
53184
|
const publicKeyB64 = exportPublicKey(keyPair.publicKey);
|
|
52772
53185
|
await mkdir18(home, { recursive: true, mode: 448 });
|
|
52773
|
-
const temporary = `${file3}.${
|
|
52774
|
-
await
|
|
52775
|
-
await
|
|
53186
|
+
const temporary = `${file3}.${randomUUID17().slice(0, 8)}.tmp`;
|
|
53187
|
+
await writeFile19(temporary, JSON.stringify({ v: 2, publicKeyB64, secretKeyB64: exportSecretKey(keyPair.secretKey) }, null, 2) + "\n", { mode: 384 });
|
|
53188
|
+
await rename10(temporary, file3);
|
|
52776
53189
|
return { keyPair, publicKeyB64 };
|
|
52777
53190
|
}
|
|
52778
53191
|
function pairingUrl(offer) {
|
|
@@ -53155,7 +53568,7 @@ function createPaseoBridge({ clientFactory, version: version2, token, serverId,
|
|
|
53155
53568
|
// integrations/paseo/server/web.ts
|
|
53156
53569
|
import { randomBytes as randomBytes8 } from "node:crypto";
|
|
53157
53570
|
import { createReadStream } from "node:fs";
|
|
53158
|
-
import { mkdir as mkdir19, readFile as readFile24, rename as
|
|
53571
|
+
import { mkdir as mkdir19, readFile as readFile24, rename as rename11, stat as stat14, writeFile as writeFile20 } from "node:fs/promises";
|
|
53159
53572
|
import http from "node:http";
|
|
53160
53573
|
import path49 from "node:path";
|
|
53161
53574
|
var DEFAULT_WEB_PORT = 7433;
|
|
@@ -53331,8 +53744,8 @@ function createWebServer({ app, home, port = DEFAULT_WEB_PORT, log: log3 = () =>
|
|
|
53331
53744
|
bound = server.address().port;
|
|
53332
53745
|
const info = { port: bound, token, url: `http://127.0.0.1:${bound}/`, pid: process.pid, serverId };
|
|
53333
53746
|
await mkdir19(home, { recursive: true, mode: 448 });
|
|
53334
|
-
await
|
|
53335
|
-
await
|
|
53747
|
+
await writeFile20(`${webFile(home)}.tmp`, JSON.stringify(info), { mode: 384 });
|
|
53748
|
+
await rename11(`${webFile(home)}.tmp`, webFile(home));
|
|
53336
53749
|
return info;
|
|
53337
53750
|
},
|
|
53338
53751
|
async close() {
|