@treeseed/cli 0.9.0 → 0.10.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/dist/cli/handlers/capacity.js +273 -129
- package/dist/cli/handlers/dev.js +11 -35
- package/dist/cli/handlers/release.js +15 -0
- package/dist/cli/handlers/seed.js +66 -5
- package/dist/cli/operations-registry.js +40 -87
- package/dist/cli/parser.js +2 -2
- package/dist/cli/registry.d.ts +0 -2
- package/dist/cli/registry.js +0 -2
- package/dist/cli/runtime.js +1 -0
- package/package.json +2 -2
|
@@ -1,144 +1,288 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync } from "node:fs";
|
|
2
|
+
import { spawnSync } from "node:child_process";
|
|
3
|
+
import { resolve } from "node:path";
|
|
4
|
+
import { resolveCapacityProviderLaunchEnvironment } from "@treeseed/sdk/capacity-provider";
|
|
5
|
+
import { resolveMarketProfile } from "@treeseed/sdk/market-client";
|
|
6
|
+
import { findNearestTreeseedRoot, findNearestTreeseedWorkspaceRoot } from "@treeseed/sdk/workflow-support";
|
|
7
|
+
import { fail, guidedResult } from "./utils.js";
|
|
8
|
+
const ENTRYPOINT_RELATIVE_PATH = ["dist", "provider", "entrypoint.js"];
|
|
9
|
+
const COMPOSE_FILE_NAME = "compose.capacity-provider.yml";
|
|
10
|
+
const DEFAULT_PROJECT_NAME = "treeseed-capacity-provider";
|
|
11
|
+
const DEFAULT_HOST_DATA_DIR = ".treeseed/local-capacity-provider/data";
|
|
12
|
+
const PROVIDER_LIFECYCLE_ACTIONS = /* @__PURE__ */ new Set(["build", "up", "down", "restart", "logs", "status", "test-local"]);
|
|
13
|
+
const PROVIDER_ENTRYPOINT_ACTIONS = /* @__PURE__ */ new Set(["doctor", "register", "plan"]);
|
|
14
|
+
function stringArg(invocation, name) {
|
|
15
|
+
const value = invocation.args[name];
|
|
16
|
+
return typeof value === "string" && value.trim().length > 0 ? value.trim() : null;
|
|
17
|
+
}
|
|
18
|
+
function boolArg(invocation, name) {
|
|
19
|
+
return invocation.args[name] === true;
|
|
20
|
+
}
|
|
21
|
+
function readPackageName(packageRoot) {
|
|
22
|
+
const packageJsonPath = resolve(packageRoot, "package.json");
|
|
23
|
+
if (!existsSync(packageJsonPath)) return null;
|
|
24
|
+
try {
|
|
25
|
+
const parsed = JSON.parse(readFileSync(packageJsonPath, "utf8"));
|
|
26
|
+
return parsed.name ?? null;
|
|
27
|
+
} catch {
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
function agentEntrypoint(packageRoot) {
|
|
32
|
+
return resolve(packageRoot, ...ENTRYPOINT_RELATIVE_PATH);
|
|
33
|
+
}
|
|
34
|
+
function resolveAgentPackageRoot(invocation, context) {
|
|
35
|
+
const explicitRoot = stringArg(invocation, "agentPackageRoot");
|
|
36
|
+
if (explicitRoot) {
|
|
37
|
+
return resolve(context.cwd, explicitRoot);
|
|
38
|
+
}
|
|
39
|
+
if (readPackageName(context.cwd) === "@treeseed/agent") {
|
|
40
|
+
return context.cwd;
|
|
41
|
+
}
|
|
42
|
+
const workspaceRoot = findNearestTreeseedWorkspaceRoot(context.cwd);
|
|
43
|
+
const workspaceAgentRoot = workspaceRoot ? resolve(workspaceRoot, "packages", "agent") : null;
|
|
44
|
+
if (workspaceAgentRoot && existsSync(resolve(workspaceAgentRoot, "package.json"))) {
|
|
45
|
+
return workspaceAgentRoot;
|
|
46
|
+
}
|
|
47
|
+
const nearestProjectRoot = findNearestTreeseedRoot(context.cwd);
|
|
48
|
+
const projectAgentRoot = nearestProjectRoot ? resolve(nearestProjectRoot, "packages", "agent") : null;
|
|
49
|
+
if (projectAgentRoot && existsSync(resolve(projectAgentRoot, "package.json"))) {
|
|
50
|
+
return projectAgentRoot;
|
|
51
|
+
}
|
|
52
|
+
const installedRoot = resolve(context.cwd, "node_modules", "@treeseed", "agent");
|
|
53
|
+
if (existsSync(resolve(installedRoot, "package.json"))) {
|
|
54
|
+
return installedRoot;
|
|
55
|
+
}
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
function resolveAgentPackage(invocation, context, options = {}) {
|
|
59
|
+
const packageRoot = resolveAgentPackageRoot(invocation, context);
|
|
60
|
+
if (!packageRoot) {
|
|
61
|
+
throw new Error(
|
|
62
|
+
"Unable to locate @treeseed/agent. Build the workspace package, install @treeseed/agent, or pass --agent-package-root."
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
const entrypointPath = agentEntrypoint(packageRoot);
|
|
66
|
+
if (options.requireEntrypoint !== false && !existsSync(entrypointPath)) {
|
|
67
|
+
throw new Error(
|
|
68
|
+
`Missing provider runtime at ${entrypointPath}. Run npm -w packages/agent run build:dist or pass --agent-package-root to a built package.`
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
const composeFilePath = resolve(packageRoot, COMPOSE_FILE_NAME);
|
|
72
|
+
return { packageRoot, entrypointPath, composeFilePath };
|
|
73
|
+
}
|
|
74
|
+
function providerSelector(invocation) {
|
|
75
|
+
return stringArg(invocation, "provider") ?? "local";
|
|
76
|
+
}
|
|
77
|
+
function environmentSelector(invocation) {
|
|
78
|
+
return stringArg(invocation, "environment") ?? "local";
|
|
79
|
+
}
|
|
80
|
+
function resolveMarket(invocation) {
|
|
81
|
+
return resolveMarketProfile(stringArg(invocation, "market") ?? "local");
|
|
82
|
+
}
|
|
83
|
+
function resolveTenantRoot(context, agentPackageRoot) {
|
|
84
|
+
return findNearestTreeseedRoot(context.cwd) ?? (readPackageName(agentPackageRoot) === "@treeseed/agent" ? agentPackageRoot : context.cwd);
|
|
85
|
+
}
|
|
86
|
+
function defaultHostDataDir(context) {
|
|
87
|
+
const tenantRoot = findNearestTreeseedRoot(context.cwd) ?? context.cwd;
|
|
88
|
+
return resolve(tenantRoot, DEFAULT_HOST_DATA_DIR);
|
|
89
|
+
}
|
|
90
|
+
function providerProjectName(invocation) {
|
|
91
|
+
const provider = providerSelector(invocation).replace(/[^A-Za-z0-9_.-]+/gu, "-").replace(/^-+|-+$/gu, "") || "local";
|
|
92
|
+
return `${DEFAULT_PROJECT_NAME}-${provider}`;
|
|
93
|
+
}
|
|
94
|
+
function composeCommandArgs(composeFilePath, projectName, action) {
|
|
95
|
+
const base = ["compose", "-f", composeFilePath, "-p", projectName];
|
|
96
|
+
switch (action) {
|
|
97
|
+
case "up":
|
|
98
|
+
return [...base, "up", "-d"];
|
|
99
|
+
case "down":
|
|
100
|
+
return [...base, "down"];
|
|
101
|
+
case "restart":
|
|
102
|
+
return [...base, "restart"];
|
|
103
|
+
case "logs":
|
|
104
|
+
return [...base, "logs", "--tail", "200"];
|
|
105
|
+
case "status":
|
|
106
|
+
return [...base, "ps"];
|
|
107
|
+
default:
|
|
108
|
+
return base;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
function lifecycleActionRequiresConnection(action) {
|
|
112
|
+
return action === "up" || action === "restart";
|
|
113
|
+
}
|
|
114
|
+
function runLifecycleAction(action, invocation, context) {
|
|
115
|
+
const agentPackage = resolveAgentPackage(invocation, context, { requireEntrypoint: action !== "build" });
|
|
116
|
+
if (action !== "build" && action !== "test-local" && !existsSync(agentPackage.composeFilePath)) {
|
|
117
|
+
return fail(`Missing ${COMPOSE_FILE_NAME} in ${agentPackage.packageRoot}. Build or reinstall @treeseed/agent with Phase 3 container assets.`);
|
|
118
|
+
}
|
|
119
|
+
if (action === "build" || action === "test-local") {
|
|
120
|
+
const script = action === "build" ? "capacity-provider:build" : "capacity-provider:test-local";
|
|
121
|
+
const result2 = context.spawn("npm", ["run", script], {
|
|
122
|
+
cwd: agentPackage.packageRoot,
|
|
123
|
+
env: context.env,
|
|
124
|
+
stdio: "inherit"
|
|
125
|
+
});
|
|
15
126
|
return guidedResult({
|
|
16
|
-
command:
|
|
17
|
-
summary: "
|
|
127
|
+
command: `capacity ${action}`,
|
|
128
|
+
summary: result2.status === 0 ? `Capacity provider ${action === "build" ? "image build" : "container smoke test"} completed.` : `Capacity provider ${action === "build" ? "image build" : "container smoke test"} failed.`,
|
|
18
129
|
facts: [
|
|
19
|
-
{ label: "
|
|
20
|
-
{ label: "
|
|
21
|
-
{ label: "
|
|
22
|
-
{ label: "Daily remaining", value: summary?.dailyRemainingCredits },
|
|
23
|
-
{ label: "Active providers", value: summary?.activeProviderCount }
|
|
130
|
+
{ label: "Agent package", value: agentPackage.packageRoot },
|
|
131
|
+
{ label: "Script", value: script },
|
|
132
|
+
{ label: "Exit code", value: result2.status ?? 1 }
|
|
24
133
|
],
|
|
25
|
-
|
|
134
|
+
exitCode: result2.status ?? 1,
|
|
135
|
+
report: {
|
|
136
|
+
action,
|
|
137
|
+
agentPackageRoot: agentPackage.packageRoot,
|
|
138
|
+
script
|
|
139
|
+
}
|
|
26
140
|
});
|
|
27
141
|
}
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
const response = await client.launchManagedCapacityProvider(team, { launchSource: "cli" });
|
|
46
|
-
return guidedResult({
|
|
47
|
-
command: "capacity",
|
|
48
|
-
summary: "TreeSeed-managed helper capacity is connected.",
|
|
49
|
-
facts: [
|
|
50
|
-
{ label: "Provider", value: response.payload.provider?.id },
|
|
51
|
-
{ label: "Security code prefix", value: response.payload.apiKey?.keyPrefix }
|
|
52
|
-
],
|
|
53
|
-
report: { marketId: profile.id, teamId: team, result: response.payload }
|
|
54
|
-
});
|
|
142
|
+
const diagnostic = boolArg(invocation, "diagnostic") || action === "test-local";
|
|
143
|
+
const market = resolveMarket(invocation);
|
|
144
|
+
const hostDataDirInput = stringArg(invocation, "dataDir") ?? context.env.TREESEED_PROVIDER_HOST_DATA_DIR ?? defaultHostDataDir(context);
|
|
145
|
+
const resolvedHostDataDir = resolve(context.cwd, hostDataDirInput);
|
|
146
|
+
const tenantRoot = resolveTenantRoot(context, agentPackage.packageRoot);
|
|
147
|
+
const launch = resolveCapacityProviderLaunchEnvironment({
|
|
148
|
+
tenantRoot,
|
|
149
|
+
scope: environmentSelector(invocation),
|
|
150
|
+
env: context.env,
|
|
151
|
+
diagnostic,
|
|
152
|
+
requireConnection: lifecycleActionRequiresConnection(action),
|
|
153
|
+
overrides: {
|
|
154
|
+
TREESEED_MARKET_URL: market.baseUrl,
|
|
155
|
+
TREESEED_MARKET_ID: market.id,
|
|
156
|
+
TREESEED_PROVIDER_HOST_DATA_DIR: resolvedHostDataDir,
|
|
157
|
+
TREESEED_PROVIDER_ENVIRONMENT: providerSelector(invocation),
|
|
158
|
+
...diagnostic ? { TREESEED_PROVIDER_STARTUP_MODE: "diagnostic" } : {}
|
|
55
159
|
}
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
160
|
+
});
|
|
161
|
+
const hostDataDir = resolvedHostDataDir;
|
|
162
|
+
mkdirSync(hostDataDir, { recursive: true });
|
|
163
|
+
const projectName = providerProjectName(invocation);
|
|
164
|
+
const args = composeCommandArgs(agentPackage.composeFilePath, projectName, action);
|
|
165
|
+
const result = context.spawn("docker", args, {
|
|
166
|
+
cwd: agentPackage.packageRoot,
|
|
167
|
+
env: {
|
|
168
|
+
...context.env,
|
|
169
|
+
...launch.env
|
|
170
|
+
},
|
|
171
|
+
stdio: "inherit"
|
|
172
|
+
});
|
|
173
|
+
return guidedResult({
|
|
174
|
+
command: `capacity ${action}`,
|
|
175
|
+
summary: result.status === 0 ? `Capacity provider ${action} completed${diagnostic ? " in diagnostic mode" : ""}.` : `Capacity provider ${action} failed.`,
|
|
176
|
+
facts: [
|
|
177
|
+
{ label: "Market", value: `${market.id} (${market.baseUrl})` },
|
|
178
|
+
{ label: "Provider", value: providerSelector(invocation) },
|
|
179
|
+
{ label: "Mode", value: diagnostic ? "diagnostic" : "live" },
|
|
180
|
+
{ label: "Compose project", value: projectName },
|
|
181
|
+
{ label: "Agent package", value: agentPackage.packageRoot },
|
|
182
|
+
{ label: "Data directory", value: hostDataDir },
|
|
183
|
+
{ label: "Exit code", value: result.status ?? 1 }
|
|
184
|
+
],
|
|
185
|
+
sections: [
|
|
186
|
+
{
|
|
187
|
+
title: "Environment",
|
|
188
|
+
lines: Object.entries(launch.redactedEnv).sort(([left], [right]) => left.localeCompare(right)).map(([key, value]) => `${key}=${value}`)
|
|
84
189
|
}
|
|
190
|
+
],
|
|
191
|
+
exitCode: result.status ?? 1,
|
|
192
|
+
report: {
|
|
193
|
+
action,
|
|
194
|
+
agentPackageRoot: agentPackage.packageRoot,
|
|
195
|
+
composeFile: agentPackage.composeFilePath,
|
|
196
|
+
composeProject: projectName,
|
|
197
|
+
market: { id: market.id, baseUrl: market.baseUrl },
|
|
198
|
+
provider: providerSelector(invocation),
|
|
199
|
+
diagnostic,
|
|
200
|
+
redactedEnv: launch.redactedEnv
|
|
85
201
|
}
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
function invokeProviderEntrypoint(action, invocation, context) {
|
|
205
|
+
const agentPackage = resolveAgentPackage(invocation, context);
|
|
206
|
+
const market = resolveMarket(invocation);
|
|
207
|
+
const args = [agentPackage.entrypointPath, action, "--market", market.id, "--provider", providerSelector(invocation)];
|
|
208
|
+
if (boolArg(invocation, "dryRun") || action === "doctor" || action === "plan") {
|
|
209
|
+
args.push("--dry-run");
|
|
210
|
+
}
|
|
211
|
+
if (context.outputFormat === "json" || boolArg(invocation, "json")) {
|
|
212
|
+
args.push("--json");
|
|
213
|
+
}
|
|
214
|
+
const result = spawnSync(process.execPath, args, {
|
|
215
|
+
cwd: agentPackage.packageRoot,
|
|
216
|
+
env: {
|
|
217
|
+
...context.env,
|
|
218
|
+
TREESEED_MARKET_URL: market.baseUrl,
|
|
219
|
+
TREESEED_MARKET_ID: market.id,
|
|
220
|
+
TREESEED_PROVIDER_ENVIRONMENT: providerSelector(invocation)
|
|
221
|
+
},
|
|
222
|
+
encoding: "utf8"
|
|
223
|
+
});
|
|
224
|
+
const stdout = result.stdout.trim();
|
|
225
|
+
const stderr = result.stderr.trim();
|
|
226
|
+
let report = null;
|
|
227
|
+
if (stdout.startsWith("{")) {
|
|
228
|
+
try {
|
|
229
|
+
report = JSON.parse(stdout);
|
|
230
|
+
} catch {
|
|
231
|
+
report = null;
|
|
102
232
|
}
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
233
|
+
}
|
|
234
|
+
if (context.outputFormat === "json") {
|
|
235
|
+
return {
|
|
236
|
+
exitCode: result.status ?? 1,
|
|
237
|
+
stdout: stdout ? [stdout] : [],
|
|
238
|
+
stderr: stderr ? [stderr] : [],
|
|
239
|
+
report: report ?? {
|
|
240
|
+
ok: result.status === 0,
|
|
241
|
+
action,
|
|
242
|
+
stdout,
|
|
243
|
+
stderr,
|
|
244
|
+
agentPackageRoot: agentPackage.packageRoot
|
|
245
|
+
}
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
return guidedResult({
|
|
249
|
+
command: `capacity ${action}`,
|
|
250
|
+
summary: result.status === 0 ? `Capacity provider ${action} completed.` : `Capacity provider ${action} failed.`,
|
|
251
|
+
facts: [
|
|
252
|
+
{ label: "Market", value: `${market.id} (${market.baseUrl})` },
|
|
253
|
+
{ label: "Provider", value: providerSelector(invocation) },
|
|
254
|
+
{ label: "Agent package", value: agentPackage.packageRoot },
|
|
255
|
+
{ label: "Exit code", value: result.status ?? 1 }
|
|
256
|
+
],
|
|
257
|
+
sections: [
|
|
258
|
+
{ title: "Output", lines: stdout ? stdout.split(/\r?\n/u) : [] },
|
|
259
|
+
{ title: "Errors", lines: stderr ? stderr.split(/\r?\n/u) : [] }
|
|
260
|
+
],
|
|
261
|
+
exitCode: result.status ?? 1,
|
|
262
|
+
report: report ?? {
|
|
263
|
+
ok: result.status === 0,
|
|
264
|
+
action,
|
|
265
|
+
agentPackageRoot: agentPackage.packageRoot
|
|
266
|
+
}
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
const handleCapacity = (invocation, context) => {
|
|
270
|
+
const action = invocation.positionals[0] ?? "doctor";
|
|
271
|
+
if (PROVIDER_LIFECYCLE_ACTIONS.has(action)) {
|
|
272
|
+
try {
|
|
273
|
+
return runLifecycleAction(action, invocation, context);
|
|
274
|
+
} catch (error) {
|
|
275
|
+
return fail(error instanceof Error ? error.message : String(error));
|
|
122
276
|
}
|
|
123
|
-
return { exitCode: 1, stderr: [`Unknown capacity grants action: ${subcommand}`] };
|
|
124
277
|
}
|
|
125
|
-
if (action
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
}
|
|
131
|
-
return guidedResult({
|
|
132
|
-
command: "capacity",
|
|
133
|
-
summary: "Budgeted agent task enqueued.",
|
|
134
|
-
facts: [
|
|
135
|
-
{ label: "Task", value: response.payload.task?.id },
|
|
136
|
-
{ label: "Reserved credits", value: response.payload.reservation?.reservedCredits }
|
|
137
|
-
],
|
|
138
|
-
report: { marketId: profile.id, projectId, result: response.payload }
|
|
139
|
-
});
|
|
278
|
+
if (PROVIDER_ENTRYPOINT_ACTIONS.has(action)) {
|
|
279
|
+
try {
|
|
280
|
+
return invokeProviderEntrypoint(action, invocation, context);
|
|
281
|
+
} catch (error) {
|
|
282
|
+
return fail(error instanceof Error ? error.message : String(error));
|
|
283
|
+
}
|
|
140
284
|
}
|
|
141
|
-
return
|
|
285
|
+
return fail(`Unknown capacity action "${action}". Use doctor, register, plan, build, up, down, restart, logs, status, or test-local.`);
|
|
142
286
|
};
|
|
143
287
|
export {
|
|
144
288
|
handleCapacity
|
package/dist/cli/handlers/dev.js
CHANGED
|
@@ -3,6 +3,7 @@ import { createRequire } from "node:module";
|
|
|
3
3
|
import { dirname, resolve } from "node:path";
|
|
4
4
|
import { ensureLocalWorkspaceLinks, findNearestTreeseedWorkspaceRoot, resolveTreeseedLaunchEnvironment } from "@treeseed/sdk/workflow-support";
|
|
5
5
|
import { workflowErrorResult } from "./workflow.js";
|
|
6
|
+
import { fail } from "./utils.js";
|
|
6
7
|
const require2 = createRequire(import.meta.url);
|
|
7
8
|
function resolveCoreDevEntrypoint(cwd) {
|
|
8
9
|
const workspacePackageJsonPath = resolve(cwd, "packages", "core", "package.json");
|
|
@@ -42,10 +43,16 @@ function resolveCoreDevEntrypoint(cwd) {
|
|
|
42
43
|
}
|
|
43
44
|
const handleDev = async (invocation, context) => {
|
|
44
45
|
try {
|
|
45
|
-
|
|
46
|
+
if (invocation.commandName !== "dev") {
|
|
47
|
+
return fail("`trsd dev` only starts the Market web/API dev runtime. Use `trsd capacity ...` for capacity provider lifecycle commands.");
|
|
48
|
+
}
|
|
49
|
+
const removedOptions = ["surface", "surfaces", "withWorker"].filter((name) => invocation.args[name] !== void 0);
|
|
50
|
+
if (removedOptions.length > 0) {
|
|
51
|
+
return fail(`\`trsd dev\` no longer accepts ${removedOptions.map((name) => `--${name.replace(/[A-Z]/gu, (char) => `-${char.toLowerCase()}`)}`).join(", ")}. It always starts fixed Market web/API surfaces; use \`trsd capacity ...\` for providers.`);
|
|
52
|
+
}
|
|
46
53
|
const feedback = typeof invocation.args.feedback === "string" ? invocation.args.feedback : void 0;
|
|
47
54
|
const watch = feedback !== "off";
|
|
48
|
-
const passthroughArgs = [];
|
|
55
|
+
const passthroughArgs = ["--surfaces", "web,api"];
|
|
49
56
|
const forwardStringOption = (name, flag) => {
|
|
50
57
|
const value = invocation.args[name];
|
|
51
58
|
if (typeof value === "string" && value.trim().length > 0) {
|
|
@@ -57,20 +64,11 @@ const handleDev = async (invocation, context) => {
|
|
|
57
64
|
passthroughArgs.push(flag);
|
|
58
65
|
}
|
|
59
66
|
};
|
|
60
|
-
if (managerMode) {
|
|
61
|
-
const explicitSurfaces = typeof invocation.args.surfaces === "string" && invocation.args.surfaces.trim() ? invocation.args.surfaces.trim() : typeof invocation.args.surface === "string" && invocation.args.surface.trim() ? invocation.args.surface.trim() : null;
|
|
62
|
-
const surfaces = explicitSurfaces ?? (invocation.args.withWorker === true ? "manager,worker" : "manager");
|
|
63
|
-
passthroughArgs.push("--surfaces", surfaces);
|
|
64
|
-
} else {
|
|
65
|
-
forwardStringOption("surface", "--surface");
|
|
66
|
-
forwardStringOption("surfaces", "--surfaces");
|
|
67
|
-
}
|
|
68
67
|
forwardStringOption("host", "--host");
|
|
69
68
|
forwardStringOption("port", "--port");
|
|
70
69
|
forwardStringOption("webRuntime", "--web-runtime");
|
|
71
70
|
forwardStringOption("apiHost", "--api-host");
|
|
72
71
|
forwardStringOption("apiPort", "--api-port");
|
|
73
|
-
forwardStringOption("managerPort", "--manager-port");
|
|
74
72
|
forwardStringOption("setup", "--setup");
|
|
75
73
|
forwardStringOption("feedback", "--feedback");
|
|
76
74
|
forwardStringOption("open", "--open");
|
|
@@ -78,21 +76,6 @@ const handleDev = async (invocation, context) => {
|
|
|
78
76
|
forwardBooleanOption("reset", "--reset");
|
|
79
77
|
forwardBooleanOption("force", "--force");
|
|
80
78
|
forwardBooleanOption("json", "--json");
|
|
81
|
-
const docsAutomationMode = typeof invocation.args.docsAutomation === "string" ? invocation.args.docsAutomation.trim() : "";
|
|
82
|
-
const workdayId = typeof invocation.args.workdayId === "string" ? invocation.args.workdayId.trim() : "";
|
|
83
|
-
const capacityBudget = typeof invocation.args.capacityBudget === "string" ? invocation.args.capacityBudget.trim() : "";
|
|
84
|
-
const approvalPolicy = typeof invocation.args.approvalPolicy === "string" ? invocation.args.approvalPolicy.trim() : "";
|
|
85
|
-
const devManagerEnv = managerMode ? {
|
|
86
|
-
TREESEED_DOCS_AUTOMATION_MODE: docsAutomationMode || "on",
|
|
87
|
-
...workdayId ? { TREESEED_WORKDAY_ID: workdayId } : {},
|
|
88
|
-
...capacityBudget ? {
|
|
89
|
-
TREESEED_CAPACITY_BUDGET: capacityBudget,
|
|
90
|
-
TREESEED_WORKDAY_TASK_CREDIT_BUDGET: capacityBudget
|
|
91
|
-
} : {},
|
|
92
|
-
TREESEED_APPROVAL_POLICY: approvalPolicy || "manual",
|
|
93
|
-
TREESEED_MANAGER_CONSOLE_SUMMARY: "true",
|
|
94
|
-
TREESEED_WORKER_CONSOLE_SUMMARY: "true"
|
|
95
|
-
} : {};
|
|
96
79
|
const workspaceRoot = findNearestTreeseedWorkspaceRoot(context.cwd);
|
|
97
80
|
const workspaceLinksMode = typeof invocation.args.workspaceLinks === "string" ? invocation.args.workspaceLinks : void 0;
|
|
98
81
|
const workspaceLinks = workspaceRoot ? ensureLocalWorkspaceLinks(workspaceRoot, { env: context.env, mode: workspaceLinksMode }) : null;
|
|
@@ -107,7 +90,7 @@ const handleDev = async (invocation, context) => {
|
|
|
107
90
|
tenantRoot: context.cwd,
|
|
108
91
|
scope: "local",
|
|
109
92
|
baseEnv: { ...process.env, ...context.env ?? {} },
|
|
110
|
-
overrides:
|
|
93
|
+
overrides: {}
|
|
111
94
|
}),
|
|
112
95
|
stdio: "inherit"
|
|
113
96
|
});
|
|
@@ -116,18 +99,11 @@ const handleDev = async (invocation, context) => {
|
|
|
116
99
|
suppressJsonResult: invocation.args.json === true,
|
|
117
100
|
report: {
|
|
118
101
|
command: "dev",
|
|
119
|
-
alias:
|
|
102
|
+
alias: invocation.commandName,
|
|
120
103
|
ok: (result.status ?? 1) === 0,
|
|
121
104
|
watch,
|
|
122
105
|
executable: resolved.command,
|
|
123
106
|
args,
|
|
124
|
-
docsAutomation: managerMode ? {
|
|
125
|
-
mode: docsAutomationMode || "on",
|
|
126
|
-
workdayId: workdayId || null,
|
|
127
|
-
capacityBudget: capacityBudget || null,
|
|
128
|
-
approvalPolicy: approvalPolicy || "manual",
|
|
129
|
-
withWorker: invocation.args.withWorker === true
|
|
130
|
-
} : void 0,
|
|
131
107
|
workspaceLinks
|
|
132
108
|
}
|
|
133
109
|
};
|
|
@@ -21,6 +21,17 @@ function formatReleasePlanSections(payload) {
|
|
|
21
21
|
lines: versions.map(([name, version]) => `- ${name}: ${version}`)
|
|
22
22
|
});
|
|
23
23
|
}
|
|
24
|
+
if (payload.releaseLine) {
|
|
25
|
+
sections.push({
|
|
26
|
+
title: "Release line",
|
|
27
|
+
lines: [
|
|
28
|
+
`Target: ${String(payload.releaseLine.targetLine ?? "unknown")}`,
|
|
29
|
+
`Highest current: ${String(payload.releaseLine.highestCurrentLine ?? "unknown")}`,
|
|
30
|
+
`Repair: ${payload.releaseLine.repair === true ? "yes" : "no"}`,
|
|
31
|
+
`Aligned before: ${payload.releaseLine.alignedBefore === true ? "yes" : "no"}`
|
|
32
|
+
]
|
|
33
|
+
});
|
|
34
|
+
}
|
|
24
35
|
const rewrites = payload.plannedDevReferenceRewrites ?? [];
|
|
25
36
|
if (rewrites.length > 0) {
|
|
26
37
|
sections.push({
|
|
@@ -55,9 +66,12 @@ function formatReleasePlanSections(payload) {
|
|
|
55
66
|
}
|
|
56
67
|
const handleRelease = async (invocation, context) => {
|
|
57
68
|
try {
|
|
69
|
+
const repairVersionLine = invocation.args.repairVersionLine === true;
|
|
58
70
|
const bump = ["major", "minor", "patch"].find((candidate) => invocation.args[candidate] === true) ?? "patch";
|
|
59
71
|
const result = await createWorkflowSdk(context).release({
|
|
60
72
|
bump,
|
|
73
|
+
repairVersionLine,
|
|
74
|
+
targetVersionLine: typeof invocation.args.targetVersionLine === "string" ? invocation.args.targetVersionLine : void 0,
|
|
61
75
|
worktreeMode: typeof invocation.args.worktreeMode === "string" ? invocation.args.worktreeMode : void 0,
|
|
62
76
|
ciMode: typeof invocation.args.ciMode === "string" ? invocation.args.ciMode : void 0,
|
|
63
77
|
workspaceLinks: typeof invocation.args.workspaceLinks === "string" ? invocation.args.workspaceLinks : void 0,
|
|
@@ -79,6 +93,7 @@ const handleRelease = async (invocation, context) => {
|
|
|
79
93
|
{ label: "Production branch", value: payload.productionBranch },
|
|
80
94
|
{ label: "Merge strategy", value: payload.mergeStrategy },
|
|
81
95
|
{ label: "Release level", value: payload.level },
|
|
96
|
+
{ label: "Release line", value: String(payload.releaseLine?.targetLine ?? "(none)") },
|
|
82
97
|
{ label: "Root version", value: payload.rootVersion ?? payload.plannedVersions?.["@treeseed/market"] ?? "(planned)" },
|
|
83
98
|
{ label: "Release tag", value: payload.releaseTag ?? payload.rootVersion ?? payload.plannedVersions?.["@treeseed/market"] ?? "(planned)" },
|
|
84
99
|
{ label: "Released commit", value: releasedCommit },
|
|
@@ -2,6 +2,7 @@ import { pathToFileURL } from "node:url";
|
|
|
2
2
|
import { dirname, resolve } from "node:path";
|
|
3
3
|
import { existsSync, mkdirSync, writeFileSync } from "node:fs";
|
|
4
4
|
import { formatSeedDiagnostics, formatSeedPlan, loadAndPlanSeed } from "@treeseed/sdk/seeds";
|
|
5
|
+
import { persistCapacityProviderConnectionToTreeseedConfig } from "@treeseed/sdk/capacity-provider";
|
|
5
6
|
import { MarketApiError } from "@treeseed/sdk/market-client";
|
|
6
7
|
import { createMarketClientForInvocation, marketAuthRoot, marketSelector } from "./market-utils.js";
|
|
7
8
|
import { MarketClient, resolveMarketProfile, resolveMarketSession, setMarketSession } from "@treeseed/sdk/market-client";
|
|
@@ -105,11 +106,44 @@ function formatCapacityProviderKeyNotes(result) {
|
|
|
105
106
|
if (created.length === 0) return [];
|
|
106
107
|
return [
|
|
107
108
|
"",
|
|
108
|
-
"Provider
|
|
109
|
-
...created.map((entry) => ` ${String(entry.providerName ?? entry.providerKey ?? entry.providerId)} (${String(entry.keyPrefix ?? "new key")}):
|
|
110
|
-
"
|
|
109
|
+
"Provider connection:",
|
|
110
|
+
...created.map((entry) => ` ${String(entry.providerName ?? entry.providerKey ?? entry.providerId)} (${String(entry.keyPrefix ?? "new key")}): stored in encrypted Treeseed config`),
|
|
111
|
+
" Use `treeseed capacity up --market local --provider local` to launch the provider."
|
|
111
112
|
];
|
|
112
113
|
}
|
|
114
|
+
function redactLocalCapacityProviderKeys(result) {
|
|
115
|
+
const capacityProviderKeys = result.capacityProviderKeys && typeof result.capacityProviderKeys === "object" ? result.capacityProviderKeys : null;
|
|
116
|
+
if (!capacityProviderKeys) return result;
|
|
117
|
+
return {
|
|
118
|
+
...result,
|
|
119
|
+
capacityProviderKeys: {
|
|
120
|
+
...capacityProviderKeys,
|
|
121
|
+
created: Array.isArray(capacityProviderKeys.created) ? capacityProviderKeys.created.map((entry) => {
|
|
122
|
+
if (!entry || typeof entry !== "object") return entry;
|
|
123
|
+
const { plaintextKey: _plaintextKey, ...safeEntry } = entry;
|
|
124
|
+
return {
|
|
125
|
+
...safeEntry,
|
|
126
|
+
storedInTreeseedConfig: true
|
|
127
|
+
};
|
|
128
|
+
}) : []
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
function storeLocalCapacityProviderConnection(input) {
|
|
133
|
+
const capacityProviderKeys = input.result.capacityProviderKeys && typeof input.result.capacityProviderKeys === "object" ? input.result.capacityProviderKeys : null;
|
|
134
|
+
const created = Array.isArray(capacityProviderKeys?.created) ? capacityProviderKeys.created : [];
|
|
135
|
+
const first = created.find((entry) => typeof entry.plaintextKey === "string" && String(entry.plaintextKey).length > 0);
|
|
136
|
+
if (!first) return null;
|
|
137
|
+
return persistCapacityProviderConnectionToTreeseedConfig({
|
|
138
|
+
tenantRoot: input.context.cwd,
|
|
139
|
+
scope: "local",
|
|
140
|
+
marketUrl: input.profile.baseUrl,
|
|
141
|
+
marketId: input.profile.id,
|
|
142
|
+
apiKey: String(first.plaintextKey),
|
|
143
|
+
providerHostDataDir: ".treeseed/local-capacity-provider/data",
|
|
144
|
+
providerEnvironment: "local"
|
|
145
|
+
});
|
|
146
|
+
}
|
|
113
147
|
function remoteSeedError(error, command) {
|
|
114
148
|
if (error instanceof MarketApiError) {
|
|
115
149
|
const payload = error.payload && typeof error.payload === "object" ? error.payload : { error: error.message };
|
|
@@ -293,6 +327,26 @@ const handleSeed = async (invocation, context) => {
|
|
|
293
327
|
accessToken: localAuth?.session.accessToken,
|
|
294
328
|
env: context.env
|
|
295
329
|
});
|
|
330
|
+
let providerConnection = null;
|
|
331
|
+
try {
|
|
332
|
+
providerConnection = storeLocalCapacityProviderConnection({
|
|
333
|
+
context,
|
|
334
|
+
profile: localAuth.profile,
|
|
335
|
+
result: applied.result
|
|
336
|
+
});
|
|
337
|
+
} catch (error) {
|
|
338
|
+
const message2 = `Unable to store local capacity provider connection in encrypted Treeseed config. ${error instanceof Error ? error.message : String(error)}`;
|
|
339
|
+
return {
|
|
340
|
+
exitCode: 4,
|
|
341
|
+
stderr: [message2],
|
|
342
|
+
report: {
|
|
343
|
+
command: "seed",
|
|
344
|
+
ok: false,
|
|
345
|
+
error: message2
|
|
346
|
+
}
|
|
347
|
+
};
|
|
348
|
+
}
|
|
349
|
+
const safeResult = redactLocalCapacityProviderKeys(applied.result);
|
|
296
350
|
const message = "Local seed apply completed.";
|
|
297
351
|
return {
|
|
298
352
|
exitCode: 0,
|
|
@@ -305,7 +359,7 @@ const handleSeed = async (invocation, context) => {
|
|
|
305
359
|
` unchanged: ${applied.plan.summary.unchanged}`,
|
|
306
360
|
` skipped: ${applied.plan.summary.skip}`,
|
|
307
361
|
` failed: ${applied.plan.summary.error}`,
|
|
308
|
-
...formatCapacityProviderKeyNotes(
|
|
362
|
+
...formatCapacityProviderKeyNotes(safeResult)
|
|
309
363
|
],
|
|
310
364
|
report: {
|
|
311
365
|
...applied.plan,
|
|
@@ -313,7 +367,14 @@ const handleSeed = async (invocation, context) => {
|
|
|
313
367
|
command: "seed",
|
|
314
368
|
result: {
|
|
315
369
|
message,
|
|
316
|
-
...
|
|
370
|
+
...safeResult,
|
|
371
|
+
...providerConnection ? {
|
|
372
|
+
capacityProviderConnection: {
|
|
373
|
+
scope: providerConnection.scope,
|
|
374
|
+
writtenKeys: providerConnection.writtenKeys,
|
|
375
|
+
redactedEnv: providerConnection.redactedEnv
|
|
376
|
+
}
|
|
377
|
+
} : {}
|
|
317
378
|
}
|
|
318
379
|
}
|
|
319
380
|
};
|
|
@@ -21,14 +21,11 @@ function related(name, why) {
|
|
|
21
21
|
return { name, why };
|
|
22
22
|
}
|
|
23
23
|
const DEV_RUNTIME_OPTIONS = [
|
|
24
|
-
{ name: "surface", flags: "--surface <surface>", description: "Select one local dev surface to run. Compatibility alias for --surfaces.", kind: "enum", values: ["integrated", "web", "api", "manager", "worker", "agents", "services"] },
|
|
25
|
-
{ name: "surfaces", flags: "--surfaces <surfaces>", description: "Select comma-separated local dev surfaces to run.", kind: "string" },
|
|
26
24
|
{ name: "host", flags: "--host <host>", description: "Host for the web dev server.", kind: "string" },
|
|
27
25
|
{ name: "port", flags: "--port <port>", description: "Port for the web dev server.", kind: "string" },
|
|
28
26
|
{ name: "webRuntime", flags: "--web-runtime <mode>", description: "Choose the local web runtime. Use local for Astro hot reload or provider for provider parity.", kind: "enum", values: ["auto", "local", "provider"] },
|
|
29
27
|
{ name: "apiHost", flags: "--api-host <host>", description: "Host used to construct the local API URL.", kind: "string" },
|
|
30
28
|
{ name: "apiPort", flags: "--api-port <port>", description: "Port for the local API server.", kind: "string" },
|
|
31
|
-
{ name: "managerPort", flags: "--manager-port <port>", description: "Port used for the local manager service URL.", kind: "string" },
|
|
32
29
|
{ name: "setup", flags: "--setup <mode>", description: "Control automatic local runtime setup.", kind: "enum", values: ["auto", "check", "off"] },
|
|
33
30
|
{ name: "feedback", flags: "--feedback <mode>", description: "Control live feedback, service restarts, and browser reload stamps.", kind: "enum", values: ["live", "restart", "off"] },
|
|
34
31
|
{ name: "open", flags: "--open <mode>", description: "Control whether dev opens the browser after readiness. Defaults to off; use --open on to launch it.", kind: "enum", values: ["auto", "on", "off"] },
|
|
@@ -36,17 +33,8 @@ const DEV_RUNTIME_OPTIONS = [
|
|
|
36
33
|
{ name: "reset", flags: "--reset", description: "Clear local dev runtime state before setup, migrations, and service startup.", kind: "boolean" },
|
|
37
34
|
{ name: "force", flags: "--force", description: "Terminate overlapping Treeseed dev runtimes and listeners on required local dev ports before startup.", kind: "boolean" },
|
|
38
35
|
{ name: "json", flags: "--json", description: "Emit structured JSON or newline-delimited dev events.", kind: "boolean" },
|
|
39
|
-
{ name: "watch", flags: "--watch", description: "Enable live watch behavior. `dev` defaults to live feedback; this remains for compatibility.", kind: "boolean" },
|
|
40
36
|
{ name: "workspaceLinks", flags: "--workspace-links <mode>", description: "Control local workspace package links.", kind: "enum", values: ["auto", "off"] }
|
|
41
37
|
];
|
|
42
|
-
const DEV_MANAGER_OPTIONS = [
|
|
43
|
-
...DEV_RUNTIME_OPTIONS,
|
|
44
|
-
{ name: "docsAutomation", flags: "--docs-automation <mode>", description: "Control governed documentation automation for the local manager.", kind: "enum", values: ["on", "dry-run", "off"] },
|
|
45
|
-
{ name: "withWorker", flags: "--with-worker", description: "Run the local worker alongside the manager in the same dev supervisor.", kind: "boolean" },
|
|
46
|
-
{ name: "workdayId", flags: "--workday-id <id>", description: "Start or resume a specific local documentation automation workday.", kind: "string" },
|
|
47
|
-
{ name: "capacityBudget", flags: "--capacity-budget <credits>", description: "Override the local workday task credit budget.", kind: "string" },
|
|
48
|
-
{ name: "approvalPolicy", flags: "--approval-policy <policy>", description: "Set the local docs automation approval policy.", kind: "enum", values: ["manual", "low-risk-auto"] }
|
|
49
|
-
];
|
|
50
38
|
function genericWorkflowPosition(spec) {
|
|
51
39
|
if (spec.group === "Workflow") {
|
|
52
40
|
if (spec.name === "switch") return "start work";
|
|
@@ -1075,11 +1063,13 @@ const CLI_COMMAND_OVERLAYS = /* @__PURE__ */ new Map([
|
|
|
1075
1063
|
handlerName: "export"
|
|
1076
1064
|
})],
|
|
1077
1065
|
["release", command({
|
|
1078
|
-
usage: "treeseed release --major|--minor|--patch",
|
|
1066
|
+
usage: "treeseed release --major|--minor|--patch|--repair-version-line",
|
|
1079
1067
|
options: [
|
|
1080
1068
|
{ name: "major", flags: "--major", description: "Bump to the next major version.", kind: "boolean" },
|
|
1081
1069
|
{ name: "minor", flags: "--minor", description: "Bump to the next minor version.", kind: "boolean" },
|
|
1082
1070
|
{ name: "patch", flags: "--patch", description: "Bump to the next patch version.", kind: "boolean" },
|
|
1071
|
+
{ name: "repairVersionLine", flags: "--repair-version-line", description: "Repair public package major.minor drift without enforcing patch parity.", kind: "boolean" },
|
|
1072
|
+
{ name: "targetVersionLine", flags: "--target-version-line <major.minor>", description: "Target release line for --repair-version-line, for example 0.10.", kind: "string" },
|
|
1083
1073
|
{ name: "worktreeMode", flags: "--worktree <mode>", description: "Control managed workflow worktrees.", kind: "enum", values: ["auto", "on", "off"] },
|
|
1084
1074
|
{ name: "ciMode", flags: "--ci <mode>", description: "Control hosted GitHub Actions waits.", kind: "enum", values: ["auto", "hosted", "off"] },
|
|
1085
1075
|
{ name: "workspaceLinks", flags: "--workspace-links <mode>", description: "Control local workspace package links.", kind: "enum", values: ["auto", "off"] },
|
|
@@ -1088,8 +1078,8 @@ const CLI_COMMAND_OVERLAYS = /* @__PURE__ */ new Map([
|
|
|
1088
1078
|
{ name: "dryRun", flags: "--dry-run", description: "Alias for --plan.", kind: "boolean" },
|
|
1089
1079
|
{ name: "json", flags: "--json", description: "Emit machine-readable JSON instead of human-readable text.", kind: "boolean" }
|
|
1090
1080
|
],
|
|
1091
|
-
examples: ["treeseed release --patch", "treeseed release --minor", "treeseed release --
|
|
1092
|
-
notes: ["Requires exactly one bump flag."],
|
|
1081
|
+
examples: ["treeseed release --patch", "treeseed release --minor", "treeseed release --repair-version-line --target-version-line 0.10 --plan", "treeseed release --patch --fresh"],
|
|
1082
|
+
notes: ["Requires exactly one bump flag unless --repair-version-line is used."],
|
|
1093
1083
|
help: {
|
|
1094
1084
|
workflowPosition: "promote to production",
|
|
1095
1085
|
longSummary: [
|
|
@@ -1097,11 +1087,11 @@ const CLI_COMMAND_OVERLAYS = /* @__PURE__ */ new Map([
|
|
|
1097
1087
|
],
|
|
1098
1088
|
whenToUse: [
|
|
1099
1089
|
"Use this only when staging is the approved source for production promotion.",
|
|
1100
|
-
"Choose exactly one bump flag so the release version reflects the intended change size."
|
|
1090
|
+
"Choose exactly one bump flag so the release version reflects the intended change size, or use --repair-version-line to repair package line drift."
|
|
1101
1091
|
],
|
|
1102
1092
|
beforeYouRun: [
|
|
1103
1093
|
"Confirm staging is in the state you want to promote.",
|
|
1104
|
-
"Choose one of `--major`, `--minor`, or `--
|
|
1094
|
+
"Choose one of `--major`, `--minor`, `--patch`, or `--repair-version-line` before running the command."
|
|
1105
1095
|
],
|
|
1106
1096
|
outcomes: [
|
|
1107
1097
|
"Promotes the release forward and records the version bump.",
|
|
@@ -1110,10 +1100,11 @@ const CLI_COMMAND_OVERLAYS = /* @__PURE__ */ new Map([
|
|
|
1110
1100
|
examples: [
|
|
1111
1101
|
example("treeseed release --patch", "Patch release", "Promote staging to production with the next patch version."),
|
|
1112
1102
|
example("treeseed release --minor", "Minor release", "Promote staging with the next minor version bump."),
|
|
1103
|
+
example("treeseed release --repair-version-line --target-version-line 0.10 --json", "Repair package line drift", "Publish only packages below the selected public package release line."),
|
|
1113
1104
|
example("treeseed release --patch --json", "Automate release tracking", "Emit structured release output for tooling that records deployments and version changes.")
|
|
1114
1105
|
],
|
|
1115
1106
|
warnings: [
|
|
1116
|
-
"Exactly one bump flag is required.",
|
|
1107
|
+
"Exactly one bump flag is required unless --repair-version-line is used.",
|
|
1117
1108
|
"This is a production-facing promotion command, not a dry local build operation."
|
|
1118
1109
|
],
|
|
1119
1110
|
relatedDetails: [
|
|
@@ -1174,34 +1165,32 @@ const CLI_COMMAND_OVERLAYS = /* @__PURE__ */ new Map([
|
|
|
1174
1165
|
})],
|
|
1175
1166
|
["dev", command({
|
|
1176
1167
|
options: DEV_RUNTIME_OPTIONS,
|
|
1177
|
-
examples: ["treeseed dev", "treeseed dev --reset", "treeseed dev --reset --plan --json", "treeseed dev --
|
|
1168
|
+
examples: ["treeseed dev", "treeseed dev --reset", "treeseed dev --reset --plan --json", "treeseed dev --web-runtime local --plan --json", "treeseed dev --port 4322"],
|
|
1178
1169
|
help: {
|
|
1179
1170
|
longSummary: [
|
|
1180
|
-
"Dev starts the
|
|
1181
|
-
"
|
|
1171
|
+
"Dev starts the local Treeseed Market web/API runtime as a foreground supervisor.",
|
|
1172
|
+
"Capacity provider lifecycle is package-owned and runs through `treeseed capacity ...`, not through `treeseed dev`."
|
|
1182
1173
|
],
|
|
1183
1174
|
beforeYouRun: [
|
|
1184
1175
|
"Run from the tenant or workspace root you want to develop.",
|
|
1185
|
-
"Use `--plan --json` when you want to inspect
|
|
1176
|
+
"Use `--plan --json` when you want to inspect fixed web/API commands, setup steps, readiness checks, watched paths, and restart policy without starting services.",
|
|
1186
1177
|
"Use `--reset` when you want a fresh local D1 database, Mailpit inbox, generated worker bundle, and Wrangler temp output without deleting configuration.",
|
|
1187
1178
|
"Dev prints the local web URL after readiness; it does not open a browser unless you pass `--open on` or `--open auto`.",
|
|
1188
1179
|
"Keep the foreground process running while you test. Press Ctrl+C to stop the supervised stack and free the local ports."
|
|
1189
1180
|
],
|
|
1190
1181
|
examples: [
|
|
1191
|
-
example("treeseed dev", "Start
|
|
1182
|
+
example("treeseed dev", "Start local Market development", "Run web and API locally and keep supervising them in the foreground."),
|
|
1192
1183
|
example("treeseed dev --reset", "Start from a fresh local runtime", "Clear disposable local dev state, rerun setup and D1 migrations, then start the dev supervisor."),
|
|
1193
1184
|
example("treeseed dev --reset --plan --json", "Inspect reset actions", "Emit the reset, setup, readiness, command, and watch plan without deleting local state or starting services."),
|
|
1194
1185
|
example("treeseed dev --plan --json", "Inspect the runtime plan", "Emit a structured plan with setup steps, commands, ports, URLs, readiness checks, and watch entries."),
|
|
1195
|
-
example("treeseed dev --
|
|
1196
|
-
example("treeseed dev --
|
|
1197
|
-
example("treeseed dev --surfaces integrated,agents", "Opt into agents diagnostics", "Start the integrated local platform plus the agents diagnostic loop."),
|
|
1198
|
-
example("treeseed dev --surface web --port 4322", "Run only the web surface", "Start the Astro UI on a specific port and print the URL when ready."),
|
|
1186
|
+
example("treeseed dev --web-runtime local --plan --json", "Inspect local web runtime", "Plan fixed web/API startup using the local Astro web runtime."),
|
|
1187
|
+
example("treeseed dev --port 4322", "Change the web port", "Start the fixed web/API runtime with the Astro UI on a specific port."),
|
|
1199
1188
|
example("treeseed dev --open on", "Open the browser explicitly", "Start the integrated runtime and launch the local web URL after readiness."),
|
|
1200
1189
|
example("trsd dev", "Use the short alias", "Start the same local runtime through the shorter entrypoint."),
|
|
1201
1190
|
example("treeseed dev --json", "Stream dev events", "Emit newline-delimited events while the long-running dev process supervises local services.")
|
|
1202
1191
|
],
|
|
1203
1192
|
outcomes: [
|
|
1204
|
-
"Starts
|
|
1193
|
+
"Starts fixed local web/API surfaces, waits for readiness, prints the local URL, and then remains attached as the live supervisor.",
|
|
1205
1194
|
"Restarts required crashed surfaces with capped exponential backoff and keeps setup/readiness failures alive for retry.",
|
|
1206
1195
|
"Stops watchers first and then terminates service process groups when the foreground command exits."
|
|
1207
1196
|
]
|
|
@@ -1209,45 +1198,6 @@ const CLI_COMMAND_OVERLAYS = /* @__PURE__ */ new Map([
|
|
|
1209
1198
|
executionMode: "handler",
|
|
1210
1199
|
handlerName: "dev"
|
|
1211
1200
|
})],
|
|
1212
|
-
["dev:manager", command({
|
|
1213
|
-
options: DEV_MANAGER_OPTIONS,
|
|
1214
|
-
examples: ["treeseed dev:manager", "treeseed dev:manager --with-worker", "treeseed dev:manager --docs-automation dry-run --plan --json"],
|
|
1215
|
-
help: {
|
|
1216
|
-
longSummary: [
|
|
1217
|
-
"Dev:manager starts the governed local documentation automation manager through the same integrated dev supervisor used by `treeseed dev`.",
|
|
1218
|
-
"It selects the manager surface by default, can supervise a local worker with `--with-worker`, and passes docs automation policy into the existing manager and worker runtime."
|
|
1219
|
-
],
|
|
1220
|
-
examples: [
|
|
1221
|
-
example("treeseed dev:manager", "Start the local manager", "Run the governed workday manager in the foreground."),
|
|
1222
|
-
example("treeseed dev:manager --with-worker", "Start manager plus worker", "Run scheduling and task execution in the same local supervision session."),
|
|
1223
|
-
example("treeseed dev:manager --docs-automation dry-run --plan --json", "Inspect dry-run manager mode", "Show the manager plan and docs automation settings without starting the supervisor.")
|
|
1224
|
-
],
|
|
1225
|
-
outcomes: [
|
|
1226
|
-
"Starts or plans the existing manager surface, with optional worker supervision.",
|
|
1227
|
-
"Keeps manual approval as the local default and forwards docs automation mode, workday id, capacity budget, and approval policy through runtime environment variables."
|
|
1228
|
-
]
|
|
1229
|
-
},
|
|
1230
|
-
executionMode: "handler",
|
|
1231
|
-
handlerName: "dev"
|
|
1232
|
-
})],
|
|
1233
|
-
["dev:watch", command({
|
|
1234
|
-
options: DEV_RUNTIME_OPTIONS,
|
|
1235
|
-
examples: ["treeseed dev:watch", "treeseed dev:watch --json"],
|
|
1236
|
-
help: {
|
|
1237
|
-
longSummary: [
|
|
1238
|
-
"Dev:watch is a compatibility alias for foreground dev supervision with live feedback enabled.",
|
|
1239
|
-
"It stays attached to the terminal and cleans up supervised services on Ctrl+C just like `dev`."
|
|
1240
|
-
],
|
|
1241
|
-
examples: [
|
|
1242
|
-
example("treeseed dev:watch", "Start watch mode", "Run the local runtime with watch and rebuild behavior enabled in the foreground."),
|
|
1243
|
-
example("trsd dev:watch", "Use the short alias", "Start the same watch-mode runtime through the shorter entrypoint."),
|
|
1244
|
-
example("treeseed dev:watch --feedback restart", "Restart services without browser reload", "Use watcher-driven service restarts while leaving browser refresh to your own tooling."),
|
|
1245
|
-
example("treeseed dev:watch --help", "Inspect watch help", "Read the help surface before starting a longer watch session.")
|
|
1246
|
-
]
|
|
1247
|
-
},
|
|
1248
|
-
executionMode: "handler",
|
|
1249
|
-
handlerName: "dev"
|
|
1250
|
-
})],
|
|
1251
1201
|
["build", command({ examples: ["treeseed build"], help: { longSummary: ["Build runs the tenant build path and produces the generated output for the current project."], examples: [example("treeseed build", "Build the tenant", "Run the packaged build flow for the current project."), example("trsd build", "Use the short alias", "Run the same build through the shorter entrypoint."), example("treeseed build && treeseed export", "Build before packaging context", "Produce build artifacts first and then capture a code export if needed.")] }, executionMode: "adapter" })],
|
|
1252
1202
|
["check", command({ examples: ["treeseed check"], help: { longSummary: ["Check runs the project validation path against the current tenant and shared fixture model."], examples: [example("treeseed check", "Validate the tenant", "Run the project check flow."), example("trsd check", "Use the short alias", "Run the same validation via the short entrypoint."), example("treeseed check && treeseed doctor", "Pair validation with diagnostics", "Follow failed checks with the broader doctor surface.")] }, executionMode: "adapter" })],
|
|
1253
1203
|
["preview", command({ examples: ["treeseed preview"], help: { longSummary: ["Preview serves the built tenant output locally so you can inspect the built site rather than the live dev runtime."], examples: [example("treeseed preview", "Preview the built site", "Run the packaged preview flow for the built tenant."), example("treeseed preview -- --help", "Forward preview help", "Pass through additional args when the preview runtime supports them."), example("treeseed build && treeseed preview", "Build then preview", "Generate the build output first and then serve it locally.")] }, executionMode: "adapter", buildAdapterInput: PASS_THROUGH_ARGS })],
|
|
@@ -1573,36 +1523,39 @@ const CLI_ONLY_OPERATION_SPECS = [
|
|
|
1573
1523
|
name: "capacity",
|
|
1574
1524
|
aliases: [],
|
|
1575
1525
|
group: "Utilities",
|
|
1576
|
-
summary: "
|
|
1577
|
-
description: "
|
|
1526
|
+
summary: "Operate the package-owned capacity provider runtime.",
|
|
1527
|
+
description: "Run provider diagnostics, registration, and planning through the built @treeseed/agent capacity provider entrypoint.",
|
|
1578
1528
|
provider: "default",
|
|
1579
1529
|
related: ["teams", "projects", "agents"],
|
|
1580
|
-
usage: "treeseed capacity [status|
|
|
1530
|
+
usage: "treeseed capacity [doctor|register|plan|up|down|restart|logs|status|build|test-local]",
|
|
1581
1531
|
arguments: [{ name: "action", description: "Capacity action.", required: false }],
|
|
1582
1532
|
options: [
|
|
1583
1533
|
{ name: "market", flags: "--market <id-or-url>", description: "Select a configured market id or direct market API URL.", kind: "string" },
|
|
1584
|
-
{ name: "
|
|
1585
|
-
{ name: "
|
|
1586
|
-
{ name: "
|
|
1587
|
-
{ name: "
|
|
1588
|
-
{ name: "
|
|
1589
|
-
{ name: "
|
|
1590
|
-
{ name: "daily", flags: "--daily <credits>", description: "Daily credit limit for a created grant.", kind: "string" },
|
|
1591
|
-
{ name: "monthly", flags: "--monthly <credits>", description: "Monthly credit limit for a created grant.", kind: "string" },
|
|
1534
|
+
{ name: "provider", flags: "--provider <provider-id>", description: "Provider id or local provider selector for diagnostics.", kind: "string" },
|
|
1535
|
+
{ name: "environment", flags: "--environment <scope>", description: "Treeseed config scope used when resolving encrypted provider launch values.", kind: "enum", values: ["local", "staging", "prod"] },
|
|
1536
|
+
{ name: "dataDir", flags: "--data-dir <path>", description: "Host data directory mounted into the provider container at /data.", kind: "string" },
|
|
1537
|
+
{ name: "agentPackageRoot", flags: "--agent-package-root <path>", description: "Path to a built @treeseed/agent package root.", kind: "string" },
|
|
1538
|
+
{ name: "diagnostic", flags: "--diagnostic", description: "Start lifecycle commands without live Market registration or provider credentials.", kind: "boolean" },
|
|
1539
|
+
{ name: "dryRun", flags: "--dry-run", description: "Ask the provider runtime to render deterministic output without provider secrets or Market mutation.", kind: "boolean" },
|
|
1592
1540
|
{ name: "json", flags: "--json", description: "Emit machine-readable JSON instead of human-readable text.", kind: "boolean" }
|
|
1593
1541
|
],
|
|
1594
1542
|
examples: [
|
|
1595
|
-
"treeseed capacity
|
|
1596
|
-
"treeseed capacity
|
|
1597
|
-
"treeseed capacity
|
|
1598
|
-
"treeseed capacity
|
|
1599
|
-
"treeseed capacity
|
|
1543
|
+
"treeseed capacity doctor --market local --provider local",
|
|
1544
|
+
"treeseed capacity register --market local --provider local --dry-run --json",
|
|
1545
|
+
"treeseed capacity plan --market local --provider local --dry-run --json",
|
|
1546
|
+
"treeseed capacity build",
|
|
1547
|
+
"treeseed capacity up --market local --provider local",
|
|
1548
|
+
"treeseed capacity up --market local --provider local --diagnostic",
|
|
1549
|
+
"treeseed capacity status --market local --provider local",
|
|
1550
|
+
"treeseed capacity logs --market local --provider local",
|
|
1551
|
+
"treeseed capacity down --market local --provider local",
|
|
1552
|
+
"treeseed capacity test-local"
|
|
1600
1553
|
],
|
|
1601
1554
|
help: {
|
|
1602
|
-
longSummary: ["Capacity
|
|
1603
|
-
whenToUse: ["Use this
|
|
1604
|
-
beforeYouRun: ["
|
|
1605
|
-
automationNotes: ["Use `--json`
|
|
1555
|
+
longSummary: ["Capacity invokes the package-owned @treeseed/agent provider runtime for local diagnostics, registration previews, portfolio planning, and Docker/Compose lifecycle commands."],
|
|
1556
|
+
whenToUse: ["Use this when validating a self-hosted capacity provider install, checking provider runtime output, or running the local provider stack."],
|
|
1557
|
+
beforeYouRun: ["Build @treeseed/agent first, or pass --agent-package-root to a built package. Use `trsd config` for encrypted provider values; capacity commands do not write plaintext env files."],
|
|
1558
|
+
automationNotes: ["Use `--json` for stable provider runtime output. `up` runs live local provider mode by default; pass `--diagnostic` or use `test-local` for diagnostics without provider secrets."]
|
|
1606
1559
|
},
|
|
1607
1560
|
helpVisible: true,
|
|
1608
1561
|
helpFeatured: false,
|
package/dist/cli/parser.js
CHANGED
|
@@ -82,9 +82,9 @@ function validateTreeseedInvocation(command, invocation) {
|
|
|
82
82
|
}
|
|
83
83
|
}
|
|
84
84
|
if (command.name === "release") {
|
|
85
|
-
const selected = ["major", "minor", "patch"].filter((name) => invocation.args[name] === true);
|
|
85
|
+
const selected = ["major", "minor", "patch", "repairVersionLine"].filter((name) => invocation.args[name] === true);
|
|
86
86
|
if (selected.length !== 1) {
|
|
87
|
-
errors.push(`Treeseed ${command.name} requires exactly one version bump flag: --major, --minor, or --
|
|
87
|
+
errors.push(`Treeseed ${command.name} requires exactly one version bump flag: --major, --minor, --patch, or --repair-version-line.`);
|
|
88
88
|
}
|
|
89
89
|
}
|
|
90
90
|
return errors;
|
package/dist/cli/registry.d.ts
CHANGED
|
@@ -10,8 +10,6 @@ export declare const COMMAND_HANDLERS: {
|
|
|
10
10
|
readonly status: import("./operations-types.js").TreeseedCommandHandler;
|
|
11
11
|
readonly ci: import("./operations-types.js").TreeseedCommandHandler;
|
|
12
12
|
readonly dev: import("./operations-types.js").TreeseedCommandHandler;
|
|
13
|
-
readonly 'dev:manager': import("./operations-types.js").TreeseedCommandHandler;
|
|
14
|
-
readonly 'dev:watch': import("./operations-types.js").TreeseedCommandHandler;
|
|
15
13
|
readonly doctor: import("./operations-types.js").TreeseedCommandHandler;
|
|
16
14
|
readonly rollback: import("./operations-types.js").TreeseedCommandHandler;
|
|
17
15
|
readonly template: import("./operations-types.js").TreeseedCommandHandler;
|
package/dist/cli/registry.js
CHANGED
package/dist/cli/runtime.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@treeseed/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"description": "Operator-facing Treeseed CLI package.",
|
|
5
5
|
"license": "AGPL-3.0-only",
|
|
6
6
|
"repository": {
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
"release:publish": "node ./scripts/run-ts.mjs ./scripts/publish-package.ts"
|
|
46
46
|
},
|
|
47
47
|
"dependencies": {
|
|
48
|
-
"@treeseed/sdk": "0.
|
|
48
|
+
"@treeseed/sdk": "0.10.6",
|
|
49
49
|
"ink": "^7.0.0",
|
|
50
50
|
"react": "^19.2.5"
|
|
51
51
|
},
|