@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
|
@@ -14304,8 +14304,8 @@ async function setWebRelay(home, patch) {
|
|
|
14304
14304
|
}
|
|
14305
14305
|
|
|
14306
14306
|
// packages/client/src/index.js
|
|
14307
|
-
import { createHash } from "node:crypto";
|
|
14308
|
-
import { open, readFile as readFile2, realpath, stat, lstat, mkdir as mkdir2, readlink, unlink } from "node:fs/promises";
|
|
14307
|
+
import { createHash, randomUUID as randomUUID2 } from "node:crypto";
|
|
14308
|
+
import { open, readFile as readFile2, writeFile as writeFile3, realpath, stat, lstat, mkdir as mkdir2, readlink, unlink, readdir, rename as rename2, rmdir, link } from "node:fs/promises";
|
|
14309
14309
|
import net from "node:net";
|
|
14310
14310
|
import os from "node:os";
|
|
14311
14311
|
import path3 from "node:path";
|
|
@@ -14437,7 +14437,7 @@ var AlpRpcError = class extends Error {
|
|
|
14437
14437
|
};
|
|
14438
14438
|
var ERROR = Object.freeze({ failed: 1e3, notFound: 1001, forbidden: 1003, conflict: 1004, unavailable: 1005, protocol: 1006 });
|
|
14439
14439
|
var RPC_ERROR = Object.freeze({ parseError: -32700, invalidRequest: -32600, methodNotFound: -32601, invalidParams: -32602 });
|
|
14440
|
-
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" });
|
|
14440
|
+
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" });
|
|
14441
14441
|
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 });
|
|
14442
14442
|
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"]);
|
|
14443
14443
|
var WORKSPACE_FILES = Object.freeze({ maxReadBytes: 1024 * 1024, maxListEntries: 1e3, maxPathLength: 4096 });
|
|
@@ -15053,11 +15053,11 @@ var CHOICES = {
|
|
|
15053
15053
|
};
|
|
15054
15054
|
|
|
15055
15055
|
// integrations/paseo/server/paseo/agents.ts
|
|
15056
|
-
import { randomUUID as
|
|
15056
|
+
import { randomUUID as randomUUID7 } from "node:crypto";
|
|
15057
15057
|
import path12 from "node:path";
|
|
15058
15058
|
|
|
15059
15059
|
// packages/core/src/teams.js
|
|
15060
|
-
import { readdir as
|
|
15060
|
+
import { readdir as readdir4 } from "node:fs/promises";
|
|
15061
15061
|
import path6 from "node:path";
|
|
15062
15062
|
|
|
15063
15063
|
// packages/core/src/template-path.js
|
|
@@ -15069,12 +15069,12 @@ function shippedTemplateRoot() {
|
|
|
15069
15069
|
}
|
|
15070
15070
|
|
|
15071
15071
|
// packages/core/src/resolver.js
|
|
15072
|
-
import { readFile as readFile4, readdir as
|
|
15072
|
+
import { readFile as readFile4, readdir as readdir3, stat as stat2 } from "node:fs/promises";
|
|
15073
15073
|
import path5 from "node:path";
|
|
15074
15074
|
|
|
15075
15075
|
// packages/core/src/library.js
|
|
15076
|
-
import { mkdir as mkdir3, readFile as readFile3, readdir, writeFile as
|
|
15077
|
-
import { createHash as createHash2, randomUUID as
|
|
15076
|
+
import { mkdir as mkdir3, readFile as readFile3, readdir as readdir2, writeFile as writeFile4 } from "node:fs/promises";
|
|
15077
|
+
import { createHash as createHash2, randomUUID as randomUUID3 } from "node:crypto";
|
|
15078
15078
|
import path4 from "node:path";
|
|
15079
15079
|
var MANIFEST = "library.json";
|
|
15080
15080
|
var sha = (text) => createHash2("sha256").update(text.replaceAll("\r\n", "\n")).digest("hex");
|
|
@@ -15091,7 +15091,7 @@ async function shippedFiles({ templateRoot: templateRoot2, templates: templates2
|
|
|
15091
15091
|
const root = templateRoot2 ?? shippedTemplateRoot();
|
|
15092
15092
|
const files = { "role-skills.json": await readFile3(new URL("role-skills.json", root), "utf8") };
|
|
15093
15093
|
async function walk(relative) {
|
|
15094
|
-
for (const entry of await
|
|
15094
|
+
for (const entry of await readdir2(new URL(`${relative}/`, root), { withFileTypes: true })) {
|
|
15095
15095
|
if (entry.isDirectory()) await walk(`${relative}/${entry.name}`);
|
|
15096
15096
|
else if (entry.isFile()) files[`${relative}/${entry.name}`] = await readFile3(new URL(`${relative}/${entry.name}`, root), "utf8");
|
|
15097
15097
|
}
|
|
@@ -15115,21 +15115,21 @@ async function seedLibrary(home, options2 = {}) {
|
|
|
15115
15115
|
if (seeded === void 0) {
|
|
15116
15116
|
if (current !== void 0) continue;
|
|
15117
15117
|
await mkdir3(path4.dirname(target), { recursive: true });
|
|
15118
|
-
await
|
|
15118
|
+
await writeFile4(target, content, { flag: "wx" }).catch((error51) => {
|
|
15119
15119
|
if (error51.code !== "EEXIST") throw error51;
|
|
15120
15120
|
});
|
|
15121
15121
|
manifest.files[name] = sha(content);
|
|
15122
15122
|
created.push(name);
|
|
15123
15123
|
} else if (current !== void 0 && sha(current) === seeded && seeded !== sha(content)) {
|
|
15124
|
-
await
|
|
15124
|
+
await writeFile4(target, content);
|
|
15125
15125
|
manifest.files[name] = sha(content);
|
|
15126
15126
|
updated.push(name);
|
|
15127
15127
|
}
|
|
15128
15128
|
}
|
|
15129
15129
|
if (created.length || updated.length || manifestText === void 0) {
|
|
15130
15130
|
await mkdir3(home, { recursive: true });
|
|
15131
|
-
const temporary = `${manifestPath}.${
|
|
15132
|
-
await
|
|
15131
|
+
const temporary = `${manifestPath}.${randomUUID3().slice(0, 8)}.tmp`;
|
|
15132
|
+
await writeFile4(temporary, JSON.stringify(manifest, null, 2) + "\n");
|
|
15133
15133
|
await moveFile(temporary, manifestPath);
|
|
15134
15134
|
}
|
|
15135
15135
|
return { created, updated };
|
|
@@ -15169,7 +15169,7 @@ async function jsonObject(file2, code) {
|
|
|
15169
15169
|
}
|
|
15170
15170
|
async function entries(directory) {
|
|
15171
15171
|
try {
|
|
15172
|
-
return (await
|
|
15172
|
+
return (await readdir3(directory, { withFileTypes: true })).sort((a, b) => a.name.localeCompare(b.name));
|
|
15173
15173
|
} catch (error51) {
|
|
15174
15174
|
if (error51.code === "ENOENT") return [];
|
|
15175
15175
|
throw error51;
|
|
@@ -15345,7 +15345,7 @@ function validateTeam(config2, source) {
|
|
|
15345
15345
|
}
|
|
15346
15346
|
async function directories(directory) {
|
|
15347
15347
|
try {
|
|
15348
|
-
return (await
|
|
15348
|
+
return (await readdir4(directory, { withFileTypes: true })).filter((entry) => entry.isDirectory() && validName2(entry.name)).map((entry) => entry.name).sort();
|
|
15349
15349
|
} catch (error51) {
|
|
15350
15350
|
if (error51.code === "ENOENT") return [];
|
|
15351
15351
|
throw error51;
|
|
@@ -15416,8 +15416,8 @@ async function listTeams(root, options2 = {}) {
|
|
|
15416
15416
|
var PIN_KINDS = ["claim", "decision", "finding"];
|
|
15417
15417
|
|
|
15418
15418
|
// packages/core/src/tasks.js
|
|
15419
|
-
import { mkdir as mkdir4, readFile as readFile5, readdir as
|
|
15420
|
-
import { createHash as createHash3, randomUUID as
|
|
15419
|
+
import { mkdir as mkdir4, readFile as readFile5, readdir as readdir5, rmdir as rmdir2, stat as stat3, writeFile as writeFile5 } from "node:fs/promises";
|
|
15420
|
+
import { createHash as createHash3, randomUUID as randomUUID4 } from "node:crypto";
|
|
15421
15421
|
import path8 from "node:path";
|
|
15422
15422
|
|
|
15423
15423
|
// packages/core/src/safe-path.js
|
|
@@ -15473,7 +15473,7 @@ async function taskNames(projectRoot) {
|
|
|
15473
15473
|
await assertNoSymlinks(scope, "tasks");
|
|
15474
15474
|
let names;
|
|
15475
15475
|
try {
|
|
15476
|
-
names = await
|
|
15476
|
+
names = await readdir5(tasksDir(projectRoot));
|
|
15477
15477
|
} catch (error51) {
|
|
15478
15478
|
if (error51.code === "ENOENT") return [];
|
|
15479
15479
|
throw error51;
|
|
@@ -15643,7 +15643,7 @@ async function locked(projectRoot, work) {
|
|
|
15643
15643
|
if (error51.code !== "EEXIST") throw error51;
|
|
15644
15644
|
const age = await stat3(lock).then((info) => Date.now() - info.mtimeMs, () => 0);
|
|
15645
15645
|
if (age > LOCK_STALE_MS) {
|
|
15646
|
-
await
|
|
15646
|
+
await rmdir2(lock).catch(() => {
|
|
15647
15647
|
});
|
|
15648
15648
|
continue;
|
|
15649
15649
|
}
|
|
@@ -15654,7 +15654,7 @@ async function locked(projectRoot, work) {
|
|
|
15654
15654
|
try {
|
|
15655
15655
|
return await work();
|
|
15656
15656
|
} finally {
|
|
15657
|
-
await
|
|
15657
|
+
await rmdir2(lock).catch(() => {
|
|
15658
15658
|
});
|
|
15659
15659
|
}
|
|
15660
15660
|
});
|
|
@@ -15663,15 +15663,15 @@ async function locked(projectRoot, work) {
|
|
|
15663
15663
|
}
|
|
15664
15664
|
async function prepare(dir) {
|
|
15665
15665
|
await mkdir4(dir, { recursive: true });
|
|
15666
|
-
await
|
|
15666
|
+
await writeFile5(path8.join(dir, ".gitignore"), GITIGNORE, { flag: "wx" }).catch((error51) => {
|
|
15667
15667
|
if (error51.code !== "EEXIST") throw error51;
|
|
15668
15668
|
});
|
|
15669
15669
|
}
|
|
15670
15670
|
async function save(projectRoot, task) {
|
|
15671
15671
|
const file2 = taskFile(projectRoot, task.id);
|
|
15672
15672
|
await assertNoSymlinks(path8.join(path8.resolve(projectRoot), ".alp"), path8.join("tasks", `${task.id}.json`));
|
|
15673
|
-
const temporary = `${file2}.${
|
|
15674
|
-
await
|
|
15673
|
+
const temporary = `${file2}.${randomUUID4().slice(0, 8)}.tmp`;
|
|
15674
|
+
await writeFile5(temporary, JSON.stringify(task, null, 2) + "\n");
|
|
15675
15675
|
await moveFile(temporary, file2);
|
|
15676
15676
|
return task;
|
|
15677
15677
|
}
|
|
@@ -15682,7 +15682,7 @@ function newId(tasks, title, parent) {
|
|
|
15682
15682
|
const used = tasks.filter((task) => task.id.startsWith(prefix) && !task.id.slice(prefix.length).includes(".")).map((task) => Number(task.id.slice(prefix.length)));
|
|
15683
15683
|
return `${prefix}${Math.max(0, ...used) + 1}`;
|
|
15684
15684
|
}
|
|
15685
|
-
const hash2 = createHash3("sha256").update(`${title}\0${now()}\0${
|
|
15685
|
+
const hash2 = createHash3("sha256").update(`${title}\0${now()}\0${randomUUID4()}`).digest("hex");
|
|
15686
15686
|
for (let length = 4; length <= 12; length++) if (!taken.has(`t-${hash2.slice(0, length)}`)) return `t-${hash2.slice(0, length)}`;
|
|
15687
15687
|
return fail3("INVALID_TASK", "Could not choose a free task id");
|
|
15688
15688
|
}
|
|
@@ -30404,12 +30404,14 @@ var toolShapes = {
|
|
|
30404
30404
|
body: external_exports.string().min(1).max(2e4),
|
|
30405
30405
|
roles: external_exports.array(external_exports.string().min(1)).min(1).max(10),
|
|
30406
30406
|
lessons: external_exports.array(external_exports.string().min(1).max(600)).max(50).optional(),
|
|
30407
|
-
replace: external_exports.boolean().optional()
|
|
30407
|
+
replace: external_exports.boolean().optional(),
|
|
30408
|
+
requestId: external_exports.string().min(1).max(100).optional()
|
|
30408
30409
|
},
|
|
30409
30410
|
alp_issue: {
|
|
30410
30411
|
action: external_exports.enum(["search", "create", "comment"]),
|
|
30411
30412
|
target: external_exports.enum(["project", "alp"]),
|
|
30412
30413
|
query: external_exports.string().min(1).max(200).optional(),
|
|
30414
|
+
requestId: external_exports.string().min(1).max(100).optional(),
|
|
30413
30415
|
title: external_exports.string().min(1).max(200).optional(),
|
|
30414
30416
|
body: external_exports.string().min(1).max(2e4).optional(),
|
|
30415
30417
|
issue: external_exports.number().int().positive().optional(),
|
|
@@ -30497,7 +30499,7 @@ var toolShapes = {
|
|
|
30497
30499
|
|
|
30498
30500
|
// packages/core/src/providers.js
|
|
30499
30501
|
import { existsSync as existsSync2, readFileSync } from "node:fs";
|
|
30500
|
-
import { readdir as
|
|
30502
|
+
import { readdir as readdir6, readFile as readFile6 } from "node:fs/promises";
|
|
30501
30503
|
import path9 from "node:path";
|
|
30502
30504
|
var PROVIDER_SETTINGS = ["$schema", "kind", "label", "description", "command", "args", "env", "models", "additionalModels", "enabled", "params", "readOnlyMode"];
|
|
30503
30505
|
var BUILTIN_RUNTIMES = ["codex", "claude", "acp", "antigravity"];
|
|
@@ -30553,7 +30555,7 @@ async function listProviders(library) {
|
|
|
30553
30555
|
if (!library) return [];
|
|
30554
30556
|
let names = [];
|
|
30555
30557
|
try {
|
|
30556
|
-
names = await
|
|
30558
|
+
names = await readdir6(path9.join(library, "providers"));
|
|
30557
30559
|
} catch (error51) {
|
|
30558
30560
|
if (error51.code !== "ENOENT") throw error51;
|
|
30559
30561
|
}
|
|
@@ -32435,9 +32437,9 @@ async function syncTemplateProfiles(settings, options2 = {}) {
|
|
|
32435
32437
|
}
|
|
32436
32438
|
|
|
32437
32439
|
// packages/core/src/init.js
|
|
32438
|
-
import { mkdir as mkdir5, writeFile as
|
|
32440
|
+
import { mkdir as mkdir5, writeFile as writeFile6, lstat as lstat3, readFile as readFile7, rename as rename3, rm as rm2 } from "node:fs/promises";
|
|
32439
32441
|
import path11 from "node:path";
|
|
32440
|
-
import { randomUUID as
|
|
32442
|
+
import { randomUUID as randomUUID5 } from "node:crypto";
|
|
32441
32443
|
async function syncProjectSettings(projectRoot, { library, templates: templates2, teamIds, replaceModels = false } = {}) {
|
|
32442
32444
|
const root = path11.resolve(projectRoot);
|
|
32443
32445
|
const file2 = path11.join(root, ".alp/settings.json");
|
|
@@ -32452,11 +32454,11 @@ async function syncProjectSettings(projectRoot, { library, templates: templates2
|
|
|
32452
32454
|
const next = await syncTemplateProfiles(settings, { root, library, templates: templates2, teamIds, replaceModels });
|
|
32453
32455
|
validateSettings(next, file2);
|
|
32454
32456
|
if (JSON.stringify(settings) === JSON.stringify(next)) return false;
|
|
32455
|
-
const temporary = `${file2}.${
|
|
32457
|
+
const temporary = `${file2}.${randomUUID5()}.tmp`;
|
|
32456
32458
|
try {
|
|
32457
|
-
await
|
|
32459
|
+
await writeFile6(temporary, JSON.stringify(next, null, 2) + "\n", { flag: "wx", mode: info.mode });
|
|
32458
32460
|
if (await readFile7(file2, "utf8") !== before) throw new Error(`Settings changed while saving the template: ${file2}`);
|
|
32459
|
-
await
|
|
32461
|
+
await rename3(temporary, file2);
|
|
32460
32462
|
} finally {
|
|
32461
32463
|
await rm2(temporary, { force: true });
|
|
32462
32464
|
}
|
|
@@ -32694,7 +32696,7 @@ var TimelineDeltas = class {
|
|
|
32694
32696
|
};
|
|
32695
32697
|
|
|
32696
32698
|
// integrations/paseo/server/paseo/timeline-store.ts
|
|
32697
|
-
import { randomUUID as
|
|
32699
|
+
import { randomUUID as randomUUID6 } from "node:crypto";
|
|
32698
32700
|
|
|
32699
32701
|
// node_modules/@getpaseo/protocol/dist/timeline-identity.js
|
|
32700
32702
|
function timelineItemIdentity(item) {
|
|
@@ -33099,7 +33101,7 @@ var InMemoryAgentTimelineStore = class {
|
|
|
33099
33101
|
const projection = new TimelineProjection();
|
|
33100
33102
|
for (const row of rows) projection.append(row);
|
|
33101
33103
|
this.states.set(agentId, {
|
|
33102
|
-
epoch: options2?.epoch ??
|
|
33104
|
+
epoch: options2?.epoch ?? randomUUID6(),
|
|
33103
33105
|
projection,
|
|
33104
33106
|
minSeq: projection.getRows()[0]?.seqStart ?? 0,
|
|
33105
33107
|
nextSeq
|
|
@@ -33202,6 +33204,17 @@ var InMemoryAgentTimelineStore = class {
|
|
|
33202
33204
|
}
|
|
33203
33205
|
};
|
|
33204
33206
|
|
|
33207
|
+
// integrations/paseo/server/session-usage.ts
|
|
33208
|
+
var USAGE_FIELDS = ["inputTokens", "cachedInputTokens", "outputTokens", "totalCostUsd", "contextWindowMaxTokens", "contextWindowUsedTokens"];
|
|
33209
|
+
function agentUsage(usage) {
|
|
33210
|
+
const out = {};
|
|
33211
|
+
for (const key of USAGE_FIELDS) {
|
|
33212
|
+
const value = usage?.[key];
|
|
33213
|
+
if (typeof value === "number" && Number.isFinite(value)) out[key] = value;
|
|
33214
|
+
}
|
|
33215
|
+
return out;
|
|
33216
|
+
}
|
|
33217
|
+
|
|
33205
33218
|
// integrations/paseo/server/paseo/agents.ts
|
|
33206
33219
|
var PROVIDER = "alp";
|
|
33207
33220
|
var POLL_MS = 2e3;
|
|
@@ -33327,6 +33340,8 @@ function createAgents({ clientFactory, home, broadcast, directory, log: log2 = (
|
|
|
33327
33340
|
pendingPermissions: [...questions.values()].filter((question) => question.rootId === session.id).map(permissionOf),
|
|
33328
33341
|
persistence: session.persistent ? { provider: PROVIDER, sessionId: session.id } : null,
|
|
33329
33342
|
runtimeInfo: { provider: PROVIDER, sessionId: session.id, model: `${session.runtime}:${session.model}`, modeId: session.mode },
|
|
33343
|
+
// Paseo's context meter reads the agent's last usage.
|
|
33344
|
+
...session.usage ? { lastUsage: agentUsage(session.usage) } : {},
|
|
33330
33345
|
...session.lastError ? { lastError: session.lastError.message } : {},
|
|
33331
33346
|
title: session.title ?? null,
|
|
33332
33347
|
labels: {},
|
|
@@ -33389,8 +33404,7 @@ function createAgents({ clientFactory, home, broadcast, directory, log: log2 = (
|
|
|
33389
33404
|
});
|
|
33390
33405
|
}
|
|
33391
33406
|
for (const id2 of [...roots.keys()]) if (!seen.has(id2)) {
|
|
33392
|
-
|
|
33393
|
-
epochs.delete(id2);
|
|
33407
|
+
forget(id2);
|
|
33394
33408
|
broadcast({ type: "agent_update", payload: { kind: "remove", agentId: id2 } });
|
|
33395
33409
|
directory.changed();
|
|
33396
33410
|
}
|
|
@@ -33505,8 +33519,10 @@ function createAgents({ clientFactory, home, broadcast, directory, log: log2 = (
|
|
|
33505
33519
|
break;
|
|
33506
33520
|
case "turn.ended": {
|
|
33507
33521
|
turns.delete(root);
|
|
33508
|
-
if (event.state === "completed")
|
|
33509
|
-
|
|
33522
|
+
if (event.state === "completed") {
|
|
33523
|
+
const usage = roots.get(root)?.usage;
|
|
33524
|
+
stream(root, { type: "turn_completed", provider: PROVIDER, turnId: event.turnId, ...usage ? { usage: agentUsage(usage) } : {} }, envelope.ts);
|
|
33525
|
+
} else if (event.state === "canceled") stream(root, { type: "turn_canceled", provider: PROVIDER, turnId: event.turnId, reason: event.error?.message ?? "Stopped" }, envelope.ts);
|
|
33510
33526
|
else stream(root, { type: "turn_failed", provider: PROVIDER, turnId: event.turnId, error: event.error?.message ?? "The turn failed" }, envelope.ts);
|
|
33511
33527
|
if (!replaying.has(root) && event.state !== "canceled") {
|
|
33512
33528
|
const reason = event.state === "completed" ? "finished" : "error";
|
|
@@ -33515,6 +33531,13 @@ function createAgents({ clientFactory, home, broadcast, directory, log: log2 = (
|
|
|
33515
33531
|
}
|
|
33516
33532
|
break;
|
|
33517
33533
|
}
|
|
33534
|
+
case "usage": {
|
|
33535
|
+
if (replaying.has(root) || !session) return;
|
|
33536
|
+
const next = { ...session, usage: event.usage };
|
|
33537
|
+
roots.set(root, next);
|
|
33538
|
+
upsert(next);
|
|
33539
|
+
return;
|
|
33540
|
+
}
|
|
33518
33541
|
case "session.opened":
|
|
33519
33542
|
case "session.updated":
|
|
33520
33543
|
case "session.closed":
|
|
@@ -33530,19 +33553,24 @@ function createAgents({ clientFactory, home, broadcast, directory, log: log2 = (
|
|
|
33530
33553
|
if (timelines.has(root)) return Promise.resolve();
|
|
33531
33554
|
let pending = attaching.get(root);
|
|
33532
33555
|
if (!pending) {
|
|
33556
|
+
const connection = alp;
|
|
33557
|
+
if (!connection) return Promise.reject(new Error("ALP daemon is not connected"));
|
|
33533
33558
|
pending = (async () => {
|
|
33534
33559
|
timelines.initialize(root);
|
|
33535
33560
|
deltas.set(root, new TimelineDeltas());
|
|
33536
33561
|
epochs.delete(root);
|
|
33537
33562
|
replaying.add(root);
|
|
33563
|
+
const current = () => attaching.get(root) === pending;
|
|
33538
33564
|
try {
|
|
33539
|
-
await
|
|
33565
|
+
await connection.request("session.attach", { sessionId: root, replay: true });
|
|
33540
33566
|
} catch (error51) {
|
|
33541
|
-
timelines.delete(root);
|
|
33567
|
+
if (current()) timelines.delete(root);
|
|
33542
33568
|
throw error51;
|
|
33543
33569
|
} finally {
|
|
33544
|
-
|
|
33545
|
-
|
|
33570
|
+
if (current()) {
|
|
33571
|
+
replaying.delete(root);
|
|
33572
|
+
attaching.delete(root);
|
|
33573
|
+
}
|
|
33546
33574
|
}
|
|
33547
33575
|
})();
|
|
33548
33576
|
attaching.set(root, pending);
|
|
@@ -33563,6 +33591,22 @@ function createAgents({ clientFactory, home, broadcast, directory, log: log2 = (
|
|
|
33563
33591
|
}
|
|
33564
33592
|
void ensureTimeline(root).catch((error51) => log2(`agents reattach failed: ${error51?.message ?? error51}`));
|
|
33565
33593
|
}
|
|
33594
|
+
function forget(root) {
|
|
33595
|
+
roots.delete(root);
|
|
33596
|
+
timelines.delete(root);
|
|
33597
|
+
deltas.delete(root);
|
|
33598
|
+
attaching.delete(root);
|
|
33599
|
+
replaying.delete(root);
|
|
33600
|
+
epochs.delete(root);
|
|
33601
|
+
turns.delete(root);
|
|
33602
|
+
attention.delete(root);
|
|
33603
|
+
for (const child of [...children2.values()]) {
|
|
33604
|
+
if (child.root !== root) continue;
|
|
33605
|
+
children2.delete(child.id);
|
|
33606
|
+
childTimelines.delete(child.id);
|
|
33607
|
+
childDeltas.delete(child.id);
|
|
33608
|
+
}
|
|
33609
|
+
}
|
|
33566
33610
|
function known(agentId) {
|
|
33567
33611
|
const session = roots.get(agentId);
|
|
33568
33612
|
if (!session) throw Object.assign(new Error(`No agent ${agentId}`), { code: "agent_not_found" });
|
|
@@ -33580,14 +33624,14 @@ function createAgents({ clientFactory, home, broadcast, directory, log: log2 = (
|
|
|
33580
33624
|
async function create(input) {
|
|
33581
33625
|
const { config: config2 } = input;
|
|
33582
33626
|
if (config2.provider !== PROVIDER) throw new Error(`ALP runs its own teams; ${config2.provider} is not one of them`);
|
|
33583
|
-
const sessionId = `web-${
|
|
33627
|
+
const sessionId = `web-${randomUUID7()}`;
|
|
33584
33628
|
if (input.workspaceId) directory.assign(sessionId, input.workspaceId);
|
|
33585
33629
|
await alp.request("session.create", { sessionId, spec: { cwd: config2.cwd, persist: true, ...config2.model ? { workflow: config2.model } : {}, ...config2.modeId ? { mode: config2.modeId } : {} } });
|
|
33586
33630
|
if (config2.title) await alp.request("session.rename", { sessionId, title: config2.title });
|
|
33587
33631
|
await refresh();
|
|
33588
33632
|
await ensureTimeline(sessionId);
|
|
33589
33633
|
const prompt = input.initialPrompt?.trim();
|
|
33590
|
-
if (prompt) await alp.request("session.prompt", { sessionId, clientMessageId: input.clientMessageId ??
|
|
33634
|
+
if (prompt) await alp.request("session.prompt", { sessionId, clientMessageId: input.clientMessageId ?? randomUUID7(), content: [{ type: "text", text: prompt }] });
|
|
33591
33635
|
return agentOf(known(sessionId));
|
|
33592
33636
|
}
|
|
33593
33637
|
const view = {
|
|
@@ -33769,7 +33813,7 @@ function createAgents({ clientFactory, home, broadcast, directory, log: log2 = (
|
|
|
33769
33813
|
if (running && message.activeTurnBehavior === "interrupt") await alp.request("session.interrupt", { sessionId: session.id });
|
|
33770
33814
|
await alp.request("session.prompt", {
|
|
33771
33815
|
sessionId: session.id,
|
|
33772
|
-
clientMessageId: message.messageId ??
|
|
33816
|
+
clientMessageId: message.messageId ?? randomUUID7(),
|
|
33773
33817
|
delivery: running && message.activeTurnBehavior !== "interrupt" ? "steer" : "auto",
|
|
33774
33818
|
content: [{ type: "text", text: message.text }]
|
|
33775
33819
|
});
|
|
@@ -34350,14 +34394,14 @@ function createCheckouts({ broadcast, log: log2 = () => {
|
|
|
34350
34394
|
}
|
|
34351
34395
|
|
|
34352
34396
|
// integrations/paseo/server/paseo/files.ts
|
|
34353
|
-
import { readFile as readFile8, readdir as
|
|
34397
|
+
import { readFile as readFile8, readdir as readdir7, realpath as realpath2, stat as stat5 } from "node:fs/promises";
|
|
34354
34398
|
import os4 from "node:os";
|
|
34355
34399
|
import path14 from "node:path";
|
|
34356
34400
|
var SKIPPED = /* @__PURE__ */ new Set(["node_modules", "Library", ".git", "dist", "build", ".cache", "target", ".venv", "venv", "__pycache__"]);
|
|
34357
34401
|
var HOME_SCAN_LIMIT = 5e3;
|
|
34358
34402
|
var HOME_DEPTH = 4;
|
|
34359
34403
|
var WORKSPACE_SCAN_LIMIT = 2e4;
|
|
34360
|
-
var children = (directory) =>
|
|
34404
|
+
var children = (directory) => readdir7(directory, { withFileTypes: true }).catch(() => []);
|
|
34361
34405
|
var expand = (query) => query === "~" ? os4.homedir() : query.startsWith("~/") ? path14.join(os4.homedir(), query.slice(2)) : query;
|
|
34362
34406
|
function rank2(candidate, query) {
|
|
34363
34407
|
const name = candidate.toLowerCase();
|
|
@@ -34482,7 +34526,7 @@ async function fileExplorer(message) {
|
|
|
34482
34526
|
const relative = posixRelative(realRoot, real);
|
|
34483
34527
|
if (message.mode === "list") {
|
|
34484
34528
|
const entries2 = [];
|
|
34485
|
-
for (const entry of await
|
|
34529
|
+
for (const entry of await readdir7(real, { withFileTypes: true })) {
|
|
34486
34530
|
const child = path14.join(real, entry.name);
|
|
34487
34531
|
const resolved = entry.isSymbolicLink() ? await inside(realRoot, path14.relative(realRoot, child)).then((found) => found.real, () => void 0) : child;
|
|
34488
34532
|
if (!resolved) continue;
|
|
@@ -34512,11 +34556,11 @@ async function fileExplorer(message) {
|
|
|
34512
34556
|
import { createHash as createHash6 } from "node:crypto";
|
|
34513
34557
|
|
|
34514
34558
|
// alp-plugin-client:plugin-client
|
|
34515
|
-
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;})' };
|
|
34559
|
+
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;})' };
|
|
34516
34560
|
|
|
34517
34561
|
// packages/core/src/library-edit.js
|
|
34518
|
-
import { mkdir as mkdir6, rename as
|
|
34519
|
-
import { createHash as createHash5, randomUUID as
|
|
34562
|
+
import { lstat as lstat4, mkdir as mkdir6, readdir as readdir8, rename as rename4, rm as rm3, stat as stat6, writeFile as writeFile7 } from "node:fs/promises";
|
|
34563
|
+
import { createHash as createHash5, randomUUID as randomUUID8 } from "node:crypto";
|
|
34520
34564
|
import path15 from "node:path";
|
|
34521
34565
|
var EDIT_KINDS = ["agents", "skills", "mcp", "hooks", "teams", "providers"];
|
|
34522
34566
|
var validName3 = (name) => typeof name === "string" && /^[\w.-]+$/.test(name) && name !== "." && name !== "..";
|
|
@@ -34548,6 +34592,42 @@ function base(scope, { root, library }, kind) {
|
|
|
34548
34592
|
return fail4("INVALID_SCOPE", `Scope must be library or project, not '${scope}'`);
|
|
34549
34593
|
}
|
|
34550
34594
|
var revisionOf = (content) => content === void 0 ? null : createHash5("sha256").update(JSON.stringify(content)).digest("hex").slice(0, 16);
|
|
34595
|
+
function assertProjectDataContent(kind, content) {
|
|
34596
|
+
const deny = () => fail4("UNSAFE_LIBRARY_WRITE", "Project-data writes allow only instruction entries and non-executable agent configuration");
|
|
34597
|
+
if (!object7(content) || !["agents", "skills"].includes(kind)) deny();
|
|
34598
|
+
const keys2 = kind === "skills" ? ["body"] : ["instructions", "config"];
|
|
34599
|
+
if (Object.keys(content).some((key) => !keys2.includes(key))) deny();
|
|
34600
|
+
const text = kind === "skills" ? content.body : content.instructions;
|
|
34601
|
+
if (typeof text !== "string" || !text.trim()) deny();
|
|
34602
|
+
if (content.config !== void 0) {
|
|
34603
|
+
const config2 = content.config;
|
|
34604
|
+
if (!object7(config2)) deny();
|
|
34605
|
+
const allowed = ["description", "model", "thinking", "context", "autocompact"];
|
|
34606
|
+
if (Object.keys(config2).some((key) => !allowed.includes(key))) deny();
|
|
34607
|
+
for (const key of ["description", "thinking"]) if (config2[key] !== void 0 && typeof config2[key] !== "string") deny();
|
|
34608
|
+
if (config2.model !== void 0 && (typeof config2.model !== "string" || !/^(codex|claude):[^\s/\\:]{1,240}$/.test(config2.model))) deny();
|
|
34609
|
+
for (const key of ["context", "autocompact"]) if (config2[key] !== void 0 && !(typeof config2[key] === "string" || typeof config2[key] === "number" && Number.isFinite(config2[key]))) deny();
|
|
34610
|
+
}
|
|
34611
|
+
}
|
|
34612
|
+
async function projectDataEntry(kind, name, { scope, root, library, templates: templates2 }) {
|
|
34613
|
+
if (scope !== "project" || !root || !["agents", "skills"].includes(kind)) fail4("UNSAFE_LIBRARY_WRITE", "Project-data writes require project scope and agents or skills");
|
|
34614
|
+
nameOf(name);
|
|
34615
|
+
const directory = base(scope, { root, library }, kind);
|
|
34616
|
+
await safeEntryPaths(directory, kind, name);
|
|
34617
|
+
const found = await layers(kind, name, { root, library, templates: templates2 });
|
|
34618
|
+
if (found.library !== void 0 || found.builtin !== void 0) fail4("UNSAFE_LIBRARY_WRITE", "Project-data writes cannot shadow or reveal a library or built-in entry");
|
|
34619
|
+
if (found.project !== void 0) assertProjectDataContent(kind, found.project);
|
|
34620
|
+
const owned = path15.join(directory, kind, name);
|
|
34621
|
+
const files = await readdir8(owned).catch((error51) => {
|
|
34622
|
+
if (error51.code === "ENOENT") return [];
|
|
34623
|
+
throw error51;
|
|
34624
|
+
});
|
|
34625
|
+
const allowed = new Set(FILES[kind](name).map(([file2]) => path15.basename(file2)));
|
|
34626
|
+
for (const file2 of files) {
|
|
34627
|
+
const info = await lstat4(path15.join(owned, file2));
|
|
34628
|
+
if (!allowed.has(file2) || !info.isFile() || info.isSymbolicLink() || info.nlink !== 1) fail4("UNSAFE_LIBRARY_WRITE", "Project-data entries cannot contain sidecars, links or executable assets");
|
|
34629
|
+
}
|
|
34630
|
+
}
|
|
34551
34631
|
async function safeEntryPaths(directory, kind, name) {
|
|
34552
34632
|
for (const [file2] of FILES[kind](name)) {
|
|
34553
34633
|
await assertNoSymlinks(directory, path15.join(kind, file2));
|
|
@@ -34740,14 +34820,18 @@ async function check2(kind, name, content, { scope, root, library, templates: te
|
|
|
34740
34820
|
}
|
|
34741
34821
|
async function writeAtomic(file2, text) {
|
|
34742
34822
|
await mkdir6(path15.dirname(file2), { recursive: true });
|
|
34743
|
-
const temporary = `${file2}.${
|
|
34744
|
-
await
|
|
34823
|
+
const temporary = `${file2}.${randomUUID8().slice(0, 8)}.tmp`;
|
|
34824
|
+
await writeFile7(temporary, text);
|
|
34745
34825
|
await moveFile(temporary, file2);
|
|
34746
34826
|
}
|
|
34747
34827
|
var exists2 = (target) => stat6(target).then(() => true, () => false);
|
|
34748
|
-
async function saveEntry(kind, name, content, { scope, root, library, templates: templates2, revision } = {}) {
|
|
34828
|
+
async function saveEntry(kind, name, content, { scope, root, library, templates: templates2, revision, policy } = {}) {
|
|
34749
34829
|
kindOf(kind);
|
|
34750
34830
|
nameOf(name);
|
|
34831
|
+
if (policy === "project-data") {
|
|
34832
|
+
assertProjectDataContent(kind, content);
|
|
34833
|
+
await projectDataEntry(kind, name, { scope, root, library, templates: templates2 });
|
|
34834
|
+
}
|
|
34751
34835
|
const directory = base(scope, { root, library }, kind);
|
|
34752
34836
|
await safeEntryPaths(directory, kind, name);
|
|
34753
34837
|
await check2(kind, name, content, { scope, root, library, templates: templates2 });
|
|
@@ -34769,9 +34853,10 @@ async function saveEntry(kind, name, content, { scope, root, library, templates:
|
|
|
34769
34853
|
}
|
|
34770
34854
|
return { revision: revisionOf(await readLayer(kind, name, directory)) };
|
|
34771
34855
|
}
|
|
34772
|
-
async function deleteEntry(kind, name, { scope, root, library, templates: templates2, revision } = {}) {
|
|
34856
|
+
async function deleteEntry(kind, name, { scope, root, library, templates: templates2, revision, policy } = {}) {
|
|
34773
34857
|
kindOf(kind);
|
|
34774
34858
|
nameOf(name);
|
|
34859
|
+
if (policy === "project-data") await projectDataEntry(kind, name, { scope, root, library, templates: templates2 });
|
|
34775
34860
|
const directory = base(scope, { root, library }, kind);
|
|
34776
34861
|
const current = await readLayer(kind, name, directory);
|
|
34777
34862
|
if (current === void 0) fail4("NOT_FOUND", `No ${kind} entry '${name}' in the ${scope}`);
|
|
@@ -34787,14 +34872,25 @@ async function deleteEntry(kind, name, { scope, root, library, templates: templa
|
|
|
34787
34872
|
const now3 = scope === "project" && found.library !== void 0 ? "library" : "builtin";
|
|
34788
34873
|
return { removed: true, ...fallback !== void 0 ? { now: now3 } : {} };
|
|
34789
34874
|
}
|
|
34790
|
-
async function duplicateEntry(kind, from, to, { scope, root, library, templates: templates2 } = {}) {
|
|
34875
|
+
async function duplicateEntry(kind, from, to, { scope, root, library, templates: templates2, policy } = {}) {
|
|
34876
|
+
kindOf(kind);
|
|
34877
|
+
nameOf(from);
|
|
34878
|
+
nameOf(to);
|
|
34879
|
+
if (policy === "project-data") {
|
|
34880
|
+
await projectDataEntry(kind, from, { scope, root, library, templates: templates2 });
|
|
34881
|
+
await projectDataEntry(kind, to, { scope, root, library, templates: templates2 });
|
|
34882
|
+
}
|
|
34791
34883
|
const { content } = await getEntry(kind, from, { root, library, templates: templates2 });
|
|
34792
|
-
return saveEntry(kind, to, structuredClone(content), { scope, root, library, templates: templates2, revision: null });
|
|
34884
|
+
return saveEntry(kind, to, structuredClone(content), { scope, root, library, templates: templates2, revision: null, policy });
|
|
34793
34885
|
}
|
|
34794
|
-
async function renameEntry(kind, from, to, { scope, root, library, templates: templates2 } = {}) {
|
|
34886
|
+
async function renameEntry(kind, from, to, { scope, root, library, templates: templates2, policy } = {}) {
|
|
34795
34887
|
kindOf(kind);
|
|
34796
34888
|
nameOf(from);
|
|
34797
34889
|
nameOf(to);
|
|
34890
|
+
if (policy === "project-data") {
|
|
34891
|
+
await projectDataEntry(kind, from, { scope, root, library, templates: templates2 });
|
|
34892
|
+
await projectDataEntry(kind, to, { scope, root, library, templates: templates2 });
|
|
34893
|
+
}
|
|
34798
34894
|
const directory = base(scope, { root, library }, kind);
|
|
34799
34895
|
const content = await readLayer(kind, from, directory);
|
|
34800
34896
|
if (content === void 0) fail4("NOT_FOUND", `No ${kind} entry '${from}' in the ${scope}`);
|
|
@@ -34804,9 +34900,9 @@ async function renameEntry(kind, from, to, { scope, root, library, templates: te
|
|
|
34804
34900
|
await check2(kind, to, content, { scope, root, library, templates: templates2 });
|
|
34805
34901
|
if (ownDirectory(kind)) {
|
|
34806
34902
|
if (await exists2(path15.join(directory, kind, to))) fail4("REVISION_CONFLICT", `${path15.join(directory, kind, to)} already exists`);
|
|
34807
|
-
await
|
|
34903
|
+
await rename4(path15.join(directory, kind, from), path15.join(directory, kind, to));
|
|
34808
34904
|
} else {
|
|
34809
|
-
await
|
|
34905
|
+
await rename4(path15.join(directory, kind, `${from}.json`), path15.join(directory, kind, `${to}.json`));
|
|
34810
34906
|
}
|
|
34811
34907
|
return { revision: revisionOf(await readLayer(kind, to, directory)) };
|
|
34812
34908
|
}
|
|
@@ -35309,7 +35405,9 @@ var libraryGet = defineRpc2({
|
|
|
35309
35405
|
revision: external_exports.string().nullable(),
|
|
35310
35406
|
usedBy: external_exports.array(external_exports.string()),
|
|
35311
35407
|
/** Agents: the skills the library gives it by name (role-skills.json). */
|
|
35312
|
-
librarySkills: external_exports.array(external_exports.string()).optional()
|
|
35408
|
+
librarySkills: external_exports.array(external_exports.string()).optional(),
|
|
35409
|
+
/** ALP remote mode: JSON Pointers of the values `content` holds as a secret marker, not as the value. */
|
|
35410
|
+
secrets: external_exports.array(external_exports.string()).optional()
|
|
35313
35411
|
})
|
|
35314
35412
|
});
|
|
35315
35413
|
var librarySkills2 = defineRpc2({
|
|
@@ -35582,7 +35680,7 @@ function createUsage(read) {
|
|
|
35582
35680
|
|
|
35583
35681
|
// integrations/paseo/server/paseo/workspaces.ts
|
|
35584
35682
|
import { randomBytes } from "node:crypto";
|
|
35585
|
-
import { mkdir as mkdir7, readFile as readFile9, stat as stat7, writeFile as
|
|
35683
|
+
import { mkdir as mkdir7, readFile as readFile9, stat as stat7, writeFile as writeFile8 } from "node:fs/promises";
|
|
35586
35684
|
import path18 from "node:path";
|
|
35587
35685
|
|
|
35588
35686
|
// node_modules/@getpaseo/protocol/dist/agent-state-bucket.js
|
|
@@ -35670,7 +35768,7 @@ function createWorkspaces({ home, broadcast, agents, inDevelopment, log: log2 =
|
|
|
35670
35768
|
saving = saving.then(async () => {
|
|
35671
35769
|
await mkdir7(path18.dirname(file2), { recursive: true });
|
|
35672
35770
|
const temporary = `${file2}.${process.pid}.tmp`;
|
|
35673
|
-
await
|
|
35771
|
+
await writeFile8(temporary, text);
|
|
35674
35772
|
await moveFile(temporary, file2);
|
|
35675
35773
|
}).catch((error51) => log2(`web workspaces not saved: ${error51?.message ?? error51}`));
|
|
35676
35774
|
return saving;
|
|
@@ -36143,8 +36241,8 @@ function createWorkspaces({ home, broadcast, agents, inDevelopment, log: log2 =
|
|
|
36143
36241
|
}
|
|
36144
36242
|
|
|
36145
36243
|
// integrations/paseo/server/paseo/relay.ts
|
|
36146
|
-
import { randomUUID as
|
|
36147
|
-
import { readFile as readFile10, rename as
|
|
36244
|
+
import { randomUUID as randomUUID9 } from "node:crypto";
|
|
36245
|
+
import { readFile as readFile10, rename as rename6, writeFile as writeFile9, mkdir as mkdir8 } from "node:fs/promises";
|
|
36148
36246
|
import path19 from "node:path";
|
|
36149
36247
|
|
|
36150
36248
|
// node_modules/@getpaseo/relay/dist/crypto.js
|
|
@@ -37053,9 +37151,9 @@ async function relayKeyPair(home) {
|
|
|
37053
37151
|
const keyPair = generateKeyPair();
|
|
37054
37152
|
const publicKeyB64 = exportPublicKey(keyPair.publicKey);
|
|
37055
37153
|
await mkdir8(home, { recursive: true, mode: 448 });
|
|
37056
|
-
const temporary = `${file2}.${
|
|
37057
|
-
await
|
|
37058
|
-
await
|
|
37154
|
+
const temporary = `${file2}.${randomUUID9().slice(0, 8)}.tmp`;
|
|
37155
|
+
await writeFile9(temporary, JSON.stringify({ v: 2, publicKeyB64, secretKeyB64: exportSecretKey(keyPair.secretKey) }, null, 2) + "\n", { mode: 384 });
|
|
37156
|
+
await rename6(temporary, file2);
|
|
37059
37157
|
return { keyPair, publicKeyB64 };
|
|
37060
37158
|
}
|
|
37061
37159
|
function pairingUrl(offer) {
|