@happyvertical/smrt-cli 0.55.11 → 0.55.13

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.
Files changed (25) hide show
  1. package/agents/kitchen.md +24 -7
  2. package/dist/{AuditLogCollection-WDHL-_AF-ClQNu_VR.js → AuditLogCollection-WDHL-_AF-_RXJ4g2q.js} +1 -1
  3. package/dist/{OidcIdentity-BUblgQLs-br8RyLkA.js → OidcIdentity-BUblgQLs-Us7ZUvnh.js} +2 -2
  4. package/dist/{OidcIdentityCollection-ClOyaHeF-BpQXB3mz.js → OidcIdentityCollection-ClOyaHeF-BmHrvh1o.js} +1 -1
  5. package/dist/{ProfileAssetCollection-CRMcjLJ--C5ytBKfF.js → ProfileAssetCollection-CRMcjLJ--M64P0MlJ.js} +3 -3
  6. package/dist/{ProfileCollection-C4INKh7Y-CfkyJilm.js → ProfileCollection-C4INKh7Y-Xn37Xj2d.js} +17 -17
  7. package/dist/{ProfileLinkCollection-DFfZRsgv-MQ2zhD9z.js → ProfileLinkCollection-DFfZRsgv-DTXdjPMD.js} +2 -2
  8. package/dist/{ProfileMetadataCollection-BIYKy4Y3-DXu5L2yx.js → ProfileMetadataCollection-BIYKy4Y3-C4NyBsA_.js} +1 -1
  9. package/dist/{ProfileMetafieldCollection-Buz7gzag-C2tZc1PF.js → ProfileMetafieldCollection-Buz7gzag-BlJqn0f-.js} +1 -1
  10. package/dist/{ProfileRelationshipCollection-C4g_QLI4-vTnkAIAh.js → ProfileRelationshipCollection-C4g_QLI4-BoadAuj8.js} +1 -1
  11. package/dist/{ProfileTypeCollection-B7kwi1mU-KwPGcUkI.js → ProfileTypeCollection-B7kwi1mU-BaT2OYDR.js} +2 -2
  12. package/dist/commands/kitchen/run.d.ts.map +1 -1
  13. package/dist/commands/kitchen/server.d.ts +9 -0
  14. package/dist/commands/kitchen/server.d.ts.map +1 -1
  15. package/dist/{commands-pbRVQvix.js → commands-CZtXU3Is.js} +8 -7
  16. package/dist/{dist-CYVIKmvy.js → dist-6XMOPmAQ.js} +4 -4
  17. package/dist/{dist-BsRSQ_hE.js → dist-BCW7OSeu.js} +112 -93
  18. package/dist/dist-BLSv-O7X.js +21 -0
  19. package/dist/{dist-DxkSjKQQ.js → dist-D56nENIY.js} +3 -3
  20. package/dist/{dist-ffh0LeC4.js → dist-lltZIBRI.js} +28 -9
  21. package/dist/index.js +11 -11
  22. package/dist/{oidcProvisioningPrimitives-DNP9EZlU-CBYwksp0.js → oidcProvisioningPrimitives-DNP9EZlU-B6S-rGtq.js} +3 -3
  23. package/dist/{resolveIdentity-CkyqvctR-B5btFsQd.js → resolveIdentity-CkyqvctR-BoHG4Xos.js} +14 -14
  24. package/package.json +15 -15
  25. package/dist/dist-D_WqjwkC.js +0 -21
package/agents/kitchen.md CHANGED
@@ -18,7 +18,8 @@ Checked before anything starts.
18
18
 
19
19
  1. Find the planner (below), import its plain-Node `./core`.
20
20
  2. Resolve the model; start the server on `127.0.0.1` (random port, or `--port`) with a random
21
- one-time token; open the browser (`--no-open` to skip).
21
+ one-time token; open `http://127.0.0.1:<port>/#kitchen=<token>` in the browser (`--no-open`
22
+ skips opening; the same address is printed as `Open <url>`, because the token is in it).
22
23
  3. The page chats through `/api/planner/chat`, the user builds a cookbook and chooses
23
24
  **Send to kitchen**, which POSTs it to `/api/kitchen/cookbook`.
24
25
  4. The server validates (`validateCookbook` + recipe index, as `cookbook validate`), runs the
@@ -30,7 +31,7 @@ Checked before anything starts.
30
31
 
31
32
  | Path | |
32
33
  | --- | --- |
33
- | `GET /planner.config.json` | `{ inference, kitchen: { endpoint: "/api/kitchen/cookbook", token } }`; `inference` is `{ mode: "host", host: { endpoint: "/api/planner/chat" } }`, or `{ mode: "browser" }` with no model |
34
+ | `GET /planner.config.json` | `{ inference, kitchen: { endpoint: "/api/kitchen/cookbook" } }`, **never a token**; `inference` is `{ mode: "host", host: { endpoint: "/api/planner/chat" } }`, or `{ mode: "browser" }` with no model |
34
35
  | `POST /api/planner/chat` | host contract v1: `parseHostRequest` -> `buildHostPrompt` -> model -> `parseHostReply` -> reply JSON. 400 bad request, 502 model failure (message not forwarded), 503 no model |
