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

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 (42) hide show
  1. package/dist/__build_info__-Bsb1kjgF.mjs +340 -0
  2. package/dist/{store-CleF7KeS.mjs → attach-BHO3X3cf.mjs} +16 -19
  3. package/dist/{attach-CdtGX9se.mjs → attach-CPespxlQ.mjs} +5 -4
  4. package/dist/bin.mjs +64 -1339
  5. package/dist/brief-za0ozN_E.mjs +58 -0
  6. package/dist/{builtin-files-Bdq23IIi.mjs → builtin-files-2bHf76x-.mjs} +1 -1
  7. package/dist/{completion--ywde-56.mjs → completion-CQ2UYKuJ.mjs} +5 -5
  8. package/dist/context-BNqDw9z1.mjs +106 -0
  9. package/dist/{find-BVX-bL4u.mjs → find-BYLlszqj.mjs} +1 -1
  10. package/dist/follow-ups-B4GJ3Vzw.mjs +461 -0
  11. package/dist/{format-CvTE5CZQ.mjs → format-C8MsFj8_.mjs} +19 -5
  12. package/dist/{help-groups-CpR2UzSn.mjs → help-groups-CQ98mLjF.mjs} +4 -0
  13. package/dist/{in-a-run-cL5N9gpH.mjs → in-a-run-Bp0k0J09.mjs} +1 -1
  14. package/dist/{__build_info__-B82-dGJY.mjs → install-DWtXTq4y.mjs} +3 -227
  15. package/dist/{limits-Dhe--wmX.mjs → limits-B1qzS4cX.mjs} +1 -1
  16. package/dist/{mcp-CsmboyXv.mjs → mcp-BOrVkyhN.mjs} +6 -6
  17. package/dist/{once-CrwI-ZdN.mjs → once-C1fL3GVo.mjs} +3 -3
  18. package/dist/orphan-guard-BFKg8VSd.mjs +58 -0
  19. package/dist/{pause-DssrYcda.mjs → pause-DOMK-R8V.mjs} +3 -3
  20. package/dist/post-BzA6Qobq.mjs +44 -0
  21. package/dist/{relay-DASRgsTQ.mjs → relay-OWuu4fib.mjs} +1 -1
  22. package/dist/run--4-1xAF2.mjs +1451 -0
  23. package/dist/{run-D8divGCs.mjs → run-CiPsW9Kf.mjs} +1 -1
  24. package/dist/{send-CXv8bx0i.mjs → send-CnNNW-ot.mjs} +2 -2
  25. package/dist/{src-njdtejgZ.mjs → src-B9zWIVqo.mjs} +129 -12
  26. package/dist/{src-8Mul0695.mjs → src-DQKz2eOH.mjs} +322 -75
  27. package/dist/{src-C7z_6fhn.mjs → src-DcrhgipG.mjs} +17 -10
  28. package/dist/{src-tsuZRu0H.mjs → src-Dr_fTSu-.mjs} +4832 -4155
  29. package/dist/store-oKJ-cCf3.mjs +16 -0
  30. package/dist/ui/assets/app-Bdc6OBeZ.css +1 -0
  31. package/dist/ui/assets/app-Drp8Dm9y.js +111 -0
  32. package/dist/ui/assets/{index-D-_uPI2v.js → index-BtwkftKe.js} +2 -2
  33. package/dist/ui/index.html +1 -1
  34. package/dist/{ui-CNO1M0qT.mjs → ui-CzKlsCnm.mjs} +3 -3
  35. package/dist/{usage-BVXi0iFY.mjs → usage-DHGNk2JL.mjs} +3 -3
  36. package/dist/{context-Y_I4Mofq.mjs → validate-Bs_gg22g.mjs} +4 -104
  37. package/dist/{watch-DVNIciHp.mjs → watch-CCCfw3n7.mjs} +19 -5
  38. package/dist/{workflows-B30QkwTk.mjs → workflows-CW28ZU-z.mjs} +2 -2
  39. package/dist/{worktrees-DD4_TpkH.mjs → worktrees-CyE8aF6j.mjs} +1 -1
  40. package/package.json +1 -1
  41. package/dist/ui/assets/app-D_nAPnHM.css +0 -1
  42. package/dist/ui/assets/app-DqBAtXSZ.js +0 -111
