@krapht/ork 1.0.0-alpha.12 → 1.0.0-alpha.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/dist/{__build_info__-BJbE3Zvp.mjs → __build_info__-B82-dGJY.mjs} +3 -3
  2. package/dist/{attach-BmV5ckb9.mjs → attach-CdtGX9se.mjs} +5 -5
  3. package/dist/bin.mjs +274 -236
  4. package/dist/{builtin-files-w0YULJ4c.mjs → builtin-files-Bdq23IIi.mjs} +2 -2
  5. package/dist/{chips-CyeB_rhR.mjs → chips-BqcT58qr.mjs} +1 -1
  6. package/dist/{completion-CzElB8nS.mjs → completion--ywde-56.mjs} +52 -11
  7. package/dist/{context-BAwgVSX5.mjs → context-Y_I4Mofq.mjs} +18 -8
  8. package/dist/{find-p05wlbmu.mjs → find-BVX-bL4u.mjs} +1 -1
  9. package/dist/{format-Dni98cbh.mjs → format-CvTE5CZQ.mjs} +12 -12
  10. package/dist/{help-groups-DYP_zMRP.mjs → help-groups-CpR2UzSn.mjs} +20 -6
  11. package/dist/{in-a-run-BI-hLIl_.mjs → in-a-run-cL5N9gpH.mjs} +1 -1
  12. package/dist/{limits-CElmhowV.mjs → limits-Dhe--wmX.mjs} +2 -2
  13. package/dist/{mcp-CM3b65AZ.mjs → mcp-CsmboyXv.mjs} +6 -6
  14. package/dist/once-CrwI-ZdN.mjs +76 -0
  15. package/dist/{output-CnRzrbUM.mjs → output-B1kwo0YU.mjs} +17 -1
  16. package/dist/{pause-BuS83WAI.mjs → pause-DssrYcda.mjs} +4 -4
  17. package/dist/{relay-DAsJA8wF.mjs → relay-DASRgsTQ.mjs} +2 -2
  18. package/dist/run-D8divGCs.mjs +192 -0
  19. package/dist/send-CXv8bx0i.mjs +105 -0
  20. package/dist/{src-S9yK2OHU.mjs → src-8Mul0695.mjs} +8 -10
  21. package/dist/{src-BfxkJOYm.mjs → src-C7z_6fhn.mjs} +200 -72
  22. package/dist/{src-D1QedD5y.mjs → src-njdtejgZ.mjs} +140 -38
  23. package/dist/{src-CdDTQLdQ.mjs → src-tsuZRu0H.mjs} +2787 -1134
  24. package/dist/{store-B2OaE4ID.mjs → store-CleF7KeS.mjs} +33 -76
  25. package/dist/ui/THIRD_PARTY_LICENSES.txt +18 -0
  26. package/dist/ui/assets/app-D_nAPnHM.css +1 -0
  27. package/dist/ui/assets/app-DqBAtXSZ.js +111 -0
  28. package/dist/ui/assets/{index-BL7Ad0OA.js → index-D-_uPI2v.js} +2 -2
  29. package/dist/ui/index.html +1 -1
  30. package/dist/{ui-C4Ys26oO.mjs → ui-CNO1M0qT.mjs} +4 -4
  31. package/dist/{usage-C2zx-X6q.mjs → usage-BVXi0iFY.mjs} +13 -141
  32. package/dist/{verdict-CIy8tAyX.mjs → verdict-CMvPCpWC.mjs} +2 -2
  33. package/dist/{watch-DzCeqM05.mjs → watch-DVNIciHp.mjs} +10 -8
  34. package/dist/{workflows-Rr5w90A0.mjs → workflows-B30QkwTk.mjs} +3 -3
  35. package/dist/{worktrees-f6SAbum5.mjs → worktrees-DD4_TpkH.mjs} +3 -5
  36. package/package.json +2 -2
  37. package/dist/clean-D8GI_2K-.mjs +0 -91
  38. package/dist/decide-DlbyctOE.mjs +0 -50
  39. package/dist/list-zW2xKuGr.mjs +0 -117
  40. package/dist/remove-Dh7D_hVn.mjs +0 -201
  41. package/dist/report-CEN8VoUb.mjs +0 -140
  42. package/dist/send-MFEQZH31.mjs +0 -163
  43. package/dist/ui/assets/app-CAoZtku5.js +0 -75
  44. package/dist/ui/assets/app-QoHVi-mb.css +0 -1
