acryl-cli-linux-x64 0.1.31 → 0.1.36
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 +865 -242
- package/runtime/lib/index.js +867 -242
- 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 +9 -6
- package/runtime/lib/types/tui/auth-guidance.d.ts +0 -2
- package/runtime/lib/types/tui/listWindow.d.ts +24 -0
- package/runtime/lib/types/tui/login/LoginOverlay.d.ts +52 -11
- package/runtime/lib/types/tui/login/types.d.ts +6 -1
- package/runtime/lib/types/tui/modelProfile/ModelProfileOverlay.d.ts +41 -3
- package/runtime/lib/types/tui/modelProfile/types.d.ts +24 -0
- package/runtime/lib/types/tui/store.d.ts +10 -0
- package/runtime/lib/types/yly/yly-pet.d.ts +1 -1
- package/runtime/lib/types/yly/yly-programs.d.ts +1 -1
- 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/lib/index.js +66 -1
- package/runtime/node_modules/acryl-control/lib/types/authorization/service.d.ts +23 -0
- package/runtime/node_modules/acryl-control/lib/types/authorization/types.d.ts +46 -0
- package/runtime/node_modules/acryl-control/lib/types/credential/projection.d.ts +63 -0
- package/runtime/node_modules/acryl-control/lib/types/credential/types.d.ts +38 -0
- package/runtime/node_modules/acryl-control/lib/types/index.d.ts +4 -0
- 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 +4 -2
- package/runtime/receipt.json +2 -2
|
@@ -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
|
-
"name": "acryl-
|
|
3
|
-
"version": "0.1.
|
|
2
|
+
"name": "acryl-cli",
|
|
3
|
+
"version": "0.1.36",
|
|
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.36",
|
|
6
6
|
"packageName": "acryl-cli-linux-x64",
|
|
7
|
-
"payloadSha256": "
|
|
7
|
+
"payloadSha256": "99de89fd03be2f9ae485b5d15b52063a909928eaff7c9330f178d98e55a22a32"
|
|
8
8
|
}
|