@@ -1,4 +1,4 @@
1
- import { dn as git, fn as gitOk } from "./src-tsuZRu0H.mjs";
1
+ import { Jt as gitOk, qt as git } from "./src-Dr_fTSu-.mjs";
2
2
  import path from "node:path";
3
3
  import { copyFileSync, existsSync, mkdirSync, mkdtempSync, readFileSync, readdirSync, renameSync, rmSync, writeFileSync } from "node:fs";
4
4
  import { createHash, randomUUID } from "node:crypto";
@@ -1,6 +1,6 @@
1
- import { U as openStore, at as scriptRefusal, it as TOO_LONG, ot as sendFromScript } from "./src-tsuZRu0H.mjs";
1
+ import { U as openStore, at as scriptRefusal, it as TOO_LONG, ot as sendFromScript } from "./src-Dr_fTSu-.mjs";
2
2
  import { l as writeErr } from "./output-B1kwo0YU.mjs";
3
- import { u as inheritedScrubber } from "./src-C7z_6fhn.mjs";
3
+ import { u as inheritedScrubber } from "./src-DcrhgipG.mjs";
4
4
  import { defineCommand } from "citty";
5
5
  // src/commands/send.ts
6
6
  /**
@@ -1,4 +1,5 @@
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";
1
+ import { Bn as outcomeEnd, Et as parseReport, Gn as FEEDBACK_SEVERITIES, Gt as programFound, Hn as END_KINDS, Kn as FEEDBACK_TARGETS, Kt as startAt, Nn as countedTokens, Un as endFor, Wn as FEEDBACK_KINDS, Wt as lowerChild, _i as AGENT_DRIVERS, fr as maskSecrets, ur as MASK } from "./src-Dr_fTSu-.mjs";
2
+ import { n as holdGuard, r as orphanGuard } from "./orphan-guard-BFKg8VSd.mjs";
2
3
  import path from "node:path";
3
4
  import { z } from "zod";
4
5
  import { existsSync, linkSync, mkdirSync, mkdtempSync, readFileSync, readdirSync, realpathSync, renameSync, rmSync, writeFileSync } from "node:fs";
@@ -8,6 +9,13 @@ import { createInterface } from "node:readline";
8
9
  import { execFile, spawn } from "node:child_process";
9
10
  import { setTimeout as setTimeout$1 } from "node:timers/promises";
10
11
  import { createServer } from "node:http";
12
+ // ../core/src/follow-ups/types.ts
13
+ const FOLLOW_UP_KINDS = [
14
+ "change",
15
+ "message",
16
+ "task",
17
+ "check"
18
+ ];
11
19
  // ../runtime/src/hold.ts
12
20
  /**
13
21
  * Waits at a tool call while `hold` is held: "go" once it is released within
@@ -543,13 +551,62 @@ const driverFailure = (message, kind, scope) => ({
543
551
  errors: [message]
544
552
  }
545
553
  });
554
+ // ../runtime/src/leg-spawn.ts
555
+ /**
556
+ * @file Starting one process (leg) of a session: at the project's priority, and
557
+ * off Windows in its own process group beside the orphan guard, so it and
558
+ * what it started end with `ork`, whatever ends `ork`. The process's pid, and
559
+ * the SIGINT that stops it, stay the driver's own.
560
+ */
561
+ /** The fd of the orphan guard's pipe from `ork`. */
562
+ const WATCH_FD = 3;
563
+ /**
564
+ * Starts the orphan guard, then becomes the driver. The pipe is closed by a
565
+ * bare `exec`: macOS's `sh` keeps a copy of a descriptor an `exec` command
566
+ * closes, which the driver and its leftovers would then inherit.
567
+ */
568
+ const GUARDED = `${orphanGuard(WATCH_FD)}exec ${String(WATCH_FD)}<&-; exec "$0" "$@"`;
569
+ const piped = (child) => child.stdin !== null && child.stdout !== null && child.stderr !== null;
570
+ /**
571
+ * Spawns the leg's process. A program that isn't there is spawned bare, so it
572
+ * fails as spawn's ENOENT; the guard is released once the driver exits, so a
573
+ * session that ends normally leaves its leftovers alone.
574
+ */
575
+ const spawnLeg = (start) => {
576
+ const [bin, args] = startAt(start.priority, start.bin, start.args, start.env);
577
+ const guarded = process.platform !== "win32" && programFound(start.bin, start.env);
578
+ const child = spawn(guarded ? "/bin/sh" : bin, guarded ? [
579
+ "-c",
580
+ GUARDED,
581
+ bin,
582
+ ...args
583
+ ] : args, {
584
+ cwd: start.cwd,
585
+ detached: guarded,
586
+ env: { ...start.env },
587
+ stdio: [
588
+ "pipe",
589
+ "pipe",
590
+ "pipe",
591
+ guarded ? "pipe" : "ignore"
592
+ ]
593
+ });
594
+ if (!piped(child)) throw new Error(`${start.bin} was started without pipes`);
595
+ if (guarded) {
596
+ const release = holdGuard(child.stdio[WATCH_FD]);
597
+ child.once("exit", release);
598
+ }
599
+ return child;
600
+ };
546
601
  // ../runtime/src/session-leg.ts
