@stigmer/cli 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.
- package/commands/bootstrap.d.ts +3 -0
- package/commands/bootstrap.d.ts.map +1 -0
- package/commands/bootstrap.js +75 -0
- package/commands/bootstrap.js.map +1 -0
- package/commands/marketplace.d.ts.map +1 -1
- package/commands/marketplace.js +7 -7
- package/commands/marketplace.js.map +1 -1
- package/config/resolve.d.ts.map +1 -1
- package/config/resolve.js +8 -7
- package/config/resolve.js.map +1 -1
- package/local/bootstrap.d.ts +32 -13
- package/local/bootstrap.d.ts.map +1 -1
- package/local/bootstrap.js +105 -64
- package/local/bootstrap.js.map +1 -1
- package/local/daemon/launch.d.ts +1 -1
- package/local/daemon/launch.d.ts.map +1 -1
- package/local/paths.d.ts +1 -1
- package/local/paths.js +1 -1
- package/local/plugins/defaults.d.ts +27 -7
- package/local/plugins/defaults.d.ts.map +1 -1
- package/local/plugins/defaults.js +55 -28
- package/local/plugins/defaults.js.map +1 -1
- package/local/runtime/runtimes-install.d.ts.map +1 -1
- package/local/runtime/runtimes-install.js +7 -4
- package/local/runtime/runtimes-install.js.map +1 -1
- package/local/seedpack-retire.d.ts +63 -0
- package/local/seedpack-retire.d.ts.map +1 -0
- package/local/seedpack-retire.js +361 -0
- package/local/seedpack-retire.js.map +1 -0
- package/local/system-org.d.ts +15 -0
- package/local/system-org.d.ts.map +1 -0
- package/local/system-org.js +57 -0
- package/local/system-org.js.map +1 -0
- package/marketplace/config.d.ts +3 -1
- package/marketplace/config.d.ts.map +1 -1
- package/marketplace/config.js +24 -11
- package/marketplace/config.js.map +1 -1
- package/marketplace/github.d.ts +37 -0
- package/marketplace/github.d.ts.map +1 -1
- package/marketplace/github.js +70 -1
- package/marketplace/github.js.map +1 -1
- package/marketplace/install.d.ts +13 -6
- package/marketplace/install.d.ts.map +1 -1
- package/marketplace/install.js +63 -16
- package/marketplace/install.js.map +1 -1
- package/marketplace/official.js +4 -4
- package/marketplace/official.js.map +1 -1
- package/marketplace/render.d.ts.map +1 -1
- package/marketplace/render.js +10 -4
- package/marketplace/render.js.map +1 -1
- package/package.json +7 -7
- package/program.js +2 -2
- package/program.js.map +1 -1
- package/resources/apply/declarative.js +2 -2
- package/resources/apply/declarative.js.map +1 -1
- package/resources/plugin.d.ts.map +1 -1
- package/resources/plugin.js +12 -9
- package/resources/plugin.js.map +1 -1
- package/src/commands/bootstrap.test.ts +253 -0
- package/src/commands/bootstrap.ts +91 -0
- package/src/commands/install.test.ts +28 -9
- package/src/commands/marketplace.test.ts +28 -14
- package/src/commands/marketplace.ts +9 -7
- package/src/config/resolve.test.ts +2 -2
- package/src/config/resolve.ts +8 -7
- package/src/local/bootstrap.test.ts +110 -38
- package/src/local/bootstrap.ts +179 -89
- package/src/local/daemon/launch.ts +1 -1
- package/src/local/paths.ts +1 -1
- package/src/local/plugins/defaults.test.ts +46 -13
- package/src/local/plugins/defaults.ts +77 -34
- package/src/local/runtime/runtimes-install.test.ts +2 -0
- package/src/local/runtime/runtimes-install.ts +7 -4
- package/src/local/seedpack-retire.test.ts +499 -0
- package/src/local/seedpack-retire.ts +474 -0
- package/src/local/system-org.test.ts +124 -0
- package/src/local/system-org.ts +63 -0
- package/src/marketplace/__fixtures__/cursor-marketplace.ts +5 -2
- package/src/marketplace/config.test.ts +47 -22
- package/src/marketplace/config.ts +27 -12
- package/src/marketplace/github.test.ts +77 -1
- package/src/marketplace/github.ts +115 -1
- package/src/marketplace/install.test.ts +84 -17
- package/src/marketplace/install.ts +73 -15
- package/src/marketplace/official.ts +4 -4
- package/src/marketplace/read.test.ts +1 -1
- package/src/marketplace/render.ts +13 -4
- package/src/program.ts +2 -2
- package/src/resources/apply/declarative.integration.test.ts +2 -2
- package/src/resources/apply/declarative.ts +2 -2
- package/src/resources/connect/discover.test.ts +1 -1
- package/src/resources/plugin.ts +11 -10
- package/commands/seedpack.d.ts +0 -3
- package/commands/seedpack.d.ts.map +0 -1
- package/commands/seedpack.js +0 -98
- package/commands/seedpack.js.map +0 -1
- package/local/seedpack/apply.d.ts +0 -72
- package/local/seedpack/apply.d.ts.map +0 -1
- package/local/seedpack/apply.js +0 -145
- package/local/seedpack/apply.js.map +0 -1
- package/local/seedpack/content.d.ts +0 -61
- package/local/seedpack/content.d.ts.map +0 -1
- package/local/seedpack/content.js +0 -178
- package/local/seedpack/content.js.map +0 -1
- package/src/commands/seedpack.ts +0 -116
- package/src/local/seedpack/apply.test.ts +0 -287
- package/src/local/seedpack/apply.ts +0 -199
- package/src/local/seedpack/content.test.ts +0 -169
- package/src/local/seedpack/content.ts +0 -222
|
@@ -22,10 +22,12 @@ import {
|
|
|
22
22
|
type OpenMarketplaceOptions,
|
|
23
23
|
openMarketplace,
|
|
24
24
|
} from "./materialize.js";
|
|
25
|
+
import { peekGitHubMarketplace } from "./github.js";
|
|
25
26
|
import {
|
|
26
27
|
type ReadMarketplaceTree,
|
|
27
28
|
entryDirectory,
|
|
28
29
|
findEntry,
|
|
30
|
+
marketplaceRefusal,
|
|
29
31
|
readMarketplaceTree,
|
|
30
32
|
} from "./read.js";
|
|
31
33
|
import { type InstallRef, formatInstallRef } from "./ref.js";
|
|
@@ -38,12 +40,19 @@ export interface LocatedEntry {
|
|
|
38
40
|
}
|
|
39
41
|
|
|
40
42
|
/**
|
|
41
|
-
* Find the
|
|
42
|
-
* name is searched across every
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
43
|
+
* Find the source a ref names. A prefixed ref names it outright; a bare
|
|
44
|
+
* name is searched across every known source in listing order (the official
|
|
45
|
+
* one first), and exactly one must offer it: none refuses toward
|
|
46
|
+
* `marketplace show`, more than one refuses by naming each holder, because
|
|
47
|
+
* "the first one wins" would make the answer depend on the order the user
|
|
48
|
+
* added sources in. The caller owns `open` and disposes it.
|
|
49
|
+
*
|
|
50
|
+
* The search is cheap by design: a GitHub source is asked through its
|
|
51
|
+
* marketplace file alone (`peekGitHubMarketplace`, a few KB), and only the
|
|
52
|
+
* one source that declares the name is opened as a tree and read whole,
|
|
53
|
+
* which is where "declared" becomes "offered" or the install refuses. With
|
|
54
|
+
* the vendors' catalogues built in, the alternative was three zipballs per
|
|
55
|
+
* bare install.
|
|
47
56
|
*/
|
|
48
57
|
export async function locateEntry(
|
|
49
58
|
ref: InstallRef,
|
|
@@ -77,20 +86,14 @@ export async function locateEntry(
|
|
|
77
86
|
|
|
78
87
|
const holders: LocatedEntry[] = [];
|
|
79
88
|
for (const marketplace of listing.known) {
|
|
80
|
-
|
|
81
|
-
let tree: ReadMarketplaceTree;
|
|
89
|
+
let located: LocatedEntry | undefined;
|
|
82
90
|
try {
|
|
83
|
-
|
|
91
|
+
located = await locateIn(marketplace, ref.name, options);
|
|
84
92
|
} catch (error) {
|
|
85
|
-
open.dispose();
|
|
86
93
|
for (const holder of holders) holder.open.dispose();
|
|
87
94
|
throw error;
|
|
88
95
|
}
|
|
89
|
-
if (
|
|
90
|
-
open.dispose();
|
|
91
|
-
continue;
|
|
92
|
-
}
|
|
93
|
-
holders.push({ marketplace, open, tree });
|
|
96
|
+
if (located !== undefined) holders.push(located);
|
|
94
97
|
}
|
|
95
98
|
if (holders.length === 1) return holders[0]!;
|
|
96
99
|
for (const holder of holders) holder.open.dispose();
|
|
@@ -111,6 +114,61 @@ export async function locateEntry(
|
|
|
111
114
|
);
|
|
112
115
|
}
|
|
113
116
|
|
|
117
|
+
/**
|
|
118
|
+
* The entry called `name` in one source, opened and read, or `undefined`
|
|
119
|
+
* when the source does not offer it. A GitHub source is first asked through
|
|
120
|
+
* its marketplace file alone (a few KB); its zipball is downloaded only when
|
|
121
|
+
* the file declares the name, and the tree read then decides whether it is
|
|
122
|
+
* held. A local or official tree is on disk and is read once. A GitHub
|
|
123
|
+
* repository with no marketplace file declares nothing (a built-in whose
|
|
124
|
+
* vendor moved the file must not break every bare install); one whose file
|
|
125
|
+
* the library refuses is a real fault and is said so.
|
|
126
|
+
*/
|
|
127
|
+
async function locateIn(
|
|
128
|
+
marketplace: KnownMarketplace,
|
|
129
|
+
name: string,
|
|
130
|
+
options: OpenMarketplaceOptions,
|
|
131
|
+
): Promise<LocatedEntry | undefined> {
|
|
132
|
+
if (marketplace.source.type === "github") {
|
|
133
|
+
const peek = await peekGitHubMarketplace(
|
|
134
|
+
marketplace.source,
|
|
135
|
+
options.fetchImpl,
|
|
136
|
+
);
|
|
137
|
+
if (!peek.ok) {
|
|
138
|
+
switch (peek.kind) {
|
|
139
|
+
case "not-a-marketplace":
|
|
140
|
+
return undefined;
|
|
141
|
+
case "refused":
|
|
142
|
+
throw marketplaceRefusal(
|
|
143
|
+
`${describeSource(marketplace.source)} (${peek.location})`,
|
|
144
|
+
peek.errors,
|
|
145
|
+
peek.warnings,
|
|
146
|
+
);
|
|
147
|
+
default: {
|
|
148
|
+
const exhaustive: never = peek;
|
|
149
|
+
return exhaustive;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
if (findEntry(peek.peeked.marketplace, name) === undefined) return undefined;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
const open = await openMarketplace(marketplace.source, options);
|
|
157
|
+
try {
|
|
158
|
+
const tree = readMarketplaceTree(open.root, describeSource(marketplace.source));
|
|
159
|
+
if (findEntry(tree.marketplace, name) === undefined) {
|
|
160
|
+
// Declared by a file but not held by the tree, or simply absent: not a
|
|
161
|
+
// holder. The not-found sentence names every source searched.
|
|
162
|
+
open.dispose();
|
|
163
|
+
return undefined;
|
|
164
|
+
}
|
|
165
|
+
return { marketplace, open, tree };
|
|
166
|
+
} catch (error) {
|
|
167
|
+
open.dispose();
|
|
168
|
+
throw error;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
114
172
|
/** Read, validate and zip the entry called `name`; refuses an entry the marketplace does not offer. */
|
|
115
173
|
export async function prepareEntry(
|
|
116
174
|
tree: ReadMarketplaceTree,
|
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
//
|
|
3
3
|
// The official catalogue (`plugins/` in the OSS repository, published as
|
|
4
4
|
// `@stigmer/plugins`) is the content `stigmer up` bootstraps a backend with,
|
|
5
|
-
// so it follows the
|
|
6
|
-
// the plugins a fresh install gets match the control plane that
|
|
7
|
-
// them. A lean `npx @stigmer/cli` does not carry the content; it is fetched
|
|
5
|
+
// so it follows the server's and the runner's rule: acquired at the CLI's OWN
|
|
6
|
+
// version, so the plugins a fresh install gets match the control plane that
|
|
7
|
+
// installs them. A lean `npx @stigmer/cli` does not carry the content; it is fetched
|
|
8
8
|
// once into ~/.stigmer/runtimes/<version>/ like the server and the runner.
|
|
9
9
|
//
|
|
10
|
-
// Two sources, tried in order (mirrors runtime/server.ts and
|
|
10
|
+
// Two sources, tried in order (mirrors runtime/server.ts and runtime/runner.ts):
|
|
11
11
|
// 1. A repo-tree checkout (dev): `<repo>/plugins`, the tree itself.
|
|
12
12
|
// 2. The published `@stigmer/plugins@<cli-version>`, whose package root IS
|
|
13
13
|
// the marketplace tree (`publish-libs.mjs` publishes from `dist/`, where
|
|
@@ -24,7 +24,7 @@ afterAll(() => {
|
|
|
24
24
|
describe("readMarketplaceTree", () => {
|
|
25
25
|
it("reads a Cursor-dialect tree into the one shape, dropping the missing entry with its sentence", () => {
|
|
26
26
|
const tree = readMarketplaceTree(root);
|
|
27
|
-
expect(tree.marketplace.name).toBe("
|
|
27
|
+
expect(tree.marketplace.name).toBe("acme-plugins");
|
|
28
28
|
expect(tree.marketplace.dialect).toBe("cursor");
|
|
29
29
|
expect(tree.marketplace.plugins.map((entry) => entry.name)).toEqual([
|
|
30
30
|
"thermos",
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
// same kind of thing: client-side configuration, not a server collection.
|
|
6
6
|
|
|
7
7
|
import { readPluginPackage } from "@stigmer/plugin-package";
|
|
8
|
+
import { isBuiltInMarketplaceName } from "@stigmer/plugin-package/client";
|
|
8
9
|
import { CommandResult } from "../output/index.js";
|
|
9
10
|
import { count, readPluginDirectory } from "../resources/plugin.js";
|
|
10
11
|
import {
|
|
@@ -20,13 +21,21 @@ export function renderMarketplaceList(
|
|
|
20
21
|
const total = listing.known.length + listing.unreadable.length;
|
|
21
22
|
const result =
|
|
22
23
|
listing.unreadable.length === 0
|
|
23
|
-
? CommandResult.success(`${count(total, "
|
|
24
|
+
? CommandResult.success(`${count(total, "source")} known`)
|
|
24
25
|
: CommandResult.warning(
|
|
25
|
-
`${count(total, "
|
|
26
|
+
`${count(total, "source")} known, ${count(listing.unreadable.length, "entry")} this CLI cannot read`,
|
|
26
27
|
);
|
|
27
|
-
const section = result.addSection("
|
|
28
|
+
const section = result.addSection("Sources");
|
|
28
29
|
for (const marketplace of listing.known) {
|
|
29
|
-
|
|
30
|
+
// A built-in reads "built in" beside where it comes from, so the user
|
|
31
|
+
// knows which names `remove` will refuse.
|
|
32
|
+
section.field(
|
|
33
|
+
marketplace.name,
|
|
34
|
+
isBuiltInMarketplaceName(marketplace.name) &&
|
|
35
|
+
marketplace.source.type !== "official"
|
|
36
|
+
? `${describeSource(marketplace.source)} (built in)`
|
|
37
|
+
: describeSource(marketplace.source),
|
|
38
|
+
);
|
|
30
39
|
}
|
|
31
40
|
for (const marketplace of listing.unreadable) {
|
|
32
41
|
section.field(marketplace.name, `cannot be read: ${marketplace.reason}`);
|
package/src/program.ts
CHANGED
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
import { Command } from "commander";
|
|
10
10
|
import { registerApiKey } from "./commands/apikey/index.js";
|
|
11
11
|
import { registerApply } from "./commands/apply.js";
|
|
12
|
+
import { registerBootstrap } from "./commands/bootstrap.js";
|
|
12
13
|
import { registerAuth } from "./commands/auth/index.js";
|
|
13
14
|
import { registerCompletion } from "./commands/completion.js";
|
|
14
15
|
import { registerConfig } from "./commands/config/index.js";
|
|
@@ -31,7 +32,6 @@ import { registerResume } from "./commands/resume.js";
|
|
|
31
32
|
import { registerRun } from "./commands/run.js";
|
|
32
33
|
import { registerSchedule } from "./commands/schedule.js";
|
|
33
34
|
import { registerSearch } from "./commands/search.js";
|
|
34
|
-
import { registerSeedpack } from "./commands/seedpack.js";
|
|
35
35
|
import { registerSetup } from "./commands/setup.js";
|
|
36
36
|
import { registerShare } from "./commands/share.js";
|
|
37
37
|
import { registerStatus } from "./commands/status.js";
|
|
@@ -94,10 +94,10 @@ export function buildProgram(): Command {
|
|
|
94
94
|
registerConnect(program);
|
|
95
95
|
registerMcpServer(program);
|
|
96
96
|
registerUp(program);
|
|
97
|
+
registerBootstrap(program);
|
|
97
98
|
registerDown(program);
|
|
98
99
|
registerStatus(program);
|
|
99
100
|
registerLogs(program);
|
|
100
|
-
registerSeedpack(program);
|
|
101
101
|
registerSetup(program);
|
|
102
102
|
registerReset(program);
|
|
103
103
|
registerInternalDaemon(program);
|
|
@@ -149,8 +149,8 @@ describe("applyDeclarative", () => {
|
|
|
149
149
|
// (stigmer/stigmer#402): the server rejects agent enabled_tools against
|
|
150
150
|
// STORED capabilities, so discovery must refresh them between the MCP
|
|
151
151
|
// server applies and the applies that depend on them. Regressing to
|
|
152
|
-
// discovery-at-the-end resurrects the stale-capabilities race (a
|
|
153
|
-
// upgrade adding a tool + enabling it in an agent would fail
|
|
152
|
+
// discovery-at-the-end resurrects the stale-capabilities race (a project
|
|
153
|
+
// upgrade adding a tool + enabling it in an agent would fail its apply).
|
|
154
154
|
const dir = mkdtempSync(join(tmpdir(), "decl-it-order-"));
|
|
155
155
|
try {
|
|
156
156
|
writeFileSync(
|
|
@@ -318,8 +318,8 @@ export async function reconcileProjectMembers(
|
|
|
318
318
|
// apply time (stigmer/stigmer#402), and the backend's own post-apply
|
|
319
319
|
// connect is asynchronous; discovering here means agents in this apply
|
|
320
320
|
// validate against the toolset this apply just shipped, not the previous
|
|
321
|
-
// generation's (which would falsely reject e.g. a
|
|
322
|
-
// adds a tool and enables it in the same pass). Discovery stays
|
|
321
|
+
// generation's (which would falsely reject e.g. a project upgrade that
|
|
322
|
+
// adds a tool to a server and enables it in an agent in the same pass). Discovery stays
|
|
323
323
|
// best-effort: a failed connect warns, capabilities stay stale, and the
|
|
324
324
|
// dependent apply surfaces an actionable error listing last-known tools.
|
|
325
325
|
for (const res of resources) {
|
|
@@ -22,7 +22,7 @@ function stdioSpec(scriptPath: string) {
|
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
// A spec whose args reference ${ALLOWED_DIR}, declared under spec.env — the shape
|
|
25
|
-
//
|
|
25
|
+
// a filesystem MCP server declares its root with (issue #141).
|
|
26
26
|
function stdioSpecWithPlaceholderArg(scriptPath: string) {
|
|
27
27
|
return create(McpServerSpecSchema, {
|
|
28
28
|
serverType: { case: "stdio", value: { command: process.execPath, args: [scriptPath, "${ALLOWED_DIR}"] } },
|
package/src/resources/plugin.ts
CHANGED
|
@@ -29,15 +29,13 @@ import { join } from "node:path";
|
|
|
29
29
|
import { create, toJson } from "@bufbuild/protobuf";
|
|
30
30
|
import {
|
|
31
31
|
MANIFEST_LOCATIONS,
|
|
32
|
-
readPluginPackage,
|
|
33
32
|
type PluginFiles,
|
|
34
33
|
type PluginFinding,
|
|
35
34
|
type PluginPackage,
|
|
36
35
|
} from "@stigmer/plugin-package";
|
|
37
36
|
import {
|
|
38
37
|
DIALECT_LABELS,
|
|
39
|
-
|
|
40
|
-
digestArchive,
|
|
38
|
+
preparePluginArchive,
|
|
41
39
|
selectPluginFiles,
|
|
42
40
|
type CandidateFile,
|
|
43
41
|
} from "@stigmer/plugin-package/client";
|
|
@@ -319,20 +317,23 @@ export async function preparePluginPush(
|
|
|
319
317
|
dir: string,
|
|
320
318
|
ignoreOptions: IgnoreOptions = DEFAULT_IGNORE_OPTIONS,
|
|
321
319
|
): Promise<PreparedPluginPush> {
|
|
320
|
+
// The walk is the CLI's (it prunes directories before listing them, which
|
|
321
|
+
// a flat tree cannot); everything after it is the shared tail every client
|
|
322
|
+
// runs, so a folder pushed here and the same tree read by the console have
|
|
323
|
+
// one digest by construction.
|
|
322
324
|
const directory = readPluginDirectory(dir, ignoreOptions);
|
|
323
|
-
const outcome =
|
|
325
|
+
const outcome = await preparePluginArchive(directory);
|
|
324
326
|
if (!outcome.ok) {
|
|
325
327
|
throw pluginRefusal(dir, outcome.errors, outcome.warnings);
|
|
326
328
|
}
|
|
327
|
-
const archive = archivePlugin(directory.files);
|
|
328
329
|
return {
|
|
329
330
|
dir,
|
|
330
|
-
files:
|
|
331
|
+
files: outcome.prepared.files,
|
|
331
332
|
stats: directory.stats,
|
|
332
|
-
plugin: outcome.plugin,
|
|
333
|
-
warnings: outcome.warnings,
|
|
334
|
-
archive,
|
|
335
|
-
digest:
|
|
333
|
+
plugin: outcome.prepared.plugin,
|
|
334
|
+
warnings: outcome.prepared.warnings,
|
|
335
|
+
archive: outcome.prepared.archive,
|
|
336
|
+
digest: outcome.prepared.digest,
|
|
336
337
|
};
|
|
337
338
|
}
|
|
338
339
|
|
package/commands/seedpack.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"seedpack.d.ts","sourceRoot":"","sources":["../../src/commands/seedpack.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AASzC,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAevD"}
|
package/commands/seedpack.js
DELETED
|
@@ -1,98 +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
|
-
import { configDir, dataDir, isCloudMode, load } from "../config/index.js";
|
|
13
|
-
import { CommandResult, renderResult } from "../output/index.js";
|
|
14
|
-
import { addResultFlags, resultFormat } from "./shared.js";
|
|
15
|
-
export function registerSeedpack(program) {
|
|
16
|
-
const seedpack = program.command("seedpack").description("manage the embedded system seedpack");
|
|
17
|
-
const apply = seedpack
|
|
18
|
-
.command("apply")
|
|
19
|
-
.description("apply the seedpack to the configured backend")
|
|
20
|
-
.option("--force", "re-apply even if the seedpack has not changed", false)
|
|
21
|
-
.action((options) => runApply(options));
|
|
22
|
-
addResultFlags(apply);
|
|
23
|
-
const status = seedpack
|
|
24
|
-
.command("status")
|
|
25
|
-
.description("show seedpack bootstrap status")
|
|
26
|
-
.action((options) => runStatus(options));
|
|
27
|
-
addResultFlags(status);
|
|
28
|
-
}
|
|
29
|
-
async function runApply(flags) {
|
|
30
|
-
const [{ connectBackend }, { ensureAuthenticated }, { applySeedpack }] = await Promise.all([
|
|
31
|
-
import("../backend.js"),
|
|
32
|
-
import("../config/index.js"),
|
|
33
|
-
import("../local/seedpack/apply.js"),
|
|
34
|
-
]);
|
|
35
|
-
const client = connectBackend();
|
|
36
|
-
ensureAuthenticated(client.config);
|
|
37
|
-
const result = await applySeedpack({
|
|
38
|
-
controller: client.controller,
|
|
39
|
-
stigmer: client.stigmer,
|
|
40
|
-
info: (line) => process.stderr.write(`${line}\n`),
|
|
41
|
-
warn: (line) => process.stderr.write(`${line}\n`),
|
|
42
|
-
}, {
|
|
43
|
-
markerDir: markerDir(),
|
|
44
|
-
force: flags.force === true,
|
|
45
|
-
useServerHash: isCloudMode(load()),
|
|
46
|
-
});
|
|
47
|
-
const label = backendLabel();
|
|
48
|
-
const message = result.applied
|
|
49
|
-
? `Seedpack applied to ${label} backend`
|
|
50
|
-
: `Seedpack already up to date on ${label} backend (use --force to re-apply)`;
|
|
51
|
-
renderResult(CommandResult.success(message), resultFormat(flags));
|
|
52
|
-
}
|
|
53
|
-
async function runStatus(flags) {
|
|
54
|
-
const { readServerSeedpackHash, resolveSeedpackOrg, seedpackContentHash } = await import("../local/seedpack/apply.js");
|
|
55
|
-
const { readMarker } = await import("../local/seedpack/content.js");
|
|
56
|
-
const hash = seedpackContentHash();
|
|
57
|
-
// Cloud mode asks the server (the label on the seedpack Project) so status
|
|
58
|
-
// is truthful from ANY machine, not just the one that last ran apply.
|
|
59
|
-
let stored;
|
|
60
|
-
let storedLabel;
|
|
61
|
-
if (isCloudMode(load())) {
|
|
62
|
-
const { connectBackend } = await import("../backend.js");
|
|
63
|
-
const { ensureAuthenticated } = await import("../config/index.js");
|
|
64
|
-
const client = connectBackend();
|
|
65
|
-
ensureAuthenticated(client.config);
|
|
66
|
-
stored = await readServerSeedpackHash(client.stigmer, resolveSeedpackOrg());
|
|
67
|
-
storedLabel = "Applied Hash (server)";
|
|
68
|
-
}
|
|
69
|
-
else {
|
|
70
|
-
stored = readMarker(markerDir());
|
|
71
|
-
storedLabel = "Applied Hash";
|
|
72
|
-
}
|
|
73
|
-
const result = CommandResult.success("Seedpack status");
|
|
74
|
-
const section = result.addSection("");
|
|
75
|
-
section.field("Backend", backendLabel());
|
|
76
|
-
section.field("Embedded Hash", hash);
|
|
77
|
-
if (stored === null) {
|
|
78
|
-
section.field("Status", "Not applied (run 'stigmer seedpack apply')");
|
|
79
|
-
}
|
|
80
|
-
else {
|
|
81
|
-
section.field(storedLabel, stored);
|
|
82
|
-
section.field("Status", stored === hash ? "Up to date" : "Outdated (run 'stigmer seedpack apply' to update)");
|
|
83
|
-
}
|
|
84
|
-
renderResult(result, resultFormat(flags));
|
|
85
|
-
}
|
|
86
|
-
// Marker lives with the backend's state: the data dir for local, the config dir
|
|
87
|
-
// for cloud (mirrors the Go CLI's resolveMarkerDir).
|
|
88
|
-
function markerDir() {
|
|
89
|
-
return isCloudMode(load()) ? configDir() : dataDir();
|
|
90
|
-
}
|
|
91
|
-
function backendLabel() {
|
|
92
|
-
const config = load();
|
|
93
|
-
if (!isCloudMode(config))
|
|
94
|
-
return "local";
|
|
95
|
-
const endpoint = config.backend.cloud?.endpoint ?? "api.stigmer.ai:443";
|
|
96
|
-
return `cloud (${endpoint})`;
|
|
97
|
-
}
|
|
98
|
-
//# sourceMappingURL=seedpack.js.map
|
package/commands/seedpack.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"seedpack.js","sourceRoot":"","sources":["../../src/commands/seedpack.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
import type { Stigmer } from "@stigmer/sdk";
|
|
2
|
-
import type { ControllerFn } from "../../resources/apply/handlers.js";
|
|
3
|
-
import { type SeedpackContent } from "./content.js";
|
|
4
|
-
/**
|
|
5
|
-
* Reserved label on the seedpack Project recording the last applied content
|
|
6
|
-
* hash (cloud#429). Writing a NEW value requires `can_write_reserved_labels`
|
|
7
|
-
* (the seeding identity's capability); re-sending an unchanged value is an
|
|
8
|
-
* echo the cloud guard passes for any caller — so re-applies of identical
|
|
9
|
-
* content are never treated as reserved-label writes.
|
|
10
|
-
*/
|
|
11
|
-
export declare const SEEDPACK_HASH_LABEL = "stigmer.ai/seedpack-hash";
|
|
12
|
-
/**
|
|
13
|
-
* The seedpack Project's slug. The server derives it from the manifest's
|
|
14
|
-
* `metadata.name` in `seedpack/stigmer.yaml` — "stigmer-seedpack" is already
|
|
15
|
-
* slug-shaped, so name and slug coincide. Pinned by a test against the real
|
|
16
|
-
* content so a rename there fails loudly here.
|
|
17
|
-
*/
|
|
18
|
-
export declare const SEEDPACK_PROJECT_SLUG = "stigmer-seedpack";
|
|
19
|
-
export interface SeedpackApplyDeps {
|
|
20
|
-
/** Raw command-controller accessor (full-proto apply, preserves metadata.id). */
|
|
21
|
-
readonly controller: ControllerFn;
|
|
22
|
-
/** High-level client for skill push + post-apply MCP discovery. */
|
|
23
|
-
readonly stigmer: Stigmer;
|
|
24
|
-
/** Human progress lines (stderr). */
|
|
25
|
-
readonly info: (line: string) => void;
|
|
26
|
-
/** Warnings (stderr). */
|
|
27
|
-
readonly warn: (line: string) => void;
|
|
28
|
-
}
|
|
29
|
-
export interface SeedpackApplyOptions {
|
|
30
|
-
/** Directory holding the idempotency marker (local mode only). */
|
|
31
|
-
readonly markerDir: string;
|
|
32
|
-
/** Target org slug. Defaults to STIGMER_SEEDPACK_ORG, then "stigmer". */
|
|
33
|
-
readonly org?: string;
|
|
34
|
-
/** Re-apply even when the content hash is unchanged. */
|
|
35
|
-
readonly force?: boolean;
|
|
36
|
-
/** Pre-resolved content (injectable for tests); resolved on demand otherwise. */
|
|
37
|
-
readonly content?: SeedpackContent;
|
|
38
|
-
readonly home?: string;
|
|
39
|
-
/**
|
|
40
|
-
* Cloud mode: the idempotency truth is the {@link SEEDPACK_HASH_LABEL} on the
|
|
41
|
-
* server's seedpack Project, read via {@link readServerSeedpackHash} — the
|
|
42
|
-
* local marker is neither read nor written, so a stateless machine (CI, a
|
|
43
|
-
* second operator laptop) still skips unchanged content correctly.
|
|
44
|
-
*/
|
|
45
|
-
readonly useServerHash?: boolean;
|
|
46
|
-
}
|
|
47
|
-
export interface SeedpackApplyResult {
|
|
48
|
-
/** True when the seedpack was applied; false when skipped as up to date. */
|
|
49
|
-
readonly applied: boolean;
|
|
50
|
-
/** The current content hash (stored in the marker on a successful apply). */
|
|
51
|
-
readonly hash: string;
|
|
52
|
-
/** The resolved target org. */
|
|
53
|
-
readonly org: string;
|
|
54
|
-
}
|
|
55
|
-
/** Resolve the target org: explicit option > env var > "stigmer". */
|
|
56
|
-
export declare function resolveSeedpackOrg(explicit?: string): string;
|
|
57
|
-
/** Compute the current seedpack content hash without applying (drives `status`). */
|
|
58
|
-
export declare function seedpackContentHash(opts?: Pick<SeedpackApplyOptions, "content" | "home">): string;
|
|
59
|
-
/**
|
|
60
|
-
* Read the applied content hash recorded on the backend's seedpack Project,
|
|
61
|
-
* or null when it cannot be proven (project absent — never applied — or the
|
|
62
|
-
* read failed). Null means "apply": the apply itself is idempotent server-side,
|
|
63
|
-
* so an unprovable state costs one redundant pass, never a skipped update.
|
|
64
|
-
*/
|
|
65
|
-
export declare function readServerSeedpackHash(stigmer: Stigmer, org: string): Promise<string | null>;
|
|
66
|
-
/**
|
|
67
|
-
* Apply the seedpack to the backend the deps connect to. Returns `applied:false`
|
|
68
|
-
* (without touching the backend beyond the cloud-mode hash read) when the
|
|
69
|
-
* recorded hash already matches the content hash and `force` is not set.
|
|
70
|
-
*/
|
|
71
|
-
export declare function applySeedpack(deps: SeedpackApplyDeps, opts: SeedpackApplyOptions): Promise<SeedpackApplyResult>;
|
|
72
|
-
//# sourceMappingURL=apply.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"apply.d.ts","sourceRoot":"","sources":["../../../src/local/seedpack/apply.ts"],"names":[],"mappings":"AAwBA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAG5C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mCAAmC,CAAC;AACtE,OAAO,EAKL,KAAK,eAAe,EAErB,MAAM,cAAc,CAAC;AAKtB;;;;;;GAMG;AACH,eAAO,MAAM,mBAAmB,6BAA6B,CAAC;AAE9D;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB,qBAAqB,CAAC;AAExD,MAAM,WAAW,iBAAiB;IAChC,iFAAiF;IACjF,QAAQ,CAAC,UAAU,EAAE,YAAY,CAAC;IAClC,mEAAmE;IACnE,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,qCAAqC;IACrC,QAAQ,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC,yBAAyB;IACzB,QAAQ,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CACvC;AAED,MAAM,WAAW,oBAAoB;IACnC,kEAAkE;IAClE,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,yEAAyE;IACzE,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,wDAAwD;IACxD,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;IACzB,iFAAiF;IACjF,QAAQ,CAAC,OAAO,CAAC,EAAE,eAAe,CAAC;IACnC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB;;;;;OAKG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,OAAO,CAAC;CAClC;AAED,MAAM,WAAW,mBAAmB;IAClC,4EAA4E;IAC5E,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,6EAA6E;IAC7E,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,+BAA+B;IAC/B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;CACtB;AAED,qEAAqE;AACrE,wBAAgB,kBAAkB,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAK5D;AAED,oFAAoF;AACpF,wBAAgB,mBAAmB,CAAC,IAAI,GAAE,IAAI,CAAC,oBAAoB,EAAE,SAAS,GAAG,MAAM,CAAM,GAAG,MAAM,CAGrG;AAED;;;;;GAKG;AACH,wBAAsB,sBAAsB,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAOlG;AAED;;;;GAIG;AACH,wBAAsB,aAAa,CAAC,IAAI,EAAE,iBAAiB,EAAE,IAAI,EAAE,oBAAoB,GAAG,OAAO,CAAC,mBAAmB,CAAC,CA6BrH"}
|
package/local/seedpack/apply.js
DELETED
|
@@ -1,145 +0,0 @@
|
|
|
1
|
-
// In-process seedpack apply.
|
|
2
|
-
//
|
|
3
|
-
// The TS equivalent of Go's seedpackbootstrap.Apply, with one deliberate
|
|
4
|
-
// improvement: instead of shelling out to `stigmer apply` as a subprocess, this
|
|
5
|
-
// drives the same in-process declarative-apply path that `stigmer apply` uses —
|
|
6
|
-
// one code path, no recursion guard, no second process.
|
|
7
|
-
//
|
|
8
|
-
// Two phases respect the resource hierarchy (mirrors the Go bootstrap):
|
|
9
|
-
// 1. organizations/ via file mode — the org must exist before its members.
|
|
10
|
-
// 2. the project (stigmer.yaml + agents/skills/mcp-servers/workflows) via the
|
|
11
|
-
// declarative reconciler, under the target org.
|
|
12
|
-
//
|
|
13
|
-
// Idempotent, with the applied-hash truth living with the backend it describes
|
|
14
|
-
// (cloud#429): every apply stamps the content hash as a reserved label on the
|
|
15
|
-
// seedpack Project, and cloud-mode runs skip by reading that label back — so
|
|
16
|
-
// any machine (operator laptop, CI) sees the same applied state. Local mode
|
|
17
|
-
// keeps the original marker file (the local data dir lives and dies with the
|
|
18
|
-
// local backend, so a local file IS backend-scoped state there).
|
|
19
|
-
import { mkdtempSync, rmSync } from "node:fs";
|
|
20
|
-
import { tmpdir } from "node:os";
|
|
21
|
-
import { join } from "node:path";
|
|
22
|
-
import { create } from "@bufbuild/protobuf";
|
|
23
|
-
import { ApiResourceMetadataSchema } from "@stigmer/protos/ai/stigmer/commons/apiresource/metadata_pb";
|
|
24
|
-
import { applyItem, resolveApplyItems } from "../../resources/apply/apply.js";
|
|
25
|
-
import { applyDeclarative, detectTrack } from "../../resources/apply/declarative.js";
|
|
26
|
-
import { extractSeedpack, hashSeedpackContent, readMarker, resolveSeedpackContent, writeMarker, } from "./content.js";
|
|
27
|
-
const DEFAULT_ORG = "stigmer";
|
|
28
|
-
const ORG_ENV_VAR = "STIGMER_SEEDPACK_ORG";
|
|
29
|
-
/**
|
|
30
|
-
* Reserved label on the seedpack Project recording the last applied content
|
|
31
|
-
* hash (cloud#429). Writing a NEW value requires `can_write_reserved_labels`
|
|
32
|
-
* (the seeding identity's capability); re-sending an unchanged value is an
|
|
33
|
-
* echo the cloud guard passes for any caller — so re-applies of identical
|
|
34
|
-
* content are never treated as reserved-label writes.
|
|
35
|
-
*/
|
|
36
|
-
export const SEEDPACK_HASH_LABEL = "stigmer.ai/seedpack-hash";
|
|
37
|
-
/**
|
|
38
|
-
* The seedpack Project's slug. The server derives it from the manifest's
|
|
39
|
-
* `metadata.name` in `seedpack/stigmer.yaml` — "stigmer-seedpack" is already
|
|
40
|
-
* slug-shaped, so name and slug coincide. Pinned by a test against the real
|
|
41
|
-
* content so a rename there fails loudly here.
|
|
42
|
-
*/
|
|
43
|
-
export const SEEDPACK_PROJECT_SLUG = "stigmer-seedpack";
|
|
44
|
-
/** Resolve the target org: explicit option > env var > "stigmer". */
|
|
45
|
-
export function resolveSeedpackOrg(explicit) {
|
|
46
|
-
if (explicit !== undefined && explicit !== "")
|
|
47
|
-
return explicit;
|
|
48
|
-
const env = process.env[ORG_ENV_VAR];
|
|
49
|
-
if (env !== undefined && env !== "")
|
|
50
|
-
return env;
|
|
51
|
-
return DEFAULT_ORG;
|
|
52
|
-
}
|
|
53
|
-
/** Compute the current seedpack content hash without applying (drives `status`). */
|
|
54
|
-
export function seedpackContentHash(opts = {}) {
|
|
55
|
-
const content = opts.content ?? resolveSeedpackContent({ home: opts.home });
|
|
56
|
-
return hashSeedpackContent(content.dir);
|
|
57
|
-
}
|
|
58
|
-
/**
|
|
59
|
-
* Read the applied content hash recorded on the backend's seedpack Project,
|
|
60
|
-
* or null when it cannot be proven (project absent — never applied — or the
|
|
61
|
-
* read failed). Null means "apply": the apply itself is idempotent server-side,
|
|
62
|
-
* so an unprovable state costs one redundant pass, never a skipped update.
|
|
63
|
-
*/
|
|
64
|
-
export async function readServerSeedpackHash(stigmer, org) {
|
|
65
|
-
try {
|
|
66
|
-
const project = await stigmer.project.getByReference({ org, slug: SEEDPACK_PROJECT_SLUG });
|
|
67
|
-
return project.metadata?.labels?.[SEEDPACK_HASH_LABEL] ?? null;
|
|
68
|
-
}
|
|
69
|
-
catch {
|
|
70
|
-
return null;
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
/**
|
|
74
|
-
* Apply the seedpack to the backend the deps connect to. Returns `applied:false`
|
|
75
|
-
* (without touching the backend beyond the cloud-mode hash read) when the
|
|
76
|
-
* recorded hash already matches the content hash and `force` is not set.
|
|
77
|
-
*/
|
|
78
|
-
export async function applySeedpack(deps, opts) {
|
|
79
|
-
const org = resolveSeedpackOrg(opts.org);
|
|
80
|
-
const content = opts.content ?? resolveSeedpackContent({ home: opts.home });
|
|
81
|
-
const hash = hashSeedpackContent(content.dir);
|
|
82
|
-
const appliedHash = opts.useServerHash === true
|
|
83
|
-
? await readServerSeedpackHash(deps.stigmer, org)
|
|
84
|
-
: readMarker(opts.markerDir);
|
|
85
|
-
if (opts.force !== true && appliedHash === hash) {
|
|
86
|
-
return { applied: false, hash, org };
|
|
87
|
-
}
|
|
88
|
-
deps.info("Applying system resources (seedpack)…");
|
|
89
|
-
const stage = mkdtempSync(join(tmpdir(), "stigmer-seedpack-"));
|
|
90
|
-
try {
|
|
91
|
-
extractSeedpack(content.dir, stage);
|
|
92
|
-
await applyOrganizations(deps, stage);
|
|
93
|
-
await applyProject(deps, stage, org, hash);
|
|
94
|
-
// The Project label written above is the cloud-mode record; the marker
|
|
95
|
-
// stays the local-mode one. Never both — two records of one fact drift.
|
|
96
|
-
if (opts.useServerHash !== true) {
|
|
97
|
-
writeMarker(opts.markerDir, hash);
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
finally {
|
|
101
|
-
rmSync(stage, { recursive: true, force: true });
|
|
102
|
-
}
|
|
103
|
-
deps.info("System resources applied successfully");
|
|
104
|
-
return { applied: true, hash, org };
|
|
105
|
-
}
|
|
106
|
-
// Phase 1: organizations via file mode. Organizations sit above the project and
|
|
107
|
-
// carry no org context themselves, so they apply with an empty org.
|
|
108
|
-
async function applyOrganizations(deps, stageDir) {
|
|
109
|
-
const orgDir = join(stageDir, "organizations");
|
|
110
|
-
let items;
|
|
111
|
-
try {
|
|
112
|
-
items = resolveApplyItems(orgDir);
|
|
113
|
-
}
|
|
114
|
-
catch {
|
|
115
|
-
return; // No organizations to apply.
|
|
116
|
-
}
|
|
117
|
-
for (const item of items) {
|
|
118
|
-
const outcome = await applyItem(deps.controller, item, "", false);
|
|
119
|
-
if (outcome.warning !== undefined)
|
|
120
|
-
deps.warn(outcome.warning);
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
// Phase 2: the project (agents, skills, MCP servers, workflows) via the shared
|
|
124
|
-
// declarative reconciler — the same path `stigmer apply` runs for a user project.
|
|
125
|
-
//
|
|
126
|
-
// The content hash is stamped as a reserved label on the Project HERE, in the
|
|
127
|
-
// seedpack path only — general `stigmer apply` never writes reserved labels.
|
|
128
|
-
// The stamp rides the project apply that happens anyway, so recording the hash
|
|
129
|
-
// costs no extra RPC and can never succeed while the apply failed.
|
|
130
|
-
async function applyProject(deps, stageDir, org, contentHash) {
|
|
131
|
-
const detect = detectTrack(stageDir);
|
|
132
|
-
if (detect.track !== "declarative" || detect.project === undefined) {
|
|
133
|
-
throw new Error(`seedpack is not a declarative project (detected '${detect.track}')`);
|
|
134
|
-
}
|
|
135
|
-
detect.project.metadata ??= create(ApiResourceMetadataSchema, {});
|
|
136
|
-
detect.project.metadata.labels[SEEDPACK_HASH_LABEL] = contentHash;
|
|
137
|
-
await applyDeclarative(detect, {
|
|
138
|
-
controller: deps.controller,
|
|
139
|
-
stigmer: deps.stigmer,
|
|
140
|
-
org,
|
|
141
|
-
info: deps.info,
|
|
142
|
-
warn: deps.warn,
|
|
143
|
-
});
|
|
144
|
-
}
|
|
145
|
-
//# sourceMappingURL=apply.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"apply.js","sourceRoot":"","sources":["../../../src/local/seedpack/apply.ts"],"names":[],"mappings":"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"}
|