opencode-ipynb 0.1.0 → 0.1.2
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/README.md +14 -20
- package/dist/format/markdown.d.ts +0 -2
- package/dist/format/markdown.d.ts.map +1 -1
- package/dist/format/outputs.d.ts +0 -2
- package/dist/format/outputs.d.ts.map +1 -1
- package/dist/index.js +28 -45
- package/dist/utils/attachments.d.ts +1 -8
- package/dist/utils/attachments.d.ts.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -167,15 +167,19 @@ OpenCode may use a different Python interpreter than the one in your terminal. T
|
|
|
167
167
|
|
|
168
168
|
```json
|
|
169
169
|
{
|
|
170
|
-
"plugin": [
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
170
|
+
"plugin": [
|
|
171
|
+
[
|
|
172
|
+
"opencode-ipynb",
|
|
173
|
+
{
|
|
174
|
+
"pythonPath": "C:/Users/Gabriel/miniconda3/envs/data/python.exe",
|
|
175
|
+
"preferUv": true,
|
|
176
|
+
"defaultTimeoutMs": 120000,
|
|
177
|
+
"defaultMaxOutputChars": 6000,
|
|
178
|
+
"warmKernel": false,
|
|
179
|
+
"allowOutsideWorktree": false
|
|
180
|
+
}
|
|
181
|
+
]
|
|
182
|
+
]
|
|
179
183
|
}
|
|
180
184
|
```
|
|
181
185
|
|
|
@@ -230,7 +234,7 @@ expected output.
|
|
|
230
234
|
|
|
231
235
|
## Release
|
|
232
236
|
|
|
233
|
-
The published npm tarball contains only the runtime: `dist/`, `python/ipynb_runner.py`, `python/requirements.txt`, `README.md`, and `LICENSE`. Internal developer docs
|
|
237
|
+
The published npm tarball contains only the runtime: `dist/`, `python/ipynb_runner.py`, `python/requirements.txt`, `README.md`, and `LICENSE`. Internal developer docs, helper dev scripts, and `.github/` workflows are excluded from the npm package via `.npmignore` and are also gitignored so they are not versioned in this repository. Contributors track their work through GitHub Issues and Discussions.
|
|
234
238
|
|
|
235
239
|
Cut a release by tagging the commit and pushing the tag, then publish it on GitHub — the workflow runs only on the `published` release event:
|
|
236
240
|
|
|
@@ -321,16 +325,6 @@ test/
|
|
|
321
325
|
unit/ # bun:test suites
|
|
322
326
|
```
|
|
323
327
|
|
|
324
|
-
## Roadmap
|
|
325
|
-
|
|
326
|
-
See `TODO.md` for the full plan and review-fix history (v0.1 → v1.5). Highlights:
|
|
327
|
-
|
|
328
|
-
- v0.2: polished `ipynb_outputs` UI, full `ipynb_export` polish.
|
|
329
|
-
- v0.3: real `nbclient`-based execution, save outputs, timeout, traceback capture.
|
|
330
|
-
- v0.4: image attachments, reproducibility reports.
|
|
331
|
-
- v1.0: kernel lifecycle management, cross-platform tests, npm publish.
|
|
332
|
-
- v1.1–v1.5: security, Effect, path, packaging, rich-output, and cleanup review fixes.
|
|
333
|
-
|
|
334
328
|
## License
|
|
335
329
|
|
|
336
330
|
MIT. See `LICENSE`.
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import type { CellRaw } from "../domain/cell.js";
|
|
2
2
|
import { type OutputFormatOptions } from "./outputs.js";
|
|
3
3
|
import type { ToolAttachment } from "@opencode-ai/plugin";
|
|
4
|
-
import type { SavedAttachment } from "../utils/attachments.js";
|
|
5
4
|
export interface MarkdownReadOptions {
|
|
6
5
|
readonly includeOutputs: boolean;
|
|
7
6
|
readonly includeErrors: boolean;
|
|
@@ -14,7 +13,6 @@ export interface MarkdownReadOptions {
|
|
|
14
13
|
export interface FormattedCell {
|
|
15
14
|
readonly rendered: string;
|
|
16
15
|
readonly attachments: ReadonlyArray<ToolAttachment>;
|
|
17
|
-
readonly savedAttachments: ReadonlyArray<SavedAttachment>;
|
|
18
16
|
}
|
|
19
17
|
export declare const formatCellMarkdown: (cell: CellRaw, index: number, optsInput?: Partial<MarkdownReadOptions>) => string;
|
|
20
18
|
export declare const formatCellMarkdownDetailed: (cell: CellRaw, index: number, optsInput?: Partial<MarkdownReadOptions>) => Promise<FormattedCell>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"markdown.d.ts","sourceRoot":"","sources":["../../src/format/markdown.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAA4C,MAAM,mBAAmB,CAAA;AAC1F,OAAO,EAA8D,KAAK,mBAAmB,EAAE,MAAM,cAAc,CAAA;AACnH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAA;
|
|
1
|
+
{"version":3,"file":"markdown.d.ts","sourceRoot":"","sources":["../../src/format/markdown.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAA4C,MAAM,mBAAmB,CAAA;AAC1F,OAAO,EAA8D,KAAK,mBAAmB,EAAE,MAAM,cAAc,CAAA;AACnH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAA;AAEzD,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,cAAc,EAAE,OAAO,CAAA;IAChC,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAA;IAC/B,QAAQ,CAAC,eAAe,EAAE,OAAO,CAAA;IACjC,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAA;IAC/B,QAAQ,CAAC,oBAAoB,CAAC,EAAE,OAAO,GAAG,SAAS,CAAA;IACnD,QAAQ,CAAC,UAAU,CAAC,EAAE,OAAO,GAAG,SAAS,CAAA;IACzC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC,mBAAmB,CAAC,CAAA;CAC9C;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,WAAW,EAAE,aAAa,CAAC,cAAc,CAAC,CAAA;CACpD;AAkJD,eAAO,MAAM,kBAAkB,GAC7B,MAAM,OAAO,EACb,OAAO,MAAM,EACb,YAAW,OAAO,CAAC,mBAAmB,CAAM,KAC3C,MASF,CAAA;AAED,eAAO,MAAM,0BAA0B,GACrC,MAAM,OAAO,EACb,OAAO,MAAM,EACb,YAAW,OAAO,CAAC,mBAAmB,CAAM,KAC3C,OAAO,CAAC,aAAa,CAWvB,CAAA"}
|
package/dist/format/outputs.d.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { type SavedAttachment } from "../utils/attachments.js";
|
|
2
1
|
import type { CellRaw } from "../domain/cell.js";
|
|
3
2
|
import type { NotebookRaw } from "../domain/notebook.js";
|
|
4
3
|
import type { ToolAttachment } from "@opencode-ai/plugin";
|
|
@@ -12,7 +11,6 @@ export interface OutputFormatOptions {
|
|
|
12
11
|
export interface FormattedOutput {
|
|
13
12
|
readonly rendered: string;
|
|
14
13
|
readonly attachments: ReadonlyArray<ToolAttachment>;
|
|
15
|
-
readonly savedAttachments: ReadonlyArray<SavedAttachment>;
|
|
16
14
|
}
|
|
17
15
|
export declare const formatOutputs: (cell: CellRaw, optsInput?: Partial<OutputFormatOptions>) => string;
|
|
18
16
|
export declare const formatOutputsDetailed: (cell: CellRaw, optsInput?: Partial<OutputFormatOptions>) => Promise<FormattedOutput>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"outputs.d.ts","sourceRoot":"","sources":["../../src/format/outputs.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"outputs.d.ts","sourceRoot":"","sources":["../../src/format/outputs.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAA;AAChD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAA;AAGxD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAA;AAEzD,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAA;IAC/B,QAAQ,CAAC,UAAU,CAAC,EAAE,OAAO,GAAG,SAAS,CAAA;IACzC,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAA;IAC/B,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAA;IAClC,QAAQ,CAAC,oBAAoB,CAAC,EAAE,OAAO,GAAG,SAAS,CAAA;CACpD;AASD,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,WAAW,EAAE,aAAa,CAAC,cAAc,CAAC,CAAA;CACpD;AAwHD,eAAO,MAAM,aAAa,GACxB,MAAM,OAAO,EACb,YAAW,OAAO,CAAC,mBAAmB,CAAM,KAC3C,MA0DF,CAAA;AAED,eAAO,MAAM,qBAAqB,GAChC,MAAM,OAAO,EACb,YAAW,OAAO,CAAC,mBAAmB,CAAM,KAC3C,OAAO,CAAC,eAAe,CA8DzB,CAAA;AAED,eAAO,MAAM,yBAAyB,GAAI,UAAU,WAAW,EAAE,UAAU,MAAM,KAAG,MA8BnF,CAAA;AAED,eAAO,MAAM,mBAAmB,GAAI,QAAQ,MAAM,EAAE,KAAK,MAAM,KAAG,MAAsC,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -27834,11 +27834,6 @@ var CARRIAGE_RETURN_PATTERN = /\r/g;
|
|
|
27834
27834
|
var stripAnsi = (text) => text.replace(ANSI_PATTERN, "").replace(CARRIAGE_RETURN_PATTERN, "");
|
|
27835
27835
|
|
|
27836
27836
|
// src/utils/attachments.ts
|
|
27837
|
-
import * as fs2 from "fs";
|
|
27838
|
-
import * as os from "os";
|
|
27839
|
-
import * as path4 from "path";
|
|
27840
|
-
import { randomBytes } from "crypto";
|
|
27841
|
-
import { pathToFileURL } from "url";
|
|
27842
27837
|
var EXTENSION_BY_MIME = {
|
|
27843
27838
|
"image/png": "png",
|
|
27844
27839
|
"image/jpeg": "jpg",
|
|
@@ -27851,22 +27846,15 @@ var EXTENSION_BY_MIME = {
|
|
|
27851
27846
|
var pickExtensionForMime = (mime) => {
|
|
27852
27847
|
return EXTENSION_BY_MIME[mime.toLowerCase()];
|
|
27853
27848
|
};
|
|
27854
|
-
var
|
|
27855
|
-
const ext = pickExtensionForMime(mime)
|
|
27856
|
-
|
|
27857
|
-
|
|
27858
|
-
|
|
27859
|
-
|
|
27860
|
-
|
|
27861
|
-
|
|
27862
|
-
return { path: filePath, mime, bytes: buffer.length, filename };
|
|
27849
|
+
var formatAttachment = (mime, base643, filename) => {
|
|
27850
|
+
const ext = pickExtensionForMime(mime);
|
|
27851
|
+
return {
|
|
27852
|
+
type: "file",
|
|
27853
|
+
mime,
|
|
27854
|
+
url: `data:${mime};base64,${base643}`,
|
|
27855
|
+
filename: filename ?? `image${ext ? `.${ext}` : ""}`
|
|
27856
|
+
};
|
|
27863
27857
|
};
|
|
27864
|
-
var formatAttachment = (a) => ({
|
|
27865
|
-
type: "file",
|
|
27866
|
-
mime: a.mime,
|
|
27867
|
-
url: pathToFileURL(a.path).toString(),
|
|
27868
|
-
filename: a.filename
|
|
27869
|
-
});
|
|
27870
27858
|
|
|
27871
27859
|
// src/domain/output.ts
|
|
27872
27860
|
var StreamOutputSchema = exports_external.object({
|
|
@@ -27967,11 +27955,9 @@ var formatDisplayWithAttachments = async (data, opts, optsInput, collector) => {
|
|
|
27967
27955
|
if (isImageMime(mime)) {
|
|
27968
27956
|
if (typeof value === "string") {
|
|
27969
27957
|
if (shouldSaveImage(optsInput)) {
|
|
27970
|
-
const
|
|
27971
|
-
const att = formatAttachment(saved);
|
|
27958
|
+
const att = formatAttachment(mime, value);
|
|
27972
27959
|
collector.attachments.push(att);
|
|
27973
|
-
|
|
27974
|
-
lines.push(`- ${mime}: (saved ${humanBytes(saved.bytes)} to ${att.url})`);
|
|
27960
|
+
lines.push(`- ${mime}: (attached as image, ${humanBytes(Buffer.byteLength(value, "base64"))})`);
|
|
27975
27961
|
} else {
|
|
27976
27962
|
lines.push(`- ${imageNotice(mime, value)}`);
|
|
27977
27963
|
}
|
|
@@ -28081,7 +28067,7 @@ ${e}`);
|
|
|
28081
28067
|
var formatOutputsDetailed = async (cell, optsInput = {}) => {
|
|
28082
28068
|
const opts = defaultOpts(optsInput);
|
|
28083
28069
|
if (cell.cell_type !== "code") {
|
|
28084
|
-
return { rendered: "", attachments: []
|
|
28070
|
+
return { rendered: "", attachments: [] };
|
|
28085
28071
|
}
|
|
28086
28072
|
const sections = [];
|
|
28087
28073
|
let stdout = "";
|
|
@@ -28089,7 +28075,7 @@ var formatOutputsDetailed = async (cell, optsInput = {}) => {
|
|
|
28089
28075
|
const displaySections = [];
|
|
28090
28076
|
const resultSections = [];
|
|
28091
28077
|
const errorSections = [];
|
|
28092
|
-
const collector = { attachments: []
|
|
28078
|
+
const collector = { attachments: [] };
|
|
28093
28079
|
for (const out of cell.outputs) {
|
|
28094
28080
|
const kind = detectOutputKind(out);
|
|
28095
28081
|
if (kind === "stream") {
|
|
@@ -28134,14 +28120,13 @@ ${r}`);
|
|
|
28134
28120
|
${e}`);
|
|
28135
28121
|
}
|
|
28136
28122
|
if (sections.length === 0) {
|
|
28137
|
-
return { rendered: "(no output)", attachments: collector.attachments
|
|
28123
|
+
return { rendered: "(no output)", attachments: collector.attachments };
|
|
28138
28124
|
}
|
|
28139
28125
|
return {
|
|
28140
28126
|
rendered: sections.join(`
|
|
28141
28127
|
|
|
28142
28128
|
`),
|
|
28143
|
-
attachments: collector.attachments
|
|
28144
|
-
savedAttachments: collector.saved
|
|
28129
|
+
attachments: collector.attachments
|
|
28145
28130
|
};
|
|
28146
28131
|
};
|
|
28147
28132
|
var formatNotebookDiagnostics = (notebook, filePath) => {
|
|
@@ -28602,7 +28587,6 @@ ${JSON.stringify(cell.metadata, null, 2)}
|
|
|
28602
28587
|
lines.push(formatted.rendered);
|
|
28603
28588
|
}
|
|
28604
28589
|
collector.attachments.push(...formatted.attachments);
|
|
28605
|
-
collector.saved.push(...formatted.savedAttachments);
|
|
28606
28590
|
} else if (opts.includeErrors) {
|
|
28607
28591
|
const errOutputs = cell.outputs.filter((o) => o["output_type"] === "error");
|
|
28608
28592
|
if (errOutputs.length > 0) {
|
|
@@ -28612,7 +28596,6 @@ ${JSON.stringify(cell.metadata, null, 2)}
|
|
|
28612
28596
|
lines.push("");
|
|
28613
28597
|
lines.push(formatted.rendered);
|
|
28614
28598
|
collector.attachments.push(...formatted.attachments);
|
|
28615
|
-
collector.saved.push(...formatted.savedAttachments);
|
|
28616
28599
|
}
|
|
28617
28600
|
}
|
|
28618
28601
|
return lines.join(`
|
|
@@ -28654,15 +28637,15 @@ ${JSON.stringify(cell.metadata, null, 2)}
|
|
|
28654
28637
|
};
|
|
28655
28638
|
var formatCellMarkdownDetailed = async (cell, index, optsInput = {}) => {
|
|
28656
28639
|
const opts = defaultReadOpts(optsInput);
|
|
28657
|
-
const collector = { attachments: []
|
|
28640
|
+
const collector = { attachments: [] };
|
|
28658
28641
|
if (cell.cell_type === "code") {
|
|
28659
28642
|
const rendered = await formatCodeCellDetailed(cell, index, opts, collector);
|
|
28660
|
-
return { rendered, attachments: collector.attachments
|
|
28643
|
+
return { rendered, attachments: collector.attachments };
|
|
28661
28644
|
}
|
|
28662
28645
|
if (cell.cell_type === "markdown") {
|
|
28663
|
-
return { rendered: formatMarkdownCell(cell, index, opts), attachments: []
|
|
28646
|
+
return { rendered: formatMarkdownCell(cell, index, opts), attachments: [] };
|
|
28664
28647
|
}
|
|
28665
|
-
return { rendered: formatRawCell(cell, index, opts), attachments: []
|
|
28648
|
+
return { rendered: formatRawCell(cell, index, opts), attachments: [] };
|
|
28666
28649
|
};
|
|
28667
28650
|
|
|
28668
28651
|
// src/services/NotebookReadService.ts
|
|
@@ -29419,7 +29402,7 @@ var makeOutputImpl = (pathSvc, fileSvc, permSvc) => {
|
|
|
29419
29402
|
|
|
29420
29403
|
// src/services/NotebookExportService.ts
|
|
29421
29404
|
import * as fsp2 from "fs/promises";
|
|
29422
|
-
import * as
|
|
29405
|
+
import * as path4 from "path";
|
|
29423
29406
|
|
|
29424
29407
|
// src/format/diff.ts
|
|
29425
29408
|
var renderCell = (cell, cellIndex, options) => {
|
|
@@ -29646,7 +29629,7 @@ ${rendered}`;
|
|
|
29646
29629
|
});
|
|
29647
29630
|
yield* exports_Effect.tryPromise({
|
|
29648
29631
|
try: async () => {
|
|
29649
|
-
await fsp2.mkdir(
|
|
29632
|
+
await fsp2.mkdir(path4.dirname(outAbs), { recursive: true });
|
|
29650
29633
|
await fsp2.writeFile(outAbs, finalRendered, "utf8");
|
|
29651
29634
|
},
|
|
29652
29635
|
catch: (err) => new NotebookWriteError({
|
|
@@ -30086,8 +30069,8 @@ var makeExecutionImpl = (pathSvc, fileSvc, permSvc, pythonSvc, execOpts) => {
|
|
|
30086
30069
|
// src/services/PythonService.ts
|
|
30087
30070
|
import { spawn as spawn2 } from "child_process";
|
|
30088
30071
|
import { fileURLToPath } from "url";
|
|
30089
|
-
import * as
|
|
30090
|
-
import * as
|
|
30072
|
+
import * as fs2 from "fs";
|
|
30073
|
+
import * as path5 from "path";
|
|
30091
30074
|
import * as readline from "readline";
|
|
30092
30075
|
class PythonService extends exports_Context.Tag("@ipynb/PythonService")() {
|
|
30093
30076
|
}
|
|
@@ -30159,13 +30142,13 @@ var findHelperWarned = false;
|
|
|
30159
30142
|
var findHelper = (rel) => {
|
|
30160
30143
|
const candidates = [];
|
|
30161
30144
|
if (process.cwd())
|
|
30162
|
-
candidates.push(
|
|
30163
|
-
const distDir =
|
|
30164
|
-
candidates.push(
|
|
30165
|
-
candidates.push(
|
|
30166
|
-
candidates.push(
|
|
30145
|
+
candidates.push(path5.resolve(process.cwd(), rel));
|
|
30146
|
+
const distDir = path5.dirname(__filename2);
|
|
30147
|
+
candidates.push(path5.resolve(distDir, "..", "..", rel));
|
|
30148
|
+
candidates.push(path5.resolve(distDir, "..", "..", "..", rel));
|
|
30149
|
+
candidates.push(path5.resolve(distDir, "..", rel));
|
|
30167
30150
|
for (const c of candidates) {
|
|
30168
|
-
if (
|
|
30151
|
+
if (fs2.existsSync(c))
|
|
30169
30152
|
return c;
|
|
30170
30153
|
}
|
|
30171
30154
|
if (!findHelperWarned) {
|
|
@@ -1,11 +1,4 @@
|
|
|
1
1
|
import type { ToolAttachment } from "@opencode-ai/plugin";
|
|
2
|
-
export interface SavedAttachment {
|
|
3
|
-
readonly path: string;
|
|
4
|
-
readonly mime: string;
|
|
5
|
-
readonly bytes: number;
|
|
6
|
-
readonly filename: string;
|
|
7
|
-
}
|
|
8
2
|
export declare const pickExtensionForMime: (mime: string) => string | undefined;
|
|
9
|
-
export declare const
|
|
10
|
-
export declare const formatAttachment: (a: SavedAttachment) => ToolAttachment;
|
|
3
|
+
export declare const formatAttachment: (mime: string, base64: string, filename?: string) => ToolAttachment;
|
|
11
4
|
//# sourceMappingURL=attachments.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"attachments.d.ts","sourceRoot":"","sources":["../../src/utils/attachments.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"attachments.d.ts","sourceRoot":"","sources":["../../src/utils/attachments.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAA;AAYzD,eAAO,MAAM,oBAAoB,GAAI,MAAM,MAAM,KAAG,MAAM,GAAG,SAE5D,CAAA;AAED,eAAO,MAAM,gBAAgB,GAC3B,MAAM,MAAM,EACZ,QAAQ,MAAM,EACd,WAAW,MAAM,KAChB,cAQF,CAAA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opencode-ipynb",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "OpenCode community plugin that adds robust .ipynb (Jupyter Notebook) support: inspect, read, edit, run, outputs, clean, export, reproducibility reports, and warm kernels.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"packageManager": "bun@1.3.13",
|