@stigmer/cli 3.18.0-dev.20260918103812 → 3.18.1-dev.20260919070736

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 (109) hide show
  1. package/commands/bootstrap.d.ts +3 -0
  2. package/commands/bootstrap.d.ts.map +1 -0
  3. package/commands/bootstrap.js +75 -0
  4. package/commands/bootstrap.js.map +1 -0
  5. package/commands/marketplace.d.ts.map +1 -1
  6. package/commands/marketplace.js +7 -7
  7. package/commands/marketplace.js.map +1 -1
  8. package/config/resolve.d.ts.map +1 -1
  9. package/config/resolve.js +8 -7
  10. package/config/resolve.js.map +1 -1
  11. package/local/bootstrap.d.ts +32 -13
  12. package/local/bootstrap.d.ts.map +1 -1
  13. package/local/bootstrap.js +105 -64
  14. package/local/bootstrap.js.map +1 -1
  15. package/local/daemon/launch.d.ts +1 -1
  16. package/local/daemon/launch.d.ts.map +1 -1
  17. package/local/paths.d.ts +1 -1
  18. package/local/paths.js +1 -1
  19. package/local/plugins/defaults.d.ts +27 -7
  20. package/local/plugins/defaults.d.ts.map +1 -1
  21. package/local/plugins/defaults.js +55 -28
  22. package/local/plugins/defaults.js.map +1 -1
  23. package/local/runtime/runtimes-install.d.ts.map +1 -1
  24. package/local/runtime/runtimes-install.js +7 -4
  25. package/local/runtime/runtimes-install.js.map +1 -1
  26. package/local/seedpack-retire.d.ts +63 -0
  27. package/local/seedpack-retire.d.ts.map +1 -0
  28. package/local/seedpack-retire.js +361 -0
  29. package/local/seedpack-retire.js.map +1 -0
  30. package/local/system-org.d.ts +15 -0
  31. package/local/system-org.d.ts.map +1 -0
  32. package/local/system-org.js +57 -0
  33. package/local/system-org.js.map +1 -0
  34. package/marketplace/config.d.ts +3 -1
  35. package/marketplace/config.d.ts.map +1 -1
  36. package/marketplace/config.js +24 -11
  37. package/marketplace/config.js.map +1 -1
  38. package/marketplace/github.d.ts +37 -0
  39. package/marketplace/github.d.ts.map +1 -1
  40. package/marketplace/github.js +70 -1
  41. package/marketplace/github.js.map +1 -1
  42. package/marketplace/install.d.ts +13 -6
  43. package/marketplace/install.d.ts.map +1 -1
  44. package/marketplace/install.js +63 -16
  45. package/marketplace/install.js.map +1 -1
  46. package/marketplace/official.js +4 -4
  47. package/marketplace/official.js.map +1 -1
  48. package/marketplace/render.d.ts.map +1 -1
  49. package/marketplace/render.js +10 -4
  50. package/marketplace/render.js.map +1 -1
  51. package/package.json +7 -7
  52. package/program.js +2 -2
  53. package/program.js.map +1 -1
  54. package/resources/apply/declarative.js +2 -2
  55. package/resources/apply/declarative.js.map +1 -1
  56. package/resources/plugin.d.ts.map +1 -1
  57. package/resources/plugin.js +12 -9
  58. package/resources/plugin.js.map +1 -1
  59. package/src/commands/bootstrap.test.ts +253 -0
  60. package/src/commands/bootstrap.ts +91 -0
  61. package/src/commands/install.test.ts +28 -9
  62. package/src/commands/marketplace.test.ts +28 -14
  63. package/src/commands/marketplace.ts +9 -7
  64. package/src/config/resolve.test.ts +2 -2
  65. package/src/config/resolve.ts +8 -7
  66. package/src/local/bootstrap.test.ts +110 -38
  67. package/src/local/bootstrap.ts +179 -89
  68. package/src/local/daemon/launch.ts +1 -1
  69. package/src/local/paths.ts +1 -1
  70. package/src/local/plugins/defaults.test.ts +46 -13
  71. package/src/local/plugins/defaults.ts +77 -34
  72. package/src/local/runtime/runtimes-install.test.ts +2 -0
  73. package/src/local/runtime/runtimes-install.ts +7 -4
  74. package/src/local/seedpack-retire.test.ts +499 -0
  75. package/src/local/seedpack-retire.ts +474 -0
  76. package/src/local/system-org.test.ts +124 -0
  77. package/src/local/system-org.ts +63 -0
  78. package/src/marketplace/__fixtures__/cursor-marketplace.ts +5 -2
  79. package/src/marketplace/config.test.ts +47 -22
  80. package/src/marketplace/config.ts +27 -12
  81. package/src/marketplace/github.test.ts +77 -1
  82. package/src/marketplace/github.ts +115 -1
  83. package/src/marketplace/install.test.ts +84 -17
  84. package/src/marketplace/install.ts +73 -15
  85. package/src/marketplace/official.ts +4 -4
  86. package/src/marketplace/read.test.ts +1 -1
  87. package/src/marketplace/render.ts +13 -4
  88. package/src/program.ts +2 -2
  89. package/src/resources/apply/declarative.integration.test.ts +2 -2
  90. package/src/resources/apply/declarative.ts +2 -2
  91. package/src/resources/connect/discover.test.ts +1 -1
  92. package/src/resources/plugin.ts +11 -10
  93. package/commands/seedpack.d.ts +0 -3
  94. package/commands/seedpack.d.ts.map +0 -1
  95. package/commands/seedpack.js +0 -98
  96. package/commands/seedpack.js.map +0 -1
  97. package/local/seedpack/apply.d.ts +0 -72
  98. package/local/seedpack/apply.d.ts.map +0 -1
  99. package/local/seedpack/apply.js +0 -145
  100. package/local/seedpack/apply.js.map +0 -1
  101. package/local/seedpack/content.d.ts +0 -61
  102. package/local/seedpack/content.d.ts.map +0 -1
  103. package/local/seedpack/content.js +0 -178
  104. package/local/seedpack/content.js.map +0 -1
  105. package/src/commands/seedpack.ts +0 -116
  106. package/src/local/seedpack/apply.test.ts +0 -287
  107. package/src/local/seedpack/apply.ts +0 -199
  108. package/src/local/seedpack/content.test.ts +0 -169
  109. package/src/local/seedpack/content.ts +0 -222
