@guuey/worker 0.1.1 → 0.2.0

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.
@@ -0,0 +1,26 @@
1
+ import type { Fs } from "./protocol.js";
2
+ /**
3
+ * One parsed credential file. The shape is the broker's §7.1 contract — the
4
+ * worker consumes it verbatim without consulting the snapshot (the broker
5
+ * owns ALL resolution including transport).
6
+ */
7
+ export interface CredentialFile {
8
+ /** The resolved MCP URL (may be scoped `<host>/apps/<id>` for federated ggui). */
9
+ url: string;
10
+ /** Transport the broker selected for this server. */
11
+ transport: "http" | "sse";
12
+ /** Headers to forward — typically `{ authorization: 'Bearer <token>' }`. */
13
+ headers: Record<string, string>;
14
+ /** ISO expiry; informational for the worker (the Router refreshes per invoke). */
15
+ expiresAt?: string;
16
+ }
17
+ /**
18
+ * Read all credential files the Router broker wrote for this invoke. Returns
19
+ * one `{ name, cred }` per valid `.json` file — malformed files are silently
20
+ * skipped (never crash the turn). Missing directory → empty array (no MCP).
21
+ */
22
+ export declare function listCredentials(fs: Fs): () => Array<{
23
+ name: string;
24
+ cred: CredentialFile;
25
+ }>;
26
+ //# sourceMappingURL=creds.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"creds.d.ts","sourceRoot":"","sources":["../src/creds.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,eAAe,CAAC;AAExC;;;;GAIG;AACH,MAAM,WAAW,cAAc;IAC7B,kFAAkF;IAClF,GAAG,EAAE,MAAM,CAAC;IACZ,qDAAqD;IACrD,SAAS,EAAE,MAAM,GAAG,KAAK,CAAC;IAC1B,4EAA4E;IAC5E,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,kFAAkF;IAClF,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,EAAE,EAAE,EAAE,GAAG,MAAM,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,cAAc,CAAA;CAAE,CAAC,CA6B3F"}
package/dist/creds.js ADDED
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Framework-neutral credential-file reading, shared by every worker — the
3
+ * `@guuey/host` runners AND the code-mode workers scaffolded by
4
+ * `@guuey/create-agentic-app` (which is why it lives in the protocol package
5
+ * rather than in the host: both sides read the same broker-written directory).
6
+ *
7
+ * The Router-side credential broker resolves EVERYTHING (default server,
8
+ * federation, minting, env substitution) and writes one JSON file per MCP
9
+ * server to `<sessionDir>/.guuey/credentials/<server>.json` before each
10
+ * worker spawn. Workers only read and shape — no resolution logic here.
11
+ */
12
+ import { readdirSync, readFileSync } from "node:fs";
13
+ import { join } from "node:path";
14
+ /**
15
+ * Read all credential files the Router broker wrote for this invoke. Returns
16
+ * one `{ name, cred }` per valid `.json` file — malformed files are silently
17
+ * skipped (never crash the turn). Missing directory → empty array (no MCP).
18
+ */
19
+ export function listCredentials(fs) {
20
+ return () => {
21
+ const dir = join(fs.session, ".guuey", "credentials");
22
+ let names;
23
+ try {
24
+ names = readdirSync(dir).filter((n) => n.endsWith(".json"));
25
+ }
26
+ catch {
27
+ return []; // no cred dir this turn → no MCP.
28
+ }
29
+ const out = [];
30
+ for (const file of names) {
31
+ try {
32
+ const parsed = JSON.parse(readFileSync(join(dir, file), "utf8"));
33
+ if (typeof parsed === "object" &&
34
+ parsed !== null &&
35
+ !Array.isArray(parsed) &&
36
+ typeof parsed.url === "string" &&
37
+ (parsed.transport === "http" ||
38
+ parsed.transport === "sse")) {
39
+ out.push({ name: file.replace(/\.json$/, ""), cred: parsed });
40
+ }
41
+ }
42
+ catch {
43
+ // malformed file → skip (never crash the turn).
44
+ }
45
+ }
46
+ return out;
47
+ };
48
+ }
package/dist/index.d.ts CHANGED
@@ -2,9 +2,10 @@
2
2
  * @guuey/worker — Guuey Worker Protocol v1 types + the tiered worker SDK.
