@guuey/config 0.16.11 → 0.16.14
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/agent.d.ts +102 -0
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +210 -0
- package/dist/app.d.ts +2 -2
- package/dist/loader.d.ts +13 -0
- package/dist/loader.d.ts.map +1 -1
- package/dist/loader.js +83 -16
- package/dist/schema.d.ts +20 -1
- package/dist/schema.d.ts.map +1 -1
- package/package.json +2 -2
package/dist/agent.d.ts
CHANGED
|
@@ -191,6 +191,42 @@ declare const RuntimeConfigSchema: z.ZodObject<{
|
|
|
191
191
|
declare const SystemPromptSchema: z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
|
|
192
192
|
file: z.ZodString;
|
|
193
193
|
}, z.core.$strict>]>;
|
|
194
|
+
/**
|
|
195
|
+
* One mode of a multi-mode agent (guuey#527). `systemPromptAppend` extends
|
|
196
|
+
* the base prompt (inline string or a `{ file }` the loader inlines);
|
|
197
|
+
* `systemPrompt` replaces it wholesale — exactly ONE of the two (the
|
|
198
|
+
* refine on {@link ModesSchema} enforces the xor). `tools.allowlist`, when
|
|
199
|
+
* present, must be a subset of the base allowlist — the WRITE GATE enforces
|
|
200
|
+
* that (the schema can't see the base), so a mode only ever narrows.
|
|
201
|
+
* `audience` is accepted for forward-compat but the SERVER hardcodes the
|
|
202
|
+
* binding for the recognized pair in tonight's slice.
|
|
203
|
+
*/
|
|
204
|
+
declare const ModeSchema: z.ZodObject<{
|
|
205
|
+
systemPromptAppend: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
|
|
206
|
+
file: z.ZodString;
|
|
207
|
+
}, z.core.$strict>]>>;
|
|
208
|
+
systemPrompt: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
|
|
209
|
+
file: z.ZodString;
|
|
210
|
+
}, z.core.$strict>]>>;
|
|
211
|
+
tools: z.ZodOptional<z.ZodObject<{
|
|
212
|
+
allowlist: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
213
|
+
denylist: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
214
|
+
}, z.core.$strict>>;
|
|
215
|
+
audience: z.ZodOptional<z.ZodArray<z.ZodEnum<{
|
|
216
|
+
guest: "guest";
|
|
217
|
+
authenticated: "authenticated";
|
|
218
|
+
byo: "byo";
|
|
219
|
+
}>>>;
|
|
220
|
+
}, z.core.$strict>;
|
|
221
|
+
/**
|
|
222
|
+
* Does the BASE tool allowlist permit `entry`? (guuey#527 subset rule.)
|
|
223
|
+
* A base pattern covers `entry` when it is `*`, an exact match, or a
|
|
224
|
+
* `prefix.*` wildcard whose prefix `entry` falls under. This is the SAME
|
|
225
|
+
* coverage semantics the pod's gate applies at call time, so "the mode's
|
|
226
|
+
* allowlist is a subset" means exactly "every mode tool the base already
|
|
227
|
+
* permits" — a mode can only ever NARROW, never widen.
|
|
228
|
+
*/
|
|
229
|
+
export declare function baseAllowlistPermits(baseAllowlist: readonly string[] | undefined, entry: string): boolean;
|
|
194
230
|
/**
|
|
195
231
|
* Bedrock-style invocation endpoint config.
|
|
196
232
|
*
|
|
@@ -328,6 +364,25 @@ export declare const AgentSectionV1: z.ZodObject<{
|
|
|
328
364
|
allowlist: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
329
365
|
denylist: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
330
366
|
}, z.core.$strict>>;
|
|
367
|
+
modes: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
368
|
+
systemPromptAppend: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
|
|
369
|
+
file: z.ZodString;
|
|
370
|
+
}, z.core.$strict>]>>;
|
|
371
|
+
systemPrompt: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
|
|
372
|
+
file: z.ZodString;
|
|
373
|
+
}, z.core.$strict>]>>;
|
|
374
|
+
tools: z.ZodOptional<z.ZodObject<{
|
|
375
|
+
allowlist: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
376
|
+
denylist: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
377
|
+
}, z.core.$strict>>;
|
|
378
|
+
audience: z.ZodOptional<z.ZodArray<z.ZodEnum<{
|
|
379
|
+
guest: "guest";
|
|
380
|
+
authenticated: "authenticated";
|
|
381
|
+
byo: "byo";
|
|
382
|
+
}>>>;
|
|
383
|
+
}, z.core.$strict>>>;
|
|
384
|
+
defaultMode: z.ZodOptional<z.ZodString>;
|
|
385
|
+
surfaceHints: z.ZodOptional<z.ZodBoolean>;
|
|
331
386
|
runtime: z.ZodOptional<z.ZodObject<{
|
|
332
387
|
maxTurns: z.ZodOptional<z.ZodNumber>;
|
|
333
388
|
temperature: z.ZodOptional<z.ZodNumber>;
|
|
@@ -387,6 +442,45 @@ export type GuueyAgentRuntime = z.infer<typeof RuntimeConfigSchema>;
|
|
|
387
442
|
export type GuueyAgentSystemPrompt = z.infer<typeof SystemPromptSchema>;
|
|
388
443
|
/** Endpoint config type. */
|
|
389
444
|
export type GuueyAgentEndpoint = z.infer<typeof EndpointConfigSchema>;
|
|
445
|
+
/** One declared mode's shape. */
|
|
446
|
+
export type GuueyAgentMode = z.infer<typeof ModeSchema>;
|
|
447
|
+
/** The v1 mode axis — the caller's REAL auth state, server-derived. */
|
|
448
|
+
export type ModeAudienceClass = 'guest' | 'auth';
|
|
449
|
+
/** The result of {@link applyAgentMode} — the effective snapshot + provenance. */
|
|
450
|
+
export interface AppliedAgentMode {
|
|
451
|
+
/** The snapshot to SERVE this invoke (a new object when a mode applied; the same reference otherwise). */
|
|
452
|
+
agent: GuueyAgent;
|
|
453
|
+
/** The mode key actually applied, or `null` when serving the bare base. */
|
|
454
|
+
applied: string | null;
|
|
455
|
+
/** Present when the resolution took a non-obvious branch (all fail-soft). */
|
|
456
|
+
fallback?: 'unknown-mode' | 'pin-clamped' | 'auth-undeclared';
|
|
457
|
+
}
|
|
458
|
+
/**
|
|
459
|
+
* Resolve + apply one invoke's agent mode (guuey#527/#566 — the guest/auth
|
|
460
|
+
* axis, founder-refined 2026-08-31: "letting them use guest mode vs auth
|
|
461
|
+
* mode is the correct definition").
|
|
462
|
+
*
|
|
463
|
+
* SELECTION is SERVER-DERIVED: `audience` is the caller's REAL auth state
|
|
464
|
+
* (the pod maps anonymous → 'guest', authenticated → 'auth') — never a
|
|
465
|
+
* client claim. The `pin` (the widget/SDK `mode` param) may only choose
|
|
466
|
+
* WITHIN permission: an authed caller may pin 'guest' (preview-as-visitor);
|
|
467
|
+
* a guest pinning 'auth' is CLAMPED to guest ('pin-clamped'), and an
|
|
468
|
+
* unrecognized pin key is ignored ('unknown-mode') — fail-soft always, an
|
|
469
|
+
* embed never breaks.
|
|
470
|
+
*
|
|
471
|
+
* Fallback chain: the selected key's def; an undeclared 'auth' falls to
|
|
472
|
+
* 'guest''s def ('auth-undeclared' — an app that only configures the
|
|
473
|
+
* visitor rep serves everyone that rep, which IS hire-a-rep); still
|
|
474
|
+
* nothing → base. `defaultMode` is deprecated and not consulted.
|
|
475
|
+
*
|
|
476
|
+
* Application (unchanged from the first cut, test-pinned): `systemPrompt`
|
|
477
|
+
* REPLACES the base; `systemPromptAppend` = base + "\n\n" + append; an
|
|
478
|
+
* EMPTY def serves the base by SAME REFERENCE (callers detect no-override
|
|
479
|
+
* by identity); `tools` replaces with the write-gate-proven subset; a
|
|
480
|
+
* `{ file }` prompt is unusable at serve time → base. Pure — never
|
|
481
|
+
* mutates inputs.
|
|
482
|
+
*/
|
|
483
|
+
export declare function applyAgentMode(agent: GuueyAgent, pin: string | undefined, audience: ModeAudienceClass): AppliedAgentMode;
|
|
390
484
|
/** Deploy config type. */
|
|
391
485
|
export type GuueyAgentDeploy = z.infer<typeof DeploySchema>;
|
|
392
486
|
/**
|
|
@@ -427,6 +521,14 @@ export declare const RESERVED_MEMORY_SERVER_NAME = "guuey-memory";
|
|
|
427
521
|
* platform entry at invoke time.
|
|
428
522
|
*/
|
|
429
523
|
export declare const RESERVED_PROFILE_SERVER_NAME = "guuey-profile";
|
|
524
|
+
/**
|
|
525
|
+
* The reserved colocated key the auto-injected human-handoff MCP is booted +
|
|
526
|
+
* spliced under (guuey#552, spec 2026-08-31-human-handoff-v1-design.md).
|
|
527
|
+
* NEVER builder-declarable — mirrors {@link RESERVED_MEMORY_SERVER_NAME}'s
|
|
528
|
+
* reservation for the same reason; the handoff child's own server advertises
|
|
529
|
+
* this name and its aud is `colocatedResourceUrl(appId, this)`.
|
|
530
|
+
*/
|
|
531
|
+
export declare const RESERVED_HANDOFF_SERVER_NAME = "guuey-handoff";
|
|
430
532
|
/**
|
|
431
533
|
* Every `mcpServers` map key the platform reserves. Extensible — one entry
|
|
432
534
|
* today ({@link RESERVED_MEMORY_SERVER_NAME}); future platform-injected
|
package/dist/agent.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../src/agent.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB;;;;;;GAMG;AACH,eAAO,MAAM,gBAAgB,6EAKnB,CAAC;AACX,MAAM,MAAM,cAAc,GAAG,CAAC,OAAO,gBAAgB,CAAC,CAAC,MAAM,CAAC,CAAC;AAS/D;;;;GAIG;AACH,eAAO,MAAM,mBAAmB;;;EAAiC,CAAC;AAClE,uEAAuE;AACvE,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAyIhE;;;;;;;;;;;;GAYG;AACH,QAAA,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;4BAInB,CAAC;AAEH;;;;GAIG;AACH,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;mDAA+C,CAAC;AACjF,MAAM,MAAM,kBAAkB,GAAG,MAAM,CAAC,MAAM,EAAE,mBAAmB,GAAG,KAAK,CAAC,CAAC;AAE7E;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,QAAA,MAAM,eAAe;;;kBAGnB,CAAC;AAEH;;;;;;;;GAQG;AACH,QAAA,MAAM,mBAAmB;;;kBAGvB,CAAC;AAcH;;;;GAIG;AACH,QAAA,MAAM,kBAAkB;;oBAGtB,CAAC;AAEH;;;;;;GAMG;AACH,QAAA,MAAM,oBAAoB;;;kBAGxB,CAAC;AAEH;;;;;;;;;;GAUG;AACH,QAAA,MAAM,YAAY;;;;;;;;;kBAKhB,CAAC;AA8BH;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE;IAAE,OAAO,CAAC,EAAE,aAAa,CAAC,MAAM,GAAG,KAAK,CAAC,CAAA;CAAE,GAAG,SAAS,GAAG,OAAO,CAGxG;AAED;;;;;GAKG;AACH;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;oDAAoD,CAAC;AAEnF,eAAO,MAAM,cAAc
|
|
1
|
+
{"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../src/agent.ts"],"names":[],"mappings":"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"}
|
package/dist/agent.js
CHANGED
|
@@ -279,6 +279,58 @@ const SystemPromptSchema = z.union([
|
|
|
279
279
|
z.string().min(1),
|
|
280
280
|
z.strictObject({ file: z.string().min(1) }),
|
|
281
281
|
]);
|
|
282
|
+
/**
|
|
283
|
+
* One mode of a multi-mode agent (guuey#527). `systemPromptAppend` extends
|
|
284
|
+
* the base prompt (inline string or a `{ file }` the loader inlines);
|
|
285
|
+
* `systemPrompt` replaces it wholesale — exactly ONE of the two (the
|
|
286
|
+
* refine on {@link ModesSchema} enforces the xor). `tools.allowlist`, when
|
|
287
|
+
* present, must be a subset of the base allowlist — the WRITE GATE enforces
|
|
288
|
+
* that (the schema can't see the base), so a mode only ever narrows.
|
|
289
|
+
* `audience` is accepted for forward-compat but the SERVER hardcodes the
|
|
290
|
+
* binding for the recognized pair in tonight's slice.
|
|
291
|
+
*/
|
|
292
|
+
const ModeSchema = z.strictObject({
|
|
293
|
+
systemPromptAppend: SystemPromptSchema.optional(),
|
|
294
|
+
systemPrompt: SystemPromptSchema.optional(),
|
|
295
|
+
tools: ToolGatesSchema.optional(),
|
|
296
|
+
audience: z.array(z.enum(['guest', 'authenticated', 'byo'])).optional(),
|
|
297
|
+
});
|
|
298
|
+
/**
|
|
299
|
+
* The `agent.modes` map (guuey#527). Mode keys are short machine
|
|
300
|
+
* identifiers (`rep`, `agent`, …) — the court-key grammar, reused. Each
|
|
301
|
+
* value is a {@link ModeSchema}; a mode declares AT MOST one of
|
|
302
|
+
* `systemPromptAppend` / `systemPrompt` (both = a contradiction the
|
|
303
|
+
* manifest must not carry).
|
|
304
|
+
*/
|
|
305
|
+
const MODE_KEY_RE = /^[a-z][a-z0-9-]{0,31}$/;
|
|
306
|
+
const ModesSchema = z
|
|
307
|
+
.record(z.string().regex(MODE_KEY_RE), ModeSchema)
|
|
308
|
+
.refine((modes) => Object.values(modes).every((m) => !(m.systemPromptAppend !== undefined && m.systemPrompt !== undefined)), { message: 'a mode declares at most one of systemPromptAppend / systemPrompt, never both' });
|
|
309
|
+
/**
|
|
310
|
+
* Does the BASE tool allowlist permit `entry`? (guuey#527 subset rule.)
|
|
311
|
+
* A base pattern covers `entry` when it is `*`, an exact match, or a
|
|
312
|
+
* `prefix.*` wildcard whose prefix `entry` falls under. This is the SAME
|
|
313
|
+
* coverage semantics the pod's gate applies at call time, so "the mode's
|
|
314
|
+
* allowlist is a subset" means exactly "every mode tool the base already
|
|
315
|
+
* permits" — a mode can only ever NARROW, never widen.
|
|
316
|
+
*/
|
|
317
|
+
export function baseAllowlistPermits(baseAllowlist, entry) {
|
|
318
|
+
// No base allowlist = the model may call anything, so any mode entry is
|
|
319
|
+
// trivially permitted (the mode is still a real narrowing of "anything").
|
|
320
|
+
if (baseAllowlist === undefined)
|
|
321
|
+
return true;
|
|
322
|
+
return baseAllowlist.some((b) => {
|
|
323
|
+
if (b === '*')
|
|
324
|
+
return true;
|
|
325
|
+
if (b === entry)
|
|
326
|
+
return true;
|
|
327
|
+
if (b.endsWith('.*')) {
|
|
328
|
+
const prefix = b.slice(0, -1); // keep the dot: "platform." covers "platform.whoami"
|
|
329
|
+
return entry.startsWith(prefix);
|
|
330
|
+
}
|
|
331
|
+
return false;
|
|
332
|
+
});
|
|
333
|
+
}
|
|
282
334
|
/**
|
|
283
335
|
* Bedrock-style invocation endpoint config.
|
|
284
336
|
*
|
|
@@ -423,6 +475,40 @@ export const AgentSectionV1 = z.strictObject({
|
|
|
423
475
|
})
|
|
424
476
|
.optional(),
|
|
425
477
|
tools: ToolGatesSchema.optional(),
|
|
478
|
+
/**
|
|
479
|
+
* Multi-mode agent (guuey#527) — ONE agent, per-mode prompt overlays on
|
|
480
|
+
* the base `systemPrompt` + a per-mode tool SUBSET of the base allowlist.
|
|
481
|
+
* THE AXIS (founder-refined 2026-08-31, the final word): modes are the
|
|
482
|
+
* AUDIENCE'S AUTH STATE — v1 recognizes exactly `guest` (website
|
|
483
|
+
* visitors; the hire-a-rep mode) and `auth` (signed-in users; navigated
|
|
484
|
+
* separately in studio). SELECTION is SERVER-DERIVED from the caller's
|
|
485
|
+
* REAL auth state ({@link applyAgentMode}) — an anonymous caller
|
|
486
|
+
* structurally cannot claim auth mode; the widget/SDK `mode` param is a
|
|
487
|
+
* PIN within permission (authed may pin `guest` to preview-as-visitor;
|
|
488
|
+
* a guest pinning `auth` clamps). `defaultMode` and per-mode `audience`
|
|
489
|
+
* are v1-DEPRECATED (parseable, not consulted — derivation replaced
|
|
490
|
+
* both); the grammar stays key-agnostic for future axes.
|
|
491
|
+
*
|
|
492
|
+
* Each mode: exactly one of `systemPromptAppend` (extend the base — the
|
|
493
|
+
* common case) or `systemPrompt` (full replace); an optional `tools`
|
|
494
|
+
* allowlist that must be a SUBSET of the base `agent.tools.allowlist`
|
|
495
|
+
* (the write gate enforces it — a mode can only ever NARROW).
|
|
496
|
+
*/
|
|
497
|
+
modes: ModesSchema.optional(),
|
|
498
|
+
/** The mode a caller with no audience match resolves to (a declared mode key). */
|
|
499
|
+
defaultMode: z.string().min(1).optional(),
|
|
500
|
+
/**
|
|
501
|
+
* The platform wrapper's SURFACE-FORMATTING section (guuey#531) —
|
|
502
|
+
* default ON, opt-out only: a few invoke-constant lines telling the
|
|
503
|
+
* model that guuey's chat surfaces render markdown (code fences +
|
|
504
|
+
* inline code, autolinked bare URLs, native tables), so every builder
|
|
505
|
+
* doesn't have to discover that independently. Set `false` for BYO
|
|
506
|
+
* surfaces (`@guuey/agent-client` custom clients — SMS/voice/
|
|
507
|
+
* plain-text) where markdown is not the contract. The exact text
|
|
508
|
+
* lives at `@guuey/host` `SURFACE_FORMATTING_SECTION` and is
|
|
509
|
+
* published verbatim in the docs — never tone/brand/behavior.
|
|
510
|
+
*/
|
|
511
|
+
surfaceHints: z.boolean().optional(),
|
|
426
512
|
runtime: RuntimeConfigSchema.optional(),
|
|
427
513
|
/** Claude Agent SDK-specific knobs. Only read when `framework: 'claude-agent-sdk'`. */
|
|
428
514
|
claude: ClaudeFrameworkConfigSchema.optional(),
|
|
@@ -444,7 +530,122 @@ export const AgentSectionV1 = z.strictObject({
|
|
|
444
530
|
endpoint: EndpointConfigSchema.optional(),
|
|
445
531
|
// ── Deploy ──
|
|
446
532
|
deploy: DeploySchema.optional(),
|
|
533
|
+
}).superRefine((agent, ctx) => {
|
|
534
|
+
// guuey#527 — the mode tool SUBSET rule, enforced at parse time (CLI
|
|
535
|
+
// loader AND server both run this): a mode's tool allowlist may only
|
|
536
|
+
// contain tools the BASE allowlist already permits. A mode narrows,
|
|
537
|
+
// never widens — the one privilege-adjacent axis, closed here.
|
|
538
|
+
if (agent.modes === undefined)
|
|
539
|
+
return;
|
|
540
|
+
const base = agent.tools?.allowlist;
|
|
541
|
+
for (const [mode, def] of Object.entries(agent.modes)) {
|
|
542
|
+
const modeAllow = def.tools?.allowlist;
|
|
543
|
+
if (modeAllow === undefined)
|
|
544
|
+
continue;
|
|
545
|
+
for (const entry of modeAllow) {
|
|
546
|
+
if (!baseAllowlistPermits(base, entry)) {
|
|
547
|
+
ctx.addIssue({
|
|
548
|
+
code: z.ZodIssueCode.custom,
|
|
549
|
+
path: ['modes', mode, 'tools', 'allowlist'],
|
|
550
|
+
message: `mode "${mode}" allows tool "${entry}" which the base agent.tools.allowlist does not permit — a mode can only narrow the base tools, never widen them`,
|
|
551
|
+
});
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
// A declared defaultMode must name a declared mode.
|
|
556
|
+
if (agent.defaultMode !== undefined && agent.modes[agent.defaultMode] === undefined) {
|
|
557
|
+
ctx.addIssue({
|
|
558
|
+
code: z.ZodIssueCode.custom,
|
|
559
|
+
path: ['defaultMode'],
|
|
560
|
+
message: `defaultMode "${agent.defaultMode}" is not a declared mode (${Object.keys(agent.modes).join(', ') || 'none'})`,
|
|
561
|
+
});
|
|
562
|
+
}
|
|
447
563
|
});
|
|
564
|
+
/**
|
|
565
|
+
* Resolve + apply one invoke's agent mode (guuey#527/#566 — the guest/auth
|
|
566
|
+
* axis, founder-refined 2026-08-31: "letting them use guest mode vs auth
|
|
567
|
+
* mode is the correct definition").
|
|
568
|
+
*
|
|
569
|
+
* SELECTION is SERVER-DERIVED: `audience` is the caller's REAL auth state
|
|
570
|
+
* (the pod maps anonymous → 'guest', authenticated → 'auth') — never a
|
|
571
|
+
* client claim. The `pin` (the widget/SDK `mode` param) may only choose
|
|
572
|
+
* WITHIN permission: an authed caller may pin 'guest' (preview-as-visitor);
|
|
573
|
+
* a guest pinning 'auth' is CLAMPED to guest ('pin-clamped'), and an
|
|
574
|
+
* unrecognized pin key is ignored ('unknown-mode') — fail-soft always, an
|
|
575
|
+
* embed never breaks.
|
|
576
|
+
*
|
|
577
|
+
* Fallback chain: the selected key's def; an undeclared 'auth' falls to
|
|
578
|
+
* 'guest''s def ('auth-undeclared' — an app that only configures the
|
|
579
|
+
* visitor rep serves everyone that rep, which IS hire-a-rep); still
|
|
580
|
+
* nothing → base. `defaultMode` is deprecated and not consulted.
|
|
581
|
+
*
|
|
582
|
+
* Application (unchanged from the first cut, test-pinned): `systemPrompt`
|
|
583
|
+
* REPLACES the base; `systemPromptAppend` = base + "\n\n" + append; an
|
|
584
|
+
* EMPTY def serves the base by SAME REFERENCE (callers detect no-override
|
|
585
|
+
* by identity); `tools` replaces with the write-gate-proven subset; a
|
|
586
|
+
* `{ file }` prompt is unusable at serve time → base. Pure — never
|
|
587
|
+
* mutates inputs.
|
|
588
|
+
*/
|
|
589
|
+
export function applyAgentMode(agent, pin, audience) {
|
|
590
|
+
const modes = agent.modes;
|
|
591
|
+
if (modes === undefined)
|
|
592
|
+
return { agent, applied: null };
|
|
593
|
+
// ── Selection: derived, then the pin within permission ──────────────
|
|
594
|
+
let fallback;
|
|
595
|
+
let selected = audience;
|
|
596
|
+
if (pin !== undefined && pin !== audience) {
|
|
597
|
+
if (pin !== 'guest' && pin !== 'auth') {
|
|
598
|
+
fallback = 'unknown-mode'; // ignored; pure derivation stands
|
|
599
|
+
}
|
|
600
|
+
else if (pin === 'auth' && audience === 'guest') {
|
|
601
|
+
fallback = 'pin-clamped'; // a guest cannot claim auth mode
|
|
602
|
+
}
|
|
603
|
+
else {
|
|
604
|
+
selected = pin; // authed pinning 'guest' — preview-as-visitor
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
// ── Fallback chain: selected → guest → base ─────────────────────────
|
|
608
|
+
let applied = selected;
|
|
609
|
+
let def = modes[selected];
|
|
610
|
+
if (def === undefined && selected === 'auth') {
|
|
611
|
+
def = modes['guest'];
|
|
612
|
+
if (def !== undefined) {
|
|
613
|
+
applied = 'guest';
|
|
614
|
+
fallback = fallback ?? 'auth-undeclared';
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
if (def === undefined) {
|
|
618
|
+
return { agent, applied: null, ...(fallback !== undefined ? { fallback } : {}) };
|
|
619
|
+
}
|
|
620
|
+
// ── Application (unchanged) ─────────────────────────────────────────
|
|
621
|
+
// An EMPTY def (legal — "at most one") IS the base: same reference out,
|
|
622
|
+
// so callers can cheaply detect "nothing to override" by identity.
|
|
623
|
+
if (def.systemPrompt === undefined && def.systemPromptAppend === undefined && def.tools === undefined) {
|
|
624
|
+
return { agent, applied, ...(fallback !== undefined ? { fallback } : {}) };
|
|
625
|
+
}
|
|
626
|
+
const basePrompt = typeof agent.systemPrompt === 'string' ? agent.systemPrompt : undefined;
|
|
627
|
+
let systemPrompt = agent.systemPrompt;
|
|
628
|
+
if (typeof def.systemPrompt === 'string') {
|
|
629
|
+
systemPrompt = def.systemPrompt;
|
|
630
|
+
}
|
|
631
|
+
else if (typeof def.systemPromptAppend === 'string') {
|
|
632
|
+
systemPrompt =
|
|
633
|
+
basePrompt !== undefined ? `${basePrompt}\n\n${def.systemPromptAppend}` : def.systemPromptAppend;
|
|
634
|
+
}
|
|
635
|
+
else if (def.systemPrompt !== undefined || def.systemPromptAppend !== undefined) {
|
|
636
|
+
// { file } shape — unusable at serve time; base verbatim.
|
|
637
|
+
return { agent, applied: null, ...(fallback !== undefined ? { fallback } : {}) };
|
|
638
|
+
}
|
|
639
|
+
return {
|
|
640
|
+
agent: {
|
|
641
|
+
...agent,
|
|
642
|
+
...(systemPrompt !== undefined ? { systemPrompt } : {}),
|
|
643
|
+
...(def.tools !== undefined ? { tools: def.tools } : {}),
|
|
644
|
+
},
|
|
645
|
+
applied,
|
|
646
|
+
...(fallback !== undefined ? { fallback } : {}),
|
|
647
|
+
};
|
|
648
|
+
}
|
|
448
649
|
// ── No-literal-secrets validation (deploy-time contract enforcement) ──────────
|
|
449
650
|
//
|
|
450
651
|
// The schema (McpServerSchema JSDoc) requires secrets in `mcpServers[].headers`
|
|
@@ -613,6 +814,14 @@ export const RESERVED_MEMORY_SERVER_NAME = 'guuey-memory';
|
|
|
613
814
|
* platform entry at invoke time.
|
|
614
815
|
*/
|
|
615
816
|
export const RESERVED_PROFILE_SERVER_NAME = 'guuey-profile';
|
|
817
|
+
/**
|
|
818
|
+
* The reserved colocated key the auto-injected human-handoff MCP is booted +
|
|
819
|
+
* spliced under (guuey#552, spec 2026-08-31-human-handoff-v1-design.md).
|
|
820
|
+
* NEVER builder-declarable — mirrors {@link RESERVED_MEMORY_SERVER_NAME}'s
|
|
821
|
+
* reservation for the same reason; the handoff child's own server advertises
|
|
822
|
+
* this name and its aud is `colocatedResourceUrl(appId, this)`.
|
|
823
|
+
*/
|
|
824
|
+
export const RESERVED_HANDOFF_SERVER_NAME = 'guuey-handoff';
|
|
616
825
|
/**
|
|
617
826
|
* Every `mcpServers` map key the platform reserves. Extensible — one entry
|
|
618
827
|
* today ({@link RESERVED_MEMORY_SERVER_NAME}); future platform-injected
|
|
@@ -621,6 +830,7 @@ export const RESERVED_PROFILE_SERVER_NAME = 'guuey-profile';
|
|
|
621
830
|
export const RESERVED_MCP_SERVER_NAMES = [
|
|
622
831
|
RESERVED_MEMORY_SERVER_NAME,
|
|
623
832
|
RESERVED_PROFILE_SERVER_NAME,
|
|
833
|
+
RESERVED_HANDOFF_SERVER_NAME,
|
|
624
834
|
];
|
|
625
835
|
/**
|
|
626
836
|
* Validate that no `agent.mcpServers` entry uses a platform-RESERVED name
|
package/dist/app.d.ts
CHANGED
|
@@ -35,9 +35,9 @@ export type AppUserAuthMode = (typeof APP_USER_AUTH_MODES)[number];
|
|
|
35
35
|
*/
|
|
36
36
|
export declare const AppAccessV1: z.ZodObject<{
|
|
37
37
|
userAuthMode: z.ZodOptional<z.ZodEnum<{
|
|
38
|
+
byo: "byo";
|
|
38
39
|
anonymous: "anonymous";
|
|
39
40
|
native_pool: "native_pool";
|
|
40
|
-
byo: "byo";
|
|
41
41
|
}>>;
|
|
42
42
|
userAuthConfig: z.ZodOptional<z.ZodNullable<z.ZodObject<{
|
|
43
43
|
issuerUrl: z.ZodString;
|
|
@@ -110,9 +110,9 @@ export declare const AppSectionV1: z.ZodObject<{
|
|
|
110
110
|
customDomain: z.ZodOptional<z.ZodString>;
|
|
111
111
|
access: z.ZodOptional<z.ZodObject<{
|
|
112
112
|
userAuthMode: z.ZodOptional<z.ZodEnum<{
|
|
113
|
+
byo: "byo";
|
|
113
114
|
anonymous: "anonymous";
|
|
114
115
|
native_pool: "native_pool";
|
|
115
|
-
byo: "byo";
|
|
116
116
|
}>>;
|
|
117
117
|
userAuthConfig: z.ZodOptional<z.ZodNullable<z.ZodObject<{
|
|
118
118
|
issuerUrl: z.ZodString;
|
package/dist/loader.d.ts
CHANGED
|
@@ -52,6 +52,19 @@ export interface ResolvedGuueyJson {
|
|
|
52
52
|
* (guuey#400), or `undefined` when no theme was set.
|
|
53
53
|
*/
|
|
54
54
|
resolvedTheme: GuueyAppTheme | undefined;
|
|
55
|
+
/**
|
|
56
|
+
* Resolved per-mode prompts (guuey#545): for every `agent.modes[key]`
|
|
57
|
+
* whose `systemPrompt` / `systemPromptAppend` is present, the FINAL
|
|
58
|
+
* string — the inline value as-is, or the file contents when it was a
|
|
59
|
+
* `{ file: '...' }` reference. Before this, a file-shaped mode prompt
|
|
60
|
+
* rode into the snapshot unresolved and reached the pod (which has no
|
|
61
|
+
* repo filesystem) — a silently broken deploy. `undefined` when the
|
|
62
|
+
* document declares no modes.
|
|
63
|
+
*/
|
|
64
|
+
resolvedModePrompts: Record<string, {
|
|
65
|
+
systemPrompt?: string;
|
|
66
|
+
systemPromptAppend?: string;
|
|
67
|
+
}> | undefined;
|
|
55
68
|
/** Absolute path the document was loaded from (for diagnostics). */
|
|
56
69
|
sourcePath: string;
|
|
57
70
|
}
|
package/dist/loader.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../src/loader.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../src/loader.ts"],"names":[],"mappings":"AA0BA,OAAO,EAEL,WAAW,EAGZ,MAAM,aAAa,CAAC;AAErB,OAAO,EAAc,KAAK,aAAa,EAAE,MAAM,YAAY,CAAC;AAE5D,wEAAwE;AACxE,eAAO,MAAM,sBAAsB,IAAI,CAAC;AAExC;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAC3B,QAAQ,GAAE,MAAsB,EAChC,QAAQ,GAAE,MAA+B,GACxC,MAAM,GAAG,IAAI,CAUf;AAED;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,CAgB3D;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,WAAW,GAAG,IAAI,CAIvE;AAED;;;;;GAKG;AACH,MAAM,WAAW,iBAAiB;IAChC,oCAAoC;IACpC,GAAG,EAAE,WAAW,CAAC;IACjB;;;;;OAKG;IACH,oBAAoB,EAAE,MAAM,GAAG,SAAS,CAAC;IACzC;;;;OAIG;IACH,aAAa,EAAE,aAAa,GAAG,SAAS,CAAC;IACzC;;;;;;;;OAQG;IACH,mBAAmB,EACf,MAAM,CAAC,MAAM,EAAE;QAAE,YAAY,CAAC,EAAE,MAAM,CAAC;QAAC,kBAAkB,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,GACtE,SAAS,CAAC;IACd,oEAAoE;IACpE,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,iBAAiB,CAY7D;AA2JD;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,iBAAiB,GAAG,WAAW,CAiC1E"}
|
package/dist/loader.js
CHANGED
|
@@ -4,8 +4,11 @@
|
|
|
4
4
|
* Pure-parse helpers (`parseGuueyJson` / `safeParseGuueyJson`) live in
|
|
5
5
|
* `./schema.ts` and are safe to import from non-Node contexts. This
|
|
6
6
|
* module adds the file-resolution layer: reading `guuey.json` from disk,
|
|
7
|
-
* inlining `agent.systemPrompt.file`
|
|
8
|
-
*
|
|
7
|
+
* inlining `agent.systemPrompt.file` AND every
|
|
8
|
+
* `agent.modes[*].{systemPrompt,systemPromptAppend}.file` reference
|
|
9
|
+
* (guuey#545 — a file-shaped mode prompt used to ride into the snapshot
|
|
10
|
+
* unresolved), and producing the snapshot the deploy upload + pod boot
|
|
11
|
+
* both read.
|
|
9
12
|
*
|
|
10
13
|
* Intended callers:
|
|
11
14
|
*
|
|
@@ -103,7 +106,64 @@ export function loadGuueyJson(path) {
|
|
|
103
106
|
const doc = readGuueyJsonFile(path);
|
|
104
107
|
const resolvedSystemPrompt = resolveSystemPrompt(doc, path);
|
|
105
108
|
const resolvedTheme = resolveAppTheme(doc, path);
|
|
106
|
-
|
|
109
|
+
const resolvedModePrompts = resolveModePrompts(doc, path);
|
|
110
|
+
return {
|
|
111
|
+
doc,
|
|
112
|
+
resolvedSystemPrompt,
|
|
113
|
+
resolvedTheme,
|
|
114
|
+
resolvedModePrompts,
|
|
115
|
+
sourcePath: path,
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Shared relative-file guard + read for prompt `{ file }` references
|
|
120
|
+
* (guuey#545 extraction — the base prompt, and now every mode prompt,
|
|
121
|
+
* enforce the identical rules): the path must be relative, must not
|
|
122
|
+
* traverse parent directories, and must exist. `label` names the field
|
|
123
|
+
* in every error so the failure reads like the document, not the loader.
|
|
124
|
+
*/
|
|
125
|
+
function readPromptFileRef(label, file, guueyJsonPath) {
|
|
126
|
+
if (isAbsolute(file)) {
|
|
127
|
+
throw new Error(`${label} must be a relative path (got absolute: ${file})`);
|
|
128
|
+
}
|
|
129
|
+
if (file.split('/').includes('..')) {
|
|
130
|
+
throw new Error(`${label} must not traverse parent directories (got: ${file})`);
|
|
131
|
+
}
|
|
132
|
+
const resolved = resolve(dirname(guueyJsonPath), file);
|
|
133
|
+
if (!existsSync(resolved)) {
|
|
134
|
+
throw new Error(`${label} references missing file: ${file} (resolved to ${resolved})`);
|
|
135
|
+
}
|
|
136
|
+
return readFileSync(resolved, 'utf-8');
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Resolve every mode's `systemPrompt` / `systemPromptAppend` to final
|
|
140
|
+
* strings (guuey#545). Inline strings pass through; `{ file }` references
|
|
141
|
+
* resolve under {@link readPromptFileRef}'s guards — the SAME contract as
|
|
142
|
+
* the base prompt, which the ModeSchema doc always promised. Absent
|
|
143
|
+
* modes → undefined.
|
|
144
|
+
*/
|
|
145
|
+
function resolveModePrompts(doc, guueyJsonPath) {
|
|
146
|
+
const modes = doc.agent.modes;
|
|
147
|
+
if (modes === undefined)
|
|
148
|
+
return undefined;
|
|
149
|
+
const out = {};
|
|
150
|
+
for (const [key, mode] of Object.entries(modes)) {
|
|
151
|
+
const entry = {};
|
|
152
|
+
if (mode.systemPrompt !== undefined) {
|
|
153
|
+
entry.systemPrompt =
|
|
154
|
+
typeof mode.systemPrompt === 'string'
|
|
155
|
+
? mode.systemPrompt
|
|
156
|
+
: readPromptFileRef(`agent.modes.${key}.systemPrompt.file`, mode.systemPrompt.file, guueyJsonPath);
|
|
157
|
+
}
|
|
158
|
+
if (mode.systemPromptAppend !== undefined) {
|
|
159
|
+
entry.systemPromptAppend =
|
|
160
|
+
typeof mode.systemPromptAppend === 'string'
|
|
161
|
+
? mode.systemPromptAppend
|
|
162
|
+
: readPromptFileRef(`agent.modes.${key}.systemPromptAppend.file`, mode.systemPromptAppend.file, guueyJsonPath);
|
|
163
|
+
}
|
|
164
|
+
out[key] = entry;
|
|
165
|
+
}
|
|
166
|
+
return out;
|
|
107
167
|
}
|
|
108
168
|
/**
|
|
109
169
|
* Resolve `agent.systemPrompt` to a final string (or undefined).
|
|
@@ -122,19 +182,8 @@ function resolveSystemPrompt(doc, guueyJsonPath) {
|
|
|
122
182
|
return undefined;
|
|
123
183
|
if (typeof sp === 'string')
|
|
124
184
|
return sp;
|
|
125
|
-
// sp = { file: '...' }
|
|
126
|
-
|
|
127
|
-
throw new Error(`agent.systemPrompt.file must be a relative path (got absolute: ${sp.file})`);
|
|
128
|
-
}
|
|
129
|
-
if (sp.file.split('/').includes('..')) {
|
|
130
|
-
throw new Error(`agent.systemPrompt.file must not traverse parent directories (got: ${sp.file})`);
|
|
131
|
-
}
|
|
132
|
-
const baseDir = dirname(guueyJsonPath);
|
|
133
|
-
const resolved = resolve(baseDir, sp.file);
|
|
134
|
-
if (!existsSync(resolved)) {
|
|
135
|
-
throw new Error(`agent.systemPrompt.file references missing file: ${sp.file} (resolved to ${resolved})`);
|
|
136
|
-
}
|
|
137
|
-
return readFileSync(resolved, 'utf-8');
|
|
185
|
+
// sp = { file: '...' } — shared guard+read (guuey#545 extraction).
|
|
186
|
+
return readPromptFileRef('agent.systemPrompt.file', sp.file, guueyJsonPath);
|
|
138
187
|
}
|
|
139
188
|
/**
|
|
140
189
|
* Resolve `app.theme` to the inline document (or undefined).
|
|
@@ -198,6 +247,24 @@ export function buildDeploySnapshot(loaded) {
|
|
|
198
247
|
if (loaded.resolvedSystemPrompt !== undefined) {
|
|
199
248
|
cloned.agent.systemPrompt = loaded.resolvedSystemPrompt;
|
|
200
249
|
}
|
|
250
|
+
// guuey#545 — mode prompts inline the same way the base prompt does:
|
|
251
|
+
// a `{ file }` reference must never ride into the snapshot (the pod
|
|
252
|
+
// has no repo filesystem; an unresolved object was a silently broken
|
|
253
|
+
// deploy). Only prompt fields are touched — tools/audience and every
|
|
254
|
+
// unexposed mode key survive verbatim.
|
|
255
|
+
if (loaded.resolvedModePrompts !== undefined && cloned.agent.modes !== undefined) {
|
|
256
|
+
for (const [key, resolved] of Object.entries(loaded.resolvedModePrompts)) {
|
|
257
|
+
const mode = cloned.agent.modes[key];
|
|
258
|
+
if (mode === undefined)
|
|
259
|
+
continue;
|
|
260
|
+
if (resolved.systemPrompt !== undefined) {
|
|
261
|
+
mode.systemPrompt = resolved.systemPrompt;
|
|
262
|
+
}
|
|
263
|
+
if (resolved.systemPromptAppend !== undefined) {
|
|
264
|
+
mode.systemPromptAppend = resolved.systemPromptAppend;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
}
|
|
201
268
|
const theme = cloned.app?.theme;
|
|
202
269
|
if (cloned.app !== undefined &&
|
|
203
270
|
theme !== undefined &&
|
package/dist/schema.d.ts
CHANGED
|
@@ -189,6 +189,25 @@ export declare const GuueyJsonV1: z.ZodObject<{
|
|
|
189
189
|
allowlist: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
190
190
|
denylist: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
191
191
|
}, z.core.$strict>>;
|
|
192
|
+
modes: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
193
|
+
systemPromptAppend: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
|
|
194
|
+
file: z.ZodString;
|
|
195
|
+
}, z.core.$strict>]>>;
|
|
196
|
+
systemPrompt: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
|
|
197
|
+
file: z.ZodString;
|
|
198
|
+
}, z.core.$strict>]>>;
|
|
199
|
+
tools: z.ZodOptional<z.ZodObject<{
|
|
200
|
+
allowlist: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
201
|
+
denylist: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
202
|
+
}, z.core.$strict>>;
|
|
203
|
+
audience: z.ZodOptional<z.ZodArray<z.ZodEnum<{
|
|
204
|
+
guest: "guest";
|
|
205
|
+
authenticated: "authenticated";
|
|
206
|
+
byo: "byo";
|
|
207
|
+
}>>>;
|
|
208
|
+
}, z.core.$strict>>>;
|
|
209
|
+
defaultMode: z.ZodOptional<z.ZodString>;
|
|
210
|
+
surfaceHints: z.ZodOptional<z.ZodBoolean>;
|
|
192
211
|
runtime: z.ZodOptional<z.ZodObject<{
|
|
193
212
|
maxTurns: z.ZodOptional<z.ZodNumber>;
|
|
194
213
|
temperature: z.ZodOptional<z.ZodNumber>;
|
|
@@ -245,9 +264,9 @@ export declare const GuueyJsonV1: z.ZodObject<{
|
|
|
245
264
|
customDomain: z.ZodOptional<z.ZodString>;
|
|
246
265
|
access: z.ZodOptional<z.ZodObject<{
|
|
247
266
|
userAuthMode: z.ZodOptional<z.ZodEnum<{
|
|
267
|
+
byo: "byo";
|
|
248
268
|
anonymous: "anonymous";
|
|
249
269
|
native_pool: "native_pool";
|
|
250
|
-
byo: "byo";
|
|
251
270
|
}>>;
|
|
252
271
|
userAuthConfig: z.ZodOptional<z.ZodNullable<z.ZodObject<{
|
|
253
272
|
issuerUrl: z.ZodString;
|
package/dist/schema.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAkB,KAAK,UAAU,EAAE,MAAM,YAAY,CAAC;AAC7D,OAAO,EAAgB,KAAK,QAAQ,EAAE,MAAM,UAAU,CAAC;AACvD,OAAO,EAAiB,KAAK,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAEjE;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,eAAO,MAAM,2BAA2B,MAAM,CAAC;AAE/C;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,sBAAsB,GAC9B;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACpC;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAChC;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAChC;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,KAAK,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,CAAC;AAEnD;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,OAAO,GAAG,sBAAsB,CAY5E;AAED;;;;;GAKG;AACH,qBAAa,oBAAqB,SAAQ,KAAK;aAE3B,IAAI,EAAE,gBAAgB,GAAG,oBAAoB;aAC7C,KAAK,EAAE,MAAM;gBADb,IAAI,EAAE,gBAAgB,GAAG,oBAAoB,EAC7C,KAAK,EAAE,MAAM,EAC7B,OAAO,EAAE,MAAM;CAKlB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,8BAA8B,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI,CAkBjE;AAED;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,WAAW
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAkB,KAAK,UAAU,EAAE,MAAM,YAAY,CAAC;AAC7D,OAAO,EAAgB,KAAK,QAAQ,EAAE,MAAM,UAAU,CAAC;AACvD,OAAO,EAAiB,KAAK,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAEjE;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,eAAO,MAAM,2BAA2B,MAAM,CAAC;AAE/C;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,sBAAsB,GAC9B;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACpC;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAChC;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAChC;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,KAAK,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,CAAC;AAEnD;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,OAAO,GAAG,sBAAsB,CAY5E;AAED;;;;;GAKG;AACH,qBAAa,oBAAqB,SAAQ,KAAK;aAE3B,IAAI,EAAE,gBAAgB,GAAG,oBAAoB;aAC7C,KAAK,EAAE,MAAM;gBADb,IAAI,EAAE,gBAAgB,GAAG,oBAAoB,EAC7C,KAAK,EAAE,MAAM,EAC7B,OAAO,EAAE,MAAM;CAKlB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,8BAA8B,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI,CAkBjE;AAED;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAmDtB,CAAC;AAEH,kDAAkD;AAClD,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,CAAC;AAEtD;;;;GAIG;AACH,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,CAAC;AAG3D,YAAY,EAAE,UAAU,EAAE,QAAQ,EAAE,gBAAgB,EAAE,CAAC;AAEvD;;;GAGG;AACH,eAAO,MAAM,mBAAmB,eAAe,CAAC;AAEhD;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,OAAO,GAAG,WAAW,CAExD;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAChC,GAAG,EAAE,OAAO,GACX,UAAU,CAAC,OAAO,WAAW,CAAC,SAAS,CAAC,CAE1C"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@guuey/config",
|
|
3
|
-
"version": "0.16.
|
|
3
|
+
"version": "0.16.14",
|
|
4
4
|
"description": "Open-source schemas + loaders for the three guuey config files: agent.json (declarative agent definition), guuey.json (hosted-deploy overlay), and the helper types around them. Consumed by @guuey/cli, the guuey backend, and devs writing their own agent or MCP server.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
"@types/node": "^24.0.0",
|
|
36
36
|
"typescript": "^5.0.0",
|
|
37
37
|
"vitest": "^3.2.7",
|
|
38
|
-
"@guuey/chat": "0.16.
|
|
38
|
+
"@guuey/chat": "0.16.14"
|
|
39
39
|
},
|
|
40
40
|
"publishConfig": {
|
|
41
41
|
"access": "public"
|