neko-harness 0.5.3 → 0.5.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/gateway.js CHANGED
@@ -16640,6 +16640,11 @@ function resolveCodemodeSettings(config, saved) {
16640
16640
  return { effective: { mode: config.mode }, source: "config" };
16641
16641
  return { effective: { mode: DEFAULT_CODEMODE_MODE }, source: "default" };
16642
16642
  }
16643
+ // packages/core/src/commits.ts
16644
+ function onCommits(session, listener) {
16645
+ const observation = session.observeCommits({ advance: (publication) => listener(publication), end: () => {} });
16646
+ return () => observation.detach();
16647
+ }
16643
16648
  // packages/core/src/config.ts
16644
16649
  import { existsSync, readFileSync } from "fs";
16645
16650
  import { homedir } from "os";
@@ -16909,6 +16914,10 @@ function validate(config, source) {
16909
16914
  if (level !== undefined && typeof level !== "string") {
16910
16915
  throw new Error(`neko config: ${source}: "thinkingLevel" must be a string.`);
16911
16916
  }
16917
+ const maxTurns = config.maxTurns;
16918
+ if (maxTurns !== undefined && !(Number.isSafeInteger(maxTurns) && maxTurns >= 1)) {
16919
+ throw new Error(`neko config: ${source}: "maxTurns" must be an integer of 1 or more.`);
16920
+ }
16912
16921
  const storagePath = config.storagePath;
16913
16922
  if (storagePath !== undefined && typeof storagePath !== "string") {
16914
16923
  throw new Error(`neko config: ${source}: "storagePath" must be a string.`);
@@ -16978,6 +16987,66 @@ function validate(config, source) {
16978
16987
  }
16979
16988
  }
16980
16989
  }
16990
+ // packages/core/src/conversation-follow.ts
16991
+ import {
16992
+ ConversationTranscript
16993
+ } from "@earendil-works/pi-durable";
16994
+ var PAGE_SIZE = 200;
16995
+ async function followConversation(conversation, context) {
16996
+ const transcript = new ConversationTranscript((query, limit, ctx) => conversation.entries(query, limit, undefined, ctx), { pageSize: PAGE_SIZE });
16997
+ const watch = await conversation.watch(context);
16998
+ const listeners = new Set;
16999
+ let byId;
17000
+ let value;
17001
+ const complete = async (view) => {
17002
+ while (view.items[0]?.kind === "earlier") {
17003
+ const before = view.items;
17004
+ view = await transcript.loadEarlier(context);
17005
+ if (view.items === before)
17006
+ break;
17007
+ }
17008
+ for (let gap = view.items.find((item) => item.kind === "gap");gap; ) {
17009
+ const before = view.items;
17010
+ view = await transcript.fillGap(gap, context);
17011
+ if (view.items === before)
17012
+ break;
17013
+ gap = view.items.find((item) => item.kind === "gap");
17014
+ }
17015
+ const { items, ...rest } = view;
17016
+ byId = undefined;
17017
+ return { ...rest, entries: items.flatMap((item) => item.kind === "entry" ? [item.entry] : []) };
17018
+ };
17019
+ try {
17020
+ value = await complete(transcript.merge(watch.value));
17021
+ } catch (error) {
17022
+ await watch.stop();
17023
+ throw error;
17024
+ }
17025
+ watch.start(async (call) => {
17026
+ if (call.kind !== "value")
17027
+ return;
17028
+ value = await complete(transcript.merge(call.value));
17029
+ for (const listener of listeners)
17030
+ listener(value);
17031
+ });
17032
+ return {
17033
+ get value() {
17034
+ return value;
17035
+ },
17036
+ subscribe(listener) {
17037
+ listeners.add(listener);
17038
+ return () => listeners.delete(listener);
17039
+ },
17040
+ entry(id) {
17041
+ byId ??= new Map(value.entries.map((entry) => [entry.id, entry]));
17042
+ return byId.get(id);
17043
+ },
17044
+ dispose() {
17045
+ listeners.clear();
17046
+ watch.stop();
17047
+ }
17048
+ };
17049
+ }
16981
17050
  // packages/core/src/credentials.ts
16982
17051
  import { chmod, mkdir, open, readFile, stat, unlink } from "fs/promises";
16983
17052
  import { homedir as homedir2 } from "os";
@@ -17572,13 +17641,14 @@ function totalUsage(state) {
17572
17641
  }
17573
17642
  return total;
17574
17643
  }