@@ -1,61 +0,0 @@
1
- import { type NpmInstall } from "../runtime/runtimes-install.js";
2
- /**
3
- * The canonical seedpack entries, in apply-safe order. Kept in sync with
4
- * `SEEDPACK_ENTRIES` in `@stigmer/seedpack` (`seedpack/src/index.ts`, the one
5
- * definition) — `tools/`, `icons/`, and `canary/` (CI canary metadata, not a
6
- * resource) are deliberately excluded so the content set (and thus the
7
- * idempotency hash) is identical across delivery paths.
8
- */
9
- export declare const SEEDPACK_ENTRIES: readonly ["stigmer.yaml", "organizations", "skills", "agents", "workflows", "mcp-servers"];
10
- /** Marker file recording the last successfully-applied content hash. */
11
- export declare const MARKER_FILE = ".seedpack-bootstrapped";
12
- export interface SeedpackContent {
13
- /** Absolute path to the content root (holds stigmer.yaml). */
14
- readonly dir: string;
15
- /** Where the content came from — surfaced in diagnostics. */
16
- readonly source: "repo" | "package";
17
- }
18
- export interface ResolveSeedpackOptions {
19
- home?: string;
20
- /** Release version of @stigmer/seedpack to acquire (defaults to the CLI version). */
21
- version?: string;
22
- /** npm install implementation (injectable for tests). */
23
- install?: NpmInstall;
24
- }
25
- /**
26
- * Resolve the seedpack content directory: a repo-tree checkout in dev, else the
27
- * on-demand-acquired `@stigmer/seedpack` package. Throws actionable guidance when
28
- * acquisition is not possible (non-release build, or a failed/incomplete install).
29
- */
30
- export declare function resolveSeedpackContent(opts?: ResolveSeedpackOptions): SeedpackContent;
31
- /**
32
- * Acquire the published `@stigmer/seedpack@<version>` into
33
- * ~/.stigmer/runtimes/<version>/ (idempotent) and return its package directory.
34
- * The version is pinned to the CLI's own version so system content stays in
35
- * lockstep with the control plane it bootstraps.
36
- *
37
- * Presence beats acquirability (the server acquirer's rule, stated in
38
- * runtime/server.ts): installed content is used whatever its version string;
39
- * only an install we would have to perform is refused for a non-release build.
40
- */
41
- export declare function acquireSeedpack(opts?: ResolveSeedpackOptions): string;
42
- /**
43
- * Deterministic SHA-256 over the canonical content, identical to
44
- * `@stigmer/seedpack`'s `contentHash` (and the Go algorithm): files walked in
45
- * lexical order, each contributing its forward-slash relative path, a NUL, and
46
- * its bytes. Used as the idempotency marker.
47
- */
48
- export declare function hashSeedpackContent(dir: string): string;
49
- /**
50
- * Copy the canonical entries from `srcDir` into `destDir`, producing a clean
51
- * Stigmer project the declarative-apply path can process directly (never
52
- * carrying build tooling or assets that happen to sit beside the content).
53
- */
54
- export declare function extractSeedpack(srcDir: string, destDir: string): void;
55
- /** Lexically-sorted, forward-slash relative paths of every file under the canonical entries. */
56
- export declare function listContentFiles(root: string): string[];
57
- /** The stored marker hash for `markerDir`, or null when never applied. */
58
- export declare function readMarker(markerDir: string): string | null;
59
- /** Persist the applied content hash so a future run can skip unchanged content. */
60
- export declare function writeMarker(markerDir: string, hash: string): void;
61
- //# sourceMappingURL=content.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"content.d.ts","sourceRoot":"","sources":["../../../src/local/seedpack/content.ts"],"names":[],"mappings":"AAqCA,OAAO,EAIL,KAAK,UAAU,EAChB,MAAM,gCAAgC,CAAC;AAIxC;;;;;;GAMG;AACH,eAAO,MAAM,gBAAgB,4FAOnB,CAAC;AAEX,wEAAwE;AACxE,eAAO,MAAM,WAAW,2BAA2B,CAAC;AAEpD,MAAM,WAAW,eAAe;IAC9B,8DAA8D;IAC9D,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,6DAA6D;IAC7D,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;CACrC;AAED,MAAM,WAAW,sBAAsB;IACrC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,qFAAqF;IACrF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,yDAAyD;IACzD,OAAO,CAAC,EAAE,UAAU,CAAC;CACtB;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CACpC,IAAI,GAAE,sBAA2B,GAChC,eAAe,CAIjB;AAED;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAAC,IAAI,GAAE,sBAA2B,GAAG,MAAM,CAmCzE;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAQvD;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAOrE;AAID,gGAAgG;AAChG,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAgBvD;AAED,0EAA0E;AAC1E,wBAAgB,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAM3D;AAED,mFAAmF;AACnF,wBAAgB,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAGjE"}
@@ -1,178 +0,0 @@
1
- // Resolution and on-demand acquisition of the seedpack content.
2
- //
3
- // The seedpack (system agents, skills, MCP servers, workflows under the
4
- // "stigmer" org) is the system content every backend is bootstrapped with.
5
- // A lean `npx @stigmer/cli` must not carry ~300 content files (DD-002), so the
6
- // content ships as `@stigmer/seedpack` and is acquired on demand — the same
7
- // pattern as `@stigmer/runner-slim` and the managed Temporal binary.
8
- //
9
- // Two sources, tried in order (mirrors runtime/runner.ts):
10
- // 1. A repo-tree checkout (dev): `<repo>/seedpack`.
11
- // 2. The published `@stigmer/seedpack@<cli-version>`, installed on demand into
12
- // ~/.stigmer/runtimes/<version>/ and read from
13
- // node_modules/@stigmer/seedpack.
14
- //
15
- // The content-hash and extract logic mirror `@stigmer/seedpack` exactly; the CLI
16
- // reimplements them over a resolved directory so it stays decoupled from the
17
- // package in the lean install (where the package is not a dependency, only an
18
- // on-demand artifact). `seedpack/src/index.ts` is the one definition both follow.
19
- import { createHash } from "node:crypto";
20
- import { cpSync, existsSync, mkdirSync, readdirSync, readFileSync, statSync, writeFileSync, } from "node:fs";
21
- import { homedir } from "node:os";
22
- import { dirname, join, posix, relative, sep } from "node:path";
23
- import { fileURLToPath } from "node:url";
24
- import { CliExitError } from "../../errors/cli-exit-error.js";
25
- import { ExitCode } from "../../errors/exit-codes.js";
26
- import { log } from "../../logger.js";
27
- import { VERSION } from "../../version.js";
28
- import { runtimesDir } from "../paths.js";
29
- import { ensureRuntimesRoot, isAcquirableRelease, npmInstallIntoRuntimes, } from "../runtime/runtimes-install.js";
30
- const SEEDPACK_PACKAGE = "@stigmer/seedpack";
31
- /**
32
- * The canonical seedpack entries, in apply-safe order. Kept in sync with
33
- * `SEEDPACK_ENTRIES` in `@stigmer/seedpack` (`seedpack/src/index.ts`, the one
34
- * definition) — `tools/`, `icons/`, and `canary/` (CI canary metadata, not a
35
- * resource) are deliberately excluded so the content set (and thus the
36
- * idempotency hash) is identical across delivery paths.
37
- */
38
- export const SEEDPACK_ENTRIES = [
39
- "stigmer.yaml",
40
- "organizations",
41
- "skills",
42
- "agents",
43
- "workflows",
44
- "mcp-servers",
45
- ];
46
- /** Marker file recording the last successfully-applied content hash. */
47
- export const MARKER_FILE = ".seedpack-bootstrapped";
48
- /**
49
- * Resolve the seedpack content directory: a repo-tree checkout in dev, else the
50
- * on-demand-acquired `@stigmer/seedpack` package. Throws actionable guidance when
51
- * acquisition is not possible (non-release build, or a failed/incomplete install).
52
- */
53
- export function resolveSeedpackContent(opts = {}) {
54
- const repo = repoSeedpackDir();
55
- if (repo !== null)
56
- return { dir: repo, source: "repo" };
57
- return { dir: acquireSeedpack(opts), source: "package" };
58
- }
59
- /**
60
- * Acquire the published `@stigmer/seedpack@<version>` into
61
- * ~/.stigmer/runtimes/<version>/ (idempotent) and return its package directory.
62
- * The version is pinned to the CLI's own version so system content stays in
63
- * lockstep with the control plane it bootstraps.
64
- *
65
- * Presence beats acquirability (the server acquirer's rule, stated in
66
- * runtime/server.ts): installed content is used whatever its version string;
67
- * only an install we would have to perform is refused for a non-release build.
68
- */
69
- export function acquireSeedpack(opts = {}) {
70
- const home = opts.home ?? homedir();
71
- const version = opts.version ?? VERSION;
72
- const installDir = join(runtimesDir(home), version);
73
- const pkgDir = join(installDir, "node_modules", "@stigmer", "seedpack");
74
- const marker = join(pkgDir, "stigmer.yaml");
75
- if (!existsSync(marker)) {
76
- if (!isAcquirableRelease(version)) {
77
- throw new CliExitError(`cannot acquire ${SEEDPACK_PACKAGE} for a non-release build (${version})`, ExitCode.General, [
78
- "Run from the repo (the seedpack/ tree is used directly in dev).",
79
- "On-demand acquisition is only available for published releases.",
80
- ]);
81
- }
82
- log.info(`acquiring ${SEEDPACK_PACKAGE}`, { version, dir: installDir });
83
- // The same per-version root the server and runner packages install into;
84
- // npm install is additive and non-pruning, so the prefix is safely shared.
85
- ensureRuntimesRoot(installDir);
86
- const install = opts.install ?? npmInstallIntoRuntimes;
87
- install(installDir, `${SEEDPACK_PACKAGE}@${version}`);
88
- }
89
- if (!existsSync(marker)) {
90
- throw new CliExitError(`${SEEDPACK_PACKAGE} install did not produce ${marker}`, ExitCode.General, [`Remove ${installDir} and retry.`]);
91
- }
92
- return pkgDir;
93
- }
94
- /**
95
- * Deterministic SHA-256 over the canonical content, identical to
96
- * `@stigmer/seedpack`'s `contentHash` (and the Go algorithm): files walked in
97
- * lexical order, each contributing its forward-slash relative path, a NUL, and
98
- * its bytes. Used as the idempotency marker.
99
- */
100
- export function hashSeedpackContent(dir) {
101
- const hash = createHash("sha256");
102
- for (const rel of listContentFiles(dir)) {
103
- hash.update(rel);
104
- hash.update(NUL);
105
- hash.update(readFileSync(join(dir, rel)));
106
- }
107
- return `sha256:${hash.digest("hex").slice(0, 16)}`;
108
- }
109
- /**
110
- * Copy the canonical entries from `srcDir` into `destDir`, producing a clean
111
- * Stigmer project the declarative-apply path can process directly (never
112
- * carrying build tooling or assets that happen to sit beside the content).
113
- */
114
- export function extractSeedpack(srcDir, destDir) {
115
- mkdirSync(destDir, { recursive: true });
116
- for (const entry of SEEDPACK_ENTRIES) {
117
- const src = join(srcDir, entry);
118
- if (!existsSync(src))
119
- continue;
120
- cpSync(src, join(destDir, entry), { recursive: true });
121
- }
122
- }
123
- const NUL = Uint8Array.of(0);
124
- /** Lexically-sorted, forward-slash relative paths of every file under the canonical entries. */
125
- export function listContentFiles(root) {
126
- const files = [];
127
- const walk = (abs) => {
128
- for (const dirent of readdirSync(abs, { withFileTypes: true })) {
129
- const full = join(abs, dirent.name);
130
- if (dirent.isDirectory())
131
- walk(full);
132
- else if (dirent.isFile())
133
- files.push(toPosix(relative(root, full)));
134
- }
135
- };
136
- for (const entry of SEEDPACK_ENTRIES) {
137
- const abs = join(root, entry);
138
- if (!existsSync(abs))
139
- continue;
140
- if (statSync(abs).isDirectory())
141
- walk(abs);
142
- else
143
- files.push(entry);
144
- }
145
- return files.sort();
146
- }
147
- /** The stored marker hash for `markerDir`, or null when never applied. */
148
- export function readMarker(markerDir) {
149
- try {
150
- return readFileSync(join(markerDir, MARKER_FILE), "utf8").trim() || null;
151
- }
152
- catch {
153
- return null;
154
- }
155
- }
156
- /** Persist the applied content hash so a future run can skip unchanged content. */
157
- export function writeMarker(markerDir, hash) {
158
- mkdirSync(markerDir, { recursive: true });
159
- writeFileSync(join(markerDir, MARKER_FILE), `${hash}\n`);
160
- }
161
- function toPosix(p) {
162
- return sep === posix.sep ? p : p.split(sep).join(posix.sep);
163
- }
164
- // Walk up from this module to a repo root containing seedpack/stigmer.yaml.
165
- function repoSeedpackDir() {
166
- let dir = dirname(fileURLToPath(import.meta.url));
167
- for (let i = 0; i < 10; i += 1) {
168
- const candidate = join(dir, "seedpack");
169
- if (existsSync(join(candidate, "stigmer.yaml")))
170
- return candidate;
171
- const parent = dirname(dir);
172
- if (parent === dir)
173
- break;
174
- dir = parent;
175
- }
176
- return null;
177
- }
178
- //# sourceMappingURL=content.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"content.js","sourceRoot":"","sources":["../../../src/local/seedpack/content.ts"],"names":[],"mappings":"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"}
@@ -1,116 +0,0 @@
1
- // `stigmer seedpack apply|status` — manage the embedded system seedpack.
2
- //
3
- // The seedpack (system agents, skills, MCP servers, workflows under the
4
- // "stigmer" org) is applied automatically on `stigmer up` in local mode; these
5
- // commands bootstrap it explicitly against whatever backend is configured
6
- // (local or cloud). Apply is content-hash idempotent: in cloud mode the truth
7
- // is the stigmer.ai/seedpack-hash label on the server's seedpack Project (any
8
- // machine sees the same applied state — cloud#429); in local mode it is a
9
- // marker file in the data dir, which lives and dies with the local backend.
10
- //
11
- // Heavy modules load lazily inside the action so `--help` stays fast (DD-001).
12
-
13
- import type { Command } from "commander";
14
- import { configDir, dataDir, isCloudMode, load } from "../config/index.js";
15
- import { CommandResult, type OutputFlags, renderResult } from "../output/index.js";
16
- import { addResultFlags, resultFormat } from "./shared.js";
17
-
18
- interface ApplyFlags extends OutputFlags {
19
- force?: boolean;
20
- }
21
-
22
- export function registerSeedpack(program: Command): void {
23
- const seedpack = program.command("seedpack").description("manage the embedded system seedpack");
24
-
25
- const apply = seedpack
26
- .command("apply")
27
- .description("apply the seedpack to the configured backend")
28
- .option("--force", "re-apply even if the seedpack has not changed", false)
29
- .action((options: ApplyFlags) => runApply(options));
30
- addResultFlags(apply);
31
-
32
- const status = seedpack
33
- .command("status")
34
- .description("show seedpack bootstrap status")
35
- .action((options: OutputFlags) => runStatus(options));
36
- addResultFlags(status);
37
- }
38
-
39
- async function runApply(flags: ApplyFlags): Promise<void> {
40
- const [{ connectBackend }, { ensureAuthenticated }, { applySeedpack }] = await Promise.all([
41
- import("../backend.js"),
42
- import("../config/index.js"),
43
- import("../local/seedpack/apply.js"),
44
- ]);
45
-
46
- const client = connectBackend();
47
- ensureAuthenticated(client.config);
48
-
49
- const result = await applySeedpack(
50
- {
51
- controller: client.controller,
52
- stigmer: client.stigmer,
53
- info: (line) => process.stderr.write(`${line}\n`),
54
- warn: (line) => process.stderr.write(`${line}\n`),
55
- },
56
- {
57
- markerDir: markerDir(),
58
- force: flags.force === true,
59
- useServerHash: isCloudMode(load()),
60
- },
61
- );
62
-
63
- const label = backendLabel();
64
- const message = result.applied
65
- ? `Seedpack applied to ${label} backend`
66
- : `Seedpack already up to date on ${label} backend (use --force to re-apply)`;
67
- renderResult(CommandResult.success(message), resultFormat(flags));
68
- }
69
-
70
- async function runStatus(flags: OutputFlags): Promise<void> {
71
- const { readServerSeedpackHash, resolveSeedpackOrg, seedpackContentHash } = await import("../local/seedpack/apply.js");
72
- const { readMarker } = await import("../local/seedpack/content.js");
73
-
74
- const hash = seedpackContentHash();
75
-
76
- // Cloud mode asks the server (the label on the seedpack Project) so status
77
- // is truthful from ANY machine, not just the one that last ran apply.
78
- let stored: string | null;
79
- let storedLabel: string;
80
- if (isCloudMode(load())) {
81
- const { connectBackend } = await import("../backend.js");
82
- const { ensureAuthenticated } = await import("../config/index.js");
83
- const client = connectBackend();
84
- ensureAuthenticated(client.config);
85
- stored = await readServerSeedpackHash(client.stigmer, resolveSeedpackOrg());
86
- storedLabel = "Applied Hash (server)";
87
- } else {
88
- stored = readMarker(markerDir());
89
- storedLabel = "Applied Hash";
90
- }
91
-
92
- const result = CommandResult.success("Seedpack status");
93
- const section = result.addSection("");
94
- section.field("Backend", backendLabel());
95
- section.field("Embedded Hash", hash);
96
- if (stored === null) {
97
- section.field("Status", "Not applied (run 'stigmer seedpack apply')");
98
- } else {
99
- section.field(storedLabel, stored);
100
- section.field("Status", stored === hash ? "Up to date" : "Outdated (run 'stigmer seedpack apply' to update)");
101
- }
102
- renderResult(result, resultFormat(flags));
103
- }
104
-
105
- // Marker lives with the backend's state: the data dir for local, the config dir
106
- // for cloud (mirrors the Go CLI's resolveMarkerDir).
107
- function markerDir(): string {
108
- return isCloudMode(load()) ? configDir() : dataDir();
109
- }
110
-
111
- function backendLabel(): string {
112
- const config = load();
113
- if (!isCloudMode(config)) return "local";
114
- const endpoint = config.backend.cloud?.endpoint ?? "api.stigmer.ai:443";
115
- return `cloud (${endpoint})`;
116
- }
@@ -1,287 +0,0 @@
1
- import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
2
- import { tmpdir } from "node:os";
3
- import { join } from "node:path";
4
- import type { Message } from "@bufbuild/protobuf";
5
- import type { Stigmer } from "@stigmer/sdk";
6
- import { afterEach, beforeEach, describe, expect, it } from "vitest";
7
- import { buildDeclarativeItems, scanResourceFiles } from "../../resources/apply/declarative.js";
8
- import type { ControllerFn } from "../../resources/apply/handlers.js";
9
- import {
10
- applySeedpack,
11
- readServerSeedpackHash,
12
- resolveSeedpackOrg,
13
- SEEDPACK_HASH_LABEL,
14
- SEEDPACK_PROJECT_SLUG,
15
- seedpackContentHash,
16
- } from "./apply.js";
17
- import type { SeedpackContent } from "./content.js";
18
- import { extractSeedpack, readMarker, resolveSeedpackContent } from "./content.js";
19
-
20
- const ORG_YAML = [
21
- "apiVersion: tenancy.stigmer.ai/v1",
22
- "kind: Organization",
23
- "metadata:",
24
- " name: Stigmer",
25
- " slug: stigmer",
26
- "spec:",
27
- ' description: "System org"',
28
- " management_mode: self_managed",
29
- "",
30
- ].join("\n");
31
-
32
- const PROJECT_YAML = [
33
- "apiVersion: tenancy.stigmer.ai/v1",
34
- "kind: Project",
35
- "metadata:",
36
- " name: stigmer-seedpack",
37
- " org: stigmer",
38
- "spec:",
39
- " description: System seedpack",
40
- "",
41
- ].join("\n");
42
-
43
- // A seedpack fixture with just an org + the project manifest — enough to exercise
44
- // both apply phases (organizations via file mode, the project via the declarative
45
- // reconciler) without pulling in skill-push or MCP discovery.
46
- function makeContent(): SeedpackContent {
47
- const dir = mkdtempSync(join(tmpdir(), "seedpack-apply-"));
48
- writeFileSync(join(dir, "stigmer.yaml"), PROJECT_YAML);
49
- mkdirSync(join(dir, "organizations"), { recursive: true });
50
- writeFileSync(join(dir, "organizations", "stigmer.yaml"), ORG_YAML);
51
- return { dir, source: "repo" };
52
- }
53
-
54
- // Records each applied message (and its proto type name); every controller
55
- // resolves to the same stub apply (the handlers only call `.apply`).
56
- function recordingDeps(stigmer?: unknown) {
57
- const applied: string[] = [];
58
- const appliedMessages: Message[] = [];
59
- const controller = (() => ({
60
- apply: async (m: Message) => {
61
- applied.push((m as { $typeName: string }).$typeName);
62
- appliedMessages.push(m);
63
- return m;
64
- },
65
- })) as unknown as ControllerFn;
66
- return {
67
- applied,
68
- appliedMessages,
69
- deps: {
70
- controller,
71
- stigmer: (stigmer ?? {}) as never,
72
- info: () => {},
73
- warn: () => {},
74
- },
75
- };
76
- }
77
-
78
- // A Stigmer stub whose project.getByReference reports the given stored hash
79
- // (null → the label is absent; "absent" → the project itself does not exist).
80
- function stigmerWithServerHash(stored: string | null | "absent"): Stigmer {
81
- return {
82
- project: {
83
- getByReference: async () => {
84
- if (stored === "absent") throw new Error("not found");
85
- return { metadata: { labels: stored === null ? {} : { [SEEDPACK_HASH_LABEL]: stored } } };
86
- },
87
- },
88
- } as unknown as Stigmer;
89
- }
90
-
91
- let content: SeedpackContent;
92
- let markerDir: string;
93
- beforeEach(() => {
94
- content = makeContent();
95
- markerDir = mkdtempSync(join(tmpdir(), "seedpack-marker-"));
96
- });
97
- afterEach(() => {
98
- rmSync(content.dir, { recursive: true, force: true });
99
- rmSync(markerDir, { recursive: true, force: true });
100
- });
101
-
102
- describe("resolveSeedpackOrg", () => {
103
- const saved = process.env.STIGMER_SEEDPACK_ORG;
104
- afterEach(() => {
105
- if (saved === undefined) delete process.env.STIGMER_SEEDPACK_ORG;
106
- else process.env.STIGMER_SEEDPACK_ORG = saved;
107
- });
108
-
109
- it("prefers explicit, then env var, then the default", () => {
110
- delete process.env.STIGMER_SEEDPACK_ORG;
111
- expect(resolveSeedpackOrg("acme")).toBe("acme");
112
- expect(resolveSeedpackOrg()).toBe("stigmer");
113
- process.env.STIGMER_SEEDPACK_ORG = "from-env";
114
- expect(resolveSeedpackOrg()).toBe("from-env");
115
- expect(resolveSeedpackOrg("explicit")).toBe("explicit");
116
- });
117
- });
118
-
119
- describe("applySeedpack", () => {
120
- it("applies the org and project, then writes the marker", async () => {
121
- const { applied, deps } = recordingDeps();
122
- const result = await applySeedpack(deps, { markerDir, content });
123
-
124
- expect(result.applied).toBe(true);
125
- expect(result.org).toBe("stigmer");
126
- expect(applied.some((t) => t.endsWith("Organization"))).toBe(true);
127
- expect(applied.some((t) => t.endsWith("Project"))).toBe(true);
128
- expect(readMarker(markerDir)).toBe(result.hash);
129
- });
130
-
131
- it("is idempotent: a matching marker skips the backend entirely", async () => {
132
- const { applied, deps } = recordingDeps();
133
- await applySeedpack(deps, { markerDir, content });
134
-
135
- const second = recordingDeps();
136
- const result = await applySeedpack(second.deps, { markerDir, content });
137
- expect(result.applied).toBe(false);
138
- expect(second.applied).toHaveLength(0);
139
- // The first run did touch the backend.
140
- expect(applied.length).toBeGreaterThan(0);
141
- });
142
-
143
- it("re-applies when forced even if the marker matches", async () => {
144
- const first = recordingDeps();
145
- await applySeedpack(first.deps, { markerDir, content });
146
-
147
- const forced = recordingDeps();
148
- const result = await applySeedpack(forced.deps, { markerDir, content, force: true });
149
- expect(result.applied).toBe(true);
150
- expect(forced.applied.length).toBeGreaterThan(0);
151
- });
152
-
153
- it("stamps the content hash as a reserved label on the applied Project", async () => {
154
- const { appliedMessages, deps } = recordingDeps();
155
- const result = await applySeedpack(deps, { markerDir, content });
156
-
157
- const project = appliedMessages.find((m) => (m as { $typeName: string }).$typeName.endsWith("Project")) as
158
- | { metadata?: { labels: Record<string, string> } }
159
- | undefined;
160
- expect(project).toBeDefined();
161
- expect(project?.metadata?.labels[SEEDPACK_HASH_LABEL]).toBe(result.hash);
162
- });
163
- });
164
-
165
- describe("applySeedpack — cloud mode (useServerHash)", () => {
166
- it("skips when the server's recorded hash matches, without touching the marker", async () => {
167
- const hash = seedpackContentHash({ content });
168
- const { applied, deps } = recordingDeps(stigmerWithServerHash(hash));
169
-
170
- const result = await applySeedpack(deps, { markerDir, content, useServerHash: true });
171
-
172
- expect(result.applied).toBe(false);
173
- expect(applied).toHaveLength(0);
174
- expect(readMarker(markerDir)).toBeNull();
175
- });
176
-
177
- it("applies when the server records a different hash — and never writes the marker", async () => {
178
- const { applied, deps } = recordingDeps(stigmerWithServerHash("sha256:0000000000000000"));
179
-
180
- const result = await applySeedpack(deps, { markerDir, content, useServerHash: true });
181
-
182
- expect(result.applied).toBe(true);
183
- expect(applied.length).toBeGreaterThan(0);
184
- // Cloud mode's record is the Project label; a marker here would be a
185
- // second record of the same fact, free to drift.
186
- expect(readMarker(markerDir)).toBeNull();
187
- });
188
-
189
- it("applies when the seedpack Project does not exist yet (first bootstrap)", async () => {
190
- const { applied, deps } = recordingDeps(stigmerWithServerHash("absent"));
191
-
192
- const result = await applySeedpack(deps, { markerDir, content, useServerHash: true });
193
-
194
- expect(result.applied).toBe(true);
195
- expect(applied.length).toBeGreaterThan(0);
196
- });
197
-
198
- it("ignores a stale local marker: the server is the only truth consulted", async () => {
199
- const hash = seedpackContentHash({ content });
200
- // A leftover marker from the pre-cloud#429 era says "up to date"…
201
- const { deps: first } = recordingDeps();
202
- await applySeedpack(first, { markerDir, content });
203
- // …but the server has never seen this content.
204
- const { applied, deps } = recordingDeps(stigmerWithServerHash(null));
205
-
206
- const result = await applySeedpack(deps, { markerDir, content, useServerHash: true });
207
-
208
- expect(result.applied).toBe(true);
209
- expect(applied.length).toBeGreaterThan(0);
210
- expect(hash).toBe(result.hash);
211
- });
212
-
213
- it("re-applies when forced even if the server hash matches", async () => {
214
- const hash = seedpackContentHash({ content });
215
- const { applied, deps } = recordingDeps(stigmerWithServerHash(hash));
216
-
217
- const result = await applySeedpack(deps, { markerDir, content, useServerHash: true, force: true });
218
-
219
- expect(result.applied).toBe(true);
220
- expect(applied.length).toBeGreaterThan(0);
221
- });
222
- });
223
-
224
- describe("readServerSeedpackHash", () => {
225
- it("returns the recorded label", async () => {
226
- const hash = await readServerSeedpackHash(stigmerWithServerHash("sha256:abcdef0123456789"), "stigmer");
227
- expect(hash).toBe("sha256:abcdef0123456789");
228
- });
229
-
230
- it("returns null when the label is absent", async () => {
231
- expect(await readServerSeedpackHash(stigmerWithServerHash(null), "stigmer")).toBeNull();
232
- });
233
-
234
- it("returns null when the project cannot be read (never applied / transient failure)", async () => {
235
- expect(await readServerSeedpackHash(stigmerWithServerHash("absent"), "stigmer")).toBeNull();
236
- });
237
- });
238
-
239
- describe("seedpackContentHash", () => {
240
- it("hashes the provided content", () => {
241
- expect(seedpackContentHash({ content })).toMatch(/^sha256:[0-9a-f]{16}$/);
242
- });
243
- });
244
-
245
- // Regression guard for the credential-manifest bootstrap blocker: the *real*
246
- // seedpack content must pass cleanly through the declarative scanner. Every
247
- // staged file is a resource (carries a `kind`); any non-resource file (e.g. the
248
- // CI canary manifest) must live outside the content set, never beside the
249
- // McpServer YAMLs where `loadDocuments(strict)` would reject it for missing a
250
- // `kind`. The synthetic fixtures above can't catch this — only real content can.
251
- // The cloud-mode hash read addresses the seedpack Project by a pinned slug.
252
- // The server derives the slug from the manifest's metadata.name, so this pin
253
- // holds exactly as long as the real seedpack keeps that name — verify against
254
- // the real content so a rename there fails here, not silently in prod.
255
- describe("SEEDPACK_PROJECT_SLUG pins the real manifest name", () => {
256
- it("matches seedpack/stigmer.yaml metadata.name", () => {
257
- const real = resolveSeedpackContent();
258
- const manifest = readFileSync(join(real.dir, "stigmer.yaml"), "utf8");
259
- expect(manifest).toMatch(new RegExp(`name:\\s*${SEEDPACK_PROJECT_SLUG}\\s*$`, "m"));
260
- });
261
- });
262
-
263
- describe("real seedpack content loads through the declarative scanner", () => {
264
- it("scans + builds apply items without a missing-kind error", () => {
265
- const real = resolveSeedpackContent();
266
- const stage = mkdtempSync(join(tmpdir(), "seedpack-real-"));
267
- try {
268
- extractSeedpack(real.dir, stage);
269
-
270
- const files = scanResourceFiles(stage);
271
- // The scan must reach mcp-servers/ — the directory that historically held
272
- // the kind-less credential-manifest.yaml.
273
- expect(files.some((f) => f.includes("mcp-servers"))).toBe(true);
274
-
275
- // The throw site. Before the fix this raises "missing 'kind' field".
276
- const items = buildDeclarativeItems(files, () => {});
277
- expect(items.length).toBeGreaterThan(0);
278
-
279
- const kinds = new Set(items.map((i) => (i.document as { kind?: string }).kind));
280
- expect(kinds).toContain("McpServer");
281
- expect(kinds).toContain("Agent");
282
- expect(kinds).toContain("Workflow");
283
- } finally {
284
- rmSync(stage, { recursive: true, force: true });
285
- }
286
- });
287
- });