@treeseed/cli 0.9.0 → 0.9.3

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.
@@ -1,144 +1,288 @@
1
- import { guidedResult } from "./utils.js";
2
- import { createMarketClientForInvocation } from "./market-utils.js";
3
- function required(value, message) {
4
- if (typeof value === "string" && value.trim()) return value.trim();
5
- throw new Error(message);
6
- }
7
- const handleCapacity = async (invocation, context) => {
8
- const action = invocation.positionals[0] ?? "status";
9
- const { profile, client } = createMarketClientForInvocation(invocation, context, { requireAuth: true });
10
- const teamId = typeof invocation.args.team === "string" ? invocation.args.team : typeof profile.teamId === "string" ? profile.teamId : null;
11
- if (action === "status") {
12
- const team = required(teamId, "Usage: treeseed capacity status --team <team-id>");
13
- const response = await client.teamCapacity(team);
14
- const summary = response.payload.summary;
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: "capacity",
17
- summary: "Team helper capacity status",
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: "Market", value: profile.id },
20
- { label: "Team", value: team },
21
- { label: "Monthly remaining", value: summary?.monthlyRemainingCredits },
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
- report: { marketId: profile.id, teamId: team, capacity: response.payload }
134
+ exitCode: result2.status ?? 1,
135
+ report: {
136
+ action,
137
+ agentPackageRoot: agentPackage.packageRoot,
138
+ script
139
+ }
26
140
  });
27
141
  }
