@stigmer/cli 3.19.0 → 3.20.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 (106) hide show
  1. package/commands/apply.d.ts.map +1 -1
  2. package/commands/apply.js +42 -100
  3. package/commands/apply.js.map +1 -1
  4. package/commands/validate.js +3 -4
  5. package/commands/validate.js.map +1 -1
  6. package/local/bootstrap.d.ts +1 -2
  7. package/local/bootstrap.d.ts.map +1 -1
  8. package/local/bootstrap.js +13 -41
  9. package/local/bootstrap.js.map +1 -1
  10. package/local/daemon/launch.d.ts +2 -2
  11. package/local/daemon/launch.d.ts.map +1 -1
  12. package/local/daemon/launch.js +2 -2
  13. package/local/daemon/launch.js.map +1 -1
  14. package/local/plugins/defaults.js +2 -2
  15. package/local/plugins/defaults.js.map +1 -1
  16. package/package.json +7 -7
  17. package/registry/index.d.ts +2 -2
  18. package/registry/index.d.ts.map +1 -1
  19. package/registry/index.js +2 -2
  20. package/registry/index.js.map +1 -1
  21. package/registry/metadata.d.ts +9 -0
  22. package/registry/metadata.d.ts.map +1 -1
  23. package/registry/metadata.js +14 -5
  24. package/registry/metadata.js.map +1 -1
  25. package/registry/registry.d.ts +9 -0
  26. package/registry/registry.d.ts.map +1 -1
  27. package/registry/registry.js +16 -1
  28. package/registry/registry.js.map +1 -1
  29. package/registry/verb-support.d.ts.map +1 -1
  30. package/registry/verb-support.js +0 -13
  31. package/registry/verb-support.js.map +1 -1
  32. package/resources/apply/apply.d.ts +11 -12
  33. package/resources/apply/apply.d.ts.map +1 -1
  34. package/resources/apply/apply.js +12 -21
  35. package/resources/apply/apply.js.map +1 -1
  36. package/resources/apply/handlers.js +2 -2
  37. package/resources/apply/handlers.js.map +1 -1
  38. package/resources/delete.d.ts.map +1 -1
  39. package/resources/delete.js +0 -1
  40. package/resources/delete.js.map +1 -1
  41. package/resources/get-bindings.d.ts.map +1 -1
  42. package/resources/get-bindings.js +0 -5
  43. package/resources/get-bindings.js.map +1 -1
  44. package/resources/list.d.ts.map +1 -1
  45. package/resources/list.js +0 -1
  46. package/resources/list.js.map +1 -1
  47. package/resources/validate.d.ts.map +1 -1
  48. package/resources/validate.js +0 -2
  49. package/resources/validate.js.map +1 -1
  50. package/src/commands/apply.ts +35 -150
  51. package/src/commands/validate.ts +2 -4
  52. package/src/local/bootstrap.test.ts +15 -59
  53. package/src/local/bootstrap.ts +12 -53
  54. package/src/local/daemon/launch.ts +4 -4
  55. package/src/local/plugins/defaults.ts +2 -2
  56. package/src/registry/index.ts +7 -1
  57. package/src/registry/metadata.ts +15 -5
  58. package/src/registry/registry.test.ts +1 -7
  59. package/src/registry/registry.ts +17 -1
  60. package/src/registry/verb-support.ts +0 -13
  61. package/src/resources/apply/apply.integration.test.ts +15 -3
  62. package/src/resources/apply/apply.ts +15 -26
  63. package/src/resources/apply/handlers.ts +2 -2
  64. package/src/resources/delete.ts +0 -1
  65. package/src/resources/get-bindings.ts +0 -5
  66. package/src/resources/list.ts +0 -1
  67. package/src/resources/validate.test.ts +0 -1
  68. package/src/resources/validate.ts +0 -2
  69. package/local/seedpack-retire.d.ts +0 -63
  70. package/local/seedpack-retire.d.ts.map +0 -1
  71. package/local/seedpack-retire.js +0 -361
  72. package/local/seedpack-retire.js.map +0 -1
  73. package/resources/apply/declarative.d.ts +0 -106
  74. package/resources/apply/declarative.d.ts.map +0 -1
  75. package/resources/apply/declarative.js +0 -397
  76. package/resources/apply/declarative.js.map +0 -1
  77. package/resources/apply/synth/project-track.d.ts +0 -21
  78. package/resources/apply/synth/project-track.d.ts.map +0 -1
  79. package/resources/apply/synth/project-track.js +0 -102
  80. package/resources/apply/synth/project-track.js.map +0 -1
  81. package/resources/apply/synth/reader.d.ts +0 -18
  82. package/resources/apply/synth/reader.d.ts.map +0 -1
  83. package/resources/apply/synth/reader.js +0 -55
  84. package/resources/apply/synth/reader.js.map +0 -1
  85. package/resources/apply/synth/runtime.d.ts +0 -8
  86. package/resources/apply/synth/runtime.d.ts.map +0 -1
  87. package/resources/apply/synth/runtime.js +0 -32
  88. package/resources/apply/synth/runtime.js.map +0 -1
  89. package/resources/apply/synth/synthesize.d.ts +0 -43
  90. package/resources/apply/synth/synthesize.d.ts.map +0 -1
  91. package/resources/apply/synth/synthesize.js +0 -115
  92. package/resources/apply/synth/synthesize.js.map +0 -1
  93. package/src/local/seedpack-retire.test.ts +0 -499
  94. package/src/local/seedpack-retire.ts +0 -474
  95. package/src/resources/apply/declarative.integration.test.ts +0 -204
  96. package/src/resources/apply/declarative.test.ts +0 -132
  97. package/src/resources/apply/declarative.ts +0 -491
  98. package/src/resources/apply/synth/capstone.integration.test.ts +0 -134
  99. package/src/resources/apply/synth/project-track.integration.test.ts +0 -194
  100. package/src/resources/apply/synth/project-track.ts +0 -126
  101. package/src/resources/apply/synth/reader.test.ts +0 -90
  102. package/src/resources/apply/synth/reader.ts +0 -68
  103. package/src/resources/apply/synth/runtime.test.ts +0 -29
  104. package/src/resources/apply/synth/runtime.ts +0 -39
  105. package/src/resources/apply/synth/synthesize.test.ts +0 -109
  106. package/src/resources/apply/synth/synthesize.ts +0 -161
