@anhlp/alp 0.0.0-beta.1 → 0.0.0-beta.2

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 CHANGED
@@ -4,11 +4,13 @@ Provider-neutral filesystem agent resolution with a server-side Paseo provider.
4
4
 
5
5
  ## Install
6
6
 
7
- The current release is the beta `0.0.0-beta.1` (not published yet): see the
7
+ The current release is the beta `0.0.0-beta.2` (until it is on npm, `@beta` installs
8
+ `0.0.0-beta.1`; check with `npm view @anhlp/alp dist-tags`): see the
8
9
  [release notes](docs/alp/beta-release-notes.md) for what it includes and its known issues, and
9
10
  [installing, upgrading and removing the beta](docs/alp/beta-install.md) for every step. Name the
10
- beta when you install (`@beta`, or exactly `@0.0.0-beta.1`); a plain `npm install -g @anhlp/alp`
11
- installs the older `0.10.0`.
11
+ beta when you install (`@beta`, or exactly `@0.0.0-beta.2`); a plain `npm install -g @anhlp/alp`
12
+ installs whatever npm's `latest` tag points at, which moves to a new beta only after that
13
+ beta's post-publish checks.
12
14
 
13
15
  Supported: Linux or macOS, Node.js 22 (22.12 or later) or 24, and a signed-in Codex CLI or
14
16
  Claude Code on PATH. Windows and Node.js 26 are experimental; Node.js 20 is not supported.
@@ -332,7 +334,7 @@ Details: [ALPD §60](plans/reference/ALPD.md#60-alp-as-an-acp-agent-2026-10-10).
332
334
 
333
335
  ## Paseo
334
336
 
335
- To use the published plugin, follow [the plugin's README](integrations/paseo/README.md) or [beta-install.md](docs/alp/beta-install.md#paseo-plugin): `paseo plugin add npm:@anhlp/alp-paseo@beta`. The beta supports Paseo `>=0.11.1 <0.12.0`. See [installation and runtime behavior](docs/alp/paseo-plugin.md) and the historical [phase acceptance evidence](docs/alp/phase-2-5-results.md). The plugin was verified with Paseo 0.11.1 and live Codex and Claude Code permission changes before the beta; the beta's own runs are in [beta-scope.md](docs/alp/beta-scope.md) §6.
337
+ To use the published plugin, follow [the plugin's README](integrations/paseo/README.md) or [beta-install.md](docs/alp/beta-install.md#paseo-plugin): `paseo plugin add npm:@anhlp/alp-paseo@beta` (from `0.0.0-beta.2`; in beta.1 the `npm:` source fails, [#111](https://github.com/phucanh08/alp/issues/111), so there run `npm install -g @anhlp/alp-paseo@beta`, then `paseo plugin add "$(npm root -g)/@anhlp/alp-paseo"`). The beta supports Paseo `>=0.11.1 <0.12.0`. See [installation and runtime behavior](docs/alp/paseo-plugin.md) and the historical [phase acceptance evidence](docs/alp/phase-2-5-results.md). The plugin was verified with Paseo 0.11.1 and live Codex and Claude Code permission changes before the beta; the beta's own runs are in [beta-scope.md](docs/alp/beta-scope.md) §6.
336
338
 
337
339
  **Settings → ALP** manages your library of teams, agents, skills, MCP servers, hooks and ACP providers, and the **ALP project** workspace panel manages a project's overrides ([settings screen](docs/alp/paseo-plugin.md#alp-settings-and-the-project-panel)).
338
340
 
package/dist/acp.js CHANGED
@@ -18552,8 +18552,10 @@ var AlpRpcError = class extends Error {
18552
18552
  };
18553
18553
  var ERROR = Object.freeze({ failed: 1e3, notFound: 1001, forbidden: 1003, conflict: 1004, unavailable: 1005, protocol: 1006 });
18554
18554
  var RPC_ERROR = Object.freeze({ parseError: -32700, invalidRequest: -32600, methodNotFound: -32601, invalidParams: -32602 });
18555
- var CAPABILITY = Object.freeze({ attachAfter: "attach.after", promptReceipts: "prompt.receipts", extensionMethods: "extension.methods", team: "team", task: "task", library: "library", settingsLanguage: "settings.language" });
18556
- 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", "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"]);
18555
+ 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" });
18556
+ 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 });
18557
+ 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"]);
18558
+ var WORKSPACE_FILES = Object.freeze({ maxReadBytes: 1024 * 1024, maxListEntries: 1e3, maxPathLength: 4096 });
18557
18559
 
18558
18560
  // packages/client/src/rpc/errors.js
18559
18561
  var BRAND = Symbol.for("@anhlp/alp-client/AlpClientError");
@@ -19323,6 +19325,7 @@ async function startDaemon({ home, entry, env = process.env, timeoutMs = 15e3 })
19323
19325
  // packages/cli/src/acp/agent.ts
19324
19326
  import { randomUUID } from "node:crypto";
19325
19327
  import path4 from "node:path";
19328
+ var unlistedOf = ({ teams, team, teamLabel }) => teams.some((entry) => entry.id === team) ? void 0 : { id: team, label: teamLabel ?? (team === "custom" ? "Custom" : team) };
19326
19329
  var MODES = [
19327
19330
  { id: "read-only", name: "Read only", description: "Agents read and search; nothing is changed" },
19328
19331
  { id: "workspace-write", name: "Workspace write", description: "Agents change files and run commands inside the project" },
@@ -19364,34 +19367,120 @@ ${resource.text}
19364
19367
  }
19365
19368
  return text.trim();
19366
19369
  }