28
- if (action === "providers") {
29
- const subcommand = invocation.positionals[1] ?? "list";
30
- const team = required(teamId, "Usage: treeseed capacity providers list --team <team-id>");
31
- if (subcommand === "list") {
32
- const response = await client.teamCapacity(team);
33
- const providers = response.payload.providers ?? [];
34
- return guidedResult({
35
- command: "capacity",
36
- summary: `Found ${providers.length} helper capacity provider${providers.length === 1 ? "" : "s"}.`,
37
- sections: [{
38
- title: "Providers",
39
- lines: providers.map((provider) => `${provider.id} ${provider.name} ${provider.status} workers=${provider.maxConcurrentWorkers ?? 0}`)
40
- }],
41
- report: { marketId: profile.id, teamId: team, providers }
42
- });
43
- }
44
- if (subcommand === "connect") {
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
- if (subcommand === "keys") {
57
- const keyAction = invocation.positionals[2] ?? "reset";
58
- const providerId = required(invocation.args.provider, "Usage: treeseed capacity providers keys reset --provider <provider-id>");
59
- if (keyAction === "reset") {
60
- const response = await client.resetCapacityProviderApiKey(providerId, { name: "Provider security code" });
61
- return guidedResult({
62
- command: "capacity",
63
- summary: "Provider security code was reset.",
64
- facts: [
65
- { label: "Provider", value: providerId },
66
- { label: "Prefix", value: response.payload.key?.keyPrefix },
67
- { label: "Security access code", value: response.payload.plaintextKey }
68
- ],
69
- report: { marketId: profile.id, providerId, result: response.payload }
70
- });
71
- }
72
- if (keyAction === "revoke") {
73
- const keyId = required(invocation.args.key, "Usage: treeseed capacity providers keys revoke --provider <provider-id> --key <key-id>");
74
- const response = await client.revokeCapacityProviderApiKey(providerId, keyId);
75
- return guidedResult({
76
- command: "capacity",
77
- summary: "Provider security code was revoked.",
78
- facts: [
79
- { label: "Provider", value: providerId },
80
- { label: "Key", value: keyId }
81
- ],
82
- report: { marketId: profile.id, providerId, keyId, result: response.payload }
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
- return { exitCode: 1, stderr: [`Unknown capacity providers action: ${subcommand}`] };
87
- }
88
- if (action === "grants") {
89
- const subcommand = invocation.positionals[1] ?? "list";
90
- const team = required(teamId, "Usage: treeseed capacity grants list --team <team-id>");
91
- if (subcommand === "list") {
92
- const response = await client.capacityGrants(team);
93
- return guidedResult({
94
- command: "capacity",
95
- summary: `Found ${response.payload.length} capacity grant${response.payload.length === 1 ? "" : "s"}.`,
96
- sections: [{
97
- title: "Grants",
98
- lines: response.payload.map((grant) => `${grant.id} ${grant.grantScope} daily=${grant.dailyCreditLimit ?? "policy"} monthly=${grant.monthlyCreditLimit ?? "policy"}`)
99
- }],
100
- report: { marketId: profile.id, teamId: team, grants: response.payload }
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
- if (subcommand === "create") {
104
- const providerId = required(invocation.args.provider, "Usage: treeseed capacity grants create --team <team-id> --provider <provider-id>");
105
- const response = await client.createCapacityGrant(team, {
106
- capacityProviderId: providerId,
107
- projectId: typeof invocation.args.project === "string" ? invocation.args.project : null,
108
- environment: typeof invocation.args.environment === "string" ? invocation.args.environment : null,
109
- dailyCreditLimit: Number(invocation.args.daily ?? 25),
110
- monthlyCreditLimit: Number(invocation.args.monthly ?? 500),
111
- overflowPolicy: typeof invocation.args.overflow === "string" ? invocation.args.overflow : "approval_required"
112
- });
113
- return guidedResult({
114
- command: "capacity",
115
- summary: "Capacity grant created.",
116
- facts: [
117
- { label: "Grant", value: response.payload.id },
118
- { label: "Provider", value: providerId }
119
- ],
120
- report: { marketId: profile.id, teamId: team, grant: response.payload }
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 === "enqueue") {
126
- const projectId = required(invocation.args.project, "Usage: treeseed capacity enqueue --project <project-id> --task-kind <kind>");
127
- const response = await client.enqueueAgentTask(projectId, {
128
- taskKind: typeof invocation.args.taskKind === "string" ? invocation.args.taskKind : typeof invocation.args.task === "string" ? invocation.args.task : "proposal.draft",
129
- environment: typeof invocation.args.environment === "string" ? invocation.args.environment : "staging"
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 { exitCode: 1, stderr: [`Unknown capacity action: ${action}`] };
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
@@ -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
- const managerMode = invocation.commandName === "dev:manager";
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: devManagerEnv
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: managerMode ? "dev:manager" : invocation.commandName,
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
  };
@@ -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 security codes:",
109
- ...created.map((entry) => ` ${String(entry.providerName ?? entry.providerKey ?? entry.providerId)} (${String(entry.keyPrefix ?? "new key")}): ${String(entry.plaintextKey ?? "created")}`),
110
- " Copy these now. TreeSeed will not show the plaintext codes again."
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(applied.result)
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
- ...applied.result
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";
@@ -1174,34 +1162,32 @@ const CLI_COMMAND_OVERLAYS = /* @__PURE__ */ new Map([
1174
1162
  })],
1175
1163
  ["dev", command({
1176
1164
  options: DEV_RUNTIME_OPTIONS,
1177
- examples: ["treeseed dev", "treeseed dev --reset", "treeseed dev --reset --plan --json", "treeseed dev --surfaces web,api --plan --json", "treeseed dev --surface web --port 4322"],
1165
+ examples: ["treeseed dev", "treeseed dev --reset", "treeseed dev --reset --plan --json", "treeseed dev --web-runtime local --plan --json", "treeseed dev --port 4322"],
1178
1166
  help: {
1179
1167
  longSummary: [
1180
- "Dev starts the unified local Treeseed runtime as a foreground supervisor so you can work against the integrated web, API, manager, worker, and supporting local surfaces.",
1181
- "The command keeps streaming logs and dev events until you press Ctrl+C or receive SIGTERM. Required surface failures are restarted with backoff instead of ending the supervisor."
1168
+ "Dev starts the local Treeseed Market web/API runtime as a foreground supervisor.",
1169
+ "Capacity provider lifecycle is package-owned and runs through `treeseed capacity ...`, not through `treeseed dev`."
1182
1170
  ],
1183
1171
  beforeYouRun: [
1184
1172
  "Run from the tenant or workspace root you want to develop.",
1185
- "Use `--plan --json` when you want to inspect selected surfaces, commands, setup steps, readiness checks, watched paths, and restart policy without starting services.",
1173
+ "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
1174
  "Use `--reset` when you want a fresh local D1 database, Mailpit inbox, generated worker bundle, and Wrangler temp output without deleting configuration.",
1187
1175
  "Dev prints the local web URL after readiness; it does not open a browser unless you pass `--open on` or `--open auto`.",
1188
1176
  "Keep the foreground process running while you test. Press Ctrl+C to stop the supervised stack and free the local ports."
1189
1177
  ],
1190
1178
  examples: [
1191
- example("treeseed dev", "Start integrated local development", "Run web, API, manager, and worker locally and keep supervising them in the foreground."),
1179
+ example("treeseed dev", "Start local Market development", "Run web and API locally and keep supervising them in the foreground."),
1192
1180
  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
1181
  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
1182
  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 --surfaces web,api,worker --plan --json", "Inspect selected surfaces", "Plan a comma-separated set of local surfaces without starting the supervisor."),
1196
- example("treeseed dev --surface api --plan --json", "Inspect the API surface", "Plan the local API runtime without the web UI."),
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."),
1183
+ example("treeseed dev --web-runtime local --plan --json", "Inspect local web runtime", "Plan fixed web/API startup using the local Astro web runtime."),
1184
+ example("treeseed dev --port 4322", "Change the web port", "Start the fixed web/API runtime with the Astro UI on a specific port."),
1199
1185
  example("treeseed dev --open on", "Open the browser explicitly", "Start the integrated runtime and launch the local web URL after readiness."),
1200
1186
  example("trsd dev", "Use the short alias", "Start the same local runtime through the shorter entrypoint."),
1201
1187
  example("treeseed dev --json", "Stream dev events", "Emit newline-delimited events while the long-running dev process supervises local services.")
1202
1188
  ],
1203
1189
  outcomes: [
1204
- "Starts the selected local surfaces, waits for readiness, prints the local URL, and then remains attached as the live supervisor.",
1190
+ "Starts fixed local web/API surfaces, waits for readiness, prints the local URL, and then remains attached as the live supervisor.",
1205
1191
  "Restarts required crashed surfaces with capped exponential backoff and keeps setup/readiness failures alive for retry.",
1206
1192
  "Stops watchers first and then terminates service process groups when the foreground command exits."
1207
1193
  ]
@@ -1209,45 +1195,6 @@ const CLI_COMMAND_OVERLAYS = /* @__PURE__ */ new Map([
1209
1195
  executionMode: "handler",
1210
1196
  handlerName: "dev"
1211
1197
  })],
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
1198
  ["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
1199
  ["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
1200
  ["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 +1520,39 @@ const CLI_ONLY_OPERATION_SPECS = [
1573
1520
  name: "capacity",
1574
1521
  aliases: [],
1575
1522
  group: "Utilities",
1576
- summary: "Manage team helper capacity from the selected market.",
1577
- description: "Inspect team helper credits, connect managed providers, rotate provider security codes, manage grants, and enqueue budgeted agent tasks.",
1523
+ summary: "Operate the package-owned capacity provider runtime.",
1524
+ description: "Run provider diagnostics, registration, and planning through the built @treeseed/agent capacity provider entrypoint.",
1578
1525
  provider: "default",
1579
1526
  related: ["teams", "projects", "agents"],
1580
- usage: "treeseed capacity [status|providers|grants|enqueue]",
1527
+ usage: "treeseed capacity [doctor|register|plan|up|down|restart|logs|status|build|test-local]",
1581
1528
  arguments: [{ name: "action", description: "Capacity action.", required: false }],
1582
1529
  options: [
1583
1530
  { name: "market", flags: "--market <id-or-url>", description: "Select a configured market id or direct market API URL.", kind: "string" },
1584
- { name: "team", flags: "--team <team-id>", description: "Team id for capacity status and grants.", kind: "string" },
1585
- { name: "provider", flags: "--provider <provider-id>", description: "Capacity provider id for grant or key actions.", kind: "string" },
1586
- { name: "project", flags: "--project <project-id>", description: "Project id for grant allocation or agent enqueue.", kind: "string" },
1587
- { name: "key", flags: "--key <key-id>", description: "Provider security code id to revoke.", kind: "string" },
1588
- { name: "taskKind", flags: "--task-kind <kind>", description: "Agent task signature for budgeted enqueue.", kind: "string" },
1589
- { name: "environment", flags: "--environment <environment>", description: "Project environment for grants or enqueue.", kind: "enum", values: ["local", "staging", "prod"] },
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" },
1531
+ { name: "provider", flags: "--provider <provider-id>", description: "Provider id or local provider selector for diagnostics.", kind: "string" },
1532
+ { name: "environment", flags: "--environment <scope>", description: "Treeseed config scope used when resolving encrypted provider launch values.", kind: "enum", values: ["local", "staging", "prod"] },
1533
+ { name: "dataDir", flags: "--data-dir <path>", description: "Host data directory mounted into the provider container at /data.", kind: "string" },
1534
+ { name: "agentPackageRoot", flags: "--agent-package-root <path>", description: "Path to a built @treeseed/agent package root.", kind: "string" },
1535
+ { name: "diagnostic", flags: "--diagnostic", description: "Start lifecycle commands without live Market registration or provider credentials.", kind: "boolean" },
1536
+ { name: "dryRun", flags: "--dry-run", description: "Ask the provider runtime to render deterministic output without provider secrets or Market mutation.", kind: "boolean" },
1592
1537
  { name: "json", flags: "--json", description: "Emit machine-readable JSON instead of human-readable text.", kind: "boolean" }
1593
1538
  ],
1594
1539
  examples: [
1595
- "treeseed capacity status --team team_123",
1596
- "treeseed capacity providers connect --team team_123",
1597
- "treeseed capacity providers keys reset --provider provider_123",
1598
- "treeseed capacity grants create --team team_123 --provider provider_123 --daily 25",
1599
- "treeseed capacity enqueue --project project_123 --task-kind proposal.draft"
1540
+ "treeseed capacity doctor --market local --provider local",
1541
+ "treeseed capacity register --market local --provider local --dry-run --json",
1542
+ "treeseed capacity plan --market local --provider local --dry-run --json",
1543
+ "treeseed capacity build",
1544
+ "treeseed capacity up --market local --provider local",
1545
+ "treeseed capacity up --market local --provider local --diagnostic",
1546
+ "treeseed capacity status --market local --provider local",
1547
+ "treeseed capacity logs --market local --provider local",
1548
+ "treeseed capacity down --market local --provider local",
1549
+ "treeseed capacity test-local"
1600
1550
  ],
1601
1551
  help: {
1602
- longSummary: ["Capacity talks to the market control plane so technical stewards can inspect helper credits, provider security codes, and budgeted agent task routing without opening the browser."],
1603
- whenToUse: ["Use this after connecting to a market when provider health, budget allocation, or budgeted agent enqueue needs to be checked from a terminal."],
1604
- beforeYouRun: ["Authenticate to the selected market and know the team, project, or provider id for the action you are taking."],
1605
- automationNotes: ["Use `--json` when capturing provider keys, grant ids, task ids, or dashboard summaries in automation."]
1552
+ longSummary: ["Capacity invokes the package-owned @treeseed/agent provider runtime for local diagnostics, registration previews, portfolio planning, and Docker/Compose lifecycle commands."],
1553
+ whenToUse: ["Use this when validating a self-hosted capacity provider install, checking provider runtime output, or running the local provider stack."],
1554
+ 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."],
1555
+ 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
1556
  },
1607
1557
  helpVisible: true,
1608
1558
  helpFeatured: false,
@@ -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;
@@ -54,8 +54,6 @@ const COMMAND_HANDLERS = {
54
54
  status: handleStatus,
55
55
  ci: handleCi,
56
56
  dev: handleDev,
57
- "dev:manager": handleDev,
58
- "dev:watch": handleDev,
59
57
  doctor: handleDoctor,
60
58
  rollback: handleRollback,
61
59
  template: handleTemplate,
@@ -351,6 +351,7 @@ function commandNeedsProjectRoot(spec) {
351
351
  "market",
352
352
  "teams",
353
353
  "projects",
354
+ "capacity",
354
355
  "packs",
355
356
  "template"
356
357
  ])).has(spec.name);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@treeseed/cli",
3
- "version": "0.9.0",
3
+ "version": "0.9.3",
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.9.0",
48
+ "@treeseed/sdk": "github:treeseed-ai/sdk#0.10.6",
49
49
  "ink": "^7.0.0",
50
50
  "react": "^19.2.5"
51
51
  },