@treeseed/cli 0.8.18 → 0.9.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/dev.js
CHANGED
|
@@ -67,6 +67,7 @@ const handleDev = async (invocation, context) => {
|
|
|
67
67
|
}
|
|
68
68
|
forwardStringOption("host", "--host");
|
|
69
69
|
forwardStringOption("port", "--port");
|
|
70
|
+
forwardStringOption("webRuntime", "--web-runtime");
|
|
70
71
|
forwardStringOption("apiHost", "--api-host");
|
|
71
72
|
forwardStringOption("apiPort", "--api-port");
|
|
72
73
|
forwardStringOption("managerPort", "--manager-port");
|
|
@@ -75,6 +76,7 @@ const handleDev = async (invocation, context) => {
|
|
|
75
76
|
forwardStringOption("open", "--open");
|
|
76
77
|
forwardBooleanOption("plan", "--plan");
|
|
77
78
|
forwardBooleanOption("reset", "--reset");
|
|
79
|
+
forwardBooleanOption("force", "--force");
|
|
78
80
|
forwardBooleanOption("json", "--json");
|
|
79
81
|
const docsAutomationMode = typeof invocation.args.docsAutomation === "string" ? invocation.args.docsAutomation.trim() : "";
|
|
80
82
|
const workdayId = typeof invocation.args.workdayId === "string" ? invocation.args.workdayId.trim() : "";
|
|
@@ -87,7 +89,9 @@ const handleDev = async (invocation, context) => {
|
|
|
87
89
|
TREESEED_CAPACITY_BUDGET: capacityBudget,
|
|
88
90
|
TREESEED_WORKDAY_TASK_CREDIT_BUDGET: capacityBudget
|
|
89
91
|
} : {},
|
|
90
|
-
TREESEED_APPROVAL_POLICY: approvalPolicy || "manual"
|
|
92
|
+
TREESEED_APPROVAL_POLICY: approvalPolicy || "manual",
|
|
93
|
+
TREESEED_MANAGER_CONSOLE_SUMMARY: "true",
|
|
94
|
+
TREESEED_WORKER_CONSOLE_SUMMARY: "true"
|
|
91
95
|
} : {};
|
|
92
96
|
const workspaceRoot = findNearestTreeseedWorkspaceRoot(context.cwd);
|
|
93
97
|
const workspaceLinksMode = typeof invocation.args.workspaceLinks === "string" ? invocation.args.workspaceLinks : void 0;
|
|
@@ -102,7 +106,8 @@ const handleDev = async (invocation, context) => {
|
|
|
102
106
|
env: resolveTreeseedLaunchEnvironment({
|
|
103
107
|
tenantRoot: context.cwd,
|
|
104
108
|
scope: "local",
|
|
105
|
-
baseEnv: { ...process.env, ...context.env ?? {}
|
|
109
|
+
baseEnv: { ...process.env, ...context.env ?? {} },
|
|
110
|
+
overrides: devManagerEnv
|
|
106
111
|
}),
|
|
107
112
|
stdio: "inherit"
|
|
108
113
|
});
|
|
@@ -4,19 +4,54 @@ import { existsSync, mkdirSync, writeFileSync } from "node:fs";
|
|
|
4
4
|
import { formatSeedDiagnostics, formatSeedPlan, loadAndPlanSeed } from "@treeseed/sdk/seeds";
|
|
5
5
|
import { MarketApiError } from "@treeseed/sdk/market-client";
|
|
6
6
|
import { createMarketClientForInvocation, marketAuthRoot, marketSelector } from "./market-utils.js";
|
|
7
|
-
import { resolveMarketProfile, resolveMarketSession } from "@treeseed/sdk/market-client";
|
|
7
|
+
import { MarketClient, resolveMarketProfile, resolveMarketSession, setMarketSession } from "@treeseed/sdk/market-client";
|
|
8
8
|
async function loadLocalSeedModule(projectRoot) {
|
|
9
9
|
const apiModulePath = resolve(projectRoot, "src", "lib", "market", "seeds", "local-api.js");
|
|
10
|
-
const
|
|
11
|
-
|
|
10
|
+
const applyModulePath = resolve(projectRoot, "src", "lib", "market", "seeds", "apply.js");
|
|
11
|
+
const applyModule = await import(pathToFileURL(applyModulePath).href);
|
|
12
|
+
if (!existsSync(apiModulePath)) {
|
|
13
|
+
return applyModule;
|
|
14
|
+
}
|
|
15
|
+
const apiModule = await import(pathToFileURL(apiModulePath).href);
|
|
16
|
+
return {
|
|
17
|
+
...applyModule,
|
|
18
|
+
...apiModule
|
|
19
|
+
};
|
|
12
20
|
}
|
|
13
|
-
function
|
|
21
|
+
function sessionExpiresSoon(session) {
|
|
22
|
+
if (!session.expiresAt) return false;
|
|
23
|
+
const expiresAt = Date.parse(session.expiresAt);
|
|
24
|
+
return Number.isFinite(expiresAt) && expiresAt <= Date.now() + 6e4;
|
|
25
|
+
}
|
|
26
|
+
async function requireLocalSeedSession(invocation, context) {
|
|
14
27
|
const selector = marketSelector(invocation) ?? "local";
|
|
15
28
|
const profile = resolveMarketProfile(selector);
|
|
16
|
-
const
|
|
29
|
+
const tenantRoot = marketAuthRoot(context);
|
|
30
|
+
const session = resolveMarketSession(tenantRoot, profile.id);
|
|
17
31
|
if (!session?.accessToken) {
|
|
18
32
|
throw new Error(`Not logged in to market "${profile.id}". Run treeseed auth:login --market ${profile.id}.`);
|
|
19
33
|
}
|
|
34
|
+
if (sessionExpiresSoon(session) && session.refreshToken) {
|
|
35
|
+
try {
|
|
36
|
+
const refreshed = await new MarketClient({ profile, userAgent: "treeseed-cli" }).refreshToken({ refreshToken: session.refreshToken });
|
|
37
|
+
if (refreshed.ok) {
|
|
38
|
+
const nextSession = {
|
|
39
|
+
marketId: profile.id,
|
|
40
|
+
accessToken: refreshed.accessToken,
|
|
41
|
+
refreshToken: refreshed.refreshToken,
|
|
42
|
+
expiresAt: refreshed.expiresAt,
|
|
43
|
+
principal: refreshed.principal
|
|
44
|
+
};
|
|
45
|
+
setMarketSession(tenantRoot, nextSession);
|
|
46
|
+
return { profile, session: nextSession };
|
|
47
|
+
}
|
|
48
|
+
} catch {
|
|
49
|
+
throw new Error(`Login for market "${profile.id}" expired. Run treeseed auth:login --market ${profile.id}.`);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
if (sessionExpiresSoon(session)) {
|
|
53
|
+
throw new Error(`Login for market "${profile.id}" expired. Run treeseed auth:login --market ${profile.id}.`);
|
|
54
|
+
}
|
|
20
55
|
return { profile, session };
|
|
21
56
|
}
|
|
22
57
|
function seedRequestBody(invocation) {
|
|
@@ -127,7 +162,7 @@ async function handleSeedExport(invocation, context) {
|
|
|
127
162
|
const { client } = createMarketClientForInvocation(invocation, context, { requireAuth: true });
|
|
128
163
|
payload = await client.exportSeed(team, body);
|
|
129
164
|
} else {
|
|
130
|
-
const { session } = requireLocalSeedSession(invocation, context);
|
|
165
|
+
const { session } = await requireLocalSeedSession(invocation, context);
|
|
131
166
|
const localModule = await loadLocalSeedModule(context.cwd);
|
|
132
167
|
const exporter = localModule.exportLocalSeedViaApiFromCli ?? localModule.exportSeedFromCli;
|
|
133
168
|
if (typeof exporter !== "function") {
|
|
@@ -201,27 +236,16 @@ const handleSeed = async (invocation, context) => {
|
|
|
201
236
|
}
|
|
202
237
|
};
|
|
203
238
|
}
|
|
204
|
-
const localAuth = planned.plan.environments.every((environment) => environment === "local") && !wantsValidate ? (() => {
|
|
205
|
-
try {
|
|
206
|
-
return requireLocalSeedSession(invocation, context);
|
|
207
|
-
} catch (error) {
|
|
208
|
-
return { error };
|
|
209
|
-
}
|
|
210
|
-
})() : null;
|
|
211
|
-
if (localAuth && "error" in localAuth) {
|
|
212
|
-
return remoteSeedError(localAuth.error, "seed");
|
|
213
|
-
}
|
|
214
239
|
if (!wantsApply && !wantsValidate && planned.plan.environments.length === 1 && planned.plan.environments[0] === "local") {
|
|
215
240
|
try {
|
|
216
241
|
const localModule = await loadLocalSeedModule(context.cwd);
|
|
217
|
-
const localPlanner = localModule.
|
|
242
|
+
const localPlanner = localModule.planLocalSeedFromCli ?? localModule.planLocalSeedViaApiFromCli;
|
|
218
243
|
if (typeof localPlanner === "function") {
|
|
219
244
|
const localPlanned = await localPlanner({
|
|
220
245
|
projectRoot: context.cwd,
|
|
221
246
|
seedName,
|
|
222
247
|
environments: typeof invocation.args.environments === "string" ? invocation.args.environments : void 0,
|
|
223
248
|
mode,
|
|
224
|
-
accessToken: localAuth?.session.accessToken,
|
|
225
249
|
env: context.env
|
|
226
250
|
});
|
|
227
251
|
if (localPlanned.plan) {
|
|
@@ -250,6 +274,12 @@ const handleSeed = async (invocation, context) => {
|
|
|
250
274
|
return remoteSeedError(error, "seed");
|
|
251
275
|
}
|
|
252
276
|
}
|
|
277
|
+
let localAuth;
|
|
278
|
+
try {
|
|
279
|
+
localAuth = await requireLocalSeedSession(invocation, context);
|
|
280
|
+
} catch (error) {
|
|
281
|
+
return remoteSeedError(error, "seed");
|
|
282
|
+
}
|
|
253
283
|
const localModule = await loadLocalSeedModule(context.cwd);
|
|
254
284
|
const runner = localModule.applyLocalSeedViaApiFromCli ?? localModule.applyLocalSeedFromCli;
|
|
255
285
|
if (typeof runner !== "function") {
|
|
@@ -25,6 +25,7 @@ const DEV_RUNTIME_OPTIONS = [
|
|
|
25
25
|
{ name: "surfaces", flags: "--surfaces <surfaces>", description: "Select comma-separated local dev surfaces to run.", kind: "string" },
|
|
26
26
|
{ name: "host", flags: "--host <host>", description: "Host for the web dev server.", kind: "string" },
|
|
27
27
|
{ name: "port", flags: "--port <port>", description: "Port for the web dev server.", kind: "string" },
|
|
28
|
+
{ 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"] },
|
|
28
29
|
{ name: "apiHost", flags: "--api-host <host>", description: "Host used to construct the local API URL.", kind: "string" },
|
|
29
30
|
{ name: "apiPort", flags: "--api-port <port>", description: "Port for the local API server.", kind: "string" },
|
|
30
31
|
{ name: "managerPort", flags: "--manager-port <port>", description: "Port used for the local manager service URL.", kind: "string" },
|
|
@@ -33,6 +34,7 @@ const DEV_RUNTIME_OPTIONS = [
|
|
|
33
34
|
{ 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"] },
|
|
34
35
|
{ name: "plan", flags: "--plan", description: "Print the dev runtime plan and exit without starting services.", kind: "boolean" },
|
|
35
36
|
{ name: "reset", flags: "--reset", description: "Clear local dev runtime state before setup, migrations, and service startup.", kind: "boolean" },
|
|
37
|
+
{ name: "force", flags: "--force", description: "Terminate overlapping Treeseed dev runtimes and listeners on required local dev ports before startup.", kind: "boolean" },
|
|
36
38
|
{ name: "json", flags: "--json", description: "Emit structured JSON or newline-delimited dev events.", kind: "boolean" },
|
|
37
39
|
{ name: "watch", flags: "--watch", description: "Enable live watch behavior. `dev` defaults to live feedback; this remains for compatibility.", kind: "boolean" },
|
|
38
40
|
{ name: "workspaceLinks", flags: "--workspace-links <mode>", description: "Control local workspace package links.", kind: "enum", values: ["auto", "off"] }
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@treeseed/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.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.9.0",
|
|
49
49
|
"ink": "^7.0.0",
|
|
50
50
|
"react": "^19.2.5"
|
|
51
51
|
},
|