@code-yeongyu/senpi-codemode 2026.10.21-3 → 2026.10.24-1

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/CHANGELOG.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Changelog
2
2
 
3
- ## [Unreleased]
3
+ ## [2026.10.24-1] - 2026-10-24
4
4
 
5
5
  ### Breaking Changes
6
6
 
@@ -12,6 +12,20 @@
12
12
 
13
13
  ### Removed
14
14
 
15
+ ## [2026.10.23-1] - 2026-10-23
16
+
17
+ ### Breaking Changes
18
+
19
+ ### Added
20
+
21
+ ### Changed
22
+
23
+ ### Fixed
24
+
25
+ ### Removed
26
+
27
+ - Removed the built-in llama.cpp provider's image-format exception along with the `/llama` integration ([#3202](https://github.com/code-yeongyu/senpi/issues/3202)).
28
+
15
29
  ## [2026.10.21-3] - 2026-10-22
16
30
 
17
31
  ### Breaking Changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@code-yeongyu/senpi-codemode",
3
- "version": "2026.10.21-3",
3
+ "version": "2026.10.24-1",
4
4
  "description": "Source-only senpi extension package for codemode evaluation tools",
5
5
  "type": "module",
6
6
  "main": "./src/index.ts",
@@ -33,15 +33,15 @@
33
33
  },
34
34
  "dependencies": {
35
35
  "@babel/parser": "8.0.4",
36
- "@earendil-works/pi-ai": "npm:@code-yeongyu/senpi-ai@2026.10.21-3",
36
+ "@earendil-works/pi-ai": "npm:@code-yeongyu/senpi-ai@2026.10.24-1",
37
37
  "quickjs-wasi": "3.6.2",
38
38
  "typebox": "1.3.34"
39
39
  },
40
40
  "peerDependencies": {
41
- "@code-yeongyu/senpi": "2026.10.21-3"
41
+ "@code-yeongyu/senpi": "2026.10.24-1"
42
42
  },
43
43
  "devDependencies": {
44
- "@code-yeongyu/senpi": "2026.10.21-3"
44
+ "@code-yeongyu/senpi": "2026.10.24-1"
45
45
  },
