@stigmer/server 3.17.0 → 3.18.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.
Files changed (53) hide show
  1. package/dist/boot/compose.d.ts +12 -0
  2. package/dist/boot/compose.d.ts.map +1 -1
  3. package/dist/boot/compose.js +4 -2
  4. package/dist/boot/compose.js.map +1 -1
  5. package/dist/domain/iampolicy/constants.d.ts +3 -3
  6. package/dist/domain/iampolicy/constants.js +3 -3
  7. package/dist/domain/oauthapp/refresolution/refresolution.js +1 -1
  8. package/dist/domain/oauthapp/refresolution.js +1 -1
  9. package/dist/domain/platform/controller.d.ts +8 -1
  10. package/dist/domain/platform/controller.d.ts.map +1 -1
  11. package/dist/domain/platform/controller.js +2 -3
  12. package/dist/domain/platform/controller.js.map +1 -1
  13. package/dist/domain/plugin/constants.d.ts +7 -1
  14. package/dist/domain/plugin/constants.d.ts.map +1 -1
  15. package/dist/domain/plugin/constants.js +7 -1
  16. package/dist/domain/plugin/constants.js.map +1 -1
  17. package/dist/domain/plugin/materialize/plan.d.ts.map +1 -1
  18. package/dist/domain/plugin/materialize/plan.js +16 -1
  19. package/dist/domain/plugin/materialize/plan.js.map +1 -1
  20. package/dist/domain/plugin/members.d.ts +46 -0
  21. package/dist/domain/plugin/members.d.ts.map +1 -1
  22. package/dist/domain/plugin/members.js +31 -8
  23. package/dist/domain/plugin/members.js.map +1 -1
  24. package/dist/domain/plugin/push.d.ts +5 -3
  25. package/dist/domain/plugin/push.d.ts.map +1 -1
  26. package/dist/domain/plugin/push.js +58 -14
  27. package/dist/domain/plugin/push.js.map +1 -1
  28. package/dist/pipeline/apiresource-labels.d.ts +20 -1
  29. package/dist/pipeline/apiresource-labels.d.ts.map +1 -1
  30. package/dist/pipeline/apiresource-labels.js +17 -0
  31. package/dist/pipeline/apiresource-labels.js.map +1 -1
  32. package/dist/store/interface.d.ts +6 -2
  33. package/dist/store/interface.d.ts.map +1 -1
  34. package/dist/store/interface.js.map +1 -1
  35. package/package.json +5 -5
  36. package/src/boot/compose.ts +16 -2
  37. package/src/domain/iampolicy/constants.ts +3 -3
  38. package/src/domain/oauthapp/__tests__/oauthapp.test.ts +2 -2
  39. package/src/domain/oauthapp/__tests__/refresolution.test.ts +2 -2
  40. package/src/domain/oauthapp/refresolution/refresolution.ts +1 -1
  41. package/src/domain/oauthapp/refresolution.ts +1 -1
  42. package/src/domain/platform/__tests__/platform.test.ts +47 -0
  43. package/src/domain/platform/controller.ts +10 -4
  44. package/src/domain/plugin/__tests__/materialize.test.ts +42 -47
  45. package/src/domain/plugin/__tests__/members.test.ts +149 -0
  46. package/src/domain/plugin/__tests__/plugin.test.ts +219 -8
  47. package/src/domain/plugin/constants.ts +7 -1
  48. package/src/domain/plugin/materialize/plan.ts +20 -1
  49. package/src/domain/plugin/members.ts +76 -7
  50. package/src/domain/plugin/push.ts +80 -20
  51. package/src/pipeline/apiresource-labels.ts +26 -1
  52. package/src/sandbox/__tests__/local-process.integration.test.ts +20 -6
  53. package/src/store/interface.ts +6 -2
@@ -13,7 +13,11 @@
13
13
  * authorizer's permissive default ALLOWS reserved-label writes by design
14
14
  * (the self-hosted operator owns the store), which is why a restrict-shaped
15
15
  * predicate here still pairs the label with server-owned state: the
16
- * plugin-managed guard refuses only beside an existing plugin row.
16
+ * plugin-managed guard refuses only beside an existing plugin row, and a
17
+ * plugin adopts a system-content row only when its own claim to the same
18
+ * label was just charged to `can_write_reserved_labels` by the sanitiser
19
+ * (domain/plugin/members.ts) — the label narrows which rows are eligible,
20
+ * the live authorization is what grants.
17
21
  */
18
22
  import type { ApiResourceMetadata } from "@stigmer/protos/ai/stigmer/commons/apiresource/metadata_pb";
19
23
 
@@ -39,6 +43,20 @@ export const DEFAULT_INSTANCE_LABEL = `${RESERVED_LABEL_PREFIX}default-instance`
39
43
  */
40
44
  export const SYSTEM_MANAGED_LABEL = `${RESERVED_LABEL_PREFIX}system-managed`;
41
45
 
