agent-yes 1.228.0 → 1.229.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.
- package/dist/{JsonlStore-Bm5Nj6v_.js → JsonlStore-CWOA3aDH.js} +1 -1
- package/dist/{SUPPORTED_CLIS-C5d64Xqj.js → SUPPORTED_CLIS-CvLtp6LS.js} +2 -2
- package/dist/SUPPORTED_CLIS-DJEnqsp2.js +11 -0
- package/dist/{agentShare-CpglhRYb.js → agentShare-CQwvWWfd.js} +4 -4
- package/dist/{callback-B3N2VJ1i.js → callback-BFZDARQq.js} +4 -4
- package/dist/{callback-CCEQtwXX.js → callback-BN-tH9dB.js} +3 -3
- package/dist/cli.js +9 -9
- package/dist/{cwdConflictWarn-CJZRp4S0.js → cwdConflictWarn-CKUsQ5_o.js} +2 -2
- package/dist/{globalPidIndex-CoNr7tS8.js → globalPidIndex-Ca4sTr1b.js} +1 -1
- package/dist/index.js +8 -8
- package/dist/{messageLog-Bb_Ie3Ck.js → messageLog-zVGWLX7w.js} +1 -1
- package/dist/{notifyDaemon-CfQN5blR.js → notifyDaemon-CENKHs1M.js} +4 -4
- package/dist/pidStore-Cp3HekUh.js +6 -0
- package/dist/{pidStore-DCqpU_bI.js → pidStore-Hjba3K6Q.js} +3 -3
- package/dist/{reaper-BNKvujYy.js → reaper-iQXyufgp.js} +1 -1
- package/dist/{reaper-BBc2AIKA.js → reaper-pJpMYKmj.js} +1 -1
- package/dist/{runningLock-CNMl13dC.js → runningLock-BFk3Mo8K.js} +1 -1
- package/dist/{rustBinary-B8IcqSw1.js → rustBinary-BjApGser.js} +2 -2
- package/dist/{schedule-B-RjgOOR.js → schedule-D0O3sb5A.js} +9 -9
- package/dist/{serve-DwF03sgB.js → serve-m-WChRrO.js} +67 -21
- package/dist/{setup-cZFxfS89.js → setup-fuwC5wlF.js} +2 -2
- package/dist/spawnGate-5jC6eiqk.js +5 -0
- package/dist/{spawnGate-CeFYH-Ib.js → spawnGate-CMlGqVN4.js} +2 -2
- package/dist/{subcommands-DSyCT0vl.js → subcommands-DzJbnYAx.js} +12 -12
- package/dist/{subcommands-UseeaeYM.js → subcommands-lwgJxJex.js} +3 -3
- package/dist/{todoAutomation-Cwnh4aWo.js → todoAutomation-x6guaQXc.js} +115 -6
- package/dist/{todoCli-6v1CYdxN.js → todoCli-Cjhx3DqQ.js} +38 -6
- package/dist/{tray-DBt8X-Qj.js → tray-C8VfnS7s.js} +2 -2
- package/dist/{ts-Cl3CmLH9.js → ts-oYrTk4Z_.js} +103 -20
- package/dist/{versionChecker-Dhjyjxs_.js → versionChecker-CgCXc8CJ.js} +2 -2
- package/dist/{ws-Dw2fGxTI.js → ws-D5q3R1kY.js} +4 -4
- package/package.json +1 -1
- package/ts/askApi.spec.ts +358 -0
- package/ts/askApi.ts +255 -0
- package/ts/index.ts +2 -0
- package/ts/serve.ts +131 -0
- package/ts/todoBlock.spec.ts +10 -0
- package/ts/todoBlock.ts +14 -2
- package/ts/todoCli.spec.ts +101 -0
- package/ts/todoCli.ts +69 -1
- package/ts/todoStore.spec.ts +126 -0
- package/ts/todoStore.ts +130 -2
- package/dist/SUPPORTED_CLIS-Bfresz1n.js +0 -11
- package/dist/pidStore-CatWvn5W.js +0 -6
- package/dist/spawnGate-CIC7b7nm.js +0 -5
|
@@ -1,7 +1,19 @@
|
|
|
1
|
-
import { t as JsonlStore } from "./JsonlStore-
|
|
1
|
+
import { t as JsonlStore } from "./JsonlStore-CWOA3aDH.js";
|
|
2
2
|
import path from "path";
|
|
3
3
|
import { lock } from "proper-lockfile";
|
|
4
4
|
|
|
5
|
+
//#region ts/removeControlCharacters.ts
|
|
6
|
+
const ESC = String.fromCharCode(27);
|
|
7
|
+
const C1 = String.fromCharCode(155);
|
|
8
|
+
const BACKSLASH = String.fromCharCode(92);
|
|
9
|
+
const ST_PATTERN_SOURCE = ESC + BACKSLASH + BACKSLASH;
|
|
10
|
+
const OSC_PATTERN = new RegExp(ESC + "][^\x07\x1B]*(?:\x07|" + ST_PATTERN_SOURCE + ")", "g");
|
|
11
|
+
const CSI_PATTERN = new RegExp("[" + ESC + C1 + "][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]", "g");
|
|
12
|
+
function removeControlCharacters(str) {
|
|
13
|
+
return str.replace(OSC_PATTERN, "").replace(CSI_PATTERN, "");
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
//#endregion
|
|
5
17
|
//#region ts/todoLifecycle.ts
|
|
6
18
|
/**
|
|
7
19
|
* States considered "finished" across every kind. A finished task is never
|
|
@@ -499,7 +511,10 @@ var TodoStore = class TodoStore {
|
|
|
499
511
|
return this.rawUpdate(id, () => ({ acceptanceCriteria: trimmed }));
|
|
500
512
|
}
|
|
501
513
|
setBlock(id, block) {
|
|
502
|
-
return this.rawUpdate(id, () => ({
|
|
514
|
+
return this.rawUpdate(id, (fresh) => ({
|
|
515
|
+
block,
|
|
516
|
+
blockRev: (fresh.blockRev ?? 0) + 1
|
|
517
|
+
}));
|
|
503
518
|
}
|
|
504
519
|
/**
|
|
505
520
|
* Clears a `waiting-on-agent` block ONLY if the FRESH record's block is
|
|
@@ -514,7 +529,101 @@ var TodoStore = class TodoStore {
|
|
|
514
529
|
clearWaitingOnAgentBlock(id, expectedAgentId) {
|
|
515
530
|
return this.rawUpdate(id, (fresh) => {
|
|
516
531
|
if (fresh.block?.type !== "waiting-on-agent" || fresh.block.agentId !== expectedAgentId) throw new Error(`task ${id}: block changed since this was decided (expected waiting-on-agent for "${expectedAgentId}") — not clearing`);
|
|
517
|
-
return {
|
|
532
|
+
return {
|
|
533
|
+
block: null,
|
|
534
|
+
blockRev: (fresh.blockRev ?? 0) + 1
|
|
535
|
+
};
|
|
536
|
+
});
|
|
537
|
+
}
|
|
538
|
+
/**
|
|
539
|
+
* Clears `block` ONLY if the FRESH record's `blockRev` still equals
|
|
540
|
+
* `expectedBlockRev` — the generalized form of `clearWaitingOnAgentBlock`
|
|
541
|
+
* above, for a caller (e.g. `askApi.ts`'s `answerAsk`) that decided to
|
|
542
|
+
* clear a specific `blocked-by-human` block instance from a snapshot
|
|
543
|
+
* taken at the start of a longer operation.
|
|
544
|
+
*
|
|
545
|
+
* Compares `blockRev`, NOT the block's own content: an earlier version of
|
|
546
|
+
* this method compared `JSON.stringify(fresh.block)` against the snapshot,
|
|
547
|
+
* which missed an ABA race — another process could replace the block with
|
|
548
|
+
* a byte-for-byte IDENTICAL `{type, who, question/options/actionLink}`
|
|
549
|
+
* value (e.g. the exact same question asked again) between the caller's
|
|
550
|
+
* read and this call, and the content-only check would see no difference,
|
|
551
|
+
* silently erasing that distinct, newer block instance as if it were the
|
|
552
|
+
* one the caller actually decided to answer (codex-review round-17
|
|
553
|
+
* Important). `blockRev` increments on every write to `block` regardless
|
|
554
|
+
* of whether the new value differs from the old one, so it uniquely
|
|
555
|
+
* identifies THIS PARTICULAR block-setting event, not just its shape.
|
|
556
|
+
*
|
|
557
|
+
* Clearing unconditionally by `id` alone (or by content alone) could
|
|
558
|
+
* silently erase a genuinely different, newer block that another process
|
|
559
|
+
* set in the meantime — the task would then look unblocked even though a
|
|
560
|
+
* real, later block exists (codex-review Important). Throws instead of
|
|
561
|
+
* silently no-op-ing so the caller can report the conflict rather than
|
|
562
|
+
* claim success.
|
|
563
|
+
*/
|
|
564
|
+
clearBlockIfMatches(id, expectedBlockRev) {
|
|
565
|
+
return this.rawUpdate(id, (fresh) => {
|
|
566
|
+
if ((fresh.blockRev ?? 0) !== expectedBlockRev) throw new Error(`task ${id}: block changed since this was decided — not clearing`);
|
|
567
|
+
return {
|
|
568
|
+
block: null,
|
|
569
|
+
blockRev: (fresh.blockRev ?? 0) + 1
|
|
570
|
+
};
|
|
571
|
+
});
|
|
572
|
+
}
|
|
573
|
+
/**
|
|
574
|
+
* Atomically clears a `blocked-by-human` block AND, if `gate` is given,
|
|
575
|
+
* appends its evidence and advances the transition it names — all inside
|
|
576
|
+
* ONE `rawUpdate` write (one lock acquisition, one reload, one write).
|
|
577
|
+
*
|
|
578
|
+
* This exists specifically so `askApi.ts`'s `answerAsk()` never composes
|
|
579
|
+
* "verify blockRev, approve() a gate, transition(), clearBlockIfMatches()"
|
|
580
|
+
* as separate locked writes again. That composition (this method's
|
|
581
|
+
* predecessor) had a real gap: `approve()`/`transition()` could durably
|
|
582
|
+
* succeed — evidence appended, state advanced — and ONLY THEN could the
|
|
583
|
+
* final `clearBlockIfMatches()` fail because another process replaced the
|
|
584
|
+
* block in between. The task was left in a state no caller intended:
|
|
585
|
+
* already transitioned/evidenced for the OLD block, while `block` still
|
|
586
|
+
* held a DIFFERENT, newer `blocked-by-human` ask that was never gated at
|
|
587
|
+
* all (codex-review round-18 Important — the exact race this module's
|
|
588
|
+
* whole `blockRev` mechanism exists to close, just one step further out
|
|
589
|
+
* than `clearBlockIfMatches` alone could reach). Folding everything into
|
|
590
|
+
* one `rawUpdate` cycle makes the two outcomes (nothing changed / gate +
|
|
591
|
+
* transition + clear all changed together) the only two possible ones —
|
|
592
|
+
* there is no window in which one succeeded and the other didn't.
|
|
593
|
+
*
|
|
594
|
+
* `blockRev` re-validates `canTransition` against the FRESH state (not a
|
|
595
|
+
* value captured before this call), matching `transition()`'s own
|
|
596
|
+
* concurrent-state-drift defense — a state change unrelated to `block`
|
|
597
|
+
* (and so invisible to the `blockRev` check alone) must still be caught.
|
|
598
|
+
*
|
|
599
|
+
* Independent verification (this module's single most important
|
|
600
|
+
* invariant — see the file's own header comment) is re-checked here
|
|
601
|
+
* against the FRESH owner, exactly as `approve()` checks it: `gate`, when
|
|
602
|
+
* given, is never applied if its `validator` is the task's own owner.
|
|
603
|
+
* This method does not call `approve()` (it is not a separate write), so
|
|
604
|
+
* skipping this check here would silently let a human answer their own
|
|
605
|
+
* gated ask with no independent-verification enforcement at all.
|
|
606
|
+
*/
|
|
607
|
+
answerHumanBlock(id, expectedBlockRev, gate) {
|
|
608
|
+
return this.rawUpdate(id, (fresh) => {
|
|
609
|
+
if ((fresh.blockRev ?? 0) !== expectedBlockRev) throw new Error(`task ${id}: this ask has changed since it was loaded (expected blockRev ${expectedBlockRev}, current ${fresh.blockRev ?? 0}) — refresh and try again`);
|
|
610
|
+
const patch = {
|
|
611
|
+
block: null,
|
|
612
|
+
blockRev: (fresh.blockRev ?? 0) + 1
|
|
613
|
+
};
|
|
614
|
+
if (gate) {
|
|
615
|
+
if (fresh.owner && fresh.owner.trim().toLowerCase() === gate.validator.trim().toLowerCase()) throw new Error(`task ${id}: independent verification required — validator "${gate.validator}" is the same identity as owner "${fresh.owner}"; the worker cannot certify their own work`);
|
|
616
|
+
if (!canTransition(fresh.kind, fresh.state, gate.toState)) throw new Error(`task ${id}: no transition ${fresh.state} -> ${gate.toState} for kind "${fresh.kind}" (state changed concurrently) — not clearing`);
|
|
617
|
+
const evidenceEntry = {
|
|
618
|
+
gate: gate.name,
|
|
619
|
+
passedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
620
|
+
validator: gate.validator,
|
|
621
|
+
note: gate.note
|
|
622
|
+
};
|
|
623
|
+
patch.verifyEvidence = [...fresh.verifyEvidence, evidenceEntry];
|
|
624
|
+
patch.state = gate.toState;
|
|
625
|
+
}
|
|
626
|
+
return patch;
|
|
518
627
|
});
|
|
519
628
|
}
|
|
520
629
|
/**
|
|
@@ -602,7 +711,7 @@ function monitorHint(block) {
|
|
|
602
711
|
function describeBlock(block) {
|
|
603
712
|
switch (block.type) {
|
|
604
713
|
case "blocked-by-task": return `blocked by task ${block.taskId}`;
|
|
605
|
-
case "blocked-by-human": return `waiting on ${block.who}${block.question ? `: ${block.question}` : ""}`;
|
|
714
|
+
case "blocked-by-human": return `waiting on ${block.who}${block.question ? `: ${block.question}` : ""}${block.actionLink ? ` (action: ${block.actionLink})` : ""}`;
|
|
606
715
|
case "blocked-by-external": return `waiting on external signal: ${block.signal}`;
|
|
607
716
|
case "waiting-on-agent": return `waiting on agent ${block.agentId}`;
|
|
608
717
|
}
|
|
@@ -848,5 +957,5 @@ function reconcileTodos(tasks, agents, registeredGates) {
|
|
|
848
957
|
}
|
|
849
958
|
|
|
850
959
|
//#endregion
|
|
851
|
-
export { isKnownKind as _, renderTree as a, statesOf as b, monitorHint as c, openStore as d, DONE_STATE as f, initialState as g, canTransition as h, renderDigest as i, CycleError as l, ORPHANED_STATE as m, buildTreeJSON as n, unblockedTasks as o, LIFECYCLES as p, openBlockers as r, describeBlock as s, reconcileTodos as t, TodoStore as u, nextStates as v, requiredGate as y };
|
|
852
|
-
//# sourceMappingURL=todoAutomation-
|
|
960
|
+
export { isKnownKind as _, renderTree as a, statesOf as b, monitorHint as c, openStore as d, DONE_STATE as f, initialState as g, canTransition as h, renderDigest as i, CycleError as l, ORPHANED_STATE as m, buildTreeJSON as n, unblockedTasks as o, LIFECYCLES as p, openBlockers as r, describeBlock as s, reconcileTodos as t, TodoStore as u, nextStates as v, removeControlCharacters as x, requiredGate as y };
|
|
961
|
+
//# sourceMappingURL=todoAutomation-x6guaQXc.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import "./logger-CDIsZ-Pp.js";
|
|
2
|
-
import "./
|
|
3
|
-
import
|
|
4
|
-
import {
|
|
2
|
+
import { _ as isKnownKind, a as renderTree, d as openStore, i as renderDigest, l as CycleError, n as buildTreeJSON, o as unblockedTasks, p as LIFECYCLES, s as describeBlock, t as reconcileTodos, x as removeControlCharacters } from "./todoAutomation-x6guaQXc.js";
|
|
3
|
+
import "./JsonlStore-CWOA3aDH.js";
|
|
4
|
+
import { i as readGlobalPids } from "./globalPidIndex-Ca4sTr1b.js";
|
|
5
5
|
import yargs from "yargs";
|
|
6
6
|
|
|
7
7
|
//#region ts/todoCli.ts
|
|
@@ -47,6 +47,26 @@ import yargs from "yargs";
|
|
|
47
47
|
function fail(message) {
|
|
48
48
|
throw new Error(message);
|
|
49
49
|
}
|
|
50
|
+
/**
|
|
51
|
+
* Same check ask.html's own render-time guard uses — a real URL parse, not
|
|
52
|
+
* just a scheme-prefix regex, which could still let a malformed string
|
|
53
|
+
* through. Returns the parser's own normalized `.href` (not the raw input)
|
|
54
|
+
* on success, `null` otherwise: WHATWG URL parsing tolerates/strips some
|
|
55
|
+
* control characters (e.g. embedded tabs/newlines) from the input while
|
|
56
|
+
* still returning a valid http(s) URL, so validating against `s` but then
|
|
57
|
+
* STORING `s` verbatim could still persist those raw control characters
|
|
58
|
+
* into the store — later rendered as terminal/log text by `describeBlock()`
|
|
59
|
+
* (codex-review Important). Storing `.href` instead guarantees the store
|
|
60
|
+
* only ever holds what the parser actually validated.
|
|
61
|
+
*/
|
|
62
|
+
function normalizeHttpUrl(s) {
|
|
63
|
+
try {
|
|
64
|
+
const u = new URL(s);
|
|
65
|
+
return u.protocol === "http:" || u.protocol === "https:" ? u.href : null;
|
|
66
|
+
} catch {
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
50
70
|
function parseKind(raw) {
|
|
51
71
|
if (!raw) fail(`--kind is required (one of: ${Object.keys(LIFECYCLES).join(", ")})`);
|
|
52
72
|
if (!isKnownKind(raw)) fail(`unknown kind "${raw}" (one of: ${Object.keys(LIFECYCLES).join(", ")})`);
|
|
@@ -236,7 +256,11 @@ const blockCmd = {
|
|
|
236
256
|
describe: "required for --type blocked-by-human"
|
|
237
257
|
}).option("question", { type: "string" }).option("options", {
|
|
238
258
|
type: "string",
|
|
239
|
-
array: true
|
|
259
|
+
array: true,
|
|
260
|
+
describe: "choice-shape ask (/ask renders buttons)"
|
|
261
|
+
}).option("action-link", {
|
|
262
|
+
type: "string",
|
|
263
|
+
describe: "action-shape ask (/ask renders an 'open link, then confirm' button) — e.g. an OAuth/CAPTCHA URL"
|
|
240
264
|
}).option("signal", {
|
|
241
265
|
type: "string",
|
|
242
266
|
describe: "required for --type blocked-by-external"
|
|
@@ -257,11 +281,19 @@ const blockCmd = {
|
|
|
257
281
|
break;
|
|
258
282
|
case "blocked-by-human":
|
|
259
283
|
if (!argv.who) fail("--who <name> is required for --type blocked-by-human");
|
|
284
|
+
if (argv.options?.length && argv["action-link"]) fail("--options and --action-link are mutually exclusive (choice-shape vs action-shape ask)");
|
|
285
|
+
let normalizedActionLink;
|
|
286
|
+
if (argv["action-link"]) {
|
|
287
|
+
const normalized = normalizeHttpUrl(argv["action-link"]);
|
|
288
|
+
if (!normalized) fail(`--action-link must be a valid http:// or https:// URL (got "${removeControlCharacters(argv["action-link"]).replace(/[\r\n]+/g, " ")}")`);
|
|
289
|
+
normalizedActionLink = normalized;
|
|
290
|
+
}
|
|
260
291
|
block = {
|
|
261
292
|
type: "blocked-by-human",
|
|
262
293
|
who: argv.who,
|
|
263
294
|
question: argv.question,
|
|
264
|
-
options: argv.options
|
|
295
|
+
options: argv.options,
|
|
296
|
+
actionLink: normalizedActionLink
|
|
265
297
|
};
|
|
266
298
|
break;
|
|
267
299
|
case "blocked-by-external":
|
|
@@ -424,4 +456,4 @@ async function runTodoSubcommand(rest0) {
|
|
|
424
456
|
|
|
425
457
|
//#endregion
|
|
426
458
|
export { runTodoSubcommand };
|
|
427
|
-
//# sourceMappingURL=todoCli-
|
|
459
|
+
//# sourceMappingURL=todoCli-Cjhx3DqQ.js.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as getRunningAgentCount } from "./runningLock-
|
|
1
|
+
import { n as getRunningAgentCount } from "./runningLock-BFk3Mo8K.js";
|
|
2
2
|
import { existsSync } from "fs";
|
|
3
3
|
import { mkdir, readFile, unlink, writeFile } from "fs/promises";
|
|
4
4
|
import { homedir } from "os";
|
|
@@ -187,4 +187,4 @@ async function startTray() {
|
|
|
187
187
|
|
|
188
188
|
//#endregion
|
|
189
189
|
export { ensureTray, startTray };
|
|
190
|
-
//# sourceMappingURL=tray-
|
|
190
|
+
//# sourceMappingURL=tray-C8VfnS7s.js.map
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { n as logger, t as addTransport } from "./logger-CDIsZ-Pp.js";
|
|
2
|
-
import { r as getInstalledPackage } from "./versionChecker-
|
|
2
|
+
import { r as getInstalledPackage } from "./versionChecker-CgCXc8CJ.js";
|
|
3
3
|
import { t as agentYesHome } from "./agentYesHome-CtHb5b71.js";
|
|
4
|
-
import {
|
|
5
|
-
import { i as
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
4
|
+
import { d as openStore, p as LIFECYCLES, x as removeControlCharacters } from "./todoAutomation-x6guaQXc.js";
|
|
5
|
+
import { i as shouldUseLock, r as releaseLock, t as acquireLock } from "./runningLock-BFk3Mo8K.js";
|
|
6
|
+
import { i as readGlobalPids } from "./globalPidIndex-Ca4sTr1b.js";
|
|
7
|
+
import { t as PidStore } from "./pidStore-Hjba3K6Q.js";
|
|
8
|
+
import { r as recordInbox } from "./messageLog-zVGWLX7w.js";
|
|
9
|
+
import { n as register, r as sweep } from "./reaper-iQXyufgp.js";
|
|
9
10
|
import { arch, platform } from "process";
|
|
10
11
|
import { execSync } from "child_process";
|
|
11
12
|
import { closeSync, constants, createReadStream, existsSync, mkdirSync, openSync } from "fs";
|
|
@@ -23,6 +24,7 @@ import { execSync as execSync$1 } from "node:child_process";
|
|
|
23
24
|
import os from "node:os";
|
|
24
25
|
import { readFile as readFile$1 } from "node:fs/promises";
|
|
25
26
|
import path$1 from "node:path";
|
|
27
|
+
import { existsSync as existsSync$1 } from "node:fs";
|
|
26
28
|
|
|
27
29
|
//#region \0rolldown/runtime.js
|
|
28
30
|
var __defProp = Object.defineProperty;
|
|
@@ -288,18 +290,6 @@ try {
|
|
|
288
290
|
const ptyPackage = globalThis.Bun ? "bun-pty" : "node-pty";
|
|
289
291
|
var pty_default = pty;
|
|
290
292
|
|
|
291
|
-
//#endregion
|
|
292
|
-
//#region ts/removeControlCharacters.ts
|
|
293
|
-
const ESC = String.fromCharCode(27);
|
|
294
|
-
const C1 = String.fromCharCode(155);
|
|
295
|
-
const BACKSLASH = String.fromCharCode(92);
|
|
296
|
-
const ST_PATTERN_SOURCE = ESC + BACKSLASH + BACKSLASH;
|
|
297
|
-
const OSC_PATTERN = new RegExp(ESC + "][^\x07\x1B]*(?:\x07|" + ST_PATTERN_SOURCE + ")", "g");
|
|
298
|
-
const CSI_PATTERN = new RegExp("[" + ESC + C1 + "][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]", "g");
|
|
299
|
-
function removeControlCharacters(str) {
|
|
300
|
-
return str.replace(OSC_PATTERN, "").replace(CSI_PATTERN, "");
|
|
301
|
-
}
|
|
302
|
-
|
|
303
293
|
//#endregion
|
|
304
294
|
//#region ts/sessionEnv.ts
|
|
305
295
|
const CLAUDE_SESSION_PIN_ENV = [
|
|
@@ -1200,6 +1190,99 @@ async function notifyWebhook(status, details, cwd = process.cwd()) {
|
|
|
1200
1190
|
}
|
|
1201
1191
|
}
|
|
1202
1192
|
|
|
1193
|
+
//#endregion
|
|
1194
|
+
//#region ts/askApi.ts
|
|
1195
|
+
/**
|
|
1196
|
+
* `/ask` decision panel (A7): aggregates every `blocked-by-human` task across
|
|
1197
|
+
* every project this host's agents have registered onto one human-facing
|
|
1198
|
+
* view, and closes the loop when a human answers.
|
|
1199
|
+
*
|
|
1200
|
+
* Pure store logic only — no HTTP, no live-agent notification. `ts/serve.ts`
|
|
1201
|
+
* wires this into `GET /api/asks` / `POST /api/asks/answer` and, as a
|
|
1202
|
+
* best-effort follow-up after `answerAsk()` resolves, writes the answer into
|
|
1203
|
+
* the owning agent's terminal via the same FIFO mechanism `/api/send`
|
|
1204
|
+
* already uses (see that route) — kept out of this module so it stays
|
|
1205
|
+
* testable without a live server or live agent processes.
|
|
1206
|
+
*/
|
|
1207
|
+
/** Whether `projectRoot` has ever had an `ay todo` store created — used to skip candidate project roots (e.g. from a live-agent scan) that never called `ay todo` at all. */
|
|
1208
|
+
function hasTodoStore(projectRoot) {
|
|
1209
|
+
return existsSync$1(path$1.join(projectRoot, ".agent-yes", "todos.jsonl"));
|
|
1210
|
+
}
|
|
1211
|
+
async function listAsksForProject(projectRoot) {
|
|
1212
|
+
const store = await openStore(projectRoot);
|
|
1213
|
+
const asks = [];
|
|
1214
|
+
for (const t of store.all()) {
|
|
1215
|
+
if (t.block?.type !== "blocked-by-human") continue;
|
|
1216
|
+
const block = t.block;
|
|
1217
|
+
asks.push({
|
|
1218
|
+
projectRoot,
|
|
1219
|
+
taskId: t._id,
|
|
1220
|
+
summary: t.summary,
|
|
1221
|
+
who: block.who,
|
|
1222
|
+
question: block.question,
|
|
1223
|
+
options: block.options,
|
|
1224
|
+
actionLink: block.actionLink,
|
|
1225
|
+
shape: block.actionLink ? "action" : block.options?.length ? "choice" : "acknowledge",
|
|
1226
|
+
blockRev: t.blockRev ?? 0
|
|
1227
|
+
});
|
|
1228
|
+
}
|
|
1229
|
+
return asks;
|
|
1230
|
+
}
|
|
1231
|
+
/**
|
|
1232
|
+
* Aggregates asks across every project root that actually has a store —
|
|
1233
|
+
* candidates are supplied by the caller (`ts/serve.ts` derives them from the
|
|
1234
|
+
* live-agent registry's distinct `cwd`s), keeping this module itself
|
|
1235
|
+
* agent-registry-agnostic.
|
|
1236
|
+
*
|
|
1237
|
+
* Uses `Promise.allSettled`, not `Promise.all`: this is a cross-project
|
|
1238
|
+
* aggregation by design, and `Promise.all`'s fail-fast behavior meant ONE
|
|
1239
|
+
* project with an unreadable/corrupt store made the ENTIRE decision panel
|
|
1240
|
+
* return nothing (a 500 at the route level) — hiding every other project's
|
|
1241
|
+
* perfectly healthy asks too (codex-review Important). A failed project is
|
|
1242
|
+
* logged and skipped; the healthy ones are still returned.
|
|
1243
|
+
*/
|
|
1244
|
+
async function listAsks(projectRoots) {
|
|
1245
|
+
const withStore = [...new Set(projectRoots)].filter(hasTodoStore);
|
|
1246
|
+
const results = await Promise.allSettled(withStore.map((root) => listAsksForProject(root)));
|
|
1247
|
+
const asks = [];
|
|
1248
|
+
for (const [i, result] of results.entries()) if (result.status === "fulfilled") asks.push(...result.value);
|
|
1249
|
+
else console.error(`[askApi] listAsksForProject(${withStore[i]}) failed:`, result.reason);
|
|
1250
|
+
return asks;
|
|
1251
|
+
}
|
|
1252
|
+
async function answerAsk(projectRoot, taskId, answer) {
|
|
1253
|
+
const store = await openStore(projectRoot);
|
|
1254
|
+
const rec = store.get(taskId);
|
|
1255
|
+
if (!rec) throw new Error(`no such task: ${taskId}`);
|
|
1256
|
+
if (rec.block?.type !== "blocked-by-human") throw new Error(`task ${taskId} is not currently blocked-by-human (already answered, or blocked on something else)`);
|
|
1257
|
+
const expectedBlockRev = answer.expectedBlockRev ?? rec.blockRev ?? 0;
|
|
1258
|
+
const block = rec.block;
|
|
1259
|
+
let answerText;
|
|
1260
|
+
if (block.actionLink) {
|
|
1261
|
+
if (!answer.acknowledged) throw new Error(`task ${taskId}: this ask requires { acknowledged: true } after completing ${block.actionLink}`);
|
|
1262
|
+
answerText = "acknowledged";
|
|
1263
|
+
} else if (block.options?.length) {
|
|
1264
|
+
if (!answer.choice) throw new Error(`task ${taskId}: this ask requires a choice (one of: ${block.options.join(", ")})`);
|
|
1265
|
+
if (!block.options.includes(answer.choice)) throw new Error(`task ${taskId}: "${answer.choice}" is not one of the offered options (${block.options.join(", ")})`);
|
|
1266
|
+
answerText = answer.choice;
|
|
1267
|
+
} else {
|
|
1268
|
+
if (!answer.acknowledged) throw new Error(`task ${taskId}: this ask requires { acknowledged: true }`);
|
|
1269
|
+
answerText = "acknowledged";
|
|
1270
|
+
}
|
|
1271
|
+
const gate = rec.kind === "human" || rec.kind === "decision" ? (() => {
|
|
1272
|
+
const primary = LIFECYCLES[rec.kind].transitions.find((tr) => tr.from === rec.state && tr.gate);
|
|
1273
|
+
return primary?.gate ? {
|
|
1274
|
+
name: primary.gate,
|
|
1275
|
+
toState: primary.to,
|
|
1276
|
+
validator: block.who,
|
|
1277
|
+
note: answerText
|
|
1278
|
+
} : null;
|
|
1279
|
+
})() : null;
|
|
1280
|
+
return {
|
|
1281
|
+
record: await store.answerHumanBlock(taskId, expectedBlockRev, gate),
|
|
1282
|
+
answerText
|
|
1283
|
+
};
|
|
1284
|
+
}
|
|
1285
|
+
|
|
1203
1286
|
//#endregion
|
|
1204
1287
|
//#region ts/index.ts
|
|
1205
1288
|
const config = await import("./agent-yes.config-0G11aPWe.js").then((mod) => mod.default || mod);
|
|
@@ -1960,5 +2043,5 @@ function sleep(ms) {
|
|
|
1960
2043
|
}
|
|
1961
2044
|
|
|
1962
2045
|
//#endregion
|
|
1963
|
-
export {
|
|
1964
|
-
//# sourceMappingURL=ts-
|
|
2046
|
+
export { hasTodoStore as a, AgentContext as c, answerAsk as i, CLAUDE_SESSION_PIN_ENV as l, agentYes as n, listAsks as o, config as r, listAsksForProject as s, CLIS_CONFIG as t };
|
|
2047
|
+
//# sourceMappingURL=ts-oYrTk4Z_.js.map
|
|
@@ -7,7 +7,7 @@ import { fileURLToPath } from "url";
|
|
|
7
7
|
|
|
8
8
|
//#region package.json
|
|
9
9
|
var name = "agent-yes";
|
|
10
|
-
var version = "1.
|
|
10
|
+
var version = "1.229.0";
|
|
11
11
|
|
|
12
12
|
//#endregion
|
|
13
13
|
//#region ts/versionChecker.ts
|
|
@@ -215,4 +215,4 @@ async function displayVersion() {
|
|
|
215
215
|
|
|
216
216
|
//#endregion
|
|
217
217
|
export { versionString as i, displayVersion as n, getInstalledPackage as r, checkAndAutoUpdate as t };
|
|
218
|
-
//# sourceMappingURL=versionChecker-
|
|
218
|
+
//# sourceMappingURL=versionChecker-CgCXc8CJ.js.map
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import "./logger-CDIsZ-Pp.js";
|
|
2
|
-
import "./globalPidIndex-
|
|
3
|
-
import "./messageLog-
|
|
2
|
+
import "./globalPidIndex-Ca4sTr1b.js";
|
|
3
|
+
import "./messageLog-zVGWLX7w.js";
|
|
4
4
|
import "./configShared-YKfS6NMe.js";
|
|
5
|
-
import { S as listRecords } from "./subcommands-
|
|
5
|
+
import { S as listRecords } from "./subcommands-DzJbnYAx.js";
|
|
6
6
|
import "./e2e-DB7BDdEA.js";
|
|
7
7
|
import "./webrtcLink-CjckgIZe.js";
|
|
8
8
|
import "./remotes-ZqD0FHl_.js";
|
|
@@ -418,4 +418,4 @@ async function cmdWs(args) {
|
|
|
418
418
|
|
|
419
419
|
//#endregion
|
|
420
420
|
export { WS_JSON_SCHEMA, cmdWs, collectWorkspaces, isPathInside, loadProvision, workspaceStatus };
|
|
421
|
-
//# sourceMappingURL=ws-
|
|
421
|
+
//# sourceMappingURL=ws-D5q3R1kY.js.map
|
package/package.json
CHANGED