@alook/app 0.1.50 → 0.1.51

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.
Files changed (67) hide show
  1. package/bundled/web/.open-next/.build/durable-objects/queue.js +5 -5
  2. package/bundled/web/.open-next/assets/BUILD_ID +1 -1
  3. package/bundled/web/.open-next/assets/_next/static/chunks/{30qoc1hjiiq3k.js → 1jx9uko6o9coe.js} +1 -1
  4. package/bundled/web/.open-next/assets/_next/static/chunks/{1axh15n8g62z0.js → 429glkc3c1-9s.js} +1 -1
  5. package/bundled/web/.open-next/assets/sw.js +1 -1
  6. package/bundled/web/.open-next/cache/{jeHai-9i1Q5xfGAQC4eaI → HJ8-qam47X4qCtSN6LGen}/route-cache/APP_PAGE/1ac71fc16c24600253696ffa2528949094f971f5409b0b353b2b775b5e1ba07d/$/_global-error.cache +1 -1
  7. package/bundled/web/.open-next/cache/{jeHai-9i1Q5xfGAQC4eaI → HJ8-qam47X4qCtSN6LGen}/route-cache/APP_PAGE/1bed1e66296c30f872c79a9d7a9f1e3d0c64330487b6a2bc0b0a70a1cb9db209/$/pricing-concept.cache +1 -1
  8. package/bundled/web/.open-next/cache/{jeHai-9i1Q5xfGAQC4eaI → HJ8-qam47X4qCtSN6LGen}/route-cache/APP_PAGE/262c312bb5d1afefa398e2fcec0b194edf7d1699350d9ddc0854afd32c80fac4/$/privacy.cache +1 -1
  9. package/bundled/web/.open-next/cache/{jeHai-9i1Q5xfGAQC4eaI → HJ8-qam47X4qCtSN6LGen}/route-cache/APP_PAGE/40dbf01fd0ea61688c1722eb63c7f79a732cb4edb713c7f704d9d90a28905f65/$/pricing.cache +1 -1
  10. package/bundled/web/.open-next/cache/{jeHai-9i1Q5xfGAQC4eaI → HJ8-qam47X4qCtSN6LGen}/route-cache/APP_PAGE/41da0ef926a63354a29f601d8e8d0a5951196c45ebcd28b7d4708fb7f56f3bf1/$/_not-found.cache +1 -1
  11. package/bundled/web/.open-next/cache/{jeHai-9i1Q5xfGAQC4eaI → HJ8-qam47X4qCtSN6LGen}/route-cache/APP_PAGE/9f6673da828d5ea3f28468b92951f9b0cf3d882ef027b96881eec8180df19274/$/contact.cache +1 -1
  12. package/bundled/web/.open-next/cache/{jeHai-9i1Q5xfGAQC4eaI → HJ8-qam47X4qCtSN6LGen}/route-cache/APP_PAGE/d8a5a23e7fdfb7e80b702b0046a134a514b8cc7e36ca2d7c3e46409f998defa8/$/onboarding-preview.cache +1 -1
  13. package/bundled/web/.open-next/cache/{jeHai-9i1Q5xfGAQC4eaI → HJ8-qam47X4qCtSN6LGen}/route-cache/APP_PAGE/ef3c10e78c664127cb53564ae0fbe189780ae84d395dedddfc5e4e2794dcd5bf/$/device.cache +1 -1
  14. package/bundled/web/.open-next/cache/{jeHai-9i1Q5xfGAQC4eaI → HJ8-qam47X4qCtSN6LGen}/route-cache/APP_ROUTE/b6ae7108b9aee28c54a722040ebed7e5dadc9c10505798ef8e5b6bc2418ded3b/$/serwist/sw.js.cache +1 -1
  15. package/bundled/web/.open-next/cloudflare/cache-assets-manifest.sql +1 -1
  16. package/bundled/web/.open-next/cloudflare/init.js +1 -1
  17. package/bundled/web/.open-next/dynamodb-provider/dynamodb-cache.json +1 -1
  18. package/bundled/web/.open-next/middleware/handler.mjs +4 -4
  19. package/bundled/web/.open-next/server-functions/default/src/web/.next/BUILD_ID +1 -1
  20. package/bundled/web/.open-next/server-functions/default/src/web/.next/build-manifest.json +41 -41
  21. package/bundled/web/.open-next/server-functions/default/src/web/.next/prerender-manifest.json +3 -3
  22. package/bundled/web/.open-next/server-functions/default/src/web/.next/required-server-files.json +3 -3
  23. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/c/@sidebar/channels/[serverId]/[channelId]/page_client-reference-manifest.js +1 -1
  24. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/c/@sidebar/channels/[serverId]/page_client-reference-manifest.js +1 -1
  25. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/c/@sidebar/channels/[serverId]/settings/page_client-reference-manifest.js +1 -1
  26. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/c/@sidebar/invite/[token]/page_client-reference-manifest.js +1 -1
  27. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/c/@sidebar/me/[dmId]/page_client-reference-manifest.js +1 -1
  28. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/c/@sidebar/me/bots/page_client-reference-manifest.js +1 -1
  29. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/c/@sidebar/me/friends/page_client-reference-manifest.js +1 -1
  30. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/c/@sidebar/me/machines/page_client-reference-manifest.js +1 -1
  31. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/c/@sidebar/me/page_client-reference-manifest.js +1 -1
  32. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/c/@sidebar/messages/[messageId]/page_client-reference-manifest.js +1 -1
  33. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/c/@sidebar/onboarding-preview/page_client-reference-manifest.js +1 -1
  34. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/c/@sidebar/page_client-reference-manifest.js +1 -1
  35. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/c/channels/[serverId]/[channelId]/page_client-reference-manifest.js +1 -1
  36. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/c/channels/[serverId]/page_client-reference-manifest.js +1 -1
  37. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/c/channels/[serverId]/settings/page_client-reference-manifest.js +1 -1
  38. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/c/invite/[token]/page_client-reference-manifest.js +1 -1
  39. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/c/me/[dmId]/page_client-reference-manifest.js +1 -1
  40. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/c/me/bots/page_client-reference-manifest.js +1 -1
  41. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/c/me/friends/page_client-reference-manifest.js +1 -1
  42. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/c/me/machines/page_client-reference-manifest.js +1 -1
  43. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/c/me/page_client-reference-manifest.js +1 -1
  44. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/c/messages/[messageId]/page_client-reference-manifest.js +1 -1
  45. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/c/onboarding-preview/page_client-reference-manifest.js +1 -1
  46. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/c/page_client-reference-manifest.js +1 -1
  47. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/ssr/_0_yml06_9jkq8._.js +1 -1
  48. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/ssr/_0o6wy7fmlfj85._.js +1 -1
  49. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/ssr/_0sksyrwxprmz8._.js +1 -1
  50. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/ssr/_0sqen1ofvh6kf._.js +1 -1
  51. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/ssr/_0tiehlvavpqdx._.js +1 -1
  52. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/ssr/_0uaa0i577fau8._.js +1 -1
  53. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/middleware-build-manifest.js +41 -41
  54. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/middleware-manifest.json +5 -5
  55. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/preview-props.json +3 -3
  56. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/server-reference-manifest.js +1 -1
  57. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/server-reference-manifest.json +1 -1
  58. package/bundled/web/.open-next/server-functions/default/src/web/handler.mjs +8 -8
  59. package/bundled/web/.open-next/server-functions/default/src/web/handler.mjs.meta.json +62 -62
  60. package/bundled/web/.open-next/server-functions/default/src/web/index.mjs +4 -4
  61. package/dist/daemon/index.js +507 -23
  62. package/package.json +1 -1
  63. /package/bundled/web/.open-next/assets/_next/static/{jeHai-9i1Q5xfGAQC4eaI → HJ8-qam47X4qCtSN6LGen}/_buildManifest.js +0 -0
  64. /package/bundled/web/.open-next/assets/_next/static/{jeHai-9i1Q5xfGAQC4eaI → HJ8-qam47X4qCtSN6LGen}/_clientMiddlewareManifest.js +0 -0
  65. /package/bundled/web/.open-next/assets/_next/static/{jeHai-9i1Q5xfGAQC4eaI → HJ8-qam47X4qCtSN6LGen}/_ssgManifest.js +0 -0
  66. /package/bundled/web/.open-next/cache/{jeHai-9i1Q5xfGAQC4eaI → HJ8-qam47X4qCtSN6LGen}/route-cache/APP_ROUTE/adb2ea089a587cf57dd95fa5b11714bc555600b8777692e029801fce568a54ac/$/favicon.ico.cache +0 -0
  67. /package/bundled/web/.open-next/cache/{jeHai-9i1Q5xfGAQC4eaI → HJ8-qam47X4qCtSN6LGen}/route-cache/APP_ROUTE/b31ae3d9b9e8ea6feaa1c6f14779da7794807da6a349f9246abaa4e2d2a615c7/$/robots.txt.cache +0 -0