19370
+ function shown(file2, cwd) {
19371
+ if (!cwd || !path4.isAbsolute(file2)) return file2;
19372
+ const relative = path4.relative(cwd, file2);
19373
+ return relative && !relative.startsWith("..") && !path4.isAbsolute(relative) ? relative : file2;
19374
+ }
19367
19375
  function toolKind(item) {
19368
- const word = item.detail.type === "shell" ? String(item.detail.command ?? "").trim().split(/[\s{(]/)[0] : item.name;
19376
+ const detail = item.detail;
19377
+ switch (detail.type) {
19378
+ case "read":
19379
+ return "read";
19380
+ case "edit":
19381
+ case "write":
19382
+ return "edit";
19383
+ case "search":
19384
+ return detail.toolName === "web_search" ? "fetch" : "search";
19385
+ case "fetch":
19386
+ return "fetch";
19387
+ case "plan":
19388
+ return "think";
19389
+ case "sub_agent":
19390
+ case "plain_text":
19391
+ return "other";
19392
+ }
19393
+ const word = detail.type === "shell" ? String(detail.command ?? "").trim().split(/[\s{(]/)[0] : item.name;
19369
19394
  if (/^(Read|NotebookRead|LS)$/.test(word)) return "read";
19370
19395
  if (/^(Edit|MultiEdit|Write|NotebookEdit)$/.test(word)) return "edit";
19371
19396
  if (/^(Grep|Glob)$/.test(word)) return "search";
19372
19397
  if (/^(WebFetch|WebSearch)$/.test(word)) return "fetch";
19373
19398
  if (/^(Skill|Task|TodoWrite)$/.test(word) || item.name.startsWith("alp_")) return "other";
19374
- return item.detail.type === "shell" ? "execute" : "other";
19375
- }
19376
- function toolTitle(item) {
19377
- if (item.detail.type === "shell") return clip(String(item.detail.command ?? "").split("\n")[0], 160);
19378
- const input = item.detail.input ?? {};
19399
+ return detail.type === "shell" ? "execute" : "other";
19400
+ }
19401
+ function toolTitle(item, cwd) {
19402
+ const detail = item.detail;
19403
+ switch (detail.type) {
19404
+ case "shell":
19405
+ return clip(String(detail.command ?? "").split("\n")[0], 160);
19406
+ case "read":
19407
+ return clip(`Read ${shown(detail.filePath, cwd)}`, 160);
19408
+ case "edit":
19409
+ return clip(`Edit ${shown(detail.filePath, cwd)}`, 160);
19410
+ case "write":
19411
+ return clip(`Write ${shown(detail.filePath, cwd)}`, 160);
19412
+ case "search":
19413
+ return clip(`${detail.toolName === "web_search" ? "Search the web" : "Search"} ${detail.query}`, 160);
19414
+ case "fetch":
19415
+ return clip(`Fetch ${detail.url}`, 160);
19416
+ case "sub_agent":
19417
+ return clip(`${detail.subAgentType ?? "Sub-agent"}${detail.description ? `: ${detail.description.split("\n")[0]}` : ""}`, 160);
19418
+ case "plan":
19419
+ return "Plan";
19420
+ case "plain_text":
19421
+ return clip(`${item.name}${detail.label ? `: ${detail.label}` : ""}`, 160);
19422
+ }
19423
+ const input = detail.input ?? {};
19379
19424
  if (item.name === "alp_delegate") return clip(`Delegate to ${input.agent ?? "an agent"}: ${String(input.task ?? "").split("\n")[0]}`, 160);
19380
19425
  return clip(`${item.name} ${JSON.stringify(input)}`, 160);
19381
19426
  }
19427
+ var bounded = (text) => text.length > OUTPUT_CHARS ? `${text.slice(0, OUTPUT_CHARS)}
19428
+ \u2026 (${text.length - OUTPUT_CHARS} more characters)` : text;
19382
19429
  function toolOutput(item) {
19430
+ const detail = item.detail;
19431
+ const parts = [];
19383
19432
  let text = "";
19384
- if (item.detail.type === "shell") text = item.detail.output ?? "";
19385
- else {
19386
- const output = item.detail.output;
19387
- text = Array.isArray(output) ? output.map((part) => typeof part?.text === "string" ? part.text : JSON.stringify(part)).join("\n") : output == null ? "" : typeof output === "string" ? output : JSON.stringify(output, null, 2);
19433
+ switch (detail.type) {
19434
+ case "shell":
19435
+ text = detail.output ?? "";
19436
+ break;
19437
+ case "read":
19438
+ text = detail.content ?? "";
19439
+ break;
19440
+ case "edit":
19441
+ if (detail.newString !== void 0 || detail.oldString !== void 0) parts.push({ type: "diff", path: detail.filePath, oldText: detail.oldString ?? null, newText: detail.newString ?? "" });
19442
+ else if (detail.unifiedDiff) text = "```diff\n" + detail.unifiedDiff + (detail.unifiedDiff.endsWith("\n") ? "" : "\n") + "```";
19443
+ break;
19444
+ case "write":
19445
+ if (detail.content !== void 0) parts.push({ type: "diff", path: detail.filePath, oldText: null, newText: detail.content });
19446
+ break;
19447
+ case "search":
19448
+ text = detail.content ?? [...detail.filePaths ?? [], ...(detail.webResults ?? []).map((hit) => `${hit.title} \u2014 ${hit.url}`)].join("\n");
19449
+ break;
19450
+ case "fetch":
19451
+ text = detail.result ?? "";
19452
+ break;
19453
+ case "sub_agent":
19454
+ text = detail.log || detail.description || "";
19455
+ break;
19456
+ case "plan":
19457
+ text = detail.text;
19458
+ break;
19459
+ case "plain_text":
19460
+ text = detail.text ?? "";
19461
+ break;
19462
+ default: {
19463
+ const output = detail.output;
19464
+ text = Array.isArray(output) ? output.map((part) => typeof part?.text === "string" ? part.text : JSON.stringify(part)).join("\n") : output == null ? "" : typeof output === "string" ? output : JSON.stringify(output, null, 2);
19465
+ }
19388
19466
  }
19389
19467
  if (item.error) text = text ? `${text}
19390
19468
  ${item.error}` : item.error;
19391
- if (!text) return [];
19392
- if (text.length > OUTPUT_CHARS) text = `${text.slice(0, OUTPUT_CHARS)}
19393
- \u2026 (${text.length - OUTPUT_CHARS} more characters)`;
19394
- return [{ type: "content", content: { type: "text", text } }];
19469
+ if (text) parts.push({ type: "content", content: { type: "text", text: bounded(text) } });
19470
+ return parts.map((part) => part.type === "diff" ? { ...part, newText: bounded(part.newText), ...part.oldText ? { oldText: bounded(part.oldText) } : {} } : part);
19471
+ }
19472
+ function toolInput(item) {
19473
+ const detail = item.detail;
19474
+ if (detail.type === "shell") return { command: detail.command, cwd: detail.cwd };
19475
+ if (detail.type === "unknown" || !["read", "edit", "write", "search", "fetch", "sub_agent", "plan", "plain_text"].includes(detail.type)) return detail.input;
19476
+ const { type: _type, content: _content, oldString: _old, newString: _new, unifiedDiff: _diff, result: _result, log: _log, text: _text, filePaths: _paths, webResults: _hits, ...rest } = detail;
19477
+ return rest;
19478
+ }
19479
+ function toolLocations(item) {
19480
+ const detail = item.detail;
19481
+ if (detail.type !== "read" && detail.type !== "edit" && detail.type !== "write") return void 0;
19482
+ const filePath = String(detail.filePath);
19483
+ return [{ path: filePath, ...detail.type === "read" && typeof detail.offset === "number" ? { line: detail.offset } : {} }];
19395
19484
  }
19396
19485
  var clip = (text, chars) => text.length > chars ? `${text.slice(0, chars - 1)}\u2026` : text;
19397
19486
  var status = (state) => state === "running" ? "in_progress" : state;
@@ -19430,7 +19519,7 @@ function createAcpAgent(options) {
19430
19519
  }
19431
19520
  const say = (session, text) => send(session, { sessionUpdate: "agent_message_chunk", content: { type: "text", text } });
19432
19521
  function configOptions(session) {
19433
- const teams = session.opened ? session.preview.teams.filter((team) => team.id === session.preview.team) : session.preview.teams;
19522
+ const teams = session.opened ? choices(session).filter((team) => team.id === session.preview.team) : choices(session);
19434
19523
  return [
19435
19524
  {
19436
19525
  id: "team",
@@ -19439,14 +19528,21 @@ function createAcpAgent(options) {
19439
19528
  type: "select",
19440
19529
  currentValue: session.preview.team,
19441
19530
  description: session.opened ? "A session keeps its team; start a new one for another team" : "The team that works on this session",
19442
- options: (teams.length ? teams : [{ id: session.preview.team, label: session.preview.teamLabel ?? session.preview.team }]).map((team) => ({ value: team.id, name: team.label, ...team.description ? { description: team.description } : {} }))
19531
+ options: teams.map((team) => ({ value: team.id, name: team.label, ...team.description ? { description: team.description } : {} }))
19443
19532
  },
19444
19533
  { id: "mode", name: "Permissions", category: "mode", type: "select", currentValue: session.preview.mode, options: MODES.map((mode) => ({ value: mode.id, name: mode.name, description: mode.description })) }
19445
19534
  ];
19446
19535
  }
19536
+ function choices(session) {
19537
+ const { teams, team } = session.preview;
19538
+ const own2 = unlistedOf(session.preview);
19539
+ const first = session.unlisted && session.unlisted.id !== team && !teams.some((entry) => entry.id === session.unlisted.id) ? [session.unlisted] : [];
19540
+ return [...first, ...own2 ? [own2] : [], ...teams];
19541
+ }
19447
19542
  const modeState = (session) => ({ currentModeId: session.preview.mode, availableModes: MODES });
19448
19543
  function track(id, cwd, mcpServers, preview2, opened) {
19449
- const session = { id, cwd, mcpServers, preview: preview2, opened, ours: /* @__PURE__ */ new Set(), texts: /* @__PURE__ */ new Map(), tools: /* @__PURE__ */ new Set(), questions: /* @__PURE__ */ new Map(), queue: Promise.resolve() };
19544
+ const unlisted = unlistedOf(preview2);
19545
+ const session = { id, cwd, mcpServers, preview: preview2, opened, ...unlisted ? { unlisted } : {}, ours: /* @__PURE__ */ new Set(), texts: /* @__PURE__ */ new Map(), tools: /* @__PURE__ */ new Set(), questions: /* @__PURE__ */ new Map(), queue: Promise.resolve() };
19450
19546
  sessions.set(id, session);
19451
19547
  return session;
19452
19548
  }
@@ -19544,7 +19640,8 @@ ${item2.text}`;
19544
19640
  send(session, { sessionUpdate: "plan", entries: item2.items.map((entry) => ({ content: entry.text, priority: "medium", status: entry.status })) });
19545
19641
  return;
19546
19642
  case "tool_call": {
19547
- const fields = { title: toolTitle(item2), kind: toolKind(item2), status: status(item2.status), content: toolOutput(item2), rawInput: item2.detail.type === "shell" ? { command: item2.detail.command, cwd: item2.detail.cwd } : item2.detail.input };
19643
+ const locations = toolLocations(item2);
19644
+ const fields = { title: toolTitle(item2, session.cwd), kind: toolKind(item2), status: status(item2.status), content: toolOutput(item2), rawInput: toolInput(item2), ...locations ? { locations } : {} };
19548
19645
  if (session.tools.has(item2.id)) send(session, { sessionUpdate: "tool_call_update", toolCallId: item2.id, ...fields });
19549
19646
  else {
19550
19647
  session.tools.add(item2.id);
@@ -19677,7 +19774,7 @@ ${item2.text}`;
19677
19774
  if (params.configId === "mode") await setMode(session, value);
19678
19775
  else if (params.configId === "team") {
19679
19776
  if (session.opened && value !== session.preview.team) throw RequestError.invalidParams(void 0, "A session keeps its team; start a new one for another team");
19680
- if (!session.preview.teams.some((team) => team.id === value)) throw RequestError.invalidParams(void 0, `Unknown team ${value}`);
19777
+ if (!choices(session).some((team) => team.id === value)) throw RequestError.invalidParams(void 0, `Unknown team ${value}`);
19681
19778
  session.preview = { ...await preview(session.cwd, session.mcpServers, value), mode: session.preview.mode };
19682
19779
  } else throw RequestError.invalidParams(void 0, `Unknown option ${params.configId}`);
19683
19780
  return { configOptions: configOptions(session) };
@@ -19706,7 +19803,7 @@ ${item2.text}`;
19706
19803
 
19707
19804
  // packages/cli/src/acp/main.ts
19708
19805
  async function runAcp({ daemonEntry }) {
19709
- const version2 = true ? "0.0.0-beta.1" : "0.0.0";
19806
+ const version2 = true ? "0.0.0-beta.2" : "0.0.0";
19710
19807
  const logger = createLogger({ component: "acp" });
19711
19808
  const log = (message, fields) => logger.warn(message, fields);
19712
19809
  const app = createAcpAgent({