46
+ /**
47
+ * Marks system content: a resource the platform itself seeded rather than a
48
+ * user authored — the system organization, the default agent, the
49
+ * platform's own MCP servers. The label predates this module (the retired
50
+ * seedpack wrote it on every row it applied; the official plugins' overlays
51
+ * carry it on the resources they replace) and has one server-side meaning:
52
+ * a plugin push may adopt a system-content row that holds a slug the plugin
53
+ * needs, keeping the row's id and everything bound to it, instead of
54
+ * refusing the slug as taken. It never marks a user's resource, so a user's
55
+ * row is never adopted (domain/plugin/members.ts, judgeSlug). The CLI names
56
+ * the same bytes as SYSTEM_ORG_LABEL for the organization it ensures.
57
+ */
58
+ export const SYSTEM_LABEL = `${RESERVED_LABEL_PREFIX}system`;
59
+
42
60
  /**
43
61
  * The only value that activates a reserved marker label; any other value is
44
62
  * inert (matching cloud's "true".equals(...)). Stamped by the flows that
@@ -86,3 +104,10 @@ export function isDefaultInstance(
86
104
  ): boolean {
87
105
  return metadata?.labels[DEFAULT_INSTANCE_LABEL] === RESERVED_LABEL_TRUE;
88
106
  }
107
+
108
+ /** Whether the metadata carries the SYSTEM_LABEL marker (undefined-safe). */
109
+ export function isSystemContent(
110
+ metadata: ApiResourceMetadata | undefined,
111
+ ): boolean {
112
+ return metadata?.labels[SYSTEM_LABEL] === RESERVED_LABEL_TRUE;
113
+ }
@@ -6,7 +6,11 @@
6
6
  * can read it, so no real runner install is needed.
7
7
  *
8
8
  * Unix-only like the runner itself; deterministic (poll with timeout,
9
- * never sleep).
9
+ * never sleep). Every poll gets an explicit budget: vitest's default
10
+ * second is enough on an idle laptop and not under the full suite's
11
+ * load, where a /bin/sh child can take longer than that to start and
12
+ * write its first line. Polling returns the moment the condition holds,
13
+ * so the larger budget costs nothing on a quiet host.
10
14
  */
11
15
  import {
12
16
  chmodSync,
@@ -25,6 +29,9 @@ import { createLogger } from "../../boot/logger.js";
25
29
  import { newLocalProcessSandboxProvisioner } from "../local-process.js";
26
30
  import type { SandboxDriverConfig } from "../provisioner.js";
27
31
 
32
+ /** How long a spawned child is given to start, write, or die under load. */
33
+ const CHILD_SETTLE_TIMEOUT_MS = 10_000;
34
+
28
35
  const silentLogger = createLogger({
29
36
  level: "error",
30
37
  pretty: false,
@@ -75,7 +82,9 @@ describe.skipIf(process.platform === "win32")(
75
82
  taskQueue: "session:ses_smoke",
76
83
  stigmerToken: "tok-smoke",
77
84
  });
78
- await vi.waitFor(() => expect(spawnCount()).toBe(1));
85
+ await vi.waitFor(() => expect(spawnCount()).toBe(1), {
86
+ timeout: CHILD_SETTLE_TIMEOUT_MS,
87
+ });
79
88
  expect(await driver.probe("session", "ses_smoke")).toBe("running");
80
89
 
81
90
  // Fast path: a second ensure must not spawn a second process.
@@ -104,16 +113,21 @@ describe.skipIf(process.platform === "win32")(
104
113
 
105
114
  it("deprovision kills the child; probe reports absent; re-ensure respawns", async () => {
106
115
  await driver.deprovisionSessionSandbox("ses_smoke");
107
- await vi.waitFor(async () => {
108
- expect(await driver.probe("session", "ses_smoke")).toBe("absent");
109
- });
116
+ await vi.waitFor(
117
+ async () => {
118
+ expect(await driver.probe("session", "ses_smoke")).toBe("absent");
119
+ },
120
+ { timeout: CHILD_SETTLE_TIMEOUT_MS },
121
+ );
110
122
 
111
123
  // The repair arm without stored state: a fresh ensure respawns.
112
124
  await driver.ensureSessionSandbox("ses_smoke", {
113
125
  taskQueue: "session:ses_smoke",
114
126
  stigmerToken: "",
115
127
  });
116
- await vi.waitFor(() => expect(spawnCount()).toBe(2));
128
+ await vi.waitFor(() => expect(spawnCount()).toBe(2), {
129
+ timeout: CHILD_SETTLE_TIMEOUT_MS,
130
+ });
117
131
  expect(await driver.probe("session", "ses_smoke")).toBe("running");
118
132
  });
119
133
 
@@ -217,8 +217,12 @@ export interface SearchIndexQueryResult {
217
217
  // =============================================================================
218
218
 
219
219
  /**
220
- * Key-value state for idempotent seedpack bootstrap. Common keys:
221
- * "seedpack_version", "bootstrap_status", "skill:<name>", "agent:<name>".
220
+ * Key-value state for one-shot boot work that must run once per database.
221
+ * The one writer today is the membership rules' reconciliation
222
+ * (`iampolicy/constants.ts` ROLES_RECONCILED_KEY). A database migrated
223
+ * from the Go server carries that server's bootstrap keys too; the
224
+ * migration preserves them (see sqlite/__tests__/migrations.test.ts) and
225
+ * nothing reads them.
222
226
  */
223
227
  export interface BootstrapStateStore {
224
228
  /** Returns "" (not an error) when the key does not exist — Go's contract. */