@lchase/yak 0.3.1 → 0.4.0

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 (2) hide show
  1. package/dist/index.js +32 -7
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -768,6 +768,10 @@ async function readJournal(runDir) {
768
768
  const contents = await readFile4(journalPath(runDir), "utf8").catch(() => "");
769
769
  return contents.split("\n").filter((line) => line.trim().length > 0).map((line) => JSON.parse(line));
770
770
  }
771
+ function runTagFromJournal(events) {
772
+ const started = events.find((e) => e.t === "run.started");
773
+ return started?.t === "run.started" ? started.tag : void 0;
774
+ }
771
775
  function completedStepsFromJournal(events) {
772
776
  const started = /* @__PURE__ */ new Map();
773
777
  const completed = /* @__PURE__ */ new Map();
@@ -2322,6 +2326,9 @@ function resolveDirs(runsDir, cwd, cacheDir) {
2322
2326
  function worktreePathFor(runsDir, runId) {
2323
2327
  return path15.join(path15.dirname(runsDir), ".yak", "worktrees", runId);
2324
2328
  }
2329
+ function worktreeBranchFor(runId) {
2330
+ return `yak/${runId}`;
2331
+ }
2325
2332
  function generateRunId() {
2326
2333
  const iso = (/* @__PURE__ */ new Date()).toISOString();
2327
2334
  const [datePart, timePart] = iso.split("T");
@@ -2353,7 +2360,8 @@ async function executeWorkflowFile(workflowPath, opts = {}) {
2353
2360
  workflow: workflow.name,
2354
2361
  inputHash: inputWritten?.hash ?? sha256(JSON.stringify(workflow)),
2355
2362
  adapter,
2356
- isolation
2363
+ isolation,
2364
+ ...opts.tag !== void 0 ? { tag: opts.tag } : {}
2357
2365
  });
2358
2366
  if (inputWritten) {
2359
2367
  await appendJournalEvent(runDir, runId, {
@@ -2363,11 +2371,16 @@ async function executeWorkflowFile(workflowPath, opts = {}) {
2363
2371
  bytes: inputWritten.bytes
2364
2372
  });
2365
2373
  }
2374
+ await opts.onStart?.({
2375
+ runId,
2376
+ runDir,
2377
+ ...isolation === "worktree" ? { worktreeBranch: worktreeBranchFor(runId) } : {}
2378
+ });
2366
2379
  let stepCwd = cwd;
2367
2380
  if (isolation === "worktree") {
2368
2381
  const worktreePath = worktreePathFor(runsDir, runId);
2369
2382
  try {
2370
- await createWorktree(cwd, `yak/${runId}`, "HEAD", worktreePath);
2383
+ await createWorktree(cwd, worktreeBranchFor(runId), "HEAD", worktreePath);
2371
2384
  } catch {
2372
2385
  await appendJournalEvent(runDir, runId, { t: "run.finished", status: "failed" });
2373
2386
  return { runId, runDir, status: "failed" };
@@ -2520,7 +2533,8 @@ async function pendingCommand(opts = {}) {
2520
2533
  const last = events.at(-1);
2521
2534
  if (!last || last.t !== "run.finished" || last.status !== "suspended") continue;
2522
2535
  anyPending = true;
2523
- console.log(`run ${runId} suspended:`);
2536
+ const tag = runTagFromJournal(events);
2537
+ console.log(`run ${runId} suspended${tag !== void 0 ? ` (tag: ${tag})` : ""}:`);
2524
2538
  const openIds = openRequestStepIds(events);
2525
2539
  if (openIds.length === 0) {
2526
2540
  console.log(" (no open request found \u2014 loop budget suspend from before M4, unresumable)");
@@ -2751,7 +2765,16 @@ async function runCommand(workflowPath, opts = {}) {
2751
2765
  result = await executeWorkflowFile(path18.resolve(workflowPath), {
2752
2766
  adapter: opts.adapter,
2753
2767
  isolation: opts.isolation,
2754
- input: opts.input
2768
+ input: opts.input,
2769
+ tag: opts.tag,
2770
+ // yak#23: emit the run id (and worktree branch) to stderr the moment
2771
+ // `run.started` is journalled, so an out-of-process launcher can
2772
+ // capture it without waiting for a terminal state. stdout is
2773
+ // untouched — the terminal-state line there is unchanged.
2774
+ onStart: ({ runId, worktreeBranch }) => {
2775
+ console.error(`run ${runId} started`);
2776
+ if (worktreeBranch) console.error(` worktree branch ${worktreeBranch}`);
2777
+ }
2755
2778
  });
2756
2779
  while (opts.interactive && result.status === "suspended") {
2757
2780
  await answerOpenRequestsInteractively(result.runId, result.runDir);
@@ -2796,7 +2819,8 @@ async function statusCommand(runId, opts = {}) {
2796
2819
  const events = await readJournal(runDir);
2797
2820
  const statuses = stepStatusesFromJournal(workflow.steps, events);
2798
2821
  const failuresByStep = new Map(failedStepsFromJournal(events).map((f) => [f.stepId, f]));
2799
- console.log(`run ${resolvedRunId}:`);
2822
+ const tag = runTagFromJournal(events);
2823
+ console.log(`run ${resolvedRunId}${tag !== void 0 ? ` (tag: ${tag})` : ""}:`);
2800
2824
  for (const { stepId, status } of statuses) {
2801
2825
  console.log(` ${stepId}: ${status}`);
2802
2826
  const step = workflow.steps.find((s) => s.id === stepId);
@@ -2935,13 +2959,14 @@ program.name("yak").description("An agentic workflow engine").version(readVersio
2935
2959
  program.command("run").description("Run a workflow YAML file").argument("<workflow>", "path to the workflow YAML file").option("--adapter <adapter>", "agent adapter to use", "claude-code").option("--interactive", "prompt inline for gate answers instead of exiting to resume later", false).option("--isolation <mode>", 'run inside a fresh git worktree ("worktree") or the plain cwd ("none")', "none").option(
2936
2960
  "--input <pair...>",
2937
2961
  "workflow input as key=value, repeatable \u2014 validated against the workflow inputSchema"
2938
- ).action(
2962
+ ).option("--tag <string>", "opaque correlation tag, stored on the run and echoed by yak pending/status").action(
2939
2963
  async (workflow, options) => {
2940
2964
  process.exitCode = await runCommand(workflow, {
2941
2965
  adapter: requireAdapterId(options.adapter),
2942
2966
  interactive: options.interactive,
2943
2967
  isolation: requireIsolation(options.isolation),
2944
- input: parseInputPairs(options.input)
2968
+ input: parseInputPairs(options.input),
2969
+ tag: options.tag
2945
2970
  });
2946
2971
  }
2947
2972
  );
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lchase/yak",
3
- "version": "0.3.1",
3
+ "version": "0.4.0",
4
4
  "description": "An agentic workflow engine",
5
5
  "license": "MIT",
6
6
  "type": "module",