@stigmer/cli 3.38.3 → 3.39.1-dev.20260928194002
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.map +1 -1
- package/commands/bootstrap.js +9 -2
- package/commands/bootstrap.js.map +1 -1
- package/local/bootstrap.d.ts +5 -1
- package/local/bootstrap.d.ts.map +1 -1
- package/local/bootstrap.js +31 -2
- package/local/bootstrap.js.map +1 -1
- package/package.json +7 -7
- package/src/commands/bootstrap.ts +12 -2
- package/src/local/bootstrap.ts +34 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bootstrap.d.ts","sourceRoot":"","sources":["../src/commands/bootstrap.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"bootstrap.d.ts","sourceRoot":"","sources":["../src/commands/bootstrap.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAMzC,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAQxD"}
|
package/commands/bootstrap.js
CHANGED
|
@@ -7,9 +7,13 @@
|
|
|
7
7
|
// one instead (`stigmer config context set --org`) and needs no bootstrap.
|
|
8
8
|
//
|
|
9
9
|
// Flagless on purpose: the act is idempotent, so there is nothing to force;
|
|
10
|
-
// a second run changes nothing and says so. It never deletes anything.
|
|
10
|
+
// a second run changes nothing and says so. It never deletes anything. When
|
|
11
|
+
// the default organization was deleted, its slug is never reused and the
|
|
12
|
+
// backend cannot be made ready under it: the verb fails, naming how to
|
|
13
|
+
// choose another organization.
|
|
11
14
|
// Heavy modules load lazily inside the action so `--help` stays fast.
|
|
12
15
|
import { DEFAULT_LOCAL_ORG, ensureAuthenticated } from "../config/index.js";
|
|
16
|
+
import { CliExitError, ExitCode } from "../errors/index.js";
|
|
13
17
|
import { CommandResult, renderResult } from "../output/index.js";
|
|
14
18
|
import { addResultFlags, resultFormat } from "./shared.js";
|
|
15
19
|
export function registerBootstrap(program) {
|
|
@@ -20,13 +24,16 @@ export function registerBootstrap(program) {
|
|
|
20
24
|
addResultFlags(bootstrap);
|
|
21
25
|
}
|
|
22
26
|
async function runBootstrapCommand(flags) {
|
|
23
|
-
const [{ connectBackend }, { bootstrapBackend }] = await Promise.all([
|
|
27
|
+
const [{ connectBackend }, { bootstrapBackend, RESERVED_DEFAULT_ORG_HINTS, RESERVED_DEFAULT_ORG_MESSAGE },] = await Promise.all([
|
|
24
28
|
import("../backend.js"),
|
|
25
29
|
import("../local/bootstrap.js"),
|
|
26
30
|
]);
|
|
27
31
|
const client = connectBackend();
|
|
28
32
|
ensureAuthenticated(client.config);
|
|
29
33
|
const state = await bootstrapBackend(client.stigmer);
|
|
34
|
+
if (state === "reserved") {
|
|
35
|
+
throw new CliExitError(RESERVED_DEFAULT_ORG_MESSAGE, ExitCode.Usage, RESERVED_DEFAULT_ORG_HINTS);
|
|
36
|
+
}
|
|
30
37
|
const out = CommandResult.success("Backend is ready");
|
|
31
38
|
out.addSection("Organization").field("Slug", DEFAULT_LOCAL_ORG).field("State", state);
|
|
32
39
|
renderResult(out, resultFormat(flags));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bootstrap.js","sourceRoot":"","sources":["../src/commands/bootstrap.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,uEAAuE;AACvE,4EAA4E;AAC5E,0EAA0E;AAC1E,0EAA0E;AAC1E,2EAA2E;AAC3E,2EAA2E;AAC3E,EAAE;AACF,4EAA4E;AAC5E,uEAAuE;AACvE,sEAAsE;AAGtE,OAAO,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAC5E,OAAO,EAAE,aAAa,EAAoB,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACnF,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3D,MAAM,UAAU,iBAAiB,CAAC,OAAgB;IAChD,MAAM,SAAS,GAAG,OAAO;SACtB,OAAO,CAAC,WAAW,CAAC;SACpB,WAAW,CACV,4FAA4F,CAC7F;SACA,MAAM,CAAC,CAAC,OAAoB,EAAE,EAAE,CAAC,mBAAmB,CAAC,OAAO,CAAC,CAAC,CAAC;IAClE,cAAc,CAAC,SAAS,CAAC,CAAC;AAC5B,CAAC;AAED,KAAK,UAAU,mBAAmB,CAAC,KAAkB;IACnD,MAAM,
|
|
1
|
+
{"version":3,"file":"bootstrap.js","sourceRoot":"","sources":["../src/commands/bootstrap.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,uEAAuE;AACvE,4EAA4E;AAC5E,0EAA0E;AAC1E,0EAA0E;AAC1E,2EAA2E;AAC3E,2EAA2E;AAC3E,EAAE;AACF,4EAA4E;AAC5E,4EAA4E;AAC5E,yEAAyE;AACzE,uEAAuE;AACvE,+BAA+B;AAC/B,sEAAsE;AAGtE,OAAO,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAC5E,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC5D,OAAO,EAAE,aAAa,EAAoB,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACnF,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3D,MAAM,UAAU,iBAAiB,CAAC,OAAgB;IAChD,MAAM,SAAS,GAAG,OAAO;SACtB,OAAO,CAAC,WAAW,CAAC;SACpB,WAAW,CACV,4FAA4F,CAC7F;SACA,MAAM,CAAC,CAAC,OAAoB,EAAE,EAAE,CAAC,mBAAmB,CAAC,OAAO,CAAC,CAAC,CAAC;IAClE,cAAc,CAAC,SAAS,CAAC,CAAC;AAC5B,CAAC;AAED,KAAK,UAAU,mBAAmB,CAAC,KAAkB;IACnD,MAAM,CACJ,EAAE,cAAc,EAAE,EAClB,EAAE,gBAAgB,EAAE,0BAA0B,EAAE,4BAA4B,EAAE,EAC/E,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;QACpB,MAAM,CAAC,eAAe,CAAC;QACvB,MAAM,CAAC,uBAAuB,CAAC;KAChC,CAAC,CAAC;IAEH,MAAM,MAAM,GAAG,cAAc,EAAE,CAAC;IAChC,mBAAmB,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAEnC,MAAM,KAAK,GAAG,MAAM,gBAAgB,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IACrD,IAAI,KAAK,KAAK,UAAU,EAAE,CAAC;QACzB,MAAM,IAAI,YAAY,CAAC,4BAA4B,EAAE,QAAQ,CAAC,KAAK,EAAE,0BAA0B,CAAC,CAAC;IACnG,CAAC;IAED,MAAM,GAAG,GAAG,aAAa,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAC;IACtD,GAAG,CAAC,UAAU,CAAC,cAAc,CAAC,CAAC,KAAK,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;IACtF,YAAY,CAAC,GAAG,EAAE,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC;AACzC,CAAC"}
|
package/local/bootstrap.d.ts
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import { type Stigmer } from "@stigmer/sdk";
|
|
2
2
|
import type { BackendClient } from "../client/index.js";
|
|
3
3
|
export type Say = (line: string) => void;
|
|
4
|
-
export type BootstrapOutcome = "present" | "created";
|
|
4
|
+
export type BootstrapOutcome = "present" | "created" | "reserved";
|
|
5
|
+
/** What the CLI says when the default organization was deleted and its slug is reserved. */
|
|
6
|
+
export declare const RESERVED_DEFAULT_ORG_MESSAGE = "The 'stigmer' organization was deleted, and an organization's slug is never reused, so it cannot be created again.";
|
|
7
|
+
/** How to choose another organization, in the order the CLI resolves one (config/resolve.ts). */
|
|
8
|
+
export declare const RESERVED_DEFAULT_ORG_HINTS: readonly string[];
|
|
5
9
|
/**
|
|
6
10
|
* Make sure the organization the CLI falls back to exists on the backend
|
|
7
11
|
* `stigmer` is bound to: what `stigmer bootstrap` runs. Idempotent; a lost
|
package/local/bootstrap.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bootstrap.d.ts","sourceRoot":"","sources":["../src/local/bootstrap.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"bootstrap.d.ts","sourceRoot":"","sources":["../src/local/bootstrap.ts"],"names":[],"mappings":"AAuCA,OAAO,EAAkB,KAAK,OAAO,EAAgB,MAAM,cAAc,CAAC;AAC1E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAIxD,MAAM,MAAM,GAAG,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;AAEzC,MAAM,MAAM,gBAAgB,GAAG,SAAS,GAAG,SAAS,GAAG,UAAU,CAAC;AAQlE,4FAA4F;AAC5F,eAAO,MAAM,4BAA4B,uHAAoI,CAAC;AAE9K,iGAAiG;AACjG,eAAO,MAAM,0BAA0B,EAAE,SAAS,MAAM,EAKvD,CAAC;AAEF;;;;GAIG;AACH,wBAAsB,gBAAgB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAwBlF;AAED,oHAAoH;AACpH,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,MAAM,CAAC,EAAE,aAAa,CAAC;IAChC,QAAQ,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC;IACnB,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,gBAAgB,CAAC,CAAC;CACtE;AAMD,+FAA+F;AAC/F,wBAAsB,qBAAqB,CAAC,IAAI,GAAE,aAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CAkBnF"}
|
package/local/bootstrap.js
CHANGED
|
@@ -13,6 +13,14 @@
|
|
|
13
13
|
// other refusal propagates with the server's sentence; the caller decides
|
|
14
14
|
// how loud to be.
|
|
15
15
|
//
|
|
16
|
+
// One `already-exists` is not that race. An organization's slug is never
|
|
17
|
+
// reused, so once `stigmer` has been deleted no create can take it again,
|
|
18
|
+
// and the server says so with the ORGANIZATION_SLUG_RESERVED reason. That
|
|
19
|
+
// is `reserved`: the default organization is gone for good, and the person
|
|
20
|
+
// must name another (RESERVED_DEFAULT_ORG_HINTS says how). Reporting it as
|
|
21
|
+
// `present` would leave every command that falls back to `stigmer` failing
|
|
22
|
+
// with no explanation.
|
|
23
|
+
//
|
|
16
24
|
// The create carries no label. Writing a label in the reserved `stigmer.ai/`
|
|
17
25
|
// namespace needs a platform permission that a self-hosted server with
|
|
18
26
|
// authentication on grants to nobody, and nothing reads one on an
|
|
@@ -28,9 +36,23 @@
|
|
|
28
36
|
// client is pinned to a fresh local config (localhost:SERVER_PORT) with no
|
|
29
37
|
// auth, the trusted-local identity.
|
|
30
38
|
import { ManagementMode } from "@stigmer/protos/ai/stigmer/tenancy/organization/v1/enum_pb";
|
|
31
|
-
import { StigmerError } from "@stigmer/sdk";
|
|
39
|
+
import { getErrorReason, StigmerError } from "@stigmer/sdk";
|
|
32
40
|
import { DEFAULT_LOCAL_ORG } from "../config/resolve.js";
|
|
33
41
|
import { log } from "../logger.js";
|
|
42
|
+
/**
|
|
43
|
+
* The refusal reason of a create whose slug a deleted organization held
|
|
44
|
+
* (OrganizationCommandController.create's contract): a slug is never reused.
|
|
45
|
+
*/
|
|
46
|
+
const REASON_ORGANIZATION_SLUG_RESERVED = "ORGANIZATION_SLUG_RESERVED";
|
|
47
|
+
/** What the CLI says when the default organization was deleted and its slug is reserved. */
|
|
48
|
+
export const RESERVED_DEFAULT_ORG_MESSAGE = `The '${DEFAULT_LOCAL_ORG}' organization was deleted, and an organization's slug is never reused, so it cannot be created again.`;
|
|
49
|
+
/** How to choose another organization, in the order the CLI resolves one (config/resolve.ts). */
|
|
50
|
+
export const RESERVED_DEFAULT_ORG_HINTS = [
|
|
51
|
+
"Name the organization to use, in any of these ways:",
|
|
52
|
+
" --org <slug> on a command",
|
|
53
|
+
" STIGMER_ORG_ID=<slug> in the environment",
|
|
54
|
+
" stigmer config context set --org <slug>",
|
|
55
|
+
];
|
|
34
56
|
/**
|
|
35
57
|
* Make sure the organization the CLI falls back to exists on the backend
|
|
36
58
|
* `stigmer` is bound to: what `stigmer bootstrap` runs. Idempotent; a lost
|
|
@@ -55,7 +77,9 @@ export async function bootstrapBackend(stigmer) {
|
|
|
55
77
|
}
|
|
56
78
|
catch (error) {
|
|
57
79
|
if (error instanceof StigmerError && error.code === "already-exists") {
|
|
58
|
-
return
|
|
80
|
+
return getErrorReason(error)?.reason === REASON_ORGANIZATION_SLUG_RESERVED
|
|
81
|
+
? "reserved"
|
|
82
|
+
: "present";
|
|
59
83
|
}
|
|
60
84
|
throw error;
|
|
61
85
|
}
|
|
@@ -79,6 +103,11 @@ export async function bootstrapLocalBackend(deps = {}) {
|
|
|
79
103
|
log.debug("bootstrap complete", { org: outcome });
|
|
80
104
|
if (outcome === "created")
|
|
81
105
|
say(`Created the '${DEFAULT_LOCAL_ORG}' organization`);
|
|
106
|
+
if (outcome === "reserved") {
|
|
107
|
+
say(`Warning: ${RESERVED_DEFAULT_ORG_MESSAGE}`);
|
|
108
|
+
for (const hint of RESERVED_DEFAULT_ORG_HINTS)
|
|
109
|
+
say(hint);
|
|
110
|
+
}
|
|
82
111
|
}
|
|
83
112
|
async function freshLocalClient() {
|
|
84
113
|
const [{ createBackendClient }, { getDefault }] = await Promise.all([
|
package/local/bootstrap.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bootstrap.js","sourceRoot":"","sources":["../src/local/bootstrap.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAC5E,wEAAwE;AACxE,0EAA0E;AAC1E,4EAA4E;AAC5E,6EAA6E;AAC7E,4EAA4E;AAC5E,4EAA4E;AAC5E,sBAAsB;AACtB,EAAE;AACF,uEAAuE;AACvE,4EAA4E;AAC5E,yEAAyE;AACzE,0EAA0E;AAC1E,kBAAkB;AAClB,EAAE;AACF,6EAA6E;AAC7E,uEAAuE;AACvE,kEAAkE;AAClE,2EAA2E;AAC3E,mEAAmE;AACnE,EAAE;AACF,uEAAuE;AACvE,4EAA4E;AAC5E,yEAAyE;AACzE,0EAA0E;AAC1E,2EAA2E;AAC3E,4EAA4E;AAC5E,2EAA2E;AAC3E,oCAAoC;AAEpC,OAAO,EAAE,cAAc,EAAE,MAAM,4DAA4D,CAAC;AAC5F,OAAO,EAAgB,YAAY,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"bootstrap.js","sourceRoot":"","sources":["../src/local/bootstrap.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stigmer/cli",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.39.1-dev.20260928194002",
|
|
4
4
|
"description": "Stigmer command-line interface — manage agents, workflows, MCP servers, skills, and executions from the terminal",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -35,12 +35,12 @@
|
|
|
35
35
|
"@connectrpc/connect": "^2.0.0",
|
|
36
36
|
"@connectrpc/connect-node": "^2.1.1",
|
|
37
37
|
"@modelcontextprotocol/sdk": "^1.26.0",
|
|
38
|
-
"@stigmer/ink": "3.
|
|
39
|
-
"@stigmer/mcp-server": "3.
|
|
40
|
-
"@stigmer/plugin-package": "3.
|
|
41
|
-
"@stigmer/protos": "3.
|
|
42
|
-
"@stigmer/sdk": "3.
|
|
43
|
-
"@stigmer/zip-structure": "3.
|
|
38
|
+
"@stigmer/ink": "3.39.1-dev.20260928194002",
|
|
39
|
+
"@stigmer/mcp-server": "3.39.1-dev.20260928194002",
|
|
40
|
+
"@stigmer/plugin-package": "3.39.1-dev.20260928194002",
|
|
41
|
+
"@stigmer/protos": "3.39.1-dev.20260928194002",
|
|
42
|
+
"@stigmer/sdk": "3.39.1-dev.20260928194002",
|
|
43
|
+
"@stigmer/zip-structure": "3.39.1-dev.20260928194002",
|
|
44
44
|
"commander": "^12.1.0",
|
|
45
45
|
"fflate": "^0.8.3",
|
|
46
46
|
"ink": "^7.0.0",
|
|
@@ -7,11 +7,15 @@
|
|
|
7
7
|
// one instead (`stigmer config context set --org`) and needs no bootstrap.
|
|
8
8
|
//
|
|
9
9
|
// Flagless on purpose: the act is idempotent, so there is nothing to force;
|
|
10
|
-
// a second run changes nothing and says so. It never deletes anything.
|
|
10
|
+
// a second run changes nothing and says so. It never deletes anything. When
|
|
11
|
+
// the default organization was deleted, its slug is never reused and the
|
|
12
|
+
// backend cannot be made ready under it: the verb fails, naming how to
|
|
13
|
+
// choose another organization.
|
|
11
14
|
// Heavy modules load lazily inside the action so `--help` stays fast.
|
|
12
15
|
|
|
13
16
|
import type { Command } from "commander";
|
|
14
17
|
import { DEFAULT_LOCAL_ORG, ensureAuthenticated } from "../config/index.js";
|
|
18
|
+
import { CliExitError, ExitCode } from "../errors/index.js";
|
|
15
19
|
import { CommandResult, type OutputFlags, renderResult } from "../output/index.js";
|
|
16
20
|
import { addResultFlags, resultFormat } from "./shared.js";
|
|
17
21
|
|
|
@@ -26,7 +30,10 @@ export function registerBootstrap(program: Command): void {
|
|
|
26
30
|
}
|
|
27
31
|
|
|
28
32
|
async function runBootstrapCommand(flags: OutputFlags): Promise<void> {
|
|
29
|
-
const [
|
|
33
|
+
const [
|
|
34
|
+
{ connectBackend },
|
|
35
|
+
{ bootstrapBackend, RESERVED_DEFAULT_ORG_HINTS, RESERVED_DEFAULT_ORG_MESSAGE },
|
|
36
|
+
] = await Promise.all([
|
|
30
37
|
import("../backend.js"),
|
|
31
38
|
import("../local/bootstrap.js"),
|
|
32
39
|
]);
|
|
@@ -35,6 +42,9 @@ async function runBootstrapCommand(flags: OutputFlags): Promise<void> {
|
|
|
35
42
|
ensureAuthenticated(client.config);
|
|
36
43
|
|
|
37
44
|
const state = await bootstrapBackend(client.stigmer);
|
|
45
|
+
if (state === "reserved") {
|
|
46
|
+
throw new CliExitError(RESERVED_DEFAULT_ORG_MESSAGE, ExitCode.Usage, RESERVED_DEFAULT_ORG_HINTS);
|
|
47
|
+
}
|
|
38
48
|
|
|
39
49
|
const out = CommandResult.success("Backend is ready");
|
|
40
50
|
out.addSection("Organization").field("Slug", DEFAULT_LOCAL_ORG).field("State", state);
|
package/src/local/bootstrap.ts
CHANGED
|
@@ -13,6 +13,14 @@
|
|
|
13
13
|
// other refusal propagates with the server's sentence; the caller decides
|
|
14
14
|
// how loud to be.
|
|
15
15
|
//
|
|
16
|
+
// One `already-exists` is not that race. An organization's slug is never
|
|
17
|
+
// reused, so once `stigmer` has been deleted no create can take it again,
|
|
18
|
+
// and the server says so with the ORGANIZATION_SLUG_RESERVED reason. That
|
|
19
|
+
// is `reserved`: the default organization is gone for good, and the person
|
|
20
|
+
// must name another (RESERVED_DEFAULT_ORG_HINTS says how). Reporting it as
|
|
21
|
+
// `present` would leave every command that falls back to `stigmer` failing
|
|
22
|
+
// with no explanation.
|
|
23
|
+
//
|
|
16
24
|
// The create carries no label. Writing a label in the reserved `stigmer.ai/`
|
|
17
25
|
// namespace needs a platform permission that a self-hosted server with
|
|
18
26
|
// authentication on grants to nobody, and nothing reads one on an
|
|
@@ -29,14 +37,31 @@
|
|
|
29
37
|
// auth, the trusted-local identity.
|
|
30
38
|
|
|
31
39
|
import { ManagementMode } from "@stigmer/protos/ai/stigmer/tenancy/organization/v1/enum_pb";
|
|
32
|
-
import { type Stigmer, StigmerError } from "@stigmer/sdk";
|
|
40
|
+
import { getErrorReason, type Stigmer, StigmerError } from "@stigmer/sdk";
|
|
33
41
|
import type { BackendClient } from "../client/index.js";
|
|
34
42
|
import { DEFAULT_LOCAL_ORG } from "../config/resolve.js";
|
|
35
43
|
import { log } from "../logger.js";
|
|
36
44
|
|
|
37
45
|
export type Say = (line: string) => void;
|
|
38
46
|
|
|
39
|
-
export type BootstrapOutcome = "present" | "created";
|
|
47
|
+
export type BootstrapOutcome = "present" | "created" | "reserved";
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* The refusal reason of a create whose slug a deleted organization held
|
|
51
|
+
* (OrganizationCommandController.create's contract): a slug is never reused.
|
|
52
|
+
*/
|
|
53
|
+
const REASON_ORGANIZATION_SLUG_RESERVED = "ORGANIZATION_SLUG_RESERVED";
|
|
54
|
+
|
|
55
|
+
/** What the CLI says when the default organization was deleted and its slug is reserved. */
|
|
56
|
+
export const RESERVED_DEFAULT_ORG_MESSAGE = `The '${DEFAULT_LOCAL_ORG}' organization was deleted, and an organization's slug is never reused, so it cannot be created again.`;
|
|
57
|
+
|
|
58
|
+
/** How to choose another organization, in the order the CLI resolves one (config/resolve.ts). */
|
|
59
|
+
export const RESERVED_DEFAULT_ORG_HINTS: readonly string[] = [
|
|
60
|
+
"Name the organization to use, in any of these ways:",
|
|
61
|
+
" --org <slug> on a command",
|
|
62
|
+
" STIGMER_ORG_ID=<slug> in the environment",
|
|
63
|
+
" stigmer config context set --org <slug>",
|
|
64
|
+
];
|
|
40
65
|
|
|
41
66
|
/**
|
|
42
67
|
* Make sure the organization the CLI falls back to exists on the backend
|
|
@@ -61,7 +86,9 @@ export async function bootstrapBackend(stigmer: Stigmer): Promise<BootstrapOutco
|
|
|
61
86
|
return "created";
|
|
62
87
|
} catch (error) {
|
|
63
88
|
if (error instanceof StigmerError && error.code === "already-exists") {
|
|
64
|
-
return
|
|
89
|
+
return getErrorReason(error)?.reason === REASON_ORGANIZATION_SLUG_RESERVED
|
|
90
|
+
? "reserved"
|
|
91
|
+
: "present";
|
|
65
92
|
}
|
|
66
93
|
throw error;
|
|
67
94
|
}
|
|
@@ -93,6 +120,10 @@ export async function bootstrapLocalBackend(deps: BootstrapDeps = {}): Promise<v
|
|
|
93
120
|
}
|
|
94
121
|
log.debug("bootstrap complete", { org: outcome });
|
|
95
122
|
if (outcome === "created") say(`Created the '${DEFAULT_LOCAL_ORG}' organization`);
|
|
123
|
+
if (outcome === "reserved") {
|
|
124
|
+
say(`Warning: ${RESERVED_DEFAULT_ORG_MESSAGE}`);
|
|
125
|
+
for (const hint of RESERVED_DEFAULT_ORG_HINTS) say(hint);
|
|
126
|
+
}
|
|
96
127
|
}
|
|
97
128
|
|
|
98
129
|
async function freshLocalClient(): Promise<BackendClient> {
|