@smithers-orchestrator/cli 0.16.9 → 0.17.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/package.json +21 -12
- package/src/InitWorkflowPackOptions.ts +2 -0
- package/src/InitWorkflowPackResult.ts +8 -2
- package/src/agent-commands/agentAddWizard.js +190 -0
- package/src/agent-commands/regenerateAgentsTsIfPresent.js +28 -0
- package/src/agent-commands/runAgentAdd.js +147 -0
- package/src/agent-detection.js +214 -17
- package/src/hijack-session.js +1 -1
- package/src/index.js +526 -23
- package/src/mcp/semantic-tools.js +1 -1
- package/src/mdx-plugin.js +6 -0
- package/src/output.js +52 -0
- package/src/smithersRuntime.js +2 -1
- package/src/util/logger.ts +97 -0
- package/src/workflow-pack.js +151 -16
package/src/output.js
CHANGED
|
@@ -8,6 +8,9 @@ import { NodeOutputRouteError } from "@smithers-orchestrator/server/gatewayRoute
|
|
|
8
8
|
import { EXIT_OK } from "./util/exitCodes.js";
|
|
9
9
|
import { formatCliErrorForStderr, getCliErrorMapping } from "./util/errorMessage.js";
|
|
10
10
|
|
|
11
|
+
const RUN_ID_PATTERN = /^[a-z0-9_-]{1,64}$/;
|
|
12
|
+
const NODE_ID_PATTERN = /^[a-zA-Z0-9:_-]{1,128}$/;
|
|
13
|
+
|
|
11
14
|
/**
|
|
12
15
|
* @param {any} response
|
|
13
16
|
* @returns {string}
|
|
@@ -69,6 +72,52 @@ async function resolveLatestIteration(adapter, runId, nodeId) {
|
|
|
69
72
|
}
|
|
70
73
|
}
|
|
71
74
|
|
|
75
|
+
/**
|
|
76
|
+
* @param {Record<string, unknown> | null} row
|
|
77
|
+
* @returns {Record<string, unknown> | null}
|
|
78
|
+
*/
|
|
79
|
+
function stripOutputKeyColumns(row) {
|
|
80
|
+
if (!row || typeof row !== "object") {
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
const result = { ...row };
|
|
84
|
+
delete result.run_id;
|
|
85
|
+
delete result.runId;
|
|
86
|
+
delete result.node_id;
|
|
87
|
+
delete result.nodeId;
|
|
88
|
+
delete result.iteration;
|
|
89
|
+
return result;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* @param {RunOutputCommandInput} input
|
|
94
|
+
* @param {number} iteration
|
|
95
|
+
* @returns {Promise<RunOutputCommandResult>}
|
|
96
|
+
*/
|
|
97
|
+
async function runRawJsonOutput(input, iteration) {
|
|
98
|
+
if (!RUN_ID_PATTERN.test(input.runId)) {
|
|
99
|
+
throw new NodeOutputRouteError("InvalidRunId", "runId must match /^[a-z0-9_-]{1,64}$/.");
|
|
100
|
+
}
|
|
101
|
+
if (!NODE_ID_PATTERN.test(input.nodeId)) {
|
|
102
|
+
throw new NodeOutputRouteError("InvalidNodeId", "nodeId must match /^[a-zA-Z0-9:_-]{1,128}$/.");
|
|
103
|
+
}
|
|
104
|
+
const run = await input.adapter.getRun(input.runId);
|
|
105
|
+
if (!run) {
|
|
106
|
+
throw new NodeOutputRouteError("RunNotFound", `Run not found: ${input.runId}`);
|
|
107
|
+
}
|
|
108
|
+
const node = await input.adapter.getNode(input.runId, input.nodeId, iteration);
|
|
109
|
+
if (!node) {
|
|
110
|
+
throw new NodeOutputRouteError("NodeNotFound", `Node not found: ${input.nodeId}`);
|
|
111
|
+
}
|
|
112
|
+
const outputTable = typeof node.outputTable === "string" ? node.outputTable.trim() : "";
|
|
113
|
+
if (!outputTable) {
|
|
114
|
+
throw new NodeOutputRouteError("NodeHasNoOutput", `Node ${input.nodeId} has no output table.`);
|
|
115
|
+
}
|
|
116
|
+
const row = await input.adapter.getRawNodeOutputForIteration(outputTable, input.runId, input.nodeId, iteration);
|
|
117
|
+
input.stdout.write(`${JSON.stringify(stripOutputKeyColumns(row))}\n`);
|
|
118
|
+
return { exitCode: EXIT_OK };
|
|
119
|
+
}
|
|
120
|
+
|
|
72
121
|
/**
|
|
73
122
|
* @param {RunOutputCommandInput} input
|
|
74
123
|
* @returns {Promise<RunOutputCommandResult>}
|
|
@@ -80,6 +129,9 @@ export async function runOutputOnce(input) {
|
|
|
80
129
|
iteration = latest ?? 0;
|
|
81
130
|
}
|
|
82
131
|
try {
|
|
132
|
+
if (input.json && !input.pretty) {
|
|
133
|
+
return await runRawJsonOutput(input, iteration);
|
|
134
|
+
}
|
|
83
135
|
const response = await getNodeOutputRoute({
|
|
84
136
|
runId: input.runId,
|
|
85
137
|
nodeId: input.nodeId,
|
package/src/smithersRuntime.js
CHANGED
|
@@ -3,10 +3,11 @@ import { Cause, Effect, Exit, Layer, ManagedRuntime } from "effect";
|
|
|
3
3
|
import { SchedulerLive, WorkflowSessionLive } from "@smithers-orchestrator/scheduler";
|
|
4
4
|
import { CorrelationContextLive, MetricsServiceLive, TracingServiceLive, createSmithersRuntimeLayer, getCurrentSmithersTraceAnnotations, getCurrentSmithersTraceSpan, } from "@smithers-orchestrator/observability";
|
|
5
5
|
import { toSmithersError } from "@smithers-orchestrator/errors/toSmithersError";
|
|
6
|
+
import { SmithersLoggerLayer } from "./util/logger.ts";
|
|
6
7
|
const ObservabilityLayer = Layer.mergeAll(CorrelationContextLive, MetricsServiceLive, TracingServiceLive);
|
|
7
8
|
const SmithersCoreLayer = Layer.mergeAll(ObservabilityLayer, SchedulerLive.pipe(Layer.provide(ObservabilityLayer)), WorkflowSessionLive);
|
|
8
9
|
const SmithersWorkflowEngineLayer = Layer.suspend(() => WorkflowEngine.layerMemory);
|
|
9
|
-
const SmithersRuntimeLayer = Layer.mergeAll(SmithersCoreLayer, SmithersWorkflowEngineLayer, createSmithersRuntimeLayer()).pipe(Layer.orDie);
|
|
10
|
+
const SmithersRuntimeLayer = Layer.mergeAll(SmithersLoggerLayer, SmithersCoreLayer, SmithersWorkflowEngineLayer, createSmithersRuntimeLayer()).pipe(Layer.orDie);
|
|
10
11
|
const runtime = ManagedRuntime.make(SmithersRuntimeLayer);
|
|
11
12
|
/**
|
|
12
13
|
* @template A, E, R
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { format } from "node:util";
|
|
2
|
+
import { Logger } from "effect";
|
|
3
|
+
|
|
4
|
+
type JsonModeState = {
|
|
5
|
+
jsonMode: boolean;
|
|
6
|
+
consoleRoutingInstalled: boolean;
|
|
7
|
+
originalConsole?: {
|
|
8
|
+
debug: typeof console.debug;
|
|
9
|
+
error: typeof console.error;
|
|
10
|
+
info: typeof console.info;
|
|
11
|
+
log: typeof console.log;
|
|
12
|
+
trace: typeof console.trace;
|
|
13
|
+
warn: typeof console.warn;
|
|
14
|
+
};
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
const STATE_KEY = Symbol.for("smithers.cli.jsonMode");
|
|
18
|
+
|
|
19
|
+
function getState(): JsonModeState {
|
|
20
|
+
const globalState = globalThis as typeof globalThis & {
|
|
21
|
+
[STATE_KEY]?: JsonModeState;
|
|
22
|
+
};
|
|
23
|
+
globalState[STATE_KEY] ??= {
|
|
24
|
+
jsonMode: false,
|
|
25
|
+
consoleRoutingInstalled: false,
|
|
26
|
+
};
|
|
27
|
+
return globalState[STATE_KEY];
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function setJsonMode(enabled: boolean): void {
|
|
31
|
+
getState().jsonMode = enabled;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function isJsonMode(): boolean {
|
|
35
|
+
return getState().jsonMode === true;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function writeConsoleArgsToStderr(args: ReadonlyArray<unknown>): void {
|
|
39
|
+
process.stderr.write(`${format(...args)}\n`);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function installJsonModeConsoleRouting(): void {
|
|
43
|
+
const state = getState();
|
|
44
|
+
if (state.consoleRoutingInstalled) {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const originalConsole = {
|
|
49
|
+
debug: console.debug.bind(console),
|
|
50
|
+
error: console.error.bind(console),
|
|
51
|
+
info: console.info.bind(console),
|
|
52
|
+
log: console.log.bind(console),
|
|
53
|
+
trace: console.trace.bind(console),
|
|
54
|
+
warn: console.warn.bind(console),
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
console.debug = (...args: unknown[]) => {
|
|
58
|
+
if (isJsonMode()) return writeConsoleArgsToStderr(args);
|
|
59
|
+
return originalConsole.debug(...args);
|
|
60
|
+
};
|
|
61
|
+
console.error = (...args: unknown[]) => {
|
|
62
|
+
if (isJsonMode()) return writeConsoleArgsToStderr(args);
|
|
63
|
+
return originalConsole.error(...args);
|
|
64
|
+
};
|
|
65
|
+
console.info = (...args: unknown[]) => {
|
|
66
|
+
if (isJsonMode()) return writeConsoleArgsToStderr(args);
|
|
67
|
+
return originalConsole.info(...args);
|
|
68
|
+
};
|
|
69
|
+
console.log = (...args: unknown[]) => {
|
|
70
|
+
if (isJsonMode()) return writeConsoleArgsToStderr(args);
|
|
71
|
+
return originalConsole.log(...args);
|
|
72
|
+
};
|
|
73
|
+
console.trace = (...args: unknown[]) => {
|
|
74
|
+
if (isJsonMode()) return writeConsoleArgsToStderr(args);
|
|
75
|
+
return originalConsole.trace(...args);
|
|
76
|
+
};
|
|
77
|
+
console.warn = (...args: unknown[]) => {
|
|
78
|
+
if (isJsonMode()) return writeConsoleArgsToStderr(args);
|
|
79
|
+
return originalConsole.warn(...args);
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
state.originalConsole = originalConsole;
|
|
83
|
+
state.consoleRoutingInstalled = true;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export const smithersEffectLogger = Logger.make<unknown, void>((options) => {
|
|
87
|
+
const line = Logger.stringLogger.log(options);
|
|
88
|
+
const stream = isJsonMode() ? process.stderr : process.stdout;
|
|
89
|
+
stream.write(`${line}\n`);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
export const SmithersLoggerLayer = Logger.replace(
|
|
93
|
+
Logger.defaultLogger,
|
|
94
|
+
smithersEffectLogger,
|
|
95
|
+
);
|
|
96
|
+
|
|
97
|
+
installJsonModeConsoleRouting();
|
package/src/workflow-pack.js
CHANGED
|
@@ -4,7 +4,7 @@ import { dirname, resolve } from "node:path";
|
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
5
|
import { generateAgentsTs } from "./agent-detection.js";
|
|
6
6
|
/**
|
|
7
|
-
* @typedef {{ force?: boolean; rootDir?: string; skipInstall?: boolean; }} InitOptions
|
|
7
|
+
* @typedef {{ force?: boolean; rootDir?: string; skipInstall?: boolean; agentsOnly?: boolean; }} InitOptions
|
|
8
8
|
*/
|
|
9
9
|
/**
|
|
10
10
|
* @typedef {{ status: "ok" | "skipped" | "failed"; reason?: string; }} InitInstallResult
|
|
@@ -15,6 +15,9 @@ import { generateAgentsTs } from "./agent-detection.js";
|
|
|
15
15
|
/**
|
|
16
16
|
* @typedef {{ command: string; description: string; }} WorkflowCta
|
|
17
17
|
*/
|
|
18
|
+
/**
|
|
19
|
+
* @typedef {{ path: string; contents: string; preserveExisting?: boolean; }} TemplateFile
|
|
20
|
+
*/
|
|
18
21
|
|
|
19
22
|
/**
|
|
20
23
|
* @param {string} path
|
|
@@ -78,6 +81,7 @@ const BUNDLED_VERSION_PINS = {
|
|
|
78
81
|
reactTypes: "19.2.14",
|
|
79
82
|
reactDomTypes: "19.2.3",
|
|
80
83
|
mdxTypes: "2.0.13",
|
|
84
|
+
nodeTypes: "25.6.0",
|
|
81
85
|
};
|
|
82
86
|
/**
|
|
83
87
|
* @returns {DependencyVersions}
|
|
@@ -90,6 +94,7 @@ function readDependencyVersions() {
|
|
|
90
94
|
reactTypesVersion: resolveDependencyVersion("@types/react", BUNDLED_VERSION_PINS.reactTypes),
|
|
91
95
|
reactDomTypesVersion: resolveDependencyVersion("@types/react-dom", BUNDLED_VERSION_PINS.reactDomTypes),
|
|
92
96
|
mdxTypesVersion: resolveDependencyVersion("@types/mdx", BUNDLED_VERSION_PINS.mdxTypes),
|
|
97
|
+
nodeTypesVersion: resolveDependencyVersion("@types/node", BUNDLED_VERSION_PINS.nodeTypes),
|
|
93
98
|
};
|
|
94
99
|
}
|
|
95
100
|
/**
|
|
@@ -116,6 +121,7 @@ function renderPackageJson(versions) {
|
|
|
116
121
|
"@types/react": versions.reactTypesVersion,
|
|
117
122
|
"@types/react-dom": versions.reactDomTypesVersion,
|
|
118
123
|
"@types/mdx": versions.mdxTypesVersion,
|
|
124
|
+
"@types/node": versions.nodeTypesVersion,
|
|
119
125
|
},
|
|
120
126
|
}, null, 2) + "\n";
|
|
121
127
|
}
|
|
@@ -143,6 +149,104 @@ function renderTsconfig() {
|
|
|
143
149
|
exclude: ["./executions/**/*"],
|
|
144
150
|
}, null, 2) + "\n";
|
|
145
151
|
}
|
|
152
|
+
/**
|
|
153
|
+
* @returns {TemplateFile[]}
|
|
154
|
+
*/
|
|
155
|
+
function renderAgentScaffoldFiles() {
|
|
156
|
+
return [
|
|
157
|
+
{
|
|
158
|
+
path: ".smithers/agents/claude-code.ts",
|
|
159
|
+
preserveExisting: true,
|
|
160
|
+
contents: [
|
|
161
|
+
'import { ClaudeCodeAgent as SmithersClaudeCodeAgent } from "smithers-orchestrator";',
|
|
162
|
+
"",
|
|
163
|
+
'// Built-in Claude Code CLI agent (cliEngine: "claude-code").',
|
|
164
|
+
"// Tweak `model`, `cwd`, or uncomment extra options below to match your setup.",
|
|
165
|
+
"export const ClaudeCodeAgent = new SmithersClaudeCodeAgent({",
|
|
166
|
+
' model: "claude-opus-4-6",',
|
|
167
|
+
" cwd: process.cwd(),",
|
|
168
|
+
' // systemPrompt: "Add shared instructions for every Claude run.",',
|
|
169
|
+
" // timeoutMs: 10 * 60 * 1000,",
|
|
170
|
+
" // dangerouslySkipPermissions: true,",
|
|
171
|
+
"});",
|
|
172
|
+
"",
|
|
173
|
+
].join("\n"),
|
|
174
|
+
},
|
|
175
|
+
{
|
|
176
|
+
path: ".smithers/agents/codex.ts",
|
|
177
|
+
preserveExisting: true,
|
|
178
|
+
contents: [
|
|
179
|
+
'import { CodexAgent as SmithersCodexAgent } from "smithers-orchestrator";',
|
|
180
|
+
"",
|
|
181
|
+
'// Built-in Codex CLI agent (cliEngine: "codex").',
|
|
182
|
+
"// Tweak `model`, `cwd`, or uncomment extra options below to match your setup.",
|
|
183
|
+
"export const CodexAgent = new SmithersCodexAgent({",
|
|
184
|
+
' model: "gpt-5.3-codex",',
|
|
185
|
+
" cwd: process.cwd(),",
|
|
186
|
+
" skipGitRepoCheck: true,",
|
|
187
|
+
' // systemPrompt: "Add shared instructions for every Codex run.",',
|
|
188
|
+
' // sandbox: "workspace-write",',
|
|
189
|
+
" // fullAuto: true,",
|
|
190
|
+
"});",
|
|
191
|
+
"",
|
|
192
|
+
].join("\n"),
|
|
193
|
+
},
|
|
194
|
+
{
|
|
195
|
+
path: ".smithers/agents/gemini.ts",
|
|
196
|
+
preserveExisting: true,
|
|
197
|
+
contents: [
|
|
198
|
+
'import { GeminiAgent as SmithersGeminiAgent } from "smithers-orchestrator";',
|
|
199
|
+
"",
|
|
200
|
+
'// Built-in Gemini CLI agent (cliEngine: "gemini").',
|
|
201
|
+
"// Tweak `model`, `cwd`, or uncomment extra options below to match your setup.",
|
|
202
|
+
"export const GeminiAgent = new SmithersGeminiAgent({",
|
|
203
|
+
' model: "gemini-3.1-pro-preview",',
|
|
204
|
+
" cwd: process.cwd(),",
|
|
205
|
+
' // systemPrompt: "Add shared instructions for every Gemini run.",',
|
|
206
|
+
' // approvalMode: "yolo",',
|
|
207
|
+
' // allowedTools: ["read_file", "write_file"],',
|
|
208
|
+
"});",
|
|
209
|
+
"",
|
|
210
|
+
].join("\n"),
|
|
211
|
+
},
|
|
212
|
+
{
|
|
213
|
+
path: ".smithers/agents/index.ts",
|
|
214
|
+
preserveExisting: true,
|
|
215
|
+
contents: [
|
|
216
|
+
'export { ClaudeCodeAgent } from "./claude-code";',
|
|
217
|
+
'export { CodexAgent } from "./codex";',
|
|
218
|
+
'export { GeminiAgent } from "./gemini";',
|
|
219
|
+
"",
|
|
220
|
+
].join("\n"),
|
|
221
|
+
},
|
|
222
|
+
{
|
|
223
|
+
path: ".smithers/agents/README.md",
|
|
224
|
+
preserveExisting: true,
|
|
225
|
+
contents: [
|
|
226
|
+
"# Agent Config",
|
|
227
|
+
"",
|
|
228
|
+
"These files export the configured agent instances used by your Smithers workflows.",
|
|
229
|
+
"",
|
|
230
|
+
"- `claude-code.ts`, `codex.ts`, and `gemini.ts` are user-owned config.",
|
|
231
|
+
"- Edit them to pin models, set `cwd`, add a shared `systemPrompt`, or enable engine-specific flags.",
|
|
232
|
+
"- `index.ts` re-exports all three so root-level files can import from `./agents`.",
|
|
233
|
+
"",
|
|
234
|
+
"Examples:",
|
|
235
|
+
"",
|
|
236
|
+
"```ts",
|
|
237
|
+
'import { ClaudeCodeAgent } from "./agents";',
|
|
238
|
+
'import { CodexAgent } from "./agents/codex";',
|
|
239
|
+
"```",
|
|
240
|
+
"",
|
|
241
|
+
"Inside `.smithers/workflows/*`, use `../agents` or `../agents/<name>` instead.",
|
|
242
|
+
"",
|
|
243
|
+
"`smithers init` and `smithers init --agents-only` only create missing files in this directory.",
|
|
244
|
+
"Existing files here are left alone so your custom agent config is preserved.",
|
|
245
|
+
"",
|
|
246
|
+
].join("\n"),
|
|
247
|
+
},
|
|
248
|
+
];
|
|
249
|
+
}
|
|
146
250
|
/**
|
|
147
251
|
* @returns {TemplateFile[]}
|
|
148
252
|
*/
|
|
@@ -2046,6 +2150,21 @@ function renderTemplateFiles(versions, env) {
|
|
|
2046
2150
|
path: ".smithers/tsconfig.json",
|
|
2047
2151
|
contents: renderTsconfig(),
|
|
2048
2152
|
},
|
|
2153
|
+
{
|
|
2154
|
+
path: ".smithers/types/assets.d.ts",
|
|
2155
|
+
contents: [
|
|
2156
|
+
'declare module "*.md" {',
|
|
2157
|
+
" const Component: any;",
|
|
2158
|
+
" export default Component;",
|
|
2159
|
+
"}",
|
|
2160
|
+
"",
|
|
2161
|
+
'declare module "*.mdx" {',
|
|
2162
|
+
" const Component: any;",
|
|
2163
|
+
" export default Component;",
|
|
2164
|
+
"}",
|
|
2165
|
+
"",
|
|
2166
|
+
].join("\n"),
|
|
2167
|
+
},
|
|
2049
2168
|
{
|
|
2050
2169
|
path: ".smithers/bunfig.toml",
|
|
2051
2170
|
contents: ['preload = ["./preload.ts"]', ""].join("\n"),
|
|
@@ -2054,6 +2173,7 @@ function renderTemplateFiles(versions, env) {
|
|
|
2054
2173
|
path: ".smithers/preload.ts",
|
|
2055
2174
|
contents: ['import { mdxPlugin } from "smithers-orchestrator";', "", "mdxPlugin();", ""].join("\n"),
|
|
2056
2175
|
},
|
|
2176
|
+
...renderAgentScaffoldFiles(),
|
|
2057
2177
|
{
|
|
2058
2178
|
path: ".smithers/agents.ts",
|
|
2059
2179
|
contents: generateAgentsTs(env),
|
|
@@ -2085,35 +2205,50 @@ function renderTemplateFiles(versions, env) {
|
|
|
2085
2205
|
* @returns {InitResult}
|
|
2086
2206
|
*/
|
|
2087
2207
|
export function initWorkflowPack(options = {}) {
|
|
2088
|
-
const
|
|
2208
|
+
const projectRoot = options.rootDir ?? process.cwd();
|
|
2209
|
+
const rootDir = resolve(projectRoot, ".smithers");
|
|
2089
2210
|
const writtenFiles = [];
|
|
2090
2211
|
const skippedFiles = [];
|
|
2091
2212
|
const preservedPaths = [];
|
|
2092
|
-
const versions = readDependencyVersions();
|
|
2093
|
-
const env = process.env;
|
|
2094
2213
|
ensureDir(rootDir);
|
|
2095
|
-
ensureDir(resolve(rootDir, "
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
if (existsSync(executionsDir)) {
|
|
2101
|
-
preservedPaths.push(executionsDir);
|
|
2214
|
+
ensureDir(resolve(rootDir, "agents"));
|
|
2215
|
+
/** @type {TemplateFile[]} */
|
|
2216
|
+
let templateFiles;
|
|
2217
|
+
if (options.agentsOnly) {
|
|
2218
|
+
templateFiles = renderAgentScaffoldFiles();
|
|
2102
2219
|
}
|
|
2103
2220
|
else {
|
|
2104
|
-
|
|
2221
|
+
const versions = readDependencyVersions();
|
|
2222
|
+
const env = process.env;
|
|
2223
|
+
ensureDir(resolve(rootDir, "prompts"));
|
|
2224
|
+
ensureDir(resolve(rootDir, "components"));
|
|
2225
|
+
ensureDir(resolve(rootDir, "workflows"));
|
|
2226
|
+
ensureDir(resolve(rootDir, "tickets"));
|
|
2227
|
+
const executionsDir = resolve(rootDir, "executions");
|
|
2228
|
+
if (existsSync(executionsDir)) {
|
|
2229
|
+
preservedPaths.push(executionsDir);
|
|
2230
|
+
}
|
|
2231
|
+
else {
|
|
2232
|
+
ensureDir(executionsDir);
|
|
2233
|
+
}
|
|
2234
|
+
templateFiles = renderTemplateFiles(versions, env);
|
|
2105
2235
|
}
|
|
2106
|
-
for (const file of
|
|
2107
|
-
const absolutePath = resolve(
|
|
2236
|
+
for (const file of templateFiles) {
|
|
2237
|
+
const absolutePath = resolve(projectRoot, file.path);
|
|
2108
2238
|
ensureParent(absolutePath);
|
|
2109
|
-
if (existsSync(absolutePath) && !options.force) {
|
|
2239
|
+
if (existsSync(absolutePath) && (file.preserveExisting || !options.force)) {
|
|
2110
2240
|
skippedFiles.push(absolutePath);
|
|
2241
|
+
if (file.preserveExisting) {
|
|
2242
|
+
process.stderr.write(`[smithers:init] ${file.path} skipped: already exists\n`);
|
|
2243
|
+
}
|
|
2111
2244
|
continue;
|
|
2112
2245
|
}
|
|
2113
2246
|
writeFileSync(absolutePath, file.contents, "utf8");
|
|
2114
2247
|
writtenFiles.push(absolutePath);
|
|
2115
2248
|
}
|
|
2116
|
-
const install =
|
|
2249
|
+
const install = options.agentsOnly
|
|
2250
|
+
? { status: "skipped", reason: "agents-only" }
|
|
2251
|
+
: runBunInstall(rootDir, options.skipInstall ?? false);
|
|
2117
2252
|
return {
|
|
2118
2253
|
rootDir,
|
|
2119
2254
|
writtenFiles,
|