@@ -1,18 +1,23 @@
1
1
  // `stigmer apply` — deploy resources to the backend.
2
2
  //
3
3
  // File mode (-f): apply individual YAML resource files (or a directory)
4
- // Declarative mode: a stigmer.yaml project directory (scan + reconcile)
5
- // Plugin track: a directory holding a plugin manifest (either flag,
4
+ // Plugin track: a directory holding a plugin manifest (the -f path,
6
5
  // or the working directory) installs as a plugin — the
7
6
  // same read, zip and push as `push plugin <dir>`, so the
8
7
  // two verbs are one code path
9
8
  //
9
+ // A bare `stigmer apply` in a directory that is neither prints what the
10
+ // command can do. A `stigmer.yaml` there is the retired Project format, and
11
+ // the guidance says so: a folder of resources that belong together is a
12
+ // plugin.
13
+ //
10
14
  // Resources marshal strictly from YAML to full protos and apply through the raw
11
15
  // command controllers (preserving metadata.id so updates aren't misrouted as
12
16
  // creates). Heavy modules are lazy-imported so `--help` stays fast (DD-001).
17
+ import { existsSync } from "node:fs";
18
+ import { join } from "node:path";
13
19
  import type { Command } from "commander";
14
20
  import { ensureAuthenticated, resolveOrganization } from "../config/index.js";