17644
+ var RUN_FAILURE_DETAIL_CHARS = 500;
17575
17645
  function projectChatView(view, modelLabel, options = {}) {
17576
17646
  const live = view.docs["pi.live"] ?? {};
17577
17647
  const usage = totalUsage(view.docs["pi.usage"] ?? { models: {}, tools: {} });
17578
17648
  const agent = view.docs["pi.agent"];
17579
17649
  const agentModel = agent?.model ?? null;
17580
17650
  const contextWindow = options.models?.find((m) => `${m.provider}/${m.modelId}` === (agentModel ? `${agentModel.provider}/${agentModel.modelId}` : modelLabel))?.contextWindow ?? 0;
17581
- const tokens = contextTokens(options.contextEntries ?? view.entries);
17651
+ const tokens = contextTokens(view.entries);
17582
17652
  const results = new Map;
17583
17653
  for (const entry of view.entries) {
17584
17654
  for (const message of entry.model ?? []) {
@@ -17730,10 +17800,18 @@ function projectChatView(view, modelLabel, options = {}) {
17730
17800
  percent: tokens !== null && contextWindow > 0 ? tokens / contextWindow * 100 : null
17731
17801
  },
17732
17802
  compaction: {
17733
- active: [...live.compactions ?? []],
17803
+ active: (live.compactions ?? []).map(({ trigger, ...status }) => ({ ...status, reason: trigger })),
17734
17804
  latest: options.compaction ?? null,
17735
- ...live.compactionFailure ? { failure: live.compactionFailure } : {}
17805
+ ...live.compactionFailure ? {
17806
+ failure: {
17807
+ taskId: live.compactionFailure.taskId,
17808
+ reason: live.compactionFailure.trigger,
17809
+ error: live.compactionFailure.error
17810
+ }
17811
+ } : {}
17736
17812
  },
17813
+ ...live.run === undefined && live.runFailure ? { runFailure: runFailureView(live.runFailure) } : {},
17814
+ continuable: true,
17737
17815
  model: agentModel !== null ? `${agentModel.provider}/${agentModel.modelId}` : modelLabel,
17738
17816
  agent: {
17739
17817
  model: agentModel,
@@ -17754,6 +17832,13 @@ function projectChatView(view, modelLabel, options = {}) {
17754
17832
  streaming: projectStreaming(live)
17755
17833
  };
17756
17834
  }
17835
+ function runFailureView(failure) {
17836
+ const detail = failure.detail?.replace(/\p{Cc}/gu, " ").trim();
17837
+ return {
17838
+ reason: failure.reason,
17839
+ ...detail ? { detail: detail.length > RUN_FAILURE_DETAIL_CHARS ? `${detail.slice(0, RUN_FAILURE_DETAIL_CHARS)}\u2026` : detail } : {}
17840
+ };
17841
+ }
17757
17842
  function withArgs(item, name, args) {
17758
17843
  const summary = summarizeToolCall(name, args);
17759
17844
  const synthesized = name === "write" ? synthesizedWriteDiff(args) : null;
@@ -17838,7 +17923,7 @@ ${block.text}`;
17838
17923
  return { thinking, text, toolCalls };
17839
17924
  }
17840
17925
  function contextTokens(entries) {
17841
- const compacted = entries.reduce((id, entry) => entry.kind === "pi.compaction" ? Math.max(id, entry.id) : id, 0);
17926
+ const compacted = entries.reduce((id, entry) => entry.kind === "pi.compaction" || entry.kind === "pi.reset" ? Math.max(id, entry.id) : id, 0);
17842
17927
  for (let i = entries.length - 1;i >= 0; i--) {
17843
17928
  const entry = entries[i];
17844
17929
  const message = entry.model?.[0];
@@ -17916,6 +18001,7 @@ function nestedChangeWraps() {
17916
18001
  }
17917
18002
 
17918
18003
  // packages/core/src/subagents.ts
18004
+ import { StringEnum } from "@earendil-works/pi-ai";
17919
18005
  import {
17920
18006
  AssistantEntry,
17921
18007
  configure,
@@ -17926,8 +18012,7 @@ import {
17926
18012
  LiveDoc,
17927
18013
  UsageDoc
17928
18014
  } from "@earendil-works/pi-durable";
17929
- import { Type } from "typebox";
17930
- import { Value } from "typebox/value";
18015
+ import { arr, compile, int, lit, nul, num, obj, oneOf, opt, str, union } from "@earendil-works/pi-schema";
17931
18016
 
17932
18017
  // packages/core/src/plan-doc.ts
17933
18018
  import { defineDoc as defineDoc2 } from "@earendil-works/pi-durable";
@@ -18313,59 +18398,60 @@ async function acquireSlot(tx, round, cwd) {
18313
18398
  slots.items.push({ taskId: round.taskId, parentId: round.parentId, cwd, coder: round.role === "coder" });
18314
18399
  return true;
18315
18400
  }
18316
- var actionParameters = Type.Union([
18317
- Type.Object({
18318
- action: Type.Optional(Type.Literal("create")),
18319
- type: Type.Enum(["explore", "plan", "coder"]),
18320
- title: Type.String({ minLength: 1, maxLength: 80 }),
18321
- task: Type.String({ minLength: 1, maxLength: 32768 })
18322
- }, { additionalProperties: false }),
18323
- Type.Object({
18324
- action: Type.Literal("continue"),
18325
- agentId: Type.String(),
18326
- title: Type.String({ minLength: 1, maxLength: 80 }),
18327
- task: Type.String({ minLength: 1, maxLength: 32768 })
18328
- }, { additionalProperties: false }),
18329
- Type.Object({
18330
- action: Type.Literal("list"),
18331
- cursor: Type.Optional(Type.Integer({ minimum: 0 })),
18332
- limit: Type.Optional(Type.Integer({ minimum: 1, maximum: 100 }))
18333
- }, { additionalProperties: false })
18401
+ var actionParameters = union([
18402
+ obj({
18403
+ action: opt(lit("create")),
18404
+ type: oneOf(["explore", "plan", "coder"]),
18405
+ title: str({ minLength: 1, maxLength: 80 }),
18406
+ task: str({ minLength: 1, maxLength: 32768 })
18407
+ }),
18408
+ obj({
18409
+ action: lit("continue"),
18410
+ agentId: str(),
18411
+ title: str({ minLength: 1, maxLength: 80 }),
18412
+ task: str({ minLength: 1, maxLength: 32768 })
18413
+ }),
18414
+ obj({
18415
+ action: lit("list"),
18416
+ cursor: opt(int({ minimum: 0 })),
18417
+ limit: opt(int({ minimum: 1, maximum: 100 }))
18418
+ })
18334
18419
  ]);
18335
- var parameters = Type.Object({
18336
- action: Type.Optional(Type.String({ enum: ["create", "continue", "list"], description: "Defaults to create." })),
18337
- type: Type.Optional(Type.String({ enum: ["explore", "plan", "coder"], description: "Required for create only." })),
18338
- agentId: Type.Optional(Type.String({ description: "Required for continue only; use an ID returned by create/list." })),
18339
- title: Type.Optional(Type.String({ minLength: 1, maxLength: 80, description: "Required for create/continue." })),
18340
- task: Type.Optional(Type.String({ minLength: 1, maxLength: 32768, description: "Required for create/continue." })),
18341
- cursor: Type.Optional(Type.Integer({ minimum: 0, description: "List pagination cursor only." })),
18342
- limit: Type.Optional(Type.Integer({ minimum: 1, maximum: 100, description: "List page size only." }))
18343
- }, { additionalProperties: false });
18344
- var structuredOutputSchema = Type.Union([
18345
- Type.Object({
18346
- agentId: Type.String(),
18347
- roundId: Type.Integer(),
18348
- status: Type.Enum(["completed", "failed", "cancelled"]),
18349
- report: Type.String()
18350
- }, { additionalProperties: false }),
18351
- Type.Object({
18352
- items: Type.Array(Type.Object({
18353
- agentId: Type.String(),
18354
- parentId: Type.Integer(),
18355
- childId: Type.Integer(),
18356
- role: Type.Enum(["explore", "plan", "coder"]),
18357
- title: Type.String(),
18358
- status: Type.Enum(["idle", "queued", "running"]),
18359
- activeRoundId: Type.Union([Type.Integer(), Type.Null()]),
18360
- lastRoundId: Type.Integer(),
18361
- lastReport: Type.Optional(Type.Union([Type.String(), Type.Null()])),
18362
- roundCount: Type.Integer(),
18363
- taskTitle: Type.String(),
18364
- approvalCount: Type.Integer(),
18365
- createdAt: Type.Number()
18366
- }, { additionalProperties: false })),
18367
- next: Type.Union([Type.Integer(), Type.Null()])
18368
- }, { additionalProperties: false })
18420
+ var isActionParameters = compile(actionParameters).check;
18421
+ var parameters = obj({
18422
+ action: opt(StringEnum(["create", "continue", "list"], { description: "Defaults to create." })),
18423
+ type: opt(StringEnum(["explore", "plan", "coder"], { description: "Required for create only." })),
18424
+ agentId: opt(str({ description: "Required for continue only; use an ID returned by create/list." })),
18425
+ title: opt(str({ minLength: 1, maxLength: 80, description: "Required for create/continue." })),
18426
+ task: opt(str({ minLength: 1, maxLength: 32768, description: "Required for create/continue." })),
18427
+ cursor: opt(int({ minimum: 0, description: "List pagination cursor only." })),
18428
+ limit: opt(int({ minimum: 1, maximum: 100, description: "List page size only." }))
18429
+ });
18430
+ var structuredOutputSchema = union([
18431
+ obj({
18432
+ agentId: str(),
18433
+ roundId: int(),
18434
+ status: oneOf(["completed", "failed", "cancelled"]),
18435
+ report: str()
18436
+ }),
18437
+ obj({
18438
+ items: arr(obj({
18439
+ agentId: str(),
18440
+ parentId: int(),
18441
+ childId: int(),
18442
+ role: oneOf(["explore", "plan", "coder"]),
18443
+ title: str(),
18444
+ status: oneOf(["idle", "queued", "running"]),
18445
+ activeRoundId: union([int(), nul()]),
18446
+ lastRoundId: int(),
18447
+ lastReport: opt(union([str(), nul()])),
18448
+ roundCount: int(),
18449
+ taskTitle: str(),
18450
+ approvalCount: int(),
18451
+ createdAt: num()
18452
+ })),
18453
+ next: union([int(), nul()])
18454
+ })
18369
18455
  ]);
18370
18456
  var ADMISSION_POLL_MS = 100;
18371
18457
  function pause(runtime, ms) {
@@ -18511,7 +18597,7 @@ function createSubagentExtension(prepare, discard, guard) {
18511
18597
  replay: "safe",
18512
18598
  callers: ["model"],
18513
18599
  execute: async (input, api, context) => {
18514
- if (!Value.Check(actionParameters, input))
18600
+ if (!isActionParameters(input))
18515
18601
  throw new Error("Invalid subagent arguments. create requires type/title/task; continue requires agentId/title/task; list accepts only cursor/limit. Do not mix fields from different actions.");
18516
18602
  const args = input;
18517
18603
  if ((await api.snapshot(SubagentDoc, api.conversationId, context))?.role)
@@ -18567,6 +18653,7 @@ function createSubagentExtension(prepare, discard, guard) {
18567
18653
  model: agent.model,
18568
18654
  thinkingLevel: agent.thinkingLevel,
18569
18655
  cwd: agent.cwd,
18656
+ maxTurns: agent.maxTurns ?? null,
18570
18657
  extensions: agent.extensions.filter((e) => e.name !== extension.name && !MAIN_ONLY_EXTENSIONS.has(e.name)),
18571
18658
  modelTools: agentChangeFor({ plan: "normal", codemode, role: "subagent" }).modelTools,
18572
18659
  tools: enabled.filter((t) => t.name !== "subagent" && t.name !== "job" && !MAIN_ONLY_TOOLS.has(t.name) && (role === "coder" || READ_TOOLS.has(t.name) || role === "explore" && t.name === "bash"))
@@ -18711,7 +18798,7 @@ async function installSubagentCoordinator(harness, parents, context) {
18711
18798
  }, context);
18712
18799
  }
18713
18800
  }
18714
- const stop = harness.subscribeCommits(({ changes }) => {
18801
+ const stop = onCommits(harness, ({ changes }) => {
18715
18802
  for (const c of changes)
18716
18803
  if (c.type === "document" && c.record.kind === "app.neko.delegations" && c.conversationId !== undefined)
18717
18804
  known.add(c.conversationId);
@@ -19490,6 +19577,9 @@ var parseFrontmatter = (content) => {
19490
19577
  return { frontmatter: parsed ?? {}, body };
19491
19578
  };
19492
19579
  var stripFrontmatter = (content) => extractFrontmatter(content).body;
19580
+ // packages/core/src/run-failure.ts
19581
+ var CONTINUE_BUSY = "CONTINUE_BUSY: The session is running; wait for it to finish.";
19582
+ var CONTINUE_UNAVAILABLE = "CONTINUE_UNAVAILABLE: The last run was answered; there is nothing to continue.";
19493
19583
  // packages/core/src/runtime.ts
19494
19584
  import { homedir as homedir4 } from "os";
19495
19585
  import { join as join5 } from "path";
@@ -19499,14 +19589,15 @@ import { builtinProviders } from "@earendil-works/pi-ai/providers/all";
19499
19589
  import { PI_ATTRIBUTION } from "@earendil-works/pi-ai/utils/identity";
19500
19590
  import {
19501
19591
  AssistantEntry as AssistantEntry2,
19592
+ ConversationBusy,
19593
+ configure as configure3,
19502
19594
  createRegistry,
19503
19595
  defineDoc as defineDoc10,
19504
19596
  Harness,
19505
19597
  InboxDoc as InboxDoc3,
19506
19598
  LiveDoc as importLiveDoc,
19507
19599
  MemoryStorage,
19508
- UsageDoc as UsageDoc2,
19509
- watchEvents
19600
+ UsageDoc as UsageDoc2
19510
19601
  } from "@earendil-works/pi-durable";
19511
19602
  import { createNodePhotonImages } from "@earendil-works/pi-durable/images/node";
19512
19603
  import { openNodeSqliteStorage } from "@earendil-works/pi-durable/storage/sqlite/node";
@@ -19516,7 +19607,7 @@ import { createCodingTools } from "@earendil-works/pi-durable/tools";
19516
19607
  import { BACKGROUND_CONTEXT, withAbortSignal } from "@earendil-works/chord/context";
19517
19608
  import { defineExtension as defineExtension2, defineTool as defineTool2 } from "@earendil-works/pi-durable";
19518
19609
  import { getOrThrow } from "@earendil-works/pi-durable/env";
19519
- import { Type as Type2 } from "typebox";
19610
+ import { bool, int as int2, obj as obj2, opt as opt2, str as str2 } from "@earendil-works/pi-schema";
19520
19611
  var SEARCH_LIMITS = {
19521
19612
  entries: 1e4,
19522
19613
  fileBytes: 2 * 1024 * 1024,
@@ -19524,8 +19615,8 @@ var SEARCH_LIMITS = {
19524
19615
  outputBytes: 32 * 1024,
19525
19616
  timeoutMs: 1e4
19526
19617
  };
19527
- var path = Type2.Optional(Type2.String({ description: "Directory relative to this conversation's cwd, or absolute path." }));
19528
- var limit = Type2.Optional(Type2.Integer({ minimum: 1, maximum: 500, description: "Maximum results (default 100)." }));
19618
+ var path = opt2(str2({ description: "Directory relative to this conversation's cwd, or absolute path." }));
19619
+ var limit = opt2(int2({ minimum: 1, maximum: 500, description: "Maximum results (default 100)." }));
19529
19620
  var text2 = (value) => ({ type: "text", text: value });
19530
19621
  async function search(api, context, run) {
19531
19622
  if (!api.env)
@@ -19565,7 +19656,7 @@ ${status}${skipped ? ` Skipped/unreadable files: ${skipped}.` : ""}`)],
19565
19656
  var FindFiles = defineTool2({
19566
19657
  name: "find_files",
19567
19658
  description: "Discover files and directories without a shell. query is a literal path/name substring (not a glob). Respects gitignore; returns absolute paths usable by read. A partial result is not a complete absence of matches.",
19568
- parameters: Type2.Object({ path, query: Type2.Optional(Type2.String()), limit }),
19659
+ parameters: obj2({ path, query: opt2(str2()), limit }, { open: true }),
19569
19660
  replay: "safe",
19570
19661
  execute: (args, api, context) => search(api, context, async (env, ctx) => {
19571
19662
  const files = await listing(env, args.path ?? ".", ctx);
@@ -19591,14 +19682,14 @@ var FindFiles = defineTool2({
19591
19682
  var SearchText = defineTool2({
19592
19683
  name: "search_text",
19593
19684
  description: "Search UTF-8 file contents without a shell. pattern and filePattern are literal substrings, not regex/globs. Returns absolute paths, 1-based line numbers and context for read. Binary/large/unreadable files and exhausted budgets are explicitly reported as partial results.",
19594
- parameters: Type2.Object({
19595
- pattern: Type2.String({ minLength: 1, maxLength: 4096 }),
19685
+ parameters: obj2({
19686
+ pattern: str2({ minLength: 1, maxLength: 4096 }),
19596
19687
  path,
19597
- filePattern: Type2.Optional(Type2.String()),
19598
- caseSensitive: Type2.Optional(Type2.Boolean()),
19599
- contextLines: Type2.Optional(Type2.Integer({ minimum: 0, maximum: 5 })),
19688
+ filePattern: opt2(str2()),
19689
+ caseSensitive: opt2(bool()),
19690
+ contextLines: opt2(int2({ minimum: 0, maximum: 5 })),
19600
19691
  limit
19601
- }),
19692
+ }, { open: true }),
19602
19693
  replay: "safe",
19603
19694
  execute: (args, api, context) => search(api, context, async (env, ctx) => {
19604
19695
  const files = await listing(env, args.path ?? ".", ctx);
@@ -19767,7 +19858,7 @@ class ContextPruner {
19767
19858
  #closed = false;
19768
19859
  constructor(options) {
19769
19860
  this.#options = options;
19770
- this.#unsubscribe = options.harness.subscribeCommits(({ changes }) => {
19861
+ this.#unsubscribe = onCommits(options.harness, ({ changes }) => {
19771
19862
  if (!options.settings().enabled)
19772
19863
  return;
19773
19864
  for (const change of changes) {
@@ -19875,7 +19966,7 @@ import {
19875
19966
  defineTask as defineTask2,
19876
19967
  defineTool as defineTool3
19877
19968
  } from "@earendil-works/pi-durable";
19878
- import { Type as Type3 } from "typebox";
19969
+ import { int as int3, lit as lit2, num as num2, obj as obj3, opt as opt3, str as str3, union as union2 } from "@earendil-works/pi-schema";
19879
19970
  var plain = (value) => JSON.parse(JSON.stringify(value));
19880
19971
 
19881
19972
  class JobEntry {
@@ -20016,15 +20107,15 @@ var delay = (ms, signal) => new Promise((resolve) => {
20016
20107
  else
20017
20108
  signal?.addEventListener("abort", done, { once: true });
20018
20109
  });
20019
- var action = Type3.Union([Type3.Literal("start"), Type3.Literal("output"), Type3.Literal("stop"), Type3.Literal("list")]);
20020
- var parameters2 = Type3.Object({
20110
+ var action = union2([lit2("start"), lit2("output"), lit2("stop"), lit2("list")]);
20111
+ var parameters2 = obj3({
20021
20112
  action,
20022
- command: Type3.Optional(Type3.String({ description: "start: shell command to run in the session's working directory." })),
20023
- title: Type3.Optional(Type3.String({ description: "start: short label shown in the job list." })),
20024
- timeout: Type3.Optional(Type3.Number({ description: "start: optional timeout in seconds; no default timeout." })),
20025
- jobId: Type3.Optional(Type3.String({ description: "output/stop: the job id returned by start or list." })),
20026
- since: Type3.Optional(Type3.Integer({ description: "output: resume after this offset, as returned by the previous output call." }))
20027
- });
20113
+ command: opt3(str3({ description: "start: shell command to run in the session's working directory." })),
20114
+ title: opt3(str3({ description: "start: short label shown in the job list." })),
20115
+ timeout: opt3(num2({ description: "start: optional timeout in seconds; no default timeout." })),
20116
+ jobId: opt3(str3({ description: "output/stop: the job id returned by start or list." })),
20117
+ since: opt3(int3({ description: "output: resume after this offset, as returned by the previous output call." }))
20118
+ }, { open: true });
20028
20119
  var stringField = (value, name) => {
20029
20120
  if (typeof value !== "string" || !value.trim())
20030
20121
  throw new Error(`Invalid job arguments: ${name} must be a nonempty string.`);
@@ -20314,7 +20405,7 @@ import {
20314
20405
  wrapTool as wrapTool3
20315
20406
  } from "@earendil-works/pi-durable";
20316
20407
  import { createBashTool } from "@earendil-works/pi-durable/tools";
20317
- import { Type as Type5 } from "typebox";
20408
+ import { arr as arr3, obj as obj5, opt as opt5, str as str5 } from "@earendil-works/pi-schema";
20318
20409
 
20319
20410
  // packages/core/src/plan-bash.ts
20320
20411
  var SAFE_PATTERNS = [
@@ -20423,13 +20514,14 @@ function isSafeCommand(command) {
20423
20514
 
20424
20515
  // packages/core/src/user-questions.ts
20425
20516
  import { randomUUID } from "crypto";
20517
+ import { StringEnum as StringEnum2 } from "@earendil-works/pi-ai";
20426
20518
  import {
20427
20519
  defineDoc as defineDoc6,
20428
20520
  defineDocFamily,
20429
20521
  defineExtension as defineExtension5,
20430
20522
  defineTool as defineTool4
20431
20523
  } from "@earendil-works/pi-durable";
20432
- import { Type as Type4 } from "typebox";
20524
+ import { arr as arr2, bool as bool2, nul as nul2, obj as obj4, opt as opt4, str as str4, union as union3 } from "@earendil-works/pi-schema";
20433
20525
  var QuestionDoc = defineDocFamily({
20434
20526
  kind: "app.neko.question",
20435
20527
  checkpointWhen: () => false,
@@ -20493,7 +20585,7 @@ class UserQuestions {
20493
20585
  constructor(harness, context) {
20494
20586
  this.harness = harness;
20495
20587
  this.#context = context;
20496
- const stop = harness.subscribeCommits(({ changes }) => {
20588
+ const stop = onCommits(harness, ({ changes }) => {
20497
20589
  if (!changes.some((c) => c.type === "task" && (c.value.abortRequested || c.value.state.status === "terminal")))
20498
20590
  return;
20499
20591
  this.reconcileAll();
@@ -20599,13 +20691,16 @@ class UserQuestions {
20599
20691
  if (signal?.aborted)
20600
20692
  return onAbort();
20601
20693
  watch.closed.then((end) => {
20602
- if (end.reason === "stopped")
20694
+ if (end.kind === "stopped")
20603
20695
  return;
20604
- finish(() => reject(signal?.aborted ? signal.reason : end.reason === "listener_error" || end.reason === "session_failed" ? end.error : new Error(`Question watch ended: ${end.reason}`)));
20696
+ finish(() => reject(signal?.aborted ? signal.reason : end.kind === "listener_error" || end.kind === "failed" ? end.error : new Error(`Question watch ended: ${end.kind}`)));
20605
20697
  });
20606
20698
  check(watch.value);
20607
20699
  if (!done)
20608
- watch.start(async (value) => check(value));
20700
+ watch.start(async (call) => {
20701
+ if (call.kind === "value")
20702
+ check(call.value);
20703
+ });
20609
20704
  });
20610
20705
  } finally {
20611
20706
  signal?.removeEventListener("abort", onAbort);
@@ -20659,31 +20754,31 @@ class UserQuestions {
20659
20754
  }, context);
20660
20755
  }
20661
20756
  }
20662
- var optionSchema = Type4.Object({
20663
- id: Type4.String({
20757
+ var optionSchema = obj4({
20758
+ id: str4({
20664
20759
  minLength: 1,
20665
20760
  maxLength: QUESTION_LIMITS.optionIdChars,
20666
20761
  description: "Unique within the question."
20667
20762
  }),
20668
- label: Type4.String({
20763
+ label: str4({
20669
20764
  minLength: 1,
20670
20765
  maxLength: QUESTION_LIMITS.labelChars,
20671
20766
  description: "Short, unique, readable alone."
20672
20767
  }),
20673
- description: Type4.Optional(Type4.String({ maxLength: QUESTION_LIMITS.descriptionChars })),
20674
- recommended: Type4.Optional(Type4.Boolean({ description: "Your suggested choice; shown as a hint, never preselected." }))
20675
- }, { additionalProperties: false });
20676
- var parameters3 = Type4.Object({
20677
- question: Type4.String({ minLength: 1, maxLength: QUESTION_LIMITS.questionChars }),
20678
- multiple: Type4.Optional(Type4.Boolean({ description: "Let the user pick several options; needs at least 2 options. Default false." })),
20679
- options: Type4.Optional(Type4.Array(optionSchema, { maxItems: QUESTION_LIMITS.maxOptions }))
20680
- }, { additionalProperties: false });
20681
- var structuredOutputSchema2 = Type4.Object({
20682
- status: Type4.String({ enum: ["answered", "skipped", "cancelled"] }),
20683
- optionIds: Type4.Optional(Type4.Array(Type4.String())),
20684
- labels: Type4.Optional(Type4.Array(Type4.String())),
20685
- text: Type4.Optional(Type4.Union([Type4.String(), Type4.Null()]))
20686
- }, { additionalProperties: false });
20768
+ description: opt4(str4({ maxLength: QUESTION_LIMITS.descriptionChars })),
20769
+ recommended: opt4(bool2({ description: "Your suggested choice; shown as a hint, never preselected." }))
20770
+ });
20771
+ var parameters3 = obj4({
20772
+ question: str4({ minLength: 1, maxLength: QUESTION_LIMITS.questionChars }),
20773
+ multiple: opt4(bool2({ description: "Let the user pick several options; needs at least 2 options. Default false." })),
20774
+ options: opt4(arr2(optionSchema, { maxItems: QUESTION_LIMITS.maxOptions }))
20775
+ });
20776
+ var structuredOutputSchema2 = obj4({
20777
+ status: StringEnum2(["answered", "skipped", "cancelled"]),
20778
+ optionIds: opt4(arr2(str4())),
20779
+ labels: opt4(arr2(str4())),
20780
+ text: opt4(union3([str4(), nul2()]))
20781
+ });
20687
20782
  function questionOutput(record) {
20688
20783
  if (record.status === "answered" && record.answer) {
20689
20784
  const labels = answerLabels(record, record.answer);
@@ -20855,22 +20950,24 @@ class PlanService {
20855
20950
  return toRecord(item);
20856
20951
  }, context);
20857
20952
  }
20858
- async decide(id, version, decision) {
20953
+ async decideWith(id, version, decision, act) {
20859
20954
  return this.harness.commit(async (tx) => {
20860
20955
  const state = await tx.doc(PlanDoc, id);
20861
20956
  const item = state.items.find((i) => i.version === version);
20862
20957
  if (!item)
20863
20958
  throw new Error("Plan not found.");
20864
- if (item.status === "awaiting_approval") {
20865
- if (decision.kind === "approve") {
20866
- settle2(state, item, "approved");
20867
- state.mode = "normal";
20868
- } else {
20869
- settle2(state, item, "revision_requested");
20870
- item.feedback = decision.feedback;
20871
- }
20959
+ if (item.status !== "awaiting_approval")
20960
+ return toRecord(item);
20961
+ await act(tx);
20962
+ if (decision.kind === "approve") {
20963
+ settle2(state, item, "approved");
20964
+ state.mode = "normal";
20965
+ } else {
20966
+ settle2(state, item, "revision_requested");
20967
+ item.feedback = decision.feedback;
20872
20968
  }
20873
- return { record: toRecord(item), item: clone2(item) };
20969
+ item.dispatched = true;
20970
+ return toRecord(item);
20874
20971
  }, this.#context);
20875
20972
  }
20876
20973
  async supersedePending(id) {
@@ -20921,15 +21018,15 @@ function planRevisionPrompt(plan, feedback) {
20921
21018
  ].join(`
20922
21019
  `);
20923
21020
  }
20924
- var parameters4 = Type5.Object({
20925
- title: Type5.String({ minLength: 1, maxLength: PLAN_LIMITS.titleChars, description: "Short name of the plan." }),
20926
- steps: Type5.Array(Type5.String({ minLength: 1, maxLength: PLAN_LIMITS.stepChars }), {
21021
+ var parameters4 = obj5({
21022
+ title: str5({ minLength: 1, maxLength: PLAN_LIMITS.titleChars, description: "Short name of the plan." }),
21023
+ steps: arr3(str5({ minLength: 1, maxLength: PLAN_LIMITS.stepChars }), {
20927
21024
  minItems: 1,
20928
21025
  maxItems: PLAN_LIMITS.maxSteps,
20929
21026
  description: "Ordered, concrete implementation steps."
20930
21027
  }),
20931
- note: Type5.Optional(Type5.String({ maxLength: PLAN_LIMITS.noteChars, description: "Risks, assumptions and how to verify." }))
20932
- }, { additionalProperties: false });
21028
+ note: opt5(str5({ maxLength: PLAN_LIMITS.noteChars, description: "Risks, assumptions and how to verify." }))
21029
+ });
20933
21030
  function submitPlanTool(service) {
20934
21031
  return defineTool5({
20935
21032
  name: "submit_plan",
@@ -21582,7 +21679,7 @@ class SessionMetadataManager {
21582
21679
  this.context = context;
21583
21680
  this.report = report;
21584
21681
  registry.install(defineExtension8({ name: "neko-naming", tasks: [this.task] }));
21585
- this.#unsubscribe = harness.subscribeCommits(({ changes }) => {
21682
+ this.#unsubscribe = onCommits(harness, ({ changes }) => {
21586
21683
  const ids = new Set;
21587
21684
  const submissions = new Map;
21588
21685
  let notice = false;
@@ -21597,7 +21694,7 @@ class SessionMetadataManager {
21597
21694
  if (c.record.kind === "pi.agent" || c.record.kind === QuestionsDoc.definition.kind || c.record.kind === PlanDoc.definition.kind)
21598
21695
  ids.add(c.conversationId);
21599
21696
  if (c.record.kind === "pi.live") {
21600
- const running = c.value?.run !== undefined;
21697
+ const running = c.kind === "change" && c.value.run !== undefined;
21601
21698
  if (this.#live.get(c.conversationId) !== running) {
21602
21699
  this.#live.set(c.conversationId, running);
21603
21700
  ids.add(c.conversationId);
@@ -21727,8 +21824,9 @@ class SessionMetadataManager {
21727
21824
  }
21728
21825
 
21729
21826
  // packages/core/src/todos.ts
21827
+ import { StringEnum as StringEnum3 } from "@earendil-works/pi-ai";
21730
21828
  import { defineDoc as defineDoc8, defineExtension as defineExtension9, defineTool as defineTool6 } from "@earendil-works/pi-durable";
21731
- import { Type as Type6 } from "typebox";
21829
+ import { arr as arr4, int as int4, obj as obj6, opt as opt6, str as str6 } from "@earendil-works/pi-schema";
21732
21830
  var TodosDoc = defineDoc8({
21733
21831
  kind: "app.neko.todos",
21734
21832
  checkpointWhen: () => false,
@@ -21745,23 +21843,23 @@ var TodoReceiptDoc = defineDoc8({
21745
21843
  scope: "task",
21746
21844
  initial: () => ({ applied: false, revision: 0, items: [] })
21747
21845
  });
21748
- var itemSchema = Type6.Object({
21749
- id: Type6.String({
21846
+ var itemSchema = obj6({
21847
+ id: str6({
21750
21848
  minLength: 1,
21751
21849
  maxLength: TODO_LIMITS.idChars,
21752
21850
  description: "Stable id; keep it when you update the same task."
21753
21851
  }),
21754
- text: Type6.String({ minLength: 1, maxLength: TODO_LIMITS.textChars }),
21755
- status: Type6.String({ enum: [...TODO_STATUSES] })
21756
- }, { additionalProperties: false });
21757
- var parameters5 = Type6.Object({
21758
- action: Type6.String({ enum: ["list", "replace"], description: "list reads the list; replace overwrites it." }),
21759
- items: Type6.Optional(Type6.Array(itemSchema, {
21852
+ text: str6({ minLength: 1, maxLength: TODO_LIMITS.textChars }),
21853
+ status: StringEnum3([...TODO_STATUSES])
21854
+ });
21855
+ var parameters5 = obj6({
21856
+ action: StringEnum3(["list", "replace"], { description: "list reads the list; replace overwrites it." }),
21857
+ items: opt6(arr4(itemSchema, {
21760
21858
  maxItems: TODO_LIMITS.maxItems,
21761
21859
  description: "Required for replace only: the complete ordered list; [] clears it."
21762
21860
  }))
21763
- }, { additionalProperties: false });
21764
- var structuredOutputSchema3 = Type6.Object({ revision: Type6.Integer({ minimum: 0 }), items: Type6.Array(itemSchema) }, { additionalProperties: false });
21861
+ });
21862
+ var structuredOutputSchema3 = obj6({ revision: int4({ minimum: 0 }), items: arr4(itemSchema) });
21765
21863
  var clone3 = (value) => JSON.parse(JSON.stringify(value));
21766
21864
  function renderTodos(list) {
21767
21865
  const { completed, total } = todoProgress(list.items);
@@ -21856,7 +21954,7 @@ class ToolApprovals {
21856
21954
  #parents = new Set;
21857
21955
  constructor(harness, context) {
21858
21956
  this.harness = harness;
21859
- const stop = harness.subscribeCommits(({ changes }) => {
21957
+ const stop = onCommits(harness, ({ changes }) => {
21860
21958
  if (!changes.some((c) => c.type === "task" && (c.value.abortRequested || c.value.state.status === "terminal")))
21861
21959
  return;
21862
21960
  for (const parent of this.#parents)
@@ -21891,14 +21989,12 @@ class ToolApprovals {
21891
21989
  }, context);
21892
21990
  }
21893
21991
  async wait(parent, id, context) {
21894
- const state = await this.harness.documentState(ApprovalsDoc, parent, context);
21895
- if (!state)
21992
+ const watch = await this.harness.watchDoc(ApprovalsDoc, parent, context);
21993
+ if (!watch)
21896
21994
  throw new Error("Approval unavailable");
21897
21995
  try {
21898
21996
  return await new Promise((resolve, reject) => {
21899
- let stop = () => {};
21900
21997
  const cleanup = () => {
21901
- stop();
21902
21998
  context.abortSignal?.removeEventListener("abort", abort);
21903
21999
  };
21904
22000
  const abort = () => {
@@ -21906,13 +22002,16 @@ class ToolApprovals {
21906
22002
  reject(context.abortSignal?.reason ?? new Error("Cancelled"));
21907
22003
  };
21908
22004
  const check = () => {
21909
- const item = state.value?.items.find((a) => a.id === id);
22005
+ const item = watch.value.items.find((a) => a.id === id);
21910
22006
  if (item && item.status !== "pending") {
21911
22007
  cleanup();
21912
22008
  resolve(structuredClone(item));
21913
22009
  }
21914
22010
  };
21915
- stop = state.subscribe(check);
22011
+ watch.start(async (call) => {
22012
+ if (call.kind === "value")
22013
+ check();
22014
+ });
21916
22015
  context.abortSignal?.addEventListener("abort", abort, { once: true });
21917
22016
  if (context.abortSignal?.aborted)
21918
22017
  abort();
@@ -21920,7 +22019,7 @@ class ToolApprovals {
21920
22019
  check();
21921
22020
  });
21922
22021
  } finally {
21923
- state.dispose();
22022
+ await watch.stop();
21924
22023
  }
21925
22024
  }
21926
22025
  async ensure(parent, candidate, context) {
@@ -22230,8 +22329,8 @@ function createDeepseekProvider(resolveKey, fetchImpl = fetch, options = {}) {
22230
22329
  }
22231
22330
 
22232
22331
  // packages/core/src/web-search/index.ts
22233
- import { Type as Type7 } from "@earendil-works/pi-ai";
22234
22332
  import { defineExtension as defineExtension11, defineTool as defineTool7 } from "@earendil-works/pi-durable";
22333
+ import { arr as arr5, num as num3, obj as obj7, opt as opt7, str as str7 } from "@earendil-works/pi-schema";
22235
22334
  var MAX_URLS = 20;
22236
22335
  var MAX_RESULTS = 10;
22237
22336
  var DEFAULT_RESULTS = 5;
@@ -22255,10 +22354,10 @@ function createWebSearchTools(resolveProvider) {
22255
22354
  defineTool7({
22256
22355
  name: "web_search",
22257
22356
  description: "Search the live web for current or unknown information. Returns ranked sources (title, URL, bounded excerpts). Keep the query short and focused (ideally under 128 characters). Use only when up-to-date or external information is needed; use web_extract to read a known URL.",
22258
- parameters: Type7.Object({
22259
- query: Type7.String({ minLength: 1, maxLength: 4096, description: "The search query" }),
22260
- maxResults: Type7.Optional(Type7.Number({ description: `Maximum number of results (1-${MAX_RESULTS}, default ${DEFAULT_RESULTS})` }))
22261
- }),
22357
+ parameters: obj7({
22358
+ query: str7({ minLength: 1, maxLength: 4096, description: "The search query" }),
22359
+ maxResults: opt7(num3({ description: `Maximum number of results (1-${MAX_RESULTS}, default ${DEFAULT_RESULTS})` }))
22360
+ }, { open: true }),
22262
22361
  async execute({ query, maxResults }, _api, context) {
22263
22362
  try {
22264
22363
  if (!query.trim() || query.length > 4096)
@@ -22286,13 +22385,13 @@ ${item.date ? `Published: ${item.date}
22286
22385
  defineTool7({
22287
22386
  name: "web_extract",
22288
22387
  description: "Extract bounded markdown excerpts from web pages by URL. Every requested URL has a result or failure entry; long content is truncated.",
22289
- parameters: Type7.Object({
22290
- urls: Type7.Array(Type7.String({ maxLength: 2048, description: "http(s) URL" }), {
22388
+ parameters: obj7({
22389
+ urls: arr5(str7({ maxLength: 2048, description: "http(s) URL" }), {
22291
22390
  minItems: 1,
22292
22391
  maxItems: MAX_URLS,
22293
22392
  description: `URLs to extract (1-${MAX_URLS})`
22294
22393
  })
22295
- }),
22394
+ }, { open: true }),
22296
22395
  async execute({ urls }, _api, context) {
22297
22396
  try {
22298
22397
  if (!urls.length || urls.length > MAX_URLS)
@@ -22690,7 +22789,7 @@ class WorkspaceFiles {
22690
22789
  }
22691
22790
  #disposeWatch(watch) {
22692
22791
  watch.controller.abort();
22693
- const closing = watch.work.catch(() => {}).then(() => watch.watcher?.close(BACKGROUND_CONTEXT2)).then(() => {}).catch(() => {}).finally(() => this.#disposing.delete(closing));
22792
+ const closing = watch.work.catch(() => {}).then(() => watch.watcher?.stop(BACKGROUND_CONTEXT2)).then(() => {}).catch(() => {}).finally(() => this.#disposing.delete(closing));
22694
22793
  this.#disposing.add(closing);
22695
22794
  }
22696
22795
  #closeWatcher(item) {
@@ -22731,7 +22830,7 @@ class WorkspaceFiles {
22731
22830
  user.generation++;
22732
22831
  user.loaded = 0;
22733
22832
  }
22734
- if ("error" in change) {
22833
+ if (change.kind === "failed") {
22735
22834
  if (this.#watches.get(item.root) === current)
22736
22835
  this.#watches.delete(item.root);
22737
22836
  for (const user of [...current.users])
@@ -22741,7 +22840,7 @@ class WorkspaceFiles {
22741
22840
  if (result.ok) {
22742
22841
  current.watcher = result.value;
22743
22842
  if (current.controller.signal.aborted)
22744
- await result.value.close(BACKGROUND_CONTEXT2);
22843
+ await result.value.stop(BACKGROUND_CONTEXT2);
22745
22844
  } else {
22746
22845
  forget();
22747
22846
  }
@@ -23086,6 +23185,9 @@ var ActivityDoc = defineDoc10({
23086
23185
  });
23087
23186
  async function createNekoRuntime(options = {}) {
23088
23187
  const context = options.context ?? BACKGROUND_CONTEXT3;
23188
+ if (options.maxTurns !== undefined && !(Number.isSafeInteger(options.maxTurns) && options.maxTurns >= 1))
23189
+ throw new RangeError(`maxTurns must be an integer of 1 or more, got ${options.maxTurns}`);
23190
+ const turnLimit = options.maxTurns === undefined ? {} : { maxTurns: options.maxTurns };
23089
23191
  const defaultCwd = normalizeWorkspace(options.cwd);
23090
23192
  const model = options.model ?? DEFAULT_MODEL;
23091
23193
  const modelOverride = options.modelOverride;
@@ -23205,7 +23307,7 @@ async function createNekoRuntime(options = {}) {
23205
23307
  return compactionFor(contextState);
23206
23308
  }
23207
23309
  },
23208
- onReport: options.onReport,
23310
+ onReport: (report) => options.onReport?.(report.error, report),
23209
23311
  conversationCreated: async (tx, record) => {
23210
23312
  (await tx.doc(SessionMetadataDoc, record.id)).createdAt = Date.now();
23211
23313
  },
@@ -23251,7 +23353,8 @@ async function createNekoRuntime(options = {}) {
23251
23353
  agent: {
23252
23354
  model: rootModel,
23253
23355
  thinkingLevel: resolveLevel(rootModel, options.thinkingLevel ?? "high"),
23254
- cwd: defaultCwd
23356
+ cwd: defaultCwd,
23357
+ ...turnLimit
23255
23358
  }
23256
23359
  });
23257
23360
  enabled = new Set(normalizeEnabledProviders((await harness.snapshot(ProviderSettingsDoc, conversation.id, context))?.enabled));
@@ -23397,9 +23500,7 @@ async function createNekoRuntime(options = {}) {
23397
23500
  if (change)
23398
23501
  await target.configure(change, context);
23399
23502
  };
23400
- const submitTo = async (target, content, submitOptions, extra) => admit(target.id, async () => {
23401
- await syncAgent(target);
23402
- const agent = await target.agent(context);
23503
+ const prepareSubmission = async (target, agent, content, submitOptions, extra) => {
23403
23504
  const workspace = executionWorkspace(agent.cwd);
23404
23505
  const duplicate = submitOptions?.requestId !== undefined && await storage.submissionByRequest(target.id, submitOptions.requestId, context);
23405
23506
  const data = { at: Date.now(), prompt: "", images: [], ...extra };
@@ -23453,15 +23554,23 @@ async function createNekoRuntime(options = {}) {
23453
23554
  }
23454
23555
  if (prepared)
23455
23556
  resourceSnapshots.stage(target.id, requestId, workspace, prepared);
23456
- let result;
23457
- try {
23458
- result = await target.submit({
23557
+ return {
23558
+ draft: {
23459
23559
  type: "input",
23460
23560
  content,
23461
23561
  entry: { kind: NekoInput.kind, data },
23462
23562
  requestId,
23463
23563
  ...submitOptions?.whenBusy !== undefined ? { whenBusy: submitOptions.whenBusy } : {}
23464
- }, context);
23564
+ },
23565
+ requestId
23566
+ };
23567
+ };
23568
+ const submitNow = async (target, content, submitOptions, extra) => {
23569
+ await syncAgent(target);
23570
+ const { draft, requestId } = await prepareSubmission(target, await target.agent(context), content, submitOptions, extra);
23571
+ let result;
23572
+ try {
23573
+ result = await target.submit(draft, context);
23465
23574
  } catch (error) {
23466
23575
  resourceSnapshots.discard(target.id, requestId);
23467
23576
  throw error;
@@ -23471,10 +23580,11 @@ async function createNekoRuntime(options = {}) {
23471
23580
  await touchConversation(target.id);
23472
23581
  await metadata.reconcile(target.id);
23473
23582
  return result;
23474
- });
23475
- const dispatchPlan = async (target, item) => {
23583
+ };
23584
+ const submitTo = (target, ...args) => admit(target.id, () => submitNow(target, ...args));
23585
+ const dispatchPlan = async (target, item, submit = submitTo) => {
23476
23586
  const approve = item.status === "approved";
23477
- await submitTo(target, approve ? approvedPlanPrompt(item) : planRevisionPrompt(item, item.feedback ?? ""), { requestId: `${approve ? "plan-exec" : "plan-revise"}:${item.version}`, whenBusy: "followUp" }, {
23587
+ await submit(target, approve ? approvedPlanPrompt(item) : planRevisionPrompt(item, item.feedback ?? ""), { requestId: `${approve ? "plan-exec" : "plan-revise"}:${item.version}`, whenBusy: "followUp" }, {
23478
23588
  planDecision: {
23479
23589
  version: item.version,
23480
23590
  kind: approve ? "approve" : "revise",
@@ -23511,15 +23621,12 @@ async function createNekoRuntime(options = {}) {
23511
23621
  waitAnswer(submission) {
23512
23622
  return waitAnswerOf(target, submission);
23513
23623
  },
23514
- viewState() {
23515
- return target.viewState(context);
23624
+ follow() {
23625
+ return followConversation(target, context);
23516
23626
  },
23517
23627
  watch() {
23518
23628
  return target.watch(context);
23519
23629
  },
23520
- events() {
23521
- return watchEvents(harness, target.id, context);
23522
- },
23523
23630
  async usage() {
23524
23631
  return mergeUsage(await harness.snapshot(UsageDoc2, target.id, context) ?? { models: {}, tools: {} }, (await harness.snapshot(SessionMetadataDoc, target.id, context))?.namingUsage ?? { models: {}, tools: {} });
23525
23632
  },
@@ -23568,18 +23675,49 @@ async function createNekoRuntime(options = {}) {
23568
23675
  },
23569
23676
  async respondPlan(version, decision) {
23570
23677
  const parsed = validatePlanDecision(decision);
23571
- const known = await plans.get(target.id, version);
23572
- if (!known)
23573
- throw new Error("Plan not found.");
23574
- if (known.status === "awaiting_approval") {
23678
+ return admit(target.id, async () => {
23679
+ const known = await plans.get(target.id, version);
23680
+ if (!known)
23681
+ throw new Error("Plan not found.");
23682
+ if (known.status !== "awaiting_approval") {
23683
+ const legacy = await plans.undispatched(target.id);
23684
+ if (legacy?.version === version)
23685
+ await dispatchPlan(target, legacy, submitNow);
23686
+ return known;
23687
+ }
23575
23688
  if (await isRunning(target.id))
23576
23689
  throw new Error(PLAN_BUSY);
23577
- await guardProvider((await target.agent(context)).model);
23578
- }
23579
- const { record, item } = await plans.decide(target.id, version, parsed);
23580
- if ((item.status === "approved" || item.status === "revision_requested") && !item.dispatched)
23581
- await dispatchPlan(target, item);
23582
- return record;
23690
+ await syncAgent(target);
23691
+ const agent = await target.agent(context);
23692
+ const approve = parsed.kind === "approve";
23693
+ const feedback = parsed.kind === "revise" ? parsed.feedback : "";
23694
+ const { draft, requestId } = await prepareSubmission(target, agent, approve ? approvedPlanPrompt(known) : planRevisionPrompt(known, feedback), { requestId: `${approve ? "plan-exec" : "plan-revise"}:${version}`, whenBusy: "followUp" }, {
23695
+ planDecision: {
23696
+ version,
23697
+ kind: approve ? "approve" : "revise",
23698
+ title: known.title,
23699
+ ...!approve && feedback ? { feedback } : {}
23700
+ }
23701
+ });
23702
+ const codemode = (await harness.snapshot(CodemodeDoc, target.id, context))?.mode ?? "off";
23703
+ const leave = approve ? agentSyncChange(agent, { plan: "normal", codemode, role: "main" }) : undefined;
23704
+ let record;
23705
+ try {
23706
+ record = await plans.decideWith(target.id, version, parsed, async (tx) => {
23707
+ await target.submit(tx, draft);
23708
+ if (leave)
23709
+ await configure3(tx, target.id, leave);
23710
+ });
23711
+ } catch (error) {
23712
+ resourceSnapshots.discard(target.id, requestId);
23713
+ throw error;
23714
+ }
23715
+ if (record.status !== "approved" && record.status !== "revision_requested")
23716
+ resourceSnapshots.discard(target.id, requestId);
23717
+ await touchConversation(target.id);
23718
+ await metadata.reconcile(target.id);
23719
+ return record;
23720
+ });
23583
23721
  },
23584
23722
  async workspaceDir(path, signal) {
23585
23723
  return workspaceFiles.children(savedWorkspace((await target.agent(context)).cwd), path, signal ?? neverAborted());
@@ -23610,6 +23748,26 @@ async function createNekoRuntime(options = {}) {
23610
23748
  await target.abort(context);
23611
23749
  await plans.cancelPending(target.id);
23612
23750
  },
23751
+ continueRun() {
23752
+ return admit(target.id, async () => {
23753
+ await syncAgent(target);
23754
+ await guardProvider((await target.agent(context)).model);
23755
+ const live = await harness.snapshot(importLiveDoc, target.id, context);
23756
+ if (live?.run !== undefined)
23757
+ throw new Error(CONTINUE_BUSY);
23758
+ if (live?.runFailure === undefined)
23759
+ throw new Error(CONTINUE_UNAVAILABLE);
23760
+ try {
23761
+ await target.submit({ type: "continue" }, context);
23762
+ } catch (error) {
23763
+ if (error instanceof ConversationBusy)
23764
+ throw new Error(CONTINUE_BUSY);
23765
+ throw error;
23766
+ }
23767
+ await touchConversation(target.id);
23768
+ await metadata.reconcile(target.id);
23769
+ });
23770
+ },
23613
23771
  async withdraw(submissionId) {
23614
23772
  const id = submissionId;
23615
23773
  const inbox = await harness.snapshot(InboxDoc3, target.id, context);
@@ -23799,15 +23957,12 @@ async function createNekoRuntime(options = {}) {
23799
23957
  root: rootSession,
23800
23958
  submit: rootSession.submit,
23801
23959
  waitAnswer: rootSession.waitAnswer,
23802
- async viewState(id) {
23803
- return (await sessionFor(id)).viewState();
23960
+ async follow(id) {
23961
+ return (await sessionFor(id)).follow();
23804
23962
  },
23805
23963
  async watch(id) {
23806
23964
  return (await sessionFor(id)).watch();
23807
23965
  },
23808
- async events(id) {
23809
- return (await sessionFor(id)).events();
23810
- },
23811
23966
  async usage(id) {
23812
23967
  return (await sessionFor(id)).usage();
23813
23968
  },
@@ -23859,6 +24014,7 @@ async function createNekoRuntime(options = {}) {
23859
24014
  model: effective,
23860
24015
  thinkingLevel: resolveLevel(effective, createOptions?.thinkingLevel ?? options.thinkingLevel ?? "high"),
23861
24016
  cwd: workspace.path,
24017
+ ...turnLimit,
23862
24018
  ...agentChangeFor({ plan: "normal", codemode: mode, role: "main" })
23863
24019
  },
23864
24020
  init: async (tx, id) => {
@@ -24060,7 +24216,20 @@ async function createNekoRuntime(options = {}) {
24060
24216
  }
24061
24217
  // packages/gateway/src/contract.ts
24062
24218
  import { hostNamed, method, remote } from "@earendil-works/chord";
24063
- import { Type as Type8 } from "typebox";
24219
+ import {
24220
+ arr as arr6,
24221
+ bool as bool3,
24222
+ int as int5,
24223
+ lit as lit3,
24224
+ map,
24225
+ nul as nul3,
24226
+ num as num4,
24227
+ obj as obj8,
24228
+ oneOf as oneOf2,
24229
+ opt as opt8,
24230
+ str as str8,
24231
+ union as union4
24232
+ } from "@earendil-works/pi-schema";
24064
24233
  var GATEWAY_HOST = "neko";
24065
24234
  var rpc = (args, result) => [args, result];
24066
24235
  function contract(name, def) {
@@ -24073,447 +24242,458 @@ function contract(name, def) {
24073
24242
  ]));
24074
24243
  return remote(name, { ...def, host: hostNamed(GATEWAY_HOST), variants });
24075
24244
  }
24076
- var str = Type8.String();
24077
- var num = Type8.Number();
24078
- var bool = Type8.Boolean();
24079
- var nil = Type8.Null();
24080
- var integer = Type8.Integer({ minimum: 0, maximum: Number.MAX_SAFE_INTEGER });
24081
- var nullableString = Type8.Union([str, nil]);
24082
- var phase = Type8.Enum(["pending", "running", "done"]);
24083
- var level = Type8.Enum(["project", "user", "builtin"]);
24084
- var thinking = Type8.Enum(["off", "minimal", "low", "medium", "high", "xhigh", "max"]);
24085
- var model2 = Type8.Object({ provider: str, modelId: str });
24086
- var change = Type8.Object({ model: Type8.Optional(model2), thinkingLevel: Type8.Optional(thinking) }, { additionalProperties: false });
24087
- var usage = Type8.Object({ input: num, output: num, cacheRead: num, cacheWrite: num, cost: num });
24088
- var image = Type8.Object({
24089
- name: str,
24090
- mimeType: str,
24245
+ var text3 = str8();
24246
+ var number = num4();
24247
+ var boolean = bool3();
24248
+ var nil = nul3();
24249
+ var integer = int5({ minimum: 0, maximum: Number.MAX_SAFE_INTEGER });
24250
+ var nullableString = union4([text3, nil]);
24251
+ var phase = oneOf2(["pending", "running", "done"]);
24252
+ var level = oneOf2(["project", "user", "builtin"]);
24253
+ var thinking = oneOf2(["off", "minimal", "low", "medium", "high", "xhigh", "max"]);
24254
+ var model2 = obj8({ provider: text3, modelId: text3 }, { open: true });
24255
+ var changeProperties = { model: opt8(model2), thinkingLevel: opt8(thinking) };
24256
+ var change = obj8(changeProperties);
24257
+ var usage = obj8({ input: number, output: number, cacheRead: number, cacheWrite: number, cost: number }, { open: true });
24258
+ var image = obj8({
24259
+ name: text3,
24260
+ mimeType: text3,
24091
24261
  width: integer,
24092
24262
  height: integer,
24093
24263
  bytes: integer,
24094
24264
  entryId: integer,
24095
24265
  contentIndex: integer
24096
- });
24097
- var skill = Type8.Object({ name: str, location: str, body: str, args: str });
24098
- var CodemodeViewSchema = Type8.Object({
24099
- calls: Type8.Array(Type8.Object({
24266
+ }, { open: true });
24267
+ var skill = obj8({ name: text3, location: text3, body: text3, args: text3 }, { open: true });
24268
+ var CodemodeViewSchema = obj8({
24269
+ calls: arr6(obj8({
24100
24270
  id: integer,
24101
- name: str,
24102
- args: str,
24103
- status: Type8.Enum(["running", "ok", "error", "cancelled"]),
24104
- durationMs: Type8.Union([num, nil]),
24271
+ name: text3,
24272
+ args: text3,
24273
+ status: oneOf2(["running", "ok", "error", "cancelled"]),
24274
+ durationMs: union4([number, nil]),
24105
24275
  error: nullableString
24106
- })),
24276
+ }, { open: true })),
24107
24277
  omitted: integer,
24108
24278
  fullOutputPath: nullableString
24109
- });
24110
- var call = Type8.Object({
24111
- callId: str,
24112
- name: str,
24113
- summary: str,
24279
+ }, { open: true });
24280
+ var call = obj8({
24281
+ callId: text3,
24282
+ name: text3,
24283
+ summary: text3,
24114
24284
  detail: nullableString,
24115
24285
  phase,
24116
24286
  output: nullableString,
24117
24287
  diff: nullableString,
24118
- diffAdded: Type8.Union([num, nil]),
24119
- diffRemoved: Type8.Union([num, nil]),
24120
- diffTruncated: Type8.Optional(bool),
24121
- codemode: Type8.Optional(CodemodeViewSchema)
24122
- });
24123
- var DelegationSchema = Type8.Object({
24288
+ diffAdded: union4([number, nil]),
24289
+ diffRemoved: union4([number, nil]),
24290
+ diffTruncated: opt8(boolean),
24291
+ codemode: opt8(CodemodeViewSchema)
24292
+ }, { open: true });
24293
+ var DelegationSchema = obj8({
24124
24294
  parentId: integer,
24125
- agentId: Type8.Optional(str),
24126
- round: Type8.Optional(integer),
24127
- runnerId: Type8.Optional(integer),
24128
- inputEntryId: Type8.Optional(integer),
24129
- answerEntryId: Type8.Optional(integer),
24130
- roundUsage: Type8.Optional(Type8.Union([usage, nil])),
24295
+ agentId: opt8(text3),
24296
+ round: opt8(integer),
24297
+ runnerId: opt8(integer),
24298
+ inputEntryId: opt8(integer),
24299
+ answerEntryId: opt8(integer),
24300
+ roundUsage: opt8(union4([usage, nil])),
24131
24301
  taskId: integer,
24132
- callId: str,
24302
+ callId: text3,
24133
24303
  childId: integer,
24134
- role: Type8.Enum(["explore", "plan", "coder"]),
24135
- title: str,
24136
- createdAt: num,
24137
- startedAt: Type8.Union([num, nil]),
24138
- endedAt: Type8.Union([num, nil]),
24139
- status: Type8.Enum(["queued", "running", "completed", "failed", "cancelled"]),
24304
+ role: oneOf2(["explore", "plan", "coder"]),
24305
+ title: text3,
24306
+ createdAt: number,
24307
+ startedAt: union4([number, nil]),
24308
+ endedAt: union4([number, nil]),
24309
+ status: oneOf2(["queued", "running", "completed", "failed", "cancelled"]),
24140
24310
  report: nullableString,
24141
- approvalCount: Type8.Optional(integer),
24142
- historyThrough: Type8.Optional(integer),
24143
- historyUsage: Type8.Optional(usage)
24144
- });
24145
- var SubagentSummarySchema = Type8.Object({
24146
- agentId: str,
24311
+ approvalCount: opt8(integer),
24312
+ historyThrough: opt8(integer),
24313
+ historyUsage: opt8(usage)
24314
+ }, { open: true });
24315
+ var SubagentSummarySchema = obj8({
24316
+ agentId: text3,
24147
24317
  parentId: integer,
24148
24318
  childId: integer,
24149
- role: Type8.Enum(["explore", "plan", "coder"]),
24150
- title: str,
24151
- status: Type8.Enum(["idle", "queued", "running"]),
24152
- activeRoundId: Type8.Union([integer, nil]),
24319
+ role: oneOf2(["explore", "plan", "coder"]),
24320
+ title: text3,
24321
+ status: oneOf2(["idle", "queued", "running"]),
24322
+ activeRoundId: union4([integer, nil]),
24153
24323
  lastRoundId: integer,
24154
- lastReport: Type8.Optional(nullableString),
24324
+ lastReport: opt8(nullableString),
24155
24325
  roundCount: integer,
24156
- taskTitle: str,
24326
+ taskTitle: text3,
24157
24327
  approvalCount: integer,
24158
- createdAt: num,
24159
- historyThrough: Type8.Optional(integer),
24160
- historyUsage: Type8.Optional(usage)
24161
- });
24162
- var jobStatus = Type8.Enum(["running", "exited", "failed", "stopped", "lost"]);
24163
- var JobSummarySchema = Type8.Object({
24164
- jobId: str,
24165
- title: str,
24166
- command: str,
24167
- cwd: str,
24328
+ createdAt: number,
24329
+ historyThrough: opt8(integer),
24330
+ historyUsage: opt8(usage)
24331
+ }, { open: true });
24332
+ var jobStatus = oneOf2(["running", "exited", "failed", "stopped", "lost"]);
24333
+ var JobSummarySchema = obj8({
24334
+ jobId: text3,
24335
+ title: text3,
24336
+ command: text3,
24337
+ cwd: text3,
24168
24338
  status: jobStatus,
24169
- startedAt: num,
24170
- endedAt: Type8.Union([num, nil]),
24171
- exitCode: Type8.Union([num, nil]),
24172
- reason: Type8.Optional(Type8.Enum(["timeout", "spawn-error", "restart", "aborted"])),
24173
- timeoutSeconds: Type8.Optional(num),
24339
+ startedAt: number,
24340
+ endedAt: union4([number, nil]),
24341
+ exitCode: union4([number, nil]),
24342
+ reason: opt8(oneOf2(["timeout", "spawn-error", "restart", "aborted"])),
24343
+ timeoutSeconds: opt8(number),
24174
24344
  outputBytes: integer
24175
- });
24176
- var JobOutputSchema = Type8.Object({
24345
+ }, { open: true });
24346
+ var JobOutputSchema = obj8({
24177
24347
  job: JobSummarySchema,
24178
- text: str,
24348
+ text: text3,
24179
24349
  offset: integer,
24180
- truncated: bool,
24350
+ truncated: boolean,
24181
24351
  dropped: integer
24182
- });
24183
- var QueuedInputSchema = Type8.Object({
24352
+ }, { open: true });
24353
+ var QueuedInputSchema = obj8({
24184
24354
  id: integer,
24185
- mode: Type8.Enum(["steer", "followUp"]),
24186
- preview: str,
24355
+ mode: oneOf2(["steer", "followUp"]),
24356
+ preview: text3,
24187
24357
  images: integer,
24188
- skill: Type8.Optional(Type8.Object({ name: str, args: str }))
24189
- });
24190
- var WithdrawResultSchema = Type8.Object({
24191
- result: Type8.Enum(["withdrawn", "placed", "settled", "unknown"]),
24192
- text: Type8.Optional(str),
24193
- images: Type8.Optional(integer)
24358
+ skill: opt8(obj8({ name: text3, args: text3 }, { open: true }))
24359
+ }, { open: true });
24360
+ var WithdrawResultSchema = obj8({
24361
+ result: oneOf2(["withdrawn", "placed", "settled", "unknown"]),
24362
+ text: opt8(text3),
24363
+ images: opt8(integer)
24364
+ }, { open: true });
24365
+ var SteerResultSchema = obj8({
24366
+ result: oneOf2(["steered", "withdrawn", "placed", "settled", "unknown"]),
24367
+ id: opt8(integer),
24368
+ text: opt8(text3),
24369
+ images: opt8(integer)
24370
+ }, { open: true });
24371
+ var TodoItemSchema = obj8({
24372
+ id: str8({ minLength: 1, maxLength: TODO_LIMITS.idChars }),
24373
+ text: str8({ minLength: 1, maxLength: TODO_LIMITS.textChars }),
24374
+ status: oneOf2(["pending", "in_progress", "completed"])
24194
24375
  });
24195
- var SteerResultSchema = Type8.Object({
24196
- result: Type8.Enum(["steered", "withdrawn", "placed", "settled", "unknown"]),
24197
- id: Type8.Optional(integer),
24198
- text: Type8.Optional(str),
24199
- images: Type8.Optional(integer)
24200
- });
24201
- var TodoItemSchema = Type8.Object({
24202
- id: Type8.String({ minLength: 1, maxLength: TODO_LIMITS.idChars }),
24203
- text: Type8.String({ minLength: 1, maxLength: TODO_LIMITS.textChars }),
24204
- status: Type8.Enum(["pending", "in_progress", "completed"])
24205
- }, { additionalProperties: false });
24206
- var TodoListSchema = Type8.Object({
24376
+ var TodoListSchema = obj8({
24207
24377
  revision: integer,
24208
- items: Type8.Array(TodoItemSchema, { maxItems: TODO_LIMITS.maxItems })
24378
+ items: arr6(TodoItemSchema, { maxItems: TODO_LIMITS.maxItems })
24379
+ }, { open: true });
24380
+ var QuestionOptionSchema = obj8({
24381
+ id: str8({ minLength: 1, maxLength: QUESTION_LIMITS.optionIdChars }),
24382
+ label: str8({ minLength: 1, maxLength: QUESTION_LIMITS.labelChars }),
24383
+ description: opt8(str8({ maxLength: QUESTION_LIMITS.descriptionChars })),
24384
+ recommended: opt8(boolean)
24209
24385
  });
24210
- var QuestionOptionSchema = Type8.Object({
24211
- id: Type8.String({ minLength: 1, maxLength: QUESTION_LIMITS.optionIdChars }),
24212
- label: Type8.String({ minLength: 1, maxLength: QUESTION_LIMITS.labelChars }),
24213
- description: Type8.Optional(Type8.String({ maxLength: QUESTION_LIMITS.descriptionChars })),
24214
- recommended: Type8.Optional(bool)
24215
- }, { additionalProperties: false });
24216
- var questionStatus = Type8.Enum(["pending", "answered", "skipped", "cancelled"]);
24217
- var QuestionSummarySchema = Type8.Object({
24386
+ var questionStatus = oneOf2(["pending", "answered", "skipped", "cancelled"]);
24387
+ var QuestionSummarySchema = obj8({
24218
24388
  id: integer,
24219
- version: str,
24220
- preview: Type8.String({ maxLength: QUESTION_LIMITS.previewChars }),
24221
- multiple: bool,
24389
+ version: text3,
24390
+ preview: str8({ maxLength: QUESTION_LIMITS.previewChars }),
24391
+ multiple: boolean,
24222
24392
  optionCount: integer,
24223
- createdAt: num
24224
- });
24225
- var WorkspaceEntrySchema = Type8.Object({
24226
- name: str,
24227
- path: str,
24228
- kind: Type8.Enum(["file", "directory", "symlink"]),
24229
- protected: Type8.Optional(Type8.Literal(true))
24230
- }, { additionalProperties: false });
24231
- var WorkspaceDirSchema = Type8.Object({
24232
- path: str,
24233
- entries: Type8.Array(WorkspaceEntrySchema, { maxItems: 1000 }),
24234
- limited: bool,
24235
- incomplete: bool
24393
+ createdAt: number
24394
+ }, { open: true });
24395
+ var WorkspaceEntrySchema = obj8({
24396
+ name: text3,
24397
+ path: text3,
24398
+ kind: oneOf2(["file", "directory", "symlink"]),
24399
+ protected: opt8(lit3(true))
24236
24400
  });
24237
- var WorkspaceFileSchema = Type8.Object({
24238
- path: str,
24239
- size: num,
24240
- mtimeMs: num,
24241
- kind: Type8.Enum(["text", "binary", "protected"]),
24242
- content: Type8.Optional(str),
24243
- truncated: bool
24244
- });
24245
- var ChangeSummarySchema = Type8.Object({ revision: integer, files: integer, added: integer, removed: integer });
24246
- var ChangedFileSchema = Type8.Object({
24247
- path: str,
24248
- outside: Type8.Optional(Type8.Literal(true)),
24401
+ var WorkspaceDirSchema = obj8({
24402
+ path: text3,
24403
+ entries: arr6(WorkspaceEntrySchema, { maxItems: 1000 }),
24404
+ limited: boolean,
24405
+ incomplete: boolean
24406
+ }, { open: true });
24407
+ var WorkspaceFileSchema = obj8({
24408
+ path: text3,
24409
+ size: number,
24410
+ mtimeMs: number,
24411
+ kind: oneOf2(["text", "binary", "protected"]),
24412
+ content: opt8(text3),
24413
+ truncated: boolean
24414
+ }, { open: true });
24415
+ var ChangeSummarySchema = obj8({ revision: integer, files: integer, added: integer, removed: integer }, { open: true });
24416
+ var ChangedFileSchema = obj8({
24417
+ path: text3,
24418
+ outside: opt8(lit3(true)),
24249
24419
  ops: integer,
24250
24420
  added: integer,
24251
24421
  removed: integer,
24252
- agents: Type8.Array(str, { maxItems: 64 }),
24422
+ agents: arr6(text3, { maxItems: 64 }),
24253
24423
  lastSeq: integer
24254
- }, { additionalProperties: false });
24255
- var ChangeListSchema = Type8.Object({
24256
- revision: integer,
24257
- files: Type8.Array(ChangedFileSchema, { maxItems: 500 }),
24258
- truncated: bool
24259
24424
  });
24260
- var ChangeOpSchema = Type8.Object({
24425
+ var ChangeListSchema = obj8({
24426
+ revision: integer,
24427
+ files: arr6(ChangedFileSchema, { maxItems: 500 }),
24428
+ truncated: boolean
24429
+ }, { open: true });
24430
+ var ChangeOpSchema = obj8({
24261
24431
  seq: integer,
24262
- agent: str,
24263
- tool: Type8.Enum(["edit", "write"]),
24264
- diff: str,
24432
+ agent: text3,
24433
+ tool: oneOf2(["edit", "write"]),
24434
+ diff: text3,
24265
24435
  added: integer,
24266
24436
  removed: integer,
24267
- truncated: bool
24268
- }, { additionalProperties: false });
24269
- var ChangeDetailSchema = Type8.Object({
24270
- path: str,
24271
- outside: Type8.Optional(Type8.Literal(true)),
24272
- ops: Type8.Array(ChangeOpSchema, { maxItems: 50 }),
24273
- truncated: bool
24437
+ truncated: boolean
24274
24438
  });
24275
- var QuestionListSchema = Type8.Object({
24439
+ var ChangeDetailSchema = obj8({
24440
+ path: text3,
24441
+ outside: opt8(lit3(true)),
24442
+ ops: arr6(ChangeOpSchema, { maxItems: 50 }),
24443
+ truncated: boolean
24444
+ }, { open: true });
24445
+ var QuestionListSchema = obj8({
24276
24446
  revision: integer,
24277
- pending: Type8.Array(QuestionSummarySchema, { maxItems: QUESTION_LIMITS.maxPending })
24278
- });
24279
- var QuestionRecordSchema = Type8.Object({
24447
+ pending: arr6(QuestionSummarySchema, { maxItems: QUESTION_LIMITS.maxPending })
24448
+ }, { open: true });
24449
+ var QuestionRecordSchema = obj8({
24280
24450
  id: integer,
24281
- callId: str,
24282
- version: str,
24283
- question: Type8.String({ maxLength: QUESTION_LIMITS.questionChars }),
24284
- multiple: bool,
24285
- options: Type8.Array(QuestionOptionSchema, { maxItems: QUESTION_LIMITS.maxOptions }),
24451
+ callId: text3,
24452
+ version: text3,
24453
+ question: str8({ maxLength: QUESTION_LIMITS.questionChars }),
24454
+ multiple: boolean,
24455
+ options: arr6(QuestionOptionSchema, { maxItems: QUESTION_LIMITS.maxOptions }),
24286
24456
  status: questionStatus,
24287
- answer: Type8.Union([
24288
- Type8.Object({
24289
- optionIds: Type8.Array(Type8.String(), { maxItems: QUESTION_LIMITS.maxOptions }),
24290
- text: Type8.Union([Type8.String({ maxLength: QUESTION_LIMITS.textChars }), nil])
24291
- }),
24457
+ answer: union4([
24458
+ obj8({
24459
+ optionIds: arr6(str8(), { maxItems: QUESTION_LIMITS.maxOptions }),
24460
+ text: union4([str8({ maxLength: QUESTION_LIMITS.textChars }), nil])
24461
+ }, { open: true }),
24292
24462
  nil
24293
24463
  ]),
24294
- createdAt: num,
24295
- settledAt: Type8.Union([num, nil])
24296
- });
24297
- var QuestionResponseSchema = Type8.Union([
24298
- Type8.Object({
24299
- kind: Type8.Literal("answer"),
24300
- optionIds: Type8.Optional(Type8.Array(Type8.String(), { maxItems: QUESTION_LIMITS.maxOptions })),
24301
- text: Type8.Optional(Type8.String({ maxLength: QUESTION_LIMITS.textChars }))
24302
- }, { additionalProperties: false }),
24303
- Type8.Object({ kind: Type8.Literal("skip") }, { additionalProperties: false })
24464
+ createdAt: number,
24465
+ settledAt: union4([number, nil])
24466
+ }, { open: true });
24467
+ var QuestionResponseSchema = union4([
24468
+ obj8({
24469
+ kind: lit3("answer"),
24470
+ optionIds: opt8(arr6(str8(), { maxItems: QUESTION_LIMITS.maxOptions })),
24471
+ text: opt8(str8({ maxLength: QUESTION_LIMITS.textChars }))
24472
+ }),
24473
+ obj8({ kind: lit3("skip") })
24304
24474
  ]);
24305
- var PlanRecordSchema = Type8.Object({
24306
- version: str,
24307
- title: Type8.String({ maxLength: PLAN_LIMITS.titleChars }),
24308
- steps: Type8.Array(Type8.String({ maxLength: PLAN_LIMITS.stepChars }), { maxItems: PLAN_LIMITS.maxSteps }),
24309
- note: Type8.String({ maxLength: PLAN_LIMITS.noteChars }),
24310
- status: Type8.Enum(["awaiting_approval", "approved", "revision_requested", "superseded", "cancelled"]),
24311
- feedback: Type8.Union([Type8.String({ maxLength: PLAN_LIMITS.feedbackChars }), nil]),
24312
- createdAt: num,
24313
- settledAt: Type8.Union([num, nil])
24314
- });
24315
- var PlanViewSchema = Type8.Object({
24316
- mode: Type8.Enum(["normal", "plan"]),
24475
+ var PlanRecordSchema = obj8({
24476
+ version: text3,
24477
+ title: str8({ maxLength: PLAN_LIMITS.titleChars }),
24478
+ steps: arr6(str8({ maxLength: PLAN_LIMITS.stepChars }), { maxItems: PLAN_LIMITS.maxSteps }),
24479
+ note: str8({ maxLength: PLAN_LIMITS.noteChars }),
24480
+ status: oneOf2(["awaiting_approval", "approved", "revision_requested", "superseded", "cancelled"]),
24481
+ feedback: union4([str8({ maxLength: PLAN_LIMITS.feedbackChars }), nil]),
24482
+ createdAt: number,
24483
+ settledAt: union4([number, nil])
24484
+ }, { open: true });
24485
+ var PlanViewSchema = obj8({
24486
+ mode: oneOf2(["normal", "plan"]),
24317
24487
  revision: integer,
24318
- current: Type8.Union([PlanRecordSchema, nil])
24319
- });
24320
- var PlanDecisionSchema = Type8.Union([
24321
- Type8.Object({ kind: Type8.Literal("approve") }, { additionalProperties: false }),
24322
- Type8.Object({ kind: Type8.Literal("revise"), feedback: Type8.String({ minLength: 1, maxLength: PLAN_LIMITS.feedbackChars }) }, { additionalProperties: false })
24488
+ current: union4([PlanRecordSchema, nil])
24489
+ }, { open: true });
24490
+ var PlanDecisionSchema = union4([
24491
+ obj8({ kind: lit3("approve") }),
24492
+ obj8({ kind: lit3("revise"), feedback: str8({ minLength: 1, maxLength: PLAN_LIMITS.feedbackChars }) })
24323
24493
  ]);
24324
- var ToolInteractionSchema = Type8.Union([
24325
- Type8.Object({
24326
- kind: Type8.Literal("ask_user"),
24494
+ var ToolInteractionSchema = union4([
24495
+ obj8({
24496
+ kind: lit3("ask_user"),
24327
24497
  id: integer,
24328
- question: str,
24329
- multiple: bool,
24330
- options: Type8.Array(Type8.Object({ id: str, label: str, recommended: Type8.Optional(bool) })),
24498
+ question: text3,
24499
+ multiple: boolean,
24500
+ options: arr6(obj8({ id: text3, label: text3, recommended: opt8(boolean) }, { open: true })),
24331
24501
  status: questionStatus,
24332
- optionIds: Type8.Optional(Type8.Array(str)),
24333
- labels: Type8.Optional(Type8.Array(str)),
24334
- text: Type8.Optional(Type8.Union([str, nil]))
24335
- }),
24336
- Type8.Object({
24337
- kind: Type8.Literal("todo"),
24338
- action: Type8.Enum(["list", "replace"]),
24502
+ optionIds: opt8(arr6(text3)),
24503
+ labels: opt8(arr6(text3)),
24504
+ text: opt8(union4([text3, nil]))
24505
+ }, { open: true }),
24506
+ obj8({
24507
+ kind: lit3("todo"),
24508
+ action: oneOf2(["list", "replace"]),
24339
24509
  revision: integer,
24340
24510
  completed: integer,
24341
24511
  total: integer
24342
- }),
24343
- Type8.Object({
24344
- kind: Type8.Literal("submit_plan"),
24345
- version: str,
24346
- title: str,
24347
- steps: Type8.Array(str),
24348
- note: str
24349
- })
24512
+ }, { open: true }),
24513
+ obj8({
24514
+ kind: lit3("submit_plan"),
24515
+ version: text3,
24516
+ title: text3,
24517
+ steps: arr6(text3),
24518
+ note: text3
24519
+ }, { open: true })
24350
24520
  ]);
24351
- var ChatViewSchema = Type8.Object({
24352
- historyBefore: Type8.Optional(Type8.Union([integer, nil])),
24353
- agents: Type8.Optional(Type8.Array(SubagentSummarySchema)),
24354
- jobs: Type8.Optional(Type8.Array(JobSummarySchema)),
24355
- queued: Type8.Optional(Type8.Array(QueuedInputSchema)),
24356
- todos: Type8.Optional(TodoListSchema),
24357
- questions: Type8.Optional(QuestionListSchema),
24358
- plan: Type8.Optional(PlanViewSchema),
24359
- changes: Type8.Optional(ChangeSummarySchema),
24360
- rounds: Type8.Optional(Type8.Array(DelegationSchema)),
24361
- subagents: Type8.Optional(Type8.Array(DelegationSchema)),
24362
- taskUsage: Type8.Optional(usage),
24363
- model: str,
24364
- agent: Type8.Object({ model: Type8.Union([model2, nil]), thinkingLevel: Type8.Union([thinking, nil]) }),
24365
- cwd: str,
24366
- busy: bool,
24521
+ var ChatViewSchema = obj8({
24522
+ historyBefore: opt8(union4([integer, nil])),
24523
+ agents: opt8(arr6(SubagentSummarySchema)),
24524
+ jobs: opt8(arr6(JobSummarySchema)),
24525
+ queued: opt8(arr6(QueuedInputSchema)),
24526
+ todos: opt8(TodoListSchema),
24527
+ questions: opt8(QuestionListSchema),
24528
+ plan: opt8(PlanViewSchema),
24529
+ changes: opt8(ChangeSummarySchema),
24530
+ rounds: opt8(arr6(DelegationSchema)),
24531
+ subagents: opt8(arr6(DelegationSchema)),
24532
+ taskUsage: opt8(usage),
24533
+ model: text3,
24534
+ agent: obj8({ model: union4([model2, nil]), thinkingLevel: union4([thinking, nil]) }, { open: true }),
24535
+ cwd: text3,
24536
+ busy: boolean,
24367
24537
  status: nullableString,
24368
24538
  usage,
24369
- contextUsage: Type8.Optional(Type8.Object({ tokens: Type8.Union([num, nil]), window: num, percent: Type8.Union([num, nil]) })),
24370
- compaction: Type8.Optional(Type8.Object({
24371
- failure: Type8.Optional(Type8.Object({ taskId: integer, reason: Type8.Enum(["manual", "threshold", "overflow"]), error: str })),
24372
- active: Type8.Array(Type8.Object({
24539
+ contextUsage: opt8(obj8({ tokens: union4([number, nil]), window: number, percent: union4([number, nil]) }, { open: true })),
24540
+ compaction: opt8(obj8({
24541
+ failure: opt8(obj8({ taskId: integer, reason: oneOf2(["manual", "threshold", "overflow"]), error: text3 }, { open: true })),
24542
+ active: arr6(obj8({
24373
24543
  taskId: integer,
24374
- reason: Type8.Enum(["manual", "threshold", "overflow"]),
24375
- blocking: bool,
24544
+ reason: oneOf2(["manual", "threshold", "overflow"]),
24545
+ blocking: boolean,
24376
24546
  attempt: integer,
24377
- retry: Type8.Optional(Type8.Object({ at: num, error: str }))
24378
- })),
24379
- latest: Type8.Union([
24547
+ retry: opt8(obj8({ at: number, error: text3 }, { open: true }))
24548
+ }, { open: true })),
24549
+ latest: union4([
24380
24550
  nil,
24381
- Type8.Object({
24551
+ obj8({
24382
24552
  taskId: integer,
24383
- phase: Type8.Enum(["summarizing", "waiting-to-apply", "applied", "nothing", "skipped", "cancelled", "failed"]),
24384
- at: num
24385
- })
24553
+ phase: oneOf2([
24554
+ "summarizing",
24555
+ "waiting-to-apply",
24556
+ "applied",
24557
+ "nothing",
24558
+ "skipped",
24559
+ "cancelled",
24560
+ "failed"
24561
+ ]),
24562
+ at: number
24563
+ }, { open: true })
24386
24564
  ])
24387
- })),
24388
- items: Type8.Array(Type8.Union([
24389
- Type8.Object({
24390
- type: Type8.Literal("user"),
24391
- order: Type8.Optional(num),
24392
- key: str,
24565
+ }, { open: true })),
24566
+ runFailure: opt8(obj8({ reason: text3, detail: opt8(text3) }, { open: true })),
24567
+ continuable: opt8(lit3(true)),
24568
+ items: arr6(union4([
24569
+ obj8({
24570
+ type: lit3("user"),
24571
+ order: opt8(number),
24572
+ key: text3,
24393
24573
  id: integer,
24394
- text: str,
24395
- images: Type8.Optional(Type8.Array(image)),
24396
- skill: Type8.Optional(skill),
24397
- defaultImagePrompt: Type8.Optional(Type8.Object({ version: Type8.Integer({ minimum: 1 }), text: str }))
24398
- }),
24399
- Type8.Object({
24400
- type: Type8.Literal("assistant"),
24401
- order: Type8.Optional(num),
24402
- key: str,
24574
+ text: text3,
24575
+ images: opt8(arr6(image)),
24576
+ skill: opt8(skill),
24577
+ defaultImagePrompt: opt8(obj8({ version: int5({ minimum: 1 }), text: text3 }, { open: true }))
24578
+ }, { open: true }),
24579
+ obj8({
24580
+ type: lit3("assistant"),
24581
+ order: opt8(number),
24582
+ key: text3,
24403
24583
  id: integer,
24404
- thinking: str,
24405
- text: str,
24584
+ thinking: text3,
24585
+ text: text3,
24406
24586
  stopReason: nullableString,
24407
24587
  errorMessage: nullableString,
24408
24588
  note: nullableString
24409
- }),
24410
- Type8.Object({
24411
- type: Type8.Literal("tool"),
24412
- order: Type8.Optional(num),
24413
- key: str,
24414
- images: Type8.Optional(Type8.Array(image)),
24415
- callId: str,
24416
- name: str,
24417
- summary: str,
24589
+ }, { open: true }),
24590
+ obj8({
24591
+ type: lit3("tool"),
24592
+ order: opt8(number),
24593
+ key: text3,
24594
+ images: opt8(arr6(image)),
24595
+ callId: text3,
24596
+ name: text3,
24597
+ summary: text3,
24418
24598
  detail: nullableString,
24419
24599
  phase,
24420
- isError: bool,
24600
+ isError: boolean,
24421
24601
  output: nullableString,
24422
24602
  result: nullableString,
24423
- durationMs: Type8.Union([num, nil]),
24603
+ durationMs: union4([number, nil]),
24424
24604
  note: nullableString,
24425
24605
  diff: nullableString,
24426
- diffAdded: Type8.Union([num, nil]),
24427
- diffRemoved: Type8.Union([num, nil]),
24428
- diffTruncated: Type8.Optional(bool),
24429
- interaction: Type8.Optional(ToolInteractionSchema),
24430
- codemode: Type8.Optional(CodemodeViewSchema)
24431
- }),
24432
- Type8.Object({
24433
- type: Type8.Literal("system"),
24434
- order: Type8.Optional(num),
24435
- key: str,
24606
+ diffAdded: union4([number, nil]),
24607
+ diffRemoved: union4([number, nil]),
24608
+ diffTruncated: opt8(boolean),
24609
+ interaction: opt8(ToolInteractionSchema),
24610
+ codemode: opt8(CodemodeViewSchema)
24611
+ }, { open: true }),
24612
+ obj8({
24613
+ type: lit3("system"),
24614
+ order: opt8(number),
24615
+ key: text3,
24436
24616
  id: integer,
24437
- text: str,
24438
- jobId: Type8.Optional(str),
24439
- planDecision: Type8.Optional(Type8.Object({ version: str, kind: Type8.Enum(["approve", "revise"]) }, { additionalProperties: false }))
24440
- })
24617
+ text: text3,
24618
+ jobId: opt8(text3),
24619
+ planDecision: opt8(obj8({ version: text3, kind: oneOf2(["approve", "revise"]) }))
24620
+ }, { open: true })
24441
24621
  ])),
24442
- streaming: Type8.Union([nil, Type8.Object({ thinking: str, text: str, toolCalls: Type8.Array(call) })])
24443
- });
24444
- var SessionSummarySchema = Type8.Object({
24445
- workspaceRoot: str,
24446
- lastUsedAt: num,
24447
- title: str,
24448
- firstPromptPreview: str,
24449
- createdAt: num,
24450
- lastMessageAt: Type8.Union([num, nil]),
24451
- model: Type8.Union([model2, nil]),
24452
- status: Type8.Enum(["idle", "running", "error"]),
24453
- awaitingAnswer: Type8.Optional(bool),
24454
- awaitingPlan: Type8.Optional(bool),
24455
- id: str
24456
- });
24457
- var DirectoryStateSchema = Type8.Object({ revision: integer, sessions: Type8.Array(SessionSummarySchema) });
24458
- var WorkspaceSummarySchema = Type8.Object({ path: str, createdAt: num });
24459
- var WorkspaceStateSchema = Type8.Object({ revision: integer, workspaces: Type8.Array(WorkspaceSummarySchema) });
24460
- var credentialStatus = Type8.Object({
24461
- savedConfigured: bool,
24462
- environmentConfigured: bool,
24463
- source: Type8.Enum(["saved", "environment", "runtime", "keyless", "none"]),
24464
- enabled: Type8.Optional(bool)
24465
- });
24466
- var CredentialStateSchema = Type8.Object({
24622
+ streaming: union4([nil, obj8({ thinking: text3, text: text3, toolCalls: arr6(call) }, { open: true })])
24623
+ }, { open: true });
24624
+ var SessionSummarySchema = obj8({
24625
+ workspaceRoot: text3,
24626
+ lastUsedAt: number,
24627
+ title: text3,
24628
+ firstPromptPreview: text3,
24629
+ createdAt: number,
24630
+ lastMessageAt: union4([number, nil]),
24631
+ model: union4([model2, nil]),
24632
+ status: oneOf2(["idle", "running", "error"]),
24633
+ awaitingAnswer: opt8(boolean),
24634
+ awaitingPlan: opt8(boolean),
24635
+ id: text3
24636
+ }, { open: true });
24637
+ var DirectoryStateSchema = obj8({ revision: integer, sessions: arr6(SessionSummarySchema) }, { open: true });
24638
+ var WorkspaceSummarySchema = obj8({ path: text3, createdAt: number }, { open: true });
24639
+ var WorkspaceStateSchema = obj8({ revision: integer, workspaces: arr6(WorkspaceSummarySchema) }, { open: true });
24640
+ var credentialStatus = obj8({
24641
+ savedConfigured: boolean,
24642
+ environmentConfigured: boolean,
24643
+ source: oneOf2(["saved", "environment", "runtime", "keyless", "none"]),
24644
+ enabled: opt8(boolean)
24645
+ }, { open: true });
24646
+ var CredentialStateSchema = obj8({
24467
24647
  revision: integer,
24468
- statuses: Type8.Record(str, credentialStatus)
24469
- });
24470
- var AttachmentSchema = Type8.Object({ sessionId: str, attachmentId: str });
24471
- var chatInput = Type8.Object({ sessionId: str, attachmentId: str }, { additionalProperties: false });
24648
+ statuses: map(credentialStatus)
24649
+ }, { open: true });
24650
+ var AttachmentSchema = obj8({ sessionId: text3, attachmentId: text3 }, { open: true });
24651
+ var chatInput = obj8({ sessionId: text3, attachmentId: text3 });
24472
24652
  var NekoSessionDirectory = contract("neko.session-directory", {
24473
24653
  version: 1,
24474
- input: Type8.Object({}, { additionalProperties: false }),
24654
+ input: obj8({}),
24475
24655
  variants: { ready: { state: { state: DirectoryStateSchema } } }
24476
24656
  });
24477
24657
  var NekoSessionManagement = contract("neko.session-management", {
24478
24658
  version: 1,
24479
- input: Type8.Object({}, { additionalProperties: false }),
24659
+ input: obj8({}),
24480
24660
  variants: {
24481
24661
  ready: {
24482
24662
  methods: {
24483
- create: rpc(Type8.Object({ ...change.properties, cwd: Type8.Optional(str) }, { additionalProperties: false }), SessionSummarySchema),
24484
- archive: rpc(str, nil),
24485
- attach: rpc(str, AttachmentSchema),
24663
+ create: rpc(obj8({ ...changeProperties, cwd: opt8(text3) }), SessionSummarySchema),
24664
+ archive: rpc(text3, nil),
24665
+ attach: rpc(text3, AttachmentSchema),
24486
24666
  detach: rpc(nil, nil),
24487
- fork: rpc(str, SessionSummarySchema)
24667
+ fork: rpc(text3, SessionSummarySchema)
24488
24668
  }
24489
24669
  }
24490
24670
  }
24491
24671
  });
24492
- var resize = Type8.Object({
24493
- maxWidth: Type8.Optional(integer),
24494
- maxHeight: Type8.Optional(integer),
24495
- maxBytes: Type8.Optional(integer),
24496
- jpegQuality: Type8.Optional(integer)
24497
- });
24498
- var inputLimits = Type8.Object({
24499
- maxRequestBytes: Type8.Optional(integer),
24500
- images: Type8.Optional(Type8.Object({
24501
- resize: Type8.Optional(resize),
24502
- maxPerMessage: Type8.Optional(integer),
24503
- maxPerRequest: Type8.Optional(integer)
24504
- }))
24505
- });
24506
- var modelInfo = Type8.Object({
24507
- provider: str,
24508
- modelId: str,
24509
- name: str,
24510
- available: bool,
24511
- contextWindow: num,
24512
- input: Type8.Array(str),
24513
- inputLimits: Type8.Optional(inputLimits),
24514
- reasoning: bool,
24515
- supportedThinkingLevels: Type8.Array(thinking),
24516
- thinkingLevelAdjustments: Type8.Object({
24672
+ var resize = obj8({
24673
+ maxWidth: opt8(integer),
24674
+ maxHeight: opt8(integer),
24675
+ maxBytes: opt8(integer),
24676
+ jpegQuality: opt8(integer)
24677
+ }, { open: true });
24678
+ var inputLimits = obj8({
24679
+ maxRequestBytes: opt8(integer),
24680
+ images: opt8(obj8({
24681
+ resize: opt8(resize),
24682
+ maxPerMessage: opt8(integer),
24683
+ maxPerRequest: opt8(integer)
24684
+ }, { open: true }))
24685
+ }, { open: true });
24686
+ var modelInfo = obj8({
24687
+ provider: text3,
24688
+ modelId: text3,
24689
+ name: text3,
24690
+ available: boolean,
24691
+ contextWindow: number,
24692
+ input: arr6(text3),
24693
+ inputLimits: opt8(inputLimits),
24694
+ reasoning: boolean,
24695
+ supportedThinkingLevels: arr6(thinking),
24696
+ thinkingLevelAdjustments: obj8({
24517
24697
  off: thinking,
24518
24698
  minimal: thinking,
24519
24699
  low: thinking,
@@ -24521,35 +24701,35 @@ var modelInfo = Type8.Object({
24521
24701
  high: thinking,
24522
24702
  xhigh: thinking,
24523
24703
  max: thinking
24524
- })
24525
- });
24704
+ }, { open: true })
24705
+ }, { open: true });
24526
24706
  var NekoModels = contract("neko.models", {
24527
24707
  version: 1,
24528
- input: Type8.Object({}, { additionalProperties: false }),
24529
- variants: { ready: { methods: { list: rpc(nil, Type8.Array(modelInfo)) } } }
24708
+ input: obj8({}),
24709
+ variants: { ready: { methods: { list: rpc(nil, arr6(modelInfo)) } } }
24530
24710
  });
24531
- var imageChunk = Type8.Object({ data: str, total: integer, mimeType: str });
24711
+ var imageChunk = obj8({ data: text3, total: integer, mimeType: text3 }, { open: true });
24532
24712
  var NekoSubagent = contract("neko.subagent", {
24533
24713
  version: 1,
24534
- input: Type8.Object({
24535
- sessionId: str,
24536
- attachmentId: str,
24537
- taskId: Type8.Optional(integer),
24538
- agentId: Type8.Optional(str)
24539
- }),
24714
+ input: obj8({
24715
+ sessionId: text3,
24716
+ attachmentId: text3,
24717
+ taskId: opt8(integer),
24718
+ agentId: opt8(text3)
24719
+ }, { open: true }),
24540
24720
  variants: {
24541
24721
  ready: {
24542
24722
  state: { revision: integer },
24543
24723
  methods: {
24544
- chunk: rpc(Type8.Object({
24545
- kind: Type8.Enum(["view", "history"]),
24546
- before: Type8.Optional(integer),
24547
- token: Type8.Optional(integer),
24724
+ chunk: rpc(obj8({
24725
+ kind: oneOf2(["view", "history"]),
24726
+ before: opt8(integer),
24727
+ token: opt8(integer),
24548
24728
  offset: integer
24549
- }), Type8.Object({ token: integer, data: str, next: Type8.Union([integer, nil]) })),
24550
- getImage: rpc(Type8.Object({ entryId: integer, contentIndex: integer, offset: integer }), imageChunk),
24551
- decideApproval: rpc(Type8.Object({ id: integer, version: str, decision: Type8.Enum(["allowed", "denied"]) }), Type8.Enum(["pending", "allowed", "denied", "cancelled"])),
24552
- stop: rpc(Type8.Union([nil, Type8.Object({ taskId: integer })]), nil)
24729
+ }, { open: true }), obj8({ token: integer, data: text3, next: union4([integer, nil]) }, { open: true })),
24730
+ getImage: rpc(obj8({ entryId: integer, contentIndex: integer, offset: integer }, { open: true }), imageChunk),
24731
+ decideApproval: rpc(obj8({ id: integer, version: text3, decision: oneOf2(["allowed", "denied"]) }, { open: true }), oneOf2(["pending", "allowed", "denied", "cancelled"])),
24732
+ stop: rpc(union4([nil, obj8({ taskId: integer }, { open: true })]), nil)
24553
24733
  }
24554
24734
  }
24555
24735
  }
@@ -24561,175 +24741,176 @@ var NekoChat = contract("neko.chat", {
24561
24741
  ready: {
24562
24742
  state: { view: ChatViewSchema },
24563
24743
  methods: {
24564
- submit: rpc(Type8.Object({
24565
- content: str,
24566
- images: Type8.Optional(Type8.Array(str, { maxItems: 4 })),
24567
- requestId: Type8.Optional(str),
24568
- whenBusy: Type8.Optional(Type8.Enum(["steer", "followUp"]))
24569
- }, { additionalProperties: false }), nil),
24744
+ submit: rpc(obj8({
24745
+ content: text3,
24746
+ images: opt8(arr6(text3, { maxItems: 4 })),
24747
+ requestId: opt8(text3),
24748
+ whenBusy: opt8(oneOf2(["steer", "followUp"]))
24749
+ }), nil),
24570
24750
  abort: rpc(nil, nil),
24571
- withdraw: rpc(Type8.Object({ id: integer }, { additionalProperties: false }), WithdrawResultSchema),
24572
- steer: rpc(Type8.Object({ id: integer }, { additionalProperties: false }), SteerResultSchema),
24573
- questionGet: rpc(Type8.Object({ id: integer }, { additionalProperties: false }), Type8.Union([QuestionRecordSchema, nil])),
24574
- questionRespond: rpc(Type8.Object({ id: integer, version: str, response: QuestionResponseSchema }, { additionalProperties: false }), QuestionRecordSchema),
24575
- planGet: rpc(Type8.Object({ version: str }, { additionalProperties: false }), Type8.Union([PlanRecordSchema, nil])),
24576
- planRespond: rpc(Type8.Object({ version: str, decision: PlanDecisionSchema }, { additionalProperties: false }), PlanRecordSchema),
24577
- planMode: rpc(Type8.Object({ mode: Type8.Enum(["normal", "plan"]) }, { additionalProperties: false }), PlanViewSchema),
24751
+ continueRun: rpc(nil, nil),
24752
+ withdraw: rpc(obj8({ id: integer }), WithdrawResultSchema),
24753
+ steer: rpc(obj8({ id: integer }), SteerResultSchema),
24754
+ questionGet: rpc(obj8({ id: integer }), union4([QuestionRecordSchema, nil])),
24755
+ questionRespond: rpc(obj8({ id: integer, version: text3, response: QuestionResponseSchema }), QuestionRecordSchema),
24756
+ planGet: rpc(obj8({ version: text3 }), union4([PlanRecordSchema, nil])),
24757
+ planRespond: rpc(obj8({ version: text3, decision: PlanDecisionSchema }), PlanRecordSchema),
24758
+ planMode: rpc(obj8({ mode: oneOf2(["normal", "plan"]) }), PlanViewSchema),
24578
24759
  usage: rpc(nil, usage),
24579
- workspaceDir: rpc(Type8.Object({ path: str }, { additionalProperties: false }), WorkspaceDirSchema),
24580
- workspaceFile: rpc(Type8.Object({ path: str }, { additionalProperties: false }), WorkspaceFileSchema),
24760
+ workspaceDir: rpc(obj8({ path: text3 }), WorkspaceDirSchema),
24761
+ workspaceFile: rpc(obj8({ path: text3 }), WorkspaceFileSchema),
24581
24762
  changesList: rpc(nil, ChangeListSchema),
24582
- changeGet: rpc(Type8.Object({ path: str }, { additionalProperties: false }), Type8.Union([ChangeDetailSchema, nil])),
24583
- skills: rpc(nil, Type8.Array(Type8.Object({ name: str, description: str, location: str, level }))),
24584
- jobOutput: rpc(Type8.Object({ jobId: str, since: Type8.Optional(integer) }, { additionalProperties: false }), JobOutputSchema),
24585
- jobStop: rpc(Type8.Object({ jobId: str }, { additionalProperties: false }), JobSummarySchema),
24763
+ changeGet: rpc(obj8({ path: text3 }), union4([ChangeDetailSchema, nil])),
24764
+ skills: rpc(nil, arr6(obj8({ name: text3, description: text3, location: text3, level }, { open: true }))),
24765
+ jobOutput: rpc(obj8({ jobId: text3, since: opt8(integer) }), JobOutputSchema),
24766
+ jobStop: rpc(obj8({ jobId: text3 }), JobSummarySchema),
24586
24767
  configure: rpc(change, nil),
24587
- compact: rpc(Type8.Object({ instructions: Type8.Optional(str) }, { additionalProperties: false }), nil),
24588
- importImage: rpc(str, Type8.Object({ id: str, name: str })),
24589
- draftImage: rpc(Type8.Object({ id: str, offset: integer }, { additionalProperties: false }), imageChunk),
24590
- beginImage: rpc(Type8.Object({ name: str, mimeType: str, size: Type8.Integer({ minimum: 1, maximum: 20971520 }) }, { additionalProperties: false }), str),
24591
- appendImage: rpc(Type8.Object({ id: str, offset: integer, data: Type8.String({ maxLength: 350000 }) }, { additionalProperties: false }), nil),
24592
- finishImage: rpc(str, nil),
24593
- releaseImage: rpc(str, nil),
24594
- getImage: rpc(Type8.Object({ entryId: integer, contentIndex: integer, offset: integer }, { additionalProperties: false }), imageChunk)
24768
+ compact: rpc(obj8({ instructions: opt8(text3) }), nil),
24769
+ importImage: rpc(text3, obj8({ id: text3, name: text3 }, { open: true })),
24770
+ draftImage: rpc(obj8({ id: text3, offset: integer }), imageChunk),
24771
+ beginImage: rpc(obj8({ name: text3, mimeType: text3, size: int5({ minimum: 1, maximum: 20971520 }) }), text3),
24772
+ appendImage: rpc(obj8({ id: text3, offset: integer, data: str8({ maxLength: 350000 }) }), nil),
24773
+ finishImage: rpc(text3, nil),
24774
+ releaseImage: rpc(text3, nil),
24775
+ getImage: rpc(obj8({ entryId: integer, contentIndex: integer, offset: integer }), imageChunk)
24595
24776
  }
24596
24777
  }
24597
24778
  }
24598
24779
  });
24599
- var browse = Type8.Object({ path: str, query: Type8.Optional(str), showHidden: Type8.Optional(bool), cursor: Type8.Optional(str) }, { additionalProperties: false });
24600
- var page = Type8.Object({
24601
- path: str,
24780
+ var browse = obj8({ path: text3, query: opt8(text3), showHidden: opt8(boolean), cursor: opt8(text3) });
24781
+ var page = obj8({
24782
+ path: text3,
24602
24783
  parent: nullableString,
24603
- entries: Type8.Array(Type8.Object({ name: str, path: str, error: Type8.Optional(str) })),
24784
+ entries: arr6(obj8({ name: text3, path: text3, error: opt8(text3) }, { open: true })),
24604
24785
  next: nullableString
24605
- });
24786
+ }, { open: true });
24606
24787
  var NekoWorkspaces = contract("neko.workspaces", {
24607
24788
  version: 2,
24608
- input: Type8.Object({}, { additionalProperties: false }),
24789
+ input: obj8({}),
24609
24790
  variants: {
24610
24791
  ready: {
24611
24792
  state: { state: WorkspaceStateSchema },
24612
24793
  methods: {
24613
- add: rpc(Type8.Object({ path: str }, { additionalProperties: false }), WorkspaceSummarySchema),
24614
- remove: rpc(Type8.Object({ path: str }, { additionalProperties: false }), Type8.Null()),
24794
+ add: rpc(obj8({ path: text3 }), WorkspaceSummarySchema),
24795
+ remove: rpc(obj8({ path: text3 }), nul3()),
24615
24796
  browse: rpc(browse, page)
24616
24797
  }
24617
24798
  }
24618
24799
  }
24619
24800
  });
24620
- var provider = Type8.String({ minLength: 1, maxLength: 64 });
24801
+ var provider = str8({ minLength: 1, maxLength: 64 });
24621
24802
  var NekoCredentials = contract("neko.credentials", {
24622
24803
  version: 2,
24623
- input: Type8.Object({}, { additionalProperties: false }),
24804
+ input: obj8({}),
24624
24805
  variants: {
24625
24806
  ready: {
24626
24807
  state: { state: CredentialStateSchema },
24627
24808
  methods: {
24628
- save: rpc(Type8.Object({ provider, key: Type8.String({ minLength: 1, maxLength: 8192 }) }, { additionalProperties: false }), nil),
24629
- remove: rpc(Type8.Object({ provider }, { additionalProperties: false }), nil),
24630
- setEnabled: rpc(Type8.Object({ provider, enabled: bool }, { additionalProperties: false }), nil)
24809
+ save: rpc(obj8({ provider, key: str8({ minLength: 1, maxLength: 8192 }) }), nil),
24810
+ remove: rpc(obj8({ provider }), nil),
24811
+ setEnabled: rpc(obj8({ provider, enabled: boolean }), nil)
24631
24812
  }
24632
24813
  }
24633
24814
  }
24634
24815
  });
24635
- var SearchSettingsStateSchema = Type8.Object({
24816
+ var SearchSettingsStateSchema = obj8({
24636
24817
  revision: integer,
24637
- selected: Type8.Enum(["tavily", "deepseek"])
24638
- });
24818
+ selected: oneOf2(["tavily", "deepseek"])
24819
+ }, { open: true });
24639
24820
  var NekoSearchSettings = contract("neko.search-settings", {
24640
24821
  version: 1,
24641
- input: Type8.Object({}, { additionalProperties: false }),
24822
+ input: obj8({}),
24642
24823
  variants: {
24643
24824
  ready: {
24644
24825
  state: { state: SearchSettingsStateSchema },
24645
24826
  methods: {
24646
- set: rpc(Type8.Object({ provider: Type8.Enum(["tavily", "deepseek"]) }, { additionalProperties: false }), nil)
24827
+ set: rpc(obj8({ provider: oneOf2(["tavily", "deepseek"]) }), nil)
24647
24828
  }
24648
24829
  }
24649
24830
  }
24650
24831
  });
24651
- var contextSource = Type8.Enum(["default", "config", "saved"]);
24652
- var ContextSettingsStateSchema = Type8.Object({
24832
+ var contextSource = oneOf2(["default", "config", "saved"]);
24833
+ var ContextSettingsStateSchema = obj8({
24653
24834
  revision: integer,
24654
- effective: Type8.Object({
24655
- compaction: Type8.Object({
24656
- enabled: bool,
24657
- triggerPercent: Type8.Union([integer, nil]),
24835
+ effective: obj8({
24836
+ compaction: obj8({
24837
+ enabled: boolean,
24838
+ triggerPercent: union4([integer, nil]),
24658
24839
  keepRecentTokens: integer
24659
- }),
24660
- pruning: Type8.Object({
24661
- enabled: bool,
24840
+ }, { open: true }),
24841
+ pruning: obj8({
24842
+ enabled: boolean,
24662
24843
  triggerPercent: integer,
24663
24844
  keepRecent: integer,
24664
24845
  minChars: integer,
24665
24846
  minSavePercent: integer
24666
- })
24667
- }),
24668
- sources: Type8.Object({
24669
- compaction: Type8.Object({ enabled: contextSource, triggerPercent: contextSource, keepRecentTokens: contextSource }),
24670
- pruning: Type8.Object({
24847
+ }, { open: true })
24848
+ }, { open: true }),
24849
+ sources: obj8({
24850
+ compaction: obj8({ enabled: contextSource, triggerPercent: contextSource, keepRecentTokens: contextSource }, { open: true }),
24851
+ pruning: obj8({
24671
24852
  enabled: contextSource,
24672
24853
  triggerPercent: contextSource,
24673
24854
  keepRecent: contextSource,
24674
24855
  minChars: contextSource,
24675
24856
  minSavePercent: contextSource
24676
- })
24677
- })
24857
+ }, { open: true })
24858
+ }, { open: true })
24859
+ }, { open: true });
24860
+ var nullable = (schema) => union4([schema, nil]);
24861
+ var ContextSettingsPatchSchema = obj8({
24862
+ compaction: opt8(obj8({
24863
+ enabled: opt8(nullable(boolean)),
24864
+ triggerPercent: opt8(nullable(integer)),
24865
+ keepRecentTokens: opt8(nullable(integer))
24866
+ })),
24867
+ pruning: opt8(obj8({
24868
+ enabled: opt8(nullable(boolean)),
24869
+ triggerPercent: opt8(nullable(integer)),
24870
+ keepRecent: opt8(nullable(integer)),
24871
+ minChars: opt8(nullable(integer)),
24872
+ minSavePercent: opt8(nullable(integer))
24873
+ }))
24678
24874
  });
24679
- var nullable = (schema) => Type8.Union([schema, nil]);
24680
- var ContextSettingsPatchSchema = Type8.Object({
24681
- compaction: Type8.Optional(Type8.Object({
24682
- enabled: Type8.Optional(nullable(bool)),
24683
- triggerPercent: Type8.Optional(nullable(integer)),
24684
- keepRecentTokens: Type8.Optional(nullable(integer))
24685
- }, { additionalProperties: false })),
24686
- pruning: Type8.Optional(Type8.Object({
24687
- enabled: Type8.Optional(nullable(bool)),
24688
- triggerPercent: Type8.Optional(nullable(integer)),
24689
- keepRecent: Type8.Optional(nullable(integer)),
24690
- minChars: Type8.Optional(nullable(integer)),
24691
- minSavePercent: Type8.Optional(nullable(integer))
24692
- }, { additionalProperties: false }))
24693
- }, { additionalProperties: false });
24694
24875
  var NekoContextSettings = contract("neko.context-settings", {
24695
24876
  version: 1,
24696
- input: Type8.Object({}, { additionalProperties: false }),
24877
+ input: obj8({}),
24697
24878
  variants: {
24698
24879
  ready: {
24699
24880
  state: { state: ContextSettingsStateSchema },
24700
24881
  methods: {
24701
24882
  set: rpc(ContextSettingsPatchSchema, nil),
24702
- reset: rpc(Type8.Object({}, { additionalProperties: false }), nil)
24883
+ reset: rpc(obj8({}), nil)
24703
24884
  }
24704
24885
  }
24705
24886
  }
24706
24887
  });
24707
- var CodemodeSettingsStateSchema = Type8.Object({
24888
+ var CodemodeSettingsStateSchema = obj8({
24708
24889
  revision: integer,
24709
- effective: Type8.Object({ mode: Type8.Enum([...CODEMODE_MODES]) }),
24710
- source: Type8.Enum(["default", "config", "saved"])
24711
- });
24890
+ effective: obj8({ mode: oneOf2([...CODEMODE_MODES]) }, { open: true }),
24891
+ source: oneOf2(["default", "config", "saved"])
24892
+ }, { open: true });
24712
24893
  var NekoCodemodeSettings = contract("neko.codemode-settings", {
24713
24894
  version: 1,
24714
- input: Type8.Object({}, { additionalProperties: false }),
24895
+ input: obj8({}),
24715
24896
  variants: {
24716
24897
  ready: {
24717
24898
  state: { state: CodemodeSettingsStateSchema },
24718
24899
  methods: {
24719
- set: rpc(Type8.Object({ mode: Type8.Enum([...CODEMODE_MODES]) }, { additionalProperties: false }), nil),
24720
- reset: rpc(Type8.Object({}, { additionalProperties: false }), nil)
24900
+ set: rpc(obj8({ mode: oneOf2([...CODEMODE_MODES]) }), nil),
24901
+ reset: rpc(obj8({}), nil)
24721
24902
  }
24722
24903
  }
24723
24904
  }
24724
24905
  });
24725
- var defaultModelSource = Type8.Enum(["cli", "saved", "config", "default"]);
24726
- var DefaultModelStateSchema = Type8.Object({
24906
+ var defaultModelSource = oneOf2(["cli", "saved", "config", "default"]);
24907
+ var DefaultModelStateSchema = obj8({
24727
24908
  effective: model2,
24728
24909
  source: defaultModelSource
24729
- });
24910
+ }, { open: true });
24730
24911
  var NekoDefaultModel = contract("neko.default-model", {
24731
24912
  version: 1,
24732
- input: Type8.Object({}, { additionalProperties: false }),
24913
+ input: obj8({}),
24733
24914
  variants: {
24734
24915
  ready: {
24735
24916
  state: { state: DefaultModelStateSchema },
@@ -24740,74 +24921,76 @@ var NekoDefaultModel = contract("neko.default-model", {
24740
24921
  }
24741
24922
  }
24742
24923
  });
24743
- var FileCandidatesSchema = Type8.Object({
24744
- entries: Type8.Array(Type8.Object({ name: str, path: str, kind: Type8.Enum(["file", "directory"]) }), { maxItems: 100 }),
24745
- limited: bool,
24746
- incomplete: bool
24747
- });
24924
+ var FileCandidatesSchema = obj8({
24925
+ entries: arr6(obj8({ name: text3, path: text3, kind: oneOf2(["file", "directory"]) }, { open: true }), {
24926
+ maxItems: 100
24927
+ }),
24928
+ limited: boolean,
24929
+ incomplete: boolean
24930
+ }, { open: true });
24748
24931
  var NekoWorkspaceFiles = contract("neko.workspace-files", {
24749
24932
  version: 1,
24750
- input: Type8.Object({}, { additionalProperties: false }),
24933
+ input: obj8({}),
24751
24934
  variants: {
24752
24935
  ready: {
24753
24936
  methods: {
24754
- search: rpc(Type8.Object({ workspaceRoot: str, query: str }, { additionalProperties: false }), FileCandidatesSchema)
24937
+ search: rpc(obj8({ workspaceRoot: text3, query: text3 }), FileCandidatesSchema)
24755
24938
  }
24756
24939
  }
24757
24940
  }
24758
24941
  });
24759
- var marketSkill = Type8.Object({
24760
- name: str,
24761
- description: str,
24762
- category: str,
24763
- source: str,
24764
- license: str,
24765
- version: str,
24766
- sha256: str,
24942
+ var marketSkill = obj8({
24943
+ name: text3,
24944
+ description: text3,
24945
+ category: text3,
24946
+ source: text3,
24947
+ license: text3,
24948
+ version: text3,
24949
+ sha256: text3,
24767
24950
  sizeBytes: integer,
24768
- uploadedAt: str,
24769
- installed: Type8.Object({ project: bool, user: bool, builtin: bool }),
24770
- activeLevel: Type8.Union([level, nil])
24771
- });
24772
- var preview = Type8.Object({ body: str, files: Type8.Array(str) });
24773
- var scope = Type8.Enum(["user", "project"]);
24774
- var installResult = Type8.Object({ name: str, scope, path: str, shadowedBy: Type8.Optional(scope) });
24951
+ uploadedAt: text3,
24952
+ installed: obj8({ project: boolean, user: boolean, builtin: boolean }, { open: true }),
24953
+ activeLevel: union4([level, nil])
24954
+ }, { open: true });
24955
+ var preview = obj8({ body: text3, files: arr6(text3) }, { open: true });
24956
+ var scope = oneOf2(["user", "project"]);
24957
+ var installResult = obj8({ name: text3, scope, path: text3, shadowedBy: opt8(scope) }, { open: true });
24775
24958
  var NekoSkillMarket = contract("neko.skill-market", {
24776
24959
  version: 1,
24777
- input: Type8.Object({}, { additionalProperties: false }),
24960
+ input: obj8({}),
24778
24961
  variants: {
24779
24962
  ready: {
24780
24963
  methods: {
24781
- list: rpc(Type8.Object({ query: Type8.Optional(str), workspaceRoot: Type8.Optional(str) }, { additionalProperties: false }), Type8.Array(marketSkill)),
24782
- detail: rpc(Type8.Object({ name: str, workspaceRoot: Type8.Optional(str) }, { additionalProperties: false }), marketSkill),
24783
- preview: rpc(Type8.Object({ name: str }, { additionalProperties: false }), preview),
24784
- install: rpc(Type8.Object({ name: str, scope, workspaceRoot: Type8.Optional(str), overwrite: Type8.Optional(bool) }, { additionalProperties: false }), installResult),
24785
- uninstall: rpc(Type8.Object({ name: str, scope, workspaceRoot: Type8.Optional(str) }, { additionalProperties: false }), nil)
24964
+ list: rpc(obj8({ query: opt8(text3), workspaceRoot: opt8(text3) }), arr6(marketSkill)),
24965
+ detail: rpc(obj8({ name: text3, workspaceRoot: opt8(text3) }), marketSkill),
24966
+ preview: rpc(obj8({ name: text3 }), preview),
24967
+ install: rpc(obj8({ name: text3, scope, workspaceRoot: opt8(text3), overwrite: opt8(boolean) }), installResult),
24968
+ uninstall: rpc(obj8({ name: text3, scope, workspaceRoot: opt8(text3) }), nil)
24786
24969
  }
24787
24970
  }
24788
24971
  }
24789
24972
  });
24790
- var ShellStatusSchema = Type8.Union([
24791
- Type8.Object({ status: Type8.Literal("ready"), path: str, source: Type8.Enum(["config", "auto"]) }),
24792
- Type8.Object({
24793
- status: Type8.Literal("missing"),
24794
- reason: Type8.Enum(["not_found", "invalid_config"]),
24795
- detail: Type8.Optional(str)
24796
- })
24973
+ var ShellStatusSchema = union4([
24974
+ obj8({ status: lit3("ready"), path: text3, source: oneOf2(["config", "auto"]) }, { open: true }),
24975
+ obj8({
24976
+ status: lit3("missing"),
24977
+ reason: oneOf2(["not_found", "invalid_config"]),
24978
+ detail: opt8(text3)
24979
+ }, { open: true })
24797
24980
  ]);
24798
- var ApplicationInfoSchema = Type8.Object({
24799
- runningVersion: str,
24981
+ var ApplicationInfoSchema = obj8({
24982
+ runningVersion: text3,
24800
24983
  installedVersion: nullableString,
24801
- protocolVersion: Type8.Integer({ minimum: 1 }),
24984
+ protocolVersion: int5({ minimum: 1 }),
24802
24985
  latestVersion: nullableString,
24803
- checkedAt: Type8.Union([integer, nil]),
24804
- checkState: Type8.Enum(["unknown", "checking", "ok", "failed", "development"]),
24805
- serverId: str,
24806
- shell: Type8.Optional(ShellStatusSchema)
24807
- });
24986
+ checkedAt: union4([integer, nil]),
24987
+ checkState: oneOf2(["unknown", "checking", "ok", "failed", "development"]),
24988
+ serverId: text3,
24989
+ shell: opt8(ShellStatusSchema)
24990
+ }, { open: true });
24808
24991
  var NekoApplicationInfo = contract("neko.application-info", {
24809
24992
  version: 1,
24810
- input: Type8.Object({}),
24993
+ input: obj8({}, { open: true }),
24811
24994
  variants: {
24812
24995
  ready: { state: { info: ApplicationInfoSchema }, methods: { check: rpc(nil, ApplicationInfoSchema) } }
24813
24996
  }
@@ -24821,7 +25004,7 @@ function isServerId(value) {
24821
25004
  // packages/gateway/src/mobile/admin.ts
24822
25005
  import { createHash, timingSafeEqual } from "crypto";
24823
25006
  import { ChordError } from "@earendil-works/chord";
24824
- import { Type as Type9 } from "typebox";
25007
+ import { arr as arr7, bool as bool4, int as int6, lit as lit4, nul as nul4, obj as obj9, opt as opt9, str as str9, union as union5 } from "@earendil-works/pi-schema";
24825
25008
 
24826
25009
  // packages/gateway/src/principal.ts
24827
25010
  var HOST_PRINCIPAL = { kind: "host" };
@@ -25150,62 +25333,56 @@ class MobileStore {
25150
25333
  }
25151
25334
 
25152
25335
  // packages/gateway/src/mobile/admin.ts
25153
- var listenerStateSchema = Type9.Union([
25154
- Type9.Object({ status: Type9.Literal("disabled") }),
25155
- Type9.Object({ status: Type9.Literal("starting") }),
25156
- Type9.Object({
25157
- status: Type9.Literal("listening"),
25158
- address: Type9.String(),
25159
- port: Type9.Integer({ minimum: 1, maximum: 65535 }),
25160
- bindAddress: Type9.Optional(Type9.String()),
25161
- mode: Type9.Optional(Type9.Union([Type9.Literal("direct"), Type9.Literal("wsl-relay")]))
25162
- }),
25163
- Type9.Object({ status: Type9.Literal("error"), error: Type9.String() }),
25164
- Type9.Object({ status: Type9.Literal("stopping") })
25336
+ var listenerStateSchema = union5([
25337
+ obj9({ status: lit4("disabled") }, { open: true }),
25338
+ obj9({ status: lit4("starting") }, { open: true }),
25339
+ obj9({
25340
+ status: lit4("listening"),
25341
+ address: str9(),
25342
+ port: int6({ minimum: 1, maximum: 65535 }),
25343
+ bindAddress: opt9(str9()),
25344
+ mode: opt9(union5([lit4("direct"), lit4("wsl-relay")]))
25345
+ }, { open: true }),
25346
+ obj9({ status: lit4("error"), error: str9() }, { open: true }),
25347
+ obj9({ status: lit4("stopping") }, { open: true })
25165
25348
  ]);
25166
- var adminDeviceSchema = Type9.Object({
25167
- deviceId: Type9.String(),
25168
- name: Type9.String(),
25169
- pairedAt: Type9.Integer(),
25170
- lastSeenAt: Type9.Integer(),
25171
- online: Type9.Boolean()
25172
- });
25349
+ var adminDeviceSchema = obj9({
25350
+ deviceId: str9(),
25351
+ name: str9(),
25352
+ pairedAt: int6(),
25353
+ lastSeenAt: int6(),
25354
+ online: bool4()
25355
+ }, { open: true });
25173
25356
  var NekoMobileAdmin = contract("neko.mobile-admin", {
25174
25357
  version: 1,
25175
- input: Type9.Object({ token: Type9.String() }),
25358
+ input: obj9({ token: str9() }, { open: true }),
25176
25359
  variants: {
25177
25360
  admin: {
25178
25361
  methods: {
25179
- state: rpc(Type9.Null(), Type9.Object({
25362
+ state: rpc(nul4(), obj9({
25180
25363
  state: listenerStateSchema,
25181
- candidates: Type9.Array(Type9.String()),
25182
- port: Type9.Integer({ minimum: 1, maximum: 65535 }),
25183
- certificate: Type9.Union([
25184
- Type9.Object({ fingerprint: Type9.String(), expiresAt: Type9.Integer() }),
25185
- Type9.Null()
25186
- ]),
25187
- devices: Type9.Array(adminDeviceSchema),
25188
- lastConnectedAddress: Type9.Union([Type9.String(), Type9.Null()]),
25189
- wsl: Type9.Optional(Type9.Union([
25190
- Type9.Object({ interop: Type9.Boolean(), error: Type9.Union([Type9.String(), Type9.Null()]) }),
25191
- Type9.Null()
25192
- ]))
25193
- })),
25194
- enable: rpc(Type9.Object({
25195
- address: Type9.String(),
25196
- port: Type9.Optional(Type9.Integer({ minimum: 1, maximum: 65535 }))
25197
- }), Type9.Object({
25198
- status: Type9.Literal("listening"),
25199
- address: Type9.String(),
25200
- port: Type9.Integer({ minimum: 1, maximum: 65535 }),
25201
- bindAddress: Type9.Optional(Type9.String()),
25202
- mode: Type9.Optional(Type9.Union([Type9.Literal("direct"), Type9.Literal("wsl-relay")]))
25203
- })),
25204
- disable: rpc(Type9.Null(), listenerStateSchema),
25205
- createPairing: rpc(Type9.Null(), Type9.Object({ pairingText: Type9.String(), expiresAt: Type9.Integer() })),
25206
- cancelPairing: rpc(Type9.Null(), Type9.Null()),
25207
- revoke: rpc(Type9.Object({ deviceId: Type9.String({ minLength: 1 }) }), Type9.Object({ revoked: Type9.Boolean() })),
25208
- regenerateCertificate: rpc(Type9.Null(), Type9.Object({ fingerprint: Type9.String(), expiresAt: Type9.Integer() }))
25364
+ candidates: arr7(str9()),
25365
+ port: int6({ minimum: 1, maximum: 65535 }),
25366
+ certificate: union5([obj9({ fingerprint: str9(), expiresAt: int6() }, { open: true }), nul4()]),
25367
+ devices: arr7(adminDeviceSchema),
25368
+ lastConnectedAddress: union5([str9(), nul4()]),
25369
+ wsl: opt9(union5([obj9({ interop: bool4(), error: union5([str9(), nul4()]) }, { open: true }), nul4()]))
25370
+ }, { open: true })),
25371
+ enable: rpc(obj9({
25372
+ address: str9(),
25373
+ port: opt9(int6({ minimum: 1, maximum: 65535 }))
25374
+ }, { open: true }), obj9({
25375
+ status: lit4("listening"),
25376
+ address: str9(),
25377
+ port: int6({ minimum: 1, maximum: 65535 }),
25378
+ bindAddress: opt9(str9()),
25379
+ mode: opt9(union5([lit4("direct"), lit4("wsl-relay")]))
25380
+ }, { open: true })),
25381
+ disable: rpc(nul4(), listenerStateSchema),
25382
+ createPairing: rpc(nul4(), obj9({ pairingText: str9(), expiresAt: int6() }, { open: true })),
25383
+ cancelPairing: rpc(nul4(), nul4()),
25384
+ revoke: rpc(obj9({ deviceId: str9({ minLength: 1 }) }, { open: true }), obj9({ revoked: bool4() }, { open: true })),
25385
+ regenerateCertificate: rpc(nul4(), obj9({ fingerprint: str9(), expiresAt: int6() }, { open: true }))
25209
25386
  }
25210
25387
  }
25211
25388
  }
@@ -25381,9 +25558,6 @@ import { ChordError as ChordError2 } from "@earendil-works/chord";
25381
25558
  var messageTime = (session) => session.lastMessageAt ?? session.createdAt;
25382
25559
  var byMessage = (a, b) => messageTime(b) - messageTime(a) || Number(b.id) - Number(a.id);
25383
25560
 
25384
- // packages/gateway/src/mobile/adapter.ts
25385
- import { Check as Check2 } from "typebox/value";
25386
-
25387
25561
  // packages/gateway/src/subagent-client.ts
25388
25562
  function subagentClient(connect) {
25389
25563
  let value;
@@ -25527,16 +25701,29 @@ function subagentClient(connect) {
25527
25701
  // packages/gateway/src/mobile/projection.ts
25528
25702
  import { createHash as createHash2 } from "crypto";
25529
25703
 
25704
+ // packages/gateway/src/mobile/protocol.ts
25705
+ import {
25706
+ arr as arr8,
25707
+ bool as bool5,
25708
+ compile as compile2,
25709
+ int as int7,
25710
+ lit as lit5,
25711
+ nul as nul5,
25712
+ num as num5,
25713
+ obj as obj10,
25714
+ opt as opt10,
25715
+ str as str10,
25716
+ union as union6
25717
+ } from "@earendil-works/pi-schema";
25718
+
25530
25719
  // packages/core/src/application-version.ts
25531
- var RUNNING_VERSION = "0.5.3";
25720
+ var RUNNING_VERSION = "0.5.4";
25532
25721
  var APPLICATION_PROTOCOL = 10;
25533
25722
  function stableVersion(value) {
25534
25723
  return typeof value === "string" && /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$/.test(value) && value.split(".").every((n) => Number.isSafeInteger(Number(n)));
25535
25724
  }
25536
25725
 
25537
25726
  // packages/gateway/src/mobile/protocol.ts
25538
- import { Type as Type10 } from "typebox";
25539
- import { Check } from "typebox/value";
25540
25727
  var MOBILE_LIMITS = {
25541
25728
  maxFrameBytes: 262144,
25542
25729
  maxPayloadBytes: 131072,
@@ -25560,14 +25747,14 @@ var MOBILE_CAPABILITIES = [
25560
25747
  var MOBILE_CLOSE_REVOKED = 4401;
25561
25748
  var MOBILE_CLOSE_INCOMPATIBLE = 4402;
25562
25749
  var MOBILE_CLOSE_SLOW_CONSUMER = 4408;
25563
- var MobileHelloParams = Type10.Object({
25564
- apiVersions: Type10.Array(Type10.Integer(), { minItems: 1 }),
25565
- app: Type10.Object({
25566
- version: Type10.String({ minLength: 1, maxLength: 64 }),
25567
- platform: Type10.String({ minLength: 1, maxLength: 64 }),
25568
- build: Type10.String({ maxLength: 128 })
25569
- })
25570
- });
25750
+ var MobileHelloParams = obj10({
25751
+ apiVersions: arr8(int7(), { minItems: 1 }),
25752
+ app: obj10({
25753
+ version: str10({ minLength: 1, maxLength: 64 }),
25754
+ platform: str10({ minLength: 1, maxLength: 64 }),
25755
+ build: str10({ maxLength: 128 })
25756
+ }, { open: true })
25757
+ }, { open: true });
25571
25758
  function asJsonRpcRequest(value) {
25572
25759
  if (typeof value !== "object" || value === null)
25573
25760
  return;
@@ -25580,8 +25767,18 @@ function asJsonRpcRequest(value) {
25580
25767
  return;
25581
25768
  return { jsonrpc: "2.0", id: record.id, method: record.method, params: record.params };
25582
25769
  }
25770
+ var validators = new WeakMap;
25771
+ function checkSchema(schema, value) {
25772
+ let validator = validators.get(schema);
25773
+ if (!validator) {
25774
+ validator = compile2(schema);
25775
+ validators.set(schema, validator);
25776
+ }
25777
+ return validator.check(value);
25778
+ }
25779
+ var helloParams = compile2(MobileHelloParams);
25583
25780
  function isMobileHelloParams(value) {
25584
- return Check(MobileHelloParams, value);
25781
+ return helloParams.check(value);
25585
25782
  }
25586
25783
  function negotiateApiVersion(clientVersions) {
25587
25784
  let best;
@@ -25605,480 +25802,444 @@ function buildHelloResult(serverId, serverName, apiVersion) {
25605
25802
  limits: MOBILE_LIMITS
25606
25803
  };
25607
25804
  }
25608
- var opt = Type10.Optional;
25609
- var str2 = Type10.String();
25610
- var int = Type10.Integer({ minimum: 0 });
25611
- var nullable2 = (schema) => Type10.Union([schema, Type10.Null()]);
25612
- var MobileContentRefSchema = Type10.Object({
25613
- sessionId: str2,
25614
- agentId: opt(str2),
25615
- key: str2,
25616
- field: str2,
25617
- digest: str2,
25618
- bytes: int
25619
- });
25620
- var MobileImageRefSchema = Type10.Object({
25621
- name: str2,
25622
- mimeType: str2,
25623
- width: int,
25624
- height: int,
25625
- bytes: int,
25626
- entryId: int,
25627
- contentIndex: int
25628
- });
25629
- var planStatus = Type10.Union([
25630
- Type10.Literal("awaiting_approval"),
25631
- Type10.Literal("approved"),
25632
- Type10.Literal("revision_requested"),
25633
- Type10.Literal("superseded"),
25634
- Type10.Literal("cancelled")
25635
- ]);
25636
- var questionStatus2 = Type10.Union([
25637
- Type10.Literal("pending"),
25638
- Type10.Literal("answered"),
25639
- Type10.Literal("skipped"),
25640
- Type10.Literal("cancelled")
25805
+ var text4 = str10();
25806
+ var count = int7({ minimum: 0 });
25807
+ var nullable2 = (schema) => union6([schema, nul5()]);
25808
+ var MobileContentRefSchema = obj10({
25809
+ sessionId: text4,
25810
+ agentId: opt10(text4),
25811
+ key: text4,
25812
+ field: text4,
25813
+ digest: text4,
25814
+ bytes: count
25815
+ }, { open: true });
25816
+ var MobileImageRefSchema = obj10({
25817
+ name: text4,
25818
+ mimeType: text4,
25819
+ width: count,
25820
+ height: count,
25821
+ bytes: count,
25822
+ entryId: count,
25823
+ contentIndex: count
25824
+ }, { open: true });
25825
+ var planStatus = union6([
25826
+ lit5("awaiting_approval"),
25827
+ lit5("approved"),
25828
+ lit5("revision_requested"),
25829
+ lit5("superseded"),
25830
+ lit5("cancelled")
25641
25831
  ]);
25642
- var MobileToolInteractionSchema = Type10.Union([
25643
- Type10.Object({
25644
- kind: Type10.Literal("ask_user"),
25645
- id: int,
25646
- question: str2,
25647
- multiple: Type10.Boolean(),
25648
- options: Type10.Array(Type10.Object({ id: str2, label: str2, recommended: opt(Type10.Boolean()) })),
25832
+ var questionStatus2 = union6([lit5("pending"), lit5("answered"), lit5("skipped"), lit5("cancelled")]);
25833
+ var MobileToolInteractionSchema = union6([
25834
+ obj10({
25835
+ kind: lit5("ask_user"),
25836
+ id: count,
25837
+ question: text4,
25838
+ multiple: bool5(),
25839
+ options: arr8(obj10({ id: text4, label: text4, recommended: opt10(bool5()) }, { open: true })),
25649
25840
  status: questionStatus2,
25650
- optionIds: opt(Type10.Array(str2)),
25651
- labels: opt(Type10.Array(str2)),
25652
- text: opt(nullable2(str2))
25653
- }),
25654
- Type10.Object({
25655
- kind: Type10.Literal("todo"),
25656
- action: Type10.Union([Type10.Literal("list"), Type10.Literal("replace")]),
25657
- revision: int,
25658
- completed: int,
25659
- total: int
25660
- }),
25661
- Type10.Object({
25662
- kind: Type10.Literal("submit_plan"),
25663
- version: str2,
25664
- title: str2,
25665
- steps: Type10.Array(str2),
25666
- note: str2
25667
- })
25841
+ optionIds: opt10(arr8(text4)),
25842
+ labels: opt10(arr8(text4)),
25843
+ text: opt10(nullable2(text4))
25844
+ }, { open: true }),
25845
+ obj10({
25846
+ kind: lit5("todo"),
25847
+ action: union6([lit5("list"), lit5("replace")]),
25848
+ revision: count,
25849
+ completed: count,
25850
+ total: count
25851
+ }, { open: true }),
25852
+ obj10({
25853
+ kind: lit5("submit_plan"),
25854
+ version: text4,
25855
+ title: text4,
25856
+ steps: arr8(text4),
25857
+ note: text4
25858
+ }, { open: true })
25668
25859
  ]);
25669
- var MobileCodemodeSchema = Type10.Object({
25670
- calls: Type10.Array(Type10.Object({
25671
- id: int,
25672
- name: str2,
25673
- args: Type10.String({ maxLength: CODEMODE_VIEW_LIMITS.argsChars }),
25674
- status: Type10.Union([
25675
- Type10.Literal("running"),
25676
- Type10.Literal("ok"),
25677
- Type10.Literal("error"),
25678
- Type10.Literal("cancelled")
25679
- ]),
25680
- durationMs: opt(Type10.Number()),
25681
- error: opt(Type10.String({ maxLength: CODEMODE_VIEW_LIMITS.errorChars }))
25682
- }), { maxItems: CODEMODE_VIEW_LIMITS.maxCalls }),
25683
- omitted: int,
25684
- fullOutputPath: opt(str2)
25685
- });
25686
- var MobileToolItemSchema = Type10.Object({
25687
- callId: str2,
25688
- name: str2,
25689
- summary: str2,
25690
- status: Type10.Union([Type10.Literal("running"), Type10.Literal("done"), Type10.Literal("error")]),
25691
- detail: opt(str2),
25692
- output: opt(str2),
25693
- result: opt(str2),
25694
- diff: opt(str2),
25695
- diffAdded: opt(Type10.Number()),
25696
- diffRemoved: opt(Type10.Number()),
25697
- diffTruncated: opt(Type10.Boolean()),
25698
- durationMs: opt(Type10.Number()),
25699
- note: opt(str2),
25700
- interaction: opt(MobileToolInteractionSchema),
25701
- codemode: opt(MobileCodemodeSchema)
25702
- });
25703
- var MobileChatItemSchema = Type10.Object({
25704
- key: str2,
25705
- type: Type10.Union([
25706
- Type10.Literal("user"),
25707
- Type10.Literal("assistant"),
25708
- Type10.Literal("tool"),
25709
- Type10.Literal("error"),
25710
- Type10.Literal("system")
25711
- ]),
25712
- text: opt(str2),
25713
- thinking: opt(str2),
25714
- note: opt(str2),
25715
- error: opt(str2),
25716
- skill: opt(str2),
25717
- jobId: opt(str2),
25718
- tool: opt(MobileToolItemSchema),
25719
- images: opt(Type10.Array(MobileImageRefSchema)),
25720
- refs: opt(Type10.Array(MobileContentRefSchema))
25721
- });
25722
- var MobileStreamingSchema = Type10.Object({
25723
- text: str2,
25724
- thinking: str2,
25725
- textOmitted: int,
25726
- thinkingOmitted: int,
25727
- toolCalls: Type10.Array(Type10.Object({
25728
- callId: str2,
25729
- name: str2,
25730
- summary: str2,
25731
- status: Type10.Union([Type10.Literal("running"), Type10.Literal("done")])
25732
- }))
25733
- });
25734
- var MobileUsageSchema = Type10.Object({
25735
- input: int,
25736
- output: int,
25737
- cacheRead: int,
25738
- cacheWrite: int,
25739
- totalTokens: int,
25740
- cost: Type10.Number({ minimum: 0 })
25741
- });
25742
- var MobileSubagentRoundSchema = Type10.Object({
25743
- taskId: int,
25744
- callId: str2,
25745
- agentId: str2,
25746
- round: opt(int),
25747
- role: str2,
25748
- title: str2,
25749
- status: Type10.Union([
25750
- Type10.Literal("queued"),
25751
- Type10.Literal("running"),
25752
- Type10.Literal("completed"),
25753
- Type10.Literal("failed"),
25754
- Type10.Literal("cancelled")
25755
- ]),
25756
- approvalCount: int,
25757
- readonly: Type10.Boolean(),
25758
- createdAt: Type10.Number(),
25759
- endedAt: nullable2(Type10.Number()),
25760
- usage: opt(MobileUsageSchema)
25761
- });
25762
- var MobileAgentSchema = Type10.Object({
25763
- agentId: str2,
25764
- role: str2,
25765
- title: str2,
25766
- status: Type10.Union([Type10.Literal("idle"), Type10.Literal("queued"), Type10.Literal("running")]),
25767
- activeRoundId: nullable2(int),
25768
- lastRoundId: int,
25769
- roundCount: int,
25770
- approvalCount: int
25771
- });
25772
- var MobileQueuedSchema = Type10.Object({
25773
- id: int,
25774
- mode: Type10.Union([Type10.Literal("steer"), Type10.Literal("followUp")]),
25775
- preview: Type10.String(),
25776
- images: int
25777
- });
25778
- var MobileChatStatusSchema = Type10.Object({
25779
- busy: Type10.Boolean(),
25780
- queued: opt(Type10.Array(MobileQueuedSchema)),
25781
- todos: opt(Type10.Object({ revision: int, count: int, completed: int })),
25782
- questions: opt(Type10.Object({ revision: int, pendingCount: int })),
25783
- plan: opt(Type10.Object({ revision: int, pending: Type10.Boolean(), version: opt(Type10.String({ minLength: 1 })) })),
25784
- status: nullable2(str2),
25860
+ var MobileCodemodeSchema = obj10({
25861
+ calls: arr8(obj10({
25862
+ id: count,
25863
+ name: text4,
25864
+ args: str10({ maxLength: CODEMODE_VIEW_LIMITS.argsChars }),
25865
+ status: union6([lit5("running"), lit5("ok"), lit5("error"), lit5("cancelled")]),
25866
+ durationMs: opt10(num5()),
25867
+ error: opt10(str10({ maxLength: CODEMODE_VIEW_LIMITS.errorChars }))
25868
+ }, { open: true }), { maxItems: CODEMODE_VIEW_LIMITS.maxCalls }),
25869
+ omitted: count,
25870
+ fullOutputPath: opt10(text4)
25871
+ }, { open: true });
25872
+ var MobileToolItemSchema = obj10({
25873
+ callId: text4,
25874
+ name: text4,
25875
+ summary: text4,
25876
+ status: union6([lit5("running"), lit5("done"), lit5("error")]),
25877
+ detail: opt10(text4),
25878
+ output: opt10(text4),
25879
+ result: opt10(text4),
25880
+ diff: opt10(text4),
25881
+ diffAdded: opt10(num5()),
25882
+ diffRemoved: opt10(num5()),
25883
+ diffTruncated: opt10(bool5()),
25884
+ durationMs: opt10(num5()),
25885
+ note: opt10(text4),
25886
+ interaction: opt10(MobileToolInteractionSchema),
25887
+ codemode: opt10(MobileCodemodeSchema)
25888
+ }, { open: true });
25889
+ var MobileChatItemSchema = obj10({
25890
+ key: text4,
25891
+ type: union6([lit5("user"), lit5("assistant"), lit5("tool"), lit5("error"), lit5("system")]),
25892
+ text: opt10(text4),
25893
+ thinking: opt10(text4),
25894
+ note: opt10(text4),
25895
+ error: opt10(text4),
25896
+ skill: opt10(text4),
25897
+ jobId: opt10(text4),
25898
+ tool: opt10(MobileToolItemSchema),
25899
+ images: opt10(arr8(MobileImageRefSchema)),
25900
+ refs: opt10(arr8(MobileContentRefSchema))
25901
+ }, { open: true });
25902
+ var MobileStreamingSchema = obj10({
25903
+ text: text4,
25904
+ thinking: text4,
25905
+ textOmitted: count,
25906
+ thinkingOmitted: count,
25907
+ toolCalls: arr8(obj10({
25908
+ callId: text4,
25909
+ name: text4,
25910
+ summary: text4,
25911
+ status: union6([lit5("running"), lit5("done")])
25912
+ }, { open: true }))
25913
+ }, { open: true });
25914
+ var MobileUsageSchema = obj10({
25915
+ input: count,
25916
+ output: count,
25917
+ cacheRead: count,
25918
+ cacheWrite: count,
25919
+ totalTokens: count,
25920
+ cost: num5({ minimum: 0 })
25921
+ }, { open: true });
25922
+ var MobileSubagentRoundSchema = obj10({
25923
+ taskId: count,
25924
+ callId: text4,
25925
+ agentId: text4,
25926
+ round: opt10(count),
25927
+ role: text4,
25928
+ title: text4,
25929
+ status: union6([lit5("queued"), lit5("running"), lit5("completed"), lit5("failed"), lit5("cancelled")]),
25930
+ approvalCount: count,
25931
+ readonly: bool5(),
25932
+ createdAt: num5(),
25933
+ endedAt: nullable2(num5()),
25934
+ usage: opt10(MobileUsageSchema)
25935
+ }, { open: true });
25936
+ var MobileAgentSchema = obj10({
25937
+ agentId: text4,
25938
+ role: text4,
25939
+ title: text4,
25940
+ status: union6([lit5("idle"), lit5("queued"), lit5("running")]),
25941
+ activeRoundId: nullable2(count),
25942
+ lastRoundId: count,
25943
+ roundCount: count,
25944
+ approvalCount: count
25945
+ }, { open: true });
25946
+ var MobileQueuedSchema = obj10({
25947
+ id: count,
25948
+ mode: union6([lit5("steer"), lit5("followUp")]),
25949
+ preview: str10(),
25950
+ images: count
25951
+ }, { open: true });
25952
+ var mobileChatStatusProperties = {
25953
+ busy: bool5(),
25954
+ queued: opt10(arr8(MobileQueuedSchema)),
25955
+ todos: opt10(obj10({ revision: count, count, completed: count }, { open: true })),
25956
+ questions: opt10(obj10({ revision: count, pendingCount: count }, { open: true })),
25957
+ plan: opt10(obj10({ revision: count, pending: bool5(), version: opt10(str10({ minLength: 1 })) }, { open: true })),
25958
+ status: nullable2(text4),
25785
25959
  usage: MobileUsageSchema,
25786
- taskUsage: opt(MobileUsageSchema),
25787
- contextUsage: opt(Type10.Object({ tokens: nullable2(Type10.Number()), window: Type10.Number(), percent: nullable2(Type10.Number()) })),
25788
- agent: Type10.Object({ model: nullable2(str2), thinkingLevel: nullable2(str2) }),
25789
- subagents: Type10.Array(MobileSubagentRoundSchema),
25790
- agents: Type10.Array(MobileAgentSchema),
25791
- approvalCount: int,
25792
- compaction: opt(Type10.Object({ phase: str2, at: Type10.Number() })),
25793
- readonly: opt(Type10.Boolean())
25794
- });
25795
- var MobileChatSnapshotSchema = Type10.Object({
25796
- ...MobileChatStatusSchema.properties,
25797
- items: Type10.Array(MobileChatItemSchema),
25798
- historyBefore: nullable2(str2),
25960
+ taskUsage: opt10(MobileUsageSchema),
25961
+ contextUsage: opt10(obj10({ tokens: nullable2(num5()), window: num5(), percent: nullable2(num5()) }, { open: true })),
25962
+ agent: obj10({ model: nullable2(text4), thinkingLevel: nullable2(text4) }, { open: true }),
25963
+ subagents: arr8(MobileSubagentRoundSchema),
25964
+ agents: arr8(MobileAgentSchema),
25965
+ approvalCount: count,
25966
+ compaction: opt10(obj10({ phase: text4, at: num5() }, { open: true })),
25967
+ runFailure: opt10(obj10({ reason: text4, detail: opt10(text4) }, { open: true })),
25968
+ readonly: opt10(bool5())
25969
+ };
25970
+ var MobileChatStatusSchema = obj10(mobileChatStatusProperties, { open: true });
25971
+ var MobileChatSnapshotSchema = obj10({
25972
+ ...mobileChatStatusProperties,
25973
+ items: arr8(MobileChatItemSchema),
25974
+ historyBefore: nullable2(text4),
25799
25975
  streaming: nullable2(MobileStreamingSchema)
25800
- });
25801
- var MobileWorkspaceSchema = Type10.Object({ root: str2, name: str2 });
25802
- var MobileSessionSummarySchema = Type10.Object({
25803
- id: str2,
25804
- workspace: str2,
25805
- title: str2,
25806
- preview: str2,
25807
- lastUsedAt: Type10.Integer(),
25808
- lastMessageAt: Type10.Integer(),
25809
- archived: Type10.Boolean(),
25810
- awaitingAnswer: opt(Type10.Boolean()),
25811
- awaitingPlan: opt(Type10.Boolean())
25812
- });
25813
- var MobileApprovalSchema = Type10.Object({
25814
- id: int,
25815
- version: str2,
25816
- taskId: int,
25817
- agentId: opt(str2),
25818
- title: opt(str2),
25819
- command: str2,
25820
- cwd: str2,
25821
- timeoutSeconds: opt(Type10.Number({ minimum: 0 })),
25822
- requestedAt: Type10.Number()
25823
- });
25824
- var MobileTodoItemSchema = Type10.Object({
25825
- id: Type10.String({ minLength: 1, maxLength: TODO_LIMITS.idChars }),
25826
- text: Type10.String({ minLength: 1, maxLength: TODO_LIMITS.textChars }),
25827
- status: Type10.Union([Type10.Literal("pending"), Type10.Literal("in_progress"), Type10.Literal("completed")])
25828
- });
25829
- var MobileTodoListSchema = Type10.Object({
25830
- revision: int,
25831
- items: Type10.Array(MobileTodoItemSchema, { maxItems: TODO_LIMITS.maxItems })
25832
- });
25833
- var MobileQuestionOptionSchema = Type10.Object({
25834
- id: Type10.String({ minLength: 1, maxLength: QUESTION_LIMITS.optionIdChars }),
25835
- label: Type10.String({ minLength: 1, maxLength: QUESTION_LIMITS.labelChars }),
25836
- description: opt(Type10.String({ maxLength: QUESTION_LIMITS.descriptionChars })),
25837
- recommended: opt(Type10.Boolean())
25838
- });
25839
- var MobileQuestionSummarySchema = Type10.Object({
25840
- id: int,
25841
- version: str2,
25842
- preview: Type10.String({ maxLength: QUESTION_LIMITS.previewChars }),
25843
- multiple: Type10.Boolean(),
25844
- optionCount: int,
25845
- createdAt: Type10.Number()
25846
- });
25847
- var MobileQuestionListSchema = Type10.Object({
25848
- revision: int,
25849
- pending: Type10.Array(MobileQuestionSummarySchema, { maxItems: QUESTION_LIMITS.maxPending })
25850
- });
25851
- var MobileQuestionSchema = Type10.Object({
25852
- id: int,
25853
- callId: str2,
25854
- version: str2,
25855
- question: Type10.String({ maxLength: QUESTION_LIMITS.questionChars }),
25856
- multiple: Type10.Boolean(),
25857
- options: Type10.Array(MobileQuestionOptionSchema, { maxItems: QUESTION_LIMITS.maxOptions }),
25976
+ }, { open: true });
25977
+ var MobileWorkspaceSchema = obj10({ root: text4, name: text4 }, { open: true });
25978
+ var MobileSessionSummarySchema = obj10({
25979
+ id: text4,
25980
+ workspace: text4,
25981
+ title: text4,
25982
+ preview: text4,
25983
+ lastUsedAt: int7(),
25984
+ lastMessageAt: int7(),
25985
+ archived: bool5(),
25986
+ awaitingAnswer: opt10(bool5()),
25987
+ awaitingPlan: opt10(bool5())
25988
+ }, { open: true });
25989
+ var MobileApprovalSchema = obj10({
25990
+ id: count,
25991
+ version: text4,
25992
+ taskId: count,
25993
+ agentId: opt10(text4),
25994
+ title: opt10(text4),
25995
+ command: text4,
25996
+ cwd: text4,
25997
+ timeoutSeconds: opt10(num5({ minimum: 0 })),
25998
+ requestedAt: num5()
25999
+ }, { open: true });
26000
+ var MobileTodoItemSchema = obj10({
26001
+ id: str10({ minLength: 1, maxLength: TODO_LIMITS.idChars }),
26002
+ text: str10({ minLength: 1, maxLength: TODO_LIMITS.textChars }),
26003
+ status: union6([lit5("pending"), lit5("in_progress"), lit5("completed")])
26004
+ }, { open: true });
26005
+ var MobileTodoListSchema = obj10({
26006
+ revision: count,
26007
+ items: arr8(MobileTodoItemSchema, { maxItems: TODO_LIMITS.maxItems })
26008
+ }, { open: true });
26009
+ var MobileQuestionOptionSchema = obj10({
26010
+ id: str10({ minLength: 1, maxLength: QUESTION_LIMITS.optionIdChars }),
26011
+ label: str10({ minLength: 1, maxLength: QUESTION_LIMITS.labelChars }),
26012
+ description: opt10(str10({ maxLength: QUESTION_LIMITS.descriptionChars })),
26013
+ recommended: opt10(bool5())
26014
+ }, { open: true });
26015
+ var MobileQuestionSummarySchema = obj10({
26016
+ id: count,
26017
+ version: text4,
26018
+ preview: str10({ maxLength: QUESTION_LIMITS.previewChars }),
26019
+ multiple: bool5(),
26020
+ optionCount: count,
26021
+ createdAt: num5()
26022
+ }, { open: true });
26023
+ var MobileQuestionListSchema = obj10({
26024
+ revision: count,
26025
+ pending: arr8(MobileQuestionSummarySchema, { maxItems: QUESTION_LIMITS.maxPending })
26026
+ }, { open: true });
26027
+ var MobileQuestionSchema = obj10({
26028
+ id: count,
26029
+ callId: text4,
26030
+ version: text4,
26031
+ question: str10({ maxLength: QUESTION_LIMITS.questionChars }),
26032
+ multiple: bool5(),
26033
+ options: arr8(MobileQuestionOptionSchema, { maxItems: QUESTION_LIMITS.maxOptions }),
25858
26034
  status: questionStatus2,
25859
- answer: nullable2(Type10.Object({
25860
- optionIds: Type10.Array(Type10.String(), { maxItems: QUESTION_LIMITS.maxOptions }),
25861
- text: nullable2(Type10.String({ maxLength: QUESTION_LIMITS.textChars }))
25862
- })),
25863
- createdAt: Type10.Number(),
25864
- settledAt: nullable2(Type10.Number())
25865
- });
25866
- var MobileQuestionResponseSchema = Type10.Union([
25867
- Type10.Object({
25868
- kind: Type10.Literal("answer"),
25869
- optionIds: opt(Type10.Array(Type10.String(), { maxItems: QUESTION_LIMITS.maxOptions })),
25870
- text: opt(Type10.String({ maxLength: QUESTION_LIMITS.textChars }))
25871
- }, { additionalProperties: false }),
25872
- Type10.Object({ kind: Type10.Literal("skip") }, { additionalProperties: false })
26035
+ answer: nullable2(obj10({
26036
+ optionIds: arr8(str10(), { maxItems: QUESTION_LIMITS.maxOptions }),
26037
+ text: nullable2(str10({ maxLength: QUESTION_LIMITS.textChars }))
26038
+ }, { open: true })),
26039
+ createdAt: num5(),
26040
+ settledAt: nullable2(num5())
26041
+ }, { open: true });
26042
+ var MobileQuestionResponseSchema = union6([
26043
+ obj10({
26044
+ kind: lit5("answer"),
26045
+ optionIds: opt10(arr8(str10(), { maxItems: QUESTION_LIMITS.maxOptions })),
26046
+ text: opt10(str10({ maxLength: QUESTION_LIMITS.textChars }))
26047
+ }),
26048
+ obj10({ kind: lit5("skip") })
25873
26049
  ]);
25874
- var MobilePlanSchema = Type10.Object({
25875
- version: Type10.String({ minLength: 1 }),
25876
- title: Type10.String({ maxLength: PLAN_LIMITS.titleChars }),
25877
- steps: Type10.Array(Type10.String({ maxLength: PLAN_LIMITS.stepChars }), { maxItems: PLAN_LIMITS.maxSteps }),
25878
- note: Type10.String({ maxLength: PLAN_LIMITS.noteChars }),
26050
+ var MobilePlanSchema = obj10({
26051
+ version: str10({ minLength: 1 }),
26052
+ title: str10({ maxLength: PLAN_LIMITS.titleChars }),
26053
+ steps: arr8(str10({ maxLength: PLAN_LIMITS.stepChars }), { maxItems: PLAN_LIMITS.maxSteps }),
26054
+ note: str10({ maxLength: PLAN_LIMITS.noteChars }),
25879
26055
  status: planStatus,
25880
- feedback: nullable2(Type10.String({ maxLength: PLAN_LIMITS.feedbackChars })),
25881
- createdAt: Type10.Number(),
25882
- settledAt: nullable2(Type10.Number())
25883
- });
25884
- var MobilePlanDecisionSchema = Type10.Union([
25885
- Type10.Object({ kind: Type10.Literal("approve") }, { additionalProperties: false }),
25886
- Type10.Object({ kind: Type10.Literal("revise"), feedback: Type10.String({ minLength: 1, maxLength: PLAN_LIMITS.feedbackChars }) }, { additionalProperties: false })
26056
+ feedback: nullable2(str10({ maxLength: PLAN_LIMITS.feedbackChars })),
26057
+ createdAt: num5(),
26058
+ settledAt: nullable2(num5())
26059
+ }, { open: true });
26060
+ var MobilePlanDecisionSchema = union6([
26061
+ obj10({ kind: lit5("approve") }),
26062
+ obj10({ kind: lit5("revise"), feedback: str10({ minLength: 1, maxLength: PLAN_LIMITS.feedbackChars }) })
25887
26063
  ]);
25888
- var sessionListParams = Type10.Object({
25889
- workspace: str2,
25890
- query: opt(str2),
25891
- cursor: opt(str2)
25892
- });
25893
- var sessionListResult = Type10.Object({
25894
- sessions: Type10.Array(MobileSessionSummarySchema),
25895
- nextCursor: opt(str2)
25896
- });
25897
- var subscription = { subscriptionId: Type10.String({ minLength: 1 }) };
25898
- var pageResult = Type10.Object({ items: Type10.Array(MobileChatItemSchema), historyBefore: nullable2(str2) });
25899
- var pageParams = Type10.Object({
26064
+ var sessionListParams = obj10({
26065
+ workspace: text4,
26066
+ query: opt10(text4),
26067
+ cursor: opt10(text4)
26068
+ }, { open: true });
26069
+ var sessionListResult = obj10({
26070
+ sessions: arr8(MobileSessionSummarySchema),
26071
+ nextCursor: opt10(text4)
26072
+ }, { open: true });
26073
+ var subscription = { subscriptionId: str10({ minLength: 1 }) };
26074
+ var pageResult = obj10({ items: arr8(MobileChatItemSchema), historyBefore: nullable2(text4) }, { open: true });
26075
+ var pageParams = obj10({
25900
26076
  ...subscription,
25901
- before: Type10.String({ minLength: 1 }),
25902
- limit: opt(Type10.Integer({ minimum: 1, maximum: 50 }))
25903
- });
25904
- var chunkResult = Type10.Object({ data: str2, nextOffset: int, total: int, done: Type10.Boolean() });
26077
+ before: str10({ minLength: 1 }),
26078
+ limit: opt10(int7({ minimum: 1, maximum: 50 }))
26079
+ }, { open: true });
26080
+ var chunkResultProperties = { data: text4, nextOffset: count, total: count, done: bool5() };
26081
+ var chunkResult = obj10(chunkResultProperties, { open: true });
25905
26082
  var MOBILE_API_V1_METHODS = {
25906
26083
  "server.hello": { params: MobileHelloParams, result: buildHelloResultSchema() },
25907
- "workspaces.list": { params: Type10.Null(), result: Type10.Object({ workspaces: Type10.Array(MobileWorkspaceSchema) }) },
26084
+ "workspaces.list": { params: nul5(), result: obj10({ workspaces: arr8(MobileWorkspaceSchema) }, { open: true }) },
25908
26085
  "sessions.list": { params: sessionListParams, result: sessionListResult },
25909
- "sessions.create": { params: Type10.Object({ workspace: str2 }), result: MobileSessionSummarySchema },
26086
+ "sessions.create": { params: obj10({ workspace: text4 }, { open: true }), result: MobileSessionSummarySchema },
25910
26087
  "chat.attach": {
25911
- params: Type10.Object({ sessionId: Type10.String({ minLength: 1 }) }),
25912
- result: Type10.Object({ subscriptionId: str2, sessionId: str2, snapshot: MobileChatSnapshotSchema })
26088
+ params: obj10({ sessionId: str10({ minLength: 1 }) }, { open: true }),
26089
+ result: obj10({ subscriptionId: text4, sessionId: text4, snapshot: MobileChatSnapshotSchema }, { open: true })
25913
26090
  },
25914
- "chat.detach": { params: Type10.Object(subscription), result: Type10.Null() },
26091
+ "chat.detach": { params: obj10(subscription, { open: true }), result: nul5() },
25915
26092
  "chat.history": { params: pageParams, result: pageResult },
25916
26093
  "chat.content": {
25917
- params: Type10.Object({ ref: MobileContentRefSchema, offset: int }),
26094
+ params: obj10({ ref: MobileContentRefSchema, offset: count }, { open: true }),
25918
26095
  result: chunkResult
25919
26096
  },
25920
26097
  "chat.submit": {
25921
- params: Type10.Object({
26098
+ params: obj10({
25922
26099
  ...subscription,
25923
- requestId: Type10.String({ minLength: 1, maxLength: 128 }),
25924
- text: Type10.String({ minLength: 1, maxLength: 65536 }),
25925
- mode: opt(Type10.Literal("steer"))
25926
- }),
25927
- result: Type10.Object({ accepted: Type10.Literal(true), queued: Type10.Boolean() })
26100
+ requestId: str10({ minLength: 1, maxLength: 128 }),
26101
+ text: str10({ minLength: 1, maxLength: 65536 }),
26102
+ mode: opt10(lit5("steer"))
26103
+ }, { open: true }),
26104
+ result: obj10({ accepted: lit5(true), queued: bool5() }, { open: true })
25928
26105
  },
25929
26106
  "chat.submissionStatus": {
25930
- params: Type10.Object({ ...subscription, requestId: Type10.String({ minLength: 1, maxLength: 128 }) }),
25931
- result: Type10.Object({ status: Type10.Union([Type10.Literal("accepted"), Type10.Literal("unknown")]) })
26107
+ params: obj10({ ...subscription, requestId: str10({ minLength: 1, maxLength: 128 }) }, { open: true }),
26108
+ result: obj10({ status: union6([lit5("accepted"), lit5("unknown")]) }, { open: true })
25932
26109
  },
25933
26110
  "chat.steer": {
25934
- params: Type10.Object({ ...subscription, id: int }),
25935
- result: Type10.Object({
25936
- result: Type10.Union([
25937
- Type10.Literal("steered"),
25938
- Type10.Literal("withdrawn"),
25939
- Type10.Literal("placed"),
25940
- Type10.Literal("settled"),
25941
- Type10.Literal("unknown")
25942
- ]),
25943
- id: opt(int),
25944
- text: opt(Type10.String()),
25945
- images: opt(int)
25946
- })
26111
+ params: obj10({ ...subscription, id: count }, { open: true }),
26112
+ result: obj10({
26113
+ result: union6([lit5("steered"), lit5("withdrawn"), lit5("placed"), lit5("settled"), lit5("unknown")]),
26114
+ id: opt10(count),
26115
+ text: opt10(str10()),
26116
+ images: opt10(count)
26117
+ }, { open: true })
25947
26118
  },
25948
26119
  "chat.withdraw": {
25949
- params: Type10.Object({ ...subscription, id: int }),
25950
- result: Type10.Object({
25951
- result: Type10.Union([
25952
- Type10.Literal("withdrawn"),
25953
- Type10.Literal("placed"),
25954
- Type10.Literal("settled"),
25955
- Type10.Literal("unknown")
25956
- ]),
25957
- text: opt(Type10.String()),
25958
- images: opt(int)
25959
- })
26120
+ params: obj10({ ...subscription, id: count }, { open: true }),
26121
+ result: obj10({
26122
+ result: union6([lit5("withdrawn"), lit5("placed"), lit5("settled"), lit5("unknown")]),
26123
+ text: opt10(str10()),
26124
+ images: opt10(count)
26125
+ }, { open: true })
25960
26126
  },
25961
- "chat.abort": { params: Type10.Object(subscription), result: Type10.Object({ accepted: Type10.Boolean() }) },
26127
+ "chat.abort": { params: obj10(subscription, { open: true }), result: obj10({ accepted: bool5() }, { open: true }) },
25962
26128
  "subagents.open": {
25963
- params: Type10.Object({ ...subscription, agentId: opt(Type10.String({ minLength: 1 })), taskId: opt(int) }),
25964
- result: Type10.Object({
25965
- subagentSubscriptionId: str2,
25966
- agentId: str2,
26129
+ params: obj10({ ...subscription, agentId: opt10(str10({ minLength: 1 })), taskId: opt10(count) }, { open: true }),
26130
+ result: obj10({
26131
+ subagentSubscriptionId: text4,
26132
+ agentId: text4,
25967
26133
  snapshot: MobileChatSnapshotSchema
25968
- })
26134
+ }, { open: true })
25969
26135
  },
25970
26136
  "subagents.history": {
25971
- params: Type10.Object({
25972
- subagentSubscriptionId: Type10.String({ minLength: 1 }),
25973
- before: Type10.String({ minLength: 1 }),
25974
- limit: opt(Type10.Integer({ minimum: 1, maximum: 50 }))
25975
- }),
26137
+ params: obj10({
26138
+ subagentSubscriptionId: str10({ minLength: 1 }),
26139
+ before: str10({ minLength: 1 }),
26140
+ limit: opt10(int7({ minimum: 1, maximum: 50 }))
26141
+ }, { open: true }),
25976
26142
  result: pageResult
25977
26143
  },
25978
26144
  "subagents.close": {
25979
- params: Type10.Object({ subagentSubscriptionId: Type10.String({ minLength: 1 }) }),
25980
- result: Type10.Null()
26145
+ params: obj10({ subagentSubscriptionId: str10({ minLength: 1 }) }, { open: true }),
26146
+ result: nul5()
25981
26147
  },
25982
26148
  "subagents.stop": {
25983
- params: Type10.Object({ ...subscription, taskId: int }),
25984
- result: Type10.Object({ stopped: Type10.Boolean() })
26149
+ params: obj10({ ...subscription, taskId: count }, { open: true }),
26150
+ result: obj10({ stopped: bool5() }, { open: true })
25985
26151
  },
25986
26152
  "approvals.list": {
25987
- params: Type10.Object(subscription),
25988
- result: Type10.Object({ approvals: Type10.Array(MobileApprovalSchema) })
26153
+ params: obj10(subscription, { open: true }),
26154
+ result: obj10({ approvals: arr8(MobileApprovalSchema) }, { open: true })
25989
26155
  },
25990
- "approvals.get": { params: Type10.Object({ ...subscription, id: int }), result: MobileApprovalSchema },
26156
+ "approvals.get": { params: obj10({ ...subscription, id: count }, { open: true }), result: MobileApprovalSchema },
25991
26157
  "approvals.decide": {
25992
- params: Type10.Object({
26158
+ params: obj10({
25993
26159
  ...subscription,
25994
- taskId: int,
25995
- id: int,
25996
- version: Type10.String({ minLength: 1 }),
25997
- decision: Type10.Union([Type10.Literal("allow"), Type10.Literal("deny")])
25998
- }),
25999
- result: Type10.Object({
26000
- status: Type10.Union([
26001
- Type10.Literal("pending"),
26002
- Type10.Literal("allowed"),
26003
- Type10.Literal("denied"),
26004
- Type10.Literal("cancelled")
26005
- ])
26006
- })
26160
+ taskId: count,
26161
+ id: count,
26162
+ version: str10({ minLength: 1 }),
26163
+ decision: union6([lit5("allow"), lit5("deny")])
26164
+ }, { open: true }),
26165
+ result: obj10({
26166
+ status: union6([lit5("pending"), lit5("allowed"), lit5("denied"), lit5("cancelled")])
26167
+ }, { open: true })
26007
26168
  },
26008
- "todos.get": { params: Type10.Object(subscription), result: MobileTodoListSchema },
26009
- "questions.list": { params: Type10.Object(subscription), result: MobileQuestionListSchema },
26010
- "questions.get": { params: Type10.Object({ ...subscription, id: int }), result: MobileQuestionSchema },
26169
+ "todos.get": { params: obj10(subscription, { open: true }), result: MobileTodoListSchema },
26170
+ "questions.list": { params: obj10(subscription, { open: true }), result: MobileQuestionListSchema },
26171
+ "questions.get": { params: obj10({ ...subscription, id: count }, { open: true }), result: MobileQuestionSchema },
26011
26172
  "questions.respond": {
26012
- params: Type10.Object({
26173
+ params: obj10({
26013
26174
  ...subscription,
26014
- id: int,
26015
- version: Type10.String({ minLength: 1 }),
26175
+ id: count,
26176
+ version: str10({ minLength: 1 }),
26016
26177
  response: MobileQuestionResponseSchema
26017
- }),
26178
+ }, { open: true }),
26018
26179
  result: MobileQuestionSchema
26019
26180
  },
26020
26181
  "plan.get": {
26021
- params: Type10.Object({ ...subscription, version: Type10.String({ minLength: 1 }) }),
26182
+ params: obj10({ ...subscription, version: str10({ minLength: 1 }) }, { open: true }),
26022
26183
  result: MobilePlanSchema
26023
26184
  },
26024
26185
  "plan.respond": {
26025
- params: Type10.Object({
26186
+ params: obj10({
26026
26187
  ...subscription,
26027
- version: Type10.String({ minLength: 1 }),
26188
+ version: str10({ minLength: 1 }),
26028
26189
  decision: MobilePlanDecisionSchema
26029
- }),
26190
+ }, { open: true }),
26030
26191
  result: MobilePlanSchema
26031
26192
  },
26032
26193
  "plan.exit": {
26033
- params: Type10.Object(subscription),
26034
- result: Type10.Object({ mode: Type10.Literal("normal"), revision: int })
26194
+ params: obj10(subscription, { open: true }),
26195
+ result: obj10({ mode: lit5("normal"), revision: count }, { open: true })
26035
26196
  },
26036
26197
  "media.read": {
26037
- params: Type10.Object({
26198
+ params: obj10({
26038
26199
  ...subscription,
26039
- agentId: opt(Type10.String({ minLength: 1 })),
26040
- entryId: int,
26041
- contentIndex: int,
26042
- offset: int
26043
- }),
26044
- result: Type10.Object({ ...chunkResult.properties, mimeType: str2 })
26200
+ agentId: opt10(str10({ minLength: 1 })),
26201
+ entryId: count,
26202
+ contentIndex: count,
26203
+ offset: count
26204
+ }, { open: true }),
26205
+ result: obj10({ ...chunkResultProperties, mimeType: text4 }, { open: true })
26045
26206
  }
26046
26207
  };
26047
26208
  function buildHelloResultSchema() {
26048
- return Type10.Object({
26049
- apiVersion: Type10.Integer({ minimum: 1 }),
26050
- serverId: str2,
26051
- serverName: str2,
26052
- gatewayVersion: str2,
26053
- capabilities: Type10.Array(str2),
26054
- limits: Type10.Object({
26055
- maxFrameBytes: Type10.Integer(),
26056
- maxPayloadBytes: Type10.Integer(),
26057
- pageItems: Type10.Integer(),
26058
- chunkBytes: Type10.Integer(),
26059
- maxConcurrentRequests: Type10.Integer(),
26060
- maxSendBufferBytes: Type10.Integer()
26061
- })
26062
- });
26209
+ return obj10({
26210
+ apiVersion: int7({ minimum: 1 }),
26211
+ serverId: text4,
26212
+ serverName: text4,
26213
+ gatewayVersion: text4,
26214
+ capabilities: arr8(text4),
26215
+ limits: obj10({
26216
+ maxFrameBytes: int7(),
26217
+ maxPayloadBytes: int7(),
26218
+ pageItems: int7(),
26219
+ chunkBytes: int7(),
26220
+ maxConcurrentRequests: int7(),
26221
+ maxSendBufferBytes: int7()
26222
+ }, { open: true })
26223
+ }, { open: true });
26063
26224
  }
26064
26225
  var patchBody = {
26065
- seq: Type10.Integer({ minimum: 1 }),
26066
- upserts: Type10.Array(MobileChatItemSchema),
26067
- status: opt(MobileChatStatusSchema),
26068
- streaming: opt(nullable2(MobileStreamingSchema)),
26069
- streamingAppend: opt(Type10.Object({ text: opt(str2), thinking: opt(str2) }))
26226
+ seq: int7({ minimum: 1 }),
26227
+ upserts: arr8(MobileChatItemSchema),
26228
+ status: opt10(MobileChatStatusSchema),
26229
+ streaming: opt10(nullable2(MobileStreamingSchema)),
26230
+ streamingAppend: opt10(obj10({ text: opt10(text4), thinking: opt10(text4) }, { open: true }))
26070
26231
  };
26071
26232
  var MOBILE_API_V1_NOTIFICATIONS = {
26072
- "workspaces.changed": Type10.Object({ revision: Type10.Integer({ minimum: 1 }) }),
26073
- "sessions.changed": Type10.Object({ revision: Type10.Integer({ minimum: 1 }) }),
26074
- "chat.patch": Type10.Object({ subscriptionId: str2, ...patchBody }),
26075
- "chat.reset": Type10.Object({ subscriptionId: str2, seq: Type10.Integer({ minimum: 1 }) }),
26076
- "subagents.patch": Type10.Object({ subagentSubscriptionId: str2, ...patchBody }),
26077
- "subagents.reset": Type10.Object({ subagentSubscriptionId: str2, seq: Type10.Integer({ minimum: 1 }) }),
26078
- "approvals.changed": Type10.Object({ subscriptionId: str2, revision: Type10.Integer({ minimum: 1 }) }),
26079
- "todos.changed": Type10.Object({ subscriptionId: str2, revision: Type10.Integer({ minimum: 1 }) }),
26080
- "questions.changed": Type10.Object({ subscriptionId: str2, revision: Type10.Integer({ minimum: 1 }) }),
26081
- "plan.changed": Type10.Object({ subscriptionId: str2, revision: Type10.Integer({ minimum: 1 }) })
26233
+ "workspaces.changed": obj10({ revision: int7({ minimum: 1 }) }, { open: true }),
26234
+ "sessions.changed": obj10({ revision: int7({ minimum: 1 }) }, { open: true }),
26235
+ "chat.patch": obj10({ subscriptionId: text4, ...patchBody }, { open: true }),
26236
+ "chat.reset": obj10({ subscriptionId: text4, seq: int7({ minimum: 1 }) }, { open: true }),
26237
+ "subagents.patch": obj10({ subagentSubscriptionId: text4, ...patchBody }, { open: true }),
26238
+ "subagents.reset": obj10({ subagentSubscriptionId: text4, seq: int7({ minimum: 1 }) }, { open: true }),
26239
+ "approvals.changed": obj10({ subscriptionId: text4, revision: int7({ minimum: 1 }) }, { open: true }),
26240
+ "todos.changed": obj10({ subscriptionId: text4, revision: int7({ minimum: 1 }) }, { open: true }),
26241
+ "questions.changed": obj10({ subscriptionId: text4, revision: int7({ minimum: 1 }) }, { open: true }),
26242
+ "plan.changed": obj10({ subscriptionId: text4, revision: int7({ minimum: 1 }) }, { open: true })
26082
26243
  };
26083
26244
 
26084
26245
  // packages/gateway/src/mobile/projection.ts
@@ -26120,12 +26281,12 @@ function utf8Prefix(value, maxBytes) {
26120
26281
  function jsonBytes2(value) {
26121
26282
  return Buffer.byteLength(JSON.stringify(value), "utf8");
26122
26283
  }
26123
- var count = (value) => Math.max(0, Math.round(value ?? 0));
26284
+ var count2 = (value) => Math.max(0, Math.round(value ?? 0));
26124
26285
  function mapUsage(usage) {
26125
- const input = count(usage.input);
26126
- const output = count(usage.output);
26127
- const cacheRead = count(usage.cacheRead);
26128
- const cacheWrite = count(usage.cacheWrite);
26286
+ const input = count2(usage.input);
26287
+ const output = count2(usage.output);
26288
+ const cacheRead = count2(usage.cacheRead);
26289
+ const cacheWrite = count2(usage.cacheWrite);
26129
26290
  return {
26130
26291
  input,
26131
26292
  output,
@@ -26177,9 +26338,9 @@ function mapChatItem(raw, owner) {
26177
26338
  images: list.map((image) => ({
26178
26339
  name: image.name,
26179
26340
  mimeType: image.mimeType,
26180
- width: count(image.width),
26181
- height: count(image.height),
26182
- bytes: count(image.bytes),
26341
+ width: count2(image.width),
26342
+ height: count2(image.height),
26343
+ bytes: count2(image.bytes),
26183
26344
  entryId: image.entryId,
26184
26345
  contentIndex: image.contentIndex
26185
26346
  }))
@@ -26266,7 +26427,7 @@ function mapRound(round, readonlyRound) {
26266
26427
  role: round.role,
26267
26428
  title: round.title,
26268
26429
  status: round.status,
26269
- approvalCount: count(round.approvalCount),
26430
+ approvalCount: count2(round.approvalCount),
26270
26431
  readonly: readonlyRound || round.historyThrough !== undefined,
26271
26432
  createdAt: round.createdAt,
26272
26433
  endedAt: round.endedAt,
@@ -26283,7 +26444,7 @@ function mapStatus(view, options = {}) {
26283
26444
  activeRoundId: agent.activeRoundId,
26284
26445
  lastRoundId: agent.lastRoundId,
26285
26446
  roundCount: agent.roundCount,
26286
- approvalCount: count(agent.approvalCount)
26447
+ approvalCount: count2(agent.approvalCount)
26287
26448
  }));
26288
26449
  const approvalCount = view.approvals !== undefined ? view.approvals.filter((approval) => approval.status === "pending").length : rounds.reduce((sum, round) => sum + round.approvalCount, 0);
26289
26450
  const latest = view.compaction?.latest;
@@ -26319,6 +26480,12 @@ function mapStatus(view, options = {}) {
26319
26480
  agents,
26320
26481
  approvalCount,
26321
26482
  ...latest ? { compaction: { phase: latest.phase, at: latest.at } } : {},
26483
+ ...view.runFailure === undefined ? {} : {
26484
+ runFailure: {
26485
+ reason: view.runFailure.reason,
26486
+ ...view.runFailure.detail === undefined ? {} : { detail: view.runFailure.detail }
26487
+ }
26488
+ },
26322
26489
  ...options.readonly === undefined ? {} : { readonly: options.readonly }
26323
26490
  };
26324
26491
  }
@@ -26761,12 +26928,12 @@ class MobileAdapter {
26761
26928
  this.sendError(id, -32601, "method not found", { code: "not_found" });
26762
26929
  return;
26763
26930
  }
26764
- if (!Check2(spec.params, params)) {
26931
+ if (!checkSchema(spec.params, params)) {
26765
26932
  this.sendError(id, -32602, "invalid params", { code: "invalid_params" });
26766
26933
  return;
26767
26934
  }
26768
26935
  const result = await this.invoke(method, params);
26769
- if (!Check2(spec.result, result)) {
26936
+ if (!checkSchema(spec.result, result)) {
26770
26937
  this.onError?.(new Error(`mobile result for ${method} does not match its schema`));
26771
26938
  this.sendError(id, -32603, "internal result mismatch", { code: "internal" });
26772
26939
  return;
@@ -28897,6 +29064,7 @@ async function removeGatewayPortFile(nekoDir, serverId) {
28897
29064
  // packages/gateway/src/server-services.ts
28898
29065
  import { randomUUID as randomUUID6 } from "crypto";
28899
29066
  import { ChordError as ChordError5, local as local3, method as method2 } from "@earendil-works/chord";
29067
+ import { nul as nul6, obj as obj13 } from "@earendil-works/pi-schema";
28900
29068
 
28901
29069
  // packages/core/src/application-updates.ts
28902
29070
  import { mkdir as mkdir3, readFile as readFile6, rm as rm3, writeFile as writeFile3 } from "fs/promises";
@@ -29045,9 +29213,6 @@ class UpdateChecker {
29045
29213
  }
29046
29214
  }
29047
29215
 
29048
- // packages/gateway/src/server-services.ts
29049
- import { Type as Type13 } from "typebox";
29050
-
29051
29216
  // packages/gateway/src/session-host.ts
29052
29217
  import { open as open3 } from "fs/promises";
29053
29218
  import { basename as basename3, extname } from "path";
@@ -29058,7 +29223,7 @@ import {
29058
29223
  } from "@earendil-works/chord";
29059
29224
  import { withAbortSignal as withAbortSignal4 } from "@earendil-works/chord/context";
29060
29225
  import { UsageDoc as UsageDoc4 } from "@earendil-works/pi-durable";
29061
- import { Type as Type12 } from "typebox";
29226
+ import { obj as obj12, str as str12 } from "@earendil-works/pi-schema";
29062
29227
 
29063
29228
  // packages/gateway/src/image-uploads.ts
29064
29229
  var IMAGE_CHUNK_BYTES = 256 * 1024;
@@ -29157,18 +29322,23 @@ class ImageUploads {
29157
29322
  // packages/gateway/src/subagent-host.ts
29158
29323
  import { ChordError as ChordError3, local, opaque } from "@earendil-works/chord";
29159
29324
  import { UsageDoc as UsageDoc3 } from "@earendil-works/pi-durable";
29160
- import { Type as Type11 } from "typebox";
29325
+ import { int as int8, obj as obj11, str as str11 } from "@earendil-works/pi-schema";
29161
29326
  async function openReader(runtime, childId, parentId, context, through, historyUsage) {
29162
29327
  const child = await runtime.harness.conversation(childId, context);
29163
29328
  if (!child)
29164
29329
  throw new ChordError3("gone", "Subagent unavailable");
29165
- const native = await child.viewState(context);
29330
+ const native = await child.watch(context);
29331
+ const listeners = new Set;
29166
29332
  if (through !== undefined)
29167
- native.dispose();
29333
+ await native.stop();
29334
+ else
29335
+ native.start(async () => {
29336
+ for (const listener of listeners)
29337
+ listener();
29338
+ });
29168
29339
  const project = (entries, streaming = true) => {
29169
29340
  const result = projectChatView({ ...native.value, entries: [...entries].sort((a, b) => a.id - b.id) }, "", {
29170
- models: runtime.listModels(),
29171
- contextEntries: native.value.entries
29341
+ models: runtime.listModels()
29172
29342
  });
29173
29343
  if (!streaming || through !== undefined) {
29174
29344
  result.streaming = null;
@@ -29217,8 +29387,10 @@ async function openReader(runtime, childId, parentId, context, through, historyU
29217
29387
  subscribe: (fn) => {
29218
29388
  if (through !== undefined)
29219
29389
  return () => {};
29220
- const stop = native.subscribe(() => fn(null));
29221
- const stopApprovals = runtime.harness.subscribeCommits(({ changes }) => {
29390
+ const listener = () => fn(null);
29391
+ listeners.add(listener);
29392
+ const stop = () => listeners.delete(listener);
29393
+ const stopApprovals = onCommits(runtime.harness, ({ changes }) => {
29222
29394
  if (changes.some((c) => c.type === "document" && ["app.neko.approvals", "app.neko.delegations", "app.neko.subagents"].includes(c.record.kind) && c.conversationId === parentId))
29223
29395
  fn(null);
29224
29396
  });
@@ -29277,20 +29449,23 @@ async function openReader(runtime, childId, parentId, context, through, historyU
29277
29449
  mimeType: image.mimeType
29278
29450
  };
29279
29451
  },
29280
- close: () => native.dispose()
29452
+ close: () => {
29453
+ listeners.clear();
29454
+ native.stop();
29455
+ }
29281
29456
  };
29282
29457
  }
29283
29458
  var ChildProjection = local("neko.subagent-projection", {
29284
29459
  version: 1,
29285
- input: Type11.Object({ parentId: Type11.Integer(), agentId: Type11.String() }),
29460
+ input: obj11({ parentId: int8(), agentId: str11() }, { open: true }),
29286
29461
  members: {
29287
- revision: Type11.Integer(),
29462
+ revision: int8(),
29288
29463
  reader: opaque("neko.subagent-reader@1")
29289
29464
  }
29290
29465
  });
29291
29466
  function installSubagentHost(host, runtime, context) {
29292
29467
  host.serve(ChildProjection, (input, _principal, self2) => {
29293
- const revision = self2.state("revision", Type11.Integer(), 0);
29468
+ const revision = self2.state("revision", int8(), 0);
29294
29469
  const reader = self2.resource("reader", {
29295
29470
  version: 1,
29296
29471
  async open() {
@@ -29331,7 +29506,7 @@ function installSubagentHost(host, runtime, context) {
29331
29506
  parentId: Number(input.sessionId),
29332
29507
  agentId: input.agentId ?? `round-${input.taskId}`
29333
29508
  });
29334
- const authorizedRevision = self2.state("authorizedRevision", Type11.Integer(), 0);
29509
+ const authorizedRevision = self2.state("authorizedRevision", int8(), 0);
29335
29510
  self2.on("authorizedView", shared.revision, async (value, ctx) => {
29336
29511
  try {
29337
29512
  target.value;
@@ -29384,7 +29559,7 @@ function installSubagentHost(host, runtime, context) {
29384
29559
  }
29385
29560
 
29386
29561
  // packages/gateway/src/session-host.ts
29387
- var OwnerInput = Type12.Object({});
29562
+ var OwnerInput = obj12({}, { open: true });
29388
29563
  var Owner = local2("neko.attachment-owner", {
29389
29564
  version: 1,
29390
29565
  input: OwnerInput,
@@ -29392,7 +29567,7 @@ var Owner = local2("neko.attachment-owner", {
29392
29567
  });
29393
29568
  var Projection = local2("neko.projection", {
29394
29569
  version: 1,
29395
- input: Type12.Object({ id: Type12.String() }),
29570
+ input: obj12({ id: str12() }, { open: true }),
29396
29571
  members: {
29397
29572
  view: ChatViewSchema,
29398
29573
  reader: opaque2("neko.projection-reader@1")
@@ -29412,20 +29587,12 @@ var emptyView = {
29412
29587
  var JOB_COMMAND_PREVIEW_CHARS = 1000;
29413
29588
  var clipJob = (job) => job.command.length > JOB_COMMAND_PREVIEW_CHARS ? { ...job, command: `${job.command.slice(0, JOB_COMMAND_PREVIEW_CHARS)}\u2026` } : job;
29414
29589
  async function openProjection(runtime, session, context) {
29415
- const view = await session.viewState();
29416
- const history = new Map;
29417
- let cursor;
29418
- do {
29419
- const page = await session.conversation.entries({ order: "ascending" }, 100, cursor, context);
29420
- for (const entry of page.items)
29421
- history.set(entry.id, entry);
29422
- cursor = page.next;
29423
- } while (cursor);
29590
+ const view = await session.follow();
29424
29591
  let changed;
29425
29592
  const stop = view.subscribe(() => changed?.(null));
29426
29593
  const stopMetadata = runtime.onDirectoryChange(() => changed?.(null));
29427
29594
  let childIds = new Set;
29428
- const stopChildren = runtime.harness.subscribeCommits(({ changes }) => {
29595
+ const stopChildren = onCommits(runtime.harness, ({ changes }) => {
29429
29596
  if (changes.some((change) => change.type === "entry" && change.value.kind === "pi.tool-result" && childIds.has(change.value.conversationId) || change.type === "document" && ([
29430
29597
  "app.neko.delegations",
29431
29598
  "app.neko.approvals",
@@ -29446,12 +29613,9 @@ async function openProjection(runtime, session, context) {
29446
29613
  };
29447
29614
  },
29448
29615
  async project() {
29449
- for (const entry of view.value.entries)
29450
- history.set(entry.id, entry);
29451
29616
  const [naming, compaction] = await Promise.all([runtime.namingUsage(session.id), session.compactionRecord()]);
29452
29617
  const projected = projectChatView({
29453
29618
  ...view.value,
29454
- entries: [...history.values()].sort((a, b) => a.id - b.id),
29455
29619
  docs: {
29456
29620
  ...view.value.docs,
29457
29621
  "pi.usage": mergeUsage(view.value.docs["pi.usage"] ?? {
@@ -29459,7 +29623,7 @@ async function openProjection(runtime, session, context) {
29459
29623
  tools: {}
29460
29624
  }, naming)
29461
29625
  }
29462
- }, "", { models: runtime.listModels(), contextEntries: view.value.entries, compaction });
29626
+ }, "", { models: runtime.listModels(), compaction });
29463
29627
  const jobs = (await session.jobs()).map(clipJob);
29464
29628
  const [todos, questions, plan] = await Promise.all([session.todos(), session.questions(), session.plan()]);
29465
29629
  const changes = await session.changeSummary().catch(() => {
@@ -29500,16 +29664,13 @@ async function openProjection(runtime, session, context) {
29500
29664
  },
29501
29665
  async entry(id, ctx) {
29502
29666
  ctx.abortSignal?.throwIfAborted();
29503
- for (const entry of view.value.entries)
29504
- history.set(entry.id, entry);
29505
- return history.get(id);
29667
+ return view.entry(id);
29506
29668
  },
29507
29669
  close() {
29508
29670
  stop();
29509
29671
  stopMetadata();
29510
29672
  stopChildren();
29511
29673
  view.dispose();
29512
- history.clear();
29513
29674
  }
29514
29675
  };
29515
29676
  }
@@ -29685,6 +29846,14 @@ function serveSessions(host, runtime, context) {
29685
29846
  await projection.value.session.abort();
29686
29847
  return null;
29687
29848
  },
29849
+ continueRun: async () => {
29850
+ try {
29851
+ await projection.value.session.continueRun();
29852
+ return null;
29853
+ } catch (error) {
29854
+ throw new ChordError4("invalid", error instanceof Error ? error.message : "Cannot continue");
29855
+ }
29856
+ },
29688
29857
  withdraw: ({ id }) => projection.value.session.withdraw(id),
29689
29858
  steer: ({ id }) => projection.value.session.steer(id),
29690
29859
  questionGet: async ({ id }) => await projection.value.session.question(id) ?? null,
@@ -30504,7 +30673,7 @@ async function listDrives() {
30504
30673
  // packages/gateway/src/server-services.ts
30505
30674
  var ServerState = local3("neko.server-state", {
30506
30675
  version: 1,
30507
- input: Type13.Object({}),
30676
+ input: obj13({}, { open: true }),
30508
30677
  members: {
30509
30678
  directory: DirectoryStateSchema,
30510
30679
  workspaces: WorkspaceStateSchema,
@@ -30513,11 +30682,11 @@ var ServerState = local3("neko.server-state", {
30513
30682
  contextSettings: ContextSettingsStateSchema,
30514
30683
  codemodeSettings: CodemodeSettingsStateSchema,
30515
30684
  defaultModel: DefaultModelStateSchema,
30516
- refreshCredentials: method2(Type13.Null(), Type13.Null()),
30517
- refreshSearchSettings: method2(Type13.Null(), Type13.Null()),
30518
- refreshContextSettings: method2(Type13.Null(), Type13.Null()),
30519
- refreshCodemodeSettings: method2(Type13.Null(), Type13.Null()),
30520
- refreshDefaultModel: method2(Type13.Null(), Type13.Null())
30685
+ refreshCredentials: method2(nul6(), nul6()),
30686
+ refreshSearchSettings: method2(nul6(), nul6()),
30687
+ refreshContextSettings: method2(nul6(), nul6()),
30688
+ refreshCodemodeSettings: method2(nul6(), nul6()),
30689
+ refreshDefaultModel: method2(nul6(), nul6())
30521
30690
  }
30522
30691
  });
30523
30692
  async function createNekoServerServices(options) {
@@ -30663,7 +30832,7 @@ async function createNekoServerServices(options) {
30663
30832
  searchSettings.replace(ctx, { revision: current.revision + 1, ...next });
30664
30833
  return null;
30665
30834
  };
30666
- self2.on("directory", { subscribe: runtime.harness.subscribeCommits.bind(runtime.harness) }, async (event, ctx) => {
30835
+ self2.on("directory", { subscribe: (listener) => onCommits(runtime.harness, listener) }, async (event, ctx) => {
30667
30836
  if (!event.changes.some((change) => change.type === "conversation" || change.type === "document" && [
30668
30837
  "app.neko.session-metadata",
30669
30838
  "app.neko.activity",
@@ -31107,6 +31276,7 @@ async function startGateway(options = {}) {
31107
31276
  ...searchProvider !== undefined ? { searchProvider } : {},
31108
31277
  ...fileConfig.context !== undefined ? { contextSettings: fileConfig.context } : {},
31109
31278
  ...fileConfig.codemode !== undefined ? { codemodeSettings: fileConfig.codemode } : {},
31279
+ ...fileConfig.maxTurns !== undefined ? { maxTurns: fileConfig.maxTurns } : {},
31110
31280
  ...fileConfig.defaultModel !== undefined ? { model: fileConfig.defaultModel } : {},
31111
31281
  ...options.model !== undefined ? { modelOverride: options.model } : {},
31112
31282
  thinkingLevel: options.thinkingLevel ?? fileConfig.thinkingLevel ?? "high",
@@ -31232,7 +31402,7 @@ async function bindGateway(runtime, options) {
31232
31402
  }
31233
31403
  };
31234
31404
  runtime.closed.then(async (result) => {
31235
- if (result.reason === "failed") {
31405
+ if (result.kind === "failed") {
31236
31406
  options.onError?.(new Error("Gateway storage failed"));
31237
31407
  await gateway.close();
31238
31408
  }