3
3
  * See docs/superpowers/specs/2026-06-22-worker-platform-northstar-design.md §1.
4
4
  */
5
- export { PROTOCOL_VERSION, type ProtocolVersion, type JsonValue, type AuthMode, type Identity, type Fs, type HistoryMessage, type PriorMemoryRecord, type StopReason, type Invoke, type Shutdown, type ControlMessage, type TextEvent, type DoneEvent, type ErrorEvent, type NativeEvent, type WorkerHelloEvent, type WorkerEvent, } from "./protocol.js";
5
+ export { PROTOCOL_VERSION, type ProtocolVersion, type JsonValue, type AuthMode, type Identity, type Fs, type HistoryMessage, type PriorMemoryRecord, type ProfileSection, type StopReason, type Invoke, type Shutdown, type ControlMessage, type TextEvent, type DoneEvent, type ErrorEvent, type NativeEvent, type WorkerHelloEvent, type WorkerEvent, } from "./protocol.js";
6
6
  export { parseControl, parseEvent, isInvoke, isShutdown, isText, isDone, isError, isNative, isHello, } from "./parse.js";
7
7
  export { createEmitter, type Emitter, type WriteSink } from "./emit.js";
8
+ export { listCredentials, type CredentialFile } from "./creds.js";
8
9
  export { serve, serveOn, type ServeOptions } from "./serve.js";
9
10
  export { Turn, type WorkerHandler } from "./turn.js";
10
11
  export { serveNative, serveNativeOn } from "./serve-native.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EACL,gBAAgB,EAChB,KAAK,eAAe,EACpB,KAAK,SAAS,EACd,KAAK,QAAQ,EACb,KAAK,QAAQ,EACb,KAAK,EAAE,EACP,KAAK,cAAc,EACnB,KAAK,iBAAiB,EACtB,KAAK,UAAU,EACf,KAAK,MAAM,EACX,KAAK,QAAQ,EACb,KAAK,cAAc,EACnB,KAAK,SAAS,EACd,KAAK,SAAS,EACd,KAAK,UAAU,EACf,KAAK,WAAW,EAChB,KAAK,gBAAgB,EACrB,KAAK,WAAW,GACjB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,YAAY,EACZ,UAAU,EACV,QAAQ,EACR,UAAU,EACV,MAAM,EACN,MAAM,EACN,OAAO,EACP,QAAQ,EACR,OAAO,GACR,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,aAAa,EAAE,KAAK,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,WAAW,CAAC;AACxE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,YAAY,CAAC;AAC/D,OAAO,EAAE,IAAI,EAAE,KAAK,aAAa,EAAE,MAAM,WAAW,CAAC;AACrD,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAC/D,YAAY,EAAE,UAAU,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EACL,gBAAgB,EAChB,KAAK,eAAe,EACpB,KAAK,SAAS,EACd,KAAK,QAAQ,EACb,KAAK,QAAQ,EACb,KAAK,EAAE,EACP,KAAK,cAAc,EACnB,KAAK,iBAAiB,EACtB,KAAK,cAAc,EACnB,KAAK,UAAU,EACf,KAAK,MAAM,EACX,KAAK,QAAQ,EACb,KAAK,cAAc,EACnB,KAAK,SAAS,EACd,KAAK,SAAS,EACd,KAAK,UAAU,EACf,KAAK,WAAW,EAChB,KAAK,gBAAgB,EACrB,KAAK,WAAW,GACjB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,YAAY,EACZ,UAAU,EACV,QAAQ,EACR,UAAU,EACV,MAAM,EACN,MAAM,EACN,OAAO,EACP,QAAQ,EACR,OAAO,GACR,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,aAAa,EAAE,KAAK,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,WAAW,CAAC;AACxE,OAAO,EAAE,eAAe,EAAE,KAAK,cAAc,EAAE,MAAM,YAAY,CAAC;AAClE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,YAAY,CAAC;AAC/D,OAAO,EAAE,IAAI,EAAE,KAAK,aAAa,EAAE,MAAM,WAAW,CAAC;AACrD,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAC/D,YAAY,EAAE,UAAU,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC"}
