better-dsh 0.0.0 → 0.2.2-a
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/LICENSE +24 -0
- package/README.md +294 -4
- package/control-prompt.md +37 -0
- package/cordis.patch.yml +53 -0
- package/docs/00_adr/0001-bridge-tool-layer-not-service-layer.md +14 -0
- package/docs/00_adr/0002-masking-is-presentation-only.md +15 -0
- package/docs/10_plans/A2A-messaging-channel-test-archive.md +256 -0
- package/docs/10_plans/code-mode-vs-rlm-ipython-comparison.md +137 -0
- package/docs/10_plans/dashr-blueprint-review.md +201 -0
- package/docs/10_plans/dashr-blueprint.md +561 -0
- package/docs/10_plans/dashr-compaction-window-and-archive.md +307 -0
- package/docs/10_plans/dashr-profile-layer-feasibility.md +367 -0
- package/docs/10_plans/dashr-sandbox-escalation-semantics-gap.md +171 -0
- package/docs/10_plans/dashr-security-sandbox-analysis.md +187 -0
- package/docs/10_plans/dashr-surface-invariant-and-omp-imports.md +97 -0
- package/docs/10_plans/ipython-kernel-interactive-interface-test-report.md +152 -0
- package/docs/10_plans/kernel-refactoring/Dash-IPython-Control-Prompt-draft.md +146 -0
- package/docs/10_plans/kernel-refactoring/Dash-IPython-Control-Prompt-draft_v3.md +50 -0
- package/docs/10_plans/kernel-refactoring/Dash-IPython-Control-Prompt-draft_v4.md +79 -0
- package/docs/10_plans/kernel-refactoring/Dash-vs-PrimeAgent-systemprompt-toolcatalog-comparison.md +138 -0
- package/docs/10_plans/kernel-refactoring/RLM-system-prompt-injection-gap-report.md +161 -0
- package/docs/10_plans/kernel-refactoring/V0.1.5-development-plan.md +109 -0
- package/docs/10_plans/kernel-refactoring/actinoable-surface-to-llm-in-agent-runtime_dsh.md +50 -0
- package/docs/10_plans/kernel-refactoring/actinoable-surface-to-llm-in-agent-runtime_prime.md +113 -0
- package/docs/10_plans/recallable-compaction.md +147 -0
- package/docs/10_plans/spike-tag-repro.mjs +102 -0
- package/docs/10_plans/upstream-analysis.md +128 -0
- package/docs/50_test-reports/REPL-/345/267/245/345/205/267/350/260/203/347/224/250-/346/210/252/346/226/255/350/257/212/346/226/255.md +110 -0
- package/docs/50_test-reports/kernel-provisioning.md +44 -0
- package/docs/50_test-reports/repl-kernel-provisioning-test-report.md +87 -0
- package/docs/50_test-reports/upstream-dsh-0.1.2-alpha.5-local-test-report.md +81 -0
- package/docs/50_test-reports/upstream-dsh-0.1.2-alpha.5-report.md +93 -0
- package/docs/50_test-reports/v0.1.8-improved-/345/256/236/346/265/213/346/212/245/345/221/212.md +142 -0
- package/docs/50_test-reports/v0.1.8-/345/256/236/346/265/213/346/212/245/345/221/212.md +193 -0
- package/docs/50_test-reports/v0.1.8b-/345/256/236/346/265/213/346/212/245/345/221/212.md +96 -0
- package/docs/50_test-reports/v0.1.8c-/345/256/236/346/265/213/346/212/245/345/221/212.md +127 -0
- package/docs/50_test-reports/v0.1.8d-/345/256/236/346/265/213/346/212/245/345/221/212.md +150 -0
- package/docs/50_test-reports/v0.1.8d_artifacts/README.md +138 -0
- package/docs/50_test-reports/v0.1.8d_artifacts/code-mode-repl-only.observation.md +74 -0
- package/docs/50_test-reports/v0.1.8d_artifacts/dsh-session-session-4a293388-9ae1-474b-87a0-9e17bb556d94.jsonl +3890 -0
- package/docs/50_test-reports/v0.1.8d_artifacts/dsh-session-session-4a293388-9ae1-474b-87a0-9e17bb556d94.w-sample-0435.jsonl +544 -0
- package/docs/50_test-reports/v0.1.8d_artifacts/functions.json +592 -0
- package/docs/50_test-reports/v0.1.8d_artifacts/skills-catalog.snapshot.md +30 -0
- package/docs/50_test-reports/v0.1.8d_artifacts/tools-sdk.output-schemas.json +1236 -0
- package/docs/50_test-reports/v0.1.8d_artifacts/tools-sdk.python.txt +592 -0
- package/docs/50_test-reports/v0.1.8d_artifacts/tools-sdk.typescript.txt +516 -0
- package/docs/50_test-reports/v0.1.8d_artifacts/wire-vs-transcription.diff.md +54 -0
- package/docs/50_test-reports/v0.1.8e-/345/256/236/346/265/213/346/212/245/345/221/212.md +224 -0
- package/docs/50_test-reports/v0.1.9a-/345/256/236/346/265/213/346/212/245/345/221/212.md +168 -0
- package/docs/50_test-reports/v0.2.0b-/345/256/236/346/265/213/346/212/245/345/221/212.md +123 -0
- package/docs/50_test-reports/v0.2.0b_artifacts/f2probe/Cargo.lock +7 -0
- package/docs/50_test-reports/v0.2.0b_artifacts/f2probe/Cargo.toml +6 -0
- package/docs/50_test-reports/v0.2.0b_artifacts/f2probe/src/bin/messy.rs +8 -0
- package/docs/50_test-reports/v0.2.0b_artifacts/f2probe/src/main.rs +4 -0
- package/docs/50_test-reports/v0.2.0b_artifacts/hashline-probe.md +5 -0
- package/docs/50_test-reports/v0.2.0b_artifacts/slowprobe/Cargo.lock +7 -0
- package/docs/50_test-reports/v0.2.0b_artifacts/slowprobe/Cargo.toml +7 -0
- package/docs/50_test-reports/v0.2.0b_artifacts/slowprobe/build.rs +4 -0
- package/docs/50_test-reports/v0.2.0b_artifacts/slowprobe/src/main.rs +13 -0
- package/docs/50_test-reports/v0.2.1-/345/256/236/346/265/213/346/212/245/345/221/212.md +110 -0
- package/docs/50_test-reports/v0.2.1b-/345/256/236/346/265/213/346/212/245/345/221/212.md +86 -0
- package/docs/50_test-reports/v0.2.1c-/345/256/236/346/265/213/346/212/245/345/221/212.md +66 -0
- package/docs/50_test-reports/v0.2.1d-/345/256/236/346/265/213/346/212/245/345/221/212.md +67 -0
- package/docs/50_test-reports/v0.2.1e-P1-/345/256/236/346/265/213/346/212/245/345/221/212.md +136 -0
- package/docs/50_test-reports/v0.2.1ef-dev-audit-report.md +73 -0
- package/docs/50_test-reports/v0.2.1f-plugin-shipped-ui-patches/345/256/236/346/265/213/346/212/245/345/221/212.md +102 -0
- package/docs/60_exploration-and-research/cordis-research.md +350 -0
- package/docs/60_exploration-and-research/dsh-web-profile-package-map.md +186 -0
- package/docs/60_exploration-and-research/dsh-web-ui-slot-system-research.md +310 -0
- package/docs/60_exploration-and-research/dsh-webui-strip-boundary-research.md +300 -0
- package/docs/60_exploration-and-research/ios-chat-app-bridge-research.md +324 -0
- package/docs/60_exploration-and-research/web-frontend-composability-research.md +191 -0
- package/docs/REPL-/345/267/245/345/205/267/350/260/203/347/224/250-/346/210/252/346/226/255/350/257/212/346/226/255.md +110 -0
- package/docs/adr/0001-bridge-tool-layer-not-service-layer.md +14 -0
- package/docs/adr/0002-masking-is-presentation-only.md +15 -0
- package/docs/distro-blueprint.md +81 -0
- package/docs/dsh-webUI-with-rlm-mode.png +0 -0
- package/docs/plans/A2A-messaging-channel-test-archive.md +256 -0
- package/docs/plans/code-mode-vs-rlm-ipython-comparison.md +137 -0
- package/docs/plans/dashr-blueprint-review.md +201 -0
- package/docs/plans/dashr-blueprint.md +561 -0
- package/docs/plans/dashr-compaction-window-and-archive.md +307 -0
- package/docs/plans/dashr-profile-layer-feasibility.md +367 -0
- package/docs/plans/dashr-sandbox-escalation-semantics-gap.md +171 -0
- package/docs/plans/dashr-security-sandbox-analysis.md +187 -0
- package/docs/plans/dashr-surface-invariant-and-omp-imports.md +97 -0
- package/docs/plans/ipython-kernel-interactive-interface-test-report.md +152 -0
- package/docs/plans/kernel-refactoring/Dash-IPython-Control-Prompt-draft.md +146 -0
- package/docs/plans/kernel-refactoring/Dash-IPython-Control-Prompt-draft_v3.md +50 -0
- package/docs/plans/kernel-refactoring/Dash-IPython-Control-Prompt-draft_v4.md +79 -0
- package/docs/plans/kernel-refactoring/Dash-vs-PrimeAgent-systemprompt-toolcatalog-comparison.md +138 -0
- package/docs/plans/kernel-refactoring/RLM-system-prompt-injection-gap-report.md +161 -0
- package/docs/plans/kernel-refactoring/V0.1.5-development-plan.md +109 -0
- package/docs/plans/kernel-refactoring/actinoable-surface-to-llm-in-agent-runtime_dsh.md +50 -0
- package/docs/plans/kernel-refactoring/actinoable-surface-to-llm-in-agent-runtime_prime.md +113 -0
- package/docs/plans/recallable-compaction.md +147 -0
- package/docs/plans/spike-tag-repro.mjs +102 -0
- package/docs/plans/upstream-analysis.md +128 -0
- package/docs/repositioning-and-rebranding.md +102 -0
- package/docs/v0.1.8-improved-/345/256/236/346/265/213/346/212/245/345/221/212.md +142 -0
- package/docs/v0.1.8-/345/256/236/346/265/213/346/212/245/345/221/212.md +193 -0
- package/docs/v0.1.8b-/345/256/236/346/265/213/346/212/245/345/221/212.md +96 -0
- package/docs/v0.1.8c-/345/256/236/346/265/213/346/212/245/345/221/212.md +127 -0
- package/docs/v0.1.8d-/345/256/236/346/265/213/346/212/245/345/221/212.md +150 -0
- package/docs/v0.1.8d_artifacts/README.md +138 -0
- package/docs/v0.1.8d_artifacts/code-mode-repl-only.observation.md +74 -0
- package/docs/v0.1.8d_artifacts/dsh-session-session-4a293388-9ae1-474b-87a0-9e17bb556d94.jsonl +3890 -0
- package/docs/v0.1.8d_artifacts/dsh-session-session-4a293388-9ae1-474b-87a0-9e17bb556d94.w-sample-0435.jsonl +544 -0
- package/docs/v0.1.8d_artifacts/functions.json +592 -0
- package/docs/v0.1.8d_artifacts/skills-catalog.snapshot.md +30 -0
- package/docs/v0.1.8d_artifacts/tools-sdk.output-schemas.json +1236 -0
- package/docs/v0.1.8d_artifacts/tools-sdk.python.txt +592 -0
- package/docs/v0.1.8d_artifacts/tools-sdk.typescript.txt +516 -0
- package/docs/v0.1.8d_artifacts/wire-vs-transcription.diff.md +54 -0
- package/docs/v0.1.8e-/345/256/236/346/265/213/346/212/245/345/221/212.md +224 -0
- package/docs/v0.1.9a-/345/256/236/346/265/213/346/212/245/345/221/212.md +168 -0
- package/docs/v0.2.0b-/345/256/236/346/265/213/346/212/245/345/221/212.md +123 -0
- package/docs/v0.2.0b_artifacts/f2probe/Cargo.lock +7 -0
- package/docs/v0.2.0b_artifacts/f2probe/Cargo.toml +6 -0
- package/docs/v0.2.0b_artifacts/f2probe/src/bin/messy.rs +8 -0
- package/docs/v0.2.0b_artifacts/f2probe/src/main.rs +4 -0
- package/docs/v0.2.0b_artifacts/hashline-probe.md +5 -0
- package/docs/v0.2.0b_artifacts/slowprobe/Cargo.lock +7 -0
- package/docs/v0.2.0b_artifacts/slowprobe/Cargo.toml +7 -0
- package/docs/v0.2.0b_artifacts/slowprobe/build.rs +4 -0
- package/docs/v0.2.0b_artifacts/slowprobe/src/main.rs +13 -0
- package/docs/v0.2.1-/345/256/236/346/265/213/346/212/245/345/221/212.md +110 -0
- package/docs/v0.2.1b-/345/256/236/346/265/213/346/212/245/345/221/212.md +86 -0
- package/docs/v0.2.1c-/345/256/236/346/265/213/346/212/245/345/221/212.md +66 -0
- package/lib/client/index.js +473 -0
- package/lib/index.d.ts +736 -0
- package/lib/index.js +11518 -0
- package/lib/kernel-env-hxaihi9C.js +195 -0
- package/lib/kernel-env.d.ts +80 -0
- package/lib/kernel-env.js +3 -0
- package/lib/py-sdk-BCaOGYz7.d.ts +125 -0
- package/lib/py-sdk-CbgYiX8O.js +691 -0
- package/lib/py-sdk.d.ts +2 -0
- package/lib/py-sdk.js +3 -0
- package/package.json +325 -4
- package/scripts/kernel-provision.mjs +35 -0
- package/index.js +0 -3
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
import { existsSync, mkdirSync } from "node:fs";
|
|
2
|
+
import { dirname, join, resolve } from "node:path";
|
|
3
|
+
import { execFile } from "node:child_process";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
import { promisify } from "node:util";
|
|
6
|
+
|
|
7
|
+
//#region src/kernel-env.ts
|
|
8
|
+
const execFileAsync = promisify(execFile);
|
|
9
|
+
/** The installed package root (where `lib/` and `src/` live): the default home of the managed venv. */
|
|
10
|
+
const PACKAGE_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), "..");
|
|
11
|
+
/** The config value meaning "no explicit interpreter — auto-manage a venv". */
|
|
12
|
+
const AUTO_PYTHON_SENTINEL = "python3";
|
|
13
|
+
/** Preferred CPython version for a managed venv. */
|
|
14
|
+
const DEFAULT_KERNEL_PYTHON_VERSION = "3.11";
|
|
15
|
+
/** Pinned, tested `ipykernel` version (2026-09-02 tested value; upgrade = explicit change + regression). */
|
|
16
|
+
const IPYKERNEL_VERSION = "7.3.0";
|
|
17
|
+
/** Pinned, tested `dill` version. */
|
|
18
|
+
const DILL_VERSION = "0.4.1";
|
|
19
|
+
/** A probe that never imports user modules and reports exactly what we need. */
|
|
20
|
+
const PROBE_CODE = [
|
|
21
|
+
"import json, sys",
|
|
22
|
+
"r = {\"version\": sys.version.split()[0], \"ipykernel\": False, \"dill\": False}",
|
|
23
|
+
"try:",
|
|
24
|
+
" import ipykernel # noqa: F401",
|
|
25
|
+
" r[\"ipykernel\"] = True",
|
|
26
|
+
"except Exception:",
|
|
27
|
+
" pass",
|
|
28
|
+
"try:",
|
|
29
|
+
" import dill # noqa: F401",
|
|
30
|
+
" r[\"dill\"] = True",
|
|
31
|
+
"except Exception:",
|
|
32
|
+
" pass",
|
|
33
|
+
"print(json.dumps(r))"
|
|
34
|
+
].join("\n");
|
|
35
|
+
async function probePython(python) {
|
|
36
|
+
try {
|
|
37
|
+
const { stdout } = await execFileAsync(python, ["-c", PROBE_CODE], { timeout: 15e3 });
|
|
38
|
+
const parsed = JSON.parse(stdout.trim());
|
|
39
|
+
return {
|
|
40
|
+
version: typeof parsed.version === "string" && parsed.version.length > 0 ? parsed.version : "unknown",
|
|
41
|
+
ipykernel: parsed.ipykernel === true,
|
|
42
|
+
dill: parsed.dill === true
|
|
43
|
+
};
|
|
44
|
+
} catch {
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
/** The venv interpreter path for this platform. */
|
|
49
|
+
function venvPythonPath(venvDir) {
|
|
50
|
+
return process.platform === "win32" ? join(venvDir, "Scripts", "python.exe") : join(venvDir, "bin", "python");
|
|
51
|
+
}
|
|
52
|
+
async function commandExists(cmd) {
|
|
53
|
+
try {
|
|
54
|
+
await execFileAsync(cmd, ["--version"], { timeout: 1e4 });
|
|
55
|
+
return true;
|
|
56
|
+
} catch {
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
/** Tool-cache env for uv: caches live NEXT TO the venv (plugin territory), so a read-only home can never block provisioning. */
|
|
61
|
+
function uvToolEnv(venvDir) {
|
|
62
|
+
const cacheDir = join(dirname(venvDir), ".uv-cache");
|
|
63
|
+
return {
|
|
64
|
+
...process.env,
|
|
65
|
+
UV_CACHE_DIR: cacheDir,
|
|
66
|
+
UV_PYTHON_INSTALL_DIR: join(cacheDir, "python"),
|
|
67
|
+
UV_LINK_MODE: "copy"
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
/** uv venv arguments (pure; unit-tested). */
|
|
71
|
+
function uvVenvArgs(venvDir, pythonVersion) {
|
|
72
|
+
return [
|
|
73
|
+
"venv",
|
|
74
|
+
venvDir,
|
|
75
|
+
"--python",
|
|
76
|
+
pythonVersion
|
|
77
|
+
];
|
|
78
|
+
}
|
|
79
|
+
/** python3 -m venv fallback arguments (pure; cache-free by construction). */
|
|
80
|
+
function venvFallbackArgs(venvDir) {
|
|
81
|
+
return [
|
|
82
|
+
"-m",
|
|
83
|
+
"venv",
|
|
84
|
+
venvDir
|
|
85
|
+
];
|
|
86
|
+
}
|
|
87
|
+
/** uv pip install arguments with pinned versions (pure; unit-tested). */
|
|
88
|
+
function uvInstallArgs(python) {
|
|
89
|
+
return [
|
|
90
|
+
"pip",
|
|
91
|
+
"install",
|
|
92
|
+
"--python",
|
|
93
|
+
python,
|
|
94
|
+
"--quiet",
|
|
95
|
+
`ipykernel==${IPYKERNEL_VERSION}`,
|
|
96
|
+
`dill==${DILL_VERSION}`
|
|
97
|
+
];
|
|
98
|
+
}
|
|
99
|
+
/** pip install arguments with pinned versions for the venv interpreter (pure). */
|
|
100
|
+
function pipInstallArgs() {
|
|
101
|
+
return [
|
|
102
|
+
"-m",
|
|
103
|
+
"pip",
|
|
104
|
+
"install",
|
|
105
|
+
"--quiet",
|
|
106
|
+
"--disable-pip-version-check",
|
|
107
|
+
`ipykernel==${IPYKERNEL_VERSION}`,
|
|
108
|
+
`dill==${DILL_VERSION}`
|
|
109
|
+
];
|
|
110
|
+
}
|
|
111
|
+
/** Create the venv (when absent) and return its interpreter path. */
|
|
112
|
+
async function createVenv(venvDir, pythonVersion) {
|
|
113
|
+
const python = venvPythonPath(venvDir);
|
|
114
|
+
if (existsSync(python)) return python;
|
|
115
|
+
if (await commandExists("uv")) {
|
|
116
|
+
mkdirSync(join(dirname(venvDir), ".uv-cache"), { recursive: true });
|
|
117
|
+
await execFileAsync("uv", uvVenvArgs(venvDir, pythonVersion), {
|
|
118
|
+
timeout: 12e4,
|
|
119
|
+
env: uvToolEnv(venvDir)
|
|
120
|
+
});
|
|
121
|
+
} else await execFileAsync("python3", venvFallbackArgs(venvDir), { timeout: 12e4 });
|
|
122
|
+
return python;
|
|
123
|
+
}
|
|
124
|
+
/** Install pinned `ipykernel` + `dill` into the venv interpreter. */
|
|
125
|
+
async function installDeps(python, venvDir) {
|
|
126
|
+
if (await commandExists("uv")) await execFileAsync("uv", uvInstallArgs(python), {
|
|
127
|
+
timeout: 18e4,
|
|
128
|
+
env: uvToolEnv(venvDir)
|
|
129
|
+
});
|
|
130
|
+
else await execFileAsync(python, pipInstallArgs(), { timeout: 18e4 });
|
|
131
|
+
}
|
|
132
|
+
/** Provision (or repair) the managed venv so it has `ipykernel` + `dill`. */
|
|
133
|
+
async function ensureVenv(venvDir, pythonVersion, log) {
|
|
134
|
+
const python = venvPythonPath(venvDir);
|
|
135
|
+
const existing = existsSync(python) ? await probePython(python) : null;
|
|
136
|
+
if (existing?.ipykernel === true && existing.dill === true) return python;
|
|
137
|
+
await createVenv(venvDir, pythonVersion);
|
|
138
|
+
if (!existsSync(python)) throw new Error(`dashr-repl: managed kernel venv was not created at ${venvDir} (no interpreter at ${python})`);
|
|
139
|
+
log?.("info", `dashr-repl: provisioning kernel venv at ${venvDir} (ipykernel + dill)`);
|
|
140
|
+
await installDeps(python, venvDir);
|
|
141
|
+
return python;
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Resolve the kernel interpreter, provisioning a managed venv when no
|
|
145
|
+
* explicit interpreter is configured. Throws when the resolved interpreter
|
|
146
|
+
* cannot run `ipykernel`; a missing `dill` only disables snapshots (warned).
|
|
147
|
+
*/
|
|
148
|
+
async function resolveKernelEnv(options = {}) {
|
|
149
|
+
const log = options.log;
|
|
150
|
+
const explicit = options.python !== void 0 && options.python !== "" && options.python !== AUTO_PYTHON_SENTINEL ? options.python : void 0;
|
|
151
|
+
if (explicit !== void 0) {
|
|
152
|
+
const probe$1 = await probePython(explicit);
|
|
153
|
+
if (probe$1 === null) throw new Error(`dashr-repl: kernel python ${JSON.stringify(explicit)} could not be executed — check the path`);
|
|
154
|
+
if (!probe$1.ipykernel) throw new Error(`dashr-repl: kernel python ${JSON.stringify(explicit)} has no ipykernel — install it (pip install ipykernel) or set python to a managed venv`);
|
|
155
|
+
if (!probe$1.dill) log?.("warn", `dashr-repl: kernel python ${JSON.stringify(explicit)} has no dill — namespace snapshots are DISABLED (install it: pip install dill)`);
|
|
156
|
+
return {
|
|
157
|
+
python: explicit,
|
|
158
|
+
managed: false,
|
|
159
|
+
venvDir: void 0,
|
|
160
|
+
dill: probe$1.dill,
|
|
161
|
+
ipykernel: true,
|
|
162
|
+
version: probe$1.version
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
const venvDir = options.venvDir ?? join(PACKAGE_ROOT, ".venv-kernel");
|
|
166
|
+
const python = venvPythonPath(venvDir);
|
|
167
|
+
if (options.autoInstall === false) {
|
|
168
|
+
const probe$1 = await probePython(python);
|
|
169
|
+
if (probe$1 === null || !probe$1.ipykernel) throw new Error(`dashr-repl: managed kernel venv is missing or incomplete at ${venvDir} — run 'npm run kernel:venv' in the dashr package, or set kernelAutoInstall: true (or python to a prepared interpreter)`);
|
|
170
|
+
if (!probe$1.dill) log?.("warn", `dashr-repl: kernel venv at ${venvDir} has no dill — namespace snapshots are DISABLED (run 'npm run kernel:venv' to reinstall)`);
|
|
171
|
+
return {
|
|
172
|
+
python,
|
|
173
|
+
managed: true,
|
|
174
|
+
venvDir,
|
|
175
|
+
dill: probe$1.dill,
|
|
176
|
+
ipykernel: true,
|
|
177
|
+
version: probe$1.version
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
const resolved = await ensureVenv(venvDir, options.pythonVersion ?? DEFAULT_KERNEL_PYTHON_VERSION, log);
|
|
181
|
+
const probe = await probePython(resolved);
|
|
182
|
+
if (probe === null || !probe.ipykernel) throw new Error(`dashr-repl: managed kernel venv at ${venvDir} still has no ipykernel after provisioning — check uv/python3-venv availability and retry`);
|
|
183
|
+
if (!probe.dill) log?.("warn", `dashr-repl: managed kernel venv at ${venvDir} has no dill after provisioning — namespace snapshots are DISABLED`);
|
|
184
|
+
return {
|
|
185
|
+
python: resolved,
|
|
186
|
+
managed: true,
|
|
187
|
+
venvDir,
|
|
188
|
+
dill: probe.dill,
|
|
189
|
+
ipykernel: true,
|
|
190
|
+
version: probe.version
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
//#endregion
|
|
195
|
+
export { PACKAGE_ROOT as a, uvInstallArgs as c, venvFallbackArgs as d, IPYKERNEL_VERSION as i, uvToolEnv as l, DEFAULT_KERNEL_PYTHON_VERSION as n, pipInstallArgs as o, DILL_VERSION as r, resolveKernelEnv as s, AUTO_PYTHON_SENTINEL as t, uvVenvArgs as u };
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
//#region src/kernel-env.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Kernel environment resolution and provisioning.
|
|
4
|
+
*
|
|
5
|
+
* The runtime OWNS the interpreter it spawns: it never trusts a bare
|
|
6
|
+
* `python3` on the PATH, because that interpreter may lack `ipykernel`
|
|
7
|
+
* (hard failure — the kernel cannot start) or `dill` (snapshot capability —
|
|
8
|
+
* silently degrading to no snapshots). Instead it resolves one of two
|
|
9
|
+
* environments:
|
|
10
|
+
*
|
|
11
|
+
* - **Explicit** — `config.python` names a real interpreter (a path, or any
|
|
12
|
+
* name other than the bare-`python3` sentinel the default/patch produce).
|
|
13
|
+
* It is probed, and a missing `ipykernel` is a loud error while a missing
|
|
14
|
+
* `dill` is a loud warning (snapshots disabled).
|
|
15
|
+
* - **Managed** — no explicit interpreter: the runtime provisions a venv
|
|
16
|
+
* UNDER THE PACKAGE (`<packageRoot>/.venv-kernel`, or `config.kernelEnvDir`)
|
|
17
|
+
* with `ipykernel` + `dill`, installing it on first use when
|
|
18
|
+
* `config.kernelAutoInstall` is on. The venv lives beside the package, NOT
|
|
19
|
+
* in `/tmp` (the pre-v0.1.9 dangling-symlink failure mode), so it survives
|
|
20
|
+
* the host's tmp reaper and the process restart.
|
|
21
|
+
*
|
|
22
|
+
* Provisioning uses `uv` when available (fast, can fetch the pinned CPython
|
|
23
|
+
* version), falling back to `python3 -m venv` + `ensurepip`. It is idempotent:
|
|
24
|
+
* a complete venv is reused untouched; a partial one is repaired.
|
|
25
|
+
* @module dashr/kernel-env
|
|
26
|
+
*/
|
|
27
|
+
/** The installed package root (where `lib/` and `src/` live): the default home of the managed venv. */
|
|
28
|
+
declare const PACKAGE_ROOT: string;
|
|
29
|
+
/** The config value meaning "no explicit interpreter — auto-manage a venv". */
|
|
30
|
+
declare const AUTO_PYTHON_SENTINEL = "python3";
|
|
31
|
+
/** Preferred CPython version for a managed venv. */
|
|
32
|
+
declare const DEFAULT_KERNEL_PYTHON_VERSION = "3.11";
|
|
33
|
+
/** Pinned, tested `ipykernel` version (2026-09-02 tested value; upgrade = explicit change + regression). */
|
|
34
|
+
declare const IPYKERNEL_VERSION = "7.3.0";
|
|
35
|
+
/** Pinned, tested `dill` version. */
|
|
36
|
+
declare const DILL_VERSION = "0.4.1";
|
|
37
|
+
interface KernelEnv {
|
|
38
|
+
/** Absolute path to the interpreter to spawn (`-m ipykernel_launcher`). */
|
|
39
|
+
python: string;
|
|
40
|
+
/** True when this runtime provisioned a venv (vs an explicit interpreter). */
|
|
41
|
+
managed: boolean;
|
|
42
|
+
/** The managed venv root, when {@link managed}. */
|
|
43
|
+
venvDir: string | undefined;
|
|
44
|
+
/** True when `dill` is importable — snapshot capability is available. */
|
|
45
|
+
dill: boolean;
|
|
46
|
+
/** True when `ipykernel` is importable (a hard requirement). */
|
|
47
|
+
ipykernel: boolean;
|
|
48
|
+
/** The interpreter's reported version, e.g. `3.11.15`. */
|
|
49
|
+
version: string;
|
|
50
|
+
}
|
|
51
|
+
interface ResolveKernelEnvOptions {
|
|
52
|
+
/** `config.python`; the bare sentinel (or absent) selects a managed venv. */
|
|
53
|
+
python?: string;
|
|
54
|
+
/** Managed venv directory; defaults to `<packageRoot>/.venv-kernel`. */
|
|
55
|
+
venvDir?: string;
|
|
56
|
+
/** Preferred CPython version for the managed venv. */
|
|
57
|
+
pythonVersion?: string;
|
|
58
|
+
/** Provision the managed venv when missing/incomplete (default true). */
|
|
59
|
+
autoInstall?: boolean;
|
|
60
|
+
/** Logger callback (info on provisioning, warn on degraded snapshot). */
|
|
61
|
+
log?: (level: 'info' | 'warn', message: string) => void;
|
|
62
|
+
}
|
|
63
|
+
/** Tool-cache env for uv: caches live NEXT TO the venv (plugin territory), so a read-only home can never block provisioning. */
|
|
64
|
+
declare function uvToolEnv(venvDir: string): NodeJS.ProcessEnv;
|
|
65
|
+
/** uv venv arguments (pure; unit-tested). */
|
|
66
|
+
declare function uvVenvArgs(venvDir: string, pythonVersion: string): string[];
|
|
67
|
+
/** python3 -m venv fallback arguments (pure; cache-free by construction). */
|
|
68
|
+
declare function venvFallbackArgs(venvDir: string): string[];
|
|
69
|
+
/** uv pip install arguments with pinned versions (pure; unit-tested). */
|
|
70
|
+
declare function uvInstallArgs(python: string): string[];
|
|
71
|
+
/** pip install arguments with pinned versions for the venv interpreter (pure). */
|
|
72
|
+
declare function pipInstallArgs(): string[];
|
|
73
|
+
/**
|
|
74
|
+
* Resolve the kernel interpreter, provisioning a managed venv when no
|
|
75
|
+
* explicit interpreter is configured. Throws when the resolved interpreter
|
|
76
|
+
* cannot run `ipykernel`; a missing `dill` only disables snapshots (warned).
|
|
77
|
+
*/
|
|
78
|
+
declare function resolveKernelEnv(options?: ResolveKernelEnvOptions): Promise<KernelEnv>;
|
|
79
|
+
//#endregion
|
|
80
|
+
export { AUTO_PYTHON_SENTINEL, DEFAULT_KERNEL_PYTHON_VERSION, DILL_VERSION, IPYKERNEL_VERSION, KernelEnv, PACKAGE_ROOT, ResolveKernelEnvOptions, pipInstallArgs, resolveKernelEnv, uvInstallArgs, uvToolEnv, uvVenvArgs, venvFallbackArgs };
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { a as PACKAGE_ROOT, c as uvInstallArgs, d as venvFallbackArgs, i as IPYKERNEL_VERSION, l as uvToolEnv, n as DEFAULT_KERNEL_PYTHON_VERSION, o as pipInstallArgs, r as DILL_VERSION, s as resolveKernelEnv, t as AUTO_PYTHON_SENTINEL, u as uvVenvArgs } from "./kernel-env-hxaihi9C.js";
|
|
2
|
+
|
|
3
|
+
export { AUTO_PYTHON_SENTINEL, DEFAULT_KERNEL_PYTHON_VERSION, DILL_VERSION, IPYKERNEL_VERSION, PACKAGE_ROOT, pipInstallArgs, resolveKernelEnv, uvInstallArgs, uvToolEnv, uvVenvArgs, venvFallbackArgs };
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
//#region src/py-sdk.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* DASHR kernel SDK codegen — Python flavor, cell edition.
|
|
4
|
+
*
|
|
5
|
+
* The pure projection from one calling scope's visible tool schemas to the
|
|
6
|
+
* Python SDK text the model programs against inside `eval` cells. The
|
|
7
|
+
* type-rendering machinery is ported from `@deepseek-ai/dsh-tools`
|
|
8
|
+
* `py-types.ts` (0.1.0-rc.6) per blueprint §7.4, deliberately slimmed to
|
|
9
|
+
* DASHR's single-language, stateful surface:
|
|
10
|
+
*
|
|
11
|
+
* - The usage instructions are OURS, not upstream's: upstream promises a
|
|
12
|
+
* one-shot program ("runs as the body of an async function", value-less
|
|
13
|
+
* between calls), while a DASHR cell runs on a PERSISTENT kernel whose
|
|
14
|
+
* variables, imports, and definitions survive across `eval` calls.
|
|
15
|
+
* The prose here must never state the throwaway contract.
|
|
16
|
+
* - No language table and no context-free renderer: DASHR renders Python
|
|
17
|
+
* only, and object shapes always render through the named-`TypedDict`
|
|
18
|
+
* path this module owns. (Upstream's exported `jsonSchemaToPy` degrades
|
|
19
|
+
* every object to `dict[str, Any]`; reusing it would lose the shape.)
|
|
20
|
+
* - The bare-identifier rule, `camelCase` derivation, class-name capping
|
|
21
|
+
* and collision suffixing, `typing` import emission, and the
|
|
22
|
+
* deterministic lexicographic member order are ported near-verbatim: the
|
|
23
|
+
* parseability invariants (NFKC stability, reserved words, unprintable
|
|
24
|
+
* escapes, bracket-nesting cap) exist because the emitted block is the
|
|
25
|
+
* model's ONLY declaration of the tools, and a syntax error in it poisons
|
|
26
|
+
* the whole mode.
|
|
27
|
+
* - renders one `tool.<name>(args) -> Output` member per tool — no `Tools`
|
|
28
|
+
* protocol and no `tools` singleton — matching the kernel's `tool`
|
|
29
|
+
* object holder. Which names may render as members is decided by
|
|
30
|
+
* {@link isFlatBindableName}, the one policy the renderer and the bridge
|
|
31
|
+
* share.
|
|
32
|
+
* @module dashr-repl/py-sdk
|
|
33
|
+
*/
|
|
34
|
+
/**
|
|
35
|
+
* One tool as the SDK renderer sees it: the model-facing schema
|
|
36
|
+
* (name/description/parameters) plus the tool's canonical output schema.
|
|
37
|
+
* The caller (the presentation plugin) excludes `eval` itself and reads
|
|
38
|
+
* both through the tool registry's public projection APIs.
|
|
39
|
+
*/
|
|
40
|
+
interface DASHRSdkSchema {
|
|
41
|
+
/** Tool name as registered (may be exotic; the renderer routes non-bindable names to not-callable comments). */
|
|
42
|
+
readonly name: string;
|
|
43
|
+
/** Tool description, rendered as the method docstring. */
|
|
44
|
+
readonly description: string;
|
|
45
|
+
/** Validated JSON-Schema node for the arguments object. */
|
|
46
|
+
readonly parameters: unknown;
|
|
47
|
+
/** Validated JSON-Schema node for the canonical output value. */
|
|
48
|
+
readonly output: unknown;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Whether a tool name can be emitted AND bound as a `tool` member — the ONE
|
|
52
|
+
* policy shared by this renderer and the bridge's binding
|
|
53
|
+
* loop (src/index.ts), so the catalog never promises a name the kernel does
|
|
54
|
+
* not bind. Strictly narrower than the runtime's validation: the
|
|
55
|
+
* language-portable identifier subset (`[A-Za-z_][A-Za-z0-9_]*`, ASCII — a
|
|
56
|
+
* non-ASCII XID name is legal CPython but not portable, so the runtime
|
|
57
|
+
* refuses it as a binding global and the catalog must not teach it), minus
|
|
58
|
+
* every portable reserved word (ECMAScript ∪ Python — `type` and `match`
|
|
59
|
+
* are legal Python but reserved on the seam), minus the seam's reserved
|
|
60
|
+
* binding globals (`console`, dunders), minus underscore-leading names
|
|
61
|
+
* (kernel-shim prefix plus the call-site hazards; not callable as taught
|
|
62
|
+
* flat globals). The runtime's `validateBindings` remains the authoritative
|
|
63
|
+
* backstop: everything this accepts, it accepts.
|
|
64
|
+
*/
|
|
65
|
+
declare function isFlatBindableName(name: string): boolean;
|
|
66
|
+
/**
|
|
67
|
+
* Render the `dashr:tool-catalog` prompt section body from the registry
|
|
68
|
+
* schemas: the cell-flavored usage instructions above, the
|
|
69
|
+
* `ToolCallError` declaration, one named `TypedDict` per tool argument or
|
|
70
|
+
* output object (and per nested object), and one
|
|
71
|
+
* `tool.<name>(args: XArgs) -> XOutput` member per visible tool — no `Tools`
|
|
72
|
+
* protocol, no `tools` singleton, every tool is a member of the `tool`
|
|
73
|
+
* object exactly as the kernel binds it — inside one fenced
|
|
74
|
+
* ```python block. The `typing` import line lists exactly the symbols the
|
|
75
|
+
* render used (and is omitted entirely when none are).
|
|
76
|
+
*
|
|
77
|
+
* Deterministic — tools are emitted in lexicographic name order and class
|
|
78
|
+
* declarations precede the function that references them in that same
|
|
79
|
+
* order (nested classes before the parent that references them), so an
|
|
80
|
+
* unchanged tool set produces byte-identical text across assemblies.
|
|
81
|
+
*
|
|
82
|
+
* Non-bindable names (reserved, exotic, or underscore-leading) render as
|
|
83
|
+
* comment lines: they are registered upstream but NOT callable from cells,
|
|
84
|
+
* and the comment keeps the signature and description visible instead of
|
|
85
|
+
* silently dropping the tool.
|
|
86
|
+
* @param schemas - the calling scope's visible tools (caller excludes
|
|
87
|
+
* `eval` and the masked delegation names).
|
|
88
|
+
* @returns the complete section body.
|
|
89
|
+
*/
|
|
90
|
+
declare function renderToolsSdkPy(schemas: readonly DASHRSdkSchema[]): string;
|
|
91
|
+
/**
|
|
92
|
+
* The `dashr:tool-catalog` section's presentation mode (design D4):
|
|
93
|
+
* `'signatures'` renders one compact declaration line per visible tool
|
|
94
|
+
* (the omp code-mode shape: `name(args: {…})` per line, argument and output
|
|
95
|
+
* sketches abbreviated to depth 2 — the default, chosen for low-tier model
|
|
96
|
+
* robustness); `'convention'` renders the one-sentence calling convention
|
|
97
|
+
* alone (zero repetition, the A/B deployment experiment's other arm).
|
|
98
|
+
* Both modes keep the output contract (each tool's canonical JSON output
|
|
99
|
+
* shape) and the non-flat-name exception; neither presents a REPL binding
|
|
100
|
+
* listing — the declaration lines themselves are the authoritative surface.
|
|
101
|
+
*/
|
|
102
|
+
type ReplBridgeCatalogMode = 'signatures' | 'convention';
|
|
103
|
+
/** The deployed presentation mode; flip to `'convention'` to ship arm A. */
|
|
104
|
+
declare const REPL_BRIDGE_CATALOG_MODE: ReplBridgeCatalogMode;
|
|
105
|
+
/**
|
|
106
|
+
* Render the `dashr:tool-catalog` prompt section body as the REPL bridge
|
|
107
|
+
* instructions (design D4/D5): the scripting-pad positioning and the
|
|
108
|
+
* calling convention above, then — in the default `'signatures'` mode —
|
|
109
|
+
* one compact declaration line per visible tool
|
|
110
|
+
* (`tool.<name>(args: {…}) -> <output shape>`, omp code-mode shape with
|
|
111
|
+
* the output contract kept), inside one fenced ```python block.
|
|
112
|
+
* Non-bindable names (reserved, exotic, underscore-leading) are omitted
|
|
113
|
+
* from the lines; the convention sentence above states that limit once.
|
|
114
|
+
*
|
|
115
|
+
* Deterministic — lines are emitted in lexicographic name order, so an
|
|
116
|
+
* unchanged tool set produces byte-identical text across assemblies.
|
|
117
|
+
* @param schemas - the calling scope's visible tools (the caller already
|
|
118
|
+
* excluded the transport and the wire-masked names).
|
|
119
|
+
* @param mode - override the deployed {@link REPL_BRIDGE_CATALOG_MODE}
|
|
120
|
+
* (the two render states; tests exercise both).
|
|
121
|
+
* @returns the complete section body.
|
|
122
|
+
*/
|
|
123
|
+
declare function renderReplBridgeInstructions(schemas: readonly DASHRSdkSchema[], mode?: ReplBridgeCatalogMode): string;
|
|
124
|
+
//#endregion
|
|
125
|
+
export { renderReplBridgeInstructions as a, isFlatBindableName as i, REPL_BRIDGE_CATALOG_MODE as n, renderToolsSdkPy as o, ReplBridgeCatalogMode as r, DASHRSdkSchema as t };
|