@@ -32556,14 +32556,16 @@ class OpenCodeServiceLane {
32556
32556
  if (!this.identity || this.identity.generation !== generation || this.isProcessClosed(this.identity.process)) {
32557
32557
  if (/EADDRINUSE|address already in use/i.test(this.stderrBuffer))
32558
32558
  throw new OpenCodePortBindError("OpenCode service port bind raced");
32559
- throw new Error("OpenCode service exited before readiness");
32559
+ const process2 = this.identity?.process;
32560
+ const detail = scrubDriverErrorMessage(this.stderrBuffer.replaceAll(this.password, "[redacted]"), "no native stderr");
32561
+ throw new Error(`OpenCode service exited before readiness (code=${process2?.exitCode ?? "unknown"}, signal=${process2?.signalCode ?? "none"}): ${detail}`);
32560
32562
  }
32561
32563
  try {
32562
32564
  const healthTimeoutMs = Math.max(1, Math.min(1000, deadline - Date.now(), this.options.requestTimeoutMs ?? REQUEST_TIMEOUT_MS));
32563
- const { response, body } = await this.fetchJsonWithTimeout("/global/health", { method: "GET" }, "health", healthTimeoutMs);
32565
+ const { response, body } = await this.fetchJsonWithTimeout(this.healthPath, { method: "GET" }, "health", healthTimeoutMs);
32564
32566
  if (response.ok) {
32565
32567
  const health = record5(body);
32566
- if (health?.healthy !== true) {
32568
+ if (!this.acceptsHealth(health)) {
32567
32569
  throw new OpenCodeIncompatibleError("Installed OpenCode service did not report healthy status");
32568
32570
  }
32569
32571
  await this.verifyOpenApi();
@@ -32580,12 +32582,27 @@ class OpenCodeServiceLane {
32580
32582
  throw new Error("OpenCode service readiness timed out");
32581
32583
  }
32582
32584
  async verifyOpenApi() {
32583
- const { response, body } = await this.fetchJsonWithTimeout("/doc", { method: "GET" }, "OpenAPI");
32585
+ const { response, body } = await this.fetchJsonWithTimeout(this.openApiPath, { method: "GET" }, "OpenAPI");
32584
32586
  if (!response.ok)
32585
32587
  throw new OpenCodeIncompatibleError("Installed OpenCode service does not expose its OpenAPI document");
32586
32588
  const document = record5(body);
32587
32589
  const paths = record5(document?.paths);
32588
- const required2 = [
32590
+ const required2 = this.requiredApiPaths;
32591
+ if (!paths || required2.some((path10) => !record5(paths[path10]))) {
32592
+ throw new OpenCodeIncompatibleError("Installed OpenCode service is missing required session capabilities");
32593
+ }
32594
+ }
32595
+ get healthPath() {
32596
+ return "/global/health";
32597
+ }
32598
+ get openApiPath() {
32599
+ return "/doc";
32600
+ }
32601
+ acceptsHealth(health) {
32602
+ return health?.healthy === true;
32603
+ }
32604
+ get requiredApiPaths() {
32605
+ return [
32589
32606
  "/api/session",
32590
32607
  "/api/session/active",
32591
32608
  "/api/session/{sessionID}/prompt",
@@ -32597,12 +32614,12 @@ class OpenCodeServiceLane {
32597
32614
  "/api/session/{sessionID}/permission/{requestID}/reply",
32598
32615
  "/api/event"
32599
32616
  ];
32600
- if (!paths || required2.some((path10) => !record5(paths[path10]))) {
32601
- throw new OpenCodeIncompatibleError("Installed OpenCode service is missing required v2 session capabilities");
32602
- }
32617
+ }
32618
+ get selectedModel() {
32619
+ return parseModelRef(resolveLaunchFieldsOrDefault(this.ctx.config.runtimeConfig).model);
32603
32620
  }
32604
32621
  async openSession(resumeId) {
32605
- const model = parseModelRef(resolveLaunchFieldsOrDefault(this.ctx.config.runtimeConfig).model);
32622
+ const model = this.selectedModel;
32606
32623
  if (resumeId) {
32607
32624
  const { response: response2, body: body2 } = await this.fetchJsonWithTimeout(`/api/session/${encodeURIComponent(resumeId)}`, { method: "GET" }, "session resume");
32608
32625
  if (response2.status === 404) {
@@ -32945,7 +32962,7 @@ class OpenCodeServiceLane {
32945
32962
  async handleLiveEvent(value) {
32946
32963
  const event = record5(value);
32947
32964
  const data = record5(event?.data);
32948
- if (event?.type !== "permission.v2.asked" || data?.sessionID !== this.sessionId)
32965
+ if (event?.type !== this.permissionEventType || data?.sessionID !== this.sessionId)
32949
32966
  return;
32950
32967
  if (typeof data.id !== "string" || !/^per/.test(data.id)) {
32951
32968
  throw new OpenCodeProtocolError("OpenCode emitted a malformed permission request");
@@ -32968,13 +32985,19 @@ class OpenCodeServiceLane {
32968
32985
  }
32969
32986
  }
32970
32987
  }
32988
+ get permissionEventType() {
32989
+ return "permission.v2.asked";
32990
+ }
32991
+ get permissionReply() {
32992
+ return { reply: "once" };
32993
+ }
32971
32994
  async replyPermission(requestId) {
32972
32995
  if (this.handledPermissions.has(requestId))
32973
32996
  return;
32974
32997
  const existing = this.permissionFlights.get(requestId);
32975
32998
  if (existing)
32976
32999
  return existing;
32977
- const flight = this.requestNoContent(`/api/session/${encodeURIComponent(this.sessionId)}/permission/${encodeURIComponent(requestId)}/reply`, "POST", { reply: "once" }, "permission reply").catch((error62) => {
33000
+ const flight = this.requestNoContent(`/api/session/${encodeURIComponent(this.sessionId)}/permission/${encodeURIComponent(requestId)}/reply`, "POST", this.permissionReply, "permission reply").catch((error62) => {
32978
33001
  if (!(error62 instanceof OpenCodeHttpError) || error62.status !== 404)
32979
33002
  throw error62;
32980
33003
  }).then(() => {
@@ -33351,6 +33374,28 @@ async function legacyOpenCodeApiEnvironment(environment, model) {
33351
33374
  return credential?.type === "api" && typeof credential.key === "string" && credential.key.trim() ? { [name]: credential.key } : {};
33352
33375
  }
33353
33376
 
33377
+ // agent-driver/dist/adapters/opencode/compatibility.js
33378
+ var OPEN_CODE_V1 = {
33379
+ major: 1,
33380
+ modelArgs: ["models", "--pure"],
33381
+ serviceArgs: ["serve", "--pure"],
33382
+ sessionListArgs: (maxCount) => ["session", "list", "--format", "json", "--max-count", String(maxCount), "--pure"]
33383
+ };
33384
+ var OPEN_CODE_V2 = {
33385
+ major: 2,
33386
+ modelArgs: ["models", "--standalone"],
33387
+ serviceArgs: ["serve"],
33388
+ sessionListArgs: (maxCount) => ["api", "--standalone", "GET", `/api/session?parentID=null&order=desc&limit=${maxCount}`]
33389
+ };
33390
+ function resolveOpenCodeCompatibility(version3) {
33391
+ const match = version3?.trim().match(/^(?:opencode\s+)?v?(\d+)\.\d+\.\d+(?:[-+][\w.-]+)?$/i);
33392
+ if (match?.[1] === "1")
33393
+ return OPEN_CODE_V1;
33394
+ if (match?.[1] === "2")
33395
+ return OPEN_CODE_V2;
33396
+ throw new Error("Installed OpenCode CLI version is unrecognized or has an unsupported major version");
33397
+ }
33398
+
33354
33399
  // agent-driver/dist/adapters/opencode/recent-context.js
33355
33400
  var OPENCODE_DISCOVERY_TIMEOUT_MS = 15000;
33356
33401
  var OPENCODE_DISCOVERY_OUTPUT_MAX_BYTES = 4 * 1024 * 1024;
@@ -33384,6 +33429,7 @@ async function discoverOpenCodeRecentContext(request, dependencies = {}) {
33384
33429
  const collector = new RecentContextCollector(request, "unavailable");
33385
33430
  if (collector.satisfied)
33386
33431
  return collector.result();
33432
+ const compatibility = dependencies.compatibility ?? OPEN_CODE_V1;
33387
33433
  const startedAt = Date.now();
33388
33434
  const timeoutMs = dependencies.timeoutMs ?? OPENCODE_DISCOVERY_TIMEOUT_MS;
33389
33435
  let remainingOutputBytes = dependencies.outputMaxBytes ?? OPENCODE_DISCOVERY_OUTPUT_MAX_BYTES;
@@ -33392,7 +33438,7 @@ async function discoverOpenCodeRecentContext(request, dependencies = {}) {
33392
33438
  const remainingTimeoutMs = timeoutMs - (Date.now() - startedAt);
33393
33439
  if (remainingTimeoutMs <= 0)
33394
33440
  throw new Error("OpenCode discovery timed out");
33395
- const spec = resolveSpawnSpec("opencode", ["session", "list", "--format", "json", "--max-count", String(maxCount), "--pure"], request.command);
33441
+ const spec = resolveSpawnSpec("opencode", [...compatibility.sessionListArgs(maxCount)], request.command);
33396
33442
  const commandOutput = await collectCommandOutput(spec.command, spec.args, spec.shell, dependencies, remainingTimeoutMs, remainingOutputBytes);
33397
33443
  remainingOutputBytes -= commandOutput.outputBytes;
33398
33444
  let parsed;
@@ -33401,14 +33447,17 @@ async function discoverOpenCodeRecentContext(request, dependencies = {}) {
33401
33447
  } catch {
33402
33448
  throw new Error("OpenCode session listing returned invalid JSON");
33403
33449
  }
33450
+ if (compatibility.major === 2)
33451
+ parsed = asRecord(parsed)?.data;
33404
33452
  if (!Array.isArray(parsed))
33405
33453
  throw new Error("OpenCode session listing returned an invalid response");
33406
33454
  for (const value of parsed) {
33407
33455
  const session2 = asRecord(value);
33408
33456
  if (!session2)
33409
33457
  continue;
33410
- const modifiedAt = session2.updated ?? session2.updatedAt;
33411
- collector.add({ projectPath: session2.directory, modifiedAt });
33458
+ const modifiedAt = compatibility.major === 2 ? asRecord(session2.time)?.updated : session2.updated ?? session2.updatedAt;
33459
+ const projectPath = compatibility.major === 2 ? asRecord(session2.location)?.directory : session2.directory;
33460
+ collector.add({ projectPath, modifiedAt });
33412
33461
  }
33413
33462
  if (collector.satisfied || parsed.length < maxCount)
33414
33463
  break;
@@ -33420,6 +33469,419 @@ async function discoverOpenCodeRecentContext(request, dependencies = {}) {
33420
33469
  return collector.result();
33421
33470
  }
33422
33471
 
33472
+ // agent-driver/dist/adapters/opencode/v2-service-lane.js
33473
+ class OpenCodeV2ServiceLane extends OpenCodeServiceLane {
33474
+ root = null;
33475
+ v2AdmissionTail = Promise.resolve();
33476
+ v2EvaluationTimer;
33477
+ v2Evaluating = false;
33478
+ projectedMessages = new Set;
33479
+ liveTools = new Map;
33480
+ settledTools = new Set;
33481
+ usage = new SettledUsageProjector;
33482
+ get healthPath() {
33483
+ return "/api/info";
33484
+ }
33485
+ get openApiPath() {
33486
+ return "/openapi.json";
33487
+ }
33488
+ acceptsHealth(health) {
33489
+ if (typeof health?.version !== "string" || !Number.isInteger(health.pid) || Number(health.pid) < 1)
33490
+ return false;
33491
+ try {
33492
+ return resolveOpenCodeCompatibility(health.version).major === 2;
33493
+ } catch {
33494
+ return false;
33495
+ }
33496
+ }
33497
+ get requiredApiPaths() {
33498
+ return [
33499
+ "/api/session",
33500
+ "/api/session/active",
33501
+ "/api/session/{sessionID}",
33502
+ "/api/session/{sessionID}/prompt",
33503
+ "/api/session/{sessionID}/inbox",
33504
+ "/api/session/{sessionID}/message",
33505
+ "/api/session/{sessionID}/message/{messageID}",
33506
+ "/api/session/{sessionID}/interrupt",
33507
+ "/api/session/{sessionID}/model",
33508
+ "/api/session/{sessionID}/permission",
33509
+ "/api/session/{sessionID}/permission/{requestID}/reply",
33510
+ "/api/event"
33511
+ ];
33512
+ }
33513
+ get selectedModel() {
33514
+ const model = super.selectedModel;
33515
+ if (typeof model?.id !== "string")
33516
+ return model;
33517
+ const hash2 = model.id.lastIndexOf("#");
33518
+ return hash2 > 0 && hash2 < model.id.length - 1 ? { ...model, id: model.id.slice(0, hash2), variant: model.id.slice(hash2 + 1) } : model;
33519
+ }
33520
+ get permissionEventType() {
33521
+ return "permission.asked";
33522
+ }
33523
+ get permissionReply() {
33524
+ return { decision: "once" };
33525
+ }
33526
+ protocolFailure(message2, cause) {
33527
+ super.protocolFailure(cause === undefined ? message2 : `${message2}: ${scrubDriverErrorMessage(cause)}`);
33528
+ }
33529
+ async primeHistory() {}
33530
+ startStreams() {
33531
+ const identity = this.identity;
33532
+ this.liveTask = this.runLiveStream(identity).catch((error62) => {
33533
+ if (!this.stopping)
33534
+ this.protocolFailure("OpenCode CLI v2 live stream failed", error62);
33535
+ });
33536
+ }
33537
+ async recoverPendingPermissions() {
33538
+ await super.recoverPendingPermissions();
33539
+ const root = this.root;
33540
+ if (root)
33541
+ for (const message2 of await this.messagesAfter(root))
33542
+ this.projectTools(message2);
33543
+ this.schedule();
33544
+ }
33545
+ async handleLiveEvent(value) {
33546
+ await super.handleLiveEvent(value);
33547
+ const event = record5(value);
33548
+ const data = record5(event?.data);
33549
+ if (data?.sessionID !== this.sessionId || !this.root)
33550
+ return;
33551
+ switch (event?.type) {
33552
+ case "session.step.started":
33553
+ this.events.emit("runtime_event", {
33554
+ kind: "internal_progress",
33555
+ source: "opencode.service",
33556
+ itemType: "step_started"
33557
+ });
33558
+ break;
33559
+ case "session.tool.input.started": {
33560
+ const key = this.toolKey(data.assistantMessageID, data.id);
33561
+ if (key && typeof data.name === "string" && !this.liveTools.has(key) && !this.settledTools.has(key)) {
33562
+ this.liveTools.set(key, { name: data.name, called: false });
33563
+ }
33564
+ break;
33565
+ }
33566
+ case "session.tool.called":
33567
+ this.projectTool(data);
33568
+ break;
33569
+ case "session.tool.success":
33570
+ case "session.tool.failed": {
33571
+ this.finishTool(this.toolKey(data.assistantMessageID, data.id));
33572
+ break;
33573
+ }
33574
+ case "session.compaction.started":
33575
+ this.events.emit("runtime_event", { kind: "compaction_started" });
33576
+ break;
33577
+ case "session.compaction.failed":
33578
+ case "session.compaction.ended":
33579
+ this.events.emit("runtime_event", { kind: "compaction_finished" });
33580
+ break;
33581
+ default:
33582
+ break;
33583
+ }
33584
+ this.schedule();
33585
+ }
33586
+ async send(input2) {
33587
+ if (!this.ready || this.stopping || !this.sessionId || !this.identityMatches())
33588
+ return { ok: false, reason: "closed" };
33589
+ if (input2.mode === "idle") {
33590
+ if (this.root)
33591
+ return { ok: false, reason: "runtime_busy" };
33592
+ return this.beginRoot(input2);
33593
+ }
33594
+ const root = this.root;
33595
+ if (!root)
33596
+ return { ok: false, reason: "not_ready" };
33597
+ return this.admit(input2.text, "steer", this.newMessageId(), root);
33598
+ }
33599
+ async beginRoot(input2) {
33600
+ const page = await this.messagePage(undefined, 1);
33601
+ if (this.stopping || !this.identityMatches())
33602
+ return { ok: false, reason: "closed" };
33603
+ const receipt = input2.terminalOwner?.startsWith("msg_") ? input2.terminalOwner : this.newMessageId();
33604
+ const root = {
33605
+ receipt,
33606
+ baseline: typeof page.data[0]?.id === "string" ? page.data[0].id : null,
33607
+ inputs: new Set,
33608
+ generation: 0,
33609
+ pending: 0
33610
+ };
33611
+ this.root = root;
33612
+ return this.admit(input2.text, "queue", receipt, root);
33613
+ }
33614
+ admit(text2, delivery, id3, root) {
33615
+ root.generation += 1;
33616
+ root.pending += 1;
33617
+ const run = this.v2AdmissionTail.then(async () => {
33618
+ await this.waitForLiveStream();
33619
+ if (this.root !== root || this.stopping || !this.identityMatches())
33620
+ return { ok: false, reason: "closed" };
33621
+ const { response, body } = await this.fetchJsonWithTimeout(`/api/session/${encodeURIComponent(this.sessionId)}/prompt`, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ id: id3, text: text2, delivery, resume: true }) }, "prompt admission");
33622
+ if (!response.ok)
33623
+ throw new OpenCodeHttpError(response.status, "prompt admission");
33624
+ const input2 = record5(record5(body)?.data);
33625
+ if (input2?.id !== id3 || input2.sessionID !== this.sessionId || input2.type !== "user" || input2.delivery !== delivery) {
33626
+ throw new OpenCodeProtocolError("OpenCode CLI v2 returned an invalid prompt receipt");
33627
+ }
33628
+ if (this.root !== root || this.stopping || !this.identityMatches())
33629
+ return { ok: false, reason: "closed" };
33630
+ root.inputs.add(id3);
33631
+ return { ok: true, acceptedAs: delivery === "steer" ? "steer" : "prompt", receipt: id3 };
33632
+ }).catch((error62) => {
33633
+ if (this.root === root && !this.stopping)
33634
+ this.protocolFailure("OpenCode CLI v2 prompt admission failed", error62);
33635
+ throw error62;
33636
+ }).finally(() => {
33637
+ root.pending -= 1;
33638
+ this.schedule();
33639
+ });
33640
+ this.v2AdmissionTail = run.then(() => {}, () => {});
33641
+ return run;
33642
+ }
33643
+ async messagePage(cursor, limit = 100) {
33644
+ const query = new URLSearchParams({ limit: String(limit), ...cursor ? { cursor } : { order: "desc" } });
33645
+ const { response, body } = await this.fetchJsonWithTimeout(`/api/session/${encodeURIComponent(this.sessionId)}/message?${query}`, { method: "GET" }, "message recovery");
33646
+ if (!response.ok)
33647
+ throw new OpenCodeHttpError(response.status, "message recovery");
33648
+ const page = record5(body);
33649
+ const cursors = record5(page?.cursor);
33650
+ if (!Array.isArray(page?.data) || !cursors || page.data.some((item) => typeof record5(item)?.id !== "string")) {
33651
+ throw new OpenCodeProtocolError("OpenCode CLI v2 returned an invalid message page");
33652
+ }
33653
+ if (cursors.next !== undefined && cursors.next !== null && typeof cursors.next !== "string")
33654
+ throw new OpenCodeProtocolError("OpenCode CLI v2 returned an invalid message cursor");
33655
+ return { data: page.data, next: typeof cursors.next === "string" ? cursors.next : undefined };
33656
+ }
33657
+ async messagesAfter(root) {
33658
+ const messages = [];
33659
+ const cursors = new Set;
33660
+ let cursor;
33661
+ for (;; ) {
33662
+ const page = await this.messagePage(cursor);
33663
+ if (this.root !== root || this.stopping)
33664
+ return [];
33665
+ for (const message2 of page.data) {
33666
+ if (message2.id === root.baseline)
33667
+ return messages.reverse();
33668
+ messages.push(message2);
33669
+ }
33670
+ if (!page.next) {
33671
+ if (root.baseline !== null)
33672
+ throw new OpenCodeProtocolError("OpenCode CLI v2 message recovery lost its root boundary");
33673
+ return messages.reverse();
33674
+ }
33675
+ if (cursors.has(page.next))
33676
+ throw new OpenCodeProtocolError("OpenCode CLI v2 message cursor did not advance");
33677
+ cursors.add(page.next);
33678
+ cursor = page.next;
33679
+ }
33680
+ }
33681
+ schedule() {
33682
+ if (!this.root || this.stopping || this.v2EvaluationTimer || this.v2Evaluating)
33683
+ return;
33684
+ this.v2EvaluationTimer = setTimeout(() => {
33685
+ this.v2EvaluationTimer = undefined;
33686
+ this.evaluate();
33687
+ }, this.options.activePollMs ?? 100);
33688
+ this.v2EvaluationTimer.unref?.();
33689
+ }
33690
+ async isActive() {
33691
+ const { response, body } = await this.fetchJsonWithTimeout("/api/session/active", { method: "GET" }, "active session query");
33692
+ if (!response.ok)
33693
+ throw new OpenCodeHttpError(response.status, "active session query");
33694
+ const active = record5(record5(body)?.data);
33695
+ if (!active)
33696
+ throw new OpenCodeProtocolError("OpenCode CLI v2 returned invalid active session data");
33697
+ return active[this.sessionId] !== undefined;
33698
+ }
33699
+ async evaluate() {
33700
+ const root = this.root;
33701
+ const identity = this.identity;
33702
+ if (!root || !identity || this.stopping || root.pending > 0 || root.inputs.size === 0 || this.v2Evaluating)
33703
+ return;
33704
+ this.v2Evaluating = true;
33705
+ const generation = root.generation;
33706
+ const current = () => this.root === root && root.generation === generation && root.pending === 0 && this.isIdentity(identity);
33707
+ try {
33708
+ if (await this.isActive())
33709
+ return;
33710
+ if (!current())
33711
+ return;
33712
+ const messages = await this.messagesAfter(root);
33713
+ if (!current())
33714
+ return;
33715
+ let lastInput = -1;
33716
+ const delivered = new Set;
33717
+ for (const [index2, message2] of messages.entries()) {
33718
+ if (message2.type === "user" && typeof message2.id === "string" && root.inputs.has(message2.id)) {
33719
+ delivered.add(message2.id);
33720
+ lastInput = index2;
33721
+ }
33722
+ }
33723
+ const idle = messages.slice(lastInput + 1).reverse().find((message2) => message2.type === "idle");
33724
+ if (delivered.size !== root.inputs.size) {
33725
+ const { response, body } = await this.fetchJsonWithTimeout(`/api/session/${encodeURIComponent(this.sessionId)}/inbox`, { method: "GET" }, "pending input recovery");
33726
+ if (!response.ok)
33727
+ throw new OpenCodeHttpError(response.status, "pending input recovery");
33728
+ const pending = record5(body)?.data;
33729
+ if (!Array.isArray(pending))
33730
+ throw new OpenCodeProtocolError("OpenCode CLI v2 returned invalid inbox data");
33731
+ if (!current())
33732
+ return;
33733
+ const retained = new Set(pending.map((item) => record5(item)?.id));
33734
+ for (const id3 of root.inputs) {
33735
+ if (delivered.has(id3) || retained.has(id3))
33736
+ continue;
33737
+ const recovered = await this.fetchJsonWithTimeout(`/api/session/${encodeURIComponent(this.sessionId)}/message/${encodeURIComponent(id3)}`, { method: "GET" }, "accepted input recovery");
33738
+ if (!current())
33739
+ return;
33740
+ if (recovered.response.status === 404)
33741
+ throw new OpenCodeProtocolError("OpenCode CLI v2 lost an accepted input from both inbox and messages");
33742
+ if (!recovered.response.ok)
33743
+ throw new OpenCodeHttpError(recovered.response.status, "accepted input recovery");
33744
+ const message2 = record5(record5(recovered.body)?.data);
33745
+ if (message2?.id !== id3 || message2.type !== "user")
33746
+ throw new OpenCodeProtocolError("OpenCode CLI v2 returned an invalid recovered input");
33747
+ }
33748
+ return;
33749
+ }
33750
+ for (const message2 of messages) {
33751
+ this.projectTools(message2);
33752
+ this.projectMessage(message2);
33753
+ }
33754
+ if (!idle || await this.isActive() || !current())
33755
+ return;
33756
+ if (!["succeeded", "failed", "interrupted"].includes(String(idle.outcome))) {
33757
+ throw new OpenCodeProtocolError("OpenCode CLI v2 returned an invalid idle outcome");
33758
+ }
33759
+ this.root = null;
33760
+ if (idle.outcome === "failed") {
33761
+ const error62 = record5(idle.error);
33762
+ this.events.emit("runtime_event", {
33763
+ kind: "error",
33764
+ code: "opencode.turn_failed",
33765
+ message: typeof error62?.message === "string" ? error62.message : "OpenCode CLI v2 execution failed"
33766
+ });
33767
+ }
33768
+ this.events.emit("runtime_event", {
33769
+ kind: "turn_end",
33770
+ sessionId: this.sessionId,
33771
+ turnOwner: root.receipt
33772
+ });
33773
+ } catch (error62) {
33774
+ if (!current() || this.stopping)
33775
+ return;
33776
+ if (error62 instanceof OpenCodeProtocolError || error62 instanceof OpenCodeHttpError && error62.status < 500) {
33777
+ this.protocolFailure("OpenCode CLI v2 durable message recovery failed", error62);
33778
+ } else
33779
+ this.diagnostic("warning", "OpenCode CLI v2 message recovery temporarily unavailable; keeping the root active");
33780
+ } finally {
33781
+ this.v2Evaluating = false;
33782
+ this.schedule();
33783
+ }
33784
+ }
33785
+ toolKey(messageId, id3) {
33786
+ return typeof messageId === "string" && typeof id3 === "string" ? `${messageId}:${id3}` : undefined;
33787
+ }
33788
+ projectTool(data) {
33789
+ const key = this.toolKey(data.assistantMessageID, data.id);
33790
+ if (!key || this.settledTools.has(key))
33791
+ return;
33792
+ const tool = this.liveTools.get(key) ?? { name: typeof data.name === "string" ? data.name : "OpenCode tool", called: false };
33793
+ if (tool.called)
33794
+ return;
33795
+ tool.called = true;
33796
+ this.liveTools.set(key, tool);
33797
+ this.events.emit("runtime_event", { kind: "tool_call", callId: key, name: tool.name, input: data.input });
33798
+ }
33799
+ finishTool(key) {
33800
+ if (!key || this.settledTools.has(key))
33801
+ return;
33802
+ const tool = this.liveTools.get(key);
33803
+ if (!tool?.called)
33804
+ return;
33805
+ this.liveTools.delete(key);
33806
+ this.settledTools.add(key);
33807
+ this.events.emit("runtime_event", { kind: "tool_output", callId: key, name: tool.name });
33808
+ }
33809
+ projectTools(message2) {
33810
+ if (message2.type !== "assistant" || !Array.isArray(message2.content) || !this.root || this.stopping)
33811
+ return;
33812
+ for (const value of message2.content) {
33813
+ const tool = record5(value);
33814
+ const state = record5(tool?.state);
33815
+ if (tool?.type !== "tool" || !["running", "completed", "error"].includes(String(state?.status)))
33816
+ continue;
33817
+ this.projectTool({ assistantMessageID: message2.id, id: tool.id, name: tool.name, input: state?.input });
33818
+ if (state?.status !== "running")
33819
+ this.finishTool(this.toolKey(message2.id, tool.id));
33820
+ }
33821
+ }
33822
+ projectMessage(message2) {
33823
+ if (message2.type !== "assistant" || typeof message2.id !== "string" || this.projectedMessages.has(message2.id))
33824
+ return;
33825
+ const time3 = record5(message2.time);
33826
+ if (time3?.completed === undefined)
33827
+ return;
33828
+ this.projectedMessages.add(message2.id);
33829
+ if (Array.isArray(message2.content))
33830
+ for (const value of message2.content) {
33831
+ const content = record5(value);
33832
+ if (typeof content?.text !== "string" || !content.text)
33833
+ continue;
33834
+ if (content.type === "text")
33835
+ this.events.emit("runtime_event", { kind: "assistant_message_completed", text: content.text });
33836
+ if (content.type === "reasoning")
33837
+ this.events.emit("runtime_event", { kind: "assistant_reasoning_completed", text: content.text });
33838
+ }
33839
+ const tokens = record5(message2.tokens);
33840
+ if (!tokens || !this.sessionId)
33841
+ return;
33842
+ const cache = record5(tokens.cache);
33843
+ const identity = { runtime: "opencode", backendSessionId: this.sessionId, providerRecordId: message2.id };
33844
+ const usage = this.usage.project({
33845
+ ...identity,
33846
+ source: "opencode.v2",
33847
+ input: tokens.input,
33848
+ output: tokens.output,
33849
+ reasoning: tokens.reasoning,
33850
+ cacheRead: cache?.read,
33851
+ cacheWrite: cache?.write,
33852
+ inputIncludesCache: false,
33853
+ outputIncludesReasoning: false
33854
+ });
33855
+ if (usage)
33856
+ this.events.emit("runtime_event", usage);
33857
+ this.usage.release(identity);
33858
+ }
33859
+ async interrupt(_input) {
33860
+ const root = this.root;
33861
+ if (!root || !this.ready || this.stopping || !this.identityMatches())
33862
+ return false;
33863
+ root.generation += 1;
33864
+ root.pending += 1;
33865
+ try {
33866
+ await this.requestNoContent(`/api/session/${encodeURIComponent(this.sessionId)}/interrupt?resume=false`, "POST", undefined, "session interrupt");
33867
+ return true;
33868
+ } catch (error62) {
33869
+ if (!this.stopping)
33870
+ this.stop({ reason: "interrupt_timeout", forceAfterMs: 0 });
33871
+ throw error62;
33872
+ } finally {
33873
+ root.pending -= 1;
33874
+ this.schedule();
33875
+ }
33876
+ }
33877
+ stop(input2 = {}) {
33878
+ this.root = null;
33879
+ if (this.v2EvaluationTimer)
33880
+ clearTimeout(this.v2EvaluationTimer);
33881
+ return super.stop(input2);
33882
+ }
33883
+ }
33884
+
33423
33885
  // agent-driver/dist/adapters/opencode/index.js
33424
33886
  function createOpenCodeMessageId() {
33425
33887
  return `msg_${randomBytes4(16).toString("hex")}`;
@@ -33427,6 +33889,7 @@ function createOpenCodeMessageId() {
33427
33889
 
33428
33890
  class OpenCodeDriver {
33429
33891
  outputProbe;
33892
+ versionProbe;
33430
33893
  id = "opencode";
33431
33894
  instructionDelivery = { kind: "workspace_file", canonical: "AGENTS.md", aliases: ["CLAUDE.md"] };
33432
33895
  execution = {
@@ -33435,17 +33898,29 @@ class OpenCodeDriver {
33435
33898
  wakeStart: "immediate",
33436
33899
  terminalOwnership: "transport_request"
33437
33900
  };
33438
- constructor(outputProbe = probeCommandOutput) {
33901
+ constructor(outputProbe = probeCommandOutput, versionProbe = probeCliRuntime) {
33439
33902
  this.outputProbe = outputProbe;
33903
+ this.versionProbe = versionProbe;
33440
33904
  }
33441
33905
  discoverRecentContext(request) {
33442
- return discoverOpenCodeRecentContext(request);
33906
+ if (request.recentProjectsTopK === 0)
33907
+ return discoverOpenCodeRecentContext(request);
33908
+ const result = this.versionProbe("opencode", {}, request.command);
33909
+ if (result.status !== "healthy")
33910
+ throw new Error("Installed OpenCode CLI could not report its version");
33911
+ return discoverOpenCodeRecentContext(request, { compatibility: resolveOpenCodeCompatibility(result.version) });
33443
33912
  }
33444
33913
  probe(command) {
33445
- const result = probeCliRuntime("opencode", {}, command);
33914
+ const result = this.versionProbe("opencode", {}, command);
33446
33915
  if (result.status !== "healthy")
33447
33916
  return result;
33448
- const spec = resolveSpawnSpec("opencode", ["models", "--pure"], command);
33917
+ let compatibility;
33918
+ try {
33919
+ compatibility = resolveOpenCodeCompatibility(result.version);
33920
+ } catch {
33921
+ return { ...result, status: "unhealthy", lastError: "unsupported_opencode_cli_version" };
33922
+ }
33923
+ const spec = resolveSpawnSpec("opencode", [...compatibility.modelArgs], command);
33449
33924
  const output2 = this.outputProbe(spec.command, spec.args);
33450
33925
  return {
33451
33926
  ...result,
@@ -33456,20 +33931,29 @@ class OpenCodeDriver {
33456
33931
  return createOpenCodeMessageId();
33457
33932
  }
33458
33933
  async openLane(ctx, options) {
33459
- return new OpenCodeServiceLane(this, ctx, {
33934
+ const command = resolveLaunchFieldsOrDefault(ctx.config.runtimeConfig).command;
33935
+ const result = this.versionProbe("opencode", {}, command);
33936
+ if (result.status !== "healthy")
33937
+ throw new Error("Installed OpenCode CLI could not report its version");
33938
+ const compatibility = resolveOpenCodeCompatibility(result.version);
33939
+ const factory = {
33940
+ spawnService: (launch, port, password) => this.spawnService(launch, port, password, compatibility)
33941
+ };
33942
+ const Lane = compatibility.major === 1 ? OpenCodeServiceLane : OpenCodeV2ServiceLane;
33943
+ return new Lane(factory, ctx, {
33460
33944
  onRawStdoutLine: options?.onRawStdoutLine
33461
33945
  });
33462
33946
  }
33463
- async spawnService(ctx, port, password) {
33947
+ async spawnService(ctx, port, password, compatibility = OPEN_CODE_V1) {
33464
33948
  const { spawnEnv } = await prepareCliTransport(ctx, {
33465
- OPENCODE_SERVER_PASSWORD: password
33949
+ OPENCODE_SERVER_PASSWORD: password,
33950
+ ...compatibility.major === 2 ? { OPENCODE_PASSWORD: password } : {}
33466
33951
  });
33467
33952
  const fields2 = resolveLaunchFieldsOrDefault(ctx.config.runtimeConfig);
33468
33953
  Object.assign(spawnEnv, await legacyOpenCodeApiEnvironment(spawnEnv, fields2.model));
33469
33954
  const override = fields2.command;
33470
33955
  const args = [
33471
- "serve",
33472
- "--pure",
33956
+ ...compatibility.serviceArgs,
33473
33957
  "--hostname",
33474
33958
  "127.0.0.1",
33475
33959
  "--port",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alook/app",
3
- "version": "0.1.50",
3
+ "version": "0.1.51",
4
4
  "description": "Run Alook locally — one command, no clone needed",
5
5
  "license": "Apache-2.0",
6
6
  "homepage": "https://github.com/alookai/alook#readme",