package/dist/index.js CHANGED
@@ -5,6 +5,7 @@
5
5
  export { PROTOCOL_VERSION, } from "./protocol.js";
6
6
  export { parseControl, parseEvent, isInvoke, isShutdown, isText, isDone, isError, isNative, isHello, } from "./parse.js";
7
7
  export { createEmitter } from "./emit.js";
8
+ export { listCredentials } from "./creds.js";
8
9
  export { serve, serveOn } from "./serve.js";
9
10
  export { Turn } from "./turn.js";
10
11
  export { serveNative, serveNativeOn } from "./serve-native.js";
@@ -1 +1 @@
1
- {"version":3,"file":"parse.d.ts","sourceRoot":"","sources":["../src/parse.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,EAEV,cAAc,EACd,SAAS,EACT,UAAU,EAIV,MAAM,EAEN,WAAW,EAEX,QAAQ,EAER,SAAS,EACT,WAAW,EACX,gBAAgB,EACjB,MAAM,eAAe,CAAC;AAEvB,wBAAgB,QAAQ,CAAC,CAAC,EAAE,cAAc,GAAG,CAAC,IAAI,MAAM,CAEvD;AACD,wBAAgB,UAAU,CAAC,CAAC,EAAE,cAAc,GAAG,CAAC,IAAI,QAAQ,CAE3D;AAyDD,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,cAAc,CAgCzD;AAED,wBAAgB,MAAM,CAAC,CAAC,EAAE,WAAW,GAAG,CAAC,IAAI,SAAS,CAErD;AACD,wBAAgB,MAAM,CAAC,CAAC,EAAE,WAAW,GAAG,CAAC,IAAI,SAAS,CAErD;AACD,wBAAgB,OAAO,CAAC,CAAC,EAAE,WAAW,GAAG,CAAC,IAAI,UAAU,CAEvD;AACD,wBAAgB,QAAQ,CAAC,CAAC,EAAE,WAAW,GAAG,CAAC,IAAI,WAAW,CAEzD;AACD,wBAAgB,OAAO,CAAC,CAAC,EAAE,WAAW,GAAG,CAAC,IAAI,gBAAgB,CAE7D;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,CA6CpD"}
1
+ {"version":3,"file":"parse.d.ts","sourceRoot":"","sources":["../src/parse.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,EAEV,cAAc,EACd,SAAS,EACT,UAAU,EAIV,MAAM,EAEN,WAAW,EAGX,QAAQ,EAER,SAAS,EACT,WAAW,EACX,gBAAgB,EACjB,MAAM,eAAe,CAAC;AAEvB,wBAAgB,QAAQ,CAAC,CAAC,EAAE,cAAc,GAAG,CAAC,IAAI,MAAM,CAEvD;AACD,wBAAgB,UAAU,CAAC,CAAC,EAAE,cAAc,GAAG,CAAC,IAAI,QAAQ,CAE3D;AA0ED,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,cAAc,CAkDzD;AAED,wBAAgB,MAAM,CAAC,CAAC,EAAE,WAAW,GAAG,CAAC,IAAI,SAAS,CAErD;AACD,wBAAgB,MAAM,CAAC,CAAC,EAAE,WAAW,GAAG,CAAC,IAAI,SAAS,CAErD;AACD,wBAAgB,OAAO,CAAC,CAAC,EAAE,WAAW,GAAG,CAAC,IAAI,UAAU,CAEvD;AACD,wBAAgB,QAAQ,CAAC,CAAC,EAAE,WAAW,GAAG,CAAC,IAAI,WAAW,CAEzD;AACD,wBAAgB,OAAO,CAAC,CAAC,EAAE,WAAW,GAAG,CAAC,IAAI,gBAAgB,CAE7D;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,CA6CpD"}
package/dist/parse.js CHANGED
@@ -55,6 +55,23 @@ function parsePriorMemory(v) {
55
55
  }
56
56
  return out.length > 0 ? out : undefined;
57
57
  }
58
+ /**
59
+ * Parse the optional `profileSections` push (cross-app-profile T7). Lenient like
60
+ * {@link parsePriorMemory}: a non-conforming entry (not an object, or missing a
61
+ * string `app`/`content`) is DROPPED, never throwing. Returns `undefined` when
62
+ * absent or when no entry survives (so the field stays off the Invoke).
63
+ */
64
+ function parseProfileSections(v) {
65
+ if (!Array.isArray(v))
66
+ return undefined;
67
+ const out = [];
68
+ for (const entry of v) {
69
+ if (isObject(entry) && typeof entry.app === "string" && typeof entry.content === "string") {
70
+ out.push({ app: entry.app, content: entry.content });
71
+ }
72
+ }
73
+ return out.length > 0 ? out : undefined;
74
+ }
58
75
  export function parseControl(line) {
59
76
  let raw;
60
77
  try {
@@ -71,6 +88,7 @@ export function parseControl(line) {
71
88
  if (typeof raw.input !== "string")
72
89
  throw new Error("invoke missing string `input`");
73
90
  const priorMemory = parsePriorMemory(raw.priorMemory);
91
+ const profileSections = parseProfileSections(raw.profileSections);
74
92
  return {
75
93
  type: "invoke",
76
94
  input: raw.input,
@@ -82,6 +100,23 @@ export function parseControl(line) {
82
100
  // preserved; `priorMemory` is omitted when empty/absent.
83
101
  ...(priorMemory ? { priorMemory } : {}),
84
102
  ...(raw.priorState !== undefined ? { priorState: raw.priorState } : {}),
103
+ // memory-mcp prompted memory (spec §4) — DISTINCT from `priorMemory`
104
+ // above (see the `Invoke.userMemory` doc). Omitted when absent/non-string
105
+ // so it never lands on the typed Invoke as `undefined`.
106
+ ...(typeof raw.userMemory === "string" ? { userMemory: raw.userMemory } : {}),
107
+ // memory-mcp T5: the memory-child attachment signal — gates the SAVE
108
+ // instruction (all three frameworks) independent of `userMemory`.
109
+ // Omitted unless a real boolean so it never lands as `undefined`.
110
+ ...(typeof raw.memoryAttached === "boolean" ? { memoryAttached: raw.memoryAttached } : {}),
111
+ // cross-app-profile T7: the resolved profile access + recall sections.
112
+ // `profileAccess` is an explicit enum allowlist (an out-of-enum string —
113
+ // e.g. `'write'` — is dropped, not coerced), mirroring the fail-closed
114
+ // mint-claim check; `profileSections` drops malformed entries. Both
115
+ // omitted when absent so they never land as `undefined`.
116
+ ...(raw.profileAccess === "read" || raw.profileAccess === "read-write"
117
+ ? { profileAccess: raw.profileAccess }
118
+ : {}),
119
+ ...(profileSections ? { profileSections } : {}),
85
120
  };
86
121
  }
87
122
  case "shutdown":
@@ -41,6 +41,19 @@ export interface PriorMemoryRecord {
41
41
  key?: string;
42
42
  value: JsonValue;
43
43
  }
44
+ /**
45
+ * One app's section of the user's cross-app profile (cross-app-profile T7). The
46
+ * Router reads every section it may recall (`readProfileSections`), resolves the
47
+ * writing app's display `name` for provenance, and pushes them by value so the
48
+ * worker renders them into the `<user_profile>` RECALL block. `app` is the
49
+ * source app's display name (or a synthetic `""` for the truncation marker line,
50
+ * whose `content` is the `[…omitted…]` note); `content` is the section body.
51
+ * Minimal + dependency-free, mirroring {@link PriorMemoryRecord}.
52
+ */
53
+ export interface ProfileSection {
54
+ app: string;
55
+ content: string;
56
+ }
44
57
  export type StopReason = "end_turn" | "max_turns" | "error";
45
58
  /** Start a turn. Carries the pushed context (identity, fs, a recent history
46
59
  * window — the full transcript is at `/session/.guuey/history.jsonl`).
@@ -58,6 +71,60 @@ export interface Invoke {
58
71
  priorMemory?: PriorMemoryRecord[];
59
72
  /** Prior working-state blob carried from the previous turn (the `<working_state>` preamble). */
60
73
  priorState?: JsonValue;
74
+ /**
75
+ * Content of the authenticated caller's persistent `MEMORY.md` file —
76
+ * prompted memory's RECALL half (memory-mcp spec §4), read Router-side
77
+ * BEFORE this invoke and pushed by value so recall never depends on the
78
+ * model choosing to read a file. DISTINCT from `priorMemory`: that is
79
+ * thread-scoped conversation memory folded from AgJSON (the persistence-
80
+ * fold's `<thread_memory>` push); this is the user's own cross-session,
81
+ * cross-thread memory file at `$GUUEY_HOME_DIR/memories/MEMORY.md`.
82
+ * FRAMEWORK-BLIND as of memory-mcp T5: present for an authenticated caller
83
+ * when the memory MCP child is attached this pod (the Router's
84
+ * `recallUserMemory` gate — `authenticated && memoryAttached`, the single
85
+ * producer and canonical statement of this invariant), for ANY framework
86
+ * (all three renderers consume it as the RECALL block). Absent for an
87
+ * anonymous caller (never read), a memory-off / pre-rollout pod, or — the
88
+ * bootstrap case — an authenticated caller on an attached pod with no memory
89
+ * file YET (turn one): {@link memoryAttached} is still true, so the SAVE
90
+ * instruction still renders (save-only) even though this is absent.
91
+ */
92
+ userMemory?: string;
93
+ /**
94
+ * Whether the auto-injected memory MCP child booted with a ready port this
95
+ * pod (memory-mcp T5) — the pod-boot constant the Router threads from
96
+ * `SseServerOptions.memoryAttached`. When true, an AUTHENTICATED invoke has
97
+ * the `save_memory` tool spliced (T4), so all three framework renderers emit
98
+ * the SAVE instruction — independent of whether {@link userMemory} exists
99
+ * (fixing the bootstrap gap: turn one, no file yet, the model must still be
100
+ * told the tool exists). Absent/false → no memory tool → no SAVE instruction.
101
+ * DISTINCT from {@link userMemory}, which gates only the RECALL block: the
102
+ * SAVE gate is attachment, the RECALL gate is file presence.
103
+ */
104
+ memoryAttached?: boolean;
105
+ /**
106
+ * The resolved cross-app profile access for THIS invoke (cross-app-profile
107
+ * T6/T7) — the Router's fail-closed grant check (`resolveProfileForInvoke`)
108
+ * clamps the honored grant to the app's declared posture and threads the
109
+ * result here. Present ONLY for an authenticated caller with a live grant;
110
+ * absent → no profile surface this turn. Gates BOTH halves of the profile
111
+ * system-prompt section across all three frameworks: the `save_profile` SAVE
112
+ * instruction renders ONLY when this is `"read-write"` (a `"read"` grant has
113
+ * no write tool to name), and the RECALL block renders whenever
114
+ * {@link profileSections} is present. Kept as an inline literal (NOT imported
115
+ * from `@guuey/config`) to keep this package dependency-free.
116
+ */
117
+ profileAccess?: "read" | "read-write";
118
+ /**
119
+ * The user's cross-app profile sections for the RECALL push
120
+ * (cross-app-profile T7). Each entry is one writing-app's section (plus, when
121
+ * older sections were dropped to fit the 64 KiB recall budget, a leading
122
+ * marker entry with `app: ""`). Pushed by value like {@link priorMemory}; the
123
+ * worker renders them into the `<user_profile>` block. Absent → nothing to
124
+ * recall. Gated by {@link profileAccess} (never rendered for a guest / an
125
+ * ungranted app).
126
+ */
127
+ profileSections?: ProfileSection[];
61
128
  }
62
129
  /** Graceful termination (also signalled by stdin EOF). */
63
130
  export interface Shutdown {
@@ -1 +1 @@
1
- {"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,oFAAoF;AACpF,eAAO,MAAM,gBAAgB,EAAG,IAAa,CAAC;AAC9C,MAAM,MAAM,eAAe,GAAG,OAAO,gBAAgB,CAAC;AAEtD;8EAC8E;AAC9E,MAAM,MAAM,SAAS,GACjB,MAAM,GACN,MAAM,GACN,OAAO,GACP,IAAI,GACJ,SAAS,EAAE,GACX;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,CAAC;AAEjC,MAAM,MAAM,QAAQ,GAAG,WAAW,GAAG,eAAe,CAAC;AACrD,2EAA2E;AAC3E,MAAM,WAAW,QAAQ;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,QAAQ,CAAC;CACpB;AACD,8DAA8D;AAC9D,MAAM,WAAW,EAAE;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AACD,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;CACd;AACD;;;;;GAKG;AACH,MAAM,WAAW,iBAAiB;IAChC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,SAAS,CAAC;CAClB;AACD,MAAM,MAAM,UAAU,GAAG,UAAU,GAAG,WAAW,GAAG,OAAO,CAAC;AAI5D;;;;;6DAK6D;AAC7D,MAAM,WAAW,MAAM;IACrB,IAAI,EAAE,QAAQ,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,QAAQ,CAAC;IACnB,EAAE,EAAE,EAAE,CAAC;IACP,OAAO,EAAE,cAAc,EAAE,CAAC;IAC1B,qFAAqF;IACrF,WAAW,CAAC,EAAE,iBAAiB,EAAE,CAAC;IAClC,gGAAgG;IAChG,UAAU,CAAC,EAAE,SAAS,CAAC;CACxB;AACD,0DAA0D;AAC1D,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,UAAU,CAAC;CAClB;AACD,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,QAAQ,CAAC;AAI/C,0CAA0C;AAC1C,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AACD,2DAA2D;AAC3D,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,UAAU,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;CAChB;AACD,wBAAwB;AACxB,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;CACjB;AACD;;;;;;;;GAQG;AACH,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IACxB,8EAA8E;IAC9E,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,gFAAgF;IAChF,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC;CAC3B;AACD;;;;;;;;;GASG;AACH,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,wEAAwE;IACxE,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,uGAAuG;IACvG,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,8GAA8G;IAC9G,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CACpC;AACD,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,SAAS,GAAG,UAAU,GAAG,WAAW,GAAG,gBAAgB,CAAC"}
1
+ {"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,oFAAoF;AACpF,eAAO,MAAM,gBAAgB,EAAG,IAAa,CAAC;AAC9C,MAAM,MAAM,eAAe,GAAG,OAAO,gBAAgB,CAAC;AAEtD;8EAC8E;AAC9E,MAAM,MAAM,SAAS,GACjB,MAAM,GACN,MAAM,GACN,OAAO,GACP,IAAI,GACJ,SAAS,EAAE,GACX;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,CAAC;AAEjC,MAAM,MAAM,QAAQ,GAAG,WAAW,GAAG,eAAe,CAAC;AACrD,2EAA2E;AAC3E,MAAM,WAAW,QAAQ;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,QAAQ,CAAC;CACpB;AACD,8DAA8D;AAC9D,MAAM,WAAW,EAAE;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AACD,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;CACd;AACD;;;;;GAKG;AACH,MAAM,WAAW,iBAAiB;IAChC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,SAAS,CAAC;CAClB;AACD;;;;;;;;GAQG;AACH,MAAM,WAAW,cAAc;IAC7B,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;CACjB;AACD,MAAM,MAAM,UAAU,GAAG,UAAU,GAAG,WAAW,GAAG,OAAO,CAAC;AAI5D;;;;;6DAK6D;AAC7D,MAAM,WAAW,MAAM;IACrB,IAAI,EAAE,QAAQ,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,QAAQ,CAAC;IACnB,EAAE,EAAE,EAAE,CAAC;IACP,OAAO,EAAE,cAAc,EAAE,CAAC;IAC1B,qFAAqF;IACrF,WAAW,CAAC,EAAE,iBAAiB,EAAE,CAAC;IAClC,gGAAgG;IAChG,UAAU,CAAC,EAAE,SAAS,CAAC;IACvB;;;;;;;;;;;;;;;;;OAiBG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;;;;;;;OAUG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB;;;;;;;;;;;OAWG;IACH,aAAa,CAAC,EAAE,MAAM,GAAG,YAAY,CAAC;IACtC;;;;;;;;OAQG;IACH,eAAe,CAAC,EAAE,cAAc,EAAE,CAAC;CACpC;AACD,0DAA0D;AAC1D,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,UAAU,CAAC;CAClB;AACD,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,QAAQ,CAAC;AAI/C,0CAA0C;AAC1C,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AACD,2DAA2D;AAC3D,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,UAAU,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;CAChB;AACD,wBAAwB;AACxB,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;CACjB;AACD;;;;;;;;GAQG;AACH,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IACxB,8EAA8E;IAC9E,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,gFAAgF;IAChF,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC;CAC3B;AACD;;;;;;;;;GASG;AACH,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,wEAAwE;IACxE,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,uGAAuG;IACvG,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,8GAA8G;IAC9G,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CACpC;AACD,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,SAAS,GAAG,UAAU,GAAG,WAAW,GAAG,gBAAgB,CAAC"}
@@ -8,8 +8,20 @@ export type NativeHandler = (invoke: Invoke, emit: NativeEmit) => Promise<string
8
8
  export interface NativeServeInfo {
9
9
  framework: string;
10
10
  sdkName?: string | null;
11
+ /** Installed SDK version for the hello handshake. When OMITTED (the
12
+ * template default), it is resolved at runtime from `sdkName`'s installed
13
+ * package.json — works for unbundled workers with a real node_modules;
14
+ * degrades to null inside a self-contained bundle (nothing to resolve). */
11
15
  sdkVersion?: string | null;
12
16
  }
17
+ /**
18
+ * Resolve `pkgName`'s installed version by walking up from its resolved main
19
+ * entry (a `require.resolve(pkg + "/package.json")` throws
20
+ * ERR_PACKAGE_PATH_NOT_EXPORTED for SDKs whose exports map omits the
21
+ * subpath — the claude/openai SDKs both do). Never throws: null when the
22
+ * package can't be resolved (bundled worker, absent dep).
23
+ */
24
+ export declare function resolveInstalledVersion(pkgName: string): string | null;
13
25
  export declare function serveNativeOn(handler: NativeHandler, info: NativeServeInfo, opts: ServeOptions): Promise<void>;
14
26
  /** The public entry: wire stdin (fd 0) + an fd-3 Writable, then run the loop. */
15
27
  export declare function serveNative(handler: NativeHandler, info: NativeServeInfo, opts?: {
@@ -1 +1 @@
1
- {"version":3,"file":"serve-native.d.ts","sourceRoot":"","sources":["../src/serve-native.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AACvD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/C,MAAM,WAAW,UAAU;IACzB,MAAM,CAAC,KAAK,EAAE,SAAS,GAAG,IAAI,CAAC;IAC/B,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AACD,MAAM,MAAM,aAAa,GAAG,CAC1B,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,UAAU,KACb,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,GAAG,MAAM,GAAG,IAAI,CAAC;AAC5C,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAED,wBAAsB,aAAa,CACjC,OAAO,EAAE,aAAa,EACtB,IAAI,EAAE,eAAe,EACrB,IAAI,EAAE,YAAY,GACjB,OAAO,CAAC,IAAI,CAAC,CA+Bf;AAED,iFAAiF;AACjF,wBAAgB,WAAW,CACzB,OAAO,EAAE,aAAa,EACtB,IAAI,EAAE,eAAe,EACrB,IAAI,CAAC,EAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,GACzB,OAAO,CAAC,IAAI,CAAC,CAQf"}
1
+ {"version":3,"file":"serve-native.d.ts","sourceRoot":"","sources":["../src/serve-native.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AACvD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/C,MAAM,WAAW,UAAU;IACzB,MAAM,CAAC,KAAK,EAAE,SAAS,GAAG,IAAI,CAAC;IAC/B,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AACD,MAAM,MAAM,aAAa,GAAG,CAC1B,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,UAAU,KACb,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,GAAG,MAAM,GAAG,IAAI,CAAC;AAC5C,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB;;;gFAG4E;IAC5E,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAED;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAsBtE;AAED,wBAAsB,aAAa,CACjC,OAAO,EAAE,aAAa,EACtB,IAAI,EAAE,eAAe,EACrB,IAAI,EAAE,YAAY,GACjB,OAAO,CAAC,IAAI,CAAC,CAuCf;AAED,iFAAiF;AACjF,wBAAgB,WAAW,CACzB,OAAO,EAAE,aAAa,EACtB,IAAI,EAAE,eAAe,EACrB,IAAI,CAAC,EAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,GACzB,OAAO,CAAC,IAAI,CAAC,CAQf"}
@@ -5,10 +5,44 @@
5
5
  * `Turn`. Lets a template worker emit `hello` → `native`* → `done` per invoke,
6
6
  * like `@guuey/host` does.
7
7
  */
8
- import { createWriteStream } from "node:fs";
8
+ import { createWriteStream, readFileSync } from "node:fs";
9
+ import { createRequire } from "node:module";
10
+ import { dirname, join } from "node:path";
11
+ const require = createRequire(import.meta.url);
9
12
  import { createEmitter } from "./emit.js";
10
13
  import { lines } from "./lines.js";
11
14
  import { isInvoke, isShutdown, parseControl } from "./parse.js";
15
+ /**
16
+ * Resolve `pkgName`'s installed version by walking up from its resolved main
17
+ * entry (a `require.resolve(pkg + "/package.json")` throws
18
+ * ERR_PACKAGE_PATH_NOT_EXPORTED for SDKs whose exports map omits the
19
+ * subpath — the claude/openai SDKs both do). Never throws: null when the
20
+ * package can't be resolved (bundled worker, absent dep).
21
+ */
22
+ export function resolveInstalledVersion(pkgName) {
23
+ try {
24
+ const entry = require.resolve(pkgName);
25
+ let dir = dirname(entry);
26
+ for (let depth = 0; depth < 6; depth++) {
27
+ try {
28
+ const pkg = JSON.parse(readFileSync(join(dir, "package.json"), "utf8"));
29
+ if (pkg.name === pkgName)
30
+ return pkg.version ?? null;
31
+ }
32
+ catch {
33
+ // not at this level — keep walking
34
+ }
35
+ const parent = dirname(dir);
36
+ if (parent === dir)
37
+ break;
38
+ dir = parent;
39
+ }
40
+ return null;
41
+ }
42
+ catch {
43
+ return null;
44
+ }
45
+ }
12
46
  export async function serveNativeOn(handler, info, opts) {
13
47
  const emitter = createEmitter(opts.output);
14
48
  const idleMs = opts.idleMs ?? 5 * 60_000;
@@ -28,7 +62,11 @@ export async function serveNativeOn(handler, info, opts) {
28
62
  break;
29
63
  if (!isInvoke(msg))
30
64
  continue;
31
- emitter.hello(info.framework, info.sdkName ?? null, info.sdkVersion ?? null);
65
+ emitter.hello(info.framework, info.sdkName ?? null, info.sdkVersion !== undefined
66
+ ? info.sdkVersion
67
+ : info.sdkName
68
+ ? resolveInstalledVersion(info.sdkName)
69
+ : null);
32
70
  try {
33
71
  const scoped = {
34
72
  native: (event) => emitter.native(info.framework, event),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@guuey/worker",
3
- "version": "0.1.1",
3
+ "version": "0.2.0",
4
4
  "description": "Guuey Worker Protocol v1 — the Router↔Worker contract types and the tiered worker SDK (typed interpreter + serve loop).",
5
5
  "license": "MIT",
6
6
  "type": "module",