547
602
  /**
548
603
  * @file One process (leg) of a session the runner drives: it writes the queued
549
604
  * stdin lines, yields the adapter's decoded events, and says how it ended. A
550
605
  * session is one leg, or several when a paused node's tool call was deferred
551
606
  * or a message waits for a tool that takes none mid-session; a resumed leg
552
- * carries what the legs before it spent, and its start is not news.
607
+ * carries what the legs before it spent, and its start is not news. Off
608
+ * Windows the process ends with `ork`, whatever ends `ork` (the orphan
609
+ * guard).
553
610
  */
554
611
  const REASON_LIMIT = 500;
555
612
  /** Marks a session's start with the driver that runs it. */
@@ -638,16 +695,7 @@ const failureReason = (name, stderr, code) => {
638
695
  };
639
696
  /** Runs one process of a session, yielding its events; returns how it ended. */
640
697
  const runLeg = async function* (input) {
641
- const [bin, args] = startAt(input.priority, input.bin, input.args, input.env);
642
- const child = spawn(bin, args, {
643
- cwd: input.cwd,
644
- env: { ...input.env },
645
- stdio: [
646
- "pipe",
647
- "pipe",
648
- "pipe"
649
- ]
650
- });
698
+ const child = spawnLeg(input);
651
699
  lowerChild(input.priority, child.pid);
652
700
  const exited = new Promise((resolve) => {
653
701
  child.on("close", (code, signal) => {
@@ -884,6 +932,74 @@ const feedbackTool = defineTool({
884
932
  return Promise.resolve(text(sent.ok ? "Recorded. Thank you; carry on with your task." : `Not recorded: ${sent.error}.`));
885
933
  }
886
934
  });
935
+ // ../runtime/src/tools/follow-up.ts
936
+ /**
937
+ * @file `follow_up`: a session's way to leave work the change leaves for later
938
+ * (a change for a later run, a note for another project, a message a person
939
+ * must send, a task or a check for the maintainer). Ork keeps it where the
940
+ * project's `followUps` rule says, merges duplicates, caps it per session,
941
+ * and never sends or runs anything on its own.
942
+ */
943
+ const isFor = (value) => /^(?:agent|me|project:\S.*|person:\S.*)$/u.test(value);
944
+ const isDue = (value) => /^(?:now|after-merge|after-deploy|\d{4}-\d{2}-\d{2})$/u.test(value);
945
+ const followUpTool = defineTool({
946
+ name: "follow_up",
947
+ description: "Leave work this change leaves for later and that is not yours to do now: a change for a later run (for: agent), something for another registered project (for: project:<name>), a message a person must get (for: person:<name>, kind: message, with a draft), or a task or check for the maintainer (for: me, with steps). Ork keeps it, merges duplicates, and sends or runs nothing itself. Not for problems with Ork or the workflow (use feedback), nor for what you can finish now.",
948
+ shape: {
949
+ title: z.string().min(1).max(200).describe("One line."),
950
+ body: z.string().max(4e3).optional().describe("What and why, briefly."),
951
+ for: z.string().refine(isFor, "agent, me, project:<name> or person:<name>").describe("Who acts: agent, me, project:<name> or person:<name>."),
952
+ kind: z.enum(FOLLOW_UP_KINDS),
953
+ due: z.string().refine(isDue, "now, after-merge, after-deploy or YYYY-MM-DD").describe("now, after-merge, after-deploy, or a YYYY-MM-DD date."),
954
+ where: z.array(z.string()).max(20).optional().describe("Files it is about, relative to the project root."),
955
+ ref: z.string().min(1).optional().describe("The pull request or branch an after-merge follow-up waits on, when you know it."),
956
+ draft: z.strictObject({
957
+ to: z.string().min(1),
958
+ channel: z.string().optional().describe("github (to: an issue or PR URL), email, slack… A hint for the maintainer."),
959
+ text: z.string().min(1).max(4e3)
960
+ }).optional().describe("For a message: what the maintainer will send."),
961
+ steps: z.array(z.strictObject({
962
+ text: z.string().min(1),
963
+ command: z.string().optional().describe("Shown to the maintainer to copy; Ork never runs it.")
964
+ })).max(20).optional().describe("For a task or check: what to do, in order.")
965
+ },
966
+ available: ({ ports }) => ports.followUps !== void 0,
967
+ run: async ({ ports }, args) => {
968
+ const port = ports.followUps;
969
+ if (port === void 0) return text("No follow-ups here.");
970
+ if (!isFor(args.for) || !isDue(args.due)) return text("Not kept.");
971
+ const input = {
972
+ title: args.title,
973
+ for: args.for,
974
+ kind: args.kind,
975
+ due: args.due,
976
+ ...args.body === void 0 ? {} : { body: args.body },
977
+ ...args.where === void 0 ? {} : { where: args.where },
978
+ ...args.ref === void 0 ? {} : { ref: args.ref },
979
+ ...args.draft === void 0 ? {} : { draft: {
980
+ to: args.draft.to,
981
+ text: args.draft.text,
982
+ ...args.draft.channel === void 0 ? {} : { channel: args.draft.channel }
983
+ } },
984
+ ...args.steps === void 0 ? {} : { steps: args.steps.map((step) => ({
985
+ text: step.text,
986
+ ...step.command === void 0 ? {} : { command: step.command }
987
+ })) }
988
+ };
989
+ const result = await port.add(input);
990
+ if (!result.ok) return {
991
+ ...text(`Not kept: ${result.error}.`),
992
+ isError: true
993
+ };
994
+ const { followUp, merged, note } = result.added;
995
+ return text([
996
+ merged ? `Merged into follow-up ${followUp.id}, which was already kept.` : `Kept as follow-up ${followUp.id}.`,
997
+ ...note === void 0 ? [] : [note],
998
+ ...result.relayed === void 0 ? [] : [`Also sent to ${result.relayed.run}/${result.relayed.node}, a live run of that project.`],
999
+ "Carry on with your task."
1000
+ ].join(" "));
1001
+ }
1002
+ });
887
1003
  // ../runtime/src/tools/input.ts
888
1004
  /**
889
1005
  * @file `read_input`: what the workflow sent a node back with, whole. A loop's
@@ -1074,6 +1190,7 @@ const ORK_TOOLS = [
1074
1190
  claimTool,
1075
1191
  releaseTool,
1076
1192
  feedbackTool,
1193
+ followUpTool,
1077
1194
  {
1078
1195
  name: REPORT_TOOL$1,
1079
1196
  bind: (context) => context.report === void 0 || checksItsReport(context.driver) ? null : bound(context.report)