@paigy/harness 0.3.7 → 0.3.9
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/README.md +3 -1
- package/dist/cli.js +142 -346
- package/dist/main.js +221 -454
- package/package.json +13 -12
package/dist/cli.js
CHANGED
|
@@ -14929,7 +14929,7 @@ var require_mock_interceptor = __commonJS({
|
|
|
14929
14929
|
var require_mock_client = __commonJS({
|
|
14930
14930
|
"../../node_modules/.pnpm/undici@6.27.0/node_modules/undici/lib/mock/mock-client.js"(exports, module) {
|
|
14931
14931
|
"use strict";
|
|
14932
|
-
var { promisify } = __require("util");
|
|
14932
|
+
var { promisify: promisify2 } = __require("util");
|
|
14933
14933
|
var Client = require_client();
|
|
14934
14934
|
var { buildMockDispatch } = require_mock_utils();
|
|
14935
14935
|
var {
|
|
@@ -14969,7 +14969,7 @@ var require_mock_client = __commonJS({
|
|
|
14969
14969
|
return new MockInterceptor(opts, this[kDispatches]);
|
|
14970
14970
|
}
|
|
14971
14971
|
async [kClose]() {
|
|
14972
|
-
await
|
|
14972
|
+
await promisify2(this[kOriginalClose])();
|
|
14973
14973
|
this[kConnected] = 0;
|
|
14974
14974
|
this[kMockAgent][Symbols.kClients].delete(this[kOrigin]);
|
|
14975
14975
|
}
|
|
@@ -14982,7 +14982,7 @@ var require_mock_client = __commonJS({
|
|
|
14982
14982
|
var require_mock_pool = __commonJS({
|
|
14983
14983
|
"../../node_modules/.pnpm/undici@6.27.0/node_modules/undici/lib/mock/mock-pool.js"(exports, module) {
|
|
14984
14984
|
"use strict";
|
|
14985
|
-
var { promisify } = __require("util");
|
|
14985
|
+
var { promisify: promisify2 } = __require("util");
|
|
14986
14986
|
var Pool = require_pool();
|
|
14987
14987
|
var { buildMockDispatch } = require_mock_utils();
|
|
14988
14988
|
var {
|
|
@@ -15022,7 +15022,7 @@ var require_mock_pool = __commonJS({
|
|
|
15022
15022
|
return new MockInterceptor(opts, this[kDispatches]);
|
|
15023
15023
|
}
|
|
15024
15024
|
async [kClose]() {
|
|
15025
|
-
await
|
|
15025
|
+
await promisify2(this[kOriginalClose])();
|
|
15026
15026
|
this[kConnected] = 0;
|
|
15027
15027
|
this[kMockAgent][Symbols.kClients].delete(this[kOrigin]);
|
|
15028
15028
|
}
|
|
@@ -24062,7 +24062,7 @@ async function subscribeWake(onNudge, opts = {}) {
|
|
|
24062
24062
|
}
|
|
24063
24063
|
};
|
|
24064
24064
|
}
|
|
24065
|
-
var import_undici, require2, __create2, __defProp2, __getOwnPropDesc2, __getOwnPropNames2, __getProtoOf2, __hasOwnProp2, __require2, __commonJS2, __copyProps2, __toESM2, require_nacl_fast, BACKEND_URL, NETWORK_MSG, PROXY_ENV, agent, INSTANCE_ID, WORKSPACE_ID, envSession, SESSION_ID, 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, 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, GetThreadSchema, GET_THREAD_DESCRIPTION, SearchThreadsSchema, SEARCH_THREADS_DESCRIPTION, AGENT_TOOLS, AGENT_TOOL_NAMES, ContextSchema, ParticipantSchema, TransformSchema, OptionSchema, VisualSchema, NotifyLevelSchema, SelectShapeSchema, ReceiptEventSchema, AttentionSchema, NotifyRequestFields, NotifyRequestSchema, NotifyStatusSchema, AgentStateSchema, TurnSchema, UserAnswerSchema, IntentSchema, RideAlongSchema, AwaitItemSchema,
|
|
24065
|
+
var import_undici, require2, __create2, __defProp2, __getOwnPropDesc2, __getOwnPropNames2, __getProtoOf2, __hasOwnProp2, __require2, __commonJS2, __copyProps2, __toESM2, require_nacl_fast, BACKEND_URL, NETWORK_MSG, PROXY_ENV, agent, INSTANCE_ID, WORKSPACE_ID, envSession, SESSION_ID, 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, 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, GetThreadSchema, GET_THREAD_DESCRIPTION, SearchThreadsSchema, SEARCH_THREADS_DESCRIPTION, AGENT_TOOLS, AGENT_TOOL_NAMES, ContextSchema, ParticipantSchema, TransformSchema, OptionSchema, 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, BrokerTuningSchema, UserSettingsSchema, HistoryItemSchema, ACTIVITY_LINES, ACTIVITY_LINE_MAX, AgentActivitySchema, ConnectionSummarySchema, LedgerItemSchema, AgentLedgerSchema, ReassignResultSchema, MoveRingSchema, MoveSchema, QueueQuestionSchema, QueueItemSchema, NoteSourceSchema, NoteStatusSchema, NoteRepeatSchema, DecisionSchema, NoteSchema, TriageItemSchema, TriageAssignmentSchema, TriageStatusSchema, SubmitTriageSchema, TriageProposalSchema, AcceptTriageSchema, AcceptTriageResultSchema, DeliveryModeSchema, WAKE_EVENT, wakeChannel, RegisterDeliverySchema, OAuthStartSchema, DeliveryConfigSchema, StatusSchema, EnvelopeRecipientSchema, EnvelopeHeaderSchema, EnvelopeSchema, SealedAnswerSchema, DeviceCredentialSchema, DeviceRosterSchema, WakeNudgeSchema, PairingStatusSchema, PairingRevealSchema, DeviceCodeSchema, DeviceInfoSchema, DeviceTokenSchema, SupportRequestSchema, NotificationFeedbackKindSchema, FeedbackResolutionSchema, FeedbackOutcomeSchema, import_tweetnacl, import_tweetnacl2, import_tweetnacl3, import_tweetnacl4, import_tweetnacl5, AGENT_NAME, TOKEN_PATH, KEY_PATH, sleep, UnpairedError, ApiError, AWAIT_WINDOW_MS, tokenOverride, authToken, HEARTBEAT_MS, RETRY_MS, JOIN, lines;
|
|
24066
24066
|
var init_dist = __esm({
|
|
24067
24067
|
"../../packages/sdk/dist/index.js"() {
|
|
24068
24068
|
"use strict";
|
|
@@ -26774,9 +26774,9 @@ var init_dist = __esm({
|
|
|
26774
26774
|
ClaimGoalSchema = external_exports.object({ goalId: external_exports.string().uuid().optional() }).strict();
|
|
26775
26775
|
GetGoalSchema = external_exports.object({ goalId: external_exports.string().uuid() }).strict();
|
|
26776
26776
|
GET_GOAL_DESCRIPTION = "Read the current authorized Goal brief: state, owner, blockers, open decisions, progress, and the next operation. Foreign or sibling-owned Goals are not disclosed.";
|
|
26777
|
-
UPDATE_GOAL_DESCRIPTION = "Update an owned Goal at an exact revision. State, ownership, dependencies, children, progress, and review acknowledgement are explicit; stale revisions are rejected. Returns the new revision and a prose summary.";
|
|
26777
|
+
UPDATE_GOAL_DESCRIPTION = "Update an owned Goal at an exact revision. State, ownership, dependencies, children, progress, and review acknowledgement are explicit; stale revisions are rejected. reviewed: true acknowledges new evidence and closes the Deliveries addressed to you on that Goal, never over an open decision. Returns the new revision and a prose summary.";
|
|
26778
26778
|
CLAIM_GOAL_DESCRIPTION = "Claim the oldest runnable or review-pending Goal you own, or pass goalId to claim that Goal. Returns a Goal-scoped brief, current revision, blockers, and the next valid operation. Claiming creates or renews the execution lease.";
|
|
26779
|
-
CHECK_REPLIES_DESCRIPTION = "Your open Deliveries: every Notification or Call currently addressed to you \u2014 a request the user started toward you, an answer relayed to something you asked, a handoff \u2014 each
|
|
26779
|
+
CHECK_REPLIES_DESCRIPTION = "Your open Deliveries: every Notification or Call currently addressed to you \u2014 a request the user started toward you, an answer relayed to something you asked, a handoff \u2014 one row each: its Goals, the newest words in brief, accepted decisions and open decision needs, without the Entries. 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 it in full with contact({deliveryId}). Once you have acted on what arrived, update_goal with reviewed: true closes the Deliveries addressed to you on that Goal. Your runnable and review-pending Goals come from claim_goal, not from here.";
|
|
26780
26780
|
CheckRepliesSchema = external_exports.object({}).strict();
|
|
26781
26781
|
GetThreadSchema = external_exports.object({
|
|
26782
26782
|
parentId: external_exports.string().describe("The Thread to read \u2014 the threadId a Delivery returned, or the parentId of a search hit.")
|
|
@@ -27155,67 +27155,6 @@ var init_dist = __esm({
|
|
|
27155
27155
|
inFlight: external_exports.boolean().optional()
|
|
27156
27156
|
})
|
|
27157
27157
|
]);
|
|
27158
|
-
CallbackTriggerSchema = external_exports.enum(["on_done", "on_blocked", "scheduled"]);
|
|
27159
|
-
NotifyResponseSchema = external_exports.object({
|
|
27160
|
-
notificationId: external_exports.string(),
|
|
27161
|
-
workId: external_exports.string().uuid().optional(),
|
|
27162
|
-
decisionId: external_exports.string().uuid().optional(),
|
|
27163
|
-
status: NotifyStatusSchema,
|
|
27164
|
-
createdAt: external_exports.string().datetime(),
|
|
27165
|
-
answer: UserAnswerSchema.optional(),
|
|
27166
|
-
answeredAt: external_exports.string().datetime().optional(),
|
|
27167
|
-
/** Ride-alongs for THIS agent — pending work it should pick up when it's done with
|
|
27168
|
-
* what it came for. Present on any reply, because an unwakeable agent's only
|
|
27169
|
-
* reliable moment is one it initiated. Absent/empty = nothing owed. */
|
|
27170
|
-
also: external_exports.array(RideAlongSchema).optional()
|
|
27171
|
-
});
|
|
27172
|
-
NotifyPlanUnitSchema = external_exports.object({
|
|
27173
|
-
notificationId: external_exports.string(),
|
|
27174
|
-
/** The unit's own heading, so the agent can tell which of its paragraphs this became. */
|
|
27175
|
-
title: external_exports.string(),
|
|
27176
|
-
/** How loudly this unit was arbitrated to arrive — per unit, which is the point of units. */
|
|
27177
|
-
level: NotifyLevelSchema,
|
|
27178
|
-
/** Answered from something the user already decided: nobody is interrupted, and a trail card
|
|
27179
|
-
* says so. The agent should not wait on this one. */
|
|
27180
|
-
settled: external_exports.literal(true).optional(),
|
|
27181
|
-
/** What this unit would need to be answerable and does not carry (#894). A PROPOSAL to the
|
|
27182
|
-
* agent — nothing here changed the ask, and ignoring it costs nothing. */
|
|
27183
|
-
needs: external_exports.array(external_exports.enum(["options", "visuals"])).optional(),
|
|
27184
|
-
/** The SHAPE the broker would give this unit, for the agent to ratify (#886/#894). The
|
|
27185
|
-
* split layer reads prose and can see that a paragraph is a yes/no or a pick-one — but a
|
|
27186
|
-
* broker that DECIDES that destroys the only fact separating a statement from a real ask
|
|
27187
|
-
* (#731), so it is offered, never applied: the unit is stored `text` until the agent
|
|
27188
|
-
* confirms the shape (POST /notify/:id/confirm). Ignoring it costs nothing. */
|
|
27189
|
-
proposal: external_exports.object({
|
|
27190
|
-
select: SelectShapeSchema,
|
|
27191
|
-
options: external_exports.array(external_exports.object({ label: external_exports.string().min(1) })).optional()
|
|
27192
|
-
}).optional(),
|
|
27193
|
-
/** What the broker READ this unit as wanting from the human (#952 layer 2): a `decision`
|
|
27194
|
-
* between alternatives, an `approval` the agent is blocked on, or `knowledge` it just
|
|
27195
|
-
* needs to know. Reported so the agent can correct a misread the same way it ratifies a
|
|
27196
|
-
* shape — the read RAISES (a decision always asks) and never silences a question the
|
|
27197
|
-
* agent declared (#731, #923). */
|
|
27198
|
-
wants: external_exports.enum(["decision", "approval", "knowledge"]).optional()
|
|
27199
|
-
});
|
|
27200
|
-
NotifyPlanSchema = external_exports.object({
|
|
27201
|
-
units: external_exports.array(NotifyPlanUnitSchema),
|
|
27202
|
-
/** Which unit is this arrival's ONE interruption (units-design.md D23). Absent means nobody
|
|
27203
|
-
* was interrupted — every unit was either settled or quiet enough to sit in the inbox. */
|
|
27204
|
-
speaks: external_exports.string().optional()
|
|
27205
|
-
});
|
|
27206
|
-
UserResponseSchema = external_exports.object({
|
|
27207
|
-
requestId: external_exports.string(),
|
|
27208
|
-
answer: UserAnswerSchema,
|
|
27209
|
-
answeredAt: external_exports.string().datetime(),
|
|
27210
|
-
transcript: external_exports.string().optional(),
|
|
27211
|
-
/** E2EE: the sealed answer (opaque envelope + plaintext `ignored` hint) when the item was
|
|
27212
|
-
* E2EE-sealed. Present → the server persists it opaquely and branches status on `ignored`;
|
|
27213
|
-
* the plaintext `answer` is a placeholder (`{ kind: "ignored" }`) the server ignores for a
|
|
27214
|
-
* sealed row. Absent = today's plaintext answer, unchanged. */
|
|
27215
|
-
sealed: external_exports.lazy(() => SealedAnswerSchema).optional(),
|
|
27216
|
-
/** Coverage report (#396): which of the ask's declared `points` were addressed. */
|
|
27217
|
-
covered: external_exports.array(external_exports.string()).optional()
|
|
27218
|
-
});
|
|
27219
27158
|
VoiceKeySchema = external_exports.enum(["rachel", "george", "jessica", "brian", "lily"]);
|
|
27220
27159
|
AgendaTurnSchema = external_exports.object({
|
|
27221
27160
|
/** THE TURN'S IDENTITY (the first-sentence stream, 2026-09-09): the brain call that wrote
|
|
@@ -27399,10 +27338,6 @@ var init_dist = __esm({
|
|
|
27399
27338
|
goalState: external_exports.string().optional()
|
|
27400
27339
|
}).optional()
|
|
27401
27340
|
});
|
|
27402
|
-
SnoozeRequestSchema = external_exports.object({
|
|
27403
|
-
requestId: external_exports.string(),
|
|
27404
|
-
until: external_exports.string().datetime()
|
|
27405
|
-
});
|
|
27406
27341
|
APNS_TOKEN_RE = /^[0-9a-fA-F]{64}$/;
|
|
27407
27342
|
PushTokenSchema = external_exports.object({
|
|
27408
27343
|
voipToken: external_exports.string().min(1).optional(),
|
|
@@ -27558,6 +27493,9 @@ var init_dist = __esm({
|
|
|
27558
27493
|
* harness availabilities + granted workspaces — the option set the phone's
|
|
27559
27494
|
* "new session" sheet offers. Absent for ordinary MCP agents. */
|
|
27560
27495
|
runtime: external_exports.object({
|
|
27496
|
+
/** The @paigy/harness this host is running — a machine the self-update has not reached
|
|
27497
|
+
* shows its age here (`apps/desktop/src/update.ts`). */
|
|
27498
|
+
version: external_exports.string().optional(),
|
|
27561
27499
|
harnesses: external_exports.array(external_exports.object({ name: external_exports.string(), label: external_exports.string(), status: external_exports.string() })).optional(),
|
|
27562
27500
|
workspaces: external_exports.array(external_exports.string()).optional()
|
|
27563
27501
|
}).optional(),
|
|
@@ -27620,19 +27558,6 @@ var init_dist = __esm({
|
|
|
27620
27558
|
* distilled from a clarify ruling (those carry no agent) or one whose source rows are gone. */
|
|
27621
27559
|
learnedFrom: external_exports.object({ id: external_exports.string(), name: external_exports.string() }).nullable()
|
|
27622
27560
|
});
|
|
27623
|
-
CreateRequestSchema = external_exports.object({
|
|
27624
|
-
/** The connection (token id) to send to, from GET /api/tokens. */
|
|
27625
|
-
tokenId: external_exports.string(),
|
|
27626
|
-
/** The user's message to the agent. */
|
|
27627
|
-
text: external_exports.string().min(1),
|
|
27628
|
-
/** Land the request on an existing conversation thread (History → "Continue")
|
|
27629
|
-
* instead of minting a fresh one. Must belong to the requesting user. */
|
|
27630
|
-
parentId: external_exports.string().optional(),
|
|
27631
|
-
/** Point the agent at a past conversation (possibly with a different agent) as
|
|
27632
|
-
* starting context (History → "New session from this"). A reference, not a copy —
|
|
27633
|
-
* the agent reads it via get_thread. Must belong to the requesting user. */
|
|
27634
|
-
contextParentId: external_exports.string().optional()
|
|
27635
|
-
});
|
|
27636
27561
|
QueueQuestionSchema = external_exports.object({
|
|
27637
27562
|
/** The decision need's id — what an answer is accepted against. */
|
|
27638
27563
|
id: external_exports.string(),
|
|
@@ -27724,38 +27649,6 @@ var init_dist = __esm({
|
|
|
27724
27649
|
lastRideAt: external_exports.string().nullable().default(null),
|
|
27725
27650
|
createdAt: external_exports.string()
|
|
27726
27651
|
});
|
|
27727
|
-
CreateNoteSchema = external_exports.object({
|
|
27728
|
-
/** The intent, in the user's own words. Stored verbatim; the broker only titles it. */
|
|
27729
|
-
text: external_exports.string().min(1).max(4e3),
|
|
27730
|
-
/** Capture it as a REMINDER — a note assigned to the user themselves, which rides
|
|
27731
|
-
* their next call instead of being handed to an agent. Everything else about the
|
|
27732
|
-
* note is identical; this is the one parameter that separates the two. */
|
|
27733
|
-
forMe: external_exports.boolean().optional(),
|
|
27734
|
-
/** The not-before, when the user already said one. Absent = the very next call. */
|
|
27735
|
-
dueAt: external_exports.string().datetime().optional(),
|
|
27736
|
-
repeat: NoteRepeatSchema.optional()
|
|
27737
|
-
});
|
|
27738
|
-
RecordDecisionSchema = external_exports.object({
|
|
27739
|
-
/** An open decision (from /clarify) to answer. */
|
|
27740
|
-
decisionId: external_exports.string().optional(),
|
|
27741
|
-
/** For an ad-hoc decision: what was ambiguous. Required without `decisionId`. */
|
|
27742
|
-
question: external_exports.string().min(1).max(500).optional(),
|
|
27743
|
-
/** The ruling. */
|
|
27744
|
-
answer: external_exports.string().min(1).max(2e3)
|
|
27745
|
-
}).refine((d) => d.decisionId || d.question, { message: "decisionId or question required" });
|
|
27746
|
-
AssignNoteSchema = external_exports.object({
|
|
27747
|
-
/** An EXISTING agent: token id or nickname. Omit when spawning fresh. */
|
|
27748
|
-
target: external_exports.string().min(1).optional(),
|
|
27749
|
-
/** Spawn a NEW session for this note (companion.md §2.2): the assignee doesn't
|
|
27750
|
-
* exist yet — mint it on a live desktop that advertises the harness+workspace,
|
|
27751
|
-
* named after the note. The brief arrives as its opening request. */
|
|
27752
|
-
spawn: external_exports.object({
|
|
27753
|
-
hostTokenId: external_exports.string().uuid(),
|
|
27754
|
-
harness: external_exports.string().min(1),
|
|
27755
|
-
workspace: external_exports.string().min(1)
|
|
27756
|
-
}).optional()
|
|
27757
|
-
}).refine((a) => !!a.target !== !!a.spawn, { message: "exactly one of target or spawn" });
|
|
27758
|
-
TriageVerdictSchema = external_exports.enum(["keep", "stale", "close", "assign"]);
|
|
27759
27652
|
TriageItemSchema = external_exports.object({
|
|
27760
27653
|
noteId: external_exports.string(),
|
|
27761
27654
|
/** The note's headline at run time. */
|
|
@@ -27891,20 +27784,6 @@ var init_dist = __esm({
|
|
|
27891
27784
|
ed25519: external_exports.string(),
|
|
27892
27785
|
nonce: external_exports.string()
|
|
27893
27786
|
});
|
|
27894
|
-
DeviceCodeRequestSchema = external_exports.object({
|
|
27895
|
-
/** The agent's suggested name for the pairing — the human sees it pre-filled at
|
|
27896
|
-
* approval and can override. Optional; blank → a default silly name server-side. */
|
|
27897
|
-
suggestedName: external_exports.string().optional(),
|
|
27898
|
-
/** Legacy alias for suggestedName (older MCPs sent `agent`). Accepted for
|
|
27899
|
-
* back-compat; `suggestedName` wins when both are present. ponytail: drop once no
|
|
27900
|
-
* pre-`name` MCP is in the wild. */
|
|
27901
|
-
agent: external_exports.union([external_exports.string(), external_exports.object({ name: external_exports.string().optional() })]).optional(),
|
|
27902
|
-
device: external_exports.string().optional(),
|
|
27903
|
-
proto: external_exports.string().optional(),
|
|
27904
|
-
// compiled-in tag, e.g. "paigy-pair-v2|sas=24"
|
|
27905
|
-
commitment: external_exports.string().optional()
|
|
27906
|
-
// agent's Ca
|
|
27907
|
-
});
|
|
27908
27787
|
DeviceCodeSchema = external_exports.object({
|
|
27909
27788
|
device_code: external_exports.string(),
|
|
27910
27789
|
user_code: external_exports.string(),
|
|
@@ -27938,11 +27817,6 @@ var init_dist = __esm({
|
|
|
27938
27817
|
phone_reveal: PairingRevealSchema.nullable().optional(),
|
|
27939
27818
|
uik_pub: external_exports.string().nullable().optional()
|
|
27940
27819
|
});
|
|
27941
|
-
DeviceTokenRequestSchema = external_exports.object({
|
|
27942
|
-
device_code: external_exports.string(),
|
|
27943
|
-
reveal: PairingRevealSchema.optional()
|
|
27944
|
-
// agent's reveal {x25519, ed25519, nonce}
|
|
27945
|
-
});
|
|
27946
27820
|
DeviceTokenSchema = external_exports.object({
|
|
27947
27821
|
access_token: external_exports.string(),
|
|
27948
27822
|
/** The pairing's single name (user-typed at approval, the agent's suggestion, or
|
|
@@ -27964,14 +27838,6 @@ var init_dist = __esm({
|
|
|
27964
27838
|
// present once the phone reveals
|
|
27965
27839
|
uik_pub: external_exports.string().nullable().optional()
|
|
27966
27840
|
});
|
|
27967
|
-
DeviceCommitRequestSchema = external_exports.object({
|
|
27968
|
-
code: external_exports.string(),
|
|
27969
|
-
commitment: external_exports.string()
|
|
27970
|
-
// Cb
|
|
27971
|
-
});
|
|
27972
|
-
DevicePeerCommitSchema = external_exports.object({
|
|
27973
|
-
commitment: external_exports.string().nullable()
|
|
27974
|
-
});
|
|
27975
27841
|
SupportRequestSchema = external_exports.object({
|
|
27976
27842
|
email: external_exports.string().email().max(320),
|
|
27977
27843
|
message: external_exports.string().trim().min(1).max(5e3),
|
|
@@ -27991,15 +27857,6 @@ var init_dist = __esm({
|
|
|
27991
27857
|
"other"
|
|
27992
27858
|
// anything else — the note carries it.
|
|
27993
27859
|
]);
|
|
27994
|
-
NotificationFeedbackSchema = external_exports.object({
|
|
27995
|
-
notificationId: external_exports.string(),
|
|
27996
|
-
kind: NotificationFeedbackKindSchema,
|
|
27997
|
-
/** Optional free-text elaboration for a preset; required (non-empty) for 'other'. */
|
|
27998
|
-
note: external_exports.string().trim().max(2e3).optional()
|
|
27999
|
-
}).superRefine((r, ctx) => {
|
|
28000
|
-
if (r.kind === "other" && !r.note)
|
|
28001
|
-
ctx.addIssue({ code: external_exports.ZodIssueCode.custom, path: ["note"], message: "note is required for 'other' feedback" });
|
|
28002
|
-
});
|
|
28003
27860
|
FeedbackResolutionSchema = external_exports.enum(["broker_fixed", "sent_to_agent"]);
|
|
28004
27861
|
FeedbackOutcomeSchema = external_exports.object({
|
|
28005
27862
|
resolution: FeedbackResolutionSchema,
|
|
@@ -33270,15 +33127,28 @@ function parseArgs(argv) {
|
|
|
33270
33127
|
return args;
|
|
33271
33128
|
}
|
|
33272
33129
|
var ENABLE_TOOLS_COMMAND = "npx -y -p @paigy/mcp@latest paigy-enable-tools";
|
|
33130
|
+
function onEnter(input, onLine) {
|
|
33131
|
+
if (!input.isTTY) return () => {
|
|
33132
|
+
};
|
|
33133
|
+
const listen = (chunk) => {
|
|
33134
|
+
if (/[\r\n]/.test(String(chunk))) onLine();
|
|
33135
|
+
};
|
|
33136
|
+
input.on("data", listen);
|
|
33137
|
+
input.resume();
|
|
33138
|
+
return () => {
|
|
33139
|
+
input.off("data", listen);
|
|
33140
|
+
input.pause();
|
|
33141
|
+
};
|
|
33142
|
+
}
|
|
33273
33143
|
|
|
33274
33144
|
// src/cli.ts
|
|
33275
33145
|
init_dist();
|
|
33276
33146
|
var import_qrcode = __toESM(require_lib(), 1);
|
|
33277
33147
|
import { hostname } from "os";
|
|
33278
33148
|
import { existsSync as existsSync5, mkdirSync as mkdirSync3, readFileSync as readFileSync4, writeFileSync as writeFileSync4 } from "fs";
|
|
33279
|
-
import { execSync } from "child_process";
|
|
33149
|
+
import { execFile as execFile2, execSync } from "child_process";
|
|
33280
33150
|
import { homedir as homedir7 } from "os";
|
|
33281
|
-
import { join as
|
|
33151
|
+
import { join as join6 } from "path";
|
|
33282
33152
|
|
|
33283
33153
|
// src/harness/session.ts
|
|
33284
33154
|
import { spawn } from "child_process";
|
|
@@ -34971,9 +34841,9 @@ var UpdateGoalToolSchema2 = UpdateGoalSchema2.omit({ operationId: true }).extend
|
|
|
34971
34841
|
var ClaimGoalSchema2 = external_exports.object({ goalId: external_exports.string().uuid().optional() }).strict();
|
|
34972
34842
|
var GetGoalSchema2 = external_exports.object({ goalId: external_exports.string().uuid() }).strict();
|
|
34973
34843
|
var GET_GOAL_DESCRIPTION2 = "Read the current authorized Goal brief: state, owner, blockers, open decisions, progress, and the next operation. Foreign or sibling-owned Goals are not disclosed.";
|
|
34974
|
-
var UPDATE_GOAL_DESCRIPTION2 = "Update an owned Goal at an exact revision. State, ownership, dependencies, children, progress, and review acknowledgement are explicit; stale revisions are rejected. Returns the new revision and a prose summary.";
|
|
34844
|
+
var UPDATE_GOAL_DESCRIPTION2 = "Update an owned Goal at an exact revision. State, ownership, dependencies, children, progress, and review acknowledgement are explicit; stale revisions are rejected. reviewed: true acknowledges new evidence and closes the Deliveries addressed to you on that Goal, never over an open decision. Returns the new revision and a prose summary.";
|
|
34975
34845
|
var CLAIM_GOAL_DESCRIPTION2 = "Claim the oldest runnable or review-pending Goal you own, or pass goalId to claim that Goal. Returns a Goal-scoped brief, current revision, blockers, and the next valid operation. Claiming creates or renews the execution lease.";
|
|
34976
|
-
var CHECK_REPLIES_DESCRIPTION2 = "Your open Deliveries: every Notification or Call currently addressed to you \u2014 a request the user started toward you, an answer relayed to something you asked, a handoff \u2014 each
|
|
34846
|
+
var CHECK_REPLIES_DESCRIPTION2 = "Your open Deliveries: every Notification or Call currently addressed to you \u2014 a request the user started toward you, an answer relayed to something you asked, a handoff \u2014 one row each: its Goals, the newest words in brief, accepted decisions and open decision needs, without the Entries. 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 it in full with contact({deliveryId}). Once you have acted on what arrived, update_goal with reviewed: true closes the Deliveries addressed to you on that Goal. Your runnable and review-pending Goals come from claim_goal, not from here.";
|
|
34977
34847
|
var CheckRepliesSchema2 = external_exports.object({}).strict();
|
|
34978
34848
|
var GetThreadSchema2 = external_exports.object({
|
|
34979
34849
|
parentId: external_exports.string().describe("The Thread to read \u2014 the threadId a Delivery returned, or the parentId of a search hit.")
|
|
@@ -35367,67 +35237,6 @@ var AwaitItemSchema2 = external_exports.discriminatedUnion("type", [
|
|
|
35367
35237
|
inFlight: external_exports.boolean().optional()
|
|
35368
35238
|
})
|
|
35369
35239
|
]);
|
|
35370
|
-
var CallbackTriggerSchema2 = external_exports.enum(["on_done", "on_blocked", "scheduled"]);
|
|
35371
|
-
var NotifyResponseSchema2 = external_exports.object({
|
|
35372
|
-
notificationId: external_exports.string(),
|
|
35373
|
-
workId: external_exports.string().uuid().optional(),
|
|
35374
|
-
decisionId: external_exports.string().uuid().optional(),
|
|
35375
|
-
status: NotifyStatusSchema2,
|
|
35376
|
-
createdAt: external_exports.string().datetime(),
|
|
35377
|
-
answer: UserAnswerSchema2.optional(),
|
|
35378
|
-
answeredAt: external_exports.string().datetime().optional(),
|
|
35379
|
-
/** Ride-alongs for THIS agent — pending work it should pick up when it's done with
|
|
35380
|
-
* what it came for. Present on any reply, because an unwakeable agent's only
|
|
35381
|
-
* reliable moment is one it initiated. Absent/empty = nothing owed. */
|
|
35382
|
-
also: external_exports.array(RideAlongSchema2).optional()
|
|
35383
|
-
});
|
|
35384
|
-
var NotifyPlanUnitSchema2 = external_exports.object({
|
|
35385
|
-
notificationId: external_exports.string(),
|
|
35386
|
-
/** The unit's own heading, so the agent can tell which of its paragraphs this became. */
|
|
35387
|
-
title: external_exports.string(),
|
|
35388
|
-
/** How loudly this unit was arbitrated to arrive — per unit, which is the point of units. */
|
|
35389
|
-
level: NotifyLevelSchema2,
|
|
35390
|
-
/** Answered from something the user already decided: nobody is interrupted, and a trail card
|
|
35391
|
-
* says so. The agent should not wait on this one. */
|
|
35392
|
-
settled: external_exports.literal(true).optional(),
|
|
35393
|
-
/** What this unit would need to be answerable and does not carry (#894). A PROPOSAL to the
|
|
35394
|
-
* agent — nothing here changed the ask, and ignoring it costs nothing. */
|
|
35395
|
-
needs: external_exports.array(external_exports.enum(["options", "visuals"])).optional(),
|
|
35396
|
-
/** The SHAPE the broker would give this unit, for the agent to ratify (#886/#894). The
|
|
35397
|
-
* split layer reads prose and can see that a paragraph is a yes/no or a pick-one — but a
|
|
35398
|
-
* broker that DECIDES that destroys the only fact separating a statement from a real ask
|
|
35399
|
-
* (#731), so it is offered, never applied: the unit is stored `text` until the agent
|
|
35400
|
-
* confirms the shape (POST /notify/:id/confirm). Ignoring it costs nothing. */
|
|
35401
|
-
proposal: external_exports.object({
|
|
35402
|
-
select: SelectShapeSchema2,
|
|
35403
|
-
options: external_exports.array(external_exports.object({ label: external_exports.string().min(1) })).optional()
|
|
35404
|
-
}).optional(),
|
|
35405
|
-
/** What the broker READ this unit as wanting from the human (#952 layer 2): a `decision`
|
|
35406
|
-
* between alternatives, an `approval` the agent is blocked on, or `knowledge` it just
|
|
35407
|
-
* needs to know. Reported so the agent can correct a misread the same way it ratifies a
|
|
35408
|
-
* shape — the read RAISES (a decision always asks) and never silences a question the
|
|
35409
|
-
* agent declared (#731, #923). */
|
|
35410
|
-
wants: external_exports.enum(["decision", "approval", "knowledge"]).optional()
|
|
35411
|
-
});
|
|
35412
|
-
var NotifyPlanSchema2 = external_exports.object({
|
|
35413
|
-
units: external_exports.array(NotifyPlanUnitSchema2),
|
|
35414
|
-
/** Which unit is this arrival's ONE interruption (units-design.md D23). Absent means nobody
|
|
35415
|
-
* was interrupted — every unit was either settled or quiet enough to sit in the inbox. */
|
|
35416
|
-
speaks: external_exports.string().optional()
|
|
35417
|
-
});
|
|
35418
|
-
var UserResponseSchema2 = external_exports.object({
|
|
35419
|
-
requestId: external_exports.string(),
|
|
35420
|
-
answer: UserAnswerSchema2,
|
|
35421
|
-
answeredAt: external_exports.string().datetime(),
|
|
35422
|
-
transcript: external_exports.string().optional(),
|
|
35423
|
-
/** E2EE: the sealed answer (opaque envelope + plaintext `ignored` hint) when the item was
|
|
35424
|
-
* E2EE-sealed. Present → the server persists it opaquely and branches status on `ignored`;
|
|
35425
|
-
* the plaintext `answer` is a placeholder (`{ kind: "ignored" }`) the server ignores for a
|
|
35426
|
-
* sealed row. Absent = today's plaintext answer, unchanged. */
|
|
35427
|
-
sealed: external_exports.lazy(() => SealedAnswerSchema2).optional(),
|
|
35428
|
-
/** Coverage report (#396): which of the ask's declared `points` were addressed. */
|
|
35429
|
-
covered: external_exports.array(external_exports.string()).optional()
|
|
35430
|
-
});
|
|
35431
35240
|
var VoiceKeySchema2 = external_exports.enum(["rachel", "george", "jessica", "brian", "lily"]);
|
|
35432
35241
|
var AgendaTurnSchema2 = external_exports.object({
|
|
35433
35242
|
/** THE TURN'S IDENTITY (the first-sentence stream, 2026-09-09): the brain call that wrote
|
|
@@ -35611,10 +35420,6 @@ var InboxItemSchema2 = external_exports.object({
|
|
|
35611
35420
|
goalState: external_exports.string().optional()
|
|
35612
35421
|
}).optional()
|
|
35613
35422
|
});
|
|
35614
|
-
var SnoozeRequestSchema2 = external_exports.object({
|
|
35615
|
-
requestId: external_exports.string(),
|
|
35616
|
-
until: external_exports.string().datetime()
|
|
35617
|
-
});
|
|
35618
35423
|
var APNS_TOKEN_RE2 = /^[0-9a-fA-F]{64}$/;
|
|
35619
35424
|
var PushTokenSchema2 = external_exports.object({
|
|
35620
35425
|
voipToken: external_exports.string().min(1).optional(),
|
|
@@ -35770,6 +35575,9 @@ var ConnectionSummarySchema2 = external_exports.object({
|
|
|
35770
35575
|
* harness availabilities + granted workspaces — the option set the phone's
|
|
35771
35576
|
* "new session" sheet offers. Absent for ordinary MCP agents. */
|
|
35772
35577
|
runtime: external_exports.object({
|
|
35578
|
+
/** The @paigy/harness this host is running — a machine the self-update has not reached
|
|
35579
|
+
* shows its age here (`apps/desktop/src/update.ts`). */
|
|
35580
|
+
version: external_exports.string().optional(),
|
|
35773
35581
|
harnesses: external_exports.array(external_exports.object({ name: external_exports.string(), label: external_exports.string(), status: external_exports.string() })).optional(),
|
|
35774
35582
|
workspaces: external_exports.array(external_exports.string()).optional()
|
|
35775
35583
|
}).optional(),
|
|
@@ -35832,19 +35640,6 @@ var MoveSchema2 = external_exports.object({
|
|
|
35832
35640
|
* distilled from a clarify ruling (those carry no agent) or one whose source rows are gone. */
|
|
35833
35641
|
learnedFrom: external_exports.object({ id: external_exports.string(), name: external_exports.string() }).nullable()
|
|
35834
35642
|
});
|
|
35835
|
-
var CreateRequestSchema2 = external_exports.object({
|
|
35836
|
-
/** The connection (token id) to send to, from GET /api/tokens. */
|
|
35837
|
-
tokenId: external_exports.string(),
|
|
35838
|
-
/** The user's message to the agent. */
|
|
35839
|
-
text: external_exports.string().min(1),
|
|
35840
|
-
/** Land the request on an existing conversation thread (History → "Continue")
|
|
35841
|
-
* instead of minting a fresh one. Must belong to the requesting user. */
|
|
35842
|
-
parentId: external_exports.string().optional(),
|
|
35843
|
-
/** Point the agent at a past conversation (possibly with a different agent) as
|
|
35844
|
-
* starting context (History → "New session from this"). A reference, not a copy —
|
|
35845
|
-
* the agent reads it via get_thread. Must belong to the requesting user. */
|
|
35846
|
-
contextParentId: external_exports.string().optional()
|
|
35847
|
-
});
|
|
35848
35643
|
var QueueQuestionSchema2 = external_exports.object({
|
|
35849
35644
|
/** The decision need's id — what an answer is accepted against. */
|
|
35850
35645
|
id: external_exports.string(),
|
|
@@ -35936,38 +35731,6 @@ var NoteSchema2 = external_exports.object({
|
|
|
35936
35731
|
lastRideAt: external_exports.string().nullable().default(null),
|
|
35937
35732
|
createdAt: external_exports.string()
|
|
35938
35733
|
});
|
|
35939
|
-
var CreateNoteSchema2 = external_exports.object({
|
|
35940
|
-
/** The intent, in the user's own words. Stored verbatim; the broker only titles it. */
|
|
35941
|
-
text: external_exports.string().min(1).max(4e3),
|
|
35942
|
-
/** Capture it as a REMINDER — a note assigned to the user themselves, which rides
|
|
35943
|
-
* their next call instead of being handed to an agent. Everything else about the
|
|
35944
|
-
* note is identical; this is the one parameter that separates the two. */
|
|
35945
|
-
forMe: external_exports.boolean().optional(),
|
|
35946
|
-
/** The not-before, when the user already said one. Absent = the very next call. */
|
|
35947
|
-
dueAt: external_exports.string().datetime().optional(),
|
|
35948
|
-
repeat: NoteRepeatSchema2.optional()
|
|
35949
|
-
});
|
|
35950
|
-
var RecordDecisionSchema2 = external_exports.object({
|
|
35951
|
-
/** An open decision (from /clarify) to answer. */
|
|
35952
|
-
decisionId: external_exports.string().optional(),
|
|
35953
|
-
/** For an ad-hoc decision: what was ambiguous. Required without `decisionId`. */
|
|
35954
|
-
question: external_exports.string().min(1).max(500).optional(),
|
|
35955
|
-
/** The ruling. */
|
|
35956
|
-
answer: external_exports.string().min(1).max(2e3)
|
|
35957
|
-
}).refine((d) => d.decisionId || d.question, { message: "decisionId or question required" });
|
|
35958
|
-
var AssignNoteSchema2 = external_exports.object({
|
|
35959
|
-
/** An EXISTING agent: token id or nickname. Omit when spawning fresh. */
|
|
35960
|
-
target: external_exports.string().min(1).optional(),
|
|
35961
|
-
/** Spawn a NEW session for this note (companion.md §2.2): the assignee doesn't
|
|
35962
|
-
* exist yet — mint it on a live desktop that advertises the harness+workspace,
|
|
35963
|
-
* named after the note. The brief arrives as its opening request. */
|
|
35964
|
-
spawn: external_exports.object({
|
|
35965
|
-
hostTokenId: external_exports.string().uuid(),
|
|
35966
|
-
harness: external_exports.string().min(1),
|
|
35967
|
-
workspace: external_exports.string().min(1)
|
|
35968
|
-
}).optional()
|
|
35969
|
-
}).refine((a) => !!a.target !== !!a.spawn, { message: "exactly one of target or spawn" });
|
|
35970
|
-
var TriageVerdictSchema2 = external_exports.enum(["keep", "stale", "close", "assign"]);
|
|
35971
35734
|
var TriageItemSchema2 = external_exports.object({
|
|
35972
35735
|
noteId: external_exports.string(),
|
|
35973
35736
|
/** The note's headline at run time. */
|
|
@@ -36101,20 +35864,6 @@ var PairingRevealSchema2 = external_exports.object({
|
|
|
36101
35864
|
ed25519: external_exports.string(),
|
|
36102
35865
|
nonce: external_exports.string()
|
|
36103
35866
|
});
|
|
36104
|
-
var DeviceCodeRequestSchema2 = external_exports.object({
|
|
36105
|
-
/** The agent's suggested name for the pairing — the human sees it pre-filled at
|
|
36106
|
-
* approval and can override. Optional; blank → a default silly name server-side. */
|
|
36107
|
-
suggestedName: external_exports.string().optional(),
|
|
36108
|
-
/** Legacy alias for suggestedName (older MCPs sent `agent`). Accepted for
|
|
36109
|
-
* back-compat; `suggestedName` wins when both are present. ponytail: drop once no
|
|
36110
|
-
* pre-`name` MCP is in the wild. */
|
|
36111
|
-
agent: external_exports.union([external_exports.string(), external_exports.object({ name: external_exports.string().optional() })]).optional(),
|
|
36112
|
-
device: external_exports.string().optional(),
|
|
36113
|
-
proto: external_exports.string().optional(),
|
|
36114
|
-
// compiled-in tag, e.g. "paigy-pair-v2|sas=24"
|
|
36115
|
-
commitment: external_exports.string().optional()
|
|
36116
|
-
// agent's Ca
|
|
36117
|
-
});
|
|
36118
35867
|
var DeviceCodeSchema2 = external_exports.object({
|
|
36119
35868
|
device_code: external_exports.string(),
|
|
36120
35869
|
user_code: external_exports.string(),
|
|
@@ -36148,11 +35897,6 @@ var DeviceInfoSchema2 = external_exports.object({
|
|
|
36148
35897
|
phone_reveal: PairingRevealSchema2.nullable().optional(),
|
|
36149
35898
|
uik_pub: external_exports.string().nullable().optional()
|
|
36150
35899
|
});
|
|
36151
|
-
var DeviceTokenRequestSchema2 = external_exports.object({
|
|
36152
|
-
device_code: external_exports.string(),
|
|
36153
|
-
reveal: PairingRevealSchema2.optional()
|
|
36154
|
-
// agent's reveal {x25519, ed25519, nonce}
|
|
36155
|
-
});
|
|
36156
35900
|
var DeviceTokenSchema2 = external_exports.object({
|
|
36157
35901
|
access_token: external_exports.string(),
|
|
36158
35902
|
/** The pairing's single name (user-typed at approval, the agent's suggestion, or
|
|
@@ -36174,14 +35918,6 @@ var DeviceTokenSchema2 = external_exports.object({
|
|
|
36174
35918
|
// present once the phone reveals
|
|
36175
35919
|
uik_pub: external_exports.string().nullable().optional()
|
|
36176
35920
|
});
|
|
36177
|
-
var DeviceCommitRequestSchema2 = external_exports.object({
|
|
36178
|
-
code: external_exports.string(),
|
|
36179
|
-
commitment: external_exports.string()
|
|
36180
|
-
// Cb
|
|
36181
|
-
});
|
|
36182
|
-
var DevicePeerCommitSchema2 = external_exports.object({
|
|
36183
|
-
commitment: external_exports.string().nullable()
|
|
36184
|
-
});
|
|
36185
35921
|
var SupportRequestSchema2 = external_exports.object({
|
|
36186
35922
|
email: external_exports.string().email().max(320),
|
|
36187
35923
|
message: external_exports.string().trim().min(1).max(5e3),
|
|
@@ -36201,15 +35937,6 @@ var NotificationFeedbackKindSchema2 = external_exports.enum([
|
|
|
36201
35937
|
"other"
|
|
36202
35938
|
// anything else — the note carries it.
|
|
36203
35939
|
]);
|
|
36204
|
-
var NotificationFeedbackSchema2 = external_exports.object({
|
|
36205
|
-
notificationId: external_exports.string(),
|
|
36206
|
-
kind: NotificationFeedbackKindSchema2,
|
|
36207
|
-
/** Optional free-text elaboration for a preset; required (non-empty) for 'other'. */
|
|
36208
|
-
note: external_exports.string().trim().max(2e3).optional()
|
|
36209
|
-
}).superRefine((r, ctx) => {
|
|
36210
|
-
if (r.kind === "other" && !r.note)
|
|
36211
|
-
ctx.addIssue({ code: external_exports.ZodIssueCode.custom, path: ["note"], message: "note is required for 'other' feedback" });
|
|
36212
|
-
});
|
|
36213
35940
|
var FeedbackResolutionSchema2 = external_exports.enum(["broker_fixed", "sent_to_agent"]);
|
|
36214
35941
|
var FeedbackOutcomeSchema2 = external_exports.object({
|
|
36215
35942
|
resolution: FeedbackResolutionSchema2,
|
|
@@ -36511,7 +36238,7 @@ init_dist();
|
|
|
36511
36238
|
init_catalog();
|
|
36512
36239
|
import { readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "fs";
|
|
36513
36240
|
import { homedir as homedir5 } from "os";
|
|
36514
|
-
import { join as
|
|
36241
|
+
import { join as join5 } from "path";
|
|
36515
36242
|
|
|
36516
36243
|
// src/workspaces.ts
|
|
36517
36244
|
import { existsSync as existsSync4, mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
@@ -36550,8 +36277,67 @@ function resolveWakeDir(pinned, deps) {
|
|
|
36550
36277
|
return listWorkspaces(deps)[0];
|
|
36551
36278
|
}
|
|
36552
36279
|
|
|
36280
|
+
// src/update.ts
|
|
36281
|
+
import { execFile } from "child_process";
|
|
36282
|
+
import { createRequire } from "module";
|
|
36283
|
+
import { dirname as dirname3, join as join4 } from "path";
|
|
36284
|
+
import { promisify } from "util";
|
|
36285
|
+
var SERVICE_LABEL = "ai.paigy.harness";
|
|
36286
|
+
var VERSION = createRequire(import.meta.url)("../package.json").version;
|
|
36287
|
+
var REGISTRY = "https://registry.npmjs.org/@paigy/harness/latest";
|
|
36288
|
+
var CHECK_MS = 60 * 6e4;
|
|
36289
|
+
function newer(latest, current) {
|
|
36290
|
+
const parts = (v) => /^\d+\.\d+\.\d+$/.test(v) ? v.split(".").map(Number) : null;
|
|
36291
|
+
const [a, b] = [parts(latest), parts(current)];
|
|
36292
|
+
if (!a || !b) return false;
|
|
36293
|
+
for (let i = 0; i < 3; i++) if (a[i] !== b[i]) return a[i] > b[i];
|
|
36294
|
+
return false;
|
|
36295
|
+
}
|
|
36296
|
+
function updateAction(o) {
|
|
36297
|
+
if (!o.service || !o.latest || o.latest === o.failed || !newer(o.latest, o.current)) return "none";
|
|
36298
|
+
return o.sessions > 0 ? "wait" : "install";
|
|
36299
|
+
}
|
|
36300
|
+
async function latestVersion() {
|
|
36301
|
+
const res = await fetch(REGISTRY, { signal: AbortSignal.timeout(1e4) });
|
|
36302
|
+
return res.ok ? (await res.json()).version ?? null : null;
|
|
36303
|
+
}
|
|
36304
|
+
async function install(version) {
|
|
36305
|
+
const bin = dirname3(process.execPath);
|
|
36306
|
+
await promisify(execFile)(join4(bin, "npm"), ["install", "-g", `@paigy/harness@${version}`], {
|
|
36307
|
+
env: { ...process.env, PATH: `${bin}:${process.env.PATH ?? ""}`, npm_config_update_notifier: "false" },
|
|
36308
|
+
timeout: 5 * 6e4
|
|
36309
|
+
});
|
|
36310
|
+
}
|
|
36311
|
+
function selfUpdater(deps) {
|
|
36312
|
+
const service = deps.service ?? process.env.XPC_SERVICE_NAME === SERVICE_LABEL;
|
|
36313
|
+
let latest = null;
|
|
36314
|
+
let checkedAt = -Infinity;
|
|
36315
|
+
let failed;
|
|
36316
|
+
let waiting = false;
|
|
36317
|
+
return async () => {
|
|
36318
|
+
if (!service) return;
|
|
36319
|
+
const now = (deps.now ?? Date.now)();
|
|
36320
|
+
if (now - checkedAt >= CHECK_MS) {
|
|
36321
|
+
checkedAt = now;
|
|
36322
|
+
latest = await (deps.latest ?? latestVersion)().catch(() => latest);
|
|
36323
|
+
}
|
|
36324
|
+
const action = updateAction({ current: VERSION, latest, service, sessions: deps.sessions(), failed });
|
|
36325
|
+
if (action === "wait" && !waiting) deps.log(`\u21E1 @paigy/harness ${latest} is out \u2014 updating once no session is running`);
|
|
36326
|
+
waiting = action === "wait";
|
|
36327
|
+
if (action !== "install" || !latest) return;
|
|
36328
|
+
try {
|
|
36329
|
+
await (deps.install ?? install)(latest);
|
|
36330
|
+
deps.log(`\u21E1 updated @paigy/harness ${VERSION} \u2192 ${latest} \u2014 restarting`);
|
|
36331
|
+
(deps.exit ?? (() => process.exit(0)))();
|
|
36332
|
+
} catch (e) {
|
|
36333
|
+
failed = latest;
|
|
36334
|
+
deps.log(`\u26A0 could not update to @paigy/harness ${latest}: ${e.message.split("\n")[0]} \u2014 run: npm install -g @paigy/harness`);
|
|
36335
|
+
}
|
|
36336
|
+
};
|
|
36337
|
+
}
|
|
36338
|
+
|
|
36553
36339
|
// src/host.ts
|
|
36554
|
-
var HOST_FILE =
|
|
36340
|
+
var HOST_FILE = join5(homedir5(), ".paigy", "host.json");
|
|
36555
36341
|
var runKey = (slot) => `slot:${slot}`;
|
|
36556
36342
|
var claimedRun = (sessionId2) => {
|
|
36557
36343
|
const slot = sessionSlot(sessionId2);
|
|
@@ -36581,11 +36367,15 @@ function startHost(opts) {
|
|
|
36581
36367
|
}
|
|
36582
36368
|
}
|
|
36583
36369
|
};
|
|
36370
|
+
const update = selfUpdater({ sessions: () => runs.size, log: opts.log });
|
|
36584
36371
|
const beat = () => {
|
|
36585
36372
|
void refreshIdentities();
|
|
36373
|
+
void update().catch(() => {
|
|
36374
|
+
});
|
|
36586
36375
|
for (const r of runs.values()) if (r.token) void heartbeat(void 0, { token: r.token }).catch(() => {
|
|
36587
36376
|
});
|
|
36588
36377
|
void heartbeat({
|
|
36378
|
+
version: VERSION,
|
|
36589
36379
|
harnesses: detectAll().map((a) => ({ name: a.name, label: a.label, status: a.status })),
|
|
36590
36380
|
workspaces: listWorkspaces(opts.wsDeps)
|
|
36591
36381
|
}, asHost).catch(() => {
|
|
@@ -36869,13 +36659,37 @@ function bridgeLine(r) {
|
|
|
36869
36659
|
|
|
36870
36660
|
// src/cli.ts
|
|
36871
36661
|
var STATUS_MARK = { ready: "\u2713", login: "\u25D0", "adapter-missing": "\u25D0", missing: "\u2717" };
|
|
36872
|
-
function printConnectLines(link, userCode) {
|
|
36662
|
+
function printConnectLines(link, userCode, enter) {
|
|
36873
36663
|
console.log("Connect this computer from your phone");
|
|
36874
|
-
console.log(` Open ${link}`);
|
|
36664
|
+
console.log(` Open ${link}${enter ? " (press Enter to open it here)" : ""}`);
|
|
36875
36665
|
console.log(` or scan the QR above \xB7 or type ${userCode} in Paigy \u2192 Devices \u2192 Connect a computer`);
|
|
36876
36666
|
}
|
|
36667
|
+
async function pairThisMachine() {
|
|
36668
|
+
const host = hostname().replace(/\.local$/, "");
|
|
36669
|
+
const code = await requestCode(host, void 0, host);
|
|
36670
|
+
const link = code.verification_uri_complete;
|
|
36671
|
+
console.log(await import_qrcode.default.toString(link, { type: "terminal", small: true }));
|
|
36672
|
+
printConnectLines(link, code.user_code, !!process.stdin.isTTY);
|
|
36673
|
+
const opener = process.platform === "darwin" ? "open" : "xdg-open";
|
|
36674
|
+
const stop2 = onEnter(process.stdin, () => execFile2(opener, [link], () => {
|
|
36675
|
+
}));
|
|
36676
|
+
try {
|
|
36677
|
+
const deadline = Date.now() + code.expires_in * 1e3;
|
|
36678
|
+
while (Date.now() < deadline) {
|
|
36679
|
+
const token = await pollToken(code.device_code).catch(() => null);
|
|
36680
|
+
if (token) {
|
|
36681
|
+
saveToken(token, "Desktop");
|
|
36682
|
+
return token.name;
|
|
36683
|
+
}
|
|
36684
|
+
await sleep(code.interval * 1e3);
|
|
36685
|
+
}
|
|
36686
|
+
return null;
|
|
36687
|
+
} finally {
|
|
36688
|
+
stop2();
|
|
36689
|
+
}
|
|
36690
|
+
}
|
|
36877
36691
|
function forwardCodexThreadId() {
|
|
36878
|
-
const cfg =
|
|
36692
|
+
const cfg = join6(process.env.CODEX_HOME || join6(homedir7(), ".codex"), "config.toml");
|
|
36879
36693
|
if (!existsSync5(cfg)) return;
|
|
36880
36694
|
const text = readFileSync4(cfg, "utf8");
|
|
36881
36695
|
const head = "[mcp_servers.paigy]\n";
|
|
@@ -36961,23 +36775,12 @@ async function main() {
|
|
|
36961
36775
|
const live = held ? await credentialWorks(held) : false;
|
|
36962
36776
|
if (held && !live) console.log("\u26A0 this machine was logged out \u2014 reconnecting it now");
|
|
36963
36777
|
if (!live) {
|
|
36964
|
-
const
|
|
36965
|
-
|
|
36966
|
-
printConnectLines(code.verification_uri_complete, code.user_code);
|
|
36967
|
-
const deadline = Date.now() + code.expires_in * 1e3;
|
|
36968
|
-
let paired = false;
|
|
36969
|
-
while (!paired && Date.now() < deadline) {
|
|
36970
|
-
const token = await pollToken(code.device_code).catch(() => null);
|
|
36971
|
-
if (token) {
|
|
36972
|
-
saveToken(token, "Desktop");
|
|
36973
|
-
console.log(`\u2713 paired as "${token.name}"`);
|
|
36974
|
-
paired = true;
|
|
36975
|
-
} else await sleep(code.interval * 1e3);
|
|
36976
|
-
}
|
|
36977
|
-
if (!paired) {
|
|
36778
|
+
const name = await pairThisMachine();
|
|
36779
|
+
if (name === null) {
|
|
36978
36780
|
console.error("Pairing code expired \u2014 run `paigy-harness setup` again.");
|
|
36979
36781
|
process.exit(1);
|
|
36980
36782
|
}
|
|
36783
|
+
console.log(`\u2713 paired as "${name}"`);
|
|
36981
36784
|
} else console.log("\u2713 already paired as this machine");
|
|
36982
36785
|
for (const a of detected) {
|
|
36983
36786
|
if (a.status === "adapter-missing" && a.install) continue;
|
|
@@ -36988,7 +36791,7 @@ async function main() {
|
|
|
36988
36791
|
const wsDeps = { file: workspacesFile() };
|
|
36989
36792
|
for (const dir of parsed.grant) addWorkspace(dir, wsDeps);
|
|
36990
36793
|
if (!listWorkspaces(wsDeps).length) {
|
|
36991
|
-
const guess =
|
|
36794
|
+
const guess = join6(homedir7(), "projects");
|
|
36992
36795
|
if (existsSync5(guess)) {
|
|
36993
36796
|
addWorkspace(guess, wsDeps);
|
|
36994
36797
|
console.log(`\u2713 workspace granted: ${guess} (change with --grant DIR)`);
|
|
@@ -37029,7 +36832,7 @@ async function main() {
|
|
|
37029
36832
|
}
|
|
37030
36833
|
}
|
|
37031
36834
|
try {
|
|
37032
|
-
const settings =
|
|
36835
|
+
const settings = join6(homedir7(), ".claude", "settings.json");
|
|
37033
36836
|
if (which("claude") && existsSync5(settings)) {
|
|
37034
36837
|
const cfg = JSON.parse(readFileSync4(settings, "utf8"));
|
|
37035
36838
|
if (!cfg["statusLine"]) {
|
|
@@ -37058,22 +36861,14 @@ async function main() {
|
|
|
37058
36861
|
return;
|
|
37059
36862
|
}
|
|
37060
36863
|
if (existing) console.log("\u26A0 this machine was logged out \u2014 reconnecting it now");
|
|
37061
|
-
const
|
|
37062
|
-
|
|
37063
|
-
|
|
37064
|
-
|
|
37065
|
-
while (Date.now() < deadline) {
|
|
37066
|
-
const token = await pollToken(code.device_code).catch(() => null);
|
|
37067
|
-
if (token) {
|
|
37068
|
-
saveToken(token, "Desktop");
|
|
37069
|
-
console.log(`\u2713 paired as "${token.name}" \u2014 this machine is now launchable from your phone`);
|
|
37070
|
-
console.log(" next: paigy-harness host --grant ~/your/projects (or: paigy-harness service)");
|
|
37071
|
-
return;
|
|
37072
|
-
}
|
|
37073
|
-
await sleep(code.interval * 1e3);
|
|
36864
|
+
const name = await pairThisMachine();
|
|
36865
|
+
if (name === null) {
|
|
36866
|
+
console.error("Pairing code expired \u2014 run `paigy-harness pair` again.");
|
|
36867
|
+
process.exit(1);
|
|
37074
36868
|
}
|
|
37075
|
-
console.
|
|
37076
|
-
|
|
36869
|
+
console.log(`\u2713 paired as "${name}" \u2014 this machine is now launchable from your phone`);
|
|
36870
|
+
console.log(" next: paigy-harness host --grant ~/your/projects (or: paigy-harness service)");
|
|
36871
|
+
return;
|
|
37077
36872
|
}
|
|
37078
36873
|
if (parsed.service) {
|
|
37079
36874
|
if (process.platform !== "darwin") {
|
|
@@ -37084,7 +36879,7 @@ async function main() {
|
|
|
37084
36879
|
const plist = `<?xml version="1.0" encoding="UTF-8"?>
|
|
37085
36880
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
37086
36881
|
<plist version="1.0"><dict>
|
|
37087
|
-
<key>Label</key><string
|
|
36882
|
+
<key>Label</key><string>${SERVICE_LABEL}</string>
|
|
37088
36883
|
<key>ProgramArguments</key><array>
|
|
37089
36884
|
<string>${process.execPath}</string>
|
|
37090
36885
|
<string>${bin}</string>
|
|
@@ -37095,13 +36890,13 @@ async function main() {
|
|
|
37095
36890
|
<key>SoftResourceLimits</key><dict>
|
|
37096
36891
|
<key>NumberOfFiles</key><integer>65536</integer>
|
|
37097
36892
|
</dict>
|
|
37098
|
-
<key>StandardOutPath</key><string>${
|
|
37099
|
-
<key>StandardErrorPath</key><string>${
|
|
36893
|
+
<key>StandardOutPath</key><string>${join6(homedir7(), ".paigy", "host.log")}</string>
|
|
36894
|
+
<key>StandardErrorPath</key><string>${join6(homedir7(), ".paigy", "host.log")}</string>
|
|
37100
36895
|
</dict></plist>
|
|
37101
36896
|
`;
|
|
37102
|
-
const dir =
|
|
36897
|
+
const dir = join6(homedir7(), "Library", "LaunchAgents");
|
|
37103
36898
|
mkdirSync3(dir, { recursive: true });
|
|
37104
|
-
const path =
|
|
36899
|
+
const path = join6(dir, `${SERVICE_LABEL}.plist`);
|
|
37105
36900
|
writeFileSync4(path, plist);
|
|
37106
36901
|
execSync(`launchctl unload ${path} 2>/dev/null; launchctl load ${path}`, { shell: "/bin/sh" });
|
|
37107
36902
|
console.log(`\u2713 host installed as a login service (${path}) \u2014 logs at ~/.paigy/host.log`);
|
|
@@ -37245,10 +37040,11 @@ async function main() {
|
|
|
37245
37040
|
void main();
|
|
37246
37041
|
async function credentialWorks(token) {
|
|
37247
37042
|
try {
|
|
37248
|
-
const res = await fetch(`${process.env.PAIGY_API_URL ?? "https://paigy.ai"}/api/
|
|
37043
|
+
const res = await fetch(`${process.env.PAIGY_API_URL ?? "https://paigy.ai"}/api/presence`, {
|
|
37044
|
+
method: "POST",
|
|
37249
37045
|
headers: { authorization: `Bearer ${token}` }
|
|
37250
37046
|
});
|
|
37251
|
-
return res.
|
|
37047
|
+
return res.status !== 401 && res.status !== 403;
|
|
37252
37048
|
} catch {
|
|
37253
37049
|
return true;
|
|
37254
37050
|
}
|