@paigy/harness 0.3.34 → 0.3.35

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 (3) hide show
  1. package/dist/cli.js +239 -120
  2. package/dist/main.js +237 -118
  3. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -23805,28 +23805,28 @@ function overrideToken(secret) {
23805
23805
  async function fail(what, res) {
23806
23806
  throw new ApiError(what, res.status, await res.text());
23807
23807
  }
23808
- async function createGoal(input, opts = {}) {
23808
+ async function manageGoals(input, opts = {}) {
23809
23809
  const token = authToken(opts.token) ?? "";
23810
- const res = await ensureAuthed(await (opts.reach ?? reach)(`${BACKEND_URL}/api/goals`, {
23810
+ const res = await ensureAuthed(await (opts.reach ?? reach)(`${BACKEND_URL}/api/goals/manage`, {
23811
23811
  method: "POST",
23812
- headers: { "content-type": "application/json", authorization: `Bearer ${token}`, "x-paigy-model": "goal-entry-v1" },
23812
+ headers: { "content-type": "application/json", authorization: `Bearer ${token}` },
23813
23813
  body: JSON.stringify(input)
23814
23814
  }));
23815
- if (!res.ok) await fail("create_goal", res);
23815
+ if (!res.ok) await fail("manage_goals", res);
23816
23816
  return await res.json();
23817
23817
  }
23818
23818
  async function claimGoal(goalId, opts = {}) {
23819
23819
  const token = authToken(opts.token) ?? "";
23820
- const res = await ensureAuthed(await (opts.reach ?? reach)(`${BACKEND_URL}/api/goals/claim`, { method: "POST", headers: { "content-type": "application/json", authorization: `Bearer ${token}`, "x-paigy-model": "goal-entry-v1" }, body: JSON.stringify(goalId ? { goalId } : {}) }));
23820
+ const res = await ensureAuthed(await (opts.reach ?? reach)(`${BACKEND_URL}/api/goals/claim`, { method: "POST", headers: { "content-type": "application/json", authorization: `Bearer ${token}` }, body: JSON.stringify(goalId ? { goalId } : {}) }));
23821
23821
  if (!res.ok) await fail("claim_goal", res);
23822
23822
  return await res.json();
23823
23823
  }
23824
- async function getGoal(goalId, opts = {}, read = {}) {
23824
+ async function getGoal(goalId, opts = {}, read3 = {}) {
23825
23825
  const token = authToken(opts.token) ?? "";
23826
- const query = [read.history ? "history=1" : "", read.diagnose ? "diagnose=1" : ""].filter(Boolean).join("&");
23826
+ const query = [read3.history ? "history=1" : "", read3.diagnose ? "diagnose=1" : ""].filter(Boolean).join("&");
23827
23827
  const res = await ensureAuthed(await (opts.reach ?? reach)(`${BACKEND_URL}/api/goals/${encodeURIComponent(goalId)}${query ? `?${query}` : ""}`, {
23828
23828
  method: "GET",
23829
- headers: { authorization: `Bearer ${token}`, "x-paigy-model": "goal-entry-v1" }
23829
+ headers: { authorization: `Bearer ${token}` }
23830
23830
  }));
23831
23831
  if (!res.ok) await fail("get_goal", res);
23832
23832
  return await res.json();
@@ -23834,7 +23834,7 @@ async function getGoal(goalId, opts = {}, read = {}) {
23834
23834
  async function updateGoal(goalId, input, opts = {}) {
23835
23835
  const token = authToken(opts.token) ?? "";
23836
23836
  const operationId = input.operationId ?? randomUUID2();
23837
- const res = await ensureAuthed(await (opts.reach ?? reach)(`${BACKEND_URL}/api/goals/${encodeURIComponent(goalId)}`, { method: "PATCH", headers: { "content-type": "application/json", authorization: `Bearer ${token}`, "x-paigy-model": "goal-entry-v1" }, body: JSON.stringify({ ...input, operationId }) }));
23837
+ const res = await ensureAuthed(await (opts.reach ?? reach)(`${BACKEND_URL}/api/goals/${encodeURIComponent(goalId)}`, { method: "PATCH", headers: { "content-type": "application/json", authorization: `Bearer ${token}` }, body: JSON.stringify({ ...input, operationId }) }));
23838
23838
  if (!res.ok) await fail("update_goal", res);
23839
23839
  return await res.json();
23840
23840
  }
@@ -23926,7 +23926,7 @@ async function listNotes(opts = {}) {
23926
23926
  }
23927
23927
  async function listConnections(opts = {}) {
23928
23928
  const res = await ensureAuthed(await reach(`${BACKEND_URL}/api/tokens`, {
23929
- headers: { authorization: `Bearer ${authToken(opts.token)}`, "x-paigy-model": "goal-entry-v1" }
23929
+ headers: { authorization: `Bearer ${authToken(opts.token)}` }
23930
23930
  }));
23931
23931
  if (!res.ok) throw new Error(`list_connections failed: ${res.status} ${await res.text()}`);
23932
23932
  return await res.json();
@@ -23976,9 +23976,10 @@ function currentRepo(cwd = process.cwd()) {
23976
23976
  }
23977
23977
  async function contact(input, opts = {}) {
23978
23978
  const parsed = ContactSchema.parse(input);
23979
+ if (!("asks" in parsed) && !("deliveryId" in parsed)) throw new Error("contact with nothing to send receives: call receiveContact");
23979
23980
  opts.signal?.throwIfAborted();
23980
23981
  const send22 = opts.reach ?? reach;
23981
- const headers = { "content-type": "application/json", authorization: `Bearer ${authToken(opts.token) ?? ""}`, "x-paigy-model": "goal-entry-v1" };
23982
+ const headers = { "content-type": "application/json", authorization: `Bearer ${authToken(opts.token) ?? ""}` };
23982
23983
  let deliveryId;
23983
23984
  let deliveries = [];
23984
23985
  let recorded = [];
@@ -24023,7 +24024,7 @@ async function contact(input, opts = {}) {
24023
24024
  const all = deliveries.filter((d) => !!d.deliveryId && !!d.goalId).map(({ id: id22, deliveryId: deliveryId2, goalId }) => ({ ...id22 ? { id: id22 } : {}, deliveryId: deliveryId2, goalId }));
24024
24025
  const joinedCard = deliveries[0]?.joinedCard === true;
24025
24026
  const joinedCall = deliveries[0]?.joinedCall === true;
24026
- const read = async (signal2) => {
24027
+ const read3 = async (signal2) => {
24027
24028
  const res = await ensureAuthed(await send22(`${BACKEND_URL}/api/deliveries/${encodeURIComponent(deliveryId)}`, { headers, signal: signal2 }));
24028
24029
  if (!res.ok) await fail("read_delivery", res);
24029
24030
  const one = await res.json();
@@ -24037,14 +24038,14 @@ async function contact(input, opts = {}) {
24037
24038
  };
24038
24039
  };
24039
24040
  const settled = (d) => d.kind === "notification" || d.state === "closed" || d.answers.length > 0 || d.entries.some((e) => e.kind === "contribution");
24040
- if (opts.waits === false) return read(opts.signal);
24041
+ if (opts.waits === false) return read3(opts.signal);
24041
24042
  const window = AbortSignal.timeout(AWAIT_WINDOW_MS);
24042
24043
  const signal = opts.signal ? AbortSignal.any([opts.signal, window]) : window;
24043
24044
  let latest;
24044
24045
  try {
24045
24046
  while (true) {
24046
24047
  signal.throwIfAborted();
24047
- latest = await read(signal);
24048
+ latest = await read3(signal);
24048
24049
  if (settled(latest)) return latest;
24049
24050
  await sleep2(5e3, void 0, { signal });
24050
24051
  }
@@ -24054,11 +24055,11 @@ async function contact(input, opts = {}) {
24054
24055
  throw error;
24055
24056
  }
24056
24057
  }
24057
- async function checkReplies(opts = {}) {
24058
+ async function receive(opts = {}) {
24058
24059
  const res = await ensureAuthed(await (opts.reach ?? reach)(`${BACKEND_URL}/api/deliveries`, {
24059
- headers: { authorization: `Bearer ${authToken(opts.token) ?? ""}`, "x-paigy-model": "goal-entry-v1" }
24060
+ headers: { authorization: `Bearer ${authToken(opts.token) ?? ""}` }
24060
24061
  }));
24061
- if (!res.ok) await fail("check_replies", res);
24062
+ if (!res.ok) await fail("receive", res);
24062
24063
  return await res.json();
24063
24064
  }
24064
24065
  function frame(line, topic, event, payload) {
@@ -24243,7 +24244,7 @@ ${block2}`;
24243
24244
  }
24244
24245
  return text.slice(0, start) + updated + text.slice(end);
24245
24246
  }
24246
- var import_undici, require2, CODEX_ENV, BACKEND_URL, NETWORK_MSG, PROXY_ENV, agent, INSTANCE_ID, WORKSPACE_ID, envSession, lineage, CLIENT, ignoreOverride, defaultOptions, getDefaultOptions, getRefs, getRelativePath, parseCatchDef, integerDateParser, isJsonSchema7AllOfType, emojiRegex2, zodPatterns, ALPHA_NUMERIC, primitiveMappings, asAnyOf, parseOptionalDef, parsePipelineDef, parseReadonlyDef, selectParser, get$ref, addMeta, zodToJsonSchema, OPTIONS_MIN, OPTIONS_MAX, OptionSchema, OptionInputSchema, NIGHT, AskInputSchema, StartContactSchema, ContactSchema, CONTACT_SCHEMA, CONTACT_DESCRIPTION, CreateGoalSchema, CreateGoalToolSchema, CREATE_GOAL_DESCRIPTION, UpdateGoalSchema, UpdateGoalToolSchema, ClaimGoalSchema, GetGoalSchema, GET_GOAL_DESCRIPTION, UPDATE_GOAL_DESCRIPTION, CLAIM_GOAL_DESCRIPTION, CHECK_REPLIES_DESCRIPTION, CheckRepliesSchema, AGENT_TOOLS, AGENT_TOOL_NAMES, id, key, participant, SourceSchema, ResultRefSchema, NodeRefSchema, DependencySchema, goalState, existingGoalChanges, GoalChangeSchema, BrainGoalChangeSchema, option, QuestionChangeSchema, lessonScope, LessonChangeSchema, BrainNextSchema, messageBase, BrainMessageSchema, BrainSearchSchema, BrainResultSchema, str, strs, CompactResultSchema, COMPACT_RESULT_JSON_SCHEMA, LIVE_MS, WORKING_MS, ContextSchema, ParticipantSchema, TransformSchema, VisualSchema, NotifyLevelSchema, SelectShapeSchema, ReceiptEventSchema, AttentionSchema, NotifyRequestFields, NotifyRequestSchema, NotifyStatusSchema, AgentStateSchema, TurnSchema, UserAnswerSchema, IntentSchema, RideAlongSchema, AwaitItemSchema, VoiceKeySchema, AgendaTurnSchema, CLAIM_STALE_MS, InboxItemSchema, APNS_TOKEN_RE, PushTokenSchema, MissedCallSchema, clock, QUIET, BrokerTuningSchema, UserSettingsSchema, HistoryWorkSchema, HistoryEntrySchema, HistoryPageSchema, ACTIVITY_LINES, ACTIVITY_LINE_MAX, AgentActivitySchema, ConnectionSummarySchema, LedgerItemSchema, AgentLedgerSchema, ReassignResultSchema, LessonStateSchema, LessonViewSchema, QueueQuestionSchema, QueueReplySchema, QueueItemSchema, QueueDeltaSchema, COLD_AFTER_MS, NoteSourceSchema, NoteStatusSchema, NoteRepeatSchema, DecisionSchema, NoteSchema, TriageItemSchema, TriageAssignmentSchema, TriageStatusSchema, SubmitTriageSchema, TriageProposalSchema, AcceptTriageSchema, AcceptTriageResultSchema, DeliveryModeSchema, WAKE_EVENT, wakeChannel, RegisterDeliverySchema, OAuthStartSchema, DeliveryConfigSchema, HostDecisionSchema, WakeNudgeSchema, PairingStatusSchema, DeviceCodeSchema, DeviceInfoSchema, DeviceTokenSchema, SupportRequestSchema, NotificationFeedbackKindSchema, SlimOptionSchema, QuestionRowSchema, WorkStateSchema, WorkRowSchema, ComputerRowSchema, AgentRowSchema, SnapshotSchema, CallRecapSchema, TOKEN_PATH, KEY_PATH, sleep, UnpairedError, RevokedError, ApiError, tokenOverride, authToken, AWAIT_WINDOW_MS, asked, NOT_SENT, DEMOTED, HEARTBEAT_MS, RETRY_MS, JOIN, JOIN_TIMEOUT_MS, lines;
24247
+ var import_undici, require2, CODEX_ENV, BACKEND_URL, NETWORK_MSG, PROXY_ENV, agent, INSTANCE_ID, WORKSPACE_ID, envSession, lineage, CLIENT, ignoreOverride, defaultOptions, getDefaultOptions, getRefs, getRelativePath, parseCatchDef, integerDateParser, isJsonSchema7AllOfType, emojiRegex2, zodPatterns, ALPHA_NUMERIC, primitiveMappings, asAnyOf, parseOptionalDef, parsePipelineDef, parseReadonlyDef, selectParser, get$ref, addMeta, zodToJsonSchema, OPTIONS_MIN, OPTIONS_MAX, OptionSchema, OptionInputSchema, NIGHT, AskInputSchema, StartContactSchema, ReceiveContactSchema, ContactSchema, CONTACT_SCHEMA, CONTACT_DESCRIPTION, CreateGoalSchema, UpdateGoalSchema, UpdateGoalToolSchema, changedGoal, goalTitle, goalOutcome, CreateChange, EditChange, StateChange, AssignChange, DeferChange, MoveChange, DependencyChange, read, GoalChangeSchema, editNames, ManageGoalsSchema, ManageGoalsToolSchema, MANAGE_GOALS_DESCRIPTION, ClaimGoalSchema, GetGoalSchema, GET_GOAL_DESCRIPTION, UPDATE_GOAL_DESCRIPTION, CLAIM_GOAL_DESCRIPTION, SearchToolSchema, SEARCH_DESCRIPTION, WhoIsWorkingSchema, AGENT_TOOLS, AGENT_TOOL_NAMES, id, key, participant, SourceSchema, ResultRefSchema, NodeRefSchema, DependencySchema, goalState, existingGoalChanges, BrainGoalChangeSchema, option, QuestionChangeSchema, lessonScope, LessonChangeSchema, BrainNextSchema, messageBase, BrainMessageSchema, BrainSearchSchema, BrainResultSchema, str, strs, CompactResultSchema, COMPACT_RESULT_JSON_SCHEMA, LIVE_MS, WORKING_MS, ContextSchema, ParticipantSchema, TransformSchema, VisualSchema, NotifyLevelSchema, SelectShapeSchema, ReceiptEventSchema, AttentionSchema, NotifyRequestFields, NotifyRequestSchema, NotifyStatusSchema, AgentStateSchema, TurnSchema, UserAnswerSchema, IntentSchema, RideAlongSchema, AwaitItemSchema, VoiceKeySchema, AgendaTurnSchema, CLAIM_STALE_MS, InboxItemSchema, APNS_TOKEN_RE, PushTokenSchema, MissedCallSchema, clock, QUIET, BrokerTuningSchema, UserSettingsSchema, HistoryWorkSchema, HistoryEntrySchema, HistoryPageSchema, ACTIVITY_LINES, ACTIVITY_LINE_MAX, AgentActivitySchema, ConnectionSummarySchema, LedgerItemSchema, AgentLedgerSchema, ReassignResultSchema, LessonStateSchema, LessonViewSchema, QueueQuestionSchema, QueueReplySchema, QueueItemSchema, QueueDeltaSchema, COLD_AFTER_MS, NoteSourceSchema, NoteStatusSchema, NoteRepeatSchema, DecisionSchema, NoteSchema, TriageItemSchema, TriageAssignmentSchema, TriageStatusSchema, SubmitTriageSchema, TriageProposalSchema, AcceptTriageSchema, AcceptTriageResultSchema, DeliveryModeSchema, WAKE_EVENT, wakeChannel, RegisterDeliverySchema, OAuthStartSchema, DeliveryConfigSchema, HostDecisionSchema, WakeNudgeSchema, PairingStatusSchema, DeviceCodeSchema, DeviceInfoSchema, DeviceTokenSchema, SupportRequestSchema, NotificationFeedbackKindSchema, SlimOptionSchema, QuestionRowSchema, WorkStateSchema, WorkRowSchema, ComputerRowSchema, AgentRowSchema, SnapshotSchema, CallRecapSchema, TOKEN_PATH, KEY_PATH, sleep, UnpairedError, RevokedError, ApiError, tokenOverride, authToken, AWAIT_WINDOW_MS, asked, NOT_SENT, DEMOTED, HEARTBEAT_MS, RETRY_MS, JOIN, JOIN_TIMEOUT_MS, lines;
24247
24248
  var init_dist = __esm({
24248
24249
  "../../packages/sdk/dist/index.js"() {
24249
24250
  "use strict";
@@ -24677,9 +24678,17 @@ var init_dist = __esm({
24677
24678
  waiting: external_exports.enum(["none", "hard"]).default("none").describe("hard requests a call even when channel is notification; user permissions and ring cooldowns still apply."),
24678
24679
  channel: external_exports.enum(["notification", "call"]).default("notification")
24679
24680
  }).strict();
24680
- ContactSchema = external_exports.union([StartContactSchema, external_exports.object({ deliveryId: external_exports.string().uuid() }).strict()]);
24681
+ ReceiveContactSchema = external_exports.object({
24682
+ wait: external_exports.boolean().optional().describe(
24683
+ "Only controls when this returns. true (the default when you send and acknowledge nothing): wait up to about 45 seconds for incoming communication addressed to you, and return as soon as some is available. false: return what is waiting now. It does not mean work is blocked, set urgency, or ask for a call. `waitOutcome` says which happened: `available`, `expired` (nothing arrived in the window; wait again without sending again), or `not_waited` (a hosted connection never holds a wait)."
24684
+ ),
24685
+ ackEventIds: external_exports.array(external_exports.string().uuid()).min(1).max(100).optional().describe(
24686
+ "The exact eventIds of the events you have handled: an acknowledgment (ACK). Reading alone acknowledges nothing, so an event comes back until you acknowledge it; after that the next batch can come. Each recipient acknowledges separately, for itself only. A Question you owe is answered (an ask with `answers`), never acknowledged away: that id is refused until it is answered."
24687
+ )
24688
+ }).strict();
24689
+ ContactSchema = external_exports.union([StartContactSchema, external_exports.object({ deliveryId: external_exports.string().uuid() }).strict(), ReceiveContactSchema]);
24681
24690
  CONTACT_SCHEMA = { type: "object", ...mcpInputSchema(ContactSchema) };
24682
- CONTACT_DESCRIPTION = "Contact the user with one or more asks/questions. Pass an array of asks (each with 'ask', optional 'options', 'select', 'id', 'parentId', 'repo'), plus channel:'notification'|'call', and waiting:'none'|'hard'. An ask that names a Goal (parentId) goes onto that Goal; one that names none starts a new Goal of yours. Notification returns immediately; collect durable answers with check_replies. On stdio, a Call holds one cancellable ~45s window; continue with ONLY {deliveryId}. One question per 'ask'; several questions are several objects in 'asks'. Each ask is sent exactly as written, with no reading in between: a bundled ask arrives as one card, so separate questions are separate asks. An ask with no options that is not blocking is a report, and a report is an UPDATE, never a claim on them: it reaches them and is listed apart from what waits on them, so no answer is owed and none should be awaited. On a Goal whose report card is still open it is added to that card, with no new push; Where your work stands while under way is progress: report it with update_goal, not contact. Send options (or waiting:'hard') when you actually need an answer. Each option's label must stand on its own \u2014 the person may see only the labels \u2014 so never a label that points into your text ('All three', 'Option 2', '1 and 3 only'). select:'many' makes the card a checklist, for independent options they may want several of; select:'one' (the default) a pick, for alternatives. The person can always answer in their own words, so never add an 'Other' option. If the person is already on a call, your contact joins that call automatically \u2014 whatever channel you asked for, with no ring \u2014 and the Delivery it returns IS that call: reread it with contact({deliveryId}) to see everything answered on it so far, and contact again while it is live to add information or a further question to the same call.";
24691
+ CONTACT_DESCRIPTION = "Contact the user with one or more asks/questions. Pass an array of asks (each with 'ask', optional 'options', 'select', 'id', 'parentId', 'repo'), plus channel:'notification'|'call', and waiting:'none'|'hard'. An ask that names a Goal (parentId) goes onto that Goal; one that names none starts a new Goal of yours. Notification returns immediately; collect answers by receiving (below). On stdio, a Call holds one cancellable ~45s window; continue with ONLY {deliveryId}. One question per 'ask'; several questions are several objects in 'asks'. Each ask is sent exactly as written, with no reading in between: a bundled ask arrives as one card, so separate questions are separate asks. An ask with no options that is not blocking is a report, never a claim on them, so no answer is owed and none should be awaited. A report reaches the person only when it answers something they asked you, or once the Goal is done; any other report is recorded as the Goal's progress and nobody is notified. So when the work is finished, mark the Goal done first, then send one message saying what is done and anything they need to do or check. On a Goal whose report card is still open, a report that does reach them is added to that card, with no new push. Send options (or waiting:'hard') when you actually need an answer. Each option's label must stand on its own \u2014 the person may see only the labels \u2014 so never a label that points into your text ('All three', 'Option 2', '1 and 3 only'). select:'many' makes the card a checklist, for independent options they may want several of; select:'one' (the default) a pick, for alternatives. The person can always answer in their own words, so never add an 'Other' option. If the person is already on a call, a contact that reaches them joins that call automatically \u2014 whatever channel you asked for, with no ring \u2014 and the Delivery it returns IS that call: reread it with contact({deliveryId}) to see everything answered on it so far, and contact again while it is live to add information or a further question to the same call.\n\nRECEIVING: contact with no asks sends nothing and returns `events`, a limited batch of what is addressed to you (not a history page): `question`, a Question you owe (answer it with an ask whose `answers` is its questionId); `update`, something new on one of your Goals (a reply, an answer: read it with get_goal); `instruction`, a request or note sent to you. `hasMore` says more are waiting. Reading acknowledges nothing: once you have handled events, confirm their eventIds with contact({ackEventIds}), and the next batch can come. contact({}) waits up to about 45 seconds for something to arrive; contact({wait:false}) returns at once. It also lists work given to you that nobody has started (`assigned`; claim_goal starts it) and your work gone quiet (`stalled`).";
24683
24692
  CreateGoalSchema = external_exports.object({
24684
24693
  outcome: external_exports.string().trim().min(1).max(1e4),
24685
24694
  /** The work's NAME (#2115) — one to five words, how a person refers to it out loud ("the night
@@ -24699,10 +24708,6 @@ var init_dist = __esm({
24699
24708
  * repo name. Delegated work inherits this from its parent Goal when omitted. */
24700
24709
  repo: external_exports.string().trim().min(1).max(200).optional()
24701
24710
  });
24702
- CreateGoalToolSchema = CreateGoalSchema.extend({
24703
- idempotencyKey: CreateGoalSchema.shape.idempotencyKey.optional().describe("Optional. One is minted per call; pass your own only so a retry lands on the same Goal.")
24704
- }).strict();
24705
- CREATE_GOAL_DESCRIPTION = 'Create a durable Goal for an outcome. Without parentGoalId it is placed against your open Goals: if one already IS this work, that Goal comes back (existing: true) and nothing new is created \u2014 continue it; if the work belongs under one, it is created there (parentGoalId in the receipt); otherwise it is a root. Pass parentGoalId yourself to put it under a specific Goal. Pass repo to anchor the work to a specific repository ("owner/repo" or repo name); delegated children inherit it. Pass title to name it in one to five words, as a person would refer to it out loud ("the night rings") \u2014 it heads every list and is spoken on a call; without one the brain writes it. Admission only: claim it before doing work, then update it as it advances. Returns an admission receipt with goalId, current state, revision, ownerParticipant, and the next step; no Goal content or execution lease.';
24706
24711
  UpdateGoalSchema = external_exports.object({
24707
24712
  revision: external_exports.number().int().positive(),
24708
24713
  changes: external_exports.object({
@@ -24726,7 +24731,65 @@ var init_dist = __esm({
24726
24731
  reason: external_exports.string().trim().min(1).max(2e3),
24727
24732
  operationId: external_exports.string().uuid().optional()
24728
24733
  }).strict();
24729
- UpdateGoalToolSchema = UpdateGoalSchema.omit({ operationId: true }).extend({ goalId: external_exports.string().uuid() }).strict();
24734
+ UpdateGoalToolSchema = external_exports.object({
24735
+ goalId: external_exports.string().uuid(),
24736
+ revision: UpdateGoalSchema.shape.revision,
24737
+ changes: UpdateGoalSchema.shape.changes.innerType().pick({ progress: true, reviewed: true, dueAt: true, withdraw: true }).strict().refine((v) => Object.keys(v).length > 0),
24738
+ reason: UpdateGoalSchema.shape.reason
24739
+ }).strict();
24740
+ changedGoal = external_exports.string().uuid().describe("The Goal to change, as a read shows it.");
24741
+ goalTitle = external_exports.string().trim().min(1).max(80).describe("The Goal's short display name: one to five words, how a person refers to it out loud.");
24742
+ goalOutcome = external_exports.string().trim().min(1).max(1e4).describe("The full desired result. There is no third description field.");
24743
+ CreateChange = external_exports.object({
24744
+ kind: external_exports.literal("create"),
24745
+ title: goalTitle,
24746
+ outcome: goalOutcome,
24747
+ ownerId: external_exports.string().trim().min(1).optional().describe("Who owns the work: an agent's participant (as who_is_working shows it) or the person's. Omitted: you."),
24748
+ parentGoalId: external_exports.string().uuid().optional().describe("The Goal it belongs under. Omitted: a root."),
24749
+ sourceEntryIds: external_exports.array(external_exports.string().uuid()).max(20).optional().describe("The whole Entries the work came from, ones you can read.")
24750
+ }).strict();
24751
+ EditChange = external_exports.object({ kind: external_exports.literal("edit"), goalId: changedGoal, title: goalTitle.optional(), outcome: goalOutcome.optional() }).strict();
24752
+ StateChange = external_exports.object({ kind: external_exports.literal("state"), goalId: changedGoal, state: external_exports.enum(["open", "completed", "canceled"]).describe(
24753
+ "completed: the Goal's own work is done now (refused while required children are open); open: reopen it; canceled: it will not be done."
24754
+ ) }).strict();
24755
+ AssignChange = external_exports.object({ kind: external_exports.literal("assign"), goalId: changedGoal, ownerId: external_exports.string().trim().min(1).describe("The new owner's participant.") }).strict();
24756
+ DeferChange = external_exports.object({ kind: external_exports.literal("defer"), goalId: changedGoal, until: external_exports.string().datetime({ offset: true }).nullable().describe(
24757
+ "Postpone it until this instant (its owner is woken then), or null to take the postponement back."
24758
+ ) }).strict();
24759
+ MoveChange = external_exports.object({ kind: external_exports.literal("move"), goalId: changedGoal, parentGoalId: external_exports.string().uuid().nullable().describe(
24760
+ "Its new parent, or null for a root. Only this Goal moves; its new parent's other children stay."
24761
+ ) }).strict();
24762
+ DependencyChange = external_exports.object({
24763
+ kind: external_exports.literal("dependency"),
24764
+ change: external_exports.enum(["add", "remove"]),
24765
+ goalId: changedGoal,
24766
+ dependsOnGoalId: external_exports.string().uuid().describe("The Goal it waits on."),
24767
+ action: external_exports.enum(["start", "complete"]).describe("What waits: starting goalId, or completing it."),
24768
+ reason: external_exports.string().trim().min(1).max(2e3).optional().describe("Why, as an explanation, never as policy.")
24769
+ }).strict();
24770
+ read = { revision: external_exports.number().int().positive().optional() };
24771
+ GoalChangeSchema = external_exports.discriminatedUnion("kind", [
24772
+ CreateChange,
24773
+ EditChange.extend(read),
24774
+ StateChange.extend(read),
24775
+ AssignChange.extend(read),
24776
+ DeferChange.extend(read),
24777
+ MoveChange.extend(read),
24778
+ DependencyChange
24779
+ ]);
24780
+ editNames = (changes, ctx) => changes.forEach((c, i) => {
24781
+ if (c.kind === "edit" && c.title === void 0 && c.outcome === void 0) {
24782
+ ctx.addIssue({ code: external_exports.ZodIssueCode.custom, path: ["changes", i], message: "an edit supplies title, outcome, or both" });
24783
+ }
24784
+ });
24785
+ ManageGoalsSchema = external_exports.object({
24786
+ requestId: external_exports.string().uuid().optional(),
24787
+ changes: external_exports.array(GoalChangeSchema).min(1).max(50)
24788
+ }).strict().superRefine((v, ctx) => editNames(v.changes, ctx));
24789
+ ManageGoalsToolSchema = external_exports.object({
24790
+ changes: external_exports.array(external_exports.discriminatedUnion("kind", [CreateChange, EditChange, StateChange, AssignChange, DeferChange, MoveChange, DependencyChange])).min(1).max(50).describe("The changes, applied in order, each on its own.")
24791
+ }).strict().superRefine((v, ctx) => editNames(v.changes, ctx));
24792
+ MANAGE_GOALS_DESCRIPTION = "Create, edit, assign, organize or close work. Every change here changes Goals; answering, withdrawing or asking Questions stays in contact. Each change applies independently: a refused one names why (`results[i].error`, e.g. goal_revision_conflict, goal_children_open, goal_not_joined, goal_not_found) and the rest still apply, so read every result: a partial result is never a complete success. Kinds: create (title, outcome, ownerId, parentGoalId, sourceEntryIds) returns the new Goal's id in `results[i].goalId`, in the order requested, to use in later calls; edit (title and/or outcome); state (open, completed, canceled); assign (ownerId); defer (until, or null); move (parentGoalId, or null for a root: only this Goal moves); dependency (add or remove: goalId waits on dependsOnGoalId to start or to complete). A Goal cannot be completed while its required children or dependencies remain open: finish or move them first. Finishing the children does not prove the parent's own work is done. An edit applies at the version you last read: if someone changed the Goal since, it is refused as goal_revision_conflict, so read it again (get_goal) and reconsider. You may change a Goal you own or have written on. Returns `ok` (every change applied), `results` per change (applied or failed), and `goals`, each changed Goal's id, state, title, outcome and revision.";
24730
24793
  ClaimGoalSchema = external_exports.object({ goalId: external_exports.string().uuid().optional() }).strict();
24731
24794
  GetGoalSchema = external_exports.object({
24732
24795
  goalId: external_exports.string().uuid(),
@@ -24739,18 +24802,24 @@ var init_dist = __esm({
24739
24802
  diagnose: external_exports.boolean().optional()
24740
24803
  }).strict();
24741
24804
  GET_GOAL_DESCRIPTION = "Read one Goal without claiming it, including others (the ten most recent other contributors, with names, latest entry headlines and times): its outcome, state, revision, progress, blockers, the conversation on it (each question with its options and what was decided), `next`, the one step to take, and `more`, where to read further. A question in that conversation reads `open` (nothing yet), `answered` (a choice was made, and `answer` carries it), `replied` (they said something and the read settled the question on their words \u2014 NO option of yours was chosen, and the words are the reply line beside it, so read that before you act), or `closed`. The conversation carries everything the person said, every open question and your newest entry; your older entries are left out and counted \u2014 history: true reads every entry in full. Every Goal of your person is readable, whichever of their agents owns it; another account's Goals are not disclosed.\n\ndiagnose: true is for when a read has CONFUSED you \u2014 not for the working loop. It adds `diagnosis`, which asks every reader that already answers a question about your work and NAMES the reader behind every value, so you never guess which of two places to look: what state your work is really in (the stored `goals.state` beside the derived `goal_execution_state`, which can differ); whether anything is armed to ring and when (`ladder_candidates`, with the ladder's own last decision); whether a wake fired for you and what it did (durable `wake.*` events, beside when your process was last heard from); and what has reached you (`list_waiting` \u2014 review flags, unstarted work, open questions, the person's newest words). Read `diagnosis.disagreements` FIRST: each one is two readers giving different values for the same fact, with both values and both sources, and it never chooses between them \u2014 that is yours to do, from the Goal's own history. `diagnosis.looked` names every reader asked, including any that could not answer, so an empty answer is never confused with a broken one.";
24742
- UPDATE_GOAL_DESCRIPTION = `Update a Goal you are on at an exact revision. You are on a Goal you own, or one you have written on (an update with progress, or a contact on it); any of your person's agents may write on any of their Goals, and one that never touched a Goal is refused (409 goal_not_joined). State, ownership, dependencies, children, progress, title, and review acknowledgement are explicit; stale revisions are rejected. A CONTACT ON THIS GOAL MOVES ITS REVISION: a question filed on a Goal is a change to it, so an update prepared before a contact and sent after it is refused as stale (409 goal_revision_conflict) \u2014 re-read the Goal, then write. title is the work's name in one to five words, as a person would refer to it out loud (it is spoken on a call and heads every list); null clears it. reviewed: true acknowledges new evidence and closes the Deliveries addressed to you on that Goal, never over an open decision. dueAt (an ISO instant, or null) makes the Goal wait until then; when it passes you are woken for it \u2014 use it for a promise to follow up later. withdraw: [questionId] takes back a question YOU asked on this Goal that is still open \u2014 because you acted on it yourself, it no longer matters, or you asked it wrongly (e.g. waiting: hard when nothing was blocked): it is cancelled, not answered, its card closes and it stops ringing; the id is the one the conversation shows. state: done means the work was accomplished, and it can be reopened: when the person says it is not done ("it's not working"), set state: active on that same Goal instead of starting a new one; its parent reopens with it. state: done while children are still open records your part as done: the Goal waits and closes by itself when its last open child closes. cancelled is final. Returns the Goal as get_goal reads it, at its new revision.`;
24743
- CLAIM_GOAL_DESCRIPTION = "Claim a pending answer to your question or the oldest runnable or review-pending Goal you own. Pass goalId to join any Goal of your person; its assignment stays unchanged. Read others before overlapping another agent\u2019s work. Joining lets you contribute and change its state; use update_goal with ownerParticipant when the assignment itself should change. Returns the Goal as get_goal reads it, and marks you as on it, which never shuts another agent out: other agents of your person may write on it and change it too, and two changes at once are told apart by revision (409 goal_revision_conflict).";
24744
- CHECK_REPLIES_DESCRIPTION = "What is waiting for you: your open Deliveries (a request the user started toward you, a handoff), one row each with its Goals, how many decisions are still open, and the newest words in brief; `assigned`, your Goals nobody has started yet, however they became yours (claim_goal({goalId}) starts one); and `review`, your Goals with something new on them \u2014 the user's answers and notes are Entries on the Goal, not Deliveries. A pure read with no arguments: nothing is consumed, acknowledged or claimed by reading it, so call it on startup, after a long wait, or whenever you want to know what is outstanding. To act on one, claim its Goal (claim_goal) or reread a Delivery in full with contact({deliveryId}). Once you have acted on what arrived, update_goal with reviewed: true clears the Goal from `review` and closes the Deliveries addressed to you on it.";
24745
- CheckRepliesSchema = external_exports.object({}).strict();
24805
+ UPDATE_GOAL_DESCRIPTION = "Report work on a Goal you are on, at an exact revision: progress, review acknowledgement, when to wake for it, and withdrawing a question of yours. What the Goal is (its title, outcome, state, owner, parent, dependencies) changes with manage_goals. You are on a Goal you own, or one you have written on (an update with progress, or a contact on it); any of your person's agents may write on any of their Goals, and one that never touched a Goal is refused (409 goal_not_joined). Stale revisions are rejected. A CONTACT ON THIS GOAL MOVES ITS REVISION: a question filed on a Goal is a change to it, so an update prepared before a contact and sent after it is refused as stale (409 goal_revision_conflict) \u2014 re-read the Goal, then write. progress says where the work stands. reviewed: true acknowledges new evidence and closes the Deliveries addressed to you on that Goal, never over an open decision (contact({ackEventIds}) does the same for an `update` event). dueAt (an ISO instant, or null) makes the Goal wait until then; when it passes you are woken for it \u2014 use it for a promise to follow up later. withdraw: [questionId] takes back a question YOU asked on this Goal that is still open \u2014 because you acted on it yourself, it no longer matters, or you asked it wrongly (e.g. waiting: hard when nothing was blocked): it is cancelled, not answered, its card closes and it stops ringing; the id is the one the conversation shows. Returns the Goal as get_goal reads it, at its new revision.";
24806
+ CLAIM_GOAL_DESCRIPTION = "Claim a pending answer to your question or the oldest runnable or review-pending Goal you own. Pass goalId to join any Goal of your person; its assignment stays unchanged. Read others before overlapping another agent\u2019s work. Joining lets you contribute and change it; use manage_goals (assign) when the assignment itself should change. Returns the Goal as get_goal reads it, and marks you as on it, which never shuts another agent out: other agents of your person may write on it and change it too, and two changes at once are told apart by revision (409 goal_revision_conflict).";
24807
+ SearchToolSchema = external_exports.object({
24808
+ query: external_exports.string().trim().min(1).max(500),
24809
+ types: external_exports.array(external_exports.enum(["entry", "goal", "answer"])).min(1).optional(),
24810
+ goalId: external_exports.string().uuid().optional(),
24811
+ limit: external_exports.number().int().min(1).max(20).optional()
24812
+ }).strict();
24813
+ SEARCH_DESCRIPTION = "Search your person's history across all of their agents: Entries (what anyone said or wrote, typed or spoken on a call), Goals (by title and outcome) and Answers (found by their Question or by the words that gave them). query is words to look for; records sharing more of its words rank first, and exact names work. types narrows it to entry, goal and/or answer (default: all three). goalId searches under one Goal: its Entries, its Questions' Answers, and it and its immediate children. limit is matches per type, 1 to 20 (default 8). Read-only. Each match carries its whole saved words, its ID and its links (an Answer carries its Question, the choice made and the Entries that support it); `omitted` counts what matched but was left out, so narrow the words or add a goalId to see it. Nothing found is not proof that nothing exists; a refused search says why. Sealed (encrypted) content is never searched or returned.";
24814
+ WhoIsWorkingSchema = external_exports.object({}).strict();
24746
24815
  AGENT_TOOLS = [
24747
- { name: "who_is_working", description: "Read your person's agents that contributed in the last 24 hours, newest first: at most 30 agents and their five most recently touched Goals, with their latest entry headline and time. Use get_goal to read a Goal and its other contributors before starting overlapping work. Read-only; no arguments.", inputSchema: mcpInputSchema(CheckRepliesSchema) },
24816
+ { name: "who_is_working", description: "Read your person's agents that contributed in the last 24 hours, newest first: at most 30 agents and their five most recently touched Goals, with their latest entry headline and time. Use get_goal to read a Goal and its other contributors before starting overlapping work. Read-only; no arguments.", inputSchema: mcpInputSchema(WhoIsWorkingSchema) },
24748
24817
  { name: "contact", description: CONTACT_DESCRIPTION, inputSchema: CONTACT_SCHEMA },
24749
- { name: "check_replies", description: CHECK_REPLIES_DESCRIPTION, inputSchema: mcpInputSchema(CheckRepliesSchema) },
24750
- { name: "create_goal", description: CREATE_GOAL_DESCRIPTION, inputSchema: mcpInputSchema(CreateGoalToolSchema) },
24818
+ { name: "manage_goals", description: MANAGE_GOALS_DESCRIPTION, inputSchema: mcpInputSchema(ManageGoalsToolSchema) },
24751
24819
  { name: "claim_goal", description: CLAIM_GOAL_DESCRIPTION, inputSchema: mcpInputSchema(ClaimGoalSchema) },
24752
24820
  { name: "get_goal", description: GET_GOAL_DESCRIPTION, inputSchema: mcpInputSchema(GetGoalSchema) },
24753
- { name: "update_goal", description: UPDATE_GOAL_DESCRIPTION, inputSchema: mcpInputSchema(UpdateGoalToolSchema) }
24821
+ { name: "update_goal", description: UPDATE_GOAL_DESCRIPTION, inputSchema: mcpInputSchema(UpdateGoalToolSchema) },
24822
+ { name: "search", description: SEARCH_DESCRIPTION, inputSchema: mcpInputSchema(SearchToolSchema) }
24754
24823
  ];
24755
24824
  AGENT_TOOL_NAMES = AGENT_TOOLS.map((t) => t.name);
24756
24825
  id = external_exports.string().uuid();
@@ -24781,17 +24850,6 @@ var init_dist = __esm({
24781
24850
  reason: external_exports.string().max(500).optional()
24782
24851
  }).strict()
24783
24852
  ];
24784
- GoalChangeSchema = external_exports.union([
24785
- external_exports.object({
24786
- kind: external_exports.literal("create"),
24787
- title: external_exports.string().min(1).max(120),
24788
- outcome: external_exports.string().min(1),
24789
- ownerId: participant,
24790
- parentGoalId: id.optional(),
24791
- sourceEntryIds: external_exports.array(id)
24792
- }).strict(),
24793
- ...existingGoalChanges
24794
- ]);
24795
24853
  BrainGoalChangeSchema = external_exports.union([
24796
24854
  // newSession: Paigy starts a session to own it (owner, 2026-10-06); until it has, the person owns it.
24797
24855
  external_exports.object({
@@ -25175,7 +25233,7 @@ var init_dist = __esm({
25175
25233
  /** The awaited ask was REPLACED by a newer notification on its thread (e.g. a
25176
25234
  * post-feedback revision, #633) — the user will never answer this id. Stop
25177
25235
  * awaiting it; the live ask is the thread's newest turn (await that one, or
25178
- * re-orient via check_replies). */
25236
+ * re-orient via contact({})). */
25179
25237
  external_exports.object({
25180
25238
  type: external_exports.literal("superseded"),
25181
25239
  parentId: external_exports.string(),
@@ -25905,7 +25963,7 @@ var init_dist = __esm({
25905
25963
  goalId: external_exports.string().uuid().nullable().optional(),
25906
25964
  /** When the server last heard from the agent, as the host read it: the presence it stood back for. */
25907
25965
  seenAt: external_exports.string().datetime().nullable().optional(),
25908
- /** When that work last moved (`claimable.since` on `check_replies`), the fact the bound is judged on. */
25966
+ /** When that work last moved (`claimable.since` on an agent's `contact({})` read), the fact the bound is judged on. */
25909
25967
  since: external_exports.string().datetime().nullable().optional(),
25910
25968
  /** What the host said, in its log's own words: why it stood back, or what the take-over did. */
25911
25969
  said: external_exports.string().max(300).optional()
@@ -26140,7 +26198,7 @@ var init_dist = __esm({
26140
26198
  tokenOverride = null;
26141
26199
  authToken = (explicit) => explicit ?? tokenOverride ?? readToken();
26142
26200
  AWAIT_WINDOW_MS = 45e3;
26143
- NOT_SENT = "Recorded as progress, not sent: nobody was notified. If the person should see it (a result, something to try or check, a finding), contact again and say so; report progress with update_goal.";
26201
+ NOT_SENT = "Recorded as the Goal's progress, not sent: nobody was notified. The person is told only a question, an answer to one they asked you, and what you say once the Goal is done. To close the work, mark the Goal done first, then send the one message saying what is done and anything they need to do or check.";
26144
26202
  DEMOTED = "Delivered as a card, not a call: the person's settings do not allow a call right now (silent, quiet hours, or a mode). It has reached them; do not send it again, with or without a Goal.";
26145
26203
  HEARTBEAT_MS = 25e3;
26146
26204
  RETRY_MS = [1e3, 2e3, 5e3, 1e4, 3e4];
@@ -28073,27 +28131,27 @@ var require_chunkstream = __commonJS({
28073
28131
  this._buffers = null;
28074
28132
  this.emit("close");
28075
28133
  };
28076
- ChunkStream.prototype._processReadAllowingLess = function(read) {
28134
+ ChunkStream.prototype._processReadAllowingLess = function(read3) {
28077
28135
  this._reads.shift();
28078
28136
  let smallerBuf = this._buffers[0];
28079
- if (smallerBuf.length > read.length) {
28080
- this._buffered -= read.length;
28081
- this._buffers[0] = smallerBuf.slice(read.length);
28082
- read.func.call(this, smallerBuf.slice(0, read.length));
28137
+ if (smallerBuf.length > read3.length) {
28138
+ this._buffered -= read3.length;
28139
+ this._buffers[0] = smallerBuf.slice(read3.length);
28140
+ read3.func.call(this, smallerBuf.slice(0, read3.length));
28083
28141
  } else {
28084
28142
  this._buffered -= smallerBuf.length;
28085
28143
  this._buffers.shift();
28086
- read.func.call(this, smallerBuf);
28144
+ read3.func.call(this, smallerBuf);
28087
28145
  }
28088
28146
  };
28089
- ChunkStream.prototype._processRead = function(read) {
28147
+ ChunkStream.prototype._processRead = function(read3) {
28090
28148
  this._reads.shift();
28091
28149
  let pos = 0;
28092
28150
  let count = 0;
28093
- let data = Buffer.alloc(read.length);
28094
- while (pos < read.length) {
28151
+ let data = Buffer.alloc(read3.length);
28152
+ while (pos < read3.length) {
28095
28153
  let buf = this._buffers[count++];
28096
- let len = Math.min(buf.length, read.length - pos);
28154
+ let len = Math.min(buf.length, read3.length - pos);
28097
28155
  buf.copy(data, pos, 0, len);
28098
28156
  pos += len;
28099
28157
  if (len !== buf.length) {
@@ -28103,17 +28161,17 @@ var require_chunkstream = __commonJS({
28103
28161
  if (count > 0) {
28104
28162
  this._buffers.splice(0, count);
28105
28163
  }
28106
- this._buffered -= read.length;
28107
- read.func.call(this, data);
28164
+ this._buffered -= read3.length;
28165
+ read3.func.call(this, data);
28108
28166
  };
28109
28167
  ChunkStream.prototype._process = function() {
28110
28168
  try {
28111
28169
  while (this._buffered > 0 && this._reads && this._reads.length > 0) {
28112
- let read = this._reads[0];
28113
- if (read.allowLess) {
28114
- this._processReadAllowingLess(read);
28115
- } else if (this._buffered >= read.length) {
28116
- this._processRead(read);
28170
+ let read3 = this._reads[0];
28171
+ if (read3.allowLess) {
28172
+ this._processReadAllowingLess(read3);
28173
+ } else if (this._buffered >= read3.length) {
28174
+ this._processRead(read3);
28117
28175
  } else {
28118
28176
  break;
28119
28177
  }
@@ -29738,12 +29796,12 @@ var require_sync_reader = __commonJS({
29738
29796
  };
29739
29797
  SyncReader.prototype.process = function() {
29740
29798
  while (this._reads.length > 0 && this._buffer.length) {
29741
- let read = this._reads[0];
29742
- if (this._buffer.length && (this._buffer.length >= read.length || read.allowLess)) {
29799
+ let read3 = this._reads[0];
29800
+ if (this._buffer.length && (this._buffer.length >= read3.length || read3.allowLess)) {
29743
29801
  this._reads.shift();
29744
29802
  let buf = this._buffer;
29745
- this._buffer = buf.slice(read.length);
29746
- read.func.call(this, buf.slice(0, read.length));
29803
+ this._buffer = buf.slice(read3.length);
29804
+ read3.func.call(this, buf.slice(0, read3.length));
29747
29805
  } else {
29748
29806
  break;
29749
29807
  }
@@ -31404,7 +31462,7 @@ function onEnter(input, onLine) {
31404
31462
  // src/cli.ts
31405
31463
  init_dist();
31406
31464
  var import_qrcode = __toESM(require_lib(), 1);
31407
- import { randomUUID as randomUUID7 } from "crypto";
31465
+ import { randomUUID as randomUUID6 } from "crypto";
31408
31466
  import { hostname } from "os";
31409
31467
  import { existsSync as existsSync5, mkdirSync as mkdirSync4, readFileSync as readFileSync7, writeFileSync as writeFileSync5 } from "fs";
31410
31468
  import { execFile as execFile2, execSync } from "child_process";
@@ -31413,7 +31471,7 @@ import { join as join11 } from "path";
31413
31471
 
31414
31472
  // src/run.ts
31415
31473
  init_dist();
31416
- import { randomUUID as randomUUID6 } from "crypto";
31474
+ import { randomUUID as randomUUID5 } from "crypto";
31417
31475
 
31418
31476
  // src/harness/session.ts
31419
31477
  init_dist();
@@ -33266,9 +33324,17 @@ var StartContactSchema2 = external_exports.object({
33266
33324
  waiting: external_exports.enum(["none", "hard"]).default("none").describe("hard requests a call even when channel is notification; user permissions and ring cooldowns still apply."),
33267
33325
  channel: external_exports.enum(["notification", "call"]).default("notification")
33268
33326
  }).strict();
33269
- var ContactSchema2 = external_exports.union([StartContactSchema2, external_exports.object({ deliveryId: external_exports.string().uuid() }).strict()]);
33327
+ var ReceiveContactSchema2 = external_exports.object({
33328
+ wait: external_exports.boolean().optional().describe(
33329
+ "Only controls when this returns. true (the default when you send and acknowledge nothing): wait up to about 45 seconds for incoming communication addressed to you, and return as soon as some is available. false: return what is waiting now. It does not mean work is blocked, set urgency, or ask for a call. `waitOutcome` says which happened: `available`, `expired` (nothing arrived in the window; wait again without sending again), or `not_waited` (a hosted connection never holds a wait)."
33330
+ ),
33331
+ ackEventIds: external_exports.array(external_exports.string().uuid()).min(1).max(100).optional().describe(
33332
+ "The exact eventIds of the events you have handled: an acknowledgment (ACK). Reading alone acknowledges nothing, so an event comes back until you acknowledge it; after that the next batch can come. Each recipient acknowledges separately, for itself only. A Question you owe is answered (an ask with `answers`), never acknowledged away: that id is refused until it is answered."
33333
+ )
33334
+ }).strict();
33335
+ var ContactSchema2 = external_exports.union([StartContactSchema2, external_exports.object({ deliveryId: external_exports.string().uuid() }).strict(), ReceiveContactSchema2]);
33270
33336
  var CONTACT_SCHEMA2 = { type: "object", ...mcpInputSchema2(ContactSchema2) };
33271
- var CONTACT_DESCRIPTION2 = "Contact the user with one or more asks/questions. Pass an array of asks (each with 'ask', optional 'options', 'select', 'id', 'parentId', 'repo'), plus channel:'notification'|'call', and waiting:'none'|'hard'. An ask that names a Goal (parentId) goes onto that Goal; one that names none starts a new Goal of yours. Notification returns immediately; collect durable answers with check_replies. On stdio, a Call holds one cancellable ~45s window; continue with ONLY {deliveryId}. One question per 'ask'; several questions are several objects in 'asks'. Each ask is sent exactly as written, with no reading in between: a bundled ask arrives as one card, so separate questions are separate asks. An ask with no options that is not blocking is a report, and a report is an UPDATE, never a claim on them: it reaches them and is listed apart from what waits on them, so no answer is owed and none should be awaited. On a Goal whose report card is still open it is added to that card, with no new push; Where your work stands while under way is progress: report it with update_goal, not contact. Send options (or waiting:'hard') when you actually need an answer. Each option's label must stand on its own \u2014 the person may see only the labels \u2014 so never a label that points into your text ('All three', 'Option 2', '1 and 3 only'). select:'many' makes the card a checklist, for independent options they may want several of; select:'one' (the default) a pick, for alternatives. The person can always answer in their own words, so never add an 'Other' option. If the person is already on a call, your contact joins that call automatically \u2014 whatever channel you asked for, with no ring \u2014 and the Delivery it returns IS that call: reread it with contact({deliveryId}) to see everything answered on it so far, and contact again while it is live to add information or a further question to the same call.";
33337
+ var CONTACT_DESCRIPTION2 = "Contact the user with one or more asks/questions. Pass an array of asks (each with 'ask', optional 'options', 'select', 'id', 'parentId', 'repo'), plus channel:'notification'|'call', and waiting:'none'|'hard'. An ask that names a Goal (parentId) goes onto that Goal; one that names none starts a new Goal of yours. Notification returns immediately; collect answers by receiving (below). On stdio, a Call holds one cancellable ~45s window; continue with ONLY {deliveryId}. One question per 'ask'; several questions are several objects in 'asks'. Each ask is sent exactly as written, with no reading in between: a bundled ask arrives as one card, so separate questions are separate asks. An ask with no options that is not blocking is a report, never a claim on them, so no answer is owed and none should be awaited. A report reaches the person only when it answers something they asked you, or once the Goal is done; any other report is recorded as the Goal's progress and nobody is notified. So when the work is finished, mark the Goal done first, then send one message saying what is done and anything they need to do or check. On a Goal whose report card is still open, a report that does reach them is added to that card, with no new push. Send options (or waiting:'hard') when you actually need an answer. Each option's label must stand on its own \u2014 the person may see only the labels \u2014 so never a label that points into your text ('All three', 'Option 2', '1 and 3 only'). select:'many' makes the card a checklist, for independent options they may want several of; select:'one' (the default) a pick, for alternatives. The person can always answer in their own words, so never add an 'Other' option. If the person is already on a call, a contact that reaches them joins that call automatically \u2014 whatever channel you asked for, with no ring \u2014 and the Delivery it returns IS that call: reread it with contact({deliveryId}) to see everything answered on it so far, and contact again while it is live to add information or a further question to the same call.\n\nRECEIVING: contact with no asks sends nothing and returns `events`, a limited batch of what is addressed to you (not a history page): `question`, a Question you owe (answer it with an ask whose `answers` is its questionId); `update`, something new on one of your Goals (a reply, an answer: read it with get_goal); `instruction`, a request or note sent to you. `hasMore` says more are waiting. Reading acknowledges nothing: once you have handled events, confirm their eventIds with contact({ackEventIds}), and the next batch can come. contact({}) waits up to about 45 seconds for something to arrive; contact({wait:false}) returns at once. It also lists work given to you that nobody has started (`assigned`; claim_goal starts it) and your work gone quiet (`stalled`).";
33272
33338
  var CreateGoalSchema2 = external_exports.object({
33273
33339
  outcome: external_exports.string().trim().min(1).max(1e4),
33274
33340
  /** The work's NAME (#2115) — one to five words, how a person refers to it out loud ("the night
@@ -33288,10 +33354,6 @@ var CreateGoalSchema2 = external_exports.object({
33288
33354
  * repo name. Delegated work inherits this from its parent Goal when omitted. */
33289
33355
  repo: external_exports.string().trim().min(1).max(200).optional()
33290
33356
  });
33291
- var CreateGoalToolSchema2 = CreateGoalSchema2.extend({
33292
- idempotencyKey: CreateGoalSchema2.shape.idempotencyKey.optional().describe("Optional. One is minted per call; pass your own only so a retry lands on the same Goal.")
33293
- }).strict();
33294
- var CREATE_GOAL_DESCRIPTION2 = 'Create a durable Goal for an outcome. Without parentGoalId it is placed against your open Goals: if one already IS this work, that Goal comes back (existing: true) and nothing new is created \u2014 continue it; if the work belongs under one, it is created there (parentGoalId in the receipt); otherwise it is a root. Pass parentGoalId yourself to put it under a specific Goal. Pass repo to anchor the work to a specific repository ("owner/repo" or repo name); delegated children inherit it. Pass title to name it in one to five words, as a person would refer to it out loud ("the night rings") \u2014 it heads every list and is spoken on a call; without one the brain writes it. Admission only: claim it before doing work, then update it as it advances. Returns an admission receipt with goalId, current state, revision, ownerParticipant, and the next step; no Goal content or execution lease.';
33295
33357
  var UpdateGoalSchema2 = external_exports.object({
33296
33358
  revision: external_exports.number().int().positive(),
33297
33359
  changes: external_exports.object({
@@ -33315,7 +33377,65 @@ var UpdateGoalSchema2 = external_exports.object({
33315
33377
  reason: external_exports.string().trim().min(1).max(2e3),
33316
33378
  operationId: external_exports.string().uuid().optional()
33317
33379
  }).strict();
33318
- var UpdateGoalToolSchema2 = UpdateGoalSchema2.omit({ operationId: true }).extend({ goalId: external_exports.string().uuid() }).strict();
33380
+ var UpdateGoalToolSchema2 = external_exports.object({
33381
+ goalId: external_exports.string().uuid(),
33382
+ revision: UpdateGoalSchema2.shape.revision,
33383
+ changes: UpdateGoalSchema2.shape.changes.innerType().pick({ progress: true, reviewed: true, dueAt: true, withdraw: true }).strict().refine((v) => Object.keys(v).length > 0),
33384
+ reason: UpdateGoalSchema2.shape.reason
33385
+ }).strict();
33386
+ var changedGoal2 = external_exports.string().uuid().describe("The Goal to change, as a read shows it.");
33387
+ var goalTitle2 = external_exports.string().trim().min(1).max(80).describe("The Goal's short display name: one to five words, how a person refers to it out loud.");
33388
+ var goalOutcome2 = external_exports.string().trim().min(1).max(1e4).describe("The full desired result. There is no third description field.");
33389
+ var CreateChange2 = external_exports.object({
33390
+ kind: external_exports.literal("create"),
33391
+ title: goalTitle2,
33392
+ outcome: goalOutcome2,
33393
+ ownerId: external_exports.string().trim().min(1).optional().describe("Who owns the work: an agent's participant (as who_is_working shows it) or the person's. Omitted: you."),
33394
+ parentGoalId: external_exports.string().uuid().optional().describe("The Goal it belongs under. Omitted: a root."),
33395
+ sourceEntryIds: external_exports.array(external_exports.string().uuid()).max(20).optional().describe("The whole Entries the work came from, ones you can read.")
33396
+ }).strict();
33397
+ var EditChange2 = external_exports.object({ kind: external_exports.literal("edit"), goalId: changedGoal2, title: goalTitle2.optional(), outcome: goalOutcome2.optional() }).strict();
33398
+ var StateChange2 = external_exports.object({ kind: external_exports.literal("state"), goalId: changedGoal2, state: external_exports.enum(["open", "completed", "canceled"]).describe(
33399
+ "completed: the Goal's own work is done now (refused while required children are open); open: reopen it; canceled: it will not be done."
33400
+ ) }).strict();
33401
+ var AssignChange2 = external_exports.object({ kind: external_exports.literal("assign"), goalId: changedGoal2, ownerId: external_exports.string().trim().min(1).describe("The new owner's participant.") }).strict();
33402
+ var DeferChange2 = external_exports.object({ kind: external_exports.literal("defer"), goalId: changedGoal2, until: external_exports.string().datetime({ offset: true }).nullable().describe(
33403
+ "Postpone it until this instant (its owner is woken then), or null to take the postponement back."
33404
+ ) }).strict();
33405
+ var MoveChange2 = external_exports.object({ kind: external_exports.literal("move"), goalId: changedGoal2, parentGoalId: external_exports.string().uuid().nullable().describe(
33406
+ "Its new parent, or null for a root. Only this Goal moves; its new parent's other children stay."
33407
+ ) }).strict();
33408
+ var DependencyChange2 = external_exports.object({
33409
+ kind: external_exports.literal("dependency"),
33410
+ change: external_exports.enum(["add", "remove"]),
33411
+ goalId: changedGoal2,
33412
+ dependsOnGoalId: external_exports.string().uuid().describe("The Goal it waits on."),
33413
+ action: external_exports.enum(["start", "complete"]).describe("What waits: starting goalId, or completing it."),
33414
+ reason: external_exports.string().trim().min(1).max(2e3).optional().describe("Why, as an explanation, never as policy.")
33415
+ }).strict();
33416
+ var read2 = { revision: external_exports.number().int().positive().optional() };
33417
+ var GoalChangeSchema2 = external_exports.discriminatedUnion("kind", [
33418
+ CreateChange2,
33419
+ EditChange2.extend(read2),
33420
+ StateChange2.extend(read2),
33421
+ AssignChange2.extend(read2),
33422
+ DeferChange2.extend(read2),
33423
+ MoveChange2.extend(read2),
33424
+ DependencyChange2
33425
+ ]);
33426
+ var editNames2 = (changes, ctx) => changes.forEach((c, i) => {
33427
+ if (c.kind === "edit" && c.title === void 0 && c.outcome === void 0) {
33428
+ ctx.addIssue({ code: external_exports.ZodIssueCode.custom, path: ["changes", i], message: "an edit supplies title, outcome, or both" });
33429
+ }
33430
+ });
33431
+ var ManageGoalsSchema2 = external_exports.object({
33432
+ requestId: external_exports.string().uuid().optional(),
33433
+ changes: external_exports.array(GoalChangeSchema2).min(1).max(50)
33434
+ }).strict().superRefine((v, ctx) => editNames2(v.changes, ctx));
33435
+ var ManageGoalsToolSchema2 = external_exports.object({
33436
+ changes: external_exports.array(external_exports.discriminatedUnion("kind", [CreateChange2, EditChange2, StateChange2, AssignChange2, DeferChange2, MoveChange2, DependencyChange2])).min(1).max(50).describe("The changes, applied in order, each on its own.")
33437
+ }).strict().superRefine((v, ctx) => editNames2(v.changes, ctx));
33438
+ var MANAGE_GOALS_DESCRIPTION2 = "Create, edit, assign, organize or close work. Every change here changes Goals; answering, withdrawing or asking Questions stays in contact. Each change applies independently: a refused one names why (`results[i].error`, e.g. goal_revision_conflict, goal_children_open, goal_not_joined, goal_not_found) and the rest still apply, so read every result: a partial result is never a complete success. Kinds: create (title, outcome, ownerId, parentGoalId, sourceEntryIds) returns the new Goal's id in `results[i].goalId`, in the order requested, to use in later calls; edit (title and/or outcome); state (open, completed, canceled); assign (ownerId); defer (until, or null); move (parentGoalId, or null for a root: only this Goal moves); dependency (add or remove: goalId waits on dependsOnGoalId to start or to complete). A Goal cannot be completed while its required children or dependencies remain open: finish or move them first. Finishing the children does not prove the parent's own work is done. An edit applies at the version you last read: if someone changed the Goal since, it is refused as goal_revision_conflict, so read it again (get_goal) and reconsider. You may change a Goal you own or have written on. Returns `ok` (every change applied), `results` per change (applied or failed), and `goals`, each changed Goal's id, state, title, outcome and revision.";
33319
33439
  var ClaimGoalSchema2 = external_exports.object({ goalId: external_exports.string().uuid().optional() }).strict();
33320
33440
  var GetGoalSchema2 = external_exports.object({
33321
33441
  goalId: external_exports.string().uuid(),
@@ -33328,18 +33448,24 @@ var GetGoalSchema2 = external_exports.object({
33328
33448
  diagnose: external_exports.boolean().optional()
33329
33449
  }).strict();
33330
33450
  var GET_GOAL_DESCRIPTION2 = "Read one Goal without claiming it, including others (the ten most recent other contributors, with names, latest entry headlines and times): its outcome, state, revision, progress, blockers, the conversation on it (each question with its options and what was decided), `next`, the one step to take, and `more`, where to read further. A question in that conversation reads `open` (nothing yet), `answered` (a choice was made, and `answer` carries it), `replied` (they said something and the read settled the question on their words \u2014 NO option of yours was chosen, and the words are the reply line beside it, so read that before you act), or `closed`. The conversation carries everything the person said, every open question and your newest entry; your older entries are left out and counted \u2014 history: true reads every entry in full. Every Goal of your person is readable, whichever of their agents owns it; another account's Goals are not disclosed.\n\ndiagnose: true is for when a read has CONFUSED you \u2014 not for the working loop. It adds `diagnosis`, which asks every reader that already answers a question about your work and NAMES the reader behind every value, so you never guess which of two places to look: what state your work is really in (the stored `goals.state` beside the derived `goal_execution_state`, which can differ); whether anything is armed to ring and when (`ladder_candidates`, with the ladder's own last decision); whether a wake fired for you and what it did (durable `wake.*` events, beside when your process was last heard from); and what has reached you (`list_waiting` \u2014 review flags, unstarted work, open questions, the person's newest words). Read `diagnosis.disagreements` FIRST: each one is two readers giving different values for the same fact, with both values and both sources, and it never chooses between them \u2014 that is yours to do, from the Goal's own history. `diagnosis.looked` names every reader asked, including any that could not answer, so an empty answer is never confused with a broken one.";
33331
- var UPDATE_GOAL_DESCRIPTION2 = `Update a Goal you are on at an exact revision. You are on a Goal you own, or one you have written on (an update with progress, or a contact on it); any of your person's agents may write on any of their Goals, and one that never touched a Goal is refused (409 goal_not_joined). State, ownership, dependencies, children, progress, title, and review acknowledgement are explicit; stale revisions are rejected. A CONTACT ON THIS GOAL MOVES ITS REVISION: a question filed on a Goal is a change to it, so an update prepared before a contact and sent after it is refused as stale (409 goal_revision_conflict) \u2014 re-read the Goal, then write. title is the work's name in one to five words, as a person would refer to it out loud (it is spoken on a call and heads every list); null clears it. reviewed: true acknowledges new evidence and closes the Deliveries addressed to you on that Goal, never over an open decision. dueAt (an ISO instant, or null) makes the Goal wait until then; when it passes you are woken for it \u2014 use it for a promise to follow up later. withdraw: [questionId] takes back a question YOU asked on this Goal that is still open \u2014 because you acted on it yourself, it no longer matters, or you asked it wrongly (e.g. waiting: hard when nothing was blocked): it is cancelled, not answered, its card closes and it stops ringing; the id is the one the conversation shows. state: done means the work was accomplished, and it can be reopened: when the person says it is not done ("it's not working"), set state: active on that same Goal instead of starting a new one; its parent reopens with it. state: done while children are still open records your part as done: the Goal waits and closes by itself when its last open child closes. cancelled is final. Returns the Goal as get_goal reads it, at its new revision.`;
33332
- var CLAIM_GOAL_DESCRIPTION2 = "Claim a pending answer to your question or the oldest runnable or review-pending Goal you own. Pass goalId to join any Goal of your person; its assignment stays unchanged. Read others before overlapping another agent\u2019s work. Joining lets you contribute and change its state; use update_goal with ownerParticipant when the assignment itself should change. Returns the Goal as get_goal reads it, and marks you as on it, which never shuts another agent out: other agents of your person may write on it and change it too, and two changes at once are told apart by revision (409 goal_revision_conflict).";
33333
- var CHECK_REPLIES_DESCRIPTION2 = "What is waiting for you: your open Deliveries (a request the user started toward you, a handoff), one row each with its Goals, how many decisions are still open, and the newest words in brief; `assigned`, your Goals nobody has started yet, however they became yours (claim_goal({goalId}) starts one); and `review`, your Goals with something new on them \u2014 the user's answers and notes are Entries on the Goal, not Deliveries. A pure read with no arguments: nothing is consumed, acknowledged or claimed by reading it, so call it on startup, after a long wait, or whenever you want to know what is outstanding. To act on one, claim its Goal (claim_goal) or reread a Delivery in full with contact({deliveryId}). Once you have acted on what arrived, update_goal with reviewed: true clears the Goal from `review` and closes the Deliveries addressed to you on it.";
33334
- var CheckRepliesSchema2 = external_exports.object({}).strict();
33451
+ var UPDATE_GOAL_DESCRIPTION2 = "Report work on a Goal you are on, at an exact revision: progress, review acknowledgement, when to wake for it, and withdrawing a question of yours. What the Goal is (its title, outcome, state, owner, parent, dependencies) changes with manage_goals. You are on a Goal you own, or one you have written on (an update with progress, or a contact on it); any of your person's agents may write on any of their Goals, and one that never touched a Goal is refused (409 goal_not_joined). Stale revisions are rejected. A CONTACT ON THIS GOAL MOVES ITS REVISION: a question filed on a Goal is a change to it, so an update prepared before a contact and sent after it is refused as stale (409 goal_revision_conflict) \u2014 re-read the Goal, then write. progress says where the work stands. reviewed: true acknowledges new evidence and closes the Deliveries addressed to you on that Goal, never over an open decision (contact({ackEventIds}) does the same for an `update` event). dueAt (an ISO instant, or null) makes the Goal wait until then; when it passes you are woken for it \u2014 use it for a promise to follow up later. withdraw: [questionId] takes back a question YOU asked on this Goal that is still open \u2014 because you acted on it yourself, it no longer matters, or you asked it wrongly (e.g. waiting: hard when nothing was blocked): it is cancelled, not answered, its card closes and it stops ringing; the id is the one the conversation shows. Returns the Goal as get_goal reads it, at its new revision.";
33452
+ var CLAIM_GOAL_DESCRIPTION2 = "Claim a pending answer to your question or the oldest runnable or review-pending Goal you own. Pass goalId to join any Goal of your person; its assignment stays unchanged. Read others before overlapping another agent\u2019s work. Joining lets you contribute and change it; use manage_goals (assign) when the assignment itself should change. Returns the Goal as get_goal reads it, and marks you as on it, which never shuts another agent out: other agents of your person may write on it and change it too, and two changes at once are told apart by revision (409 goal_revision_conflict).";
33453
+ var SearchToolSchema2 = external_exports.object({
33454
+ query: external_exports.string().trim().min(1).max(500),
33455
+ types: external_exports.array(external_exports.enum(["entry", "goal", "answer"])).min(1).optional(),
33456
+ goalId: external_exports.string().uuid().optional(),
33457
+ limit: external_exports.number().int().min(1).max(20).optional()
33458
+ }).strict();
33459
+ var SEARCH_DESCRIPTION2 = "Search your person's history across all of their agents: Entries (what anyone said or wrote, typed or spoken on a call), Goals (by title and outcome) and Answers (found by their Question or by the words that gave them). query is words to look for; records sharing more of its words rank first, and exact names work. types narrows it to entry, goal and/or answer (default: all three). goalId searches under one Goal: its Entries, its Questions' Answers, and it and its immediate children. limit is matches per type, 1 to 20 (default 8). Read-only. Each match carries its whole saved words, its ID and its links (an Answer carries its Question, the choice made and the Entries that support it); `omitted` counts what matched but was left out, so narrow the words or add a goalId to see it. Nothing found is not proof that nothing exists; a refused search says why. Sealed (encrypted) content is never searched or returned.";
33460
+ var WhoIsWorkingSchema2 = external_exports.object({}).strict();
33335
33461
  var AGENT_TOOLS2 = [
33336
- { name: "who_is_working", description: "Read your person's agents that contributed in the last 24 hours, newest first: at most 30 agents and their five most recently touched Goals, with their latest entry headline and time. Use get_goal to read a Goal and its other contributors before starting overlapping work. Read-only; no arguments.", inputSchema: mcpInputSchema2(CheckRepliesSchema2) },
33462
+ { name: "who_is_working", description: "Read your person's agents that contributed in the last 24 hours, newest first: at most 30 agents and their five most recently touched Goals, with their latest entry headline and time. Use get_goal to read a Goal and its other contributors before starting overlapping work. Read-only; no arguments.", inputSchema: mcpInputSchema2(WhoIsWorkingSchema2) },
33337
33463
  { name: "contact", description: CONTACT_DESCRIPTION2, inputSchema: CONTACT_SCHEMA2 },
33338
- { name: "check_replies", description: CHECK_REPLIES_DESCRIPTION2, inputSchema: mcpInputSchema2(CheckRepliesSchema2) },
33339
- { name: "create_goal", description: CREATE_GOAL_DESCRIPTION2, inputSchema: mcpInputSchema2(CreateGoalToolSchema2) },
33464
+ { name: "manage_goals", description: MANAGE_GOALS_DESCRIPTION2, inputSchema: mcpInputSchema2(ManageGoalsToolSchema2) },
33340
33465
  { name: "claim_goal", description: CLAIM_GOAL_DESCRIPTION2, inputSchema: mcpInputSchema2(ClaimGoalSchema2) },
33341
33466
  { name: "get_goal", description: GET_GOAL_DESCRIPTION2, inputSchema: mcpInputSchema2(GetGoalSchema2) },
33342
- { name: "update_goal", description: UPDATE_GOAL_DESCRIPTION2, inputSchema: mcpInputSchema2(UpdateGoalToolSchema2) }
33467
+ { name: "update_goal", description: UPDATE_GOAL_DESCRIPTION2, inputSchema: mcpInputSchema2(UpdateGoalToolSchema2) },
33468
+ { name: "search", description: SEARCH_DESCRIPTION2, inputSchema: mcpInputSchema2(SearchToolSchema2) }
33343
33469
  ];
33344
33470
  var AGENT_TOOL_NAMES2 = AGENT_TOOLS2.map((t) => t.name);
33345
33471
  var id2 = external_exports.string().uuid();
@@ -33370,17 +33496,6 @@ var existingGoalChanges2 = [
33370
33496
  reason: external_exports.string().max(500).optional()
33371
33497
  }).strict()
33372
33498
  ];
33373
- var GoalChangeSchema2 = external_exports.union([
33374
- external_exports.object({
33375
- kind: external_exports.literal("create"),
33376
- title: external_exports.string().min(1).max(120),
33377
- outcome: external_exports.string().min(1),
33378
- ownerId: participant2,
33379
- parentGoalId: id2.optional(),
33380
- sourceEntryIds: external_exports.array(id2)
33381
- }).strict(),
33382
- ...existingGoalChanges2
33383
- ]);
33384
33499
  var BrainGoalChangeSchema2 = external_exports.union([
33385
33500
  // newSession: Paigy starts a session to own it (owner, 2026-10-06); until it has, the person owns it.
33386
33501
  external_exports.object({
@@ -33781,7 +33896,7 @@ var AwaitItemSchema2 = external_exports.discriminatedUnion("type", [
33781
33896
  /** The awaited ask was REPLACED by a newer notification on its thread (e.g. a
33782
33897
  * post-feedback revision, #633) — the user will never answer this id. Stop
33783
33898
  * awaiting it; the live ask is the thread's newest turn (await that one, or
33784
- * re-orient via check_replies). */
33899
+ * re-orient via contact({})). */
33785
33900
  external_exports.object({
33786
33901
  type: external_exports.literal("superseded"),
33787
33902
  parentId: external_exports.string(),
@@ -34509,7 +34624,7 @@ var HostDecisionSchema2 = external_exports.object({
34509
34624
  goalId: external_exports.string().uuid().nullable().optional(),
34510
34625
  /** When the server last heard from the agent, as the host read it: the presence it stood back for. */
34511
34626
  seenAt: external_exports.string().datetime().nullable().optional(),
34512
- /** When that work last moved (`claimable.since` on `check_replies`), the fact the bound is judged on. */
34627
+ /** When that work last moved (`claimable.since` on an agent's `contact({})` read), the fact the bound is judged on. */
34513
34628
  since: external_exports.string().datetime().nullable().optional(),
34514
34629
  /** What the host said, in its log's own words: why it stood back, or what the take-over did. */
34515
34630
  said: external_exports.string().max(300).optional()
@@ -34867,8 +34982,13 @@ function railFor(opts) {
34867
34982
  update: (goalId, input) => updateGoal(goalId, input, opts),
34868
34983
  // One read and back: the pump owns the waiting, so a Call must not hold a window here.
34869
34984
  contact: (input) => contact(input, { ...opts, waits: false }),
34870
- create: (input) => createGoal(input, opts),
34871
- waiting: () => checkReplies(opts)
34985
+ create: async (input) => {
34986
+ const made = await manageGoals({ changes: [{ kind: "create", ...input }] }, opts);
34987
+ const goal = made.goals.find((g) => g.goalId === made.results[0]?.goalId);
34988
+ if (!goal) throw new Error(`manage_goals create failed: ${made.results[0]?.error ?? "no goal"}`);
34989
+ return { goalId: goal.goalId, revision: goal.revision };
34990
+ },
34991
+ waiting: () => receive(opts)
34872
34992
  };
34873
34993
  }
34874
34994
  function cancelAsks(state) {
@@ -34997,7 +35117,6 @@ ${event.result?.trim() || "No result reported."}`, state, rail, opts);
34997
35117
  }
34998
35118
 
34999
35119
  // src/paigy/conversation.ts
35000
- import { randomUUID as randomUUID5 } from "crypto";
35001
35120
  var HARNESS_INSTRUCTION = "You are running as an unattended background harness agent; your user reaches you through Paigy and is not at this terminal. Nothing wakes you after your turn ends but the person, so wait on CI or a deploy inside the turn. The person never sees your turn's final message: it is kept as progress on this Goal. Anything the person needs \u2014 a question, a result, a blocker \u2014 you send through Paigy's contact tool, once; the harness sends nothing on your behalf. What the person says later arrives with the Goal it was said on named in front of it; answer them on that Goal (its id as the contact's parentId).";
35002
35121
  var SAFETY_MS = 6e4;
35003
35122
  var ASK_BEAT_MS = 5e3;
@@ -35115,23 +35234,23 @@ async function gather(state, rail, held) {
35115
35234
  const moved = movedBelow(held, state);
35116
35235
  for (const { goal, since } of moved) look2(goal.goalId, "subtree", goal.title, since);
35117
35236
  const heard = [];
35118
- const read = /* @__PURE__ */ new Set();
35237
+ const read3 = /* @__PURE__ */ new Set();
35119
35238
  for (const [goalId, { since, ...found }] of looks) {
35120
35239
  let brief = found.brief;
35121
35240
  if (!brief) {
35122
35241
  try {
35123
35242
  brief = await rail.read(goalId);
35124
35243
  } catch (error) {
35125
- if (error.status === 404) read.add(goalId);
35244
+ if (error.status === 404) read3.add(goalId);
35126
35245
  continue;
35127
35246
  }
35128
35247
  }
35129
- read.add(goalId);
35248
+ read3.add(goalId);
35130
35249
  const fresh = !brief.reviewSince && (found.via === "waiting work" || found.via === "assigned") ? sinceTheWork(brief) : { after: -1 };
35131
35250
  if (found.via === "assigned") announced.add(goalId);
35132
35251
  heard.push({ goalId, ...found, brief, words: unheard(brief, state, brief.reviewSince ? null : since ?? null, fresh.after, brief.reviewSince), ...fresh.note ? { note: fresh.note } : {} });
35133
35252
  }
35134
- for (const { goal, since } of moved) if (read.has(goal.goalId)) state.below.goals.set(goal.goalId, { since, at: goal.updatedAt ?? null });
35253
+ for (const { goal, since } of moved) if (read3.has(goal.goalId)) state.below.goals.set(goal.goalId, { since, at: goal.updatedAt ?? null });
35135
35254
  return { heard, listed };
35136
35255
  }
35137
35256
  var GIVEN = "This Goal was given to you, and nobody has started it. Carry on with what you're doing unless it changes that; claim_goal with its id when you take it up.";
@@ -35249,7 +35368,7 @@ async function look(session, state, rail, opts) {
35249
35368
  if (opts?.initialPrompt?.trim()) {
35250
35369
  const prompt = opts.initialPrompt.trim();
35251
35370
  opts.initialPrompt = void 0;
35252
- const admitted = await rail.create({ outcome: prompt, idempotencyKey: randomUUID5() });
35371
+ const admitted = await rail.create({ title: prompt.split(/\s+/).slice(0, 5).join(" ").slice(0, 80), outcome: prompt });
35253
35372
  brief2 = await rail.claim();
35254
35373
  if (!brief2.goalId || brief2.revision === void 0) {
35255
35374
  state.goal = { id: admitted.goalId, revision: admitted.revision };
@@ -35340,9 +35459,9 @@ async function pump(session, state, rail, opts) {
35340
35459
  }
35341
35460
  if (!await opts.onIdle()) return;
35342
35461
  if (now() - since >= BEAT_REPORT_MS) {
35343
- const read = counts.wake + counts.rest + counts.safety;
35344
- if (read || counts.skipped || tally.noted || tally.seen || tally.announced) {
35345
- opts.log?.(`\u25B9 beats: ${read} read (${counts.wake} wake, ${counts.rest} rest, ${counts.safety} safety), ${counts.skipped} wake mid-turn skipped, ${tally.noted} noted mid-turn, ${tally.seen} seen by the hook, ${tally.announced} assigned announced${tally.paused ? `, ${tally.paused} held by the usage limit` : ""}`);
35462
+ const read3 = counts.wake + counts.rest + counts.safety;
35463
+ if (read3 || counts.skipped || tally.noted || tally.seen || tally.announced) {
35464
+ opts.log?.(`\u25B9 beats: ${read3} read (${counts.wake} wake, ${counts.rest} rest, ${counts.safety} safety), ${counts.skipped} wake mid-turn skipped, ${tally.noted} noted mid-turn, ${tally.seen} seen by the hook, ${tally.announced} assigned announced${tally.paused ? `, ${tally.paused} held by the usage limit` : ""}`);
35346
35465
  }
35347
35466
  counts.wake = counts.rest = counts.safety = counts.skipped = tally.noted = tally.seen = tally.announced = tally.paused = 0;
35348
35467
  since = now();
@@ -35360,7 +35479,7 @@ function runHarness(opts) {
35360
35479
  const clock4 = beat();
35361
35480
  let session = null;
35362
35481
  const speaksAs = opts.session ?? opts.resume ?? sessionId();
35363
- const instance = randomUUID6();
35482
+ const instance = randomUUID5();
35364
35483
  const rail = railFor({ token: opts.token, reach: reachAs(speaksAs, instance) });
35365
35484
  let inbox;
35366
35485
  if (opts.harness === "claude") {
@@ -35599,7 +35718,7 @@ function proven(pid, procStart, deps) {
35599
35718
  function localHolderPids(deps = {}) {
35600
35719
  const dir = deps.dir ?? join7(process.env.CLAUDE_CONFIG_DIR?.trim() || join7(homedir7(), ".claude"), "sessions");
35601
35720
  const list = deps.list ?? ((d) => readdirSync3(d));
35602
- const read = deps.read ?? ((f) => readFileSync5(f, "utf8"));
35721
+ const read3 = deps.read ?? ((f) => readFileSync5(f, "utf8"));
35603
35722
  const check = { alive: deps.alive ?? isAlive, started: deps.started ?? psStart };
35604
35723
  const held = /* @__PURE__ */ new Map();
35605
35724
  let files;
@@ -35612,7 +35731,7 @@ function localHolderPids(deps = {}) {
35612
35731
  if (!/^\d+\.json$/.test(file)) continue;
35613
35732
  let row;
35614
35733
  try {
35615
- row = JSON.parse(read(join7(dir, file)));
35734
+ row = JSON.parse(read3(join7(dir, file)));
35616
35735
  } catch {
35617
35736
  continue;
35618
35737
  }
@@ -35644,7 +35763,7 @@ function descendsFrom(pid, ancestor, parent = psParent) {
35644
35763
  function localHolders(deps = {}) {
35645
35764
  const dir = deps.dir ?? join7(process.env.CLAUDE_CONFIG_DIR?.trim() || join7(homedir7(), ".claude"), "sessions");
35646
35765
  const list = deps.list ?? ((d) => readdirSync3(d));
35647
- const read = deps.read ?? ((f) => readFileSync5(f, "utf8"));
35766
+ const read3 = deps.read ?? ((f) => readFileSync5(f, "utf8"));
35648
35767
  const check = { alive: deps.alive ?? isAlive, started: deps.started ?? psStart };
35649
35768
  const held = /* @__PURE__ */ new Map();
35650
35769
  let files;
@@ -35657,7 +35776,7 @@ function localHolders(deps = {}) {
35657
35776
  if (!/^\d+\.json$/.test(file)) continue;
35658
35777
  let row;
35659
35778
  try {
35660
- row = JSON.parse(read(join7(dir, file)));
35779
+ row = JSON.parse(read3(join7(dir, file)));
35661
35780
  } catch {
35662
35781
  continue;
35663
35782
  }
@@ -35891,7 +36010,7 @@ async function waitingWork(token, session) {
35891
36010
  if (quiet !== void 0 && Date.now() < quiet) return { skip: BOUND_SKIP };
35892
36011
  let found;
35893
36012
  try {
35894
- found = await checkReplies({ token, ...session ? { reach: reachAs(session) } : {} });
36013
+ found = await receive({ token, ...session ? { reach: reachAs(session) } : {} });
35895
36014
  } catch (error) {
35896
36015
  if (error instanceof RevokedError) return { skip: "was revoked: its credential is gone for good", revoked: true };
35897
36016
  if (error instanceof ApiError && error.body?.error === "identity_session_mismatch") {
@@ -36130,7 +36249,7 @@ function startHost(opts) {
36130
36249
  skip(`has a full conversation (${resumes.slice(0, 8)}) \u2014 not resuming it; its Goals go to the dead-agent handoff`);
36131
36250
  return;
36132
36251
  }
36133
- const read = async () => {
36252
+ const read3 = async () => {
36134
36253
  const got = await waitingWork(token, identity.sessionId ?? owner?.sessionId);
36135
36254
  if (!("skip" in got)) return got;
36136
36255
  if (got.revoked) {
@@ -36142,7 +36261,7 @@ function startHost(opts) {
36142
36261
  return null;
36143
36262
  };
36144
36263
  if (decided.why === "presence") {
36145
- found = await read() ?? void 0;
36264
+ found = await read3() ?? void 0;
36146
36265
  if (!found) return;
36147
36266
  const since = found.since;
36148
36267
  decided = wakeAction(false, Date.now(), seenByServer, { ...here, ...since ? { movedAt: Date.parse(since) } : {} });
@@ -36168,7 +36287,7 @@ function startHost(opts) {
36168
36287
  skip("has no granted folder to wake in");
36169
36288
  return;
36170
36289
  }
36171
- found ??= await read() ?? void 0;
36290
+ found ??= await read3() ?? void 0;
36172
36291
  if (!found) return;
36173
36292
  if (runs.has(key3)) {
36174
36293
  skip("was started by the wake that read it first");
@@ -36304,7 +36423,7 @@ function startHost(opts) {
36304
36423
  return {
36305
36424
  name,
36306
36425
  // The slot key rides along so the window's agent page can speak AS this agent —
36307
- // its pending reads (`checkReplies`, the same pure read the sweep does) need the
36426
+ // its pending reads (`receive`, the same pure read the sweep does) need the
36308
36427
  // slot's own token, and the display name is not a key.
36309
36428
  slot,
36310
36429
  tokenId: id3.tokenId,
@@ -36710,7 +36829,7 @@ async function main() {
36710
36829
  let launched;
36711
36830
  if (parsed.launch) {
36712
36831
  overrideToken(readSlot("Desktop") || null);
36713
- const session = randomUUID7();
36832
+ const session = randomUUID6();
36714
36833
  const minted = await hatch(parsed.launch, parsed.voice ?? null, {
36715
36834
  reach: reachAs(session),
36716
36835
  brief: parsed.prompt,