35
36
  | `POST /api/kitchen/cookbook` | header `x-kitchen-token`, same-origin JSON; 200 `{ ok, dir, mode, installed, added, nextSteps }`, 4xx `{ ok: false, errors }` |
36
37
  | everything else (GET/HEAD) | the planner's `app/` directory; `/` serves `index.html`; no path leaves `app/` |
@@ -39,11 +40,27 @@ Guards: every request's `Host` must be this server (DNS rebinding); the cookbook
39
40
  matching `Origin` header (chat: matching if present), `content-type: application/json`, a
40
41
  timing-safe token match, and is refused after a success. Bodies are capped (chat 256 KB,
41
42
  cookbook 2 MB). No CORS headers are sent. Only one cookbook POST applies at a time
42
- (the slot is claimed before the body is read). The token is served from
43
- `/planner.config.json`, which any local process that sends this server's `Host` can read:
44
- the kitchen defends against browsers, not against other users on the same machine, so run
45
- it on a machine you trust. Keeping the token out of that endpoint needs a planner contract
46
- change (token in the opened URL's fragment).
43
+ (the slot is claimed before the body is read).
44
+
45
+ ### The token is in the URL fragment
46
+
47
+ The one-time token is **not served by any endpoint**: `/planner.config.json` carries only the
48
+ cookbook endpoint, so another local process that sends this server's `Host` cannot read it. The
49
+ token is the fragment of the address the CLI opens and prints, `http://127.0.0.1:<port>/#kitchen=<token>`
50
+ (`server.openUrl`; `server.url` has no secret). A fragment is never sent to a server. The planner reads
51
+ `location.hash`, keeps the token in memory only (not in storage, not in any request but the cookbook
52
+ POST's `x-kitchen-token` header), and strips the `kitchen` parameter from the address with
53
+ a replacing navigation (`goto(..., { replaceState: true })`, because a bare `history.replaceState` would leave the
54
+ token in SvelteKit's own copy of the address) before anything else reads the URL, so it is not in the history
55
+ entry either.
56
+ Opening the address without the fragment (or reloading after it was stripped) leaves the page without
57
+ a token: the export panel then says so and offers Download. A planner older than this contract shows no Send
58
+ button at all, and a planner at this contract served by an older CLI (which still puts `token` in the config)
59
+ refuses to use it and says to update the CLI, so release this change before, or with, the planner's first
60
+ publish. The contract is specified on the planner
61
+ side in `happyvertical/smrt-planner` `docs/inference-host.md` ("Send to kitchen"); change both
62
+ together. The kitchen defends against browsers, not against other users on the same machine
63
+ (who can read your terminal and process list): run it on a machine you trust.
47
64
 
48
65
  ## Model
49
66
 
@@ -1,5 +1,5 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-8H4AJuhK.js";
2
- import { i as tenantId, r as TenantScoped } from "./dist-DxkSjKQQ.js";
2
+ import { i as tenantId, r as TenantScoped } from "./dist-D56nENIY.js";
3
3
  import { n as __exportAll$1 } from "./NostrIdentity-AC8fAdxe-DKxKyu_a.js";
4
4
  import { SmrtCollection, SmrtObject, field, foreignKey, smrt } from "@happyvertical/smrt-core";
5
5
  //#region ../profiles/dist/chunks/AuditLogCollection-WDHL-_AF.js
@@ -42,7 +42,7 @@ var OidcIdentity = class extends SmrtObject {
42
42
  * Find identity by issuer and subject
43
43
  */
44
44
  static async findBySubject(issuer, subject, options = {}) {
45
- const { OidcIdentityCollection } = await import("./OidcIdentityCollection-ClOyaHeF-BpQXB3mz.js").then((n) => n.r).then((n) => n.r);
45
+ const { OidcIdentityCollection } = await import("./OidcIdentityCollection-ClOyaHeF-BmHrvh1o.js").then((n) => n.r).then((n) => n.r);
46
46
  return await (await OidcIdentityCollection.create(options)).findBySubject(issuer, subject);
47
47
  }
48
48
  /** Build the collision-free natural key for one OIDC issuer subject. */
@@ -65,7 +65,7 @@ var OidcIdentity = class extends SmrtObject {
65
65
  static async findOrCreate(profile, oidcData, options = {}) {
66
66
  const profileId = profile.id;
67
67
  if (typeof profileId !== "string" || !profileId) throw new Error("OidcIdentity.findOrCreate() requires a saved Profile.");
68
- const { reuseExistingOidcIdentityForProfile } = await import("./resolveIdentity-CkyqvctR-B5btFsQd.js").then((n) => n.i).then((n) => n.i);
68
+ const { reuseExistingOidcIdentityForProfile } = await import("./resolveIdentity-CkyqvctR-BoHG4Xos.js").then((n) => n.i).then((n) => n.i);
69
69
  const profileOptions = profile.options ?? {};
70
70
  return (await reuseExistingOidcIdentityForProfile(profileId, {
71
71
  email: oidcData.email,
@@ -1,6 +1,6 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-8H4AJuhK.js";
2
2
  import { n as __exportAll$1 } from "./NostrIdentity-AC8fAdxe-DKxKyu_a.js";
3
- import { t as OidcIdentity } from "./OidcIdentity-BUblgQLs-br8RyLkA.js";
3
+ import { t as OidcIdentity } from "./OidcIdentity-BUblgQLs-Us7ZUvnh.js";
4
4
  import { SmrtCollection } from "@happyvertical/smrt-core";
5
5
  //#region ../profiles/dist/chunks/OidcIdentityCollection-ClOyaHeF.js
6
6
  var OidcIdentityCollection_ClOyaHeF_exports = /* @__PURE__ */ __exportAll({
@@ -1,7 +1,7 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-8H4AJuhK.js";
2
- import { i as tenantId, r as TenantScoped } from "./dist-DxkSjKQQ.js";
2
+ import { i as tenantId, r as TenantScoped } from "./dist-D56nENIY.js";
3
3
  import { n as __exportAll$1 } from "./NostrIdentity-AC8fAdxe-DKxKyu_a.js";
4
- import { a as getOwnedAssetsFromCollection, o as removeOwnedAssetFromCollection, t as addOwnedAssetFromCollection } from "./dist-ffh0LeC4.js";
4
+ import { a as getOwnedAssetsFromCollection, o as removeOwnedAssetFromCollection, t as addOwnedAssetFromCollection } from "./dist-lltZIBRI.js";
5
5
  import { SmrtJunction, SmrtObject, crossPackageRef, field, foreignKey, smrt } from "@happyvertical/smrt-core";
6
6
  //#region ../profiles/dist/chunks/ProfileAssetCollection-CRMcjLJ-.js
7
7
  var ProfileAssetCollection_CRMcjLJ__exports = /* @__PURE__ */ __exportAll({
@@ -84,7 +84,7 @@ var ProfileAssetCollection = class extends SmrtJunction {
84
84
  profileCollectionPromise = null;
85
85
  async getProfileCollection() {
86
86
  if (!this.profileCollectionPromise) {
87
- const { ProfileCollection } = await import("./ProfileCollection-C4INKh7Y-CfkyJilm.js").then((n) => n.o).then((n) => n.r);
87
+ const { ProfileCollection } = await import("./ProfileCollection-C4INKh7Y-Xn37Xj2d.js").then((n) => n.o).then((n) => n.r);
88
88
  this.profileCollectionPromise = ProfileCollection.create({ db: this.db });
89
89
  }
90
90
  return this.profileCollectionPromise;
@@ -1,7 +1,7 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-8H4AJuhK.js";
2
- import { a as queryGlobal, c as getTenantId, i as tenantId, n as resolvePrompt, o as queryWithGlobals, r as TenantScoped, t as definePrompt, u as withSystemContext } from "./dist-DxkSjKQQ.js";
2
+ import { a as queryGlobal, c as getTenantId, i as tenantId, n as resolvePrompt, o as queryWithGlobals, r as TenantScoped, t as definePrompt, u as withSystemContext } from "./dist-D56nENIY.js";
3
3
  import { n as __exportAll$1 } from "./NostrIdentity-AC8fAdxe-DKxKyu_a.js";
4
- import { a as getOwnedAssetsFromCollection, i as assertValidOwnedAssetSortOrder, n as assertAssetLinkable, o as removeOwnedAssetFromCollection, r as assertValidOwnedAssetRelationship, s as resolveOwnedAssetsById, t as addOwnedAssetFromCollection } from "./dist-ffh0LeC4.js";
4
+ import { a as getOwnedAssetsFromCollection, i as assertValidOwnedAssetSortOrder, n as assertAssetLinkable, o as removeOwnedAssetFromCollection, r as assertValidOwnedAssetRelationship, s as resolveOwnedAssetsById, t as addOwnedAssetFromCollection } from "./dist-lltZIBRI.js";
5
5
  import { RuntimeError, SmrtCollection, SmrtObject, ValidationError, field, foreignKey, isAbortedTransactionError, oneToMany, smrt } from "@happyvertical/smrt-core";
6
6
  import { BackfillTableUnavailableError, BackfillTracker } from "@happyvertical/smrt-core/migrations";
7
7
  //#region ../profiles/dist/chunks/ProfileCollection-C4INKh7Y.js
@@ -435,7 +435,7 @@ var Profile = class extends SmrtObject {
435
435
  async getTypeSlug() {
436
436
  const tenantId2 = this.tenantId || getTenantId();
437
437
  if (this.typeId && tenantId2) {
438
- const { ProfileTypeCollection } = await import("./ProfileTypeCollection-B7kwi1mU-KwPGcUkI.js").then((n) => n.n).then((n) => n.n);
438
+ const { ProfileTypeCollection } = await import("./ProfileTypeCollection-B7kwi1mU-BaT2OYDR.js").then((n) => n.n).then((n) => n.n);
439
439
  return (await (await ProfileTypeCollection.create(this.options)).getAvailableById(this.typeId, tenantId2))?.slug ?? "";
440
440
  }
441
441
  return (await this.loadRelated("typeId"))?.slug || "";
@@ -458,8 +458,8 @@ var Profile = class extends SmrtObject {
458
458
  * @param value - The value to set
459
459
  */
460
460
  async addMetadata(metafieldSlug, value) {
461
- const { ProfileMetafieldCollection } = await import("./ProfileMetafieldCollection-Buz7gzag-C2tZc1PF.js").then((n) => n.r).then((n) => n.n);
462
- const { ProfileMetadataCollection } = await import("./ProfileMetadataCollection-BIYKy4Y3-DXu5L2yx.js").then((n) => n.r).then((n) => n.n);
461
+ const { ProfileMetafieldCollection } = await import("./ProfileMetafieldCollection-Buz7gzag-BlJqn0f-.js").then((n) => n.r).then((n) => n.n);
462
+ const { ProfileMetadataCollection } = await import("./ProfileMetadataCollection-BIYKy4Y3-C4NyBsA_.js").then((n) => n.r).then((n) => n.n);
463
463
  const metafield = await this.resolveMetafield(await ProfileMetafieldCollection.create(this.options), metafieldSlug);
464
464
  if (!metafield) throw new Error(`Metafield '${metafieldSlug}' not found`);
465
465
  await metafield.validateValue(value);
@@ -492,7 +492,7 @@ var Profile = class extends SmrtObject {
492
492
  * @returns Object with metafield slugs as keys
493
493
  */
494
494
  async getMetadata() {
495
- const { ProfileMetadataCollection } = await import("./ProfileMetadataCollection-BIYKy4Y3-DXu5L2yx.js").then((n) => n.r).then((n) => n.n);
495
+ const { ProfileMetadataCollection } = await import("./ProfileMetadataCollection-BIYKy4Y3-C4NyBsA_.js").then((n) => n.r).then((n) => n.n);
496
496
  return await (await ProfileMetadataCollection.create(this.options)).getMetadataObject(this.id);
497
497
  }
498
498
  /**
@@ -509,8 +509,8 @@ var Profile = class extends SmrtObject {
509
509
  * @param metafieldSlug - The slug of the metafield to remove
510
510
  */
511
511
  async removeMetadata(metafieldSlug) {
512
- const { ProfileMetafieldCollection } = await import("./ProfileMetafieldCollection-Buz7gzag-C2tZc1PF.js").then((n) => n.r).then((n) => n.n);
513
- const { ProfileMetadataCollection } = await import("./ProfileMetadataCollection-BIYKy4Y3-DXu5L2yx.js").then((n) => n.r).then((n) => n.n);
512
+ const { ProfileMetafieldCollection } = await import("./ProfileMetafieldCollection-Buz7gzag-BlJqn0f-.js").then((n) => n.r).then((n) => n.n);
513
+ const { ProfileMetadataCollection } = await import("./ProfileMetadataCollection-BIYKy4Y3-C4NyBsA_.js").then((n) => n.r).then((n) => n.n);
514
514
  const metafield = await this.resolveMetafield(await ProfileMetafieldCollection.create(this.options), metafieldSlug);
515
515
  if (!metafield) throw new Error(`Metafield '${metafieldSlug}' not found`);
516
516
  const existing = await (await ProfileMetadataCollection.create(this.options)).list({
@@ -535,7 +535,7 @@ var Profile = class extends SmrtObject {
535
535
  return candidates.find((candidate) => ownerTenantId && candidate.tenantId === ownerTenantId) ?? candidates.find((candidate) => !candidate.tenantId) ?? null;
536
536
  }
537
537
  async getProfileLinkCollection() {
538
- const { ProfileLinkCollection } = await import("./ProfileLinkCollection-DFfZRsgv-MQ2zhD9z.js").then((n) => n.i).then((n) => n.r);
538
+ const { ProfileLinkCollection } = await import("./ProfileLinkCollection-DFfZRsgv-DTXdjPMD.js").then((n) => n.i).then((n) => n.r);
539
539
  return ProfileLinkCollection.create({ db: this.db });
540
540
  }
541
541
  /** This profile's web links in display order. */
@@ -552,7 +552,7 @@ var Profile = class extends SmrtObject {
552
552
  return (await this.getProfileLinkCollection()).replaceForProfile(this.id, links);
553
553
  }
554
554
  async getProfileAssetCollection() {
555
- const { ProfileAssetCollection } = await import("./ProfileAssetCollection-CRMcjLJ--C5ytBKfF.js").then((n) => n.r).then((n) => n.n);
555
+ const { ProfileAssetCollection } = await import("./ProfileAssetCollection-CRMcjLJ--M64P0MlJ.js").then((n) => n.r).then((n) => n.n);
556
556
  return ProfileAssetCollection.create({ db: this.db });
557
557
  }
558
558
  async getAssets(relationship) {
@@ -584,7 +584,7 @@ var Profile = class extends SmrtObject {
584
584
  */
585
585
  async addRelationship(toProfile, relationshipSlug, contextProfile) {
586
586
  const { ProfileRelationshipTypeCollection } = await import("./ProfileRelationshipTypeCollection-_n22WqTb-DiZUWvev.js").then((n) => n.n).then((n) => n.n);
587
- const { ProfileRelationshipCollection } = await import("./ProfileRelationshipCollection-C4g_QLI4-vTnkAIAh.js").then((n) => n.r).then((n) => n.n);
587
+ const { ProfileRelationshipCollection } = await import("./ProfileRelationshipCollection-C4g_QLI4-BoadAuj8.js").then((n) => n.r).then((n) => n.n);
588
588
  const { ProfileRelationshipType } = await import("./ProfileRelationshipType-U7IwF6Wf-DNavf24e.js").then((n) => n.n).then((n) => n.n);
589
589
  const relationshipType = await (await ProfileRelationshipTypeCollection.create(this.options)).getBySlug(relationshipSlug);
590
590
  if (!relationshipType) throw new Error(`Relationship type '${relationshipSlug}' not found`);
@@ -609,7 +609,7 @@ var Profile = class extends SmrtObject {
609
609
  * @returns Array of ProfileRelationship instances
610
610
  */
611
611
  async getRelationships(options) {
612
- const { ProfileRelationshipCollection } = await import("./ProfileRelationshipCollection-C4g_QLI4-vTnkAIAh.js").then((n) => n.r).then((n) => n.n);
612
+ const { ProfileRelationshipCollection } = await import("./ProfileRelationshipCollection-C4g_QLI4-BoadAuj8.js").then((n) => n.r).then((n) => n.n);
613
613
  const { ProfileRelationshipTypeCollection } = await import("./ProfileRelationshipTypeCollection-_n22WqTb-DiZUWvev.js").then((n) => n.n).then((n) => n.n);
614
614
  const relationshipCollection = await ProfileRelationshipCollection.create(this.options);
615
615
  const direction = options?.direction || "all";
@@ -654,7 +654,7 @@ var Profile = class extends SmrtObject {
654
654
  */
655
655
  async removeRelationship(toProfile, relationshipSlug) {
656
656
  const { ProfileRelationshipTypeCollection } = await import("./ProfileRelationshipTypeCollection-_n22WqTb-DiZUWvev.js").then((n) => n.n).then((n) => n.n);
657
- const { ProfileRelationshipCollection } = await import("./ProfileRelationshipCollection-C4g_QLI4-vTnkAIAh.js").then((n) => n.r).then((n) => n.n);
657
+ const { ProfileRelationshipCollection } = await import("./ProfileRelationshipCollection-C4g_QLI4-BoadAuj8.js").then((n) => n.r).then((n) => n.n);
658
658
  const relationshipType = await (await ProfileRelationshipTypeCollection.create(this.options)).getBySlug(relationshipSlug);
659
659
  if (!relationshipType) throw new Error(`Relationship type '${relationshipSlug}' not found`);
660
660
  const relationshipCollection = await ProfileRelationshipCollection.create(this.options);
@@ -778,7 +778,7 @@ var Profile = class extends SmrtObject {
778
778
  * @returns Array of OIDC identity records
779
779
  */
780
780
  async getOidcIdentities() {
781
- const { OidcIdentityCollection } = await import("./OidcIdentityCollection-ClOyaHeF-BpQXB3mz.js").then((n) => n.r).then((n) => n.r);
781
+ const { OidcIdentityCollection } = await import("./OidcIdentityCollection-ClOyaHeF-BmHrvh1o.js").then((n) => n.r).then((n) => n.r);
782
782
  return await (await OidcIdentityCollection.create(this.options)).findByProfile(this.id);
783
783
  }
784
784
  /**
@@ -791,7 +791,7 @@ var Profile = class extends SmrtObject {
791
791
  * type, but refuses to create or rebind authority.
792
792
  */
793
793
  async linkOidcIdentity(oidcData) {
794
- const { OidcIdentityCollection } = await import("./OidcIdentityCollection-ClOyaHeF-BpQXB3mz.js").then((n) => n.r).then((n) => n.r);
794
+ const { OidcIdentityCollection } = await import("./OidcIdentityCollection-ClOyaHeF-BmHrvh1o.js").then((n) => n.r).then((n) => n.r);
795
795
  return await (await OidcIdentityCollection.create(this.options)).linkToProfile(this, oidcData);
796
796
  }
797
797
  /**
@@ -820,7 +820,7 @@ var Profile = class extends SmrtObject {
820
820
  * @returns Array of audit log entries
821
821
  */
822
822
  async getAuditLogs(limit = 50) {
823
- const { AuditLogCollection } = await import("./AuditLogCollection-WDHL-_AF-ClQNu_VR.js").then((n) => n.r).then((n) => n.n);
823
+ const { AuditLogCollection } = await import("./AuditLogCollection-WDHL-_AF-_RXJ4g2q.js").then((n) => n.r).then((n) => n.n);
824
824
  return await (await AuditLogCollection.create(this.options)).getRecentActivity(this.id, limit);
825
825
  }
826
826
  /**
@@ -830,7 +830,7 @@ var Profile = class extends SmrtObject {
830
830
  * @returns The created audit log entry
831
831
  */
832
832
  async recordAction(options) {
833
- const { AuditLogCollection } = await import("./AuditLogCollection-WDHL-_AF-ClQNu_VR.js").then((n) => n.r).then((n) => n.n);
833
+ const { AuditLogCollection } = await import("./AuditLogCollection-WDHL-_AF-_RXJ4g2q.js").then((n) => n.r).then((n) => n.n);
834
834
  return await (await AuditLogCollection.create(this.options)).record({
835
835
  profile: this,
836
836
  ...options
@@ -1,5 +1,5 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-8H4AJuhK.js";
2
- import { i as tenantId, r as TenantScoped } from "./dist-DxkSjKQQ.js";
2
+ import { i as tenantId, r as TenantScoped } from "./dist-D56nENIY.js";
3
3
  import { n as __exportAll$1 } from "./NostrIdentity-AC8fAdxe-DKxKyu_a.js";
4
4
  import { SmrtCollection, SmrtObject, field, foreignKey, isEmbeddedDatabase, smrt, withEmbeddedWriteTransaction } from "@happyvertical/smrt-core";
5
5
  //#region ../profiles/dist/chunks/ProfileLinkCollection-DFfZRsgv.js
@@ -203,7 +203,7 @@ var ProfileLinkCollection = class ProfileLinkCollection extends SmrtCollection {
203
203
  /** The profile's tenant; throws when the profile is not visible here. */
204
204
  async requireProfileTenant(profileId) {
205
205
  if (!profileId) throw new Error("A profile link needs a profile");
206
- const { ProfileCollection } = await import("./ProfileCollection-C4INKh7Y-CfkyJilm.js").then((n) => n.o).then((n) => n.r);
206
+ const { ProfileCollection } = await import("./ProfileCollection-C4INKh7Y-Xn37Xj2d.js").then((n) => n.o).then((n) => n.r);
207
207
  const profile = await (await ProfileCollection.create({ db: this.db })).get({ id: profileId });
208
208
  if (!profile) throw new Error(`Profile '${profileId}' not found`);
209
209
  return profile.tenantId ?? null;
@@ -1,5 +1,5 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-8H4AJuhK.js";
2
- import { i as tenantId, r as TenantScoped } from "./dist-DxkSjKQQ.js";
2
+ import { i as tenantId, r as TenantScoped } from "./dist-D56nENIY.js";
3
3
  import { n as __exportAll$1 } from "./NostrIdentity-AC8fAdxe-DKxKyu_a.js";
4
4
  import { SmrtCollection, SmrtObject, field, foreignKey, smrt } from "@happyvertical/smrt-core";
5
5
  //#region ../profiles/dist/chunks/ProfileMetadataCollection-BIYKy4Y3.js
@@ -1,5 +1,5 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-8H4AJuhK.js";
2
- import { i as tenantId, r as TenantScoped } from "./dist-DxkSjKQQ.js";
2
+ import { i as tenantId, r as TenantScoped } from "./dist-D56nENIY.js";
3
3
  import { n as __exportAll$1 } from "./NostrIdentity-AC8fAdxe-DKxKyu_a.js";
4
4
  import { SmrtCollection, SmrtObject, field, smrt } from "@happyvertical/smrt-core";
5
5
  //#region ../profiles/dist/chunks/ProfileMetafieldCollection-Buz7gzag.js
@@ -1,5 +1,5 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-8H4AJuhK.js";
2
- import { i as tenantId, r as TenantScoped } from "./dist-DxkSjKQQ.js";
2
+ import { i as tenantId, r as TenantScoped } from "./dist-D56nENIY.js";
3
3
  import { n as __exportAll$1 } from "./NostrIdentity-AC8fAdxe-DKxKyu_a.js";
4
4
  import { SmrtCollection, SmrtObject, foreignKey, oneToMany, smrt } from "@happyvertical/smrt-core";
5
5
  //#region ../profiles/dist/chunks/ProfileRelationshipCollection-C4g_QLI4.js
@@ -1,7 +1,7 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-8H4AJuhK.js";
2
- import { l as isSystemContext, s as withTenantGlobalRead } from "./dist-DxkSjKQQ.js";
2
+ import { l as isSystemContext, s as withTenantGlobalRead } from "./dist-D56nENIY.js";
3
3
  import { n as __exportAll$1 } from "./NostrIdentity-AC8fAdxe-DKxKyu_a.js";
4
- import { s as ProfileType } from "./ProfileCollection-C4INKh7Y-CfkyJilm.js";
4
+ import { s as ProfileType } from "./ProfileCollection-C4INKh7Y-Xn37Xj2d.js";
5
5
  import { SmrtCollection } from "@happyvertical/smrt-core";
6
6
  //#region ../profiles/dist/chunks/ProfileTypeCollection-B7kwi1mU.js
7
7
  var ProfileTypeCollection_B7kwi1mU_exports = /* @__PURE__ */ __exportAll({
@@ -1 +1 @@
1
- {"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../../src/commands/kitchen/run.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,OAAO,EAAE,KAAK,SAAS,EAAoB,MAAM,SAAS,CAAC;AAC3D,OAAO,EACL,KAAK,WAAW,EAChB,KAAK,eAAe,EAErB,MAAM,YAAY,CAAC;AACpB,OAAO,EAEL,KAAK,WAAW,EAEhB,KAAK,cAAc,EAEpB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,KAAK,aAAa,EAAsB,MAAM,aAAa,CAAC;AAErE,MAAM,WAAW,iBAAiB;IAChC,yBAAyB;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,iDAAiD;IACjD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,OAAO,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,QAAQ,EAAE,OAAO,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7B,+EAA+E;IAC/E,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,aAAa,KAAK,IAAI,CAAC;IAC1C,+DAA+D;IAC/D,SAAS,CAAC,EAAE;QACV,OAAO,CAAC,EAAE,cAAc,CAAC;QACzB,IAAI,CAAC,EAAE,WAAW,CAAC;QACnB,EAAE,CAAC,EAAE,SAAS,GAAG,IAAI,CAAC;QACtB,KAAK,CAAC,EAAE,eAAe,CAAC;QACxB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,WAAW,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;KACrC,CAAC;IACF,qEAAqE;IACrE,IAAI,CAAC,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;CACvB;AAED,+EAA+E;AAC/E,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAWhD;AAED,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAU/C;AAED,8EAA8E;AAC9E,wBAAsB,UAAU,CAC9B,OAAO,EAAE,iBAAiB,GACzB,OAAO,CAAC,WAAW,CAAC,CAyDtB"}
1
+ {"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../../src/commands/kitchen/run.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,OAAO,EAAE,KAAK,SAAS,EAAoB,MAAM,SAAS,CAAC;AAC3D,OAAO,EACL,KAAK,WAAW,EAChB,KAAK,eAAe,EAErB,MAAM,YAAY,CAAC;AACpB,OAAO,EAEL,KAAK,WAAW,EAEhB,KAAK,cAAc,EAEpB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,KAAK,aAAa,EAAsB,MAAM,aAAa,CAAC;AAErE,MAAM,WAAW,iBAAiB;IAChC,yBAAyB;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,iDAAiD;IACjD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,OAAO,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,QAAQ,EAAE,OAAO,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7B,+EAA+E;IAC/E,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,aAAa,KAAK,IAAI,CAAC;IAC1C,+DAA+D;IAC/D,SAAS,CAAC,EAAE;QACV,OAAO,CAAC,EAAE,cAAc,CAAC;QACzB,IAAI,CAAC,EAAE,WAAW,CAAC;QACnB,EAAE,CAAC,EAAE,SAAS,GAAG,IAAI,CAAC;QACtB,KAAK,CAAC,EAAE,eAAe,CAAC;QACxB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,WAAW,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;KACrC,CAAC;IACF,qEAAqE;IACrE,IAAI,CAAC,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;CACvB;AAED,+EAA+E;AAC/E,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAWhD;AAED,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAU/C;AAED,8EAA8E;AAC9E,wBAAsB,UAAU,CAC9B,OAAO,EAAE,iBAAiB,GACzB,OAAO,CAAC,WAAW,CAAC,CA2DtB"}
@@ -13,6 +13,8 @@ export declare const CHAT_PATH = "/api/planner/chat";
13
13
  export declare const COOKBOOK_PATH = "/api/kitchen/cookbook";
14
14
  export declare const CONFIG_PATH = "/planner.config.json";
15
15
  export declare const TOKEN_HEADER = "x-kitchen-token";
16
+ /** The fragment key the planner reads the one-time token from (`#kitchen=<token>`). */
17
+ export declare const KITCHEN_FRAGMENT = "kitchen";
16
18
  export interface KitchenServerOptions {
17
19
  planner: PlannerInstall;
18
20
  core: PlannerCore;
@@ -26,7 +28,14 @@ export interface KitchenServerOptions {
26
28
  log?: (line: string) => void;
27
29
  }
28
30
  export interface KitchenServer {
31
+ /** The server's address, with no secret in it. */
29
32
  url: string;
33
+ /**
34
+ * The address to open: `url` plus `#kitchen=<token>`. A fragment is never
35
+ * sent to a server, so the token reaches the page without being readable
36
+ * from any endpoint; the planner reads it from `location.hash` and strips it.
37
+ */
38
+ openUrl: string;
30
39
  port: number;
31
40
  token: string;
32
41
  /** `host` when the chat endpoint is served, else `browser`. */
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../../src/commands/kitchen/server.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAYH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACzC,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAC/D,OAAO,KAAK,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAEhE,eAAO,MAAM,SAAS,sBAAsB,CAAC;AAC7C,eAAO,MAAM,aAAa,0BAA0B,CAAC;AACrD,eAAO,MAAM,WAAW,yBAAyB,CAAC;AAClD,eAAO,MAAM,YAAY,oBAAoB,CAAC;AAK9C,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,cAAc,CAAC;IACxB,IAAI,EAAE,WAAW,CAAC;IAClB,wEAAwE;IACxE,EAAE,EAAE,SAAS,GAAG,IAAI,CAAC;IACrB,KAAK,EAAE,eAAe,CAAC;IACvB,oCAAoC;IACpC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,gEAAgE;IAChE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CAC9B;AAED,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,+DAA+D;IAC/D,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;IACzB,4EAA4E;IAC5E,OAAO,EAAE,OAAO,CAAC,WAAW,CAAC,CAAC;IAC9B,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAsDD,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,oBAAoB,GAC5B,OAAO,CAAC,aAAa,CAAC,CAoNxB"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../../src/commands/kitchen/server.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAYH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACzC,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAC/D,OAAO,KAAK,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAEhE,eAAO,MAAM,SAAS,sBAAsB,CAAC;AAC7C,eAAO,MAAM,aAAa,0BAA0B,CAAC;AACrD,eAAO,MAAM,WAAW,yBAAyB,CAAC;AAClD,eAAO,MAAM,YAAY,oBAAoB,CAAC;AAC9C,uFAAuF;AACvF,eAAO,MAAM,gBAAgB,YAAY,CAAC;AAK1C,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,cAAc,CAAC;IACxB,IAAI,EAAE,WAAW,CAAC;IAClB,wEAAwE;IACxE,EAAE,EAAE,SAAS,GAAG,IAAI,CAAC;IACrB,KAAK,EAAE,eAAe,CAAC;IACvB,oCAAoC;IACpC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,gEAAgE;IAChE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CAC9B;AAED,MAAM,WAAW,aAAa;IAC5B,kDAAkD;IAClD,GAAG,EAAE,MAAM,CAAC;IACZ;;;;OAIG;IACH,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,+DAA+D;IAC/D,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;IACzB,4EAA4E;IAC5E,OAAO,EAAE,OAAO,CAAC,WAAW,CAAC,CAAC;IAC9B,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAsDD,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,oBAAoB,GAC5B,OAAO,CAAC,aAAa,CAAC,CAqNxB"}
@@ -7086,6 +7086,8 @@ async function resolveKitchenAI(options = {}) {
7086
7086
  */
7087
7087
  var CHAT_PATH = "/api/planner/chat";
7088
7088
  var COOKBOOK_PATH = "/api/kitchen/cookbook";
7089
+ /** The fragment key the planner reads the one-time token from (`#kitchen=<token>`). */
7090
+ var KITCHEN_FRAGMENT = "kitchen";
7089
7091
  var CHAT_LIMIT = 256 * 1024;
7090
7092
  var COOKBOOK_LIMIT = 2 * 1024 * 1024;
7091
7093
  var TYPES = {
@@ -7152,10 +7154,7 @@ async function startKitchenServer(options) {
7152
7154
  mode: "host",
7153
7155
  host: { endpoint: CHAT_PATH }
7154
7156
  } : { mode: "browser" },
7155
- kitchen: {
7156
- endpoint: COOKBOOK_PATH,
7157
- token
7158
- }
7157
+ kitchen: { endpoint: COOKBOOK_PATH }
7159
7158
  });
7160
7159
  function checkToken(supplied) {
7161
7160
  if (!supplied) return false;
@@ -7290,6 +7289,7 @@ async function startKitchenServer(options) {
7290
7289
  port = server.address().port;
7291
7290
  return {
7292
7291
  url: `http://127.0.0.1:${port}/`,
7292
+ openUrl: `http://127.0.0.1:${port}/#${KITCHEN_FRAGMENT}=${token}`,
7293
7293
  port,
7294
7294
  token,
7295
7295
  mode,
@@ -7351,11 +7351,12 @@ async function runKitchen(options) {
7351
7351
  });
7352
7352
  try {
7353
7353
  log(`Planner ${planner.version ?? ""} (${planner.source}) at ${server.url}`.replace(" ", " "));
7354
+ log(`Open ${server.openUrl}`);
7354
7355
  log(ai ? `Chat is answered by ${ai.label}.` : "No AI provider is configured (set an `ai` block in smrt.config.ts, SMRT_AI_PROVIDER, or e.g. OPENAI_API_KEY), so the planner runs its in-browser model. You can also build the cookbook by hand.");
7355
7356
  log(`Project directory: ${dir}`);
7356
7357
  log("Build your app in the planner, then choose \"Send to kitchen\". Ctrl-C to stop.");
7357
7358
  options.onReady?.(server);
7358
- if (options.open) (options.overrides?.openBrowser ?? openInBrowser)(server.url);
7359
+ if (options.open) (options.overrides?.openBrowser ?? openInBrowser)(server.openUrl);
7359
7360
  return await (options.stop ? Promise.race([server.applied, options.stop]) : server.applied);
7360
7361
  } finally {
7361
7362
  await server.close();
@@ -7887,7 +7888,7 @@ var dbMaterializeTenantHierarchyCommand = {
7887
7888
  if (!config.database?.url || config.database.url === ":memory:") throw new Error("Database configuration required for db:materialize-tenant-hierarchy. Configure database.url in smrt.config.ts (or DATABASE_URL).");
7888
7889
  const dbType = config.database.type || "sqlite";
7889
7890
  const { getDatabase } = await import("@happyvertical/sql");
7890
- const { materializeTenantHierarchy, TenantHierarchyMaterializationError } = await import("./dist-BsRSQ_hE.js");
7891
+ const { materializeTenantHierarchy, TenantHierarchyMaterializationError } = await import("./dist-BCW7OSeu.js");
7891
7892
  db = await getDatabase({
7892
7893
  type: dbType,
7893
7894
  url: config.database.url
@@ -8096,7 +8097,7 @@ var dbMigrateLedgerAccountsCommand = {
8096
8097
  if (dbType !== "postgres") throw new Error("db:migrate-ledger-accounts currently supports PostgreSQL only; no changes were made. See the smrt-ledgers README for SQLite.");
8097
8098
  await autoDiscoverAndLoad();
8098
8099
  const { getDatabase } = await import("@happyvertical/sql");
8099
- const { migrateLedgerAccountsTable, planLedgerAccountsTableMove } = await import("./dist-CYVIKmvy.js");
8100
+ const { migrateLedgerAccountsTable, planLedgerAccountsTableMove } = await import("./dist-6XMOPmAQ.js");
8100
8101
  db = await getDatabase({
8101
8102
  type: dbType,
8102
8103
  url: config.database.url