@paigy/harness 0.3.8 → 0.3.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +62 -333
- package/dist/main.js +149 -449
- package/package.json +1 -1
package/dist/main.js
CHANGED
|
@@ -12225,7 +12225,8 @@ var UpdateGoalSchema = external_exports.object({
|
|
|
12225
12225
|
children: external_exports.array(external_exports.object({ outcome: external_exports.string().trim().min(1).max(1e4), ownerParticipant: external_exports.string().trim().min(1), gate: external_exports.enum(["start", "finish"]).optional() }).strict()).optional(),
|
|
12226
12226
|
state: external_exports.enum(["active", "done", "cancelled"]).optional(),
|
|
12227
12227
|
progress: external_exports.string().trim().min(1).max(1e4).optional(),
|
|
12228
|
-
reviewed: external_exports.literal(true).optional()
|
|
12228
|
+
reviewed: external_exports.literal(true).optional(),
|
|
12229
|
+
dueAt: external_exports.string().datetime({ offset: true }).nullable().optional()
|
|
12229
12230
|
}).strict().refine((v) => Object.keys(v).length > 0),
|
|
12230
12231
|
reason: external_exports.string().trim().min(1).max(2e3),
|
|
12231
12232
|
operationId: external_exports.string().uuid().optional()
|
|
@@ -12234,9 +12235,9 @@ var UpdateGoalToolSchema = UpdateGoalSchema.omit({ operationId: true }).extend({
|
|
|
12234
12235
|
var ClaimGoalSchema = external_exports.object({ goalId: external_exports.string().uuid().optional() }).strict();
|
|
12235
12236
|
var GetGoalSchema = external_exports.object({ goalId: external_exports.string().uuid() }).strict();
|
|
12236
12237
|
var 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.";
|
|
12237
|
-
var 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.";
|
|
12238
|
+
var 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. 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. Returns the new revision and a prose summary.";
|
|
12238
12239
|
var 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.";
|
|
12239
|
-
var 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
|
|
12240
|
+
var 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.";
|
|
12240
12241
|
var CheckRepliesSchema = external_exports.object({}).strict();
|
|
12241
12242
|
var GetThreadSchema = external_exports.object({
|
|
12242
12243
|
parentId: external_exports.string().describe("The Thread to read \u2014 the threadId a Delivery returned, or the parentId of a search hit.")
|
|
@@ -12670,67 +12671,6 @@ var AwaitItemSchema = external_exports.discriminatedUnion("type", [
|
|
|
12670
12671
|
inFlight: external_exports.boolean().optional()
|
|
12671
12672
|
})
|
|
12672
12673
|
]);
|
|
12673
|
-
var CallbackTriggerSchema = external_exports.enum(["on_done", "on_blocked", "scheduled"]);
|
|
12674
|
-
var NotifyResponseSchema = external_exports.object({
|
|
12675
|
-
notificationId: external_exports.string(),
|
|
12676
|
-
workId: external_exports.string().uuid().optional(),
|
|
12677
|
-
decisionId: external_exports.string().uuid().optional(),
|
|
12678
|
-
status: NotifyStatusSchema,
|
|
12679
|
-
createdAt: external_exports.string().datetime(),
|
|
12680
|
-
answer: UserAnswerSchema.optional(),
|
|
12681
|
-
answeredAt: external_exports.string().datetime().optional(),
|
|
12682
|
-
/** Ride-alongs for THIS agent — pending work it should pick up when it's done with
|
|
12683
|
-
* what it came for. Present on any reply, because an unwakeable agent's only
|
|
12684
|
-
* reliable moment is one it initiated. Absent/empty = nothing owed. */
|
|
12685
|
-
also: external_exports.array(RideAlongSchema).optional()
|
|
12686
|
-
});
|
|
12687
|
-
var NotifyPlanUnitSchema = external_exports.object({
|
|
12688
|
-
notificationId: external_exports.string(),
|
|
12689
|
-
/** The unit's own heading, so the agent can tell which of its paragraphs this became. */
|
|
12690
|
-
title: external_exports.string(),
|
|
12691
|
-
/** How loudly this unit was arbitrated to arrive — per unit, which is the point of units. */
|
|
12692
|
-
level: NotifyLevelSchema,
|
|
12693
|
-
/** Answered from something the user already decided: nobody is interrupted, and a trail card
|
|
12694
|
-
* says so. The agent should not wait on this one. */
|
|
12695
|
-
settled: external_exports.literal(true).optional(),
|
|
12696
|
-
/** What this unit would need to be answerable and does not carry (#894). A PROPOSAL to the
|
|
12697
|
-
* agent — nothing here changed the ask, and ignoring it costs nothing. */
|
|
12698
|
-
needs: external_exports.array(external_exports.enum(["options", "visuals"])).optional(),
|
|
12699
|
-
/** The SHAPE the broker would give this unit, for the agent to ratify (#886/#894). The
|
|
12700
|
-
* split layer reads prose and can see that a paragraph is a yes/no or a pick-one — but a
|
|
12701
|
-
* broker that DECIDES that destroys the only fact separating a statement from a real ask
|
|
12702
|
-
* (#731), so it is offered, never applied: the unit is stored `text` until the agent
|
|
12703
|
-
* confirms the shape (POST /notify/:id/confirm). Ignoring it costs nothing. */
|
|
12704
|
-
proposal: external_exports.object({
|
|
12705
|
-
select: SelectShapeSchema,
|
|
12706
|
-
options: external_exports.array(external_exports.object({ label: external_exports.string().min(1) })).optional()
|
|
12707
|
-
}).optional(),
|
|
12708
|
-
/** What the broker READ this unit as wanting from the human (#952 layer 2): a `decision`
|
|
12709
|
-
* between alternatives, an `approval` the agent is blocked on, or `knowledge` it just
|
|
12710
|
-
* needs to know. Reported so the agent can correct a misread the same way it ratifies a
|
|
12711
|
-
* shape — the read RAISES (a decision always asks) and never silences a question the
|
|
12712
|
-
* agent declared (#731, #923). */
|
|
12713
|
-
wants: external_exports.enum(["decision", "approval", "knowledge"]).optional()
|
|
12714
|
-
});
|
|
12715
|
-
var NotifyPlanSchema = external_exports.object({
|
|
12716
|
-
units: external_exports.array(NotifyPlanUnitSchema),
|
|
12717
|
-
/** Which unit is this arrival's ONE interruption (units-design.md D23). Absent means nobody
|
|
12718
|
-
* was interrupted — every unit was either settled or quiet enough to sit in the inbox. */
|
|
12719
|
-
speaks: external_exports.string().optional()
|
|
12720
|
-
});
|
|
12721
|
-
var UserResponseSchema = external_exports.object({
|
|
12722
|
-
requestId: external_exports.string(),
|
|
12723
|
-
answer: UserAnswerSchema,
|
|
12724
|
-
answeredAt: external_exports.string().datetime(),
|
|
12725
|
-
transcript: external_exports.string().optional(),
|
|
12726
|
-
/** E2EE: the sealed answer (opaque envelope + plaintext `ignored` hint) when the item was
|
|
12727
|
-
* E2EE-sealed. Present → the server persists it opaquely and branches status on `ignored`;
|
|
12728
|
-
* the plaintext `answer` is a placeholder (`{ kind: "ignored" }`) the server ignores for a
|
|
12729
|
-
* sealed row. Absent = today's plaintext answer, unchanged. */
|
|
12730
|
-
sealed: external_exports.lazy(() => SealedAnswerSchema).optional(),
|
|
12731
|
-
/** Coverage report (#396): which of the ask's declared `points` were addressed. */
|
|
12732
|
-
covered: external_exports.array(external_exports.string()).optional()
|
|
12733
|
-
});
|
|
12734
12674
|
var VoiceKeySchema = external_exports.enum(["rachel", "george", "jessica", "brian", "lily"]);
|
|
12735
12675
|
var AgendaTurnSchema = external_exports.object({
|
|
12736
12676
|
/** THE TURN'S IDENTITY (the first-sentence stream, 2026-09-09): the brain call that wrote
|
|
@@ -12914,10 +12854,6 @@ var InboxItemSchema = external_exports.object({
|
|
|
12914
12854
|
goalState: external_exports.string().optional()
|
|
12915
12855
|
}).optional()
|
|
12916
12856
|
});
|
|
12917
|
-
var SnoozeRequestSchema = external_exports.object({
|
|
12918
|
-
requestId: external_exports.string(),
|
|
12919
|
-
until: external_exports.string().datetime()
|
|
12920
|
-
});
|
|
12921
12857
|
var APNS_TOKEN_RE = /^[0-9a-fA-F]{64}$/;
|
|
12922
12858
|
var PushTokenSchema = external_exports.object({
|
|
12923
12859
|
voipToken: external_exports.string().min(1).optional(),
|
|
@@ -13138,19 +13074,6 @@ var MoveSchema = external_exports.object({
|
|
|
13138
13074
|
* distilled from a clarify ruling (those carry no agent) or one whose source rows are gone. */
|
|
13139
13075
|
learnedFrom: external_exports.object({ id: external_exports.string(), name: external_exports.string() }).nullable()
|
|
13140
13076
|
});
|
|
13141
|
-
var CreateRequestSchema = external_exports.object({
|
|
13142
|
-
/** The connection (token id) to send to, from GET /api/tokens. */
|
|
13143
|
-
tokenId: external_exports.string(),
|
|
13144
|
-
/** The user's message to the agent. */
|
|
13145
|
-
text: external_exports.string().min(1),
|
|
13146
|
-
/** Land the request on an existing conversation thread (History → "Continue")
|
|
13147
|
-
* instead of minting a fresh one. Must belong to the requesting user. */
|
|
13148
|
-
parentId: external_exports.string().optional(),
|
|
13149
|
-
/** Point the agent at a past conversation (possibly with a different agent) as
|
|
13150
|
-
* starting context (History → "New session from this"). A reference, not a copy —
|
|
13151
|
-
* the agent reads it via get_thread. Must belong to the requesting user. */
|
|
13152
|
-
contextParentId: external_exports.string().optional()
|
|
13153
|
-
});
|
|
13154
13077
|
var QueueQuestionSchema = external_exports.object({
|
|
13155
13078
|
/** The decision need's id — what an answer is accepted against. */
|
|
13156
13079
|
id: external_exports.string(),
|
|
@@ -13242,38 +13165,6 @@ var NoteSchema = external_exports.object({
|
|
|
13242
13165
|
lastRideAt: external_exports.string().nullable().default(null),
|
|
13243
13166
|
createdAt: external_exports.string()
|
|
13244
13167
|
});
|
|
13245
|
-
var CreateNoteSchema = external_exports.object({
|
|
13246
|
-
/** The intent, in the user's own words. Stored verbatim; the broker only titles it. */
|
|
13247
|
-
text: external_exports.string().min(1).max(4e3),
|
|
13248
|
-
/** Capture it as a REMINDER — a note assigned to the user themselves, which rides
|
|
13249
|
-
* their next call instead of being handed to an agent. Everything else about the
|
|
13250
|
-
* note is identical; this is the one parameter that separates the two. */
|
|
13251
|
-
forMe: external_exports.boolean().optional(),
|
|
13252
|
-
/** The not-before, when the user already said one. Absent = the very next call. */
|
|
13253
|
-
dueAt: external_exports.string().datetime().optional(),
|
|
13254
|
-
repeat: NoteRepeatSchema.optional()
|
|
13255
|
-
});
|
|
13256
|
-
var RecordDecisionSchema = external_exports.object({
|
|
13257
|
-
/** An open decision (from /clarify) to answer. */
|
|
13258
|
-
decisionId: external_exports.string().optional(),
|
|
13259
|
-
/** For an ad-hoc decision: what was ambiguous. Required without `decisionId`. */
|
|
13260
|
-
question: external_exports.string().min(1).max(500).optional(),
|
|
13261
|
-
/** The ruling. */
|
|
13262
|
-
answer: external_exports.string().min(1).max(2e3)
|
|
13263
|
-
}).refine((d) => d.decisionId || d.question, { message: "decisionId or question required" });
|
|
13264
|
-
var AssignNoteSchema = external_exports.object({
|
|
13265
|
-
/** An EXISTING agent: token id or nickname. Omit when spawning fresh. */
|
|
13266
|
-
target: external_exports.string().min(1).optional(),
|
|
13267
|
-
/** Spawn a NEW session for this note (companion.md §2.2): the assignee doesn't
|
|
13268
|
-
* exist yet — mint it on a live desktop that advertises the harness+workspace,
|
|
13269
|
-
* named after the note. The brief arrives as its opening request. */
|
|
13270
|
-
spawn: external_exports.object({
|
|
13271
|
-
hostTokenId: external_exports.string().uuid(),
|
|
13272
|
-
harness: external_exports.string().min(1),
|
|
13273
|
-
workspace: external_exports.string().min(1)
|
|
13274
|
-
}).optional()
|
|
13275
|
-
}).refine((a) => !!a.target !== !!a.spawn, { message: "exactly one of target or spawn" });
|
|
13276
|
-
var TriageVerdictSchema = external_exports.enum(["keep", "stale", "close", "assign"]);
|
|
13277
13168
|
var TriageItemSchema = external_exports.object({
|
|
13278
13169
|
noteId: external_exports.string(),
|
|
13279
13170
|
/** The note's headline at run time. */
|
|
@@ -13409,20 +13300,6 @@ var PairingRevealSchema = external_exports.object({
|
|
|
13409
13300
|
ed25519: external_exports.string(),
|
|
13410
13301
|
nonce: external_exports.string()
|
|
13411
13302
|
});
|
|
13412
|
-
var DeviceCodeRequestSchema = external_exports.object({
|
|
13413
|
-
/** The agent's suggested name for the pairing — the human sees it pre-filled at
|
|
13414
|
-
* approval and can override. Optional; blank → a default silly name server-side. */
|
|
13415
|
-
suggestedName: external_exports.string().optional(),
|
|
13416
|
-
/** Legacy alias for suggestedName (older MCPs sent `agent`). Accepted for
|
|
13417
|
-
* back-compat; `suggestedName` wins when both are present. ponytail: drop once no
|
|
13418
|
-
* pre-`name` MCP is in the wild. */
|
|
13419
|
-
agent: external_exports.union([external_exports.string(), external_exports.object({ name: external_exports.string().optional() })]).optional(),
|
|
13420
|
-
device: external_exports.string().optional(),
|
|
13421
|
-
proto: external_exports.string().optional(),
|
|
13422
|
-
// compiled-in tag, e.g. "paigy-pair-v2|sas=24"
|
|
13423
|
-
commitment: external_exports.string().optional()
|
|
13424
|
-
// agent's Ca
|
|
13425
|
-
});
|
|
13426
13303
|
var DeviceCodeSchema = external_exports.object({
|
|
13427
13304
|
device_code: external_exports.string(),
|
|
13428
13305
|
user_code: external_exports.string(),
|
|
@@ -13456,11 +13333,6 @@ var DeviceInfoSchema = external_exports.object({
|
|
|
13456
13333
|
phone_reveal: PairingRevealSchema.nullable().optional(),
|
|
13457
13334
|
uik_pub: external_exports.string().nullable().optional()
|
|
13458
13335
|
});
|
|
13459
|
-
var DeviceTokenRequestSchema = external_exports.object({
|
|
13460
|
-
device_code: external_exports.string(),
|
|
13461
|
-
reveal: PairingRevealSchema.optional()
|
|
13462
|
-
// agent's reveal {x25519, ed25519, nonce}
|
|
13463
|
-
});
|
|
13464
13336
|
var DeviceTokenSchema = external_exports.object({
|
|
13465
13337
|
access_token: external_exports.string(),
|
|
13466
13338
|
/** The pairing's single name (user-typed at approval, the agent's suggestion, or
|
|
@@ -13482,14 +13354,6 @@ var DeviceTokenSchema = external_exports.object({
|
|
|
13482
13354
|
// present once the phone reveals
|
|
13483
13355
|
uik_pub: external_exports.string().nullable().optional()
|
|
13484
13356
|
});
|
|
13485
|
-
var DeviceCommitRequestSchema = external_exports.object({
|
|
13486
|
-
code: external_exports.string(),
|
|
13487
|
-
commitment: external_exports.string()
|
|
13488
|
-
// Cb
|
|
13489
|
-
});
|
|
13490
|
-
var DevicePeerCommitSchema = external_exports.object({
|
|
13491
|
-
commitment: external_exports.string().nullable()
|
|
13492
|
-
});
|
|
13493
13357
|
var SupportRequestSchema = external_exports.object({
|
|
13494
13358
|
email: external_exports.string().email().max(320),
|
|
13495
13359
|
message: external_exports.string().trim().min(1).max(5e3),
|
|
@@ -13509,15 +13373,6 @@ var NotificationFeedbackKindSchema = external_exports.enum([
|
|
|
13509
13373
|
"other"
|
|
13510
13374
|
// anything else — the note carries it.
|
|
13511
13375
|
]);
|
|
13512
|
-
var NotificationFeedbackSchema = external_exports.object({
|
|
13513
|
-
notificationId: external_exports.string(),
|
|
13514
|
-
kind: NotificationFeedbackKindSchema,
|
|
13515
|
-
/** Optional free-text elaboration for a preset; required (non-empty) for 'other'. */
|
|
13516
|
-
note: external_exports.string().trim().max(2e3).optional()
|
|
13517
|
-
}).superRefine((r, ctx) => {
|
|
13518
|
-
if (r.kind === "other" && !r.note)
|
|
13519
|
-
ctx.addIssue({ code: external_exports.ZodIssueCode.custom, path: ["note"], message: "note is required for 'other' feedback" });
|
|
13520
|
-
});
|
|
13521
13376
|
var FeedbackResolutionSchema = external_exports.enum(["broker_fixed", "sent_to_agent"]);
|
|
13522
13377
|
var FeedbackOutcomeSchema = external_exports.object({
|
|
13523
13378
|
resolution: FeedbackResolutionSchema,
|
|
@@ -13927,6 +13782,146 @@ async function subscribeWake(onNudge, opts = {}) {
|
|
|
13927
13782
|
};
|
|
13928
13783
|
}
|
|
13929
13784
|
|
|
13785
|
+
// src/main.ts
|
|
13786
|
+
var import_qrcode = __toESM(require_lib(), 1);
|
|
13787
|
+
import { homedir as homedir7, hostname } from "os";
|
|
13788
|
+
|
|
13789
|
+
// src/harness/catalog.ts
|
|
13790
|
+
import { spawnSync } from "child_process";
|
|
13791
|
+
import { existsSync as existsSync2 } from "fs";
|
|
13792
|
+
import { homedir as homedir2 } from "os";
|
|
13793
|
+
import { delimiter, dirname, join as join2 } from "path";
|
|
13794
|
+
var CATALOG = [
|
|
13795
|
+
{
|
|
13796
|
+
name: "claude",
|
|
13797
|
+
label: "Claude Code",
|
|
13798
|
+
cli: "claude",
|
|
13799
|
+
adapter: "claude-agent-acp",
|
|
13800
|
+
authProbe: ["claude", "auth", "status"],
|
|
13801
|
+
loginHint: "Run `claude` once in a terminal and sign in.",
|
|
13802
|
+
installCli: "curl -fsSL https://claude.ai/install.sh | bash",
|
|
13803
|
+
installAdapter: "npm install -g @agentclientprotocol/claude-agent-acp"
|
|
13804
|
+
},
|
|
13805
|
+
{
|
|
13806
|
+
name: "codex",
|
|
13807
|
+
label: "Codex",
|
|
13808
|
+
cli: "codex",
|
|
13809
|
+
adapter: "codex-acp",
|
|
13810
|
+
authProbe: ["codex", "login", "status"],
|
|
13811
|
+
loginHint: "Run `codex login` to authenticate.",
|
|
13812
|
+
installCli: "curl -fsSL https://chatgpt.com/codex/install.sh | sh",
|
|
13813
|
+
installAdapter: "npm install -g @agentclientprotocol/codex-acp"
|
|
13814
|
+
},
|
|
13815
|
+
{
|
|
13816
|
+
name: "agy",
|
|
13817
|
+
label: "Antigravity",
|
|
13818
|
+
cli: "agy",
|
|
13819
|
+
authProbe: ["agy", "help"],
|
|
13820
|
+
loginHint: "Install and set up Antigravity (`agy`).",
|
|
13821
|
+
installCli: "curl -fsSL https://antigravity.dev/install.sh | bash"
|
|
13822
|
+
}
|
|
13823
|
+
];
|
|
13824
|
+
function probeDirs(home = homedir2()) {
|
|
13825
|
+
return [
|
|
13826
|
+
dirname(process.execPath),
|
|
13827
|
+
join2(home, ".local", "bin"),
|
|
13828
|
+
"/usr/local/bin",
|
|
13829
|
+
"/opt/homebrew/bin",
|
|
13830
|
+
join2(home, ".npm-global", "bin")
|
|
13831
|
+
];
|
|
13832
|
+
}
|
|
13833
|
+
function which(bin) {
|
|
13834
|
+
const hit = spawnSync("which", [bin], { encoding: "utf8" });
|
|
13835
|
+
const fromPath = hit.status === 0 ? hit.stdout.trim() : "";
|
|
13836
|
+
if (fromPath) return fromPath;
|
|
13837
|
+
for (const dir of probeDirs()) {
|
|
13838
|
+
const candidate = join2(dir, bin);
|
|
13839
|
+
if (existsSync2(candidate)) return candidate;
|
|
13840
|
+
}
|
|
13841
|
+
return null;
|
|
13842
|
+
}
|
|
13843
|
+
function runProbe(argv) {
|
|
13844
|
+
const [cmd, ...args] = argv;
|
|
13845
|
+
if (!cmd) return false;
|
|
13846
|
+
const resolved = which(cmd);
|
|
13847
|
+
if (!resolved) return false;
|
|
13848
|
+
return spawnSync(resolved, args, {
|
|
13849
|
+
timeout: 1e4,
|
|
13850
|
+
stdio: "ignore",
|
|
13851
|
+
env: { ...process.env, PATH: [process.env.PATH, ...probeDirs()].filter(Boolean).join(delimiter) }
|
|
13852
|
+
}).status === 0;
|
|
13853
|
+
}
|
|
13854
|
+
function detect(entry, deps = {}) {
|
|
13855
|
+
const find = deps.which ?? which;
|
|
13856
|
+
const probe = deps.probe ?? runProbe;
|
|
13857
|
+
const base = { name: entry.name, label: entry.label };
|
|
13858
|
+
const cliPath = find(entry.cli);
|
|
13859
|
+
if (!cliPath) return { ...base, status: "missing", hint: `${entry.label} is not installed.`, install: entry.installCli };
|
|
13860
|
+
const adapterPath = entry.adapter ? find(entry.adapter) : null;
|
|
13861
|
+
if (entry.adapter && !adapterPath) {
|
|
13862
|
+
return {
|
|
13863
|
+
...base,
|
|
13864
|
+
status: "adapter-missing",
|
|
13865
|
+
hint: `${entry.label} is installed, but its ACP adapter (${entry.adapter}) is not.`,
|
|
13866
|
+
...entry.installAdapter ? { install: entry.installAdapter } : {}
|
|
13867
|
+
};
|
|
13868
|
+
}
|
|
13869
|
+
const bin = adapterPath ?? cliPath;
|
|
13870
|
+
if (!probe(entry.authProbe)) return { ...base, status: "login", bin, hint: entry.loginHint };
|
|
13871
|
+
return { ...base, status: "ready", bin };
|
|
13872
|
+
}
|
|
13873
|
+
function detectAll(deps = {}) {
|
|
13874
|
+
return CATALOG.map((entry) => detect(entry, deps));
|
|
13875
|
+
}
|
|
13876
|
+
|
|
13877
|
+
// src/host.ts
|
|
13878
|
+
import { readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "fs";
|
|
13879
|
+
import { homedir as homedir5 } from "os";
|
|
13880
|
+
import { join as join5 } from "path";
|
|
13881
|
+
|
|
13882
|
+
// src/workspaces.ts
|
|
13883
|
+
import { existsSync as existsSync3, mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
13884
|
+
import { dirname as dirname2, join as join3, resolve } from "path";
|
|
13885
|
+
import { homedir as homedir3 } from "os";
|
|
13886
|
+
function workspacesFile() {
|
|
13887
|
+
return join3(homedir3(), ".paigy", "workspaces.json");
|
|
13888
|
+
}
|
|
13889
|
+
function listWorkspaces(deps) {
|
|
13890
|
+
try {
|
|
13891
|
+
const parsed = JSON.parse(readFileSync2(deps.file, "utf8"));
|
|
13892
|
+
return Array.isArray(parsed) ? parsed.filter((w) => typeof w === "string") : [];
|
|
13893
|
+
} catch {
|
|
13894
|
+
return [];
|
|
13895
|
+
}
|
|
13896
|
+
}
|
|
13897
|
+
function addWorkspace(dir, deps) {
|
|
13898
|
+
const next = resolve(dir.replace(/^~(?=$|\/)/, homedir3()));
|
|
13899
|
+
const all = listWorkspaces(deps);
|
|
13900
|
+
if (!all.includes(next)) {
|
|
13901
|
+
all.push(next);
|
|
13902
|
+
mkdirSync2(dirname2(deps.file), { recursive: true });
|
|
13903
|
+
writeFileSync2(deps.file, JSON.stringify(all, null, 2));
|
|
13904
|
+
}
|
|
13905
|
+
return all;
|
|
13906
|
+
}
|
|
13907
|
+
function removeWorkspace(dir, deps) {
|
|
13908
|
+
const all = listWorkspaces(deps).filter((w) => w !== dir);
|
|
13909
|
+
mkdirSync2(dirname2(deps.file), { recursive: true });
|
|
13910
|
+
writeFileSync2(deps.file, JSON.stringify(all, null, 2));
|
|
13911
|
+
return all;
|
|
13912
|
+
}
|
|
13913
|
+
function allowed(cwd, deps) {
|
|
13914
|
+
const target = resolve(cwd.replace(/^~(?=$|\/)/, homedir3()));
|
|
13915
|
+
return listWorkspaces(deps).some((w) => target === w || target.startsWith(`${w}/`));
|
|
13916
|
+
}
|
|
13917
|
+
function resolveWakeDir(pinned, deps) {
|
|
13918
|
+
if (pinned && allowed(pinned, deps)) {
|
|
13919
|
+
const dir = resolve(pinned.replace(/^~(?=$|\/)/, homedir3()));
|
|
13920
|
+
if ((deps.exists ?? existsSync3)(dir)) return dir;
|
|
13921
|
+
}
|
|
13922
|
+
return listWorkspaces(deps)[0];
|
|
13923
|
+
}
|
|
13924
|
+
|
|
13930
13925
|
// ../../node_modules/.pnpm/zod-to-json-schema@3.25.2_zod@3.25.76/node_modules/zod-to-json-schema/dist/esm/Options.js
|
|
13931
13926
|
var ignoreOverride2 = /* @__PURE__ */ Symbol("Let zodToJsonSchema decide on which parser to use");
|
|
13932
13927
|
var defaultOptions2 = {
|
|
@@ -15301,7 +15296,8 @@ var UpdateGoalSchema2 = external_exports.object({
|
|
|
15301
15296
|
children: external_exports.array(external_exports.object({ outcome: external_exports.string().trim().min(1).max(1e4), ownerParticipant: external_exports.string().trim().min(1), gate: external_exports.enum(["start", "finish"]).optional() }).strict()).optional(),
|
|
15302
15297
|
state: external_exports.enum(["active", "done", "cancelled"]).optional(),
|
|
15303
15298
|
progress: external_exports.string().trim().min(1).max(1e4).optional(),
|
|
15304
|
-
reviewed: external_exports.literal(true).optional()
|
|
15299
|
+
reviewed: external_exports.literal(true).optional(),
|
|
15300
|
+
dueAt: external_exports.string().datetime({ offset: true }).nullable().optional()
|
|
15305
15301
|
}).strict().refine((v) => Object.keys(v).length > 0),
|
|
15306
15302
|
reason: external_exports.string().trim().min(1).max(2e3),
|
|
15307
15303
|
operationId: external_exports.string().uuid().optional()
|
|
@@ -15310,9 +15306,9 @@ var UpdateGoalToolSchema2 = UpdateGoalSchema2.omit({ operationId: true }).extend
|
|
|
15310
15306
|
var ClaimGoalSchema2 = external_exports.object({ goalId: external_exports.string().uuid().optional() }).strict();
|
|
15311
15307
|
var GetGoalSchema2 = external_exports.object({ goalId: external_exports.string().uuid() }).strict();
|
|
15312
15308
|
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.";
|
|
15313
|
-
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.";
|
|
15309
|
+
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. 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. Returns the new revision and a prose summary.";
|
|
15314
15310
|
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.";
|
|
15315
|
-
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
|
|
15311
|
+
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.";
|
|
15316
15312
|
var CheckRepliesSchema2 = external_exports.object({}).strict();
|
|
15317
15313
|
var GetThreadSchema2 = external_exports.object({
|
|
15318
15314
|
parentId: external_exports.string().describe("The Thread to read \u2014 the threadId a Delivery returned, or the parentId of a search hit.")
|
|
@@ -15706,67 +15702,6 @@ var AwaitItemSchema2 = external_exports.discriminatedUnion("type", [
|
|
|
15706
15702
|
inFlight: external_exports.boolean().optional()
|
|
15707
15703
|
})
|
|
15708
15704
|
]);
|
|
15709
|
-
var CallbackTriggerSchema2 = external_exports.enum(["on_done", "on_blocked", "scheduled"]);
|
|
15710
|
-
var NotifyResponseSchema2 = external_exports.object({
|
|
15711
|
-
notificationId: external_exports.string(),
|
|
15712
|
-
workId: external_exports.string().uuid().optional(),
|
|
15713
|
-
decisionId: external_exports.string().uuid().optional(),
|
|
15714
|
-
status: NotifyStatusSchema2,
|
|
15715
|
-
createdAt: external_exports.string().datetime(),
|
|
15716
|
-
answer: UserAnswerSchema2.optional(),
|
|
15717
|
-
answeredAt: external_exports.string().datetime().optional(),
|
|
15718
|
-
/** Ride-alongs for THIS agent — pending work it should pick up when it's done with
|
|
15719
|
-
* what it came for. Present on any reply, because an unwakeable agent's only
|
|
15720
|
-
* reliable moment is one it initiated. Absent/empty = nothing owed. */
|
|
15721
|
-
also: external_exports.array(RideAlongSchema2).optional()
|
|
15722
|
-
});
|
|
15723
|
-
var NotifyPlanUnitSchema2 = external_exports.object({
|
|
15724
|
-
notificationId: external_exports.string(),
|
|
15725
|
-
/** The unit's own heading, so the agent can tell which of its paragraphs this became. */
|
|
15726
|
-
title: external_exports.string(),
|
|
15727
|
-
/** How loudly this unit was arbitrated to arrive — per unit, which is the point of units. */
|
|
15728
|
-
level: NotifyLevelSchema2,
|
|
15729
|
-
/** Answered from something the user already decided: nobody is interrupted, and a trail card
|
|
15730
|
-
* says so. The agent should not wait on this one. */
|
|
15731
|
-
settled: external_exports.literal(true).optional(),
|
|
15732
|
-
/** What this unit would need to be answerable and does not carry (#894). A PROPOSAL to the
|
|
15733
|
-
* agent — nothing here changed the ask, and ignoring it costs nothing. */
|
|
15734
|
-
needs: external_exports.array(external_exports.enum(["options", "visuals"])).optional(),
|
|
15735
|
-
/** The SHAPE the broker would give this unit, for the agent to ratify (#886/#894). The
|
|
15736
|
-
* split layer reads prose and can see that a paragraph is a yes/no or a pick-one — but a
|
|
15737
|
-
* broker that DECIDES that destroys the only fact separating a statement from a real ask
|
|
15738
|
-
* (#731), so it is offered, never applied: the unit is stored `text` until the agent
|
|
15739
|
-
* confirms the shape (POST /notify/:id/confirm). Ignoring it costs nothing. */
|
|
15740
|
-
proposal: external_exports.object({
|
|
15741
|
-
select: SelectShapeSchema2,
|
|
15742
|
-
options: external_exports.array(external_exports.object({ label: external_exports.string().min(1) })).optional()
|
|
15743
|
-
}).optional(),
|
|
15744
|
-
/** What the broker READ this unit as wanting from the human (#952 layer 2): a `decision`
|
|
15745
|
-
* between alternatives, an `approval` the agent is blocked on, or `knowledge` it just
|
|
15746
|
-
* needs to know. Reported so the agent can correct a misread the same way it ratifies a
|
|
15747
|
-
* shape — the read RAISES (a decision always asks) and never silences a question the
|
|
15748
|
-
* agent declared (#731, #923). */
|
|
15749
|
-
wants: external_exports.enum(["decision", "approval", "knowledge"]).optional()
|
|
15750
|
-
});
|
|
15751
|
-
var NotifyPlanSchema2 = external_exports.object({
|
|
15752
|
-
units: external_exports.array(NotifyPlanUnitSchema2),
|
|
15753
|
-
/** Which unit is this arrival's ONE interruption (units-design.md D23). Absent means nobody
|
|
15754
|
-
* was interrupted — every unit was either settled or quiet enough to sit in the inbox. */
|
|
15755
|
-
speaks: external_exports.string().optional()
|
|
15756
|
-
});
|
|
15757
|
-
var UserResponseSchema2 = external_exports.object({
|
|
15758
|
-
requestId: external_exports.string(),
|
|
15759
|
-
answer: UserAnswerSchema2,
|
|
15760
|
-
answeredAt: external_exports.string().datetime(),
|
|
15761
|
-
transcript: external_exports.string().optional(),
|
|
15762
|
-
/** E2EE: the sealed answer (opaque envelope + plaintext `ignored` hint) when the item was
|
|
15763
|
-
* E2EE-sealed. Present → the server persists it opaquely and branches status on `ignored`;
|
|
15764
|
-
* the plaintext `answer` is a placeholder (`{ kind: "ignored" }`) the server ignores for a
|
|
15765
|
-
* sealed row. Absent = today's plaintext answer, unchanged. */
|
|
15766
|
-
sealed: external_exports.lazy(() => SealedAnswerSchema2).optional(),
|
|
15767
|
-
/** Coverage report (#396): which of the ask's declared `points` were addressed. */
|
|
15768
|
-
covered: external_exports.array(external_exports.string()).optional()
|
|
15769
|
-
});
|
|
15770
15705
|
var VoiceKeySchema2 = external_exports.enum(["rachel", "george", "jessica", "brian", "lily"]);
|
|
15771
15706
|
var AgendaTurnSchema2 = external_exports.object({
|
|
15772
15707
|
/** THE TURN'S IDENTITY (the first-sentence stream, 2026-09-09): the brain call that wrote
|
|
@@ -15950,10 +15885,6 @@ var InboxItemSchema2 = external_exports.object({
|
|
|
15950
15885
|
goalState: external_exports.string().optional()
|
|
15951
15886
|
}).optional()
|
|
15952
15887
|
});
|
|
15953
|
-
var SnoozeRequestSchema2 = external_exports.object({
|
|
15954
|
-
requestId: external_exports.string(),
|
|
15955
|
-
until: external_exports.string().datetime()
|
|
15956
|
-
});
|
|
15957
15888
|
var APNS_TOKEN_RE2 = /^[0-9a-fA-F]{64}$/;
|
|
15958
15889
|
var PushTokenSchema2 = external_exports.object({
|
|
15959
15890
|
voipToken: external_exports.string().min(1).optional(),
|
|
@@ -16174,19 +16105,6 @@ var MoveSchema2 = external_exports.object({
|
|
|
16174
16105
|
* distilled from a clarify ruling (those carry no agent) or one whose source rows are gone. */
|
|
16175
16106
|
learnedFrom: external_exports.object({ id: external_exports.string(), name: external_exports.string() }).nullable()
|
|
16176
16107
|
});
|
|
16177
|
-
var CreateRequestSchema2 = external_exports.object({
|
|
16178
|
-
/** The connection (token id) to send to, from GET /api/tokens. */
|
|
16179
|
-
tokenId: external_exports.string(),
|
|
16180
|
-
/** The user's message to the agent. */
|
|
16181
|
-
text: external_exports.string().min(1),
|
|
16182
|
-
/** Land the request on an existing conversation thread (History → "Continue")
|
|
16183
|
-
* instead of minting a fresh one. Must belong to the requesting user. */
|
|
16184
|
-
parentId: external_exports.string().optional(),
|
|
16185
|
-
/** Point the agent at a past conversation (possibly with a different agent) as
|
|
16186
|
-
* starting context (History → "New session from this"). A reference, not a copy —
|
|
16187
|
-
* the agent reads it via get_thread. Must belong to the requesting user. */
|
|
16188
|
-
contextParentId: external_exports.string().optional()
|
|
16189
|
-
});
|
|
16190
16108
|
var QueueQuestionSchema2 = external_exports.object({
|
|
16191
16109
|
/** The decision need's id — what an answer is accepted against. */
|
|
16192
16110
|
id: external_exports.string(),
|
|
@@ -16278,38 +16196,6 @@ var NoteSchema2 = external_exports.object({
|
|
|
16278
16196
|
lastRideAt: external_exports.string().nullable().default(null),
|
|
16279
16197
|
createdAt: external_exports.string()
|
|
16280
16198
|
});
|
|
16281
|
-
var CreateNoteSchema2 = external_exports.object({
|
|
16282
|
-
/** The intent, in the user's own words. Stored verbatim; the broker only titles it. */
|
|
16283
|
-
text: external_exports.string().min(1).max(4e3),
|
|
16284
|
-
/** Capture it as a REMINDER — a note assigned to the user themselves, which rides
|
|
16285
|
-
* their next call instead of being handed to an agent. Everything else about the
|
|
16286
|
-
* note is identical; this is the one parameter that separates the two. */
|
|
16287
|
-
forMe: external_exports.boolean().optional(),
|
|
16288
|
-
/** The not-before, when the user already said one. Absent = the very next call. */
|
|
16289
|
-
dueAt: external_exports.string().datetime().optional(),
|
|
16290
|
-
repeat: NoteRepeatSchema2.optional()
|
|
16291
|
-
});
|
|
16292
|
-
var RecordDecisionSchema2 = external_exports.object({
|
|
16293
|
-
/** An open decision (from /clarify) to answer. */
|
|
16294
|
-
decisionId: external_exports.string().optional(),
|
|
16295
|
-
/** For an ad-hoc decision: what was ambiguous. Required without `decisionId`. */
|
|
16296
|
-
question: external_exports.string().min(1).max(500).optional(),
|
|
16297
|
-
/** The ruling. */
|
|
16298
|
-
answer: external_exports.string().min(1).max(2e3)
|
|
16299
|
-
}).refine((d) => d.decisionId || d.question, { message: "decisionId or question required" });
|
|
16300
|
-
var AssignNoteSchema2 = external_exports.object({
|
|
16301
|
-
/** An EXISTING agent: token id or nickname. Omit when spawning fresh. */
|
|
16302
|
-
target: external_exports.string().min(1).optional(),
|
|
16303
|
-
/** Spawn a NEW session for this note (companion.md §2.2): the assignee doesn't
|
|
16304
|
-
* exist yet — mint it on a live desktop that advertises the harness+workspace,
|
|
16305
|
-
* named after the note. The brief arrives as its opening request. */
|
|
16306
|
-
spawn: external_exports.object({
|
|
16307
|
-
hostTokenId: external_exports.string().uuid(),
|
|
16308
|
-
harness: external_exports.string().min(1),
|
|
16309
|
-
workspace: external_exports.string().min(1)
|
|
16310
|
-
}).optional()
|
|
16311
|
-
}).refine((a) => !!a.target !== !!a.spawn, { message: "exactly one of target or spawn" });
|
|
16312
|
-
var TriageVerdictSchema2 = external_exports.enum(["keep", "stale", "close", "assign"]);
|
|
16313
16199
|
var TriageItemSchema2 = external_exports.object({
|
|
16314
16200
|
noteId: external_exports.string(),
|
|
16315
16201
|
/** The note's headline at run time. */
|
|
@@ -16443,20 +16329,6 @@ var PairingRevealSchema2 = external_exports.object({
|
|
|
16443
16329
|
ed25519: external_exports.string(),
|
|
16444
16330
|
nonce: external_exports.string()
|
|
16445
16331
|
});
|
|
16446
|
-
var DeviceCodeRequestSchema2 = external_exports.object({
|
|
16447
|
-
/** The agent's suggested name for the pairing — the human sees it pre-filled at
|
|
16448
|
-
* approval and can override. Optional; blank → a default silly name server-side. */
|
|
16449
|
-
suggestedName: external_exports.string().optional(),
|
|
16450
|
-
/** Legacy alias for suggestedName (older MCPs sent `agent`). Accepted for
|
|
16451
|
-
* back-compat; `suggestedName` wins when both are present. ponytail: drop once no
|
|
16452
|
-
* pre-`name` MCP is in the wild. */
|
|
16453
|
-
agent: external_exports.union([external_exports.string(), external_exports.object({ name: external_exports.string().optional() })]).optional(),
|
|
16454
|
-
device: external_exports.string().optional(),
|
|
16455
|
-
proto: external_exports.string().optional(),
|
|
16456
|
-
// compiled-in tag, e.g. "paigy-pair-v2|sas=24"
|
|
16457
|
-
commitment: external_exports.string().optional()
|
|
16458
|
-
// agent's Ca
|
|
16459
|
-
});
|
|
16460
16332
|
var DeviceCodeSchema2 = external_exports.object({
|
|
16461
16333
|
device_code: external_exports.string(),
|
|
16462
16334
|
user_code: external_exports.string(),
|
|
@@ -16490,11 +16362,6 @@ var DeviceInfoSchema2 = external_exports.object({
|
|
|
16490
16362
|
phone_reveal: PairingRevealSchema2.nullable().optional(),
|
|
16491
16363
|
uik_pub: external_exports.string().nullable().optional()
|
|
16492
16364
|
});
|
|
16493
|
-
var DeviceTokenRequestSchema2 = external_exports.object({
|
|
16494
|
-
device_code: external_exports.string(),
|
|
16495
|
-
reveal: PairingRevealSchema2.optional()
|
|
16496
|
-
// agent's reveal {x25519, ed25519, nonce}
|
|
16497
|
-
});
|
|
16498
16365
|
var DeviceTokenSchema2 = external_exports.object({
|
|
16499
16366
|
access_token: external_exports.string(),
|
|
16500
16367
|
/** The pairing's single name (user-typed at approval, the agent's suggestion, or
|
|
@@ -16516,14 +16383,6 @@ var DeviceTokenSchema2 = external_exports.object({
|
|
|
16516
16383
|
// present once the phone reveals
|
|
16517
16384
|
uik_pub: external_exports.string().nullable().optional()
|
|
16518
16385
|
});
|
|
16519
|
-
var DeviceCommitRequestSchema2 = external_exports.object({
|
|
16520
|
-
code: external_exports.string(),
|
|
16521
|
-
commitment: external_exports.string()
|
|
16522
|
-
// Cb
|
|
16523
|
-
});
|
|
16524
|
-
var DevicePeerCommitSchema2 = external_exports.object({
|
|
16525
|
-
commitment: external_exports.string().nullable()
|
|
16526
|
-
});
|
|
16527
16386
|
var SupportRequestSchema2 = external_exports.object({
|
|
16528
16387
|
email: external_exports.string().email().max(320),
|
|
16529
16388
|
message: external_exports.string().trim().min(1).max(5e3),
|
|
@@ -16543,15 +16402,6 @@ var NotificationFeedbackKindSchema2 = external_exports.enum([
|
|
|
16543
16402
|
"other"
|
|
16544
16403
|
// anything else — the note carries it.
|
|
16545
16404
|
]);
|
|
16546
|
-
var NotificationFeedbackSchema2 = external_exports.object({
|
|
16547
|
-
notificationId: external_exports.string(),
|
|
16548
|
-
kind: NotificationFeedbackKindSchema2,
|
|
16549
|
-
/** Optional free-text elaboration for a preset; required (non-empty) for 'other'. */
|
|
16550
|
-
note: external_exports.string().trim().max(2e3).optional()
|
|
16551
|
-
}).superRefine((r, ctx) => {
|
|
16552
|
-
if (r.kind === "other" && !r.note)
|
|
16553
|
-
ctx.addIssue({ code: external_exports.ZodIssueCode.custom, path: ["note"], message: "note is required for 'other' feedback" });
|
|
16554
|
-
});
|
|
16555
16405
|
var FeedbackResolutionSchema2 = external_exports.enum(["broker_fixed", "sent_to_agent"]);
|
|
16556
16406
|
var FeedbackOutcomeSchema2 = external_exports.object({
|
|
16557
16407
|
resolution: FeedbackResolutionSchema2,
|
|
@@ -16560,146 +16410,6 @@ var FeedbackOutcomeSchema2 = external_exports.object({
|
|
|
16560
16410
|
childIds: external_exports.array(external_exports.string()).optional()
|
|
16561
16411
|
});
|
|
16562
16412
|
|
|
16563
|
-
// src/main.ts
|
|
16564
|
-
var import_qrcode = __toESM(require_lib(), 1);
|
|
16565
|
-
import { homedir as homedir7, hostname } from "os";
|
|
16566
|
-
|
|
16567
|
-
// src/harness/catalog.ts
|
|
16568
|
-
import { spawnSync } from "child_process";
|
|
16569
|
-
import { existsSync as existsSync2 } from "fs";
|
|
16570
|
-
import { homedir as homedir2 } from "os";
|
|
16571
|
-
import { delimiter, dirname, join as join2 } from "path";
|
|
16572
|
-
var CATALOG = [
|
|
16573
|
-
{
|
|
16574
|
-
name: "claude",
|
|
16575
|
-
label: "Claude Code",
|
|
16576
|
-
cli: "claude",
|
|
16577
|
-
adapter: "claude-agent-acp",
|
|
16578
|
-
authProbe: ["claude", "auth", "status"],
|
|
16579
|
-
loginHint: "Run `claude` once in a terminal and sign in.",
|
|
16580
|
-
installCli: "curl -fsSL https://claude.ai/install.sh | bash",
|
|
16581
|
-
installAdapter: "npm install -g @agentclientprotocol/claude-agent-acp"
|
|
16582
|
-
},
|
|
16583
|
-
{
|
|
16584
|
-
name: "codex",
|
|
16585
|
-
label: "Codex",
|
|
16586
|
-
cli: "codex",
|
|
16587
|
-
adapter: "codex-acp",
|
|
16588
|
-
authProbe: ["codex", "login", "status"],
|
|
16589
|
-
loginHint: "Run `codex login` to authenticate.",
|
|
16590
|
-
installCli: "curl -fsSL https://chatgpt.com/codex/install.sh | sh",
|
|
16591
|
-
installAdapter: "npm install -g @agentclientprotocol/codex-acp"
|
|
16592
|
-
},
|
|
16593
|
-
{
|
|
16594
|
-
name: "agy",
|
|
16595
|
-
label: "Antigravity",
|
|
16596
|
-
cli: "agy",
|
|
16597
|
-
authProbe: ["agy", "help"],
|
|
16598
|
-
loginHint: "Install and set up Antigravity (`agy`).",
|
|
16599
|
-
installCli: "curl -fsSL https://antigravity.dev/install.sh | bash"
|
|
16600
|
-
}
|
|
16601
|
-
];
|
|
16602
|
-
function probeDirs(home = homedir2()) {
|
|
16603
|
-
return [
|
|
16604
|
-
dirname(process.execPath),
|
|
16605
|
-
join2(home, ".local", "bin"),
|
|
16606
|
-
"/usr/local/bin",
|
|
16607
|
-
"/opt/homebrew/bin",
|
|
16608
|
-
join2(home, ".npm-global", "bin")
|
|
16609
|
-
];
|
|
16610
|
-
}
|
|
16611
|
-
function which(bin) {
|
|
16612
|
-
const hit = spawnSync("which", [bin], { encoding: "utf8" });
|
|
16613
|
-
const fromPath = hit.status === 0 ? hit.stdout.trim() : "";
|
|
16614
|
-
if (fromPath) return fromPath;
|
|
16615
|
-
for (const dir of probeDirs()) {
|
|
16616
|
-
const candidate = join2(dir, bin);
|
|
16617
|
-
if (existsSync2(candidate)) return candidate;
|
|
16618
|
-
}
|
|
16619
|
-
return null;
|
|
16620
|
-
}
|
|
16621
|
-
function runProbe(argv) {
|
|
16622
|
-
const [cmd, ...args] = argv;
|
|
16623
|
-
if (!cmd) return false;
|
|
16624
|
-
const resolved = which(cmd);
|
|
16625
|
-
if (!resolved) return false;
|
|
16626
|
-
return spawnSync(resolved, args, {
|
|
16627
|
-
timeout: 1e4,
|
|
16628
|
-
stdio: "ignore",
|
|
16629
|
-
env: { ...process.env, PATH: [process.env.PATH, ...probeDirs()].filter(Boolean).join(delimiter) }
|
|
16630
|
-
}).status === 0;
|
|
16631
|
-
}
|
|
16632
|
-
function detect(entry, deps = {}) {
|
|
16633
|
-
const find = deps.which ?? which;
|
|
16634
|
-
const probe = deps.probe ?? runProbe;
|
|
16635
|
-
const base = { name: entry.name, label: entry.label };
|
|
16636
|
-
const cliPath = find(entry.cli);
|
|
16637
|
-
if (!cliPath) return { ...base, status: "missing", hint: `${entry.label} is not installed.`, install: entry.installCli };
|
|
16638
|
-
const adapterPath = entry.adapter ? find(entry.adapter) : null;
|
|
16639
|
-
if (entry.adapter && !adapterPath) {
|
|
16640
|
-
return {
|
|
16641
|
-
...base,
|
|
16642
|
-
status: "adapter-missing",
|
|
16643
|
-
hint: `${entry.label} is installed, but its ACP adapter (${entry.adapter}) is not.`,
|
|
16644
|
-
...entry.installAdapter ? { install: entry.installAdapter } : {}
|
|
16645
|
-
};
|
|
16646
|
-
}
|
|
16647
|
-
const bin = adapterPath ?? cliPath;
|
|
16648
|
-
if (!probe(entry.authProbe)) return { ...base, status: "login", bin, hint: entry.loginHint };
|
|
16649
|
-
return { ...base, status: "ready", bin };
|
|
16650
|
-
}
|
|
16651
|
-
function detectAll(deps = {}) {
|
|
16652
|
-
return CATALOG.map((entry) => detect(entry, deps));
|
|
16653
|
-
}
|
|
16654
|
-
|
|
16655
|
-
// src/host.ts
|
|
16656
|
-
import { readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "fs";
|
|
16657
|
-
import { homedir as homedir5 } from "os";
|
|
16658
|
-
import { join as join5 } from "path";
|
|
16659
|
-
|
|
16660
|
-
// src/workspaces.ts
|
|
16661
|
-
import { existsSync as existsSync3, mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
16662
|
-
import { dirname as dirname2, join as join3, resolve } from "path";
|
|
16663
|
-
import { homedir as homedir3 } from "os";
|
|
16664
|
-
function workspacesFile() {
|
|
16665
|
-
return join3(homedir3(), ".paigy", "workspaces.json");
|
|
16666
|
-
}
|
|
16667
|
-
function listWorkspaces(deps) {
|
|
16668
|
-
try {
|
|
16669
|
-
const parsed = JSON.parse(readFileSync2(deps.file, "utf8"));
|
|
16670
|
-
return Array.isArray(parsed) ? parsed.filter((w) => typeof w === "string") : [];
|
|
16671
|
-
} catch {
|
|
16672
|
-
return [];
|
|
16673
|
-
}
|
|
16674
|
-
}
|
|
16675
|
-
function addWorkspace(dir, deps) {
|
|
16676
|
-
const next = resolve(dir.replace(/^~(?=$|\/)/, homedir3()));
|
|
16677
|
-
const all = listWorkspaces(deps);
|
|
16678
|
-
if (!all.includes(next)) {
|
|
16679
|
-
all.push(next);
|
|
16680
|
-
mkdirSync2(dirname2(deps.file), { recursive: true });
|
|
16681
|
-
writeFileSync2(deps.file, JSON.stringify(all, null, 2));
|
|
16682
|
-
}
|
|
16683
|
-
return all;
|
|
16684
|
-
}
|
|
16685
|
-
function removeWorkspace(dir, deps) {
|
|
16686
|
-
const all = listWorkspaces(deps).filter((w) => w !== dir);
|
|
16687
|
-
mkdirSync2(dirname2(deps.file), { recursive: true });
|
|
16688
|
-
writeFileSync2(deps.file, JSON.stringify(all, null, 2));
|
|
16689
|
-
return all;
|
|
16690
|
-
}
|
|
16691
|
-
function allowed(cwd, deps) {
|
|
16692
|
-
const target = resolve(cwd.replace(/^~(?=$|\/)/, homedir3()));
|
|
16693
|
-
return listWorkspaces(deps).some((w) => target === w || target.startsWith(`${w}/`));
|
|
16694
|
-
}
|
|
16695
|
-
function resolveWakeDir(pinned, deps) {
|
|
16696
|
-
if (pinned && allowed(pinned, deps)) {
|
|
16697
|
-
const dir = resolve(pinned.replace(/^~(?=$|\/)/, homedir3()));
|
|
16698
|
-
if ((deps.exists ?? existsSync3)(dir)) return dir;
|
|
16699
|
-
}
|
|
16700
|
-
return listWorkspaces(deps)[0];
|
|
16701
|
-
}
|
|
16702
|
-
|
|
16703
16413
|
// src/paigy/activity.ts
|
|
16704
16414
|
function shortenPaths(s) {
|
|
16705
16415
|
return s.replace(/(?<![\w.@+-])(?:\/[\w.@+-]+){3,}/g, (p) => {
|
|
@@ -18256,13 +17966,6 @@ ipcMain.handle("paigy:beacon", async () => {
|
|
|
18256
17966
|
})();
|
|
18257
17967
|
return { qr, code: code.user_code };
|
|
18258
17968
|
});
|
|
18259
|
-
function waitingLine(d) {
|
|
18260
|
-
for (let i = d.entries.length - 1; i >= 0; i -= 1) {
|
|
18261
|
-
const words2 = entryWords(d.entries[i]).trim();
|
|
18262
|
-
if (words2) return words2.split("\n")[0];
|
|
18263
|
-
}
|
|
18264
|
-
return d.message.split("\n")[0] ?? "";
|
|
18265
|
-
}
|
|
18266
17969
|
ipcMain.handle("paigy:agent", async (_e, name) => {
|
|
18267
17970
|
const entry = (host?.roster() ?? readHostState()?.roster ?? []).find((a) => a.name === name);
|
|
18268
17971
|
if (!entry) return null;
|
|
@@ -18272,10 +17975,7 @@ ipcMain.handle("paigy:agent", async (_e, name) => {
|
|
|
18272
17975
|
...entry,
|
|
18273
17976
|
pending: open ? {
|
|
18274
17977
|
// The same two facts, from the one list: what is waiting, and how much.
|
|
18275
|
-
requests: open.slice(0, 5).map((d) => ({
|
|
18276
|
-
line: waitingLine(d).slice(0, 140),
|
|
18277
|
-
at: d.entries[d.entries.length - 1]?.createdAt ?? ""
|
|
18278
|
-
})),
|
|
17978
|
+
requests: open.slice(0, 5).map((d) => ({ line: (d.about || d.message.split("\n")[0] || "").slice(0, 140) })),
|
|
18279
17979
|
replies: open.length
|
|
18280
17980
|
} : null
|
|
18281
17981
|
};
|