march-cli 0.1.28 → 0.1.30
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 +1 -1
- package/src/agent/runner.mjs +1 -1
- package/src/agent/runtime/runner-runtime-host.mjs +1 -0
- package/src/agent/session/session-options.mjs +2 -1
- package/src/agent/tools.mjs +3 -1
- package/src/browser/cli/command.mjs +61 -0
- package/src/browser/cli/open-url.mjs +21 -0
- package/src/browser/client/http.mjs +18 -0
- package/src/browser/client/lifecycle.mjs +57 -0
- package/src/browser/client/rpc.mjs +8 -0
- package/src/browser/client/state.mjs +35 -0
- package/src/browser/daemon/constants.mjs +3 -0
- package/src/browser/daemon/entry.mjs +28 -0
- package/src/browser/daemon/server.mjs +146 -0
- package/src/browser/extension/background.js +225 -0
- package/src/browser/extension/errors.js +19 -0
- package/src/browser/extension/execute-code.js +53 -0
- package/src/browser/extension/manifest.json +15 -0
- package/src/browser/extension-install.mjs +21 -0
- package/src/browser/tools/index.mjs +89 -0
- package/src/cli/args.mjs +4 -1
- package/src/cli/commands/help-command.mjs +1 -1
- package/src/cli/fallback-ui.mjs +0 -2
- package/src/cli/input/autocomplete.mjs +0 -1
- package/src/cli/slash-commands.mjs +5 -6
- package/src/cli/tui/input/mouse-selection-controller.mjs +2 -3
- package/src/cli/tui/layout/main-pane-layout.mjs +3 -2
- package/src/cli/tui/output/selectable-copy.mjs +107 -0
- package/src/cli/tui/output-buffer.mjs +57 -93
- package/src/cli/tui/selection-screen.mjs +30 -0
- package/src/cli/ui.mjs +3 -16
- package/src/main.mjs +14 -10
- package/src/memory/root.mjs +7 -0
|
@@ -4,12 +4,9 @@ import { renderMarkdown, renderStreamingMarkdown } from "./markdown-renderer.mjs
|
|
|
4
4
|
import { renderEditDiffBlock } from "./tui-diff-rendering.mjs";
|
|
5
5
|
import { OutputScrollState } from "./output/scroll-state.mjs";
|
|
6
6
|
import { appendTextLines, wrapLine } from "./output/text-line-renderer.mjs";
|
|
7
|
-
import {
|
|
7
|
+
import { appendSelectableEntries, copySourceTextForRange, sliceEntriesWithTail } from "./output/selectable-copy.mjs";
|
|
8
8
|
|
|
9
9
|
const SPINNER_FRAMES = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
10
|
function currentTextToBlocks(textLines, sealed, cache = null) {
|
|
14
11
|
const blocks = [];
|
|
15
12
|
for (let i = 0; i < textLines.length;) {
|
|
@@ -72,13 +69,11 @@ export class OutputBuffer {
|
|
|
72
69
|
this._activeThinking = null;
|
|
73
70
|
this.overlayStatus = null;
|
|
74
71
|
this.scrollState = new OutputScrollState();
|
|
75
|
-
this._segmentLinesCache = new Map();
|
|
76
72
|
this._baseLinesCache = new Map();
|
|
73
|
+
this._baseEntriesCache = new Map();
|
|
77
74
|
}
|
|
78
75
|
|
|
79
|
-
get scrollOffset() {
|
|
80
|
-
return this.scrollState.offset;
|
|
81
|
-
}
|
|
76
|
+
get scrollOffset() { return this.scrollState.offset; }
|
|
82
77
|
|
|
83
78
|
clear() {
|
|
84
79
|
this.segments = [];
|
|
@@ -90,27 +85,19 @@ export class OutputBuffer {
|
|
|
90
85
|
this._activeThinking = null;
|
|
91
86
|
this.overlayStatus = null;
|
|
92
87
|
this.scrollState.clear();
|
|
93
|
-
this._segmentLinesCache = new Map();
|
|
94
88
|
this._baseLinesCache = new Map();
|
|
89
|
+
this._baseEntriesCache = new Map();
|
|
95
90
|
}
|
|
96
91
|
|
|
97
|
-
write(text) {
|
|
98
|
-
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
writeMarkdown(text) {
|
|
102
|
-
this._writeText(text, true);
|
|
103
|
-
}
|
|
92
|
+
write(text) { this._writeText(text, false); }
|
|
93
|
+
writeMarkdown(text) { this._writeText(text, true); }
|
|
104
94
|
|
|
105
95
|
_writeText(text, markdown) {
|
|
106
96
|
this.overlayStatus = null;
|
|
107
97
|
this._invalidateBaseLines();
|
|
108
98
|
const current = this.currentText.at(-1);
|
|
109
|
-
if (current.markdown !== markdown && current.text !== "") {
|
|
110
|
-
|
|
111
|
-
} else {
|
|
112
|
-
current.markdown = markdown;
|
|
113
|
-
}
|
|
99
|
+
if (current.markdown !== markdown && current.text !== "") this.currentText.push({ text: "", markdown });
|
|
100
|
+
else current.markdown = markdown;
|
|
114
101
|
const parts = text.split("\n");
|
|
115
102
|
this.currentText[this.currentText.length - 1].text += parts[0];
|
|
116
103
|
for (let i = 1; i < parts.length; i++) this.currentText.push({ text: parts[i], markdown });
|
|
@@ -134,10 +121,9 @@ export class OutputBuffer {
|
|
|
134
121
|
startThinking() {
|
|
135
122
|
this.overlayStatus = null;
|
|
136
123
|
this._flushText();
|
|
137
|
-
|
|
138
|
-
this.segments.push(
|
|
139
|
-
this.
|
|
140
|
-
this._activeThinking = seg;
|
|
124
|
+
this._activeThinking = { type: "thinking", tokens: 0, content: [] };
|
|
125
|
+
this.segments.push(this._activeThinking);
|
|
126
|
+
this._invalidateBaseLines();
|
|
141
127
|
}
|
|
142
128
|
|
|
143
129
|
appendThinking(text) {
|
|
@@ -151,25 +137,24 @@ export class OutputBuffer {
|
|
|
151
137
|
}
|
|
152
138
|
|
|
153
139
|
endThinking(tokens) {
|
|
154
|
-
if (this._activeThinking)
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
}
|
|
140
|
+
if (!this._activeThinking) return;
|
|
141
|
+
this._activeThinking.tokens = tokens;
|
|
142
|
+
this._activeThinking = null;
|
|
143
|
+
this._invalidateBaseLines();
|
|
159
144
|
}
|
|
160
145
|
|
|
161
146
|
addThinkingBlock(tokens, content) {
|
|
162
147
|
this.overlayStatus = null;
|
|
163
148
|
this._flushText();
|
|
164
149
|
this.segments.push({ type: "thinking", tokens, content: content.split("\n") });
|
|
165
|
-
this.
|
|
150
|
+
this._invalidateBaseLines();
|
|
166
151
|
}
|
|
167
152
|
|
|
168
153
|
addBlock(block) {
|
|
169
154
|
this.overlayStatus = null;
|
|
170
155
|
this._flushText();
|
|
171
156
|
this.segments.push(block);
|
|
172
|
-
this.
|
|
157
|
+
this._invalidateBaseLines();
|
|
173
158
|
}
|
|
174
159
|
|
|
175
160
|
setOverlayStatus(lines) {
|
|
@@ -182,14 +167,12 @@ export class OutputBuffer {
|
|
|
182
167
|
this._invalidateBaseLines();
|
|
183
168
|
}
|
|
184
169
|
|
|
185
|
-
sealCurrentText() {
|
|
186
|
-
return this._flushText();
|
|
187
|
-
}
|
|
170
|
+
sealCurrentText() { return this._flushText(); }
|
|
188
171
|
|
|
189
172
|
_flushText() {
|
|
190
173
|
if (this.currentText.length <= 1 && this.currentText[0].text === "") return false;
|
|
191
174
|
this.segments.push(...currentTextToBlocks(this.currentText, true));
|
|
192
|
-
this.
|
|
175
|
+
this._invalidateBaseLines();
|
|
193
176
|
this.currentText = [{ text: "", markdown: false }];
|
|
194
177
|
this.currentTextCache = new Map();
|
|
195
178
|
return true;
|
|
@@ -200,60 +183,44 @@ export class OutputBuffer {
|
|
|
200
183
|
if (text !== undefined) this.spinnerText = text;
|
|
201
184
|
}
|
|
202
185
|
|
|
203
|
-
tick() {
|
|
204
|
-
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
getScrollStep() {
|
|
212
|
-
return this.scrollState.getStep();
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
getMaxScrollOffset() {
|
|
216
|
-
return this.scrollState.getMaxOffset();
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
setViewportHeight(height) {
|
|
220
|
-
this.scrollState.setViewportHeight(height);
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
resetScroll() {
|
|
224
|
-
this.scrollState.reset();
|
|
225
|
-
}
|
|
186
|
+
tick() { this.spinnerIdx = (this.spinnerIdx + 1) % SPINNER_FRAMES.length; }
|
|
187
|
+
scroll(delta, options) { return this.scrollState.scroll(delta, options); }
|
|
188
|
+
getScrollStep() { return this.scrollState.getStep(); }
|
|
189
|
+
getMaxScrollOffset() { return this.scrollState.getMaxOffset(); }
|
|
190
|
+
setViewportHeight(height) { this.scrollState.setViewportHeight(height); }
|
|
191
|
+
resetScroll() { this.scrollState.reset(); }
|
|
226
192
|
|
|
227
193
|
setToolCardsExpanded(expanded) {
|
|
228
194
|
let changed = false;
|
|
229
195
|
for (const seg of this.segments) {
|
|
230
|
-
if (seg.type !== "tool-card") continue;
|
|
231
|
-
if (seg.expanded === expanded) continue;
|
|
196
|
+
if (seg.type !== "tool-card" || seg.expanded === expanded) continue;
|
|
232
197
|
seg.expanded = expanded;
|
|
233
198
|
changed = true;
|
|
234
199
|
}
|
|
235
|
-
if (changed) this.
|
|
200
|
+
if (changed) this._invalidateBaseLines();
|
|
236
201
|
return changed;
|
|
237
202
|
}
|
|
238
203
|
|
|
239
|
-
invalidate() {
|
|
240
|
-
this._invalidateSegmentLines();
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
_invalidateSegmentLines() {
|
|
244
|
-
this._segmentLinesCache.clear();
|
|
245
|
-
this._invalidateBaseLines();
|
|
246
|
-
}
|
|
204
|
+
invalidate() { this._invalidateBaseLines(); }
|
|
247
205
|
|
|
248
206
|
_invalidateBaseLines() {
|
|
249
207
|
this._baseLinesCache.clear();
|
|
208
|
+
this._baseEntriesCache.clear();
|
|
250
209
|
}
|
|
251
210
|
|
|
252
211
|
render(width) {
|
|
253
|
-
|
|
212
|
+
return this.renderSelectable(width).lines;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
renderSelectable(width) {
|
|
216
|
+
const baseEntries = this._renderBaseEntries(width);
|
|
254
217
|
const tailLine = this.spinning ? this._spinnerLine() : null;
|
|
255
|
-
this.scrollState.setTotalLines(
|
|
256
|
-
|
|
218
|
+
this.scrollState.setTotalLines(baseEntries.length + (tailLine == null ? 0 : 1));
|
|
219
|
+
const entries = sliceEntriesWithTail(baseEntries, tailLine, this.scrollState.sliceRange());
|
|
220
|
+
return {
|
|
221
|
+
lines: entries.map((entry) => entry.line),
|
|
222
|
+
copyText: (range) => copySourceTextForRange(entries, range),
|
|
223
|
+
};
|
|
257
224
|
}
|
|
258
225
|
|
|
259
226
|
_spinnerLine() {
|
|
@@ -263,31 +230,28 @@ export class OutputBuffer {
|
|
|
263
230
|
_renderBaseLines(width) {
|
|
264
231
|
const cached = this._baseLinesCache.get(width);
|
|
265
232
|
if (cached) return cached;
|
|
266
|
-
const lines =
|
|
267
|
-
const dynamicStart = this._cachedSegmentPrefixCount();
|
|
268
|
-
for (const seg of this.segments.slice(dynamicStart)) for (const line of renderBlock(seg, width)) lines.push(line);
|
|
269
|
-
for (const block of currentTextToBlocks(this.currentText, false, this.currentTextCache)) for (const line of renderBlock(block, width)) lines.push(line);
|
|
270
|
-
if (this.overlayStatus) for (const line of renderBlock(this.overlayStatus, width)) lines.push(line);
|
|
233
|
+
const lines = this._renderBaseEntries(width).map((entry) => entry.line);
|
|
271
234
|
this._baseLinesCache.set(width, lines);
|
|
272
235
|
return lines;
|
|
273
236
|
}
|
|
274
237
|
|
|
275
|
-
|
|
276
|
-
const
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
for (const line of renderBlock(this.segments[i], width)) lines.push(line);
|
|
283
|
-
}
|
|
284
|
-
this._segmentLinesCache.set(width, { prefixCount, lines });
|
|
285
|
-
return lines;
|
|
238
|
+
_renderBaseEntries(width) {
|
|
239
|
+
const cached = this._baseEntriesCache.get(width);
|
|
240
|
+
if (cached) return cached;
|
|
241
|
+
const entries = [];
|
|
242
|
+
for (const block of this._blocksForRender()) appendBlockEntries(entries, block, width);
|
|
243
|
+
this._baseEntriesCache.set(width, entries);
|
|
244
|
+
return entries;
|
|
286
245
|
}
|
|
287
246
|
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
247
|
+
_blocksForRender() {
|
|
248
|
+
const blocks = [...this.segments];
|
|
249
|
+
blocks.push(...currentTextToBlocks(this.currentText, false, this.currentTextCache));
|
|
250
|
+
if (this.overlayStatus) blocks.push(this.overlayStatus);
|
|
251
|
+
return blocks;
|
|
292
252
|
}
|
|
293
253
|
}
|
|
254
|
+
|
|
255
|
+
function appendBlockEntries(entries, block, width) {
|
|
256
|
+
appendSelectableEntries(entries, block, renderBlock(block, width), width);
|
|
257
|
+
}
|
|
@@ -73,6 +73,19 @@ export class ScreenSelection {
|
|
|
73
73
|
return hadSelection;
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
+
copyText() {
|
|
77
|
+
const sourceText = this.sourceText();
|
|
78
|
+
return sourceText || this.text();
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
sourceText() {
|
|
82
|
+
const range = this.range();
|
|
83
|
+
if (!range) return "";
|
|
84
|
+
const region = this._singleRegionForRange(range);
|
|
85
|
+
if (!region?.copyText) return "";
|
|
86
|
+
return region.copyText(localRange(range, region)) || "";
|
|
87
|
+
}
|
|
88
|
+
|
|
76
89
|
text() {
|
|
77
90
|
const range = this.range();
|
|
78
91
|
if (!range) return "";
|
|
@@ -110,6 +123,15 @@ export class ScreenSelection {
|
|
|
110
123
|
return this._plainLines.get(row);
|
|
111
124
|
}
|
|
112
125
|
|
|
126
|
+
_singleRegionForRange(range) {
|
|
127
|
+
const matches = this.regions.filter((region) => {
|
|
128
|
+
const start = region.docStart;
|
|
129
|
+
const end = region.docStart + region.lines.length - 1;
|
|
130
|
+
return range.start.row >= start && range.end.row <= end;
|
|
131
|
+
});
|
|
132
|
+
return matches.length === 1 ? matches[0] : null;
|
|
133
|
+
}
|
|
134
|
+
|
|
113
135
|
range() {
|
|
114
136
|
if (!this.anchor || !this.focus) return null;
|
|
115
137
|
const [start, end] = comparePoints(this.anchor, this.focus) <= 0
|
|
@@ -133,6 +155,14 @@ function normalizeRegion(region, index) {
|
|
|
133
155
|
topRow: Math.max(0, Math.trunc(region.topRow ?? 0)),
|
|
134
156
|
leftCol: Math.max(0, Math.trunc(region.leftCol ?? 0)),
|
|
135
157
|
width,
|
|
158
|
+
copyText: typeof region.copyText === "function" ? region.copyText : null,
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function localRange(range, region) {
|
|
163
|
+
return {
|
|
164
|
+
start: { row: range.start.row - region.docStart, col: range.start.col },
|
|
165
|
+
end: { row: range.end.row - region.docStart, col: range.end.col },
|
|
136
166
|
};
|
|
137
167
|
}
|
|
138
168
|
|
package/src/cli/ui.mjs
CHANGED
|
@@ -58,7 +58,6 @@ export function createTuiUI({
|
|
|
58
58
|
tui.setFocus(editor);
|
|
59
59
|
|
|
60
60
|
let started = false;
|
|
61
|
-
let mouseOn = true;
|
|
62
61
|
let toolsExpanded = false;
|
|
63
62
|
const activeToolBlocks = [];
|
|
64
63
|
const renderScheduler = createRenderScheduler({ requestRender: () => tui.requestRender() });
|
|
@@ -98,7 +97,7 @@ export function createTuiUI({
|
|
|
98
97
|
function ensureStarted() {
|
|
99
98
|
if (!started) {
|
|
100
99
|
tui.addInputListener((data) => {
|
|
101
|
-
const mouseResult = mouseSelectionController.handleMouseInput(data
|
|
100
|
+
const mouseResult = mouseSelectionController.handleMouseInput(data);
|
|
102
101
|
if (mouseResult) return mouseResult;
|
|
103
102
|
const copyKeyResult = mouseSelectionController.handleCopyKey(data);
|
|
104
103
|
if (copyKeyResult) return copyKeyResult;
|
|
@@ -118,7 +117,7 @@ export function createTuiUI({
|
|
|
118
117
|
}
|
|
119
118
|
|
|
120
119
|
function openExternalEditor() {
|
|
121
|
-
runTuiExternalEditor({ terminal, tui, editor, output, requestRender, mouseOn: () =>
|
|
120
|
+
runTuiExternalEditor({ terminal, tui, editor, output, requestRender, mouseOn: () => true });
|
|
122
121
|
}
|
|
123
122
|
|
|
124
123
|
function toggleToolOutput() {
|
|
@@ -240,18 +239,6 @@ export function createTuiUI({
|
|
|
240
239
|
requestRender();
|
|
241
240
|
},
|
|
242
241
|
|
|
243
|
-
toggleMouse: () => {
|
|
244
|
-
if (mouseOn) {
|
|
245
|
-
terminal.write("\x1b[?1002l\x1b[?1006l");
|
|
246
|
-
mouseOn = false;
|
|
247
|
-
return false;
|
|
248
|
-
} else {
|
|
249
|
-
terminal.write("\x1b[?1002h\x1b[?1006h");
|
|
250
|
-
mouseOn = true;
|
|
251
|
-
return true;
|
|
252
|
-
}
|
|
253
|
-
},
|
|
254
|
-
|
|
255
242
|
requestPermission: async ({ toolName, params, category }) => {
|
|
256
243
|
ensureStarted();
|
|
257
244
|
spinnerStatus.stop();
|
|
@@ -281,7 +268,7 @@ export function createTuiUI({
|
|
|
281
268
|
retryStatus.stop();
|
|
282
269
|
if (started) {
|
|
283
270
|
await terminal.drainInput?.();
|
|
284
|
-
|
|
271
|
+
terminal.write("\x1b[?1002l\x1b[?1006l");
|
|
285
272
|
tui.stop();
|
|
286
273
|
terminal.write("\x1b[?1049l");
|
|
287
274
|
}
|
package/src/main.mjs
CHANGED
|
@@ -37,6 +37,9 @@ import { registerSuperGrokOAuthProvider } from "./supergrok/oauth-provider.mjs";
|
|
|
37
37
|
import { installNetworkEnvironment } from "./network/environment.mjs";
|
|
38
38
|
import { runMemoryCommand } from "./memory/command.mjs";
|
|
39
39
|
import { normalizeRemoteMemorySources } from "./memory/remote/config.mjs";
|
|
40
|
+
import { resolveMemoryRoot } from "./memory/root.mjs";
|
|
41
|
+
import { runBrowserCommand } from "./browser/cli/command.mjs";
|
|
42
|
+
import { ensureBrowserDaemon } from "./browser/client/lifecycle.mjs";
|
|
40
43
|
export async function run(argv) {
|
|
41
44
|
const cwd = process.cwd();
|
|
42
45
|
loadDotEnv(cwd);
|
|
@@ -49,6 +52,7 @@ export async function run(argv) {
|
|
|
49
52
|
}
|
|
50
53
|
|
|
51
54
|
const config = loadConfig(cwd);
|
|
55
|
+
const stateRoot = join(homedir(), ".march");
|
|
52
56
|
const useRuntimeProcess = process.env.MARCH_RUNTIME_PROCESS !== "0";
|
|
53
57
|
installNetworkEnvironment(config.network);
|
|
54
58
|
if (args.command?.name === "login") {
|
|
@@ -70,11 +74,19 @@ export async function run(argv) {
|
|
|
70
74
|
return 1;
|
|
71
75
|
}
|
|
72
76
|
if (args.command?.name === "memory") {
|
|
73
|
-
args.memoryRoot = resolveMemoryRoot(config.memoryRoot,
|
|
77
|
+
args.memoryRoot = resolveMemoryRoot(config.memoryRoot, stateRoot);
|
|
74
78
|
return await runMemoryCommand(args, { homeDir: homedir() });
|
|
75
79
|
}
|
|
76
|
-
|
|
80
|
+
if (args.command?.name === "browser") {
|
|
81
|
+
try {
|
|
82
|
+
return await runBrowserCommand(args, { stateRoot });
|
|
83
|
+
} catch (err) {
|
|
84
|
+
process.stderr.write(`Error: ${err.message}\n`);
|
|
85
|
+
return 1;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
77
88
|
if (!existsSync(stateRoot)) mkdirSync(stateRoot, { recursive: true });
|
|
89
|
+
await ensureBrowserDaemon({ stateRoot }).catch(() => {});
|
|
78
90
|
const logger = createLogger({ logDir: join(stateRoot, "logs") });
|
|
79
91
|
installProcessLogHandlers(logger);
|
|
80
92
|
logger.event("process.start", {
|
|
@@ -223,7 +235,6 @@ export async function run(argv) {
|
|
|
223
235
|
modeState,
|
|
224
236
|
});
|
|
225
237
|
|
|
226
|
-
|
|
227
238
|
const startupResume = await resumeStartupSession({
|
|
228
239
|
resumeId: args.resume,
|
|
229
240
|
runner,
|
|
@@ -233,7 +244,6 @@ export async function run(argv) {
|
|
|
233
244
|
});
|
|
234
245
|
refreshStatusBar();
|
|
235
246
|
|
|
236
|
-
|
|
237
247
|
if (args.prompt) {
|
|
238
248
|
turnRunning = true;
|
|
239
249
|
try {
|
|
@@ -285,10 +295,4 @@ export async function run(argv) {
|
|
|
285
295
|
return 0;
|
|
286
296
|
}
|
|
287
297
|
|
|
288
|
-
function resolveMemoryRoot(configured, stateRoot) {
|
|
289
|
-
if (configured) return resolve(String(configured));
|
|
290
|
-
if (process.env.MARCH_MEMORY_ROOT) return resolve(process.env.MARCH_MEMORY_ROOT);
|
|
291
|
-
return resolve(stateRoot, "March Memories");
|
|
292
|
-
}
|
|
293
|
-
|
|
294
298
|
if (process.argv[1] === fileURLToPath(import.meta.url)) process.exitCode = await run(process.argv.slice(2));
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { resolve } from "node:path";
|
|
2
|
+
|
|
3
|
+
export function resolveMemoryRoot(configured, stateRoot) {
|
|
4
|
+
if (configured) return resolve(String(configured));
|
|
5
|
+
if (process.env.MARCH_MEMORY_ROOT) return resolve(process.env.MARCH_MEMORY_ROOT);
|
|
6
|
+
return resolve(stateRoot, "March Memories");
|
|
7
|
+
}
|