@@ -1,4 +1,4 @@
1
- import { Ar as AGENT_DRIVERS, Bt as lowerChild, En as maskSecrets, Vt as startAt, an as FEEDBACK_SEVERITIES, en as outcomeEnd, ft as parseReport, in as FEEDBACK_KINDS, nn as END_KINDS, on as FEEDBACK_TARGETS, rn as endFor, wn as MASK } from "./src-CdDTQLdQ.mjs";
1
+ import { $n as maskSecrets, $t as countedTokens, An as END_KINDS, Mn as FEEDBACK_KINDS, Nn as FEEDBACK_SEVERITIES, On as outcomeEnd, Pn as FEEDBACK_TARGETS, Pt as parseReport, Zn as MASK, ii as AGENT_DRIVERS, jn as endFor, ln as lowerChild, un as startAt } from "./src-tsuZRu0H.mjs";
2
2
  import path from "node:path";
3
3
  import { z } from "zod";
4
4
  import { existsSync, linkSync, mkdirSync, mkdtempSync, readFileSync, readdirSync, realpathSync, renameSync, rmSync, writeFileSync } from "node:fs";
@@ -448,7 +448,8 @@ const classifyProviderError = (text, status) => {
448
448
  * it can see (a turn cap, an exit code, a provider's error), and the report
449
449
  * the session handed in decides the rest. The runner then writes the end in
450
450
  * the node's numbers, its detail scrubbed with the feedback redactor. A
451
- * session the driver could not run ends as `driverFailure` says.
451
+ * session the driver could not run ends as `driverFailure` says, and one that
452
+ * reached its token cap as `tokenCapOutcome` says.
452
453
  */
453
454
  /** The end a report gives: done, a reported failure, or none handed in. */
454
455
  const reportEnd = (report) => {
@@ -479,6 +480,36 @@ const settleEnd = (outcome, facts, scrub) => {
479
480
  };
480
481
  };
481
482
  /**
483
+ * What a session's end is written with: the node's limits and program, and its
484
+ * folder and the home folder taken out of the detail.
485
+ */
486
+ const scopeOf = (spec, bin, env) => ({
487
+ facts: {
488
+ ...spec.maxTurns === void 0 ? {} : { maxTurns: spec.maxTurns },
489
+ ...spec.budgetUsd === void 0 ? {} : { budgetUsd: spec.budgetUsd },
490
+ ...spec.budgetTokens === void 0 ? {} : { budgetTokens: spec.budgetTokens },
491
+ program: path.basename(bin)
492
+ },
493
+ scrub: {
494
+ roots: [spec.cwd],
495
+ home: env["HOME"] ?? homedir()
496
+ }
497
+ });
498
+ /**
499
+ * The outcome of a session stopped once its counted tokens (RFC-015) reach
500
+ * `budgetTokens`: `budget_limit`, with what it used so far; `undefined` under
501
+ * the cap, or with none.
502
+ */
503
+ const tokenCapOutcome = ({ budgetTokens }, usage, sessionId) => budgetTokens === void 0 || usage === void 0 || countedTokens(usage) < budgetTokens ? void 0 : {
504
+ subtype: "error_max_budget_tokens",
505
+ end: endFor("budget_limit"),
506
+ sessionId,
507
+ report: null,
508
+ text: "",
509
+ usage,
510
+ errors: [`Reached the token budget (${String(budgetTokens)})`]
511
+ };
512
+ /**
482
513
  * The kind of a failure to run the driver: its program missing, else what a
483
514
  * provider's words in it say, else a crash.
484
515
  */
@@ -534,6 +565,15 @@ const settled = (outcome, input) => settleEnd(input.reported === void 0 ? outcom
534
565
  ...outcome,
535
566
  report: input.reported()
536
567
  }, input.scope.facts, input.scope.scrub);
568
+ /** The session's end at its token cap, its earlier legs' usage included. */
569
+ const tokenCapEnd = (input, used, sessionId) => {
570
+ const usage = used === void 0 || input.carried === void 0 ? used : input.adapter.usage.combine(input.carried, used);
571
+ const capped = tokenCapOutcome(input.scope.facts, usage, sessionId);
572
+ return capped === void 0 ? void 0 : {
573
+ type: "session.finished",
574
+ outcome: settled(capped, input)
575
+ };
576
+ };
537
577
  /** The kinds of a session that ended well, so a queued message continues it. */
538
578
  const wentWell = (kind) => kind === "done" || kind === "reported_failure" || kind === "no_report";
539
579
  /**
@@ -639,16 +679,26 @@ const runLeg = async function* (input) {
639
679
  for (const line of input.pending.splice(0)) write(line);
640
680
  if (input.adapter.command.input === void 0) child.stdin.end();
641
681
  let outcome;
682
+ let sessionId = "";
642
683
  const { decoder } = input;
643
684
  const decode = decoder?.decode ?? input.adapter.decode;
644
685
  try {
645
686
  for await (const line of createInterface({ input: child.stdout })) {
646
- const { events, ended } = legStep(decode(line), input);
687
+ const decoded = decode(line);
688
+ const { events, ended } = legStep(decoded, input);
689
+ for (const event of decoded.events) if (event.type === "session.started") sessionId = event.sessionId;
647
690
  yield* events;
648
691
  if (ended !== void 0) {
649
692
  child.stdin.end();
650
693
  outcome = ended;
651
694
  }
695
+ const capped = outcome === void 0 ? tokenCapEnd(input, decoded.usage, sessionId) : void 0;
696
+ if (capped !== void 0) {
697
+ stopped = true;
698
+ child.kill("SIGINT");
699
+ yield capped;
700
+ return { kind: "finished" };
701
+ }
652
702
  }
653
703
  const end = await Promise.race([exited, spawnError.then((error) => error)]);
654
704
  if (outcome !== void 0) return outcome;
@@ -969,7 +1019,7 @@ const permissionTool = defineTool({
969
1019
  * kept as the session's report, and the session runner ends the session with
970
1020
  * it instead of what the tool's last line says.
971
1021
  */
972
- const REPORT_TOOL = "report";
1022
+ const REPORT_TOOL$1 = "report";
973
1023
  /** Whether the driver holds a session's final answer to its schema itself. */
974
1024
  const checksItsReport = (driver) => AGENT_DRIVERS.find((d) => d.id === driver)?.capabilities.reportSchema ?? true;
975
1025
  /**
@@ -985,13 +1035,13 @@ const reportValidator = (schema) => {
985
1035
  }
986
1036
  };
987
1037
  const failed = (why) => ({
988
- ...text(`The report was not accepted; fix it and call ${REPORT_TOOL} again.\n${why}`),
1038
+ ...text(`The report was not accepted; fix it and call ${REPORT_TOOL$1} again.\n${why}`),
989
1039
  isError: true
990
1040
  });
991
1041
  const bound = (report) => {
992
1042
  const schema = reportValidator(report.schema);
993
1043
  return {
994
- name: REPORT_TOOL,
1044
+ name: REPORT_TOOL$1,
995
1045
  description: "Hand in your final report: call this once your work is done, as your last step, with the report the task asks for. A report that does not fit comes back with what to fix; call again with the fixed report. The last report accepted is the one your owner gets.",
996
1046
  shape: schema instanceof z.ZodObject ? schema.shape : {},
997
1047
  schema,
@@ -1025,7 +1075,7 @@ const ORK_TOOLS = [
1025
1075
  releaseTool,
1026
1076
  feedbackTool,
1027
1077
  {
1028
- name: REPORT_TOOL,
1078
+ name: REPORT_TOOL$1,
1029
1079
  bind: (context) => context.report === void 0 || checksItsReport(context.driver) ? null : bound(context.report)
1030
1080
  }
1031
1081
  ];
@@ -1034,33 +1084,6 @@ const orkTools = (context) => ORK_TOOLS.flatMap((tool) => tool.bind(context) ??
1034
1084
  /** Their Claude Code names, for the session's allowed tools. */
1035
1085
  const preapprovedTools = (tools) => tools.filter((t) => t.preapproved).map((t) => toolId(t.name));
1036
1086
  // ../runtime/src/session-runner.ts
1037
- /**
1038
- * @file The session runner: one agent CLI session, driven through an adapter's
1039
- * strategies (`adapter.ts`), written once for every driver. It serves Ork's
1040
- * tools on a local MCP endpoint, wires the session to it, and runs the tool
1041
- * as one or more processes (legs). A paused node's tool call is held, and
1042
- * past the hold window deferred; the next leg resumes the session once the
1043
- * node continues (ADR-041). A tool that takes no message mid-session gets one
1044
- * at the next leg, which resumes the session with it. A driver that cannot
1045
- * hold the final answer to the report schema gets Ork's `report` tool, and
1046
- * the session ends with the report it accepted. Interrupting stops the
1047
- * running process.
1048
- */
1049
- /**
1050
- * What a session's end is written with: the node's limits and program, and its
1051
- * folder and the home folder taken out of the detail.
1052
- */
1053
- const scopeOf = (spec, bin, env) => ({
1054
- facts: {
1055
- ...spec.maxTurns === void 0 ? {} : { maxTurns: spec.maxTurns },
1056
- ...spec.budgetUsd === void 0 ? {} : { budgetUsd: spec.budgetUsd },
1057
- program: path.basename(bin)
1058
- },
1059
- scrub: {
1060
- roots: [spec.cwd],
1061
- home: env["HOME"] ?? homedir()
1062
- }
1063
- });
1064
1087
  /** A spec that resumes `sessionId`; a fork's later legs continue the fork. */
1065
1088
  const resumed = (spec, sessionId) => ({
1066
1089
  ...spec,
@@ -1135,7 +1158,7 @@ const createSessionRuntime = (adapter, options = {}) => ({
1135
1158
  }
1136
1159
  }
1137
1160
  });
1138
- const byTool = tools.some((tool) => tool.name === REPORT_TOOL);
1161
+ const byTool = tools.some((tool) => tool.name === REPORT_TOOL$1);
1139
1162
  const mcp = await startOrkMcpHttp(tools, hold === void 0 || hook === void 0 ? void 0 : toolHook({
1140
1163
  hold,
1141
1164
  heavy,
@@ -1243,7 +1266,8 @@ const createSessionRuntime = (adapter, options = {}) => ({
1243
1266
  /**
1244
1267
  * @file The `claude-code` adapter's `EventDecoder` and `UsageReader`: maps the
1245
1268
  * `claude` CLI's `stream-json` lines to Ork's runtime events, marks the
1246
- * result of a turn the hold hook deferred, and adds up a session's legs.
1269
+ * result of a turn the hold hook deferred, and adds up a session's legs. Its
1270
+ * leg decoder keeps a report the session handed in and then wrote past.
1247
1271
  */
1248
1272
  const isObject$2 = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
1249
1273
  const get$1 = (value, key) => isObject$2(value) ? value[key] : void 0;
@@ -1378,6 +1402,56 @@ const decodeClaudeLine = (line) => {
1378
1402
  deferred: isDeferredResult(message)
1379
1403
  };
1380
1404
  };
1405
+ /** The tool `claude` hands a `--json-schema` report in with. */
1406
+ const REPORT_TOOL = "StructuredOutput";
1407
+ /**
1408
+ * A leg's decoder that keeps the last report `claude` accepted (a
1409
+ * `StructuredOutput` call whose result was not an error). When the session
1410
+ * writes on after it, `claude`'s result can come without `structured_output`;
1411
+ * the kept report is then the result's, so a session that reported is not read
1412
+ * as one that didn't.
1413
+ */
1414
+ const claudeDecoder = () => {
1415
+ const calls = /* @__PURE__ */ new Map();
1416
+ let accepted;
1417
+ /** Each model response's usage, by message id: its blocks repeat it. */
1418
+ const responses = /* @__PURE__ */ new Map();
1419
+ /** The leg's usage so far, when `message` is a model response. */
1420
+ const usageSoFar = (message) => {
1421
+ const inner = get$1(message, "message");
1422
+ const id = get$1(inner, "id");
1423
+ if (get$1(message, "type") !== "assistant" || typeof id !== "string") return;
1424
+ responses.set(id, {
1425
+ ...usageOf({ usage: get$1(inner, "usage") }),
1426
+ turns: 1
1427
+ });
1428
+ return [...responses.values()].reduce((a, b) => addUsage(a, b));
1429
+ };
1430
+ return {
1431
+ decode: (line) => {
1432
+ const message = parseLine$2(line);
1433
+ const usage = usageSoFar(message);
1434
+ for (const block of blocks(message)) {
1435
+ if (block["type"] === "tool_use" && block["name"] === REPORT_TOOL) calls.set(str$2(block["id"]), block["input"]);
1436
+ const id = str$2(block["tool_use_id"]);
1437
+ if (block["type"] === "tool_result" && calls.has(id)) {
1438
+ if (block["is_error"] !== true) accepted = calls.get(id);
1439
+ calls.delete(id);
1440
+ }
1441
+ }
1442
+ const kept = isObject$2(message) && message["type"] === "result" && (message["structured_output"] ?? null) === null && accepted !== void 0 ? {
1443
+ ...message,
1444
+ structured_output: accepted
1445
+ } : message;
1446
+ return {
1447
+ events: normalize(kept),
1448
+ deferred: isDeferredResult(message),
1449
+ ...usage === void 0 ? {} : { usage }
1450
+ };
1451
+ },
1452
+ exit: () => []
1453
+ };
1454
+ };
1381
1455
  /**
1382
1456
  * Two legs of one session, as one: the tokens of both, and the later leg's
1383
1457
  * cost, which is already the session's total (ADR-046).
@@ -1540,6 +1614,7 @@ const claudeCodeAdapter = {
1540
1614
  input: userLine
1541
1615
  },
1542
1616
  decode: decodeClaudeLine,
1617
+ legDecoder: claudeDecoder,
1543
1618
  mcp: {
1544
1619
  kind: "flag",
1545
1620
  wire: () => Promise.resolve({
@@ -1904,6 +1979,26 @@ const commandCodeDecoder = () => {
1904
1979
  let sessionId = "";
1905
1980
  let turns = 0;
1906
1981
  let held;
1982
+ /** The leg's tokens so far, from each `model_request_end` frame. */
1983
+ let used;
1984
+ /** A model request's usage, added to the leg's so far. */
1985
+ const requestEnded = (usage) => {
1986
+ const said = isObject$1(usage) ? usage : {};
1987
+ const own = {
1988
+ costUsd: 0,
1989
+ inputTokens: num$1(said["inputTokens"]),
1990
+ outputTokens: num$1(said["outputTokens"]),
1991
+ cacheReadTokens: num$1(said["cacheReadTokens"]),
1992
+ cacheWriteTokens: num$1(said["cacheWriteTokens"]),
1993
+ turns,
1994
+ durationMs: 0
1995
+ };
1996
+ used = used === void 0 ? own : {
1997
+ ...addUsage(used, own),
1998
+ turns
1999
+ };
2000
+ return used;
2001
+ };
1907
2002
  const frame = (event) => {
1908
2003
  const type = event["type"];
1909
2004
  const id = str$1(event["toolCallId"]);
@@ -1980,7 +2075,11 @@ const commandCodeDecoder = () => {
1980
2075
  return { events: [] };
1981
2076
  }
1982
2077
  const event = message["event"];
1983
- return { events: message["type"] === "event" && isObject$1(event) ? frame(event) : [] };
2078
+ if (message["type"] !== "event" || !isObject$1(event)) return { events: [] };
2079
+ return {
2080
+ events: frame(event),
2081
+ ...event["type"] === "model_request_end" ? { usage: requestEnded(event["usage"]) } : {}
2082
+ };
1984
2083
  },
1985
2084
  exit: (code) => {
1986
2085
  if (held !== void 0) return [result(held, code)];
@@ -2547,7 +2646,10 @@ const openCodeDecoder = (spec) => {
2547
2646
  switch (message["type"]) {
2548
2647
  case "step_finish":
2549
2648
  usage = sumUsage(usage, stepUsage(message["part"]));
2550
- break;
2649
+ return {
2650
+ events,
2651
+ usage
2652
+ };
2551
2653
  case "error":
2552
2654
  errors.push(errorText(message["error"]));
2553
2655
  failed ??= errorLineEnd(message["error"]);