@treeseed/cli 0.6.46 → 0.6.47

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.
@@ -44,9 +44,9 @@ function formatSavePlanSections(repositoryPlan) {
44
44
  }
45
45
  const handleSave = async (invocation, context) => {
46
46
  try {
47
+ const progressWrite = context.outputFormat === "json" ? ((output) => context.write(output, "stderr")) : context.write;
47
48
  const result = await createWorkflowSdk(context, {
48
- write: context.outputFormat === "json" ? (() => {
49
- }) : context.write
49
+ write: progressWrite
50
50
  }).save({
51
51
  message: invocation.positionals.join(" ").trim(),
52
52
  hotfix: invocation.args.hotfix === true,
@@ -3,7 +3,8 @@ import {
3
3
  resolveTreeseedLaunchEnvironment,
4
4
  resolveTreeseedToolCommand
5
5
  } from "@treeseed/sdk/workflow-support";
6
- import { existsSync, readFileSync } from "node:fs";
6
+ import { existsSync, mkdtempSync, readFileSync, rmSync } from "node:fs";
7
+ import { tmpdir } from "node:os";
7
8
  import { join } from "node:path";
8
9
  import { workflowErrorResult } from "./workflow.js";
9
10
  const WRAPPED_TOOLS = /* @__PURE__ */ new Set(["gh", "railway", "wrangler"]);
@@ -54,6 +55,34 @@ function findRailwayProjectId(value) {
54
55
  }
55
56
  return null;
56
57
  }
58
+ function findRailwayProjectIdFromCommand(value) {
59
+ if (!value || typeof value !== "object") {
60
+ return null;
61
+ }
62
+ if (Array.isArray(value)) {
63
+ for (const entry of value) {
64
+ const found = findRailwayProjectIdFromCommand(entry);
65
+ if (found) {
66
+ return found;
67
+ }
68
+ }
69
+ return null;
70
+ }
71
+ const record = value;
72
+ if (typeof record.lastDeploymentCommand === "string") {
73
+ const match = record.lastDeploymentCommand.match(/--project\s+([0-9a-f]{8}-[0-9a-f-]{27,})/iu);
74
+ if (match?.[1]) {
75
+ return match[1];
76
+ }
77
+ }
78
+ for (const entry of Object.values(record)) {
79
+ const found = findRailwayProjectIdFromCommand(entry);
80
+ if (found) {
81
+ return found;
82
+ }
83
+ }
84
+ return null;
85
+ }
57
86
  function railwayProjectIdFromDeployState(cwd, scope) {
58
87
  const stateScope = scope === "prod" ? "prod" : scope;
59
88
  const statePath = join(cwd, ".treeseed", "state", "environments", stateScope, "deploy.json");
@@ -61,12 +90,18 @@ function railwayProjectIdFromDeployState(cwd, scope) {
61
90
  return null;
62
91
  }
63
92
  try {
64
- return findRailwayProjectId(JSON.parse(readFileSync(statePath, "utf8")));
93
+ const state = JSON.parse(readFileSync(statePath, "utf8"));
94
+ return findRailwayProjectIdFromCommand(state) ?? findRailwayProjectId(state);
65
95
  } catch {
66
96
  return null;
67
97
  }
68
98
  }
99
+ function railwayCommandUsesProjectFiles(args) {
100
+ const command = args[0] ?? "";
101
+ return ["up", "dev", "develop", "run", "local", "shell"].includes(command);
102
+ }
69
103
  const handleToolWrapper = (invocation, context) => {
104
+ let isolatedRailwayCwd = null;
70
105
  try {
71
106
  const toolName = wrappedToolName(invocation.commandName);
72
107
  const scope = wrapperScope(invocation.args.environment);
@@ -101,8 +136,14 @@ const handleToolWrapper = (invocation, context) => {
101
136
  if (toolName === "railway" && scope !== "local" && targetArgs[0] !== "link") {
102
137
  const environmentName = railwayEnvironmentName(scope);
103
138
  const projectId = managedEnv.TREESEED_RAILWAY_PROJECT_ID || railwayProjectIdFromDeployState(context.cwd, scope);
139
+ const railwayCwd = railwayCommandUsesProjectFiles(targetArgs) ? context.cwd : isolatedRailwayCwd = mkdtempSync(join(tmpdir(), `treeseed-railway-${scope}-`));
140
+ const railwayEnv = isolatedRailwayCwd ? {
141
+ ...managedEnv,
142
+ HOME: isolatedRailwayCwd,
143
+ XDG_CONFIG_HOME: join(isolatedRailwayCwd, ".config")
144
+ } : managedEnv;
104
145
  if (projectId) {
105
- context.spawn(resolved.command, [
146
+ const linkResult = context.spawn(resolved.command, [
106
147
  ...resolved.argsPrefix,
107
148
  "link",
108
149
  "--project",
@@ -111,44 +152,72 @@ const handleToolWrapper = (invocation, context) => {
111
152
  environmentName,
112
153
  "--json"
113
154
  ], {
114
- cwd: context.cwd,
115
- env: managedEnv,
155
+ cwd: railwayCwd,
156
+ env: railwayEnv,
116
157
  stdio: "pipe"
117
158
  });
159
+ if ((linkResult.status ?? 1) !== 0) {
160
+ return {
161
+ exitCode: linkResult.status ?? 1,
162
+ stderr: [`Failed to link Railway project ${projectId} for ${environmentName} before running ${targetArgs.join(" ") || "railway"}.`],
163
+ report: {
164
+ command: toolName,
165
+ ok: false,
166
+ scope,
167
+ executable: resolved.command,
168
+ binaryPath: resolved.binaryPath,
169
+ argsPrefix: resolved.argsPrefix,
170
+ args: targetArgs,
171
+ projectLink: {
172
+ projectId,
173
+ environment: environmentName,
174
+ status: linkResult.status ?? 1
175
+ }
176
+ }
177
+ };
178
+ }
118
179
  }
119
- const environmentResult = context.spawn(resolved.command, [
120
- ...resolved.argsPrefix,
121
- "environment",
122
- environmentName,
123
- "--json"
124
- ], {
125
- cwd: context.cwd,
126
- env: managedEnv,
127
- stdio: "pipe"
128
- });
129
- if ((environmentResult.status ?? 1) !== 0) {
130
- return {
131
- exitCode: environmentResult.status ?? 1,
132
- stderr: [`Failed to select Railway environment ${railwayEnvironmentName(scope)} before running ${targetArgs.join(" ") || "railway"}.`],
133
- report: {
134
- command: toolName,
135
- ok: false,
136
- scope,
137
- executable: resolved.command,
138
- binaryPath: resolved.binaryPath,
139
- argsPrefix: resolved.argsPrefix,
140
- args: targetArgs,
141
- environmentSelection: {
142
- environment: environmentName,
143
- status: environmentResult.status ?? 1
180
+ if (!(isolatedRailwayCwd && projectId)) {
181
+ const environmentResult = context.spawn(resolved.command, [
182
+ ...resolved.argsPrefix,
183
+ "environment",
184
+ environmentName,
185
+ "--json"
186
+ ], {
187
+ cwd: railwayCwd,
188
+ env: railwayEnv,
189
+ stdio: "pipe"
190
+ });
191
+ if ((environmentResult.status ?? 1) !== 0) {
192
+ return {
193
+ exitCode: environmentResult.status ?? 1,
194
+ stderr: [`Failed to select Railway environment ${railwayEnvironmentName(scope)} before running ${targetArgs.join(" ") || "railway"}.`],
195
+ report: {
196
+ command: toolName,
197
+ ok: false,
198
+ scope,
199
+ executable: resolved.command,
200
+ binaryPath: resolved.binaryPath,
201
+ argsPrefix: resolved.argsPrefix,
202
+ args: targetArgs,
203
+ environmentSelection: {
204
+ environment: environmentName,
205
+ status: environmentResult.status ?? 1
206
+ }
144
207
  }
145
- }
146
- };
208
+ };
209
+ }
147
210
  }
148
211
  }
212
+ const railwayTargetCwd = toolName === "railway" && isolatedRailwayCwd ? isolatedRailwayCwd : context.cwd;
213
+ const targetEnv = toolName === "railway" && isolatedRailwayCwd ? {
214
+ ...managedEnv,
215
+ HOME: isolatedRailwayCwd,
216
+ XDG_CONFIG_HOME: join(isolatedRailwayCwd, ".config")
217
+ } : managedEnv;
149
218
  const result = context.spawn(resolved.command, [...resolved.argsPrefix, ...targetArgs], {
150
- cwd: context.cwd,
151
- env: managedEnv,
219
+ cwd: railwayTargetCwd,
220
+ env: targetEnv,
152
221
  stdio: "inherit"
153
222
  });
154
223
  return {
@@ -166,6 +235,13 @@ const handleToolWrapper = (invocation, context) => {
166
235
  };
167
236
  } catch (error) {
168
237
  return workflowErrorResult(error);
238
+ } finally {
239
+ if (isolatedRailwayCwd) {
240
+ try {
241
+ rmSync(isolatedRailwayCwd, { recursive: true, force: true });
242
+ } catch {
243
+ }
244
+ }
169
245
  }
170
246
  };
171
247
  export {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@treeseed/cli",
3
- "version": "0.6.46",
3
+ "version": "0.6.47",
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.6.50",
48
+ "@treeseed/sdk": "0.6.51",
49
49
  "ink": "^7.0.0",
50
50
  "react": "^19.2.5"
51
51
  },