@tokenfactory/acc-runner 0.40.8 → 0.40.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/chat-transport.d.ts +8 -0
- package/dist/chat-transport.d.ts.map +1 -1
- package/dist/chat-transport.js +24 -4
- package/dist/chat-transport.js.map +1 -1
- package/dist/companion-identity.d.ts +144 -0
- package/dist/companion-identity.d.ts.map +1 -0
- package/dist/companion-identity.js +189 -0
- package/dist/companion-identity.js.map +1 -0
- package/dist/companion-run.d.ts +6 -1
- package/dist/companion-run.d.ts.map +1 -1
- package/dist/companion-run.js +103 -28
- package/dist/companion-run.js.map +1 -1
- package/dist/companion.d.ts +70 -2
- package/dist/companion.d.ts.map +1 -1
- package/dist/companion.js +150 -11
- package/dist/companion.js.map +1 -1
- package/dist/runtime/auth-lifecycle.d.ts +61 -0
- package/dist/runtime/auth-lifecycle.d.ts.map +1 -0
- package/dist/runtime/auth-lifecycle.js +120 -0
- package/dist/runtime/auth-lifecycle.js.map +1 -0
- package/dist/watch.d.ts +2 -21
- package/dist/watch.d.ts.map +1 -1
- package/dist/watch.js +5 -111
- package/dist/watch.js.map +1 -1
- package/package.json +1 -1
package/dist/chat-transport.d.ts
CHANGED
|
@@ -62,6 +62,14 @@ export interface SupabaseChatTransportOptions {
|
|
|
62
62
|
*/
|
|
63
63
|
export declare function createSupabaseChatTransport(client: RunnerSupabaseClient, opts?: SupabaseChatTransportOptions): ChatLaneTransport & {
|
|
64
64
|
close: () => Promise<void>;
|
|
65
|
+
/**
|
|
66
|
+
* AUTH-REFRESH: hot-swap the Supabase client (and,
|
|
67
|
+
* optionally, the durable-ingest bearer) after a token refresh. Old
|
|
68
|
+
* per-conversation channels are torn down so the next stream frame re-subscribes
|
|
69
|
+
* on the fresh socket — turn-serving keeps working across a rotation instead of
|
|
70
|
+
* riding the old, soon-to-expire JWT until the process restarts.
|
|
71
|
+
*/
|
|
72
|
+
refreshClient: (nextClient: RunnerSupabaseClient, nextIngestToken?: string) => Promise<void>;
|
|
65
73
|
};
|
|
66
74
|
export {};
|
|
67
75
|
//# sourceMappingURL=chat-transport.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chat-transport.d.ts","sourceRoot":"","sources":["../src/chat-transport.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AAC1D,OAAO,EAEL,KAAK,iBAAiB,EAItB,KAAK,eAAe,EACrB,MAAM,gBAAgB,CAAC;AAgBxB,0EAA0E;AAC1E,UAAU,WAAW;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,eAAe,EAAE,MAAM,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;CACjC;AAED,sFAAsF;AACtF,wBAAgB,cAAc,CAAC,GAAG,EAAE,WAAW,GAAG,eAAe,CAahE;AAED,MAAM,WAAW,4BAA4B;IAC3C,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/B;;;;;;;;;OASG;IACH,MAAM,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IACxC,wDAAwD;IACxD,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;CAC1B;AAED;;;;GAIG;AACH,wBAAgB,2BAA2B,CACzC,MAAM,EAAE,oBAAoB,EAC5B,IAAI,GAAE,4BAAiC,GACtC,iBAAiB,GAAG;
|
|
1
|
+
{"version":3,"file":"chat-transport.d.ts","sourceRoot":"","sources":["../src/chat-transport.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AAC1D,OAAO,EAEL,KAAK,iBAAiB,EAItB,KAAK,eAAe,EACrB,MAAM,gBAAgB,CAAC;AAgBxB,0EAA0E;AAC1E,UAAU,WAAW;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,eAAe,EAAE,MAAM,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;CACjC;AAED,sFAAsF;AACtF,wBAAgB,cAAc,CAAC,GAAG,EAAE,WAAW,GAAG,eAAe,CAahE;AAED,MAAM,WAAW,4BAA4B;IAC3C,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/B;;;;;;;;;OASG;IACH,MAAM,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IACxC,wDAAwD;IACxD,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;CAC1B;AAED;;;;GAIG;AACH,wBAAgB,2BAA2B,CACzC,MAAM,EAAE,oBAAoB,EAC5B,IAAI,GAAE,4BAAiC,GACtC,iBAAiB,GAAG;IACrB,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3B;;;;;;OAMG;IACH,aAAa,EAAE,CAAC,UAAU,EAAE,oBAAoB,EAAE,eAAe,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9F,CAsJA"}
|
package/dist/chat-transport.js
CHANGED
|
@@ -22,6 +22,10 @@ export function mapClaimedTurn(row) {
|
|
|
22
22
|
export function createSupabaseChatTransport(client, opts = {}) {
|
|
23
23
|
const now = opts.now ?? Date.now;
|
|
24
24
|
const doFetch = opts.fetchImpl ?? globalThis.fetch;
|
|
25
|
+
// AUTH-REFRESH: the client + ingest bearer are mutable so a token refresh can
|
|
26
|
+
// swap them in place (see refreshClient). Closures below read the live values.
|
|
27
|
+
let liveClient = client;
|
|
28
|
+
let ingestToken = opts.ingest?.token;
|
|
25
29
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
26
30
|
const channels = new Map(); // any-allowed: supabase RealtimeChannel type is not re-exported by the schema-scoped client
|
|
27
31
|
async function channelFor(conversationId) {
|
|
@@ -29,7 +33,7 @@ export function createSupabaseChatTransport(client, opts = {}) {
|
|
|
29
33
|
const existing = channels.get(conversationId);
|
|
30
34
|
if (existing)
|
|
31
35
|
return existing;
|
|
32
|
-
const ch =
|
|
36
|
+
const ch = liveClient.channel(topic);
|
|
33
37
|
channels.set(conversationId, ch);
|
|
34
38
|
await new Promise((resolve) => {
|
|
35
39
|
ch.subscribe((status) => {
|
|
@@ -77,7 +81,7 @@ export function createSupabaseChatTransport(client, opts = {}) {
|
|
|
77
81
|
method: "POST",
|
|
78
82
|
headers: {
|
|
79
83
|
"Content-Type": "application/json",
|
|
80
|
-
Authorization: `Bearer ${opts.ingest.token}`,
|
|
84
|
+
Authorization: `Bearer ${ingestToken ?? opts.ingest.token}`,
|
|
81
85
|
},
|
|
82
86
|
body: JSON.stringify({
|
|
83
87
|
event,
|
|
@@ -97,7 +101,7 @@ export function createSupabaseChatTransport(client, opts = {}) {
|
|
|
97
101
|
}
|
|
98
102
|
return {
|
|
99
103
|
async claim(args) {
|
|
100
|
-
const { data, error } = await
|
|
104
|
+
const { data, error } = await liveClient.rpc("claim_chat_turn", {
|
|
101
105
|
p_conversation_id: args.conversationId,
|
|
102
106
|
p_runner_id: args.runnerId,
|
|
103
107
|
p_engine_id: args.engineId,
|
|
@@ -124,7 +128,7 @@ export function createSupabaseChatTransport(client, opts = {}) {
|
|
|
124
128
|
async close() {
|
|
125
129
|
for (const ch of channels.values()) {
|
|
126
130
|
try {
|
|
127
|
-
await
|
|
131
|
+
await liveClient.removeChannel(ch);
|
|
128
132
|
}
|
|
129
133
|
catch {
|
|
130
134
|
/* best-effort teardown */
|
|
@@ -132,6 +136,22 @@ export function createSupabaseChatTransport(client, opts = {}) {
|
|
|
132
136
|
}
|
|
133
137
|
channels.clear();
|
|
134
138
|
},
|
|
139
|
+
async refreshClient(nextClient, nextIngestToken) {
|
|
140
|
+
// Tear the old channels down on the OLD client (they carry the stale JWT),
|
|
141
|
+
// then swap. The next stream/complete re-subscribes on the fresh socket.
|
|
142
|
+
for (const ch of channels.values()) {
|
|
143
|
+
try {
|
|
144
|
+
await liveClient.removeChannel(ch);
|
|
145
|
+
}
|
|
146
|
+
catch {
|
|
147
|
+
/* best-effort teardown */
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
channels.clear();
|
|
151
|
+
liveClient = nextClient;
|
|
152
|
+
if (nextIngestToken !== undefined)
|
|
153
|
+
ingestToken = nextIngestToken;
|
|
154
|
+
},
|
|
135
155
|
};
|
|
136
156
|
}
|
|
137
157
|
//# sourceMappingURL=chat-transport.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chat-transport.js","sourceRoot":"","sources":["../src/chat-transport.ts"],"names":[],"mappings":"AAqBA,OAAO,EACL,0BAA0B,GAM3B,MAAM,gBAAgB,CAAC;AA8BxB,sFAAsF;AACtF,MAAM,UAAU,cAAc,CAAC,GAAgB;IAC7C,OAAO;QACL,EAAE,EAAE,GAAG,CAAC,EAAE;QACV,eAAe,EAAE,GAAG,CAAC,eAAe;QACpC,MAAM,EAAE,GAAG,CAAC,MAAM;QAClB,YAAY,EAAE,GAAG,CAAC,YAAY;QAC9B,MAAM,EAAE,GAAG,CAAC,MAAM,IAAI,EAAE;QACxB,IAAI,EAAE,CAAC,GAAG,CAAC,IAAI,IAAI,MAAM,CAAyB;QAClD,SAAS,EAAE,GAAG,CAAC,SAAS,IAAI,EAAE;QAC9B,SAAS,EAAE,GAAG,CAAC,SAAS,IAAI,EAAE;QAC9B,aAAa,EAAE,GAAG,CAAC,aAAa,IAAI,CAAC;QACrC,gBAAgB,EAAE,GAAG,CAAC,gBAAgB;KACvC,CAAC;AACJ,CAAC;AAoBD;;;;GAIG;AACH,MAAM,UAAU,2BAA2B,CACzC,MAA4B,EAC5B,OAAqC,EAAE;
|
|
1
|
+
{"version":3,"file":"chat-transport.js","sourceRoot":"","sources":["../src/chat-transport.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* COMPANION-IDENTITY-DISCOVERY: self-discovery + honest binding of the
|
|
3
|
+
* companion's enrollment identity.
|
|
4
|
+
*
|
|
5
|
+
* The bug this fixes: plain `acc-runner companion` (what the post-ENROLL-FIX
|
|
6
|
+
* enrollment guidance tells the operator to run) only ever bound an identity —
|
|
7
|
+
* and therefore only ever wrote `runner_ids` / `probe_tier` — when the operator
|
|
8
|
+
* had hand-set `ACC_RUNNER_COMPANION_IDENTITY`. Nothing anywhere mentioned that
|
|
9
|
+
* env var, so the flagless command came online GREEN-AND-SILENT while never
|
|
10
|
+
* serving provider status. Third seam defect in this flow.
|
|
11
|
+
*
|
|
12
|
+
* The fix has three pure pieces, all here so they are exercised without a
|
|
13
|
+
* network, a `claude` binary, or the live-wiring in companion-run.ts:
|
|
14
|
+
*
|
|
15
|
+
* 1. `discoverCompanionIdentities` — the authenticated GET /api/identities/
|
|
16
|
+
* discover call. It is ALSO the pre-online SESSION PING: a dead/expired
|
|
17
|
+
* session yields 401/403 and `sessionOk:false`, which is what lets the CLI
|
|
18
|
+
* refuse to print "online" on a zombie session.
|
|
19
|
+
* 2. `resolveBinding` — turn the discovery outcome (+ optional env override)
|
|
20
|
+
* into a binding decision: exactly one match ⇒ bound; multiple ⇒ unbound +
|
|
21
|
+
* list; zero ⇒ unbound + "no enrollment"; unreachable ⇒ unbound + degraded.
|
|
22
|
+
* 3. `companionBanner` — the HONESTY invariant: a bound companion gets a green
|
|
23
|
+
* headline naming the bound identity; anything else gets a yellow headline
|
|
24
|
+
* that literally contains "UNBOUND". `tone === "ok"` iff `binding.kind ===
|
|
25
|
+
* "bound"`, so green-and-silent-while-unbound is structurally impossible.
|
|
26
|
+
*
|
|
27
|
+
* The env var stays as a documented override (a machine with more than one
|
|
28
|
+
* enrolled subscription of the same engine picks one explicitly).
|
|
29
|
+
*/
|
|
30
|
+
/** One owner-bound companion identity the runner may serve. */
|
|
31
|
+
export interface DiscoveredIdentity {
|
|
32
|
+
id: string;
|
|
33
|
+
provider: string;
|
|
34
|
+
engine: string;
|
|
35
|
+
status: string;
|
|
36
|
+
/** null ⇒ pending (never probed); set ⇒ already adopted/probed. */
|
|
37
|
+
lastProbeAt: string | null;
|
|
38
|
+
}
|
|
39
|
+
/** The outcome of the discovery call — matches plus session/reachability facts. */
|
|
40
|
+
export interface DiscoveryOutcome {
|
|
41
|
+
/** False ONLY when the registry rejected the token (401/403). Refuse to come online. */
|
|
42
|
+
sessionOk: boolean;
|
|
43
|
+
/** False when the registry could not be reached / returned a non-auth error. */
|
|
44
|
+
reachable: boolean;
|
|
45
|
+
/** Owner-bound companion identities matching (owner, provider?, engine?). */
|
|
46
|
+
matches: DiscoveredIdentity[];
|
|
47
|
+
/** Best-effort human note (never key material). */
|
|
48
|
+
detail?: string;
|
|
49
|
+
}
|
|
50
|
+
/** The runner's binding decision. */
|
|
51
|
+
export type IdentityBinding = {
|
|
52
|
+
kind: "bound";
|
|
53
|
+
identityId: string;
|
|
54
|
+
/** The discovered row when known (null for a blind env override). */
|
|
55
|
+
identity: DiscoveredIdentity | null;
|
|
56
|
+
source: "discovery" | "override";
|
|
57
|
+
} | {
|
|
58
|
+
kind: "unbound";
|
|
59
|
+
reason: "no_enrollment" | "multiple" | "unreachable";
|
|
60
|
+
/** Candidate rows to show the operator (populated for `multiple`). */
|
|
61
|
+
matches: DiscoveredIdentity[];
|
|
62
|
+
};
|
|
63
|
+
/**
|
|
64
|
+
* Best-effort engine → LLM provider map, used only to NARROW discovery to the
|
|
65
|
+
* caller's rows for that provider. Unknown engines omit the provider filter (the
|
|
66
|
+
* server then matches on owner + engine alone), so this is advisory, never a gate.
|
|
67
|
+
*/
|
|
68
|
+
export declare function providerForEngine(engineId: string): string | undefined;
|
|
69
|
+
/** Injected deps for the discovery call (fetch is a seam for tests). */
|
|
70
|
+
export interface DiscoverDeps {
|
|
71
|
+
publicUrl: string;
|
|
72
|
+
accessToken: string;
|
|
73
|
+
engineId: string;
|
|
74
|
+
provider?: string;
|
|
75
|
+
fetchImpl?: typeof fetch;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Call GET /api/identities/discover under the runner's session. This doubles as
|
|
79
|
+
* the pre-online session ping: a 401/403 is a dead session (`sessionOk:false`),
|
|
80
|
+
* a network error or non-auth HTTP error is "unreachable" (`reachable:false`,
|
|
81
|
+
* but `sessionOk:true` — we cannot disprove the session), and a 200 returns the
|
|
82
|
+
* matching owner-bound companion identities.
|
|
83
|
+
*/
|
|
84
|
+
export declare function discoverCompanionIdentities(deps: DiscoverDeps): Promise<DiscoveryOutcome>;
|
|
85
|
+
/**
|
|
86
|
+
* Decide the binding from the discovery outcome and the optional env override.
|
|
87
|
+
* The override ALWAYS wins (escape hatch) once the session is known-good; it
|
|
88
|
+
* binds even to an id not in `matches` (a blind bind), because an operator who
|
|
89
|
+
* hand-sets the id has authoritatively chosen it. Callers must first check
|
|
90
|
+
* `outcome.sessionOk` — this function assumes the session ping already passed.
|
|
91
|
+
*/
|
|
92
|
+
export declare function resolveBinding(outcome: DiscoveryOutcome, override: string | undefined | null): IdentityBinding;
|
|
93
|
+
/**
|
|
94
|
+
* The registration payload the companion reports once bound: which runner is
|
|
95
|
+
* serving which identity, at what probed tier + capacity. `tier`/`capacity` are
|
|
96
|
+
* kept as plain strings so this module stays free of the engine capability
|
|
97
|
+
* enums (companion-run.ts passes the narrower union values through).
|
|
98
|
+
*/
|
|
99
|
+
export interface ProbeReportPayload {
|
|
100
|
+
identityId: string;
|
|
101
|
+
runnerId: string;
|
|
102
|
+
tier: string | null;
|
|
103
|
+
capacity: string;
|
|
104
|
+
}
|
|
105
|
+
/** Injected deps for the probe POST (fetch is a transport seam only). */
|
|
106
|
+
export interface ReportProbeDeps {
|
|
107
|
+
publicUrl: string;
|
|
108
|
+
accessToken: string;
|
|
109
|
+
fetchImpl?: typeof fetch;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* POST the companion registration to /api/identities/probe. This is the WRITE
|
|
113
|
+
* side of the bind: the server folds `tier` into `probe_tier`/`last_probe_at`
|
|
114
|
+
* (via acc.set_ai_identity_probe) and unions `runnerId` into the identity's
|
|
115
|
+
* `runner_ids` roster — the two columns that, left NULL/empty, made the flagless
|
|
116
|
+
* companion come online green-and-silent while provider-status could never
|
|
117
|
+
* confirm it. Shared by companion-run.ts (production) and the write-path test so
|
|
118
|
+
* the exact same request is exercised in both. Throws on a non-2xx response so
|
|
119
|
+
* CompanionRunner's registration-persist catch can log it (best-effort).
|
|
120
|
+
*/
|
|
121
|
+
export declare function reportIdentityProbe(deps: ReportProbeDeps, payload: ProbeReportPayload): Promise<void>;
|
|
122
|
+
/** The env var whose presence overrides self-discovery with an explicit id. */
|
|
123
|
+
export declare const COMPANION_IDENTITY_OVERRIDE_HINT = "ACC_RUNNER_COMPANION_IDENTITY";
|
|
124
|
+
export type BannerTone = "ok" | "warn";
|
|
125
|
+
/** A rendered (but colour-free) startup banner — the caller applies chalk. */
|
|
126
|
+
export interface CompanionBanner {
|
|
127
|
+
tone: BannerTone;
|
|
128
|
+
/** The single headline line. `tone==="ok"` iff the companion is bound. */
|
|
129
|
+
headline: string;
|
|
130
|
+
/** Follow-up guidance lines (empty for a clean bound start). */
|
|
131
|
+
lines: string[];
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Build the startup banner. HONESTY invariant (asserted by the tests):
|
|
135
|
+
* - a BOUND companion → tone "ok", headline names the bound identity id;
|
|
136
|
+
* - ANY unbound state → tone "warn", headline CONTAINS "UNBOUND" and the
|
|
137
|
+
* words "not serving provider status".
|
|
138
|
+
* There is no path to a green headline that does not name a bound identity, so a
|
|
139
|
+
* green-and-silent-while-unbound banner cannot be produced.
|
|
140
|
+
*/
|
|
141
|
+
export declare function companionBanner(binding: IdentityBinding, ctx: {
|
|
142
|
+
email: string;
|
|
143
|
+
}): CompanionBanner;
|
|
144
|
+
//# sourceMappingURL=companion-identity.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"companion-identity.d.ts","sourceRoot":"","sources":["../src/companion-identity.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,+DAA+D;AAC/D,MAAM,WAAW,kBAAkB;IACjC,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,mEAAmE;IACnE,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAED,mFAAmF;AACnF,MAAM,WAAW,gBAAgB;IAC/B,wFAAwF;IACxF,SAAS,EAAE,OAAO,CAAC;IACnB,gFAAgF;IAChF,SAAS,EAAE,OAAO,CAAC;IACnB,6EAA6E;IAC7E,OAAO,EAAE,kBAAkB,EAAE,CAAC;IAC9B,mDAAmD;IACnD,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,qCAAqC;AACrC,MAAM,MAAM,eAAe,GACvB;IACE,IAAI,EAAE,OAAO,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,qEAAqE;IACrE,QAAQ,EAAE,kBAAkB,GAAG,IAAI,CAAC;IACpC,MAAM,EAAE,WAAW,GAAG,UAAU,CAAC;CAClC,GACD;IACE,IAAI,EAAE,SAAS,CAAC;IAChB,MAAM,EAAE,eAAe,GAAG,UAAU,GAAG,aAAa,CAAC;IACrD,sEAAsE;IACtE,OAAO,EAAE,kBAAkB,EAAE,CAAC;CAC/B,CAAC;AAEN;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAWtE;AAED,wEAAwE;AACxE,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;CAC1B;AAUD;;;;;;GAMG;AACH,wBAAsB,2BAA2B,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAyC/F;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAC5B,OAAO,EAAE,gBAAgB,EACzB,QAAQ,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,GAClC,eAAe,CAiBjB;AAED;;;;;GAKG;AACH,MAAM,WAAW,kBAAkB;IACjC,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,yEAAyE;AACzE,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;CAC1B;AAED;;;;;;;;;GASG;AACH,wBAAsB,mBAAmB,CACvC,IAAI,EAAE,eAAe,EACrB,OAAO,EAAE,kBAAkB,GAC1B,OAAO,CAAC,IAAI,CAAC,CAoBf;AAED,+EAA+E;AAC/E,eAAO,MAAM,gCAAgC,kCAAkC,CAAC;AAEhF,MAAM,MAAM,UAAU,GAAG,IAAI,GAAG,MAAM,CAAC;AAEvC,8EAA8E;AAC9E,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,UAAU,CAAC;IACjB,0EAA0E;IAC1E,QAAQ,EAAE,MAAM,CAAC;IACjB,gEAAgE;IAChE,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAQD;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAC7B,OAAO,EAAE,eAAe,EACxB,GAAG,EAAE;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,GACrB,eAAe,CAqCjB"}
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* COMPANION-IDENTITY-DISCOVERY: self-discovery + honest binding of the
|
|
3
|
+
* companion's enrollment identity.
|
|
4
|
+
*
|
|
5
|
+
* The bug this fixes: plain `acc-runner companion` (what the post-ENROLL-FIX
|
|
6
|
+
* enrollment guidance tells the operator to run) only ever bound an identity —
|
|
7
|
+
* and therefore only ever wrote `runner_ids` / `probe_tier` — when the operator
|
|
8
|
+
* had hand-set `ACC_RUNNER_COMPANION_IDENTITY`. Nothing anywhere mentioned that
|
|
9
|
+
* env var, so the flagless command came online GREEN-AND-SILENT while never
|
|
10
|
+
* serving provider status. Third seam defect in this flow.
|
|
11
|
+
*
|
|
12
|
+
* The fix has three pure pieces, all here so they are exercised without a
|
|
13
|
+
* network, a `claude` binary, or the live-wiring in companion-run.ts:
|
|
14
|
+
*
|
|
15
|
+
* 1. `discoverCompanionIdentities` — the authenticated GET /api/identities/
|
|
16
|
+
* discover call. It is ALSO the pre-online SESSION PING: a dead/expired
|
|
17
|
+
* session yields 401/403 and `sessionOk:false`, which is what lets the CLI
|
|
18
|
+
* refuse to print "online" on a zombie session.
|
|
19
|
+
* 2. `resolveBinding` — turn the discovery outcome (+ optional env override)
|
|
20
|
+
* into a binding decision: exactly one match ⇒ bound; multiple ⇒ unbound +
|
|
21
|
+
* list; zero ⇒ unbound + "no enrollment"; unreachable ⇒ unbound + degraded.
|
|
22
|
+
* 3. `companionBanner` — the HONESTY invariant: a bound companion gets a green
|
|
23
|
+
* headline naming the bound identity; anything else gets a yellow headline
|
|
24
|
+
* that literally contains "UNBOUND". `tone === "ok"` iff `binding.kind ===
|
|
25
|
+
* "bound"`, so green-and-silent-while-unbound is structurally impossible.
|
|
26
|
+
*
|
|
27
|
+
* The env var stays as a documented override (a machine with more than one
|
|
28
|
+
* enrolled subscription of the same engine picks one explicitly).
|
|
29
|
+
*/
|
|
30
|
+
/**
|
|
31
|
+
* Best-effort engine → LLM provider map, used only to NARROW discovery to the
|
|
32
|
+
* caller's rows for that provider. Unknown engines omit the provider filter (the
|
|
33
|
+
* server then matches on owner + engine alone), so this is advisory, never a gate.
|
|
34
|
+
*/
|
|
35
|
+
export function providerForEngine(engineId) {
|
|
36
|
+
switch ((engineId ?? "").trim()) {
|
|
37
|
+
case "claude-code":
|
|
38
|
+
return "anthropic";
|
|
39
|
+
case "codex":
|
|
40
|
+
return "openai";
|
|
41
|
+
case "gemini":
|
|
42
|
+
return "google";
|
|
43
|
+
default:
|
|
44
|
+
return undefined;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Call GET /api/identities/discover under the runner's session. This doubles as
|
|
49
|
+
* the pre-online session ping: a 401/403 is a dead session (`sessionOk:false`),
|
|
50
|
+
* a network error or non-auth HTTP error is "unreachable" (`reachable:false`,
|
|
51
|
+
* but `sessionOk:true` — we cannot disprove the session), and a 200 returns the
|
|
52
|
+
* matching owner-bound companion identities.
|
|
53
|
+
*/
|
|
54
|
+
export async function discoverCompanionIdentities(deps) {
|
|
55
|
+
const base = (deps.publicUrl ?? "").replace(/\/+$/, "");
|
|
56
|
+
const params = new URLSearchParams();
|
|
57
|
+
if (deps.engineId)
|
|
58
|
+
params.set("engine", deps.engineId);
|
|
59
|
+
if (deps.provider)
|
|
60
|
+
params.set("provider", deps.provider);
|
|
61
|
+
const url = `${base}/api/identities/discover${params.toString() ? `?${params.toString()}` : ""}`;
|
|
62
|
+
const f = deps.fetchImpl ?? fetch;
|
|
63
|
+
let res;
|
|
64
|
+
try {
|
|
65
|
+
res = await f(url, { headers: { Authorization: `Bearer ${deps.accessToken}` } });
|
|
66
|
+
}
|
|
67
|
+
catch (err) {
|
|
68
|
+
return { sessionOk: true, reachable: false, matches: [], detail: err.message };
|
|
69
|
+
}
|
|
70
|
+
if (res.status === 401 || res.status === 403) {
|
|
71
|
+
return { sessionOk: false, reachable: true, matches: [], detail: `discover HTTP ${res.status}` };
|
|
72
|
+
}
|
|
73
|
+
if (!res.ok) {
|
|
74
|
+
return { sessionOk: true, reachable: false, matches: [], detail: `discover HTTP ${res.status}` };
|
|
75
|
+
}
|
|
76
|
+
const json = (await res.json().catch(() => null));
|
|
77
|
+
if (!json || json.ok !== true || !Array.isArray(json.matches)) {
|
|
78
|
+
return { sessionOk: true, reachable: false, matches: [], detail: "malformed discover response" };
|
|
79
|
+
}
|
|
80
|
+
const matches = json.matches
|
|
81
|
+
.filter((m) => !!m && typeof m === "object")
|
|
82
|
+
.map((m) => ({
|
|
83
|
+
id: String(m.id ?? ""),
|
|
84
|
+
provider: String(m.provider ?? ""),
|
|
85
|
+
engine: String(m.engine ?? ""),
|
|
86
|
+
status: String(m.status ?? ""),
|
|
87
|
+
lastProbeAt: typeof m.last_probe_at === "string" ? m.last_probe_at : null,
|
|
88
|
+
}))
|
|
89
|
+
.filter((m) => m.id);
|
|
90
|
+
return { sessionOk: true, reachable: true, matches };
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Decide the binding from the discovery outcome and the optional env override.
|
|
94
|
+
* The override ALWAYS wins (escape hatch) once the session is known-good; it
|
|
95
|
+
* binds even to an id not in `matches` (a blind bind), because an operator who
|
|
96
|
+
* hand-sets the id has authoritatively chosen it. Callers must first check
|
|
97
|
+
* `outcome.sessionOk` — this function assumes the session ping already passed.
|
|
98
|
+
*/
|
|
99
|
+
export function resolveBinding(outcome, override) {
|
|
100
|
+
const ov = (override ?? "").trim();
|
|
101
|
+
if (ov) {
|
|
102
|
+
const identity = outcome.matches.find((m) => m.id === ov) ?? null;
|
|
103
|
+
return { kind: "bound", identityId: ov, identity, source: "override" };
|
|
104
|
+
}
|
|
105
|
+
if (!outcome.reachable) {
|
|
106
|
+
return { kind: "unbound", reason: "unreachable", matches: [] };
|
|
107
|
+
}
|
|
108
|
+
if (outcome.matches.length === 1) {
|
|
109
|
+
const only = outcome.matches[0];
|
|
110
|
+
return { kind: "bound", identityId: only.id, identity: only, source: "discovery" };
|
|
111
|
+
}
|
|
112
|
+
if (outcome.matches.length === 0) {
|
|
113
|
+
return { kind: "unbound", reason: "no_enrollment", matches: [] };
|
|
114
|
+
}
|
|
115
|
+
return { kind: "unbound", reason: "multiple", matches: outcome.matches };
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* POST the companion registration to /api/identities/probe. This is the WRITE
|
|
119
|
+
* side of the bind: the server folds `tier` into `probe_tier`/`last_probe_at`
|
|
120
|
+
* (via acc.set_ai_identity_probe) and unions `runnerId` into the identity's
|
|
121
|
+
* `runner_ids` roster — the two columns that, left NULL/empty, made the flagless
|
|
122
|
+
* companion come online green-and-silent while provider-status could never
|
|
123
|
+
* confirm it. Shared by companion-run.ts (production) and the write-path test so
|
|
124
|
+
* the exact same request is exercised in both. Throws on a non-2xx response so
|
|
125
|
+
* CompanionRunner's registration-persist catch can log it (best-effort).
|
|
126
|
+
*/
|
|
127
|
+
export async function reportIdentityProbe(deps, payload) {
|
|
128
|
+
const url = `${(deps.publicUrl ?? "").replace(/\/+$/, "")}/api/identities/probe`;
|
|
129
|
+
const f = deps.fetchImpl ?? fetch;
|
|
130
|
+
const res = await f(url, {
|
|
131
|
+
method: "POST",
|
|
132
|
+
headers: {
|
|
133
|
+
"Content-Type": "application/json",
|
|
134
|
+
Authorization: `Bearer ${deps.accessToken}`,
|
|
135
|
+
},
|
|
136
|
+
body: JSON.stringify({
|
|
137
|
+
identity_id: payload.identityId,
|
|
138
|
+
runner_id: payload.runnerId,
|
|
139
|
+
tier: payload.tier ?? undefined,
|
|
140
|
+
capacity: payload.capacity,
|
|
141
|
+
status: "active",
|
|
142
|
+
}),
|
|
143
|
+
});
|
|
144
|
+
if (!res.ok) {
|
|
145
|
+
throw new Error(`probe report HTTP ${res.status}`);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
/** The env var whose presence overrides self-discovery with an explicit id. */
|
|
149
|
+
export const COMPANION_IDENTITY_OVERRIDE_HINT = "ACC_RUNNER_COMPANION_IDENTITY";
|
|
150
|
+
function identityLabel(identity) {
|
|
151
|
+
if (!identity)
|
|
152
|
+
return "identity";
|
|
153
|
+
const pe = [identity.provider, identity.engine].filter(Boolean).join("·");
|
|
154
|
+
return pe || "identity";
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Build the startup banner. HONESTY invariant (asserted by the tests):
|
|
158
|
+
* - a BOUND companion → tone "ok", headline names the bound identity id;
|
|
159
|
+
* - ANY unbound state → tone "warn", headline CONTAINS "UNBOUND" and the
|
|
160
|
+
* words "not serving provider status".
|
|
161
|
+
* There is no path to a green headline that does not name a bound identity, so a
|
|
162
|
+
* green-and-silent-while-unbound banner cannot be produced.
|
|
163
|
+
*/
|
|
164
|
+
export function companionBanner(binding, ctx) {
|
|
165
|
+
const who = ctx.email || "this runner";
|
|
166
|
+
if (binding.kind === "bound") {
|
|
167
|
+
const via = binding.source === "override" ? " (via env override)" : "";
|
|
168
|
+
return {
|
|
169
|
+
tone: "ok",
|
|
170
|
+
headline: `✓ Companion online for ${who} — bound to ${identityLabel(binding.identity)}, identity ${binding.identityId}${via}`,
|
|
171
|
+
lines: [],
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
const headline = `⚠ Companion online for ${who} — UNBOUND, not serving provider status (serving drafts only)`;
|
|
175
|
+
const lines = [];
|
|
176
|
+
switch (binding.reason) {
|
|
177
|
+
case "no_enrollment":
|
|
178
|
+
lines.push(" No enrollment found for this owner + engine. Enroll in Admin ▸ AI providers,", " then restart the companion so it can bind and report a chat-auth probe.");
|
|
179
|
+
break;
|
|
180
|
+
case "multiple":
|
|
181
|
+
lines.push(" More than one enrollment matches — the companion will not guess. Set", ` ${COMPANION_IDENTITY_OVERRIDE_HINT}=<id> to pick one, then restart:`, ...binding.matches.map((m) => ` • ${m.id} (${identityLabel(m)}${m.lastProbeAt ? ", probed" : ", pending"})`));
|
|
182
|
+
break;
|
|
183
|
+
case "unreachable":
|
|
184
|
+
lines.push(" Could not reach the identity registry to self-discover (network / deploy).", ` Serving drafts only; set ${COMPANION_IDENTITY_OVERRIDE_HINT}=<id> to bind explicitly.`);
|
|
185
|
+
break;
|
|
186
|
+
}
|
|
187
|
+
return { tone: "warn", headline, lines };
|
|
188
|
+
}
|
|
189
|
+
//# sourceMappingURL=companion-identity.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"companion-identity.js","sourceRoot":"","sources":["../src/companion-identity.ts"],"names":[],"mappings":"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"}
|
package/dist/companion-run.d.ts
CHANGED
|
@@ -4,7 +4,12 @@ export interface CompanionHandle {
|
|
|
4
4
|
}
|
|
5
5
|
/** Env var seeding the owner's conversations the companion should serve at boot. */
|
|
6
6
|
export declare const COMPANION_CONVERSATIONS_ENV = "ACC_RUNNER_COMPANION_CONVERSATIONS";
|
|
7
|
-
/**
|
|
7
|
+
/**
|
|
8
|
+
* Optional OVERRIDE naming the acc.ai_identities row this companion serves. The
|
|
9
|
+
* default is self-discovery (see companion-identity.ts) — this env var only
|
|
10
|
+
* short-circuits it, for a host that has more than one enrolled subscription of
|
|
11
|
+
* the same engine and must pick one explicitly.
|
|
12
|
+
*/
|
|
8
13
|
export declare const COMPANION_IDENTITY_ENV = "ACC_RUNNER_COMPANION_IDENTITY";
|
|
9
14
|
/**
|
|
10
15
|
* Start companion mode. Registers the owner-bound identity, serves the owner's
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"companion-run.d.ts","sourceRoot":"","sources":["../src/companion-run.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"companion-run.d.ts","sourceRoot":"","sources":["../src/companion-run.ts"],"names":[],"mappings":"AA6CA,gFAAgF;AAChF,MAAM,WAAW,eAAe;IAC9B,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACvB;AAED,oFAAoF;AACpF,eAAO,MAAM,2BAA2B,uCAAuC,CAAC;AAChF;;;;;GAKG;AACH,eAAO,MAAM,sBAAsB,kCAAkC,CAAC;AAEtE;;;;GAIG;AACH,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,eAAe,CAAC,CAgMjE;AAED,+DAA+D;AAC/D,wBAAsB,sBAAsB,IAAI,OAAO,CAAC,IAAI,CAAC,CAmB5D;AAED,8DAA8D;AAC9D,wBAAsB,uBAAuB,IAAI,OAAO,CAAC,IAAI,CAAC,CAK7D;AAED,wCAAwC;AACxC,wBAAsB,yBAAyB,IAAI,OAAO,CAAC,IAAI,CAAC,CAK/D"}
|