acryl-cli-linux-x64 0.1.31 → 0.1.35
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/runtime/lib/bin.js +831 -220
- package/runtime/lib/index.js +831 -220
- package/runtime/lib/types/buildInfo.generated.d.ts +4 -0
- package/runtime/lib/types/tui/acrylMark.d.ts +14 -0
- package/runtime/lib/types/tui/actions.d.ts +8 -6
- package/runtime/lib/types/tui/auth-guidance.d.ts +0 -2
- package/runtime/lib/types/tui/login/LoginOverlay.d.ts +46 -11
- package/runtime/lib/types/tui/login/types.d.ts +5 -1
- package/runtime/lib/types/tui/modelProfile/ModelProfileOverlay.d.ts +55 -3
- package/runtime/lib/types/tui/modelProfile/types.d.ts +23 -0
- package/runtime/lib/types/tui/store.d.ts +10 -0
- package/runtime/node_modules/.modules.yaml +2 -2
- package/runtime/node_modules/.package-map.json +1 -1
- package/runtime/node_modules/@earendil-works/pi-ai/dist/auth/oauth/oauth-page.js +1 -1
- package/runtime/node_modules/acryl-control/package.json +1 -1
- package/runtime/node_modules/acryl-harness-runtime/lib/index.mjs +129 -2
- package/runtime/node_modules/acryl-harness-runtime/lib/types/acryl-home.d.ts +35 -0
- package/runtime/node_modules/acryl-harness-runtime/lib/types/index.d.ts +2 -0
- package/runtime/node_modules/acryl-harness-runtime/lib/types/session-bridge.d.ts +13 -0
- package/runtime/node_modules/acryl-harness-runtime/lib/types/session-log-exporter.d.ts +31 -0
- package/runtime/node_modules/acryl-harness-runtime/package.json +1 -1
- package/runtime/node_modules/acryl-harness-runtime/src/acryl-home.ts +50 -0
- package/runtime/node_modules/acryl-harness-runtime/src/index.ts +16 -0
- package/runtime/node_modules/acryl-harness-runtime/src/session-bridge.ts +24 -1
- package/runtime/node_modules/acryl-harness-runtime/src/session-log-exporter.ts +69 -0
- package/runtime/package.json +3 -1
- package/runtime/receipt.json +2 -2
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const LOGO_SVG = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 800 800" aria-hidden="true"><
|
|
1
|
+
const LOGO_SVG = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 800 800" aria-hidden="true"><g fill="#fff"><rect x="76.0" y="418.0" width="10.5" height="10.5"/><rect x="88.0" y="394.0" width="10.5" height="10.5"/><rect x="88.0" y="406.0" width="10.5" height="10.5"/><rect x="88.0" y="418.0" width="10.5" height="10.5"/><rect x="100.0" y="382.0" width="10.5" height="10.5"/><rect x="100.0" y="394.0" width="10.5" height="10.5"/><rect x="112.0" y="370.0" width="10.5" height="10.5"/><rect x="112.0" y="382.0" width="10.5" height="10.5"/><rect x="124.0" y="358.0" width="10.5" height="10.5"/><rect x="124.0" y="370.0" width="10.5" height="10.5"/><rect x="136.0" y="346.0" width="10.5" height="10.5"/><rect x="136.0" y="358.0" width="10.5" height="10.5"/><rect x="148.0" y="334.0" width="10.5" height="10.5"/><rect x="148.0" y="346.0" width="10.5" height="10.5"/><rect x="160.0" y="334.0" width="10.5" height="10.5"/><rect x="160.0" y="346.0" width="10.5" height="10.5"/><rect x="160.0" y="358.0" width="10.5" height="10.5"/><rect x="172.0" y="358.0" width="10.5" height="10.5"/><rect x="184.0" y="370.0" width="10.5" height="10.5"/><rect x="196.0" y="370.0" width="10.5" height="10.5"/><rect x="196.0" y="382.0" width="10.5" height="10.5"/><rect x="196.0" y="394.0" width="10.5" height="10.5"/><rect x="208.0" y="370.0" width="10.5" height="10.5"/><rect x="208.0" y="406.0" width="10.5" height="10.5"/><rect x="220.0" y="370.0" width="10.5" height="10.5"/><rect x="220.0" y="418.0" width="10.5" height="10.5"/><rect x="232.0" y="370.0" width="10.5" height="10.5"/><rect x="244.0" y="370.0" width="10.5" height="10.5"/><rect x="256.0" y="358.0" width="10.5" height="10.5"/><rect x="256.0" y="370.0" width="10.5" height="10.5"/><rect x="256.0" y="382.0" width="10.5" height="10.5"/><rect x="268.0" y="346.0" width="10.5" height="10.5"/><rect x="268.0" y="382.0" width="10.5" height="10.5"/><rect x="268.0" y="394.0" width="10.5" height="10.5"/><rect x="280.0" y="334.0" width="10.5" height="10.5"/><rect x="280.0" y="394.0" width="10.5" height="10.5"/><rect x="280.0" y="406.0" width="10.5" height="10.5"/><rect x="280.0" y="418.0" width="10.5" height="10.5"/><rect x="292.0" y="310.0" width="10.5" height="10.5"/><rect x="292.0" y="418.0" width="10.5" height="10.5"/><rect x="292.0" y="430.0" width="10.5" height="10.5"/><rect x="304.0" y="298.0" width="10.5" height="10.5"/><rect x="304.0" y="430.0" width="10.5" height="10.5"/><rect x="304.0" y="442.0" width="10.5" height="10.5"/><rect x="316.0" y="286.0" width="10.5" height="10.5"/><rect x="316.0" y="442.0" width="10.5" height="10.5"/><rect x="328.0" y="274.0" width="10.5" height="10.5"/><rect x="328.0" y="442.0" width="10.5" height="10.5"/><rect x="340.0" y="274.0" width="10.5" height="10.5"/><rect x="340.0" y="442.0" width="10.5" height="10.5"/><rect x="352.0" y="274.0" width="10.5" height="10.5"/><rect x="352.0" y="310.0" width="10.5" height="10.5"/><rect x="352.0" y="442.0" width="10.5" height="10.5"/><rect x="364.0" y="274.0" width="10.5" height="10.5"/><rect x="364.0" y="310.0" width="10.5" height="10.5"/><rect x="364.0" y="442.0" width="10.5" height="10.5"/><rect x="376.0" y="274.0" width="10.5" height="10.5"/><rect x="376.0" y="310.0" width="10.5" height="10.5"/><rect x="376.0" y="442.0" width="10.5" height="10.5"/><rect x="388.0" y="274.0" width="10.5" height="10.5"/><rect x="388.0" y="310.0" width="10.5" height="10.5"/><rect x="388.0" y="358.0" width="10.5" height="10.5"/><rect x="388.0" y="442.0" width="10.5" height="10.5"/><rect x="400.0" y="274.0" width="10.5" height="10.5"/><rect x="400.0" y="310.0" width="10.5" height="10.5"/><rect x="400.0" y="358.0" width="10.5" height="10.5"/><rect x="400.0" y="370.0" width="10.5" height="10.5"/><rect x="400.0" y="442.0" width="10.5" height="10.5"/><rect x="412.0" y="274.0" width="10.5" height="10.5"/><rect x="412.0" y="310.0" width="10.5" height="10.5"/><rect x="412.0" y="358.0" width="10.5" height="10.5"/><rect x="412.0" y="382.0" width="10.5" height="10.5"/><rect x="412.0" y="394.0" width="10.5" height="10.5"/><rect x="412.0" y="442.0" width="10.5" height="10.5"/><rect x="424.0" y="310.0" width="10.5" height="10.5"/><rect x="424.0" y="358.0" width="10.5" height="10.5"/><rect x="424.0" y="406.0" width="10.5" height="10.5"/><rect x="424.0" y="442.0" width="10.5" height="10.5"/><rect x="436.0" y="310.0" width="10.5" height="10.5"/><rect x="436.0" y="358.0" width="10.5" height="10.5"/><rect x="436.0" y="406.0" width="10.5" height="10.5"/><rect x="448.0" y="310.0" width="10.5" height="10.5"/><rect x="448.0" y="322.0" width="10.5" height="10.5"/><rect x="448.0" y="346.0" width="10.5" height="10.5"/><rect x="448.0" y="358.0" width="10.5" height="10.5"/><rect x="448.0" y="430.0" width="10.5" height="10.5"/><rect x="460.0" y="334.0" width="10.5" height="10.5"/><rect x="460.0" y="442.0" width="10.5" height="10.5"/><rect x="472.0" y="442.0" width="10.5" height="10.5"/><rect x="484.0" y="454.0" width="10.5" height="10.5"/><rect x="484.0" y="466.0" width="10.5" height="10.5"/><rect x="496.0" y="478.0" width="10.5" height="10.5"/><rect x="508.0" y="478.0" width="10.5" height="10.5"/><rect x="508.0" y="490.0" width="10.5" height="10.5"/><rect x="508.0" y="502.0" width="10.5" height="10.5"/><rect x="508.0" y="514.0" width="10.5" height="10.5"/><rect x="520.0" y="478.0" width="10.5" height="10.5"/><rect x="532.0" y="454.0" width="10.5" height="10.5"/><rect x="532.0" y="466.0" width="10.5" height="10.5"/><rect x="544.0" y="442.0" width="10.5" height="10.5"/><rect x="556.0" y="442.0" width="10.5" height="10.5"/><rect x="568.0" y="430.0" width="10.5" height="10.5"/><rect x="580.0" y="418.0" width="10.5" height="10.5"/><rect x="580.0" y="430.0" width="10.5" height="10.5"/><rect x="592.0" y="406.0" width="10.5" height="10.5"/><rect x="592.0" y="418.0" width="10.5" height="10.5"/><rect x="592.0" y="430.0" width="10.5" height="10.5"/><rect x="604.0" y="394.0" width="10.5" height="10.5"/><rect x="604.0" y="406.0" width="10.5" height="10.5"/><rect x="604.0" y="430.0" width="10.5" height="10.5"/><rect x="616.0" y="382.0" width="10.5" height="10.5"/><rect x="616.0" y="430.0" width="10.5" height="10.5"/><rect x="628.0" y="370.0" width="10.5" height="10.5"/><rect x="628.0" y="430.0" width="10.5" height="10.5"/><rect x="640.0" y="430.0" width="10.5" height="10.5"/><rect x="652.0" y="430.0" width="10.5" height="10.5"/><rect x="664.0" y="430.0" width="10.5" height="10.5"/><rect x="676.0" y="430.0" width="10.5" height="10.5"/><rect x="688.0" y="430.0" width="10.5" height="10.5"/><rect x="700.0" y="430.0" width="10.5" height="10.5"/><rect x="712.0" y="430.0" width="10.5" height="10.5"/></g></svg>`;
|
|
2
2
|
function escapeHtml(value) {
|
|
3
3
|
return value
|
|
4
4
|
.replaceAll("&", "&")
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import { createRequire } from "node:module";
|
|
2
|
-
import { existsSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { appendFileSync, existsSync, mkdirSync, writeFileSync } from "node:fs";
|
|
3
3
|
import { dirname, join, resolve } from "node:path";
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
|
+
import { installModelSelection } from "@deepseek-ai/dsh-agent";
|
|
5
6
|
import { createUserMessage } from "@deepseek-ai/dsh-llm";
|
|
6
7
|
import { SessionId } from "@deepseek-ai/dsh-session";
|
|
8
|
+
import { resolveDshHome } from "@deepseek-ai/dsh-home-paths";
|
|
9
|
+
import { homedir } from "node:os";
|
|
7
10
|
import { provideCmdline } from "@deepseek-ai/dsh-cmdline";
|
|
8
11
|
import { DEFAULT_PROFILE_BUNDLES, boot, composeEntries, healProfilesModuleFallback, initProfile, loadProfile, resolveProfileDir } from "@deepseek-ai/dsh-app-boot";
|
|
9
12
|
import { defineTool } from "@deepseek-ai/dsh-tools";
|
|
@@ -114,6 +117,8 @@ function status(agent) {
|
|
|
114
117
|
*/
|
|
115
118
|
function createAcrylSessionBridge(ctx, options) {
|
|
116
119
|
const handles = /* @__PURE__ */ new Map();
|
|
120
|
+
const modelSelections = /* @__PURE__ */ new Map();
|
|
121
|
+
const modelSelectionDisposers = /* @__PURE__ */ new Map();
|
|
117
122
|
const subscribers = /* @__PURE__ */ new Map();
|
|
118
123
|
const eventListeners = /* @__PURE__ */ new Map();
|
|
119
124
|
let disposed = false;
|
|
@@ -175,6 +180,12 @@ function createAcrylSessionBridge(ctx, options) {
|
|
|
175
180
|
}
|
|
176
181
|
});
|
|
177
182
|
handles.set(handle.agent.id, handle);
|
|
183
|
+
const ref = {
|
|
184
|
+
current: void 0,
|
|
185
|
+
assembled: void 0
|
|
186
|
+
};
|
|
187
|
+
modelSelectionDisposers.set(handle.agent.id, installModelSelection(handle.agent.ctx, ref));
|
|
188
|
+
modelSelections.set(handle.agent.id, ref);
|
|
178
189
|
return handle.agent.id;
|
|
179
190
|
},
|
|
180
191
|
snapshot,
|
|
@@ -234,6 +245,15 @@ function createAcrylSessionBridge(ctx, options) {
|
|
|
234
245
|
}));
|
|
235
246
|
await accepted;
|
|
236
247
|
},
|
|
248
|
+
async selectModel(input) {
|
|
249
|
+
agentFor(input.sessionId);
|
|
250
|
+
const ref = modelSelections.get(input.sessionId);
|
|
251
|
+
if (ref === void 0) throw new Error(`ACRYL session ${input.sessionId} has no installed model selection`);
|
|
252
|
+
ref.current = {
|
|
253
|
+
provider: input.provider,
|
|
254
|
+
model: input.model
|
|
255
|
+
};
|
|
256
|
+
},
|
|
237
257
|
async cancel(sessionId) {
|
|
238
258
|
agentFor(sessionId).cancel({ kind: "user" });
|
|
239
259
|
},
|
|
@@ -243,6 +263,9 @@ function createAcrylSessionBridge(ctx, options) {
|
|
|
243
263
|
offSessionEvent();
|
|
244
264
|
subscribers.clear();
|
|
245
265
|
eventListeners.clear();
|
|
266
|
+
for (const dispose of modelSelectionDisposers.values()) dispose();
|
|
267
|
+
modelSelectionDisposers.clear();
|
|
268
|
+
modelSelections.clear();
|
|
246
269
|
const activeHandles = [...handles.values()];
|
|
247
270
|
handles.clear();
|
|
248
271
|
const sessions = ctx.get("sessions");
|
|
@@ -259,6 +282,106 @@ function createAcrylSessionBridge(ctx, options) {
|
|
|
259
282
|
});
|
|
260
283
|
}
|
|
261
284
|
//#endregion
|
|
285
|
+
//#region src/session-log-exporter.ts
|
|
286
|
+
/**
|
|
287
|
+
* A durable, cross-surface debug log for ACRYL sessions.
|
|
288
|
+
*
|
|
289
|
+
* Cordis's own `ctx.logger` already carries every structured log record any
|
|
290
|
+
* plugin emits, but nothing in this stack persisted it anywhere — a failure
|
|
291
|
+
* like a vendored provider's OAuth error only ever reached the terminal
|
|
292
|
+
* transcript, gone the moment the pane scrolled or the process exited. This
|
|
293
|
+
* registers one JSONL file exporter on `ctx.logger` per surface (CLI/TUI,
|
|
294
|
+
* web, and — once wired there too — the desktop GUI), so `error`/`warn`
|
|
295
|
+
* records (and everything, when `ACRYL_LOG_LEVEL=debug`) survive the session
|
|
296
|
+
* and can be read back after the fact instead of re-derived from a
|
|
297
|
+
* screenshot.
|
|
298
|
+
*
|
|
299
|
+
* @module acryl-harness-runtime/session-log-exporter
|
|
300
|
+
*/
|
|
301
|
+
const LOGGER_LEVEL_WARN = 2;
|
|
302
|
+
const LOGGER_LEVEL_DEBUG = 3;
|
|
303
|
+
/**
|
|
304
|
+
* Register the file exporter for this process's lifetime. `ctx.logger.exporter()`
|
|
305
|
+
* already ties its own disposal to the fiber that registers it (see
|
|
306
|
+
* `LoggerService.exporter` in `@deepseek-ai/cordis`), so this needs no extra
|
|
307
|
+
* `ctx.effect()` wrapper of its own.
|
|
308
|
+
* @param ctx - the plugin context whose `ctx.logger` gains the exporter.
|
|
309
|
+
* @param options - which surface/home this log file belongs to.
|
|
310
|
+
*/
|
|
311
|
+
function installSessionLogExporter(ctx, options) {
|
|
312
|
+
const logDir = join(resolveDshHome(options.dshHome), "logs");
|
|
313
|
+
try {
|
|
314
|
+
mkdirSync(logDir, {
|
|
315
|
+
recursive: true,
|
|
316
|
+
mode: 448
|
|
317
|
+
});
|
|
318
|
+
} catch {
|
|
319
|
+
return;
|
|
320
|
+
}
|
|
321
|
+
const day = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
322
|
+
const logFile = join(logDir, `acryl-${options.surface}-${day}.jsonl`);
|
|
323
|
+
const threshold = process.env.ACRYL_LOG_LEVEL === "debug" ? LOGGER_LEVEL_DEBUG : LOGGER_LEVEL_WARN;
|
|
324
|
+
ctx.logger.exporter({ export(message) {
|
|
325
|
+
if (message.level > threshold) return;
|
|
326
|
+
try {
|
|
327
|
+
appendFileSync(logFile, `${JSON.stringify({
|
|
328
|
+
ts: new Date(message.ts).toISOString(),
|
|
329
|
+
type: message.type,
|
|
330
|
+
name: message.name,
|
|
331
|
+
args: message.args.map((arg) => arg instanceof Error ? {
|
|
332
|
+
message: arg.message,
|
|
333
|
+
stack: arg.stack,
|
|
334
|
+
name: arg.name
|
|
335
|
+
} : arg)
|
|
336
|
+
})}\n`, { mode: 384 });
|
|
337
|
+
} catch {}
|
|
338
|
+
} });
|
|
339
|
+
}
|
|
340
|
+
//#endregion
|
|
341
|
+
//#region src/acryl-home.ts
|
|
342
|
+
/**
|
|
343
|
+
* ACRYL's own data root, nested one level above the DSH engine home it
|
|
344
|
+
* composes.
|
|
345
|
+
*
|
|
346
|
+
* The stock DSH Desktop app (from dshdesktop.com) uses plain `~/.dsh`, and so
|
|
347
|
+
* did every ACRYL surface until now — sharing that root made the two
|
|
348
|
+
* genuinely different products silently share credentials/settings/sessions,
|
|
349
|
+
* which is both confusing and useless for comparing ACRYL against a stock
|
|
350
|
+
* DSH Desktop install side by side. ACRYL now owns `~/.acryl` and nests each
|
|
351
|
+
* engine's artifacts under it by engine name:
|
|
352
|
+
*
|
|
353
|
+
* ```txt
|
|
354
|
+
* ~/.acryl/ ACRYL's own root — everything not engine-specific
|
|
355
|
+
* ~/.acryl/.dsh/ the DSH engine home (what DSH_HOME resolves to)
|
|
356
|
+
* ~/.acryl/.pi/ reserved for a future pi.dev engine
|
|
357
|
+
* ```
|
|
358
|
+
*
|
|
359
|
+
* `$DSH_HOME`, if a caller has already set it explicitly, still wins — this
|
|
360
|
+
* only changes the *default* the harness's own `resolveDshHome()` falls
|
|
361
|
+
* back to when nothing overrides it.
|
|
362
|
+
*
|
|
363
|
+
* @module acryl-harness-runtime/acryl-home
|
|
364
|
+
*/
|
|
365
|
+
/** ACRYL's own root directory name under the OS home. */
|
|
366
|
+
const ACRYL_HOME_DIR_NAME = ".acryl";
|
|
367
|
+
/** The DSH engine's directory name, nested under ACRYL's root. */
|
|
368
|
+
const ACRYL_DSH_ENGINE_DIR_NAME = ".dsh";
|
|
369
|
+
/** ACRYL's own root — `~/.acryl` unless `$ACRYL_HOME` overrides it. */
|
|
370
|
+
function resolveAcrylHome(env = process.env) {
|
|
371
|
+
const overridden = env.ACRYL_HOME?.trim();
|
|
372
|
+
return overridden && overridden !== "" ? overridden : join(homedir(), ACRYL_HOME_DIR_NAME);
|
|
373
|
+
}
|
|
374
|
+
/**
|
|
375
|
+
* The DSH engine home ACRYL boots against: `$DSH_HOME` if a caller already
|
|
376
|
+
* set it (highest precedence, same as `resolveDshHome()` itself), otherwise
|
|
377
|
+
* `<acrylHome>/.dsh` instead of the harness's own bare `~/.dsh` default.
|
|
378
|
+
*/
|
|
379
|
+
function resolveAcrylDshHome(env = process.env) {
|
|
380
|
+
const overridden = env.DSH_HOME?.trim();
|
|
381
|
+
if (overridden && overridden !== "") return resolveDshHome(void 0, env);
|
|
382
|
+
return resolveDshHome(join(resolveAcrylHome(env), ACRYL_DSH_ENGINE_DIR_NAME), env);
|
|
383
|
+
}
|
|
384
|
+
//#endregion
|
|
262
385
|
//#region src/plugin-acryl-workspace-status.ts
|
|
263
386
|
/** Canonical tool name exposed to the model. */
|
|
264
387
|
const TOOL_NAME = "acryl_workspace_status";
|
|
@@ -330,6 +453,7 @@ const profileRoot = "[]\n";
|
|
|
330
453
|
/** Boot one normal pinned-Harness ACRYL profile in a single Cordis root. */
|
|
331
454
|
async function bootAcrylHarnessProfile(options) {
|
|
332
455
|
if (options.profile.trim() === "") throw new Error("ACRYL Harness profile must not be empty");
|
|
456
|
+
process.env.DSH_HOME = resolveAcrylDshHome();
|
|
333
457
|
initProfile(resolveProfileDir(options.profile), DEFAULT_PROFILE_BUNDLES);
|
|
334
458
|
healProfilesModuleFallback(dshInstallAnchor);
|
|
335
459
|
const profile = loadProfile("acryl", options.profile, dshInstallAnchor);
|
|
@@ -343,6 +467,7 @@ async function bootAcrylHarnessProfile(options) {
|
|
|
343
467
|
if (composeEntries([patches]).find((entry) => entry.id === "hmr")?.disabled !== true && !process.execArgv.includes("--expose-internals")) throw new Error("ACRYL profile enables Cordis HMR and must be launched with Node --expose-internals");
|
|
344
468
|
const ctx = await boot("acryl", rootConfig, patches, options.prepare);
|
|
345
469
|
if (ctx.tools) installAcrylWorkspaceStatusTool(ctx);
|
|
470
|
+
installSessionLogExporter(ctx, { surface: "tui" });
|
|
346
471
|
let disposed = false;
|
|
347
472
|
return Object.freeze({
|
|
348
473
|
ctx,
|
|
@@ -363,6 +488,7 @@ async function bootAcrylHarnessProfile(options) {
|
|
|
363
488
|
*/
|
|
364
489
|
async function bootAcrylWebProfile(options = {}) {
|
|
365
490
|
const profileName = "web";
|
|
491
|
+
process.env.DSH_HOME = resolveAcrylDshHome();
|
|
366
492
|
initProfile(resolveProfileDir(profileName), DEFAULT_PROFILE_BUNDLES);
|
|
367
493
|
healProfilesModuleFallback(dshInstallAnchor);
|
|
368
494
|
const profile = loadProfile("web", profileName, dshInstallAnchor);
|
|
@@ -384,6 +510,7 @@ async function bootAcrylWebProfile(options = {}) {
|
|
|
384
510
|
return options.prepare?.(hostCtx);
|
|
385
511
|
});
|
|
386
512
|
if (ctx.tools) installAcrylWorkspaceStatusTool(ctx);
|
|
513
|
+
installSessionLogExporter(ctx, { surface: "web" });
|
|
387
514
|
const startup = ctx.get("webStartup");
|
|
388
515
|
const url = `http://${startup?.host ?? "127.0.0.1"}:${startup?.port ?? 3080}`;
|
|
389
516
|
let disposed = false;
|
|
@@ -399,6 +526,6 @@ async function bootAcrylWebProfile(options = {}) {
|
|
|
399
526
|
});
|
|
400
527
|
}
|
|
401
528
|
//#endregion
|
|
402
|
-
export { ACRYL_CODING_CAPABILITIES, bootAcrylHarnessProfile, bootAcrylWebProfile, createAcrylCodingCapabilityPatches, createAcrylSessionBridge };
|
|
529
|
+
export { ACRYL_CODING_CAPABILITIES, ACRYL_DSH_ENGINE_DIR_NAME, ACRYL_HOME_DIR_NAME, bootAcrylHarnessProfile, bootAcrylWebProfile, createAcrylCodingCapabilityPatches, createAcrylSessionBridge, installSessionLogExporter, resolveAcrylDshHome, resolveAcrylHome };
|
|
403
530
|
|
|
404
531
|
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ACRYL's own data root, nested one level above the DSH engine home it
|
|
3
|
+
* composes.
|
|
4
|
+
*
|
|
5
|
+
* The stock DSH Desktop app (from dshdesktop.com) uses plain `~/.dsh`, and so
|
|
6
|
+
* did every ACRYL surface until now — sharing that root made the two
|
|
7
|
+
* genuinely different products silently share credentials/settings/sessions,
|
|
8
|
+
* which is both confusing and useless for comparing ACRYL against a stock
|
|
9
|
+
* DSH Desktop install side by side. ACRYL now owns `~/.acryl` and nests each
|
|
10
|
+
* engine's artifacts under it by engine name:
|
|
11
|
+
*
|
|
12
|
+
* ```txt
|
|
13
|
+
* ~/.acryl/ ACRYL's own root — everything not engine-specific
|
|
14
|
+
* ~/.acryl/.dsh/ the DSH engine home (what DSH_HOME resolves to)
|
|
15
|
+
* ~/.acryl/.pi/ reserved for a future pi.dev engine
|
|
16
|
+
* ```
|
|
17
|
+
*
|
|
18
|
+
* `$DSH_HOME`, if a caller has already set it explicitly, still wins — this
|
|
19
|
+
* only changes the *default* the harness's own `resolveDshHome()` falls
|
|
20
|
+
* back to when nothing overrides it.
|
|
21
|
+
*
|
|
22
|
+
* @module acryl-harness-runtime/acryl-home
|
|
23
|
+
*/
|
|
24
|
+
/** ACRYL's own root directory name under the OS home. */
|
|
25
|
+
export declare const ACRYL_HOME_DIR_NAME = ".acryl";
|
|
26
|
+
/** The DSH engine's directory name, nested under ACRYL's root. */
|
|
27
|
+
export declare const ACRYL_DSH_ENGINE_DIR_NAME = ".dsh";
|
|
28
|
+
/** ACRYL's own root — `~/.acryl` unless `$ACRYL_HOME` overrides it. */
|
|
29
|
+
export declare function resolveAcrylHome(env?: Record<string, string | undefined>): string;
|
|
30
|
+
/**
|
|
31
|
+
* The DSH engine home ACRYL boots against: `$DSH_HOME` if a caller already
|
|
32
|
+
* set it (highest precedence, same as `resolveDshHome()` itself), otherwise
|
|
33
|
+
* `<acrylHome>/.dsh` instead of the harness's own bare `~/.dsh` default.
|
|
34
|
+
*/
|
|
35
|
+
export declare function resolveAcrylDshHome(env?: Record<string, string | undefined>): string;
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
export { ACRYL_CODING_CAPABILITIES, createAcrylCodingCapabilityPatches, type AcrylCodingCapability, type AcrylSurface, } from './coding-capabilities.ts';
|
|
2
2
|
export type { DurableSessionMessage, DurableSessionMessagePort, DurableSessionMessageReceipt, } from './durable-message.ts';
|
|
3
3
|
export { createAcrylSessionBridge, type AcrylSessionBridge, type AcrylSessionBridgeOptions, } from './session-bridge.ts';
|
|
4
|
+
export { installSessionLogExporter, type InstallSessionLogExporterOptions, } from './session-log-exporter.ts';
|
|
5
|
+
export { ACRYL_DSH_ENGINE_DIR_NAME, ACRYL_HOME_DIR_NAME, resolveAcrylDshHome, resolveAcrylHome, } from './acryl-home.ts';
|
|
4
6
|
import type { Context } from '@deepseek-ai/cordis';
|
|
5
7
|
export interface BootAcrylHarnessProfileOptions {
|
|
6
8
|
readonly profile: string;
|
|
@@ -22,6 +22,19 @@ export interface AcrylSessionBridge {
|
|
|
22
22
|
readonly sessionId: string;
|
|
23
23
|
readonly text: string;
|
|
24
24
|
}): Promise<void>;
|
|
25
|
+
/**
|
|
26
|
+
* Switch an already-open session's live model. `agentOptions.provider`/`model`
|
|
27
|
+
* are a one-time construction input to `ctx.agents.create` — not a live
|
|
28
|
+
* setting — so this is the only thing that changes what a running session
|
|
29
|
+
* sends its next request to (`ModelSelectionRef` installed on the agent's
|
|
30
|
+
* own scoped context via `installModelSelection`, per-step prompt assembly
|
|
31
|
+
* reads it fresh).
|
|
32
|
+
*/
|
|
33
|
+
selectModel(input: {
|
|
34
|
+
readonly sessionId: string;
|
|
35
|
+
readonly provider: string;
|
|
36
|
+
readonly model: string;
|
|
37
|
+
}): Promise<void>;
|
|
25
38
|
cancel(sessionId: string): Promise<void>;
|
|
26
39
|
dispose(): Promise<void>;
|
|
27
40
|
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A durable, cross-surface debug log for ACRYL sessions.
|
|
3
|
+
*
|
|
4
|
+
* Cordis's own `ctx.logger` already carries every structured log record any
|
|
5
|
+
* plugin emits, but nothing in this stack persisted it anywhere — a failure
|
|
6
|
+
* like a vendored provider's OAuth error only ever reached the terminal
|
|
7
|
+
* transcript, gone the moment the pane scrolled or the process exited. This
|
|
8
|
+
* registers one JSONL file exporter on `ctx.logger` per surface (CLI/TUI,
|
|
9
|
+
* web, and — once wired there too — the desktop GUI), so `error`/`warn`
|
|
10
|
+
* records (and everything, when `ACRYL_LOG_LEVEL=debug`) survive the session
|
|
11
|
+
* and can be read back after the fact instead of re-derived from a
|
|
12
|
+
* screenshot.
|
|
13
|
+
*
|
|
14
|
+
* @module acryl-harness-runtime/session-log-exporter
|
|
15
|
+
*/
|
|
16
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
17
|
+
export interface InstallSessionLogExporterOptions {
|
|
18
|
+
/** Which ACRYL surface this process is (`tui`, `web`, `desktop`) — becomes part of the log filename. */
|
|
19
|
+
readonly surface: string;
|
|
20
|
+
/** Harness home override; defaults to `$DSH_HOME`/`~/.dsh` exactly like credentials/settings resolve it. */
|
|
21
|
+
readonly dshHome?: string;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Register the file exporter for this process's lifetime. `ctx.logger.exporter()`
|
|
25
|
+
* already ties its own disposal to the fiber that registers it (see
|
|
26
|
+
* `LoggerService.exporter` in `@deepseek-ai/cordis`), so this needs no extra
|
|
27
|
+
* `ctx.effect()` wrapper of its own.
|
|
28
|
+
* @param ctx - the plugin context whose `ctx.logger` gains the exporter.
|
|
29
|
+
* @param options - which surface/home this log file belongs to.
|
|
30
|
+
*/
|
|
31
|
+
export declare function installSessionLogExporter(ctx: Context, options: InstallSessionLogExporterOptions): void;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ACRYL's own data root, nested one level above the DSH engine home it
|
|
3
|
+
* composes.
|
|
4
|
+
*
|
|
5
|
+
* The stock DSH Desktop app (from dshdesktop.com) uses plain `~/.dsh`, and so
|
|
6
|
+
* did every ACRYL surface until now — sharing that root made the two
|
|
7
|
+
* genuinely different products silently share credentials/settings/sessions,
|
|
8
|
+
* which is both confusing and useless for comparing ACRYL against a stock
|
|
9
|
+
* DSH Desktop install side by side. ACRYL now owns `~/.acryl` and nests each
|
|
10
|
+
* engine's artifacts under it by engine name:
|
|
11
|
+
*
|
|
12
|
+
* ```txt
|
|
13
|
+
* ~/.acryl/ ACRYL's own root — everything not engine-specific
|
|
14
|
+
* ~/.acryl/.dsh/ the DSH engine home (what DSH_HOME resolves to)
|
|
15
|
+
* ~/.acryl/.pi/ reserved for a future pi.dev engine
|
|
16
|
+
* ```
|
|
17
|
+
*
|
|
18
|
+
* `$DSH_HOME`, if a caller has already set it explicitly, still wins — this
|
|
19
|
+
* only changes the *default* the harness's own `resolveDshHome()` falls
|
|
20
|
+
* back to when nothing overrides it.
|
|
21
|
+
*
|
|
22
|
+
* @module acryl-harness-runtime/acryl-home
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
import { homedir } from 'node:os'
|
|
26
|
+
import { join } from 'node:path'
|
|
27
|
+
import { resolveDshHome } from '@deepseek-ai/dsh-home-paths'
|
|
28
|
+
|
|
29
|
+
/** ACRYL's own root directory name under the OS home. */
|
|
30
|
+
export const ACRYL_HOME_DIR_NAME = '.acryl'
|
|
31
|
+
|
|
32
|
+
/** The DSH engine's directory name, nested under ACRYL's root. */
|
|
33
|
+
export const ACRYL_DSH_ENGINE_DIR_NAME = '.dsh'
|
|
34
|
+
|
|
35
|
+
/** ACRYL's own root — `~/.acryl` unless `$ACRYL_HOME` overrides it. */
|
|
36
|
+
export function resolveAcrylHome(env: Record<string, string | undefined> = process.env): string {
|
|
37
|
+
const overridden = env.ACRYL_HOME?.trim()
|
|
38
|
+
return overridden && overridden !== '' ? overridden : join(homedir(), ACRYL_HOME_DIR_NAME)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* The DSH engine home ACRYL boots against: `$DSH_HOME` if a caller already
|
|
43
|
+
* set it (highest precedence, same as `resolveDshHome()` itself), otherwise
|
|
44
|
+
* `<acrylHome>/.dsh` instead of the harness's own bare `~/.dsh` default.
|
|
45
|
+
*/
|
|
46
|
+
export function resolveAcrylDshHome(env: Record<string, string | undefined> = process.env): string {
|
|
47
|
+
const overridden = env.DSH_HOME?.trim()
|
|
48
|
+
if (overridden && overridden !== '') return resolveDshHome(undefined, env)
|
|
49
|
+
return resolveDshHome(join(resolveAcrylHome(env), ACRYL_DSH_ENGINE_DIR_NAME), env)
|
|
50
|
+
}
|
|
@@ -14,6 +14,16 @@ export {
|
|
|
14
14
|
type AcrylSessionBridge,
|
|
15
15
|
type AcrylSessionBridgeOptions,
|
|
16
16
|
} from './session-bridge.ts'
|
|
17
|
+
export {
|
|
18
|
+
installSessionLogExporter,
|
|
19
|
+
type InstallSessionLogExporterOptions,
|
|
20
|
+
} from './session-log-exporter.ts'
|
|
21
|
+
export {
|
|
22
|
+
ACRYL_DSH_ENGINE_DIR_NAME,
|
|
23
|
+
ACRYL_HOME_DIR_NAME,
|
|
24
|
+
resolveAcrylDshHome,
|
|
25
|
+
resolveAcrylHome,
|
|
26
|
+
} from './acryl-home.ts'
|
|
17
27
|
|
|
18
28
|
import { writeFileSync } from 'node:fs'
|
|
19
29
|
import { createRequire } from 'node:module'
|
|
@@ -30,8 +40,10 @@ import {
|
|
|
30
40
|
resolveProfileDir,
|
|
31
41
|
} from '@deepseek-ai/dsh-app-boot'
|
|
32
42
|
|
|
43
|
+
import { resolveAcrylDshHome } from './acryl-home.ts'
|
|
33
44
|
import { createAcrylCodingCapabilityPatches } from './coding-capabilities.ts'
|
|
34
45
|
import { installAcrylWorkspaceStatusTool } from './plugin-acryl-workspace-status.ts'
|
|
46
|
+
import { installSessionLogExporter } from './session-log-exporter.ts'
|
|
35
47
|
|
|
36
48
|
const require = createRequire(import.meta.url)
|
|
37
49
|
const dshInstallAnchor = require.resolve('@deepseek-ai/dsh/package.json')
|
|
@@ -53,6 +65,7 @@ export async function bootAcrylHarnessProfile(
|
|
|
53
65
|
options: BootAcrylHarnessProfileOptions,
|
|
54
66
|
): Promise<AcrylHarnessRuntime> {
|
|
55
67
|
if (options.profile.trim() === '') throw new Error('ACRYL Harness profile must not be empty')
|
|
68
|
+
process.env.DSH_HOME = resolveAcrylDshHome()
|
|
56
69
|
const profileDirectory = resolveProfileDir(options.profile)
|
|
57
70
|
initProfile(profileDirectory, DEFAULT_PROFILE_BUNDLES)
|
|
58
71
|
healProfilesModuleFallback(dshInstallAnchor)
|
|
@@ -72,6 +85,7 @@ export async function bootAcrylHarnessProfile(
|
|
|
72
85
|
}
|
|
73
86
|
const ctx = await boot('acryl', rootConfig, patches, options.prepare)
|
|
74
87
|
if ((ctx as { tools?: unknown }).tools) installAcrylWorkspaceStatusTool(ctx)
|
|
88
|
+
installSessionLogExporter(ctx, { surface: 'tui' })
|
|
75
89
|
let disposed = false
|
|
76
90
|
return Object.freeze({
|
|
77
91
|
ctx,
|
|
@@ -110,6 +124,7 @@ export async function bootAcrylWebProfile(
|
|
|
110
124
|
options: BootAcrylWebProfileOptions = {},
|
|
111
125
|
): Promise<AcrylWebRuntime> {
|
|
112
126
|
const profileName = 'web'
|
|
127
|
+
process.env.DSH_HOME = resolveAcrylDshHome()
|
|
113
128
|
const profileDirectory = resolveProfileDir(profileName)
|
|
114
129
|
initProfile(profileDirectory, DEFAULT_PROFILE_BUNDLES)
|
|
115
130
|
healProfilesModuleFallback(dshInstallAnchor)
|
|
@@ -127,6 +142,7 @@ export async function bootAcrylWebProfile(
|
|
|
127
142
|
return options.prepare?.(hostCtx)
|
|
128
143
|
})
|
|
129
144
|
if ((ctx as { tools?: unknown }).tools) installAcrylWorkspaceStatusTool(ctx)
|
|
145
|
+
installSessionLogExporter(ctx, { surface: 'web' })
|
|
130
146
|
const startup = ctx.get('webStartup') as { host?: string; port?: number } | undefined
|
|
131
147
|
const host = startup?.host ?? '127.0.0.1'
|
|
132
148
|
const port = startup?.port ?? 3080
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Context } from '@deepseek-ai/cordis'
|
|
2
|
-
import type
|
|
2
|
+
import { installModelSelection, type Agent, type AgentHandle, type ModelSelectionRef } from '@deepseek-ai/dsh-agent'
|
|
3
3
|
import { createUserMessage } from '@deepseek-ai/dsh-llm'
|
|
4
4
|
import { SessionId, type SessionEvent } from '@deepseek-ai/dsh-session'
|
|
5
5
|
import type {} from '@deepseek-ai/dsh-agent-default-model'
|
|
@@ -39,6 +39,15 @@ export interface AcrylSessionBridge {
|
|
|
39
39
|
listener: (event: SessionEvent) => void,
|
|
40
40
|
): Promise<AcrylSessionEventSubscription>
|
|
41
41
|
submitPrompt(input: { readonly sessionId: string; readonly text: string }): Promise<void>
|
|
42
|
+
/**
|
|
43
|
+
* Switch an already-open session's live model. `agentOptions.provider`/`model`
|
|
44
|
+
* are a one-time construction input to `ctx.agents.create` — not a live
|
|
45
|
+
* setting — so this is the only thing that changes what a running session
|
|
46
|
+
* sends its next request to (`ModelSelectionRef` installed on the agent's
|
|
47
|
+
* own scoped context via `installModelSelection`, per-step prompt assembly
|
|
48
|
+
* reads it fresh).
|
|
49
|
+
*/
|
|
50
|
+
selectModel(input: { readonly sessionId: string; readonly provider: string; readonly model: string }): Promise<void>
|
|
42
51
|
cancel(sessionId: string): Promise<void>
|
|
43
52
|
dispose(): Promise<void>
|
|
44
53
|
}
|
|
@@ -101,6 +110,8 @@ export function createAcrylSessionBridge(
|
|
|
101
110
|
options: AcrylSessionBridgeOptions,
|
|
102
111
|
): AcrylSessionBridge {
|
|
103
112
|
const handles = new Map<string, AgentHandle>()
|
|
113
|
+
const modelSelections = new Map<string, ModelSelectionRef>()
|
|
114
|
+
const modelSelectionDisposers = new Map<string, () => void>()
|
|
104
115
|
const subscribers = new Map<string, Set<(snapshot: AcrylSessionSnapshot) => void>>()
|
|
105
116
|
const eventListeners = new Map<string, Set<(event: SessionEvent) => void>>()
|
|
106
117
|
let disposed = false
|
|
@@ -170,6 +181,9 @@ export function createAcrylSessionBridge(
|
|
|
170
181
|
agentOptions: { provider: selection.provider, model: selection.model },
|
|
171
182
|
})
|
|
172
183
|
handles.set(handle.agent.id, handle)
|
|
184
|
+
const ref: ModelSelectionRef = { current: undefined, assembled: undefined }
|
|
185
|
+
modelSelectionDisposers.set(handle.agent.id, installModelSelection(handle.agent.ctx, ref))
|
|
186
|
+
modelSelections.set(handle.agent.id, ref)
|
|
173
187
|
return handle.agent.id
|
|
174
188
|
},
|
|
175
189
|
snapshot,
|
|
@@ -235,6 +249,12 @@ export function createAcrylSessionBridge(
|
|
|
235
249
|
}))
|
|
236
250
|
await accepted
|
|
237
251
|
},
|
|
252
|
+
async selectModel(input: { readonly sessionId: string; readonly provider: string; readonly model: string }): Promise<void> {
|
|
253
|
+
agentFor(input.sessionId)
|
|
254
|
+
const ref = modelSelections.get(input.sessionId)
|
|
255
|
+
if (ref === undefined) throw new Error(`ACRYL session ${input.sessionId} has no installed model selection`)
|
|
256
|
+
ref.current = { provider: input.provider, model: input.model }
|
|
257
|
+
},
|
|
238
258
|
async cancel(sessionId: string): Promise<void> {
|
|
239
259
|
agentFor(sessionId).cancel({ kind: 'user' })
|
|
240
260
|
},
|
|
@@ -244,6 +264,9 @@ export function createAcrylSessionBridge(
|
|
|
244
264
|
offSessionEvent()
|
|
245
265
|
subscribers.clear()
|
|
246
266
|
eventListeners.clear()
|
|
267
|
+
for (const dispose of modelSelectionDisposers.values()) dispose()
|
|
268
|
+
modelSelectionDisposers.clear()
|
|
269
|
+
modelSelections.clear()
|
|
247
270
|
// Durable continuity: idle the turn, checkpoint the session log, then
|
|
248
271
|
// release the native handle. Mirror of Tomo's shutdown sequence, owned
|
|
249
272
|
// here so every surface gets the same durability guarantee.
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A durable, cross-surface debug log for ACRYL sessions.
|
|
3
|
+
*
|
|
4
|
+
* Cordis's own `ctx.logger` already carries every structured log record any
|
|
5
|
+
* plugin emits, but nothing in this stack persisted it anywhere — a failure
|
|
6
|
+
* like a vendored provider's OAuth error only ever reached the terminal
|
|
7
|
+
* transcript, gone the moment the pane scrolled or the process exited. This
|
|
8
|
+
* registers one JSONL file exporter on `ctx.logger` per surface (CLI/TUI,
|
|
9
|
+
* web, and — once wired there too — the desktop GUI), so `error`/`warn`
|
|
10
|
+
* records (and everything, when `ACRYL_LOG_LEVEL=debug`) survive the session
|
|
11
|
+
* and can be read back after the fact instead of re-derived from a
|
|
12
|
+
* screenshot.
|
|
13
|
+
*
|
|
14
|
+
* @module acryl-harness-runtime/session-log-exporter
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import { appendFileSync, mkdirSync } from 'node:fs'
|
|
18
|
+
import { join } from 'node:path'
|
|
19
|
+
import type { Context } from '@deepseek-ai/cordis'
|
|
20
|
+
import { resolveDshHome } from '@deepseek-ai/dsh-home-paths'
|
|
21
|
+
|
|
22
|
+
export interface InstallSessionLogExporterOptions {
|
|
23
|
+
/** Which ACRYL surface this process is (`tui`, `web`, `desktop`) — becomes part of the log filename. */
|
|
24
|
+
readonly surface: string
|
|
25
|
+
/** Harness home override; defaults to `$DSH_HOME`/`~/.dsh` exactly like credentials/settings resolve it. */
|
|
26
|
+
readonly dshHome?: string
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const LOGGER_LEVEL_WARN = 2
|
|
30
|
+
const LOGGER_LEVEL_DEBUG = 3
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Register the file exporter for this process's lifetime. `ctx.logger.exporter()`
|
|
34
|
+
* already ties its own disposal to the fiber that registers it (see
|
|
35
|
+
* `LoggerService.exporter` in `@deepseek-ai/cordis`), so this needs no extra
|
|
36
|
+
* `ctx.effect()` wrapper of its own.
|
|
37
|
+
* @param ctx - the plugin context whose `ctx.logger` gains the exporter.
|
|
38
|
+
* @param options - which surface/home this log file belongs to.
|
|
39
|
+
*/
|
|
40
|
+
export function installSessionLogExporter(ctx: Context, options: InstallSessionLogExporterOptions): void {
|
|
41
|
+
const dshHome = resolveDshHome(options.dshHome)
|
|
42
|
+
const logDir = join(dshHome, 'logs')
|
|
43
|
+
try {
|
|
44
|
+
mkdirSync(logDir, { recursive: true, mode: 0o700 })
|
|
45
|
+
} catch {
|
|
46
|
+
return // best-effort diagnostics only; a session must never fail to start over this
|
|
47
|
+
}
|
|
48
|
+
const day = new Date().toISOString().slice(0, 10)
|
|
49
|
+
const logFile = join(logDir, `acryl-${options.surface}-${day}.jsonl`)
|
|
50
|
+
const threshold = process.env.ACRYL_LOG_LEVEL === 'debug' ? LOGGER_LEVEL_DEBUG : LOGGER_LEVEL_WARN
|
|
51
|
+
|
|
52
|
+
ctx.logger.exporter({
|
|
53
|
+
export(message) {
|
|
54
|
+
if (message.level > threshold) return
|
|
55
|
+
try {
|
|
56
|
+
appendFileSync(logFile, `${JSON.stringify({
|
|
57
|
+
ts: new Date(message.ts).toISOString(),
|
|
58
|
+
type: message.type,
|
|
59
|
+
name: message.name,
|
|
60
|
+
args: message.args.map(arg => (arg instanceof Error
|
|
61
|
+
? { message: arg.message, stack: arg.stack, name: arg.name }
|
|
62
|
+
: arg)),
|
|
63
|
+
})}\n`, { mode: 0o600 })
|
|
64
|
+
} catch {
|
|
65
|
+
// best-effort: a write failure here must never take a session down
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
})
|
|
69
|
+
}
|
package/runtime/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "acryl-tui",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.35",
|
|
4
4
|
"private": true,
|
|
5
5
|
"description": "Canonical ACRYL pi-tui coding-agent terminal client",
|
|
6
6
|
"license": "MIT",
|
|
@@ -25,7 +25,9 @@
|
|
|
25
25
|
"node": ">=22"
|
|
26
26
|
},
|
|
27
27
|
"scripts": {
|
|
28
|
+
"prebuild": "node scripts/generate-build-info.mjs",
|
|
28
29
|
"build": "tsdown && tsc -p tsconfig.json --emitDeclarationOnly",
|
|
30
|
+
"pretypecheck": "node scripts/generate-build-info.mjs",
|
|
29
31
|
"typecheck": "tsc -p tsconfig.json --noEmit && tsc -p tsconfig.tests.json --noEmit",
|
|
30
32
|
"test": "vitest run",
|
|
31
33
|
"tui": "node lib/bin.js tui",
|
package/runtime/receipt.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"schemaVersion": 1,
|
|
3
3
|
"surface": "cli",
|
|
4
4
|
"target": "linux-x64",
|
|
5
|
-
"version": "0.1.
|
|
5
|
+
"version": "0.1.35",
|
|
6
6
|
"packageName": "acryl-cli-linux-x64",
|
|
7
|
-
"payloadSha256": "
|
|
7
|
+
"payloadSha256": "0e4da558f00aca2aa26c52a10677258683194e04e009d906f8d1d534ca688d53"
|
|
8
8
|
}
|