46
46
  "keywords": [
47
47
  "senpi",
@@ -65,7 +65,7 @@ function describeProperty(value: unknown): string {
65
65
  if (!isSchemaLike(value)) return "unknown";
66
66
  const parts = [typeLabel(value)];
67
67
  const description = firstLine(value.description);
68
- if (description !== undefined) parts.push(`— ${truncate(description, DESCRIPTION_MAX_CHARS)}`);
68
+ if (description !== undefined) parts.push(`(${truncate(description, DESCRIPTION_MAX_CHARS)})`);
69
69
  return parts.join(" ");
70
70
  }
71
71
 
@@ -150,7 +150,7 @@ function frame(mimeType, dataBase64) {
150
150
  }
151
151
 
152
152
  function dropped(reason) {
153
- return [{ kind: "text", text: `[display: image dropped — ${reason}]` }];
153
+ return [{ kind: "text", text: `[display: image dropped - ${reason}]` }];
154
154
  }
155
155
 
156
156
  export function resolveDisplayOps(value) {
@@ -11,6 +11,7 @@ let shadowedNames = null;
11
11
 
12
12
  export function indirectEval(source, filename) {
13
13
  const withPragma = filename ? `${source}\n//# sourceURL=${filename}` : source;
14
+ // oxlint-disable-next-line eslint/no-eval -- The persistent kernel evaluates user cells in global scope to retain their bindings.
14
15
  const geval = globalThis.eval;
15
16
  return geval(withPragma);
16
17
  }
@@ -744,6 +745,7 @@ function captureLastExpression(code) {
744
745
  return `${head}return ${tail.replace(/;+$/u, "")};`;
745
746
  }
746
747
 
748
+ // oxlint-disable-next-line eslint/no-misleading-character-class -- ECMAScript identifiers permit ZWNJ and ZWJ as individual continuation characters.
747
749
  const LABEL_PREFIX_RE = /^[\p{ID_Start}$_][\p{ID_Continue}\u200c\u200d$]*\s*:/u;
748
750
 
749
751
  function isStatementOnly(source) {
@@ -99,6 +99,7 @@ function captureShellPromise(promise, options) {
99
99
  return prototype[method].apply(this, args);
100
100
  };
101
101
  }
102
+ // oxlint-disable-next-line unicorn/no-thenable -- This wraps an existing shell promise to record when the cell awaits it.
102
103
  promise.then = function then(onFulfilled, onRejected) {
103
104
  if (!waiting && !settled) {
104
105
  waiting = true;
@@ -101,6 +101,7 @@ function createKernelWebView(NativeWebView, requestPort) {
101
101
  const ref = new WeakRef(view);
102
102
  natives.add(ref);
103
103
  onCellRelease(() => ref.deref()?.close());
104
+ // oxlint-disable-next-line eslint/no-constructor-return -- Worker-safe calls must return the native view instead of the main-thread proxy.
104
105
  return view;
105
106
  }
106
107
  super();
@@ -162,7 +162,7 @@ def _display_image_dict(value: dict[str, Any]) -> bool:
162
162
  return False
163
163
  encoded = _image_base64(payload)
164
164
  if encoded is None:
165
- print(f"[display: image dropped \u2014 `data` must be base64, a data: URL, or bytes; got {type(payload).__name__}]")
165
+ print(f"[display: image dropped - `data` must be base64, a data: URL, or bytes; got {type(payload).__name__}]")
166
166
  return True
167
167
  emit({"type": "display", "mimeType": mime_type, "dataBase64": encoded[0]})
168
168
  return True
@@ -21,15 +21,15 @@ GPT eval: batch a step's independent tool calls in one cell with \`tool.<name>(a
21
21
  - Write real code around the calls - loops, branches, joins, a try/except per risky item - and keep every failed or missing item in the result verbatim; re-read truncated output before deciding.
22
22
  {{#if monitor}}- Long-running build, test run, deploy, or watch work starts with \`tool.monitor({ command, filter })\`, with the decisive-line filter inside the same cell; keep working until its event wakes the turn.{{/if}}{{/if}}
23
23
  {{#if hostLine}}
24
- Host: {{hostLine}} — cells execute here. Size \`parallel(thunks)\` pools to its cores; \`tool.<name>()\` shell commands must fit this platform, even when the code you are writing targets another machine.
24
+ Host: {{hostLine}}. Cells execute here. Size \`parallel(thunks)\` pools to its cores; \`tool.<name>()\` shell commands must fit this platform, even when the code you are writing targets another machine.
25
25
  {{/if}}
26
26
 
27
27
  \`language\`: {{#if py}}\`"py"\` IPython kernel{{/if}}{{#ifAll py js}}, {{/ifAll}}{{#if js}}\`"js"\` persistent JavaScript VM{{/if}}{{#if rb}}{{#ifAny py js}}, {{/ifAny}}\`"rb"\` persistent Ruby kernel{{/if}}{{#if jl}}{{#ifAny py js rb}}, {{/ifAny}}\`"jl"\` persistent Julia kernel{{/if}}.
28
28
 
29
- A cell that outlives the foreground window detaches and keeps running; further cells on the same language queue behind it in submission order on the same kernel (state is shared, execution is serial) while other languages run at once, up to {{maxDetachedCells}} background cells per session; each detached cell completes as one notification. Do not re-run a detached or queued cell; read, cancel or enumerate them with \`eval({ action: "peek" | "stop", cell_id })\` / \`eval({ action: "list" })\`; list shows live and recently settled cells across languages without consuming notifications. Its own execution time is capped at {{runBudgetSeconds}}s — queue time and time inside host tool calls are not charged; the hard limit stays wall-clock from submission; raise \`timeout\` only for a declared long run — and a killed js cell that cannot settle restarts its kernel with every global lost.
29
+ A cell that outlives the foreground window detaches and keeps running; further cells on the same language queue behind it in submission order on the same kernel (state is shared, execution is serial) while other languages run at once, up to {{maxDetachedCells}} background cells per session; each detached cell completes as one notification. Do not re-run a detached or queued cell; read, cancel or enumerate them with \`eval({ action: "peek" | "stop", cell_id })\` / \`eval({ action: "list" })\`; list shows live and recently settled cells across languages without consuming notifications. Its own execution time is capped at {{runBudgetSeconds}}s (queue time and time inside host tool calls are not charged; the hard limit stays wall-clock from submission; raise \`timeout\` only for a declared long run), and a killed js cell that cannot settle restarts its kernel with every global lost.
30
30
 
31
31
  {{#if py}}Python runs on a live event loop: use top-level \`await\`; \`asyncio.run(…)\` raises.{{/if}}
32
- {{#if js}}{{#if jsBun}}JS runs in-process on Bun {{jsVersion}}: top-level \`await\`/\`return\` work; \`Bun.*\` builtins available, including \`new Bun.WebView()\` — a headless browser (navigate/click/evaluate/screenshot) to reach for before \`curl\` or a browser CLI when a page needs JS, a login, or a screenshot. Shell out through \`Bun.$\` or \`Bun.spawn\`, never \`Bun.spawnSync\`: a synchronous child blocks the worker and cannot be interrupted.{{#if bunSkillPath}} Before a cell that installs a package, spawns a server or PTY, or starts a long run, read the bun-1-4 skill at {{bunSkillPath}} — its builtins replace the npm packages you would otherwise install.{{/if}}{{else}}JS runs under Node.js worker: top-level \`await\`/\`return\` work; \`fetch\`/\`Buffer\` available.{{/if}}{{/if}}
32
+ {{#if js}}{{#if jsBun}}JS runs in-process on Bun {{jsVersion}}: top-level \`await\`/\`return\` work; \`Bun.*\` builtins available, including \`new Bun.WebView()\`, a headless browser (navigate/click/evaluate/screenshot) to reach for before \`curl\` or a browser CLI when a page needs JS, a login, or a screenshot. Shell out through \`Bun.$\` or \`Bun.spawn\`, never \`Bun.spawnSync\`: a synchronous child blocks the worker and cannot be interrupted.{{#if bunSkillPath}} Before a cell that installs a package, spawns a server or PTY, or starts a long run, read the bun-1-4 skill at {{bunSkillPath}}; its builtins replace the npm packages you would otherwise install.{{/if}}{{else}}JS runs under Node.js worker: top-level \`await\`/\`return\` work; \`fetch\`/\`Buffer\` available.{{/if}}{{/if}}
33
33
  {{#if rb}}Ruby: synchronous; helper options are keyword args{{#if spawns}} (e.g. \`output("id", limit: 2)\`){{/if}}; the last expression auto-displays unless it is \`nil\`, an assignment, or a definition (like IRB).{{/if}}
34
34
  {{#if jl}}Julia: synchronous; helper options are standard keyword args{{#if spawns}} (e.g. \`output("id", limit=2)\`){{/if}}; the last expression auto-displays unless it is an assignment or a definition (like the Julia REPL).{{/if}}
35
35
  On error, fix and re-run only the failing step; a normal error keeps state, while a timeout or stop message says whether the kernel restarted.
@@ -44,11 +44,11 @@ export function parseEvalRequest(
44
44
  if (!isEvalLanguage(params.language))
45
45
  throw new TypeError(`eval run language must be one of: ${enabledLanguages.join(", ")}`);
46
46
  if (typeof params.code !== "string")
47
- throw new TypeError("eval run requires code — the cell body to execute, verbatim");
47
+ throw new TypeError("eval run requires code: the cell body to execute, verbatim");
48
48
  const summary = normalizeEvalSummary(params.summary);
49
49
  if (summary === undefined)
50
50
  throw new TypeError(
51
- "eval run requires summary — one line in the user's language: what you are working on and for what purpose",
51
+ "eval run requires summary (one line in the user's language): what you are working on and for what purpose",
52
52
  );
53
53
  if (params.on_timeout !== undefined && params.on_timeout !== "detach" && params.on_timeout !== "error")
54
54
  throw new TypeError(`Unknown eval on_timeout value "${String(params.on_timeout)}"`);
@@ -91,5 +91,5 @@ function isEvalLanguage(value: unknown): value is EvalToolInput["language"] {
91
91
  }
92
92
 
93
93
  function evalRunRequiresLanguageMessage(languages: readonly EvalLanguage[]): string {
94
- return `eval run requires language — one of ${languages.map((language) => `"${language}"`).join(", ")}`;
94
+ return `eval run requires language: one of ${languages.map((language) => `"${language}"`).join(", ")}`;
95
95
  }
@@ -23,7 +23,6 @@ export function webpExclusionForModel(model: WebpModel): true | undefined {
23
23
  if (model === undefined) return undefined;
24
24
  return model.provider === "ollama" ||
25
25
  model.provider === "ollama-cloud" ||
26
- model.provider === "llama.cpp" ||
27
26
  model.provider === "lm-studio" ||
28
27
  model.provider === "local-server" ||
29
28
  model.api === "ollama-chat"
package/src/tool/image.ts CHANGED
@@ -122,7 +122,7 @@ export class EvalOutputCollector {
122
122
  if (message.mimeType.startsWith("image/")) {
123
123
  const image = validateDisplayImage(message.dataBase64);
124
124
  if ("reason" in image) {
125
- this.#sink.push(`[display: image dropped \u2014 ${image.reason}]\n`);
125
+ this.#sink.push(`[display: image dropped - ${image.reason}]\n`);
126
126
  return;
127
127
  }
128
128
  if (