15
- import { UsageError } from "../errors/index.js";
16
21
  import {
17
22
  CommandResult,
18
23
  type OutputFlags,
@@ -21,23 +26,22 @@ import {
21
26
  } from "../output/index.js";
22
27
  import { addResultFlags, globalOrg, resultFormat } from "./shared.js";
23
28
 
29
+ /**
30
+ * The manifest file the retired Project format kept at a directory's root.
31
+ * Read only to recognise an old repository and say what happened to it.
32
+ */
33
+ const RETIRED_PROJECT_FILE = "stigmer.yaml";
34
+
24
35
  interface ApplyFlags extends OutputFlags {
25
36
  file?: string;
26
- config?: string;
27
- prune?: boolean;
28
37
  dryRun?: boolean;
29
38
  }
30
39
 
31
40
  export function registerApply(program: Command): void {
32
41
  const apply = program
33
42
  .command("apply")
34
- .description("apply resources from files or a project directory")
35
- .option("-f, --file <path>", "path to a YAML file or directory")
36
- .option("--config <path>", "path to a project directory (declarative mode)")
37
- // S1: Go plumbs --prune but never sends it — the server always reconciles
38
- // orphans by member set-difference. We reproduce the flag (default on) for
39
- // parity; it is intentionally a no-op client-side. Tracked as a Go follow-up.
40
- .option("--prune", "delete orphaned resources (declarative mode)", true)
43
+ .description("apply resources from files or a plugin directory")
44
+ .option("-f, --file <path>", "path to a YAML file, a directory of YAML files, or a plugin directory")
41
45
  .option("--dry-run", "validate without applying")
42
46
  .action((options: ApplyFlags, command: Command) =>
43
47
  runApply(options, command),
@@ -56,9 +60,7 @@ async function runApply(options: ApplyFlags, command: Command): Promise<void> {
56
60
  const target =
57
61
  options.file !== undefined && options.file !== ""
58
62
  ? options.file
59
- : options.config !== undefined && options.config !== ""
60
- ? options.config
61
- : process.cwd();
63
+ : process.cwd();
62
64
  const { isPluginDirectory } = await import("../resources/plugin.js");
63
65
  if (isPluginDirectory(target)) {
64
66
  await runPluginApply(target, orgOverride, options.dryRun === true, format);
@@ -75,7 +77,7 @@ async function runApply(options: ApplyFlags, command: Command): Promise<void> {
75
77
  return;
76
78
  }
77
79
 
78
- await runDeclarativeApply(options, orgOverride, format);
80
+ renderResult(buildGuidance(target), format);
79
81
  }
80
82
 
81
83
  // Plugin track: install or upgrade the plugin folder as one unit through the
@@ -130,123 +132,6 @@ async function runPluginApply(
130
132
  );
131
133
  }
132
134
 
133
- // Declarative mode: detect stigmer.yaml (walk up). Absent → atomic guidance.
134
- // entry_point set → SDK/project synthesis track. Otherwise scan the project and
135
- // reconcile membership. Both project tracks converge on the shared reconciler.
136
- async function runDeclarativeApply(
137
- options: ApplyFlags,
138
- orgOverride: string | undefined,
139
- format: OutputFormat,
140
- ): Promise<void> {
141
- const { detectTrack, applyDeclarative, previewDeclarative } =
142
- await import("../resources/apply/declarative.js");
143
-
144
- const startDir =
145
- options.config !== undefined && options.config !== ""
146
- ? options.config
147
- : process.cwd();
148
- const detect = detectTrack(startDir);
149
-
150
- if (detect.track === "atomic") {
151
- renderResult(buildAtomicGuidance(), format);
152
- return;
153
- }
154
-
155
- if (detect.track === "project") {
156
- await runProjectApply(detect, orgOverride, format, options.dryRun === true);
157
- return;
158
- }
159
-
160
- if (options.dryRun === true) {
161
- const { results, summary } = previewDeclarative(detect, {
162
- controller: throwingController,
163
- warn: (line) => emitWarning(line),
164
- });
165
- for (const result of results) renderResult(result, format);
166
- renderResult(summary, format);
167
- return;
168
- }
169
-
170
- const { connectBackend } = await import("../backend.js");
171
- const client = connectBackend();
172
- ensureAuthenticated(client.config);
173
- const org = resolveDeclarativeOrg(
174
- client.config,
175
- detect.project?.metadata?.org,
176
- orgOverride,
177
- );
178
-
179
- const result = await applyDeclarative(detect, {
180
- controller: client.controller,
181
- stigmer: client.stigmer,
182
- org,
183
- info: (line) => process.stderr.write(`${line}\n`),
184
- warn: (line) => emitWarning(line),
185
- });
186
- renderResult(result, format);
187
- }
188
-
189
- // Project (SDK synthesis) track: run the user's entry_point, read the `.pb`
190
- // output, and reconcile membership through the same reconciler the declarative
191
- // track uses. Lazy-imported to preserve the DD-001 boundary (`--help` stays
192
- // fast).
193
- async function runProjectApply(
194
- detect: import("../resources/apply/declarative.js").DetectResult,
195
- orgOverride: string | undefined,
196
- format: OutputFormat,
197
- dryRun: boolean,
198
- ): Promise<void> {
199
- const { applyProjectTrack, previewProjectTrack } =
200
- await import("../resources/apply/synth/project-track.js");
201
-
202
- if (dryRun) {
203
- renderResult(previewProjectTrack(detect), format);
204
- return;
205
- }
206
-
207
- const { connectBackend } = await import("../backend.js");
208
- const client = connectBackend();
209
- ensureAuthenticated(client.config);
210
- const org = resolveDeclarativeOrg(
211
- client.config,
212
- detect.project?.metadata?.org,
213
- orgOverride,
214
- );
215
-
216
- const result = await applyProjectTrack(detect, {
217
- controller: client.controller,
218
- stigmer: client.stigmer,
219
- org,
220
- info: (line) => process.stderr.write(`${line}\n`),
221
- warn: (line) => emitWarning(line),
222
- });
223
- renderResult(result, format);
224
- }
225
-
226
- // Org precedence mirrors Go's resolveApplyOrganization: --org flag, then
227
- // metadata.org in stigmer.yaml, then the configured context. Empty → a clear
228
- // "set your org" usage error.
229
- function resolveDeclarativeOrg(
230
- config: import("../config/index.js").Config,
231
- projectOrg: string | undefined,
232
- override: string | undefined,
233
- ): string {
234
- const resolved = resolveOrganization(
235
- config,
236
- override ?? (projectOrg !== "" ? projectOrg : undefined),
237
- );
238
- if (resolved === "") {
239
- throw new UsageError(
240
- "organization not set\n\n" +
241
- "Specify organization in one of these ways:\n" +
242
- " 1. Set metadata.org in stigmer.yaml\n" +
243
- " 2. Use --org flag: stigmer apply --org <org>\n" +
244
- " 3. Set context: stigmer context set --org <org>",
245
- );
246
- }
247
- return resolved;
248
- }
249
-
250
135
  async function runFileApply(
251
136
  path: string,
252
137
  orgOverride: string | undefined,
@@ -298,24 +183,24 @@ async function runFileApply(
298
183
  );
299
184
  }
300
185
 
301
- function buildAtomicGuidance(): CommandResult {
302
- const result = CommandResult.warning(
303
- "No stigmer.yaml found in current directory or parents",
304
- );
186
+ // What a bare `stigmer apply` says when the target holds no plugin manifest:
187
+ // the two things the command does, and, when a `stigmer.yaml` sits there,
188
+ // what that file was and where its resources go now.
189
+ function buildGuidance(target: string): CommandResult {
190
+ const result = CommandResult.warning(`No plugin manifest in ${target}`);
305
191
  result
306
- .addSection("")
307
- .item(
308
- "The 'stigmer apply' command (without -f) requires a project with stigmer.yaml",
309
- )
310
- .item("This enables resource discovery and project-based reconciliation");
311
- result
312
- .addSection("For single-resource deployment, use file mode")
313
- .item("stigmer apply -f agent.yaml")
314
- .item("stigmer apply -f workflow.yaml")
315
- .item("stigmer apply -f mcpserver.yaml");
316
- result.hint(
317
- "To create a project: add a stigmer.yaml with your project name, then run 'stigmer apply'",
318
- );
192
+ .addSection("What 'stigmer apply' does")
193
+ .item("stigmer apply -f <file> apply a resource file (agent, workflow, MCP server, ...)")
194
+ .item("stigmer apply -f <dir> apply every YAML file in a directory")
195
+ .item("stigmer push skill <dir> publish a skill folder")
196
+ .item("stigmer push plugin <dir> install a folder of resources as one plugin");
197
+ if (existsSync(join(target, RETIRED_PROJECT_FILE))) {
198
+ result
199
+ .addSection(`About the ${RETIRED_PROJECT_FILE} here`)
200
+ .item(
201
+ "It is the Project format, which Stigmer no longer has. A folder of resources that belong together is a plugin: run `stigmer push plugin <dir>`, or apply each resource file with `stigmer apply -f`.",
202
+ );
203
+ }
319
204
  return result;
320
205
  }
321
206
 
@@ -23,7 +23,7 @@ import {
23
23
  type OutputFlags,
24
24
  renderResult,
25
25
  } from "../output/index.js";
26
- import { defaultRegistry, Verb } from "../registry/index.js";
26
+ import { defaultRegistry, unknownKindError, Verb } from "../registry/index.js";
27
27
  import { loadDocuments, resolveYamlFiles } from "../resources/documents.js";
28
28
  import { addResultFlags, resultFormat } from "./shared.js";
29
29
 
@@ -70,9 +70,7 @@ async function runValidate(options: ValidateFlags): Promise<CommandResult> {
70
70
  // Validate stays lenient (default) — strict parsing is reserved for apply.
71
71
  for (const { kind, document } of loadDocuments(file)) {
72
72
  const info = registry.getByYamlKind(kind);
73
- if (info === undefined) {
74
- throw new UsageError(`unknown resource kind '${kind}' in ${file}`);
75
- }
73
+ if (info === undefined) throw unknownKindError(kind, file);
76
74
  if (!info.supportedVerbs.has(Verb.Validate)) {
77
75
  throw new UsageError(
78
76
  `${info.displayName} does not support validation (in ${file})`,
@@ -1,9 +1,7 @@
1
- // Pins the local bootstrap's shape: prepare, then run, then retire, over one
2
- // client; a preparation failure skips the run and the retire together, and a
3
- // run that cannot start skips the retire (nothing is deleted before its
4
- // replacement is in place); a default that failed to land is one warning
5
- // naming `stigmer bootstrap` and holds the retire back with a line saying so;
6
- // a retire failure is contained by its own warning; nothing throws past the
1
+ // Pins the local bootstrap's shape: prepare, then run, over one client; a
2
+ // preparation failure skips the run with one warning naming the retry; a
3
+ // run that cannot start is one warning; a default that failed to land is one
4
+ // warning per default naming `stigmer bootstrap`; nothing throws past the
7
5
  // bootstrap.
8
6
 
9
7
  import { describe, expect, it } from "vitest";
@@ -24,9 +22,9 @@ function converged(): BootstrapResult {
24
22
  }
25
23
 
26
24
  describe("bootstrapLocalBackend", () => {
27
- it("prepares, runs, then retires, over the same client and home", async () => {
25
+ it("prepares, then runs, over the same client", async () => {
28
26
  const order: string[] = [];
29
- await bootstrapLocalBackend("/home/x", {
27
+ await bootstrapLocalBackend({
30
28
  client,
31
29
  say: () => {},
32
30
  prepare: async () => {
@@ -39,20 +37,14 @@ describe("bootstrapLocalBackend", () => {
39
37
  order.push("run");
40
38
  return converged();
41
39
  },
42
- retire: async (s, home) => {
43
- expect(s).toBe(stigmer);
44
- expect(home).toBe("/home/x");
45
- order.push("retire");
46
- },
47
40
  });
48
- expect(order).toEqual(["prepare", "run", "retire"]);
41
+ expect(order).toEqual(["prepare", "run"]);
49
42
  });
50
43
 
51
- it("skips the run and the retire when preparation fails, with one warning", async () => {
44
+ it("skips the run when preparation fails, with one warning", async () => {
52
45
  const said: string[] = [];
53
- let retired = 0;
54
46
  let ran = 0;
55
- await bootstrapLocalBackend("/home/x", {
47
+ await bootstrapLocalBackend({
56
48
  client,
57
49
  say: (line) => said.push(line),
58
50
  prepare: async () => {
@@ -62,41 +54,31 @@ describe("bootstrapLocalBackend", () => {
62
54
  ran += 1;
63
55
  return converged();
64
56
  },
65
- retire: async () => {
66
- retired += 1;
67
- },
68
57
  });
69
58
  expect(ran).toBe(0);
70
- expect(retired).toBe(0);
71
59
  expect(said).toEqual([
72
- "Warning: could not prepare the default plugins, so the local backend was not bootstrapped and nothing was retired. Run 'stigmer up' again to retry.",
60
+ "Warning: could not prepare the default plugins, so the local backend was not bootstrapped. Run 'stigmer up' again to retry.",
73
61
  ]);
74
62
  });
75
63
 
76
- it("skips the retire when the run cannot even start, with one warning naming the retry", async () => {
64
+ it("contains a run that cannot start in one warning naming the retry", async () => {
77
65
  const said: string[] = [];
78
- let retired = 0;
79
- await bootstrapLocalBackend("/home/x", {
66
+ await bootstrapLocalBackend({
80
67
  client,
81
68
  say: (line) => said.push(line),
82
69
  prepare: async () => prepared,
83
70
  run: async () => {
84
71
  throw new Error("backend unreachable");
85
72
  },
86
- retire: async () => {
87
- retired += 1;
88
- },
89
73
  });
90
- expect(retired).toBe(0);
91
74
  expect(said).toEqual([
92
- "Warning: failed to bootstrap the local backend, so nothing was retired. Run 'stigmer up' again to retry.",
75
+ "Warning: failed to bootstrap the local backend. Run 'stigmer up' again to retry.",
93
76
  ]);
94
77
  });
95
78
 
96
- it("holds the retire back when a default did not land, naming the default and saying why", async () => {
79
+ it("names each default that did not land and the verb that retries it", async () => {
97
80
  const said: string[] = [];
98
- let retired = 0;
99
- await bootstrapLocalBackend("/home/x", {
81
+ await bootstrapLocalBackend({
100
82
  client,
101
83
  say: (line) => said.push(line),
102
84
  prepare: async () => prepared,
@@ -109,35 +91,9 @@ describe("bootstrapLocalBackend", () => {
109
91
  failed: ["assistant"],
110
92
  },
111
93
  }),
112
- retire: async () => {
113
- retired += 1;
114
- },
115
94
  });
116
- expect(retired).toBe(0);
117
95
  expect(said).toEqual([
118
96
  "Warning: failed to install default plugin 'assistant'. Run 'stigmer bootstrap' to retry.",
119
- "Nothing was retired: the resources an older release installed stay until every default plugin is in place.",
120
- ]);
121
- });
122
-
123
- it("contains a retire that threw in one warning, after the run succeeded", async () => {
124
- const said: string[] = [];
125
- let ran = 0;
126
- await bootstrapLocalBackend("/home/x", {
127
- client,
128
- say: (line) => said.push(line),
129
- prepare: async () => prepared,
130
- run: async () => {
131
- ran += 1;
132
- return converged();
133
- },
134
- retire: async () => {
135
- throw new Error("project read failed");
136
- },
137
- });
138
- expect(ran).toBe(1);
139
- expect(said).toEqual([
140
- "Warning: failed to retire the resources an older release installed. Run 'stigmer up' again to retry.",
141
97
  ]);
142
98
  });
143
99
  });
@@ -6,29 +6,20 @@
6
6
  // lane. One definition, so a laptop, a container and the hosted platform
7
7
  // cannot drift in what "ready" means.
8
8
  //
9
- // Two phases, and the order matters (a third, `up`'s retire, follows them):
9
+ // Two phases, and the order matters:
10
10
  //
11
11
  // 1. prepare: resolve the official marketplace (acquiring `@stigmer/plugins`
12
12
  // at the CLI's version on a release's first run) and prepare every
13
13
  // default. No backend is touched.
14
14
  // 2. run: ensure the system org, then push the prepared defaults, each
15
- // skipped when the backend already holds it at the same digest.
15
+ // skipped when the backend already holds it at the same digest. The
16
+ // push adopts a system-content row it replaces in place (a default
17
+ // agent an earlier release seeded keeps its id, its instances and every
18
+ // conversation bound to them), so nothing here ever deletes a row.
16
19
  //
17
- // `stigmer up` adds a third phase after them: retiring the seedpack an
18
- // older release installed. That step deletes rows, so it runs only once
19
- // every default has LANDED, not merely been prepared: the plugin push adopts
20
- // the system-content rows it replaces in place (the seedpack's `assistant`
21
- // keeps its id, its instances and every conversation bound to them), and a
22
- // row that is now a plugin's member is never a candidate for the retire. A
23
- // user who upgrades offline and cannot fetch the new catalogue, or whose
24
- // backend refused a default, keeps the old rows for another day instead of
25
- // losing them and getting nothing back. The retire lives here and not in
26
- // `stigmer bootstrap` on purpose: a verb a scheduled lane runs against the
27
- // platform must never be able to delete rows.
28
- //
29
- // Inside `up` every phase is best-effort with its own warning naming the
30
- // retry, because the stack is already serving by the time any of them runs
31
- // and a seeding failure must never tear it down. Both `up` shapes (detached
20
+ // Inside `up` both phases are best-effort with their own warning naming the
21
+ // retry, because the stack is already serving by the time either runs and a
22
+ // seeding failure must never tear it down. Both `up` shapes (detached
32
23
  // and foreground) call this one function, and both seed the local server
33
24
  // `up` just started, never the active backend context: a CLI pointed at
34
25
  // cloud still gets its local stack seeded, and never has system resources
@@ -44,7 +35,6 @@ import type {
44
35
  InstallingVerb,
45
36
  PreparedDefault,
46
37
  } from "./plugins/defaults.js";
47
- import { dataDir } from "./paths.js";
48
38
  import { type EnsureSystemOrgOutcome, SYSTEM_ORG } from "./system-org.js";
49
39
 
50
40
  export type Say = (line: string) => void;
@@ -116,7 +106,6 @@ export interface BootstrapDeps {
116
106
  readonly client?: BackendClient;
117
107
  readonly say?: Say;
118
108
  readonly prepare?: () => Promise<PreparedBootstrap>;
119
- readonly retire?: (stigmer: Stigmer, home: string, say: Say) => Promise<void>;
120
109
  readonly run?: (
121
110
  stigmer: Stigmer,
122
111
  prepared: PreparedBootstrap,
@@ -130,7 +119,6 @@ const sayToStderr: Say = (line) => {
130
119
 
131
120
  /** What `stigmer up` does once the local server answers. Never throws past its own warnings. */
132
121
  export async function bootstrapLocalBackend(
133
- home: string,
134
122
  deps: BootstrapDeps = {},
135
123
  ): Promise<void> {
136
124
  const client = deps.client ?? (await freshLocalClient());
@@ -142,7 +130,7 @@ export async function bootstrapLocalBackend(
142
130
  } catch (err) {
143
131
  log.warn("bootstrap preparation failed", { error: String(err) });
144
132
  say(
145
- "Warning: could not prepare the default plugins, so the local backend was not bootstrapped and nothing was retired. Run 'stigmer up' again to retry.",
133
+ "Warning: could not prepare the default plugins, so the local backend was not bootstrapped. Run 'stigmer up' again to retry.",
146
134
  );
147
135
  return;
148
136
  }
@@ -157,7 +145,7 @@ export async function bootstrapLocalBackend(
157
145
  } catch (err) {
158
146
  log.warn("bootstrap failed", { error: String(err) });
159
147
  say(
160
- "Warning: failed to bootstrap the local backend, so nothing was retired. Run 'stigmer up' again to retry.",
148
+ "Warning: failed to bootstrap the local backend. Run 'stigmer up' again to retry.",
161
149
  );
162
150
  return;
163
151
  }
@@ -165,24 +153,9 @@ export async function bootstrapLocalBackend(
165
153
  org: result.org,
166
154
  outcomes: result.plugins.outcomes,
167
155
  });
168
- if (result.plugins.failed.length > 0) {
169
- for (const name of result.plugins.failed) {
170
- say(
171
- `Warning: failed to install default plugin '${name}'. Run 'stigmer bootstrap' to retry.`,
172
- );
173
- }
174
- say(
175
- "Nothing was retired: the resources an older release installed stay until every default plugin is in place.",
176
- );
177
- return;
178
- }
179
-
180
- try {
181
- await (deps.retire ?? retireSeedpack)(client.stigmer, home, say);
182
- } catch (err) {
183
- log.warn("seedpack retire failed", { error: String(err) });
156
+ for (const name of result.plugins.failed) {
184
157
  say(
185
- "Warning: failed to retire the resources an older release installed. Run 'stigmer up' again to retry.",
158
+ `Warning: failed to install default plugin '${name}'. Run 'stigmer bootstrap' to retry.`,
186
159
  );
187
160
  }
188
161
  }
@@ -197,20 +170,6 @@ function runLocalBootstrap(
197
170
  return runBootstrap(stigmer, prepared, say, "stigmer up");
198
171
  }
199
172
 
200
- // The retire step in the shape the seam expects; the module is loaded only
201
- // inside `up`, the one place a retire may run.
202
- async function retireSeedpack(
203
- stigmer: Stigmer,
204
- home: string,
205
- say: Say,
206
- ): Promise<void> {
207
- const { retireSeedpack: retire, renderRetireReport } = await import(
208
- "./seedpack-retire.js"
209
- );
210
- const result = await retire(stigmer, { markerDir: dataDir(home) });
211
- renderRetireReport(result, say);
212
- }
213
-
214
173
  async function freshLocalClient(): Promise<BackendClient> {
215
174
  const [{ createBackendClient }, { getDefault }] = await Promise.all([
216
175
  import("../client/index.js"),
@@ -72,7 +72,7 @@ export async function up(options: UpOptions = {}, home: string = homedir()): Pro
72
72
 
73
73
  await waitForTcp({ port: SERVER_PORT, timeoutMs: READY_TIMEOUT_MS, label: "stigmer-server" });
74
74
 
75
- await bootstrapLocalBackend(home);
75
+ await bootstrapLocalBackend();
76
76
 
77
77
  saveStartupConfig(data, buildStartupConfig(data, logs, temporalAddress, daemonPid, options));
78
78
  }
@@ -83,8 +83,8 @@ export interface UpForegroundDeps {
83
83
  runDaemon?: (deps: InternalDaemonDeps) => Promise<number>;
84
84
  /** Resolves when the stack should shut down (default: the first SIGTERM/SIGINT). */
85
85
  waitForShutdown?: () => Promise<void>;
86
- /** Post-readiness bootstrap (default: `bootstrapLocalBackend`: prepare the defaults, retire an older release's seedpack, ensure the org, install). */
87
- bootstrap?: (home: string) => Promise<void>;
86
+ /** Post-readiness bootstrap (default: `bootstrapLocalBackend`: prepare the defaults, ensure the org, install). */
87
+ bootstrap?: () => Promise<void>;
88
88
  /** Receives each line the server and runner write (default: a `[component]`-prefixed stdout mirror). */
89
89
  mirror?: OutputMirror;
90
90
  /** Invoked once the stack is serving and seeded — the moment a detached `up` would have returned. */
@@ -118,7 +118,7 @@ export async function upForeground(
118
118
  host: new NodeProcessHost({ mirror: deps.mirror ?? mirrorToStdout }),
119
119
  waitForShutdown: deps.waitForShutdown ?? waitForShutdownSignal,
120
120
  onStarted: async () => {
121
- await bootstrap(home);
121
+ await bootstrap();
122
122
  saveStartupConfig(data, buildStartupConfig(data, logs, temporalAddress, process.pid, options));
123
123
  await deps.onReady?.();
124
124
  },
@@ -10,8 +10,8 @@
10
10
  // release defect, not a condition to install around. Installing pushes the
11
11
  // prepared archives and is best-effort per entry: one default failing to
12
12
  // land does not stop the next, and the caller decides how to surface the
13
- // failures. The split lets `stigmer up` hold every replacement in hand
14
- // before it retires what the replacement supersedes (local/bootstrap.ts).
13
+ // failures. The split keeps every network read (the catalogue, the
14
+ // archives) ahead of the first write to the backend (local/bootstrap.ts).
15
15
  //
16
16
  // Idempotent by the server's own identity, not a marker file: before each
17
17
  // push the org's plugin of that name is read back; when its digest equals the
@@ -7,12 +7,18 @@ export {
7
7
  toKebabCase,
8
8
  toSnakeCase,
9
9
  } from "./aliases.js";
10
- export { CLI_RELEVANT_KINDS, type KindMeta, KIND_META } from "./metadata.js";
10
+ export {
11
+ CLI_RELEVANT_KINDS,
12
+ type KindMeta,
13
+ KIND_META,
14
+ RETIRED_KINDS,
15
+ } from "./metadata.js";
11
16
  export {
12
17
  defaultRegistry,
13
18
  type Registry,
14
19
  supportsVerb,
15
20
  type TypeInfo,
21
+ unknownKindError,
16
22
  } from "./registry.js";
17
23
  export {
18
24
  ALL_VERBS,
@@ -46,10 +46,6 @@ export const KIND_META: ReadonlyMap<ApiResourceKind, KindMeta> = new Map([
46
46
  ApiResourceKind.mcp_server,
47
47
  { name: "McpServer", displayName: "MCP Server", idPrefix: "mcp" },
48
48
  ],
49
- [
50
- ApiResourceKind.project,
51
- { name: "Project", displayName: "Project", idPrefix: "prj" },
52
- ],
53
49
  [
54
50
  ApiResourceKind.api_key,
55
51
  { name: "ApiKey", displayName: "API Key", idPrefix: "key" },
@@ -122,7 +118,6 @@ export const CLI_RELEVANT_KINDS: readonly ApiResourceKind[] = [
122
118
  ApiResourceKind.skill,
123
119
  ApiResourceKind.plugin,
124
120
  ApiResourceKind.mcp_server,
125
- ApiResourceKind.project,
126
121
  ApiResourceKind.api_key,
127
122
  ApiResourceKind.identity_provider,
128
123
  ApiResourceKind.oauth_app,
@@ -135,3 +130,18 @@ export const CLI_RELEVANT_KINDS: readonly ApiResourceKind[] = [
135
130
  ApiResourceKind.workflow_instance,
136
131
  ApiResourceKind.session,
137
132
  ];
133
+
134
+ /**
135
+ * YAML kinds the platform once served and no longer does. A manifest that
136
+ * still carries one is an old file, not a typo, so the refusal it meets
137
+ * says what happened and what to do instead of "unknown kind"; the
138
+ * registry's `unknownKindError` reads this table before falling back to the
139
+ * generic sentence. The key is the YAML `kind` value as the retired proto
140
+ * declared it; the value is the sentence that follows the kind's name.
141
+ */
142
+ export const RETIRED_KINDS: ReadonlyMap<string, string> = new Map([
143
+ [
144
+ "Project",
145
+ "is no longer a Stigmer resource. A folder of resources that belong together is a plugin: run `stigmer push plugin <dir>` to install it as one, or apply each resource file with `stigmer apply -f <file>`.",
146
+ ],
147
+ ]);
@@ -241,13 +241,7 @@ describe("registry — verb/dispatch conformance", () => {
241
241
  label: "apply",
242
242
  verb: Verb.Apply,
243
243
  wired: new Set(APPLY_HANDLERS.keys()),
244
- specialCases: new Map([
245
- [
246
- ApiResourceKind.project,
247
- "the stigmer.yaml declarative/synthesis track (resources/apply/declarative.ts); " +
248
- "file mode refuses with a pointer there (resolveHandlerForKind)",
249
- ],
250
- ]),
244
+ specialCases: new Map(),
251
245
  },
252
246
  {
253
247
  label: "get",