@agenticprimitives/runtime-member 0.0.0-alpha.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/LICENSE +21 -0
- package/README.md +40 -0
- package/bin/ap-runtime.mjs +4 -0
- package/dist/cli.d.ts +8 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +201 -0
- package/dist/cli.js.map +1 -0
- package/dist/client.d.ts +48 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +75 -0
- package/dist/client.js.map +1 -0
- package/dist/equip-entry.d.ts +8 -0
- package/dist/equip-entry.d.ts.map +1 -0
- package/dist/equip-entry.js +7 -0
- package/dist/equip-entry.js.map +1 -0
- package/dist/equip.d.ts +124 -0
- package/dist/equip.d.ts.map +1 -0
- package/dist/equip.js +173 -0
- package/dist/equip.js.map +1 -0
- package/dist/index.d.ts +27 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +22 -0
- package/dist/index.js.map +1 -0
- package/dist/join.d.ts +9 -0
- package/dist/join.d.ts.map +1 -0
- package/dist/join.js +32 -0
- package/dist/join.js.map +1 -0
- package/dist/keystore.d.ts +13 -0
- package/dist/keystore.d.ts.map +1 -0
- package/dist/keystore.js +60 -0
- package/dist/keystore.js.map +1 -0
- package/dist/loop.d.ts +78 -0
- package/dist/loop.d.ts.map +1 -0
- package/dist/loop.js +151 -0
- package/dist/loop.js.map +1 -0
- package/dist/messaging.d.ts +19 -0
- package/dist/messaging.d.ts.map +1 -0
- package/dist/messaging.js +51 -0
- package/dist/messaging.js.map +1 -0
- package/dist/pair.d.ts +19 -0
- package/dist/pair.d.ts.map +1 -0
- package/dist/pair.js +51 -0
- package/dist/pair.js.map +1 -0
- package/dist/pairing.d.ts +61 -0
- package/dist/pairing.d.ts.map +1 -0
- package/dist/pairing.js +4 -0
- package/dist/pairing.js.map +1 -0
- package/dist/record.d.ts +33 -0
- package/dist/record.d.ts.map +1 -0
- package/dist/record.js +2 -0
- package/dist/record.js.map +1 -0
- package/dist/run.d.ts +8 -0
- package/dist/run.d.ts.map +1 -0
- package/dist/run.js +24 -0
- package/dist/run.js.map +1 -0
- package/dist/serve.d.ts +26 -0
- package/dist/serve.d.ts.map +1 -0
- package/dist/serve.js +51 -0
- package/dist/serve.js.map +1 -0
- package/dist/standing.d.ts +58 -0
- package/dist/standing.d.ts.map +1 -0
- package/dist/standing.js +65 -0
- package/dist/standing.js.map +1 -0
- package/dist/workspace-mcp.d.ts +88 -0
- package/dist/workspace-mcp.d.ts.map +1 -0
- package/dist/workspace-mcp.js +129 -0
- package/dist/workspace-mcp.js.map +1 -0
- package/package.json +79 -0
- package/spec.md +10 -0
package/dist/loop.js
ADDED
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
// THE LOOP'S BODY, wake-agnostic (spec 400 §5.3 / W1c). One object holds the ACP host, the sessions (one per
|
|
2
|
+
// conversation) and the inbox cursor; `pollOnce` reads what arrived since the cursor as the member itself and answers
|
|
3
|
+
// each message from someone else with one ACP prompt and one reply that PARKS. Who calls `pollOnce` is the host's
|
|
4
|
+
// business: `ap runtime run` calls it on a timer (a laptop), `ap runtime serve` calls it when the Worker's queue wakes
|
|
5
|
+
// the Container (W1c). Either way the WORKSPACE never polls and the Worker never speaks ACP.
|
|
6
|
+
//
|
|
7
|
+
// What the loop never does: hold anyone's session, decide an act, answer a permission prompt with "allow" for the
|
|
8
|
+
// agent's own shell (the host's policy does that, refusing by default), or retry a parked act.
|
|
9
|
+
import { AcpHost, collectText } from '@agenticprimitives/acp';
|
|
10
|
+
import { askAs, continueAs, recordSigner } from './client.js';
|
|
11
|
+
import { loadRuntimeMember } from './keystore.js';
|
|
12
|
+
import { deriveForNeed, parkedNeedOf } from './standing.js';
|
|
13
|
+
import { describeOutcome, inboxPlan, replyPlan, topicReplyPlan, topicOf } from './workspace-mcp.js';
|
|
14
|
+
/** The context the agent gets with every prompt — who it is, where it stands, what waits on whom (§5.3). */
|
|
15
|
+
export function promptFor(rec, m) {
|
|
16
|
+
const who = m.fromName ?? m.from;
|
|
17
|
+
const topic = topicOf(m.conversationId);
|
|
18
|
+
const where = topic ? `a TOPIC of ${rec.workspace.name} (id ${topic.channelId}) where you were mentioned — your answer is posted in that topic for every member` : `thread ${m.conversationId}`;
|
|
19
|
+
return [
|
|
20
|
+
`[workspace: ${rec.workspace.name} · ${where} · you are ${rec.name}, a member; your grant lets you read the workspace's records and work, offer to do a step, and send messages as yourself — every write waits for the steward's signature. Use the workspace tools to read before you answer; answer briefly, in the workspace's words.]`,
|
|
21
|
+
`${who}: ${m.text}`,
|
|
22
|
+
].join('\n');
|
|
23
|
+
}
|
|
24
|
+
export class RuntimeMemberLoop {
|
|
25
|
+
o;
|
|
26
|
+
rec;
|
|
27
|
+
host;
|
|
28
|
+
mcp;
|
|
29
|
+
sessions = new Map(); // conversationId → ACP sessionId
|
|
30
|
+
log;
|
|
31
|
+
cursor;
|
|
32
|
+
busy = Promise.resolve([]);
|
|
33
|
+
started = false;
|
|
34
|
+
constructor(o) {
|
|
35
|
+
this.o = o;
|
|
36
|
+
this.rec = loadRuntimeMember(o.member);
|
|
37
|
+
this.log = o.log ?? ((l) => process.stderr.write(`${l}\n`));
|
|
38
|
+
this.mcp = { name: 'workspace', ...(o.mcpCommand ?? { command: 'ap', args: ['runtime', 'mcp', '--member', this.rec.name] }) };
|
|
39
|
+
this.host = new AcpHost({ command: o.agent[0], args: o.agent.slice(1), workspaceServerName: 'workspace', ...(o.permission ? { permission: o.permission } : {}), ...(o.cwd ? { cwd: o.cwd } : {}), onStderr: (l) => this.log(` [agent] ${l}`) });
|
|
40
|
+
this.cursor = o.since;
|
|
41
|
+
}
|
|
42
|
+
get cursorNow() { return this.cursor; }
|
|
43
|
+
ask(text, plan) {
|
|
44
|
+
return askAs(this.rec, this.rec.name, text, { plan, fetch: this.o.fetch, signer: this.o.signer });
|
|
45
|
+
}
|
|
46
|
+
/** Start the agent; take the cursor from "now" unless one was given — a runtime that joins today does not answer last month. */
|
|
47
|
+
async start() {
|
|
48
|
+
if (this.started)
|
|
49
|
+
return;
|
|
50
|
+
const init = await this.host.start();
|
|
51
|
+
this.log(`${this.rec.name} · agent ${init.agentInfo?.name ?? this.o.agent[0]} (ACP v${init.protocolVersion}) · workspace ${this.rec.workspace.name} · edge ${this.rec.edge}`);
|
|
52
|
+
this.host.on('permission', (r, out) => this.log(` permission ${r.toolCall.title ?? r.toolCall.toolCallId} → ${'optionId' in out.outcome ? out.outcome.optionId : 'cancelled'}`));
|
|
53
|
+
if (!this.cursor && !this.o.woken) {
|
|
54
|
+
const first = await this.ask("what's new for me", inboxPlan(undefined, 1));
|
|
55
|
+
this.cursor = first.data?.cursor ?? undefined;
|
|
56
|
+
}
|
|
57
|
+
this.started = true;
|
|
58
|
+
}
|
|
59
|
+
async sessionFor(conversationId) {
|
|
60
|
+
const have = this.sessions.get(conversationId);
|
|
61
|
+
if (have)
|
|
62
|
+
return have;
|
|
63
|
+
const s = await this.host.newSession(this.o.cwd ?? process.cwd(), [this.mcp]);
|
|
64
|
+
this.sessions.set(conversationId, s.sessionId);
|
|
65
|
+
return s.sessionId;
|
|
66
|
+
}
|
|
67
|
+
/** One pass: everything since the cursor, each message from someone else answered. Serialized — a wake that lands
|
|
68
|
+
* while a pass runs waits for it (the cursor is the dedupe; two wakes for one message cost one turn). */
|
|
69
|
+
pollOnce(maxTurns, wake) {
|
|
70
|
+
const next = this.busy.then(() => this.pass(maxTurns, wake), () => this.pass(maxTurns, wake));
|
|
71
|
+
this.busy = next;
|
|
72
|
+
return next;
|
|
73
|
+
}
|
|
74
|
+
async pass(maxTurns, wake) {
|
|
75
|
+
if (!this.started)
|
|
76
|
+
await this.start();
|
|
77
|
+
const cold = !this.cursor;
|
|
78
|
+
const polled = await this.ask(`what's new for me${this.cursor ? ` since ${this.cursor}` : ''}`, inboxPlan(this.cursor, 20)).catch((e) => { this.log(` poll failed: ${e.message}`); return null; });
|
|
79
|
+
const data = polled?.data;
|
|
80
|
+
let listed = data?.messages ?? [];
|
|
81
|
+
if (cold && this.o.woken) {
|
|
82
|
+
// A COLD, WOKEN start: everything up to the waking message is history; the waking message and what followed it
|
|
83
|
+
// are the pass. Woken without a message id (or the id not in the newest page) → history only, cursor at the end.
|
|
84
|
+
const at = wake?.messageId ? listed.findIndex((m) => m.id === wake.messageId) : -1;
|
|
85
|
+
listed = at >= 0 ? listed.slice(at) : [];
|
|
86
|
+
if (at < 0 && wake?.messageId)
|
|
87
|
+
this.log(` woken for ${wake.messageId}, which is not among the newest ${data?.messages?.length ?? 0} — nothing to answer`);
|
|
88
|
+
}
|
|
89
|
+
const fresh = listed.filter((m) => !m.mine);
|
|
90
|
+
if (data?.cursor)
|
|
91
|
+
this.cursor = data.cursor;
|
|
92
|
+
const reports = [];
|
|
93
|
+
for (const m of fresh) {
|
|
94
|
+
if (maxTurns !== undefined && reports.length >= maxTurns)
|
|
95
|
+
break;
|
|
96
|
+
reports.push(await this.turn(m));
|
|
97
|
+
}
|
|
98
|
+
return reports;
|
|
99
|
+
}
|
|
100
|
+
async turn(m) {
|
|
101
|
+
const sessionId = await this.sessionFor(m.conversationId);
|
|
102
|
+
const prompt = promptFor(this.rec, m);
|
|
103
|
+
this.log(`→ ${m.fromName ?? m.from}: ${m.text.slice(0, 80)}`);
|
|
104
|
+
const text = collectText(this.host, sessionId);
|
|
105
|
+
const done = await this.host.prompt(sessionId, [{ type: 'text', text: prompt }]);
|
|
106
|
+
text.stop();
|
|
107
|
+
const answer = text.text().trim();
|
|
108
|
+
this.log(`← ${this.rec.name} (${done.stopReason}): ${answer.slice(0, 120)}`);
|
|
109
|
+
let reply = '(no answer)';
|
|
110
|
+
let parkedRunRef;
|
|
111
|
+
let underStandingGrant;
|
|
112
|
+
if (answer) {
|
|
113
|
+
const to = m.fromName ?? m.from;
|
|
114
|
+
// WHERE THE REPLY GOES (spec 400 W2, B3): a mention in a topic is answered IN THAT TOPIC, as the member; a DM is
|
|
115
|
+
// answered with a DM to whoever wrote. The thread id says which.
|
|
116
|
+
const topic = topicOf(m.conversationId);
|
|
117
|
+
let sent = await (topic
|
|
118
|
+
? this.ask(`post in the topic: ${answer}`, topicReplyPlan(topic.org, topic.channelId, answer))
|
|
119
|
+
: this.ask(`send ${to} a message: ${answer}`, replyPlan(to, answer))).catch((e) => ({ text: e.message, state: 'ERROR', parked: false }));
|
|
120
|
+
// Spec 400 W2a — THE OPEN MANDATE. The reply parked for a mandate; the custodian granted this runtime a standing
|
|
121
|
+
// one for exactly this capability. Derive the child for THIS intent, sign it with our key, continue the same run
|
|
122
|
+
// presenting the chain. The harness verifies it there; a chain that does not verify leaves the run parked, and
|
|
123
|
+
// the report says so. No grant, or a need outside it (a commit, a payment) → parked, as before.
|
|
124
|
+
const need = sent.parked && sent.state === 'TASK_STATE_AUTH_REQUIRED' && sent.taskId ? parkedNeedOf(sent.data) : null;
|
|
125
|
+
if (need && this.rec.standing) {
|
|
126
|
+
const derived = await deriveForNeed(this.rec.standing, need, this.rec.agent, this.o.signer ?? recordSigner(this.rec)).catch((e) => ({ ok: false, reason: e.message }));
|
|
127
|
+
if (derived.ok) {
|
|
128
|
+
const cont = await continueAs(this.rec, this.rec.name, sent.taskId, derived.presented, { fetch: this.o.fetch, signer: this.o.signer }).catch((e) => ({ text: e.message, state: 'ERROR', parked: false }));
|
|
129
|
+
this.log(` standing grant → child ${derived.childRef.slice(0, 12)}… → ${cont.state}`);
|
|
130
|
+
if (!cont.parked && cont.state !== 'ERROR') {
|
|
131
|
+
sent = cont;
|
|
132
|
+
underStandingGrant = { childRef: derived.childRef, standingRef: this.rec.standing.ref };
|
|
133
|
+
}
|
|
134
|
+
else
|
|
135
|
+
sent = { ...sent, text: `${sent.text} (the standing grant did not carry it: ${cont.text || cont.state})` };
|
|
136
|
+
}
|
|
137
|
+
else
|
|
138
|
+
this.log(` standing grant does not cover this: ${derived.reason}`);
|
|
139
|
+
}
|
|
140
|
+
reply = describeOutcome(sent);
|
|
141
|
+
if (sent.parked)
|
|
142
|
+
parkedRunRef = sent.runRef ?? sent.taskId;
|
|
143
|
+
this.log(` reply → ${reply.slice(0, 140)}`);
|
|
144
|
+
}
|
|
145
|
+
const report = { messageId: m.id, from: m.from, fromName: m.fromName, conversationId: m.conversationId, prompt, answer, reply, ...(parkedRunRef ? { parkedRunRef } : {}), ...(underStandingGrant ? { underStandingGrant } : {}) };
|
|
146
|
+
this.o.onTurn?.(report);
|
|
147
|
+
return report;
|
|
148
|
+
}
|
|
149
|
+
async stop() { await this.busy.catch(() => undefined); await this.host.stop(); }
|
|
150
|
+
}
|
|
151
|
+
//# sourceMappingURL=loop.js.map
|
package/dist/loop.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loop.js","sourceRoot":"","sources":["../src/loop.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { type Address, type Hex } from 'viem';
|
|
2
|
+
import type { Contracts, CustodianSigner } from './equip.js';
|
|
3
|
+
export declare const MESSAGING_WIRE_SKILLS: readonly ["messaging.deliver", "interactions.respond", "interactions.deliverCredential"];
|
|
4
|
+
export interface EnableMessagingInput {
|
|
5
|
+
a2a: string;
|
|
6
|
+
member: Address;
|
|
7
|
+
recipients: Address[];
|
|
8
|
+
contracts: Contracts;
|
|
9
|
+
custodian: CustodianSigner;
|
|
10
|
+
stewardship?: unknown;
|
|
11
|
+
validForSeconds?: number;
|
|
12
|
+
fetch?: typeof fetch;
|
|
13
|
+
}
|
|
14
|
+
/** Enable (or widen) the member's messaging rail to `recipients`. Returns the recipients now covered. */
|
|
15
|
+
export declare function enableMessaging(i: EnableMessagingInput): Promise<{
|
|
16
|
+
recipients: Address[];
|
|
17
|
+
hash: Hex;
|
|
18
|
+
}>;
|
|
19
|
+
//# sourceMappingURL=messaging.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"messaging.d.ts","sourceRoot":"","sources":["../src/messaging.ts"],"names":[],"mappings":"AASA,OAAO,EAAS,KAAK,OAAO,EAAE,KAAK,GAAG,EAAE,MAAM,MAAM,CAAC;AAIrD,OAAO,KAAK,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAE7D,eAAO,MAAM,qBAAqB,0FAA2F,CAAC;AAiB9H,MAAM,WAAW,oBAAoB;IACnC,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,OAAO,CAAC;IAChB,UAAU,EAAE,OAAO,EAAE,CAAC;IACtB,SAAS,EAAE,SAAS,CAAC;IACrB,SAAS,EAAE,eAAe,CAAC;IAC3B,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;CACtB;AAED,yGAAyG;AACzG,wBAAsB,eAAe,CAAC,CAAC,EAAE,oBAAoB,GAAG,OAAO,CAAC;IAAE,UAAU,EAAE,OAAO,EAAE,CAAC;IAAC,IAAI,EAAE,GAAG,CAAA;CAAE,CAAC,CAe5G"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
// THE MEMBER'S MESSAGING RAIL (spec 400 W2a) — what the Home's ceremony does for a person or an organization, done by
|
|
2
|
+
// `ap runtime` for the runtime member: its custodian signs (1) the SIGNING WIRE, member → the deployment's
|
|
3
|
+
// interactions-session key, pinned to the messaging skills, and (2) the TRANSPORT GRANT, member → member, naming the
|
|
4
|
+
// recipients it may deliver to. Both are installed on the member's own object (`messaging.wireEnable`, self or
|
|
5
|
+
// steward), and re-verified there: delegator, delegate, shape, signature, on-chain revocation. Without this rail a
|
|
6
|
+
// reply the harness has authorized still cannot leave (`wire_absent`) — an open mandate needs a rail to run on.
|
|
7
|
+
//
|
|
8
|
+
// THE UNION IS THE POINT (the Home's rule): installing a wire replaces the previous one, so the recipients already
|
|
9
|
+
// covered are read first and carried forward; a new contact widens, never narrows.
|
|
10
|
+
import { toHex } from 'viem';
|
|
11
|
+
import { buildCaveat, encodeAllowedMethodsTerms, encodeAllowedTargetsTerms, encodeTimestampTerms, hashDelegation, ROOT_AUTHORITY } from '@agenticprimitives/delegation';
|
|
12
|
+
import { skillSelector } from '@agenticprimitives/a2a';
|
|
13
|
+
export const MESSAGING_WIRE_SKILLS = ['messaging.deliver', 'interactions.respond', 'interactions.deliverCredential'];
|
|
14
|
+
const j = async (r) => { const t = await r.text(); try {
|
|
15
|
+
return JSON.parse(t);
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
return { _raw: t.slice(0, 200), _status: r.status };
|
|
19
|
+
} };
|
|
20
|
+
function messagingCaveats(c, recipients, validUntil) {
|
|
21
|
+
return [
|
|
22
|
+
buildCaveat(c.timestampEnforcer, encodeTimestampTerms(0, validUntil)),
|
|
23
|
+
buildCaveat(c.allowedTargetsEnforcer, encodeAllowedTargetsTerms(recipients)),
|
|
24
|
+
buildCaveat(c.allowedMethodsEnforcer, encodeAllowedMethodsTerms(MESSAGING_WIRE_SKILLS.map((s) => skillSelector(s)))),
|
|
25
|
+
];
|
|
26
|
+
}
|
|
27
|
+
async function signed(d, c, sign) {
|
|
28
|
+
d.signature = await sign(hashDelegation(d, c.chainId, c.delegationManager));
|
|
29
|
+
return { ...d, salt: d.salt.toString() };
|
|
30
|
+
}
|
|
31
|
+
/** Enable (or widen) the member's messaging rail to `recipients`. Returns the recipients now covered. */
|
|
32
|
+
export async function enableMessaging(i) {
|
|
33
|
+
const f = i.fetch ?? fetch;
|
|
34
|
+
const a2a = i.a2a.replace(/\/$/, '');
|
|
35
|
+
const op = async (name, body) => j(await f(`${a2a}/interactions/${i.member}/${name}`, { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ session: i.custodian.bearer, ...(i.stewardship ? { stewardship: i.stewardship } : {}), ...body }) }));
|
|
36
|
+
const status = await op('messaging.wireStatus', {});
|
|
37
|
+
if (status.ok !== true || !status.sessionKey)
|
|
38
|
+
throw new Error(`the member's rail could not be read: ${status.error ?? JSON.stringify(status).slice(0, 160)}`);
|
|
39
|
+
const recipients = [...new Set([...(status.recipients ?? []), ...i.recipients].map((r) => r.toLowerCase()))].filter((r) => r !== i.member.toLowerCase());
|
|
40
|
+
if (!recipients.length)
|
|
41
|
+
throw new Error('name at least one recipient');
|
|
42
|
+
const validUntil = Math.floor(Date.now() / 1000) + (i.validForSeconds ?? 90 * 86_400);
|
|
43
|
+
const salt = () => BigInt(toHex(crypto.getRandomValues(new Uint8Array(16))));
|
|
44
|
+
const wire = await signed({ delegator: i.member, delegate: status.sessionKey, authority: ROOT_AUTHORITY, caveats: messagingCaveats(i.contracts, recipients, validUntil), salt: salt(), signature: '0x' }, i.contracts, i.custodian.signDigest);
|
|
45
|
+
const transport = await signed({ delegator: i.member, delegate: i.member, authority: ROOT_AUTHORITY, caveats: messagingCaveats(i.contracts, recipients, validUntil), salt: salt(), signature: '0x' }, i.contracts, i.custodian.signDigest);
|
|
46
|
+
const put = await op('messaging.wireEnable', { delegation: wire, transport });
|
|
47
|
+
if (put.ok !== true || !put.hash)
|
|
48
|
+
throw new Error(`the messaging rail was not enabled: ${put.error ?? JSON.stringify(put).slice(0, 200)}`);
|
|
49
|
+
return { recipients: (put.recipients ?? recipients).map((r) => r.toLowerCase()), hash: put.hash };
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=messaging.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"messaging.js","sourceRoot":"","sources":["../src/messaging.ts"],"names":[],"mappings":"AAAA,sHAAsH;AACtH,2GAA2G;AAC3G,qHAAqH;AACrH,+GAA+G;AAC/G,mHAAmH;AACnH,gHAAgH;AAChH,EAAE;AACF,mHAAmH;AACnH,mFAAmF;AACnF,OAAO,EAAE,KAAK,EAA0B,MAAM,MAAM,CAAC;AACrD,OAAO,EAAE,WAAW,EAAE,yBAAyB,EAAE,yBAAyB,EAAE,oBAAoB,EAAE,cAAc,EAAE,cAAc,EAAmB,MAAM,+BAA+B,CAAC;AACzL,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAIvD,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,mBAAmB,EAAE,sBAAsB,EAAE,gCAAgC,CAAU,CAAC;AAE9H,MAAM,CAAC,GAAG,KAAK,EAAE,CAAW,EAAoC,EAAE,GAAG,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC;IAAC,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,CAA4B,CAAC;AAAC,CAAC;AAAC,MAAM,CAAC;IAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC;AAAC,CAAC,CAAC,CAAC,CAAC;AAEzN,SAAS,gBAAgB,CAAC,CAAY,EAAE,UAAqB,EAAE,UAAkB;IAC/E,OAAO;QACL,WAAW,CAAC,CAAC,CAAC,iBAAiB,EAAE,oBAAoB,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC;QACrE,WAAW,CAAC,CAAC,CAAC,sBAAsB,EAAE,yBAAyB,CAAC,UAAU,CAAC,CAAC;QAC5E,WAAW,CAAC,CAAC,CAAC,sBAAsB,EAAE,yBAAyB,CAAC,qBAAqB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;KACrH,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,MAAM,CAAC,CAAa,EAAE,CAAY,EAAE,IAAY;IAC7D,CAAC,CAAC,SAAS,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,CAAC,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC;IAC5E,OAAO,EAAE,GAAG,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,QAAQ,EAAE,EAAE,CAAC;AAC3C,CAAC;AAaD,yGAAyG;AACzG,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,CAAuB;IAC3D,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,IAAI,KAAK,CAAC;IAC3B,MAAM,GAAG,GAAG,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IACrC,MAAM,EAAE,GAAG,KAAK,EAAE,IAAY,EAAE,IAA6B,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,GAAG,iBAAiB,CAAC,CAAC,MAAM,IAAI,IAAI,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,SAAS,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;IACvT,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC,sBAAsB,EAAE,EAAE,CAAiF,CAAC;IACpI,IAAI,MAAM,CAAC,EAAE,KAAK,IAAI,IAAI,CAAC,MAAM,CAAC,UAAU;QAAE,MAAM,IAAI,KAAK,CAAC,wCAAwC,MAAM,CAAC,KAAK,IAAI,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC;IAC9J,MAAM,UAAU,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,UAAU,IAAI,EAAE,CAAC,EAAE,GAAG,CAAC,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAa,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC,CAAC;IACpK,IAAI,CAAC,UAAU,CAAC,MAAM;QAAE,MAAM,IAAI,KAAK,CAAC,6BAA6B,CAAC,CAAC;IACvE,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,eAAe,IAAI,EAAE,GAAG,MAAM,CAAC,CAAC;IACtF,MAAM,IAAI,GAAG,GAAG,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,eAAe,CAAC,IAAI,UAAU,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IAC7E,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,QAAQ,EAAE,MAAM,CAAC,UAAqB,EAAE,SAAS,EAAE,cAAc,EAAE,OAAO,EAAE,gBAAgB,CAAC,CAAC,CAAC,SAAS,EAAE,UAAU,EAAE,UAAU,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;IAC1P,MAAM,SAAS,GAAG,MAAM,MAAM,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,SAAS,EAAE,cAAc,EAAE,OAAO,EAAE,gBAAgB,CAAC,CAAC,CAAC,SAAS,EAAE,UAAU,EAAE,UAAU,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;IAC3O,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC,sBAAsB,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,SAAS,EAAE,CAAwE,CAAC;IACrJ,IAAI,GAAG,CAAC,EAAE,KAAK,IAAI,IAAI,CAAC,GAAG,CAAC,IAAI;QAAE,MAAM,IAAI,KAAK,CAAC,uCAAuC,GAAG,CAAC,KAAK,IAAI,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC;IAC3I,OAAO,EAAE,UAAU,EAAE,CAAC,GAAG,CAAC,UAAU,IAAI,UAAU,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAa,CAAC,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,CAAC;AAC/G,CAAC"}
|
package/dist/pair.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { RuntimeMemberRecordV1 } from './record.js';
|
|
2
|
+
import type { RuntimeHostV1 } from './equip.js';
|
|
3
|
+
export interface PairOptions {
|
|
4
|
+
home: string;
|
|
5
|
+
code: string;
|
|
6
|
+
/** How this runtime is hosted — what the Worker should wake. Omitted: the custodian's minted choice stands. */
|
|
7
|
+
wake?: RuntimeHostV1 | null;
|
|
8
|
+
/** Which ACP agent this runtime runs (informational, shown on the Home). */
|
|
9
|
+
agent?: string;
|
|
10
|
+
pollMs?: number;
|
|
11
|
+
timeoutMs?: number;
|
|
12
|
+
fetch?: typeof fetch;
|
|
13
|
+
log?: (line: string) => void;
|
|
14
|
+
}
|
|
15
|
+
export declare function runtimePair(o: PairOptions): Promise<{
|
|
16
|
+
path: string;
|
|
17
|
+
record: RuntimeMemberRecordV1;
|
|
18
|
+
}>;
|
|
19
|
+
//# sourceMappingURL=pair.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pair.d.ts","sourceRoot":"","sources":["../src/pair.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAEzD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,+GAA+G;IAC/G,IAAI,CAAC,EAAE,aAAa,GAAG,IAAI,CAAC;IAC5B,4EAA4E;IAC5E,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;IACrB,GAAG,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CAC9B;AAID,wBAAsB,WAAW,CAAC,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,qBAAqB,CAAA;CAAE,CAAC,CA4B1G"}
|
package/dist/pair.js
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
// `ap runtime pair <code> --home <url>` — join a workspace with a PAIRING CODE the custodian minted at her Home
|
|
2
|
+
// (spec 400 W1b). The runtime generates its key HERE, claims the code with the key's address, and waits while the
|
|
3
|
+
// custodian approves on her Home — every signature hers, in her browser — then takes the finished record ONCE and
|
|
4
|
+
// keeps it with the key. No Home session, no persona key, no secret but the code — and the code grants nothing.
|
|
5
|
+
import { generatePrivateKey, privateKeyToAccount } from 'viem/accounts';
|
|
6
|
+
import { saveRuntimeMember } from './keystore.js';
|
|
7
|
+
import { PAIRING_CODE_RE, pairingHandleOf } from './pairing.js';
|
|
8
|
+
const j = async (r) => { const t = await r.text(); try {
|
|
9
|
+
return JSON.parse(t);
|
|
10
|
+
}
|
|
11
|
+
catch {
|
|
12
|
+
return { _raw: t.slice(0, 200), _status: r.status };
|
|
13
|
+
} };
|
|
14
|
+
export async function runtimePair(o) {
|
|
15
|
+
const f = o.fetch ?? fetch;
|
|
16
|
+
const log = o.log ?? (() => undefined);
|
|
17
|
+
const code = o.code.trim();
|
|
18
|
+
if (!PAIRING_CODE_RE.test(code))
|
|
19
|
+
throw new Error(`not a pairing code: ${code} (expected <handle>-XXXXXX, as the Home shows it)`);
|
|
20
|
+
const home = o.home.replace(/\/$/, '');
|
|
21
|
+
const key = generatePrivateKey();
|
|
22
|
+
const address = privateKeyToAccount(key).address;
|
|
23
|
+
log(`key ${address} generated here — never leaves this machine`);
|
|
24
|
+
const claim = await j(await f(`${home}/connect/runtime-pair/claim`, { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ code, address, ...(o.wake !== undefined ? { wake: o.wake } : {}), ...(o.agent ? { agent: o.agent } : {}) }) }));
|
|
25
|
+
if (claim.ok !== true)
|
|
26
|
+
throw new Error(`the code was not accepted at ${home}: ${claim.error ?? JSON.stringify(claim).slice(0, 200)}`);
|
|
27
|
+
log(`claimed ${code} — ${pairingHandleOf(code)} sees the request on their Home; waiting for approval…`);
|
|
28
|
+
const started = Date.now();
|
|
29
|
+
for (;;) {
|
|
30
|
+
if (Date.now() - started > (o.timeoutMs ?? 15 * 60_000))
|
|
31
|
+
throw new Error('pairing timed out — mint a new code at the Home and try again');
|
|
32
|
+
await new Promise((r) => setTimeout(r, o.pollMs ?? 3000));
|
|
33
|
+
const got = await j(await f(`${home}/connect/runtime-pair/take`, { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ code, address }) }));
|
|
34
|
+
if (got.ok !== true)
|
|
35
|
+
throw new Error(`pairing failed: ${got.error ?? JSON.stringify(got).slice(0, 200)}`);
|
|
36
|
+
if (got.state === 'completed' && got.record) {
|
|
37
|
+
if (got.record.address.toLowerCase() !== address.toLowerCase())
|
|
38
|
+
throw new Error('the record names another key — refusing it');
|
|
39
|
+
const record = { ...got.record, key };
|
|
40
|
+
const path = saveRuntimeMember(record);
|
|
41
|
+
log(`✓ paired — ${record.name} in ${record.workspace.name}; wire until ${new Date(record.validUntil * 1000).toISOString().slice(0, 10)}${record.standing ? `; open mandate ${record.standing.requirement.actions.join(', ')}` : '; every write parks'}\n kept at ${path} (0600)`);
|
|
42
|
+
return { path, record };
|
|
43
|
+
}
|
|
44
|
+
if (got.state === 'claimed')
|
|
45
|
+
continue;
|
|
46
|
+
if (got.state === 'minted')
|
|
47
|
+
continue;
|
|
48
|
+
throw new Error(`unexpected pairing state ${String(got.state)}`);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=pair.js.map
|
package/dist/pair.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pair.js","sourceRoot":"","sources":["../src/pair.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import type { Address } from 'viem';
|
|
2
|
+
import type { RuntimeMemberRecordV1 } from './record.js';
|
|
3
|
+
import type { RuntimeHostV1 } from './equip.js';
|
|
4
|
+
/** `<handle>-<6 base32 chars>` — the handle names whose Home holds the code, so a runtime needs only the code + the Home. */
|
|
5
|
+
export declare const PAIRING_CODE_RE: RegExp;
|
|
6
|
+
export declare const pairingHandleOf: (code: string) => string | null;
|
|
7
|
+
/** What the custodian chose when minting — everything the equip step needs except the runtime's key. */
|
|
8
|
+
export interface PairingOptionsV1 {
|
|
9
|
+
member: string;
|
|
10
|
+
workspace: string;
|
|
11
|
+
validForSeconds: number;
|
|
12
|
+
openMandate: string[];
|
|
13
|
+
messagingTo: Address[];
|
|
14
|
+
/** `container` is the app's own Container binding; `poll` = the runtime polls (no host declared). */
|
|
15
|
+
wake: 'container' | 'poll' | {
|
|
16
|
+
url: string;
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
export interface PairingClaimV1 {
|
|
20
|
+
address: Address;
|
|
21
|
+
wake?: RuntimeHostV1 | null;
|
|
22
|
+
agent?: string;
|
|
23
|
+
claimedAt: string;
|
|
24
|
+
}
|
|
25
|
+
export type PairingStateV1 = {
|
|
26
|
+
v: 1;
|
|
27
|
+
code: string;
|
|
28
|
+
state: 'minted';
|
|
29
|
+
options: PairingOptionsV1;
|
|
30
|
+
mintedAt: string;
|
|
31
|
+
expiresAt: string;
|
|
32
|
+
} | {
|
|
33
|
+
v: 1;
|
|
34
|
+
code: string;
|
|
35
|
+
state: 'claimed';
|
|
36
|
+
options: PairingOptionsV1;
|
|
37
|
+
mintedAt: string;
|
|
38
|
+
expiresAt: string;
|
|
39
|
+
claim: PairingClaimV1;
|
|
40
|
+
} | {
|
|
41
|
+
v: 1;
|
|
42
|
+
code: string;
|
|
43
|
+
state: 'completed';
|
|
44
|
+
options: PairingOptionsV1;
|
|
45
|
+
mintedAt: string;
|
|
46
|
+
expiresAt: string;
|
|
47
|
+
claim: PairingClaimV1;
|
|
48
|
+
record: Omit<RuntimeMemberRecordV1, 'key'>;
|
|
49
|
+
completedAt: string;
|
|
50
|
+
} | {
|
|
51
|
+
v: 1;
|
|
52
|
+
code: string;
|
|
53
|
+
state: 'taken';
|
|
54
|
+
options: PairingOptionsV1;
|
|
55
|
+
mintedAt: string;
|
|
56
|
+
expiresAt: string;
|
|
57
|
+
claim: PairingClaimV1;
|
|
58
|
+
completedAt: string;
|
|
59
|
+
takenAt: string;
|
|
60
|
+
};
|
|
61
|
+
//# sourceMappingURL=pairing.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pairing.d.ts","sourceRoot":"","sources":["../src/pairing.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AACpC,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AACzD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD,6HAA6H;AAC7H,eAAO,MAAM,eAAe,QAAoD,CAAC;AACjF,eAAO,MAAM,eAAe,SAAU,MAAM,KAAG,MAAM,GAAG,IAAsD,CAAC;AAE/G,wGAAwG;AACxG,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,MAAM,CAAC;IACxB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,WAAW,EAAE,OAAO,EAAE,CAAC;IACvB,qGAAqG;IACrG,IAAI,EAAE,WAAW,GAAG,MAAM,GAAG;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;CAC9C;AAED,MAAM,WAAW,cAAc;IAAG,OAAO,EAAE,OAAO,CAAC;IAAC,IAAI,CAAC,EAAE,aAAa,GAAG,IAAI,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE;AAEpH,MAAM,MAAM,cAAc,GACtB;IAAE,CAAC,EAAE,CAAC,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,QAAQ,CAAC;IAAC,OAAO,EAAE,gBAAgB,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GACvG;IAAE,CAAC,EAAE,CAAC,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,SAAS,CAAC;IAAC,OAAO,EAAE,gBAAgB,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,cAAc,CAAA;CAAE,GAC/H;IAAE,CAAC,EAAE,CAAC,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,WAAW,CAAC;IAAC,OAAO,EAAE,gBAAgB,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,cAAc,CAAC;IAAC,MAAM,EAAE,IAAI,CAAC,qBAAqB,EAAE,KAAK,CAAC,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,GAClM;IAAE,CAAC,EAAE,CAAC,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,gBAAgB,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,cAAc,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC"}
|
package/dist/pairing.js
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
/** `<handle>-<6 base32 chars>` — the handle names whose Home holds the code, so a runtime needs only the code + the Home. */
|
|
2
|
+
export const PAIRING_CODE_RE = /^([a-z0-9][a-z0-9-]{0,62})-([A-HJ-NP-Z2-9]{6})$/;
|
|
3
|
+
export const pairingHandleOf = (code) => PAIRING_CODE_RE.exec(code.trim())?.[1] ?? null;
|
|
4
|
+
//# sourceMappingURL=pairing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pairing.js","sourceRoot":"","sources":["../src/pairing.ts"],"names":[],"mappings":"AAYA,6HAA6H;AAC7H,MAAM,CAAC,MAAM,eAAe,GAAG,iDAAiD,CAAC;AACjF,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,IAAY,EAAiB,EAAE,CAAC,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC"}
|
package/dist/record.d.ts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export interface RuntimeMemberRecordV1 {
|
|
2
|
+
v: 1;
|
|
3
|
+
/** The member's typed name (`goose-1.svc`) and Smart Agent address. */
|
|
4
|
+
name: string;
|
|
5
|
+
agent: `0x${string}`;
|
|
6
|
+
/** The workspace the runtime belongs to — the organization's typed name and address. */
|
|
7
|
+
workspace: {
|
|
8
|
+
name: string;
|
|
9
|
+
agent: `0x${string}`;
|
|
10
|
+
};
|
|
11
|
+
/** The runtime's own key (hex private key) — generated on this machine; its address is the wire's delegate.
|
|
12
|
+
* Absent from a record that travels (a Container's `AP_RUNTIME_RECORD`): the key then comes from `AP_RUNTIME_KEY`
|
|
13
|
+
* or a signer port, never from the record. */
|
|
14
|
+
key?: `0x${string}`;
|
|
15
|
+
address: `0x${string}`;
|
|
16
|
+
/** The session wire: member SA → this key, pinned to `harness.ask`, signed by the member's custodian. */
|
|
17
|
+
wire: Record<string, unknown>;
|
|
18
|
+
wireRef: `0x${string}`;
|
|
19
|
+
validUntil: number;
|
|
20
|
+
/** The standard A2A surface: `<edge>/api/a2a/<name>` answers for any agent by name; `audience` is its origin. */
|
|
21
|
+
edge: string;
|
|
22
|
+
audience: string;
|
|
23
|
+
/** The agent runtime's host, for the steward-side ops `ap runtime` drives on the member's own object. */
|
|
24
|
+
a2a: string;
|
|
25
|
+
chainId: number;
|
|
26
|
+
/** The Home that minted the wire (for `ap runtime status`, never for a session). */
|
|
27
|
+
home: string;
|
|
28
|
+
joinedAt: string;
|
|
29
|
+
/** Spec 400 W2a — the OPEN MANDATE: a standing grant (member → this key, named capabilities, no intent binding)
|
|
30
|
+
* the custodian signed once; the loop derives a child per parked reply. Absent: every write parks. */
|
|
31
|
+
standing?: import('./standing.js').StandingGrantV1;
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=record.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"record.d.ts","sourceRoot":"","sources":["../src/record.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,qBAAqB;IACpC,CAAC,EAAE,CAAC,CAAC;IACL,uEAAuE;IACvE,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,KAAK,MAAM,EAAE,CAAC;IACrB,wFAAwF;IACxF,SAAS,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,KAAK,MAAM,EAAE,CAAA;KAAE,CAAC;IAClD;;mDAE+C;IAC/C,GAAG,CAAC,EAAE,KAAK,MAAM,EAAE,CAAC;IACpB,OAAO,EAAE,KAAK,MAAM,EAAE,CAAC;IACvB,yGAAyG;IACzG,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9B,OAAO,EAAE,KAAK,MAAM,EAAE,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,iHAAiH;IACjH,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,yGAAyG;IACzG,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,oFAAoF;IACpF,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB;2GACuG;IACvG,QAAQ,CAAC,EAAE,OAAO,eAAe,EAAE,eAAe,CAAC;CACpD"}
|
package/dist/record.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"record.js","sourceRoot":"","sources":["../src/record.ts"],"names":[],"mappings":""}
|
package/dist/run.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type LoopOptions } from './loop.js';
|
|
2
|
+
export interface RunOptions extends LoopOptions {
|
|
3
|
+
pollMs?: number;
|
|
4
|
+
/** Stop after this many turns (tests, gates); default: forever. */
|
|
5
|
+
maxTurns?: number;
|
|
6
|
+
}
|
|
7
|
+
export declare function runRuntimeMember(o: RunOptions): Promise<void>;
|
|
8
|
+
//# sourceMappingURL=run.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../src/run.ts"],"names":[],"mappings":"AAGA,OAAO,EAAqB,KAAK,WAAW,EAAE,MAAM,WAAW,CAAC;AAEhE,MAAM,WAAW,UAAW,SAAQ,WAAW;IAC7C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,mEAAmE;IACnE,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,wBAAsB,gBAAgB,CAAC,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAgBnE"}
|
package/dist/run.js
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
// `ap runtime run` — THE LOOP ON A TIMER (spec 400 §5.3): the laptop shape. Poll the member's own inbox as itself
|
|
2
|
+
// every few seconds and hand each pass to `RuntimeMemberLoop`. The Container shape (`ap runtime serve`, W1c) runs
|
|
3
|
+
// the same loop woken by the Worker instead of by a clock.
|
|
4
|
+
import { RuntimeMemberLoop } from './loop.js';
|
|
5
|
+
export async function runRuntimeMember(o) {
|
|
6
|
+
const loop = new RuntimeMemberLoop(o);
|
|
7
|
+
const log = o.log ?? ((l) => process.stderr.write(`${l}\n`));
|
|
8
|
+
await loop.start();
|
|
9
|
+
log(`polling every ${(o.pollMs ?? 15_000) / 1000}s from cursor ${loop.cursorNow ?? '(start)'}`);
|
|
10
|
+
let turns = 0;
|
|
11
|
+
try {
|
|
12
|
+
while (o.maxTurns === undefined || turns < o.maxTurns) {
|
|
13
|
+
const reports = await loop.pollOnce(o.maxTurns === undefined ? undefined : o.maxTurns - turns);
|
|
14
|
+
turns += reports.length;
|
|
15
|
+
if (o.maxTurns !== undefined && turns >= o.maxTurns)
|
|
16
|
+
break;
|
|
17
|
+
await new Promise((r) => setTimeout(r, o.pollMs ?? 15_000));
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
finally {
|
|
21
|
+
await loop.stop();
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=run.js.map
|
package/dist/run.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run.js","sourceRoot":"","sources":["../src/run.ts"],"names":[],"mappings":"AAAA,kHAAkH;AAClH,kHAAkH;AAClH,2DAA2D;AAC3D,OAAO,EAAE,iBAAiB,EAAoB,MAAM,WAAW,CAAC;AAQhE,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,CAAa;IAClD,MAAM,IAAI,GAAG,IAAI,iBAAiB,CAAC,CAAC,CAAC,CAAC;IACtC,MAAM,GAAG,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;IAC7D,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC;IACnB,GAAG,CAAC,iBAAiB,CAAC,CAAC,CAAC,MAAM,IAAI,MAAM,CAAC,GAAG,IAAI,iBAAiB,IAAI,CAAC,SAAS,IAAI,SAAS,EAAE,CAAC,CAAC;IAChG,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,IAAI,CAAC;QACH,OAAO,CAAC,CAAC,QAAQ,KAAK,SAAS,IAAI,KAAK,GAAG,CAAC,CAAC,QAAQ,EAAE,CAAC;YACtD,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,GAAG,KAAK,CAAC,CAAC;YAC/F,KAAK,IAAI,OAAO,CAAC,MAAM,CAAC;YACxB,IAAI,CAAC,CAAC,QAAQ,KAAK,SAAS,IAAI,KAAK,IAAI,CAAC,CAAC,QAAQ;gBAAE,MAAM;YAC3D,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,CAAC,MAAM,IAAI,MAAM,CAAC,CAAC,CAAC;QAC9D,CAAC;IACH,CAAC;YAAS,CAAC;QACT,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC;IACpB,CAAC;AACH,CAAC"}
|
package/dist/serve.d.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { type Server } from 'node:http';
|
|
2
|
+
import { RuntimeMemberLoop, type LoopOptions, type TurnReport } from './loop.js';
|
|
3
|
+
export interface ServeOptions extends LoopOptions {
|
|
4
|
+
port?: number;
|
|
5
|
+
host?: string;
|
|
6
|
+
/** A slow safety pass in case a wake is lost (Queues are at-least-once; default: none). */
|
|
7
|
+
fallbackPollMs?: number;
|
|
8
|
+
}
|
|
9
|
+
export interface WakeRequestV1 {
|
|
10
|
+
v?: 1;
|
|
11
|
+
member?: string;
|
|
12
|
+
conversationId?: string;
|
|
13
|
+
messageId?: string;
|
|
14
|
+
}
|
|
15
|
+
export interface WakeReplyV1 {
|
|
16
|
+
ok: true;
|
|
17
|
+
member: string;
|
|
18
|
+
cursor: string | null;
|
|
19
|
+
turns: TurnReport[];
|
|
20
|
+
}
|
|
21
|
+
export declare function serveRuntimeMember(o: ServeOptions): Promise<{
|
|
22
|
+
server: Server;
|
|
23
|
+
loop: RuntimeMemberLoop;
|
|
24
|
+
close: () => Promise<void>;
|
|
25
|
+
}>;
|
|
26
|
+
//# sourceMappingURL=serve.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"serve.d.ts","sourceRoot":"","sources":["../src/serve.ts"],"names":[],"mappings":"AAQA,OAAO,EAAgB,KAAK,MAAM,EAAE,MAAM,WAAW,CAAC;AACtD,OAAO,EAAE,iBAAiB,EAAE,KAAK,WAAW,EAAE,KAAK,UAAU,EAAE,MAAM,WAAW,CAAC;AAEjF,MAAM,WAAW,YAAa,SAAQ,WAAW;IAC/C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,2FAA2F;IAC3F,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,aAAa;IAAG,CAAC,CAAC,EAAE,CAAC,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE;AACtG,MAAM,WAAW,WAAW;IAAG,EAAE,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,KAAK,EAAE,UAAU,EAAE,CAAA;CAAE;AAErG,wBAAsB,kBAAkB,CAAC,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,iBAAiB,CAAC;IAAC,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;CAAE,CAAC,CA2B1I"}
|
package/dist/serve.js
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
// `ap runtime serve` — THE LOOP WOKEN, NOT CLOCKED (spec 400 W1c): the Container shape. The Worker's queue consumer
|
|
2
|
+
// calls `POST /wake {member, conversationId, messageId}` after a message is ADMITTED into the member's inbox; this
|
|
3
|
+
// host runs one pass of the same loop the laptop runs on a timer and answers with the turn reports, which the Worker
|
|
4
|
+
// keeps as the wake's receipt. The wake carries no content and no authority — the loop reads the message itself,
|
|
5
|
+
// under its own wire; a stray wake costs one inbox read and finds nothing new.
|
|
6
|
+
//
|
|
7
|
+
// The Worker never speaks ACP: stdio stays between this process and the agent it spawned. The Container never IS the
|
|
8
|
+
// identity: the wire is the custodian's to revoke, and after that every read here is refused.
|
|
9
|
+
import { createServer } from 'node:http';
|
|
10
|
+
import { RuntimeMemberLoop } from './loop.js';
|
|
11
|
+
export async function serveRuntimeMember(o) {
|
|
12
|
+
const loop = new RuntimeMemberLoop({ ...o, woken: true });
|
|
13
|
+
const log = o.log ?? ((l) => process.stderr.write(`${l}\n`));
|
|
14
|
+
await loop.start();
|
|
15
|
+
const server = createServer(async (req, res) => {
|
|
16
|
+
const reply = (status, body) => { res.writeHead(status, { 'content-type': 'application/json' }); res.end(JSON.stringify(body)); };
|
|
17
|
+
if (req.method === 'GET' && req.url === '/healthz')
|
|
18
|
+
return reply(200, { ok: true, member: loop.rec.name, cursor: loop.cursorNow ?? null });
|
|
19
|
+
if (req.method === 'POST' && req.url === '/wake') {
|
|
20
|
+
let raw = '';
|
|
21
|
+
for await (const c of req)
|
|
22
|
+
raw += c;
|
|
23
|
+
let wake = {};
|
|
24
|
+
try {
|
|
25
|
+
wake = raw ? JSON.parse(raw) : {};
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
return reply(400, { error: 'wake body is not JSON' });
|
|
29
|
+
}
|
|
30
|
+
if (wake.member && wake.member !== loop.rec.name)
|
|
31
|
+
return reply(404, { error: `this host serves ${loop.rec.name}, not ${wake.member}` });
|
|
32
|
+
log(`wake${wake.messageId ? ` for ${wake.messageId}` : ''}${wake.conversationId ? ` in ${wake.conversationId}` : ''}`);
|
|
33
|
+
const turns = await loop.pollOnce(undefined, { ...(wake.messageId ? { messageId: wake.messageId } : {}) }).catch((e) => { log(` pass failed: ${e.message}`); return null; });
|
|
34
|
+
if (!turns)
|
|
35
|
+
return reply(502, { error: 'the pass failed — see the host log' });
|
|
36
|
+
const out = { ok: true, member: loop.rec.name, cursor: loop.cursorNow ?? null, turns };
|
|
37
|
+
return reply(200, out);
|
|
38
|
+
}
|
|
39
|
+
reply(404, { error: 'POST /wake or GET /healthz' });
|
|
40
|
+
});
|
|
41
|
+
await new Promise((r) => server.listen(o.port ?? 8080, o.host ?? '0.0.0.0', r));
|
|
42
|
+
const addr = server.address();
|
|
43
|
+
log(`${loop.rec.name} serving wakes on ${typeof addr === 'object' && addr ? `${addr.address}:${addr.port}` : String(addr)}`);
|
|
44
|
+
const timer = o.fallbackPollMs ? setInterval(() => { void loop.pollOnce().catch(() => undefined); }, o.fallbackPollMs) : null;
|
|
45
|
+
return {
|
|
46
|
+
server, loop,
|
|
47
|
+
close: async () => { if (timer)
|
|
48
|
+
clearInterval(timer); await new Promise((r) => server.close(() => r())); await loop.stop(); },
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=serve.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"serve.js","sourceRoot":"","sources":["../src/serve.ts"],"names":[],"mappings":"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"}
|