@chances-ai/engine 28.0.0 → 29.0.0
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/dist/ai/adapters/ai-sdk-stream.js +15 -0
- package/dist/ai/adapters/ai-sdk-stream.js.map +1 -1
- package/dist/ai/types.d.ts +12 -0
- package/dist/ai/types.d.ts.map +1 -1
- package/dist/core/engine.d.ts +14 -0
- package/dist/core/engine.d.ts.map +1 -1
- package/dist/core/engine.js +48 -2
- package/dist/core/engine.js.map +1 -1
- package/dist/hashline/apply.d.ts +9 -0
- package/dist/hashline/apply.d.ts.map +1 -0
- package/dist/hashline/apply.js +523 -0
- package/dist/hashline/apply.js.map +1 -0
- package/dist/hashline/block.d.ts +25 -0
- package/dist/hashline/block.d.ts.map +1 -0
- package/dist/hashline/block.js +71 -0
- package/dist/hashline/block.js.map +1 -0
- package/dist/hashline/format.d.ts +106 -0
- package/dist/hashline/format.d.ts.map +1 -0
- package/dist/hashline/format.js +191 -0
- package/dist/hashline/format.js.map +1 -0
- package/dist/hashline/fs.d.ts +87 -0
- package/dist/hashline/fs.d.ts.map +1 -0
- package/dist/hashline/fs.js +123 -0
- package/dist/hashline/fs.js.map +1 -0
- package/dist/hashline/index.d.ts +27 -0
- package/dist/hashline/index.d.ts.map +1 -0
- package/dist/hashline/index.js +27 -0
- package/dist/hashline/index.js.map +1 -0
- package/dist/hashline/input.d.ts +101 -0
- package/dist/hashline/input.d.ts.map +1 -0
- package/dist/hashline/input.js +378 -0
- package/dist/hashline/input.js.map +1 -0
- package/dist/hashline/messages.d.ts +87 -0
- package/dist/hashline/messages.d.ts.map +1 -0
- package/dist/hashline/messages.js +94 -0
- package/dist/hashline/messages.js.map +1 -0
- package/dist/hashline/mismatch.d.ts +45 -0
- package/dist/hashline/mismatch.d.ts.map +1 -0
- package/dist/hashline/mismatch.js +118 -0
- package/dist/hashline/mismatch.js.map +1 -0
- package/dist/hashline/normalize.d.ts +22 -0
- package/dist/hashline/normalize.d.ts.map +1 -0
- package/dist/hashline/normalize.js +31 -0
- package/dist/hashline/normalize.js.map +1 -0
- package/dist/hashline/parser.d.ts +24 -0
- package/dist/hashline/parser.d.ts.map +1 -0
- package/dist/hashline/parser.js +295 -0
- package/dist/hashline/parser.js.map +1 -0
- package/dist/hashline/patcher.d.ts +111 -0
- package/dist/hashline/patcher.d.ts.map +1 -0
- package/dist/hashline/patcher.js +332 -0
- package/dist/hashline/patcher.js.map +1 -0
- package/dist/hashline/recovery.d.ts +41 -0
- package/dist/hashline/recovery.d.ts.map +1 -0
- package/dist/hashline/recovery.js +175 -0
- package/dist/hashline/recovery.js.map +1 -0
- package/dist/hashline/snapshots.d.ts +62 -0
- package/dist/hashline/snapshots.d.ts.map +1 -0
- package/dist/hashline/snapshots.js +127 -0
- package/dist/hashline/snapshots.js.map +1 -0
- package/dist/hashline/tokenizer.d.ts +66 -0
- package/dist/hashline/tokenizer.d.ts.map +1 -0
- package/dist/hashline/tokenizer.js +408 -0
- package/dist/hashline/tokenizer.js.map +1 -0
- package/dist/hashline/types.d.ts +117 -0
- package/dist/hashline/types.d.ts.map +1 -0
- package/dist/hashline/types.js +13 -0
- package/dist/hashline/types.js.map +1 -0
- package/dist/tools/builtins/_hashline-fs.d.ts +16 -0
- package/dist/tools/builtins/_hashline-fs.d.ts.map +1 -0
- package/dist/tools/builtins/_hashline-fs.js +62 -0
- package/dist/tools/builtins/_hashline-fs.js.map +1 -0
- package/dist/tools/builtins/_image.d.ts +26 -0
- package/dist/tools/builtins/_image.d.ts.map +1 -0
- package/dist/tools/builtins/_image.js +76 -0
- package/dist/tools/builtins/_image.js.map +1 -0
- package/dist/tools/builtins/_login-shell.d.ts +17 -0
- package/dist/tools/builtins/_login-shell.d.ts.map +1 -0
- package/dist/tools/builtins/_login-shell.js +66 -0
- package/dist/tools/builtins/_login-shell.js.map +1 -0
- package/dist/tools/builtins/_notebook.d.ts +15 -0
- package/dist/tools/builtins/_notebook.d.ts.map +1 -0
- package/dist/tools/builtins/_notebook.js +81 -0
- package/dist/tools/builtins/_notebook.js.map +1 -0
- package/dist/tools/builtins/_pdf.d.ts +19 -0
- package/dist/tools/builtins/_pdf.d.ts.map +1 -0
- package/dist/tools/builtins/_pdf.js +42 -0
- package/dist/tools/builtins/_pdf.js.map +1 -0
- package/dist/tools/builtins/_shared.d.ts +11 -0
- package/dist/tools/builtins/_shared.d.ts.map +1 -1
- package/dist/tools/builtins/_shared.js +40 -1
- package/dist/tools/builtins/_shared.js.map +1 -1
- package/dist/tools/builtins/ast-edit.d.ts +18 -0
- package/dist/tools/builtins/ast-edit.d.ts.map +1 -0
- package/dist/tools/builtins/ast-edit.js +109 -0
- package/dist/tools/builtins/ast-edit.js.map +1 -0
- package/dist/tools/builtins/ast-grep.d.ts +6 -0
- package/dist/tools/builtins/ast-grep.d.ts.map +1 -0
- package/dist/tools/builtins/ast-grep.js +67 -0
- package/dist/tools/builtins/ast-grep.js.map +1 -0
- package/dist/tools/builtins/bash.d.ts.map +1 -1
- package/dist/tools/builtins/bash.js +13 -2
- package/dist/tools/builtins/bash.js.map +1 -1
- package/dist/tools/builtins/edit.d.ts.map +1 -1
- package/dist/tools/builtins/edit.js +112 -31
- package/dist/tools/builtins/edit.js.map +1 -1
- package/dist/tools/builtins/read.d.ts.map +1 -1
- package/dist/tools/builtins/read.js +187 -11
- package/dist/tools/builtins/read.js.map +1 -1
- package/dist/tools/builtins.d.ts.map +1 -1
- package/dist/tools/builtins.js +4 -0
- package/dist/tools/builtins.js.map +1 -1
- package/dist/tools/file-lock.d.ts +8 -0
- package/dist/tools/file-lock.d.ts.map +1 -1
- package/dist/tools/file-lock.js +22 -0
- package/dist/tools/file-lock.js.map +1 -1
- package/dist/tools/index.d.ts +1 -1
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/types.d.ts +26 -0
- package/dist/tools/types.d.ts.map +1 -1
- package/dist/tools/types.js.map +1 -1
- package/package.json +8 -3
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure data types shared across the hashline parser, applier, and patcher.
|
|
3
|
+
* Nothing in this file references a filesystem, agent runtime, or schema
|
|
4
|
+
* library — keep it that way.
|
|
5
|
+
*
|
|
6
|
+
* Ported from oh-my-pi `packages/hashline/src/types.ts` (7.9 task 09). The
|
|
7
|
+
* line-anchored patch language + content-hash anchoring + delimiter-balance
|
|
8
|
+
* auto-repair design is oh-my-pi's; chances-cli changes are confined to the
|
|
9
|
+
* hash function (cross-runtime, see `format.ts`), the integrity check (exact
|
|
10
|
+
* snapshot-text equality, see `patcher.ts`), and the FS seam (`fs.ts`).
|
|
11
|
+
*/
|
|
12
|
+
/** A line-number anchor (1-indexed). */
|
|
13
|
+
export interface Anchor {
|
|
14
|
+
line: number;
|
|
15
|
+
}
|
|
16
|
+
/** Where an `insert` edit should land relative to existing content. */
|
|
17
|
+
export type Cursor = {
|
|
18
|
+
kind: "bof";
|
|
19
|
+
} | {
|
|
20
|
+
kind: "eof";
|
|
21
|
+
} | {
|
|
22
|
+
kind: "before_anchor";
|
|
23
|
+
anchor: Anchor;
|
|
24
|
+
} | {
|
|
25
|
+
kind: "after_anchor";
|
|
26
|
+
anchor: Anchor;
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* A single low-level edit produced by the parser and consumed by the applier.
|
|
30
|
+
* Multi-line replacements decompose to one `insert` per replacement line plus
|
|
31
|
+
* one `delete` per consumed line. Replacement payloads are tagged so the
|
|
32
|
+
* applier can distinguish literal insertion from new content for a deleted
|
|
33
|
+
* line.
|
|
34
|
+
*/
|
|
35
|
+
export type Edit = {
|
|
36
|
+
kind: "insert";
|
|
37
|
+
cursor: Cursor;
|
|
38
|
+
text: string;
|
|
39
|
+
lineNum: number;
|
|
40
|
+
index: number;
|
|
41
|
+
mode?: "replacement";
|
|
42
|
+
} | {
|
|
43
|
+
kind: "delete";
|
|
44
|
+
anchor: Anchor;
|
|
45
|
+
lineNum: number;
|
|
46
|
+
index: number;
|
|
47
|
+
oldAssertion?: string;
|
|
48
|
+
} | {
|
|
49
|
+
/**
|
|
50
|
+
* Deferred block edit (`replace block N:` / `delete block N`). The exact
|
|
51
|
+
* line span is unknown at parse time — it is computed by
|
|
52
|
+
* {@link resolveBlockEdits} once file text + path (→ language) are
|
|
53
|
+
* available, then expanded into concrete edits: a non-empty `payloads`
|
|
54
|
+
* (from `replace block`) becomes the same `replacement` inserts + deletes
|
|
55
|
+
* that `replace start..end:` produces; an empty `payloads` (from `delete
|
|
56
|
+
* block`) becomes a pure range deletion. `applyEdits` never sees this
|
|
57
|
+
* variant.
|
|
58
|
+
*/
|
|
59
|
+
kind: "block";
|
|
60
|
+
anchor: Anchor;
|
|
61
|
+
payloads: string[];
|
|
62
|
+
lineNum: number;
|
|
63
|
+
index: number;
|
|
64
|
+
};
|
|
65
|
+
/** Result of applying a parsed set of edits to a text body. */
|
|
66
|
+
export interface ApplyResult {
|
|
67
|
+
/** Post-edit text body. */
|
|
68
|
+
text: string;
|
|
69
|
+
/** First line number (1-indexed) that changed, or `undefined` for a no-op apply. */
|
|
70
|
+
firstChangedLine?: number;
|
|
71
|
+
/** Diagnostic warnings collected by the parser, patcher, or recovery. */
|
|
72
|
+
warnings?: string[];
|
|
73
|
+
}
|
|
74
|
+
/** A parsed `[A..B]` line range. */
|
|
75
|
+
export interface ParsedRange {
|
|
76
|
+
start: Anchor;
|
|
77
|
+
end: Anchor;
|
|
78
|
+
}
|
|
79
|
+
/** Optional hints for {@link splitPatchInput}. */
|
|
80
|
+
export interface SplitOptions {
|
|
81
|
+
/** Resolves absolute paths inside hashline headers to cwd-relative form. */
|
|
82
|
+
cwd?: string;
|
|
83
|
+
/**
|
|
84
|
+
* Fallback path used when the input lacks a `¶PATH` header but contains
|
|
85
|
+
* recognizable hashline operations. Lets streaming previews work before
|
|
86
|
+
* the model has written the header.
|
|
87
|
+
*/
|
|
88
|
+
path?: string;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Resolved 1-indexed inclusive line span of a `replace block N:` target.
|
|
92
|
+
*/
|
|
93
|
+
export interface BlockSpan {
|
|
94
|
+
/** First line of the block (1-indexed, inclusive). */
|
|
95
|
+
start: number;
|
|
96
|
+
/** Last line of the block (1-indexed, inclusive). */
|
|
97
|
+
end: number;
|
|
98
|
+
}
|
|
99
|
+
/** Request handed to a {@link BlockResolver} to resolve one `replace block N:` anchor. */
|
|
100
|
+
export interface BlockResolverRequest {
|
|
101
|
+
/** Target file path (used to infer language by extension). */
|
|
102
|
+
path: string;
|
|
103
|
+
/** Full text the block must be resolved against (the snapshot the tag names). */
|
|
104
|
+
text: string;
|
|
105
|
+
/** 1-indexed line the block must begin on. */
|
|
106
|
+
line: number;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Resolves a `replace block N:` anchor to the line span of the syntactic block
|
|
110
|
+
* that begins on line N. Returns `null` when no block can be resolved
|
|
111
|
+
* (unrecognized language, blank/out-of-range line, no node begins there, or the
|
|
112
|
+
* resolved subtree has a syntax error). Pure seam: the hashline core declares
|
|
113
|
+
* the contract; the host injects a tree-sitter-backed implementation (in
|
|
114
|
+
* chances-cli, `native.blockRangeAt` — task 02 wave-2).
|
|
115
|
+
*/
|
|
116
|
+
export type BlockResolver = (request: BlockResolverRequest) => BlockSpan | null;
|
|
117
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/hashline/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,wCAAwC;AACxC,MAAM,WAAW,MAAM;IACrB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,uEAAuE;AACvE,MAAM,MAAM,MAAM,GACd;IAAE,IAAI,EAAE,KAAK,CAAA;CAAE,GACf;IAAE,IAAI,EAAE,KAAK,CAAA;CAAE,GACf;IAAE,IAAI,EAAE,eAAe,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACzC;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAE7C;;;;;;GAMG;AACH,MAAM,MAAM,IAAI,GACZ;IACE,IAAI,EAAE,QAAQ,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,aAAa,CAAC;CACtB,GACD;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,YAAY,CAAC,EAAE,MAAM,CAAA;CAAE,GACzF;IACE;;;;;;;;;OASG;IACH,IAAI,EAAE,OAAO,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEN,+DAA+D;AAC/D,MAAM,WAAW,WAAW;IAC1B,2BAA2B;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,oFAAoF;IACpF,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,yEAAyE;IACzE,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;CACrB;AAED,oCAAoC;AACpC,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;CACb;AAED,kDAAkD;AAClD,MAAM,WAAW,YAAY;IAC3B,4EAA4E;IAC5E,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;;;;OAIG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB,sDAAsD;IACtD,KAAK,EAAE,MAAM,CAAC;IACd,qDAAqD;IACrD,GAAG,EAAE,MAAM,CAAC;CACb;AAED,0FAA0F;AAC1F,MAAM,WAAW,oBAAoB;IACnC,8DAA8D;IAC9D,IAAI,EAAE,MAAM,CAAC;IACb,iFAAiF;IACjF,IAAI,EAAE,MAAM,CAAC;IACb,8CAA8C;IAC9C,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,aAAa,GAAG,CAAC,OAAO,EAAE,oBAAoB,KAAK,SAAS,GAAG,IAAI,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure data types shared across the hashline parser, applier, and patcher.
|
|
3
|
+
* Nothing in this file references a filesystem, agent runtime, or schema
|
|
4
|
+
* library — keep it that way.
|
|
5
|
+
*
|
|
6
|
+
* Ported from oh-my-pi `packages/hashline/src/types.ts` (7.9 task 09). The
|
|
7
|
+
* line-anchored patch language + content-hash anchoring + delimiter-balance
|
|
8
|
+
* auto-repair design is oh-my-pi's; chances-cli changes are confined to the
|
|
9
|
+
* hash function (cross-runtime, see `format.ts`), the integrity check (exact
|
|
10
|
+
* snapshot-text equality, see `patcher.ts`), and the FS seam (`fs.ts`).
|
|
11
|
+
*/
|
|
12
|
+
export {};
|
|
13
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/hashline/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type BlockResolver, Filesystem, type WriteResult } from "../../hashline/index.js";
|
|
2
|
+
import type { ToolContext } from "../types.js";
|
|
3
|
+
/** Disk-backed hashline {@link Filesystem} bound to one tool-call's context. */
|
|
4
|
+
export declare class EngineToolFs extends Filesystem {
|
|
5
|
+
private readonly ctx;
|
|
6
|
+
constructor(ctx: ToolContext);
|
|
7
|
+
readText(path: string): Promise<string>;
|
|
8
|
+
preflightWrite(path: string): Promise<void>;
|
|
9
|
+
writeText(path: string, content: string): Promise<WriteResult>;
|
|
10
|
+
/** Lexical resolve — MUST equal the `read` tool's snapshot key (see
|
|
11
|
+
* `hashlineSnapshotKey`) so a tag minted by read resolves on edit. */
|
|
12
|
+
canonicalPath(path: string): string;
|
|
13
|
+
}
|
|
14
|
+
/** Native-backed block resolver for `replace block N:` / `delete block N`. */
|
|
15
|
+
export declare function makeBlockResolver(): BlockResolver;
|
|
16
|
+
//# sourceMappingURL=_hashline-fs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"_hashline-fs.d.ts","sourceRoot":"","sources":["../../../src/tools/builtins/_hashline-fs.ts"],"names":[],"mappings":"AAeA,OAAO,EAAE,KAAK,aAAa,EAAE,UAAU,EAAiB,KAAK,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAC1G,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAG/C,gFAAgF;AAChF,qBAAa,YAAa,SAAQ,UAAU;IAC9B,OAAO,CAAC,QAAQ,CAAC,GAAG;gBAAH,GAAG,EAAE,WAAW;IAI9B,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAMvC,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAM3C,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;IAQ7E;0EACsE;IAC7D,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;CAG7C;AAED,8EAA8E;AAC9E,wBAAgB,iBAAiB,IAAI,aAAa,CAUjD"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Engine-side bridges between the pure hashline core and the live workspace:
|
|
3
|
+
*
|
|
4
|
+
* - {@link EngineToolFs} — a hashline {@link Filesystem} whose writes route
|
|
5
|
+
* through `guardWrite` (realpath jail + protected-path floor) + atomic
|
|
6
|
+
* temp-then-rename + fs-scan cache invalidation, and whose `canonicalPath`
|
|
7
|
+
* matches the `read` tool's snapshot key so tags resolve.
|
|
8
|
+
* - {@link makeBlockResolver} — a {@link BlockResolver} backed by the native
|
|
9
|
+
* tree-sitter `blockRangeAt` (task 02 wave-2), capability-gated per call
|
|
10
|
+
* (R1-S6): a slim native build / parse failure resolves to `null`, which the
|
|
11
|
+
* patcher turns into a "use `replace N..M:`" error rather than crashing.
|
|
12
|
+
*/
|
|
13
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
14
|
+
import { dirname } from "node:path";
|
|
15
|
+
import { native } from "@chances-ai/native";
|
|
16
|
+
import { Filesystem, NotFoundError } from "../../hashline/index.js";
|
|
17
|
+
import { guardWrite, hashlineSnapshotKey, writeFileAtomic } from "./_shared.js";
|
|
18
|
+
/** Disk-backed hashline {@link Filesystem} bound to one tool-call's context. */
|
|
19
|
+
export class EngineToolFs extends Filesystem {
|
|
20
|
+
ctx;
|
|
21
|
+
constructor(ctx) {
|
|
22
|
+
super();
|
|
23
|
+
this.ctx = ctx;
|
|
24
|
+
}
|
|
25
|
+
async readText(path) {
|
|
26
|
+
const abs = hashlineSnapshotKey(this.ctx, path);
|
|
27
|
+
if (!existsSync(abs))
|
|
28
|
+
throw new NotFoundError(path);
|
|
29
|
+
return readFileSync(abs, "utf8");
|
|
30
|
+
}
|
|
31
|
+
async preflightWrite(path) {
|
|
32
|
+
// Fail-closed BEFORE any section commits: a jail escape / protected path
|
|
33
|
+
// throws here so a multi-section batch lands nothing (all-or-nothing).
|
|
34
|
+
guardWrite(this.ctx, path);
|
|
35
|
+
}
|
|
36
|
+
async writeText(path, content) {
|
|
37
|
+
const real = guardWrite(this.ctx, path);
|
|
38
|
+
writeFileAtomic(real, content);
|
|
39
|
+
// Keep grep/glob/ast within the same turn consistent ([10.4]).
|
|
40
|
+
native.invalidateFsScanCache(dirname(real));
|
|
41
|
+
return { text: content };
|
|
42
|
+
}
|
|
43
|
+
/** Lexical resolve — MUST equal the `read` tool's snapshot key (see
|
|
44
|
+
* `hashlineSnapshotKey`) so a tag minted by read resolves on edit. */
|
|
45
|
+
canonicalPath(path) {
|
|
46
|
+
return hashlineSnapshotKey(this.ctx, path);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
/** Native-backed block resolver for `replace block N:` / `delete block N`. */
|
|
50
|
+
export function makeBlockResolver() {
|
|
51
|
+
return ({ path, text, line }) => {
|
|
52
|
+
try {
|
|
53
|
+
const range = native.blockRangeAt({ code: text, path, line });
|
|
54
|
+
return range ? { start: range.startLine, end: range.endLine } : null;
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
// AST_UNAVAILABLE (slim native) or any parse failure → unresolved.
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=_hashline-fs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"_hashline-fs.js","sourceRoot":"","sources":["../../../src/tools/builtins/_hashline-fs.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAC5C,OAAO,EAAsB,UAAU,EAAE,aAAa,EAAoB,MAAM,yBAAyB,CAAC;AAE1G,OAAO,EAAE,UAAU,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAEhF,gFAAgF;AAChF,MAAM,OAAO,YAAa,SAAQ,UAAU;IACb;IAA7B,YAA6B,GAAgB;QAC3C,KAAK,EAAE,CAAC;QADmB,QAAG,GAAH,GAAG,CAAa;IAE7C,CAAC;IAEQ,KAAK,CAAC,QAAQ,CAAC,IAAY;QAClC,MAAM,GAAG,GAAG,mBAAmB,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QAChD,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;YAAE,MAAM,IAAI,aAAa,CAAC,IAAI,CAAC,CAAC;QACpD,OAAO,YAAY,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;IACnC,CAAC;IAEQ,KAAK,CAAC,cAAc,CAAC,IAAY;QACxC,yEAAyE;QACzE,uEAAuE;QACvE,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;IAC7B,CAAC;IAEQ,KAAK,CAAC,SAAS,CAAC,IAAY,EAAE,OAAe;QACpD,MAAM,IAAI,GAAG,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QACxC,eAAe,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QAC/B,+DAA+D;QAC/D,MAAM,CAAC,qBAAqB,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;QAC5C,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;IAC3B,CAAC;IAED;0EACsE;IAC7D,aAAa,CAAC,IAAY;QACjC,OAAO,mBAAmB,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;IAC7C,CAAC;CACF;AAED,8EAA8E;AAC9E,MAAM,UAAU,iBAAiB;IAC/B,OAAO,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE;QAC9B,IAAI,CAAC;YACH,MAAM,KAAK,GAAG,MAAM,CAAC,YAAY,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;YAC9D,OAAO,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,SAAS,EAAE,GAAG,EAAE,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;QACvE,CAAC;QAAC,MAAM,CAAC;YACP,mEAAmE;YACnE,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Image handling for the `read` tool (7.9 [5.5], "image done fully"). Detects
|
|
3
|
+
* image files by magic bytes, then resizes/re-encodes them to a vision token
|
|
4
|
+
* budget via `sharp` (a LAZY optional peer — absent ⇒ a clear install hint, the
|
|
5
|
+
* tool degrades, nothing else breaks). The Rust image path noted in decision
|
|
6
|
+
* 5.5 is a task-02 third-wave follow-up; sharp lands the feature now.
|
|
7
|
+
*/
|
|
8
|
+
import type { ToolImagePart } from "../types.js";
|
|
9
|
+
/** Magic-byte → MIME sniffer for the formats we support. Returns null for non-images. */
|
|
10
|
+
export declare function sniffImageMime(buf: Buffer): string | null;
|
|
11
|
+
export type ImageReadResult = {
|
|
12
|
+
ok: true;
|
|
13
|
+
output: string;
|
|
14
|
+
images: ToolImagePart[];
|
|
15
|
+
} | {
|
|
16
|
+
ok: false;
|
|
17
|
+
output: string;
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Read `buf` (already sniffed as `mime`) into a vision-ready {@link ToolImagePart}.
|
|
21
|
+
* Resizes the long edge to {@link MAX_EDGE} (never enlarges) so the encoded image
|
|
22
|
+
* fits a sane token budget; returns base64 bytes + MIME. Without the `sharp`
|
|
23
|
+
* peer, returns an actionable `ok:false` instead of shipping a multi-MB original.
|
|
24
|
+
*/
|
|
25
|
+
export declare function readImageAsParts(buf: Buffer, displayPath: string, mime: string): Promise<ImageReadResult>;
|
|
26
|
+
//# sourceMappingURL=_image.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"_image.d.ts","sourceRoot":"","sources":["../../../src/tools/builtins/_image.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAgBjD,yFAAyF;AACzF,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAYzD;AAmBD,MAAM,MAAM,eAAe,GACvB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,aAAa,EAAE,CAAA;CAAE,GACrD;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAElC;;;;;GAKG;AACH,wBAAsB,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CAgC/G"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/** Long-edge cap (px) — matches Anthropic's vision guidance; keeps the encoded
|
|
2
|
+
* image well under a sane per-image token budget. */
|
|
3
|
+
const MAX_EDGE = 1568;
|
|
4
|
+
/** Magic-byte → MIME sniffer for the formats we support. Returns null for non-images. */
|
|
5
|
+
export function sniffImageMime(buf) {
|
|
6
|
+
if (buf.length >= 8 && buf[0] === 0x89 && buf[1] === 0x50 && buf[2] === 0x4e && buf[3] === 0x47)
|
|
7
|
+
return "image/png";
|
|
8
|
+
if (buf.length >= 3 && buf[0] === 0xff && buf[1] === 0xd8 && buf[2] === 0xff)
|
|
9
|
+
return "image/jpeg";
|
|
10
|
+
if (buf.length >= 6 && buf[0] === 0x47 && buf[1] === 0x49 && buf[2] === 0x46 && buf[3] === 0x38)
|
|
11
|
+
return "image/gif";
|
|
12
|
+
if (buf.length >= 12 &&
|
|
13
|
+
buf[0] === 0x52 && buf[1] === 0x49 && buf[2] === 0x46 && buf[3] === 0x46 && // RIFF
|
|
14
|
+
buf[8] === 0x57 && buf[9] === 0x45 && buf[10] === 0x42 && buf[11] === 0x50 // WEBP
|
|
15
|
+
) {
|
|
16
|
+
return "image/webp";
|
|
17
|
+
}
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
/** Map a sharp output format to a MIME type. */
|
|
21
|
+
function formatToMime(format, fallback) {
|
|
22
|
+
switch (format) {
|
|
23
|
+
case "png":
|
|
24
|
+
return "image/png";
|
|
25
|
+
case "jpeg":
|
|
26
|
+
case "jpg":
|
|
27
|
+
return "image/jpeg";
|
|
28
|
+
case "gif":
|
|
29
|
+
return "image/gif";
|
|
30
|
+
case "webp":
|
|
31
|
+
return "image/webp";
|
|
32
|
+
default:
|
|
33
|
+
return fallback;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Read `buf` (already sniffed as `mime`) into a vision-ready {@link ToolImagePart}.
|
|
38
|
+
* Resizes the long edge to {@link MAX_EDGE} (never enlarges) so the encoded image
|
|
39
|
+
* fits a sane token budget; returns base64 bytes + MIME. Without the `sharp`
|
|
40
|
+
* peer, returns an actionable `ok:false` instead of shipping a multi-MB original.
|
|
41
|
+
*/
|
|
42
|
+
export async function readImageAsParts(buf, displayPath, mime) {
|
|
43
|
+
// Lazy optional peer: a non-literal specifier keeps it out of the type graph
|
|
44
|
+
// (sharp isn't a declared dependency), so a missing peer is a runtime null.
|
|
45
|
+
const specifier = "sharp";
|
|
46
|
+
const mod = (await import(specifier).catch(() => null));
|
|
47
|
+
const sharp = mod?.default;
|
|
48
|
+
if (typeof sharp !== "function") {
|
|
49
|
+
return {
|
|
50
|
+
ok: false,
|
|
51
|
+
output: `Cannot read image ${displayPath}: the optional 'sharp' peer is not installed. Run \`bun add sharp\` to enable image reading.`,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
try {
|
|
55
|
+
const pipeline = sharp(buf);
|
|
56
|
+
const meta = await pipeline.metadata();
|
|
57
|
+
const w = meta.width ?? 0;
|
|
58
|
+
const h = meta.height ?? 0;
|
|
59
|
+
const needsResize = w > MAX_EDGE || h > MAX_EDGE;
|
|
60
|
+
const out = needsResize
|
|
61
|
+
? await pipeline.resize({ width: MAX_EDGE, height: MAX_EDGE, fit: "inside", withoutEnlargement: true }).toBuffer()
|
|
62
|
+
: buf;
|
|
63
|
+
const outMime = formatToMime(meta.format, mime);
|
|
64
|
+
const dims = w && h ? ` ${w}×${h}` : "";
|
|
65
|
+
const resizedNote = needsResize ? ` (resized to fit ${MAX_EDGE}px for the model)` : "";
|
|
66
|
+
return {
|
|
67
|
+
ok: true,
|
|
68
|
+
output: `[image: ${displayPath}${dims}, ${outMime}${resizedNote}]`,
|
|
69
|
+
images: [{ data: out.toString("base64"), mimeType: outMime }],
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
catch (err) {
|
|
73
|
+
return { ok: false, output: `Failed to decode image ${displayPath}: ${err instanceof Error ? err.message : String(err)}` };
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=_image.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"_image.js","sourceRoot":"","sources":["../../../src/tools/builtins/_image.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/** Merge `login` PATH entries into `current`, appending only entries not already
|
|
2
|
+
* present (current dirs keep priority). Pure — the unit-testable core. */
|
|
3
|
+
export declare function mergePath(current: string, login: string): string;
|
|
4
|
+
/** Ask the login shell for its PATH (`$SHELL -lc 'printf %s "$PATH"'`). Returns
|
|
5
|
+
* the trimmed PATH, or null on any failure. Injectable for tests. */
|
|
6
|
+
export declare function resolveLoginPath(run?: (shell: string, args: string[]) => {
|
|
7
|
+
status: number | null;
|
|
8
|
+
stdout: string;
|
|
9
|
+
}): string | null;
|
|
10
|
+
/**
|
|
11
|
+
* Resolve + merge the login-shell PATH into `process.env.PATH` once per process.
|
|
12
|
+
* Best-effort and idempotent; safe to call before every bash run.
|
|
13
|
+
*/
|
|
14
|
+
export declare function ensureLoginShellPath(): void;
|
|
15
|
+
/** Test-only: re-arm the one-shot guard. */
|
|
16
|
+
export declare function __resetLoginShellPath(): void;
|
|
17
|
+
//# sourceMappingURL=_login-shell.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"_login-shell.d.ts","sourceRoot":"","sources":["../../../src/tools/builtins/_login-shell.ts"],"names":[],"mappings":"AAeA;0EAC0E;AAC1E,wBAAgB,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAUhE;AAED;qEACqE;AACrE,wBAAgB,gBAAgB,CAC9B,GAAG,GAAE,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK;IAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAG9E,GACA,MAAM,GAAG,IAAI,CAUf;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,IAAI,IAAI,CAQ3C;AAED,4CAA4C;AAC5C,wBAAgB,qBAAqB,IAAI,IAAI,CAE5C"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* (7.9 [5.9], goose) Login-shell PATH pre-resolution. A GUI-launched process
|
|
3
|
+
* (the Electron desktop, a double-clicked app) inherits a minimal `PATH` that
|
|
4
|
+
* omits the user's real toolchain dirs (`/opt/homebrew/bin`, nvm, cargo, …), so
|
|
5
|
+
* `bash` can't find `node`/`cargo`/`rg`. goose fixes this by asking the user's
|
|
6
|
+
* login shell for its `PATH` once and merging the missing entries into
|
|
7
|
+
* `process.env.PATH`, which every child process then inherits.
|
|
8
|
+
*
|
|
9
|
+
* One-shot + idempotent. No-op on Windows, when opted out
|
|
10
|
+
* (`CHANCES_NO_LOGIN_PATH=1`), or when the login shell can't be queried.
|
|
11
|
+
*/
|
|
12
|
+
import { spawnSync } from "node:child_process";
|
|
13
|
+
let resolved = false;
|
|
14
|
+
/** Merge `login` PATH entries into `current`, appending only entries not already
|
|
15
|
+
* present (current dirs keep priority). Pure — the unit-testable core. */
|
|
16
|
+
export function mergePath(current, login) {
|
|
17
|
+
const out = current.split(":").filter(Boolean);
|
|
18
|
+
const seen = new Set(out);
|
|
19
|
+
for (const entry of login.split(":").filter(Boolean)) {
|
|
20
|
+
if (!seen.has(entry)) {
|
|
21
|
+
out.push(entry);
|
|
22
|
+
seen.add(entry);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return out.join(":");
|
|
26
|
+
}
|
|
27
|
+
/** Ask the login shell for its PATH (`$SHELL -lc 'printf %s "$PATH"'`). Returns
|
|
28
|
+
* the trimmed PATH, or null on any failure. Injectable for tests. */
|
|
29
|
+
export function resolveLoginPath(run = (shell, args) => {
|
|
30
|
+
const r = spawnSync(shell, args, { encoding: "utf8", timeout: 3000 });
|
|
31
|
+
return { status: r.status, stdout: r.stdout ?? "" };
|
|
32
|
+
}) {
|
|
33
|
+
const shell = process.env.SHELL || "/bin/bash";
|
|
34
|
+
try {
|
|
35
|
+
const r = run(shell, ["-lc", 'printf %s "$PATH"']);
|
|
36
|
+
if (r.status !== 0)
|
|
37
|
+
return null;
|
|
38
|
+
const path = r.stdout.trim();
|
|
39
|
+
return path.length > 0 ? path : null;
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Resolve + merge the login-shell PATH into `process.env.PATH` once per process.
|
|
47
|
+
* Best-effort and idempotent; safe to call before every bash run.
|
|
48
|
+
*/
|
|
49
|
+
export function ensureLoginShellPath() {
|
|
50
|
+
if (resolved)
|
|
51
|
+
return;
|
|
52
|
+
resolved = true;
|
|
53
|
+
if (process.platform === "win32")
|
|
54
|
+
return;
|
|
55
|
+
if (process.env.CHANCES_NO_LOGIN_PATH === "1")
|
|
56
|
+
return;
|
|
57
|
+
const login = resolveLoginPath();
|
|
58
|
+
if (!login)
|
|
59
|
+
return;
|
|
60
|
+
process.env.PATH = mergePath(process.env.PATH ?? "", login);
|
|
61
|
+
}
|
|
62
|
+
/** Test-only: re-arm the one-shot guard. */
|
|
63
|
+
export function __resetLoginShellPath() {
|
|
64
|
+
resolved = false;
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=_login-shell.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"_login-shell.js","sourceRoot":"","sources":["../../../src/tools/builtins/_login-shell.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAE/C,IAAI,QAAQ,GAAG,KAAK,CAAC;AAErB;0EAC0E;AAC1E,MAAM,UAAU,SAAS,CAAC,OAAe,EAAE,KAAa;IACtD,MAAM,GAAG,GAAG,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAC/C,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;IAC1B,KAAK,MAAM,KAAK,IAAI,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC;QACrD,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;YACrB,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAChB,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QAClB,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACvB,CAAC;AAED;qEACqE;AACrE,MAAM,UAAU,gBAAgB,CAC9B,MAAoF,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE;IAClG,MAAM,CAAC,GAAG,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;IACtE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,IAAI,EAAE,EAAE,CAAC;AACtD,CAAC;IAED,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,KAAK,IAAI,WAAW,CAAC;IAC/C,IAAI,CAAC;QACH,MAAM,CAAC,GAAG,GAAG,CAAC,KAAK,EAAE,CAAC,KAAK,EAAE,mBAAmB,CAAC,CAAC,CAAC;QACnD,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,IAAI,CAAC;QAChC,MAAM,IAAI,GAAG,CAAC,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;QAC7B,OAAO,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;IACvC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,oBAAoB;IAClC,IAAI,QAAQ;QAAE,OAAO;IACrB,QAAQ,GAAG,IAAI,CAAC;IAChB,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO;QAAE,OAAO;IACzC,IAAI,OAAO,CAAC,GAAG,CAAC,qBAAqB,KAAK,GAAG;QAAE,OAAO;IACtD,MAAM,KAAK,GAAG,gBAAgB,EAAE,CAAC;IACjC,IAAI,CAAC,KAAK;QAAE,OAAO;IACnB,OAAO,CAAC,GAAG,CAAC,IAAI,GAAG,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,EAAE,EAAE,KAAK,CAAC,CAAC;AAC9D,CAAC;AAED,4CAA4C;AAC5C,MAAM,UAAU,qBAAqB;IACnC,QAAQ,GAAG,KAAK,CAAC;AACnB,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Jupyter notebook (`.ipynb`) rendering for the `read` tool (7.9 [5.5], the
|
|
3
|
+
* "notebooks last" stage of the staged multimodal decision — delivered this
|
|
4
|
+
* task, no longer deferred). A notebook is JSON, so reading the raw file would
|
|
5
|
+
* dump unreadable escaped source + base64 output blobs at the model. Instead we
|
|
6
|
+
* parse `cells[]` and render a compact, legible cell view (source + text
|
|
7
|
+
* outputs). This is a READ-ONLY view: it carries no `¶path#tag` hashline header
|
|
8
|
+
* because the model must not line-edit a rendered notebook — to change a
|
|
9
|
+
* notebook, edit the raw `.ipynb` JSON (a future NotebookEdit tool). No external
|
|
10
|
+
* dependency: pure `JSON.parse`.
|
|
11
|
+
*/
|
|
12
|
+
import type { ToolResult } from "../types.js";
|
|
13
|
+
/** Render an `.ipynb` JSON document as a compact, read-only cell view. */
|
|
14
|
+
export declare function renderNotebook(raw: string, displayPath: string): ToolResult;
|
|
15
|
+
//# sourceMappingURL=_notebook.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"_notebook.d.ts","sourceRoot":"","sources":["../../../src/tools/builtins/_notebook.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AA6D9C,0EAA0E;AAC1E,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,UAAU,CA+B3E"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/** Char budget for the rendered notebook before truncation (≈ read token cap). */
|
|
2
|
+
const MAX_RENDER_CHARS = 200_000;
|
|
3
|
+
/** Per-cell output char cap so one chatty cell can't dominate the render. */
|
|
4
|
+
const MAX_OUTPUT_CHARS = 4_000;
|
|
5
|
+
/** `.ipynb` source/text fields are either a string or an array of line strings. */
|
|
6
|
+
function joinSource(src) {
|
|
7
|
+
if (Array.isArray(src))
|
|
8
|
+
return src.join("");
|
|
9
|
+
return typeof src === "string" ? src : "";
|
|
10
|
+
}
|
|
11
|
+
function stripAnsi(text) {
|
|
12
|
+
// Strip terminal control sequences that show up in stream/traceback output.
|
|
13
|
+
// biome-ignore lint/suspicious/noControlCharactersInRegex: stripping ANSI by design.
|
|
14
|
+
return text.replace(/\[[0-9;]*m/g, "");
|
|
15
|
+
}
|
|
16
|
+
function renderOutputs(outputs) {
|
|
17
|
+
const blocks = [];
|
|
18
|
+
for (const out of outputs) {
|
|
19
|
+
switch (out.output_type) {
|
|
20
|
+
case "stream":
|
|
21
|
+
blocks.push(stripAnsi(joinSource(out.text)));
|
|
22
|
+
break;
|
|
23
|
+
case "execute_result":
|
|
24
|
+
case "display_data": {
|
|
25
|
+
const plain = out.data?.["text/plain"];
|
|
26
|
+
if (plain !== undefined)
|
|
27
|
+
blocks.push(joinSource(plain));
|
|
28
|
+
else if (out.data)
|
|
29
|
+
blocks.push(`[${Object.keys(out.data).join(", ")} output]`);
|
|
30
|
+
break;
|
|
31
|
+
}
|
|
32
|
+
case "error":
|
|
33
|
+
blocks.push(stripAnsi([`${out.ename ?? "Error"}: ${out.evalue ?? ""}`, ...(out.traceback ?? [])].join("\n")));
|
|
34
|
+
break;
|
|
35
|
+
default:
|
|
36
|
+
break;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
let text = blocks.join("\n").replace(/\n+$/, "");
|
|
40
|
+
if (text.length > MAX_OUTPUT_CHARS)
|
|
41
|
+
text = `${text.slice(0, MAX_OUTPUT_CHARS)}\n… [output truncated]`;
|
|
42
|
+
return text;
|
|
43
|
+
}
|
|
44
|
+
/** Render an `.ipynb` JSON document as a compact, read-only cell view. */
|
|
45
|
+
export function renderNotebook(raw, displayPath) {
|
|
46
|
+
let nb;
|
|
47
|
+
try {
|
|
48
|
+
nb = JSON.parse(raw);
|
|
49
|
+
}
|
|
50
|
+
catch (err) {
|
|
51
|
+
return { ok: false, output: `Not a valid .ipynb (JSON parse failed) ${displayPath}: ${err instanceof Error ? err.message : String(err)}` };
|
|
52
|
+
}
|
|
53
|
+
const cells = Array.isArray(nb.cells) ? nb.cells : null;
|
|
54
|
+
if (!cells)
|
|
55
|
+
return { ok: false, output: `No cells[] found in ${displayPath} — not a Jupyter notebook.` };
|
|
56
|
+
const parts = [
|
|
57
|
+
`[notebook: ${displayPath}, ${cells.length} cell(s) — read-only rendering; edit the raw .ipynb JSON to change it]`,
|
|
58
|
+
];
|
|
59
|
+
let truncated = false;
|
|
60
|
+
for (let i = 0; i < cells.length; i++) {
|
|
61
|
+
if (parts.join("\n").length > MAX_RENDER_CHARS) {
|
|
62
|
+
truncated = true;
|
|
63
|
+
break;
|
|
64
|
+
}
|
|
65
|
+
const cell = cells[i];
|
|
66
|
+
const type = cell.cell_type ?? "unknown";
|
|
67
|
+
const src = joinSource(cell.source).replace(/\n$/, "");
|
|
68
|
+
parts.push(`\n# Cell ${i + 1} · ${type}`);
|
|
69
|
+
if (src.length > 0)
|
|
70
|
+
parts.push(src);
|
|
71
|
+
if (type === "code" && Array.isArray(cell.outputs) && cell.outputs.length > 0) {
|
|
72
|
+
const outText = renderOutputs(cell.outputs);
|
|
73
|
+
if (outText.length > 0)
|
|
74
|
+
parts.push(`## Output:\n${outText}`);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
if (truncated)
|
|
78
|
+
parts.push(`\n… [notebook truncated at ${MAX_RENDER_CHARS} chars — open the raw file for the rest]`);
|
|
79
|
+
return { ok: true, output: parts.join("\n") };
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=_notebook.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"_notebook.js","sourceRoot":"","sources":["../../../src/tools/builtins/_notebook.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PDF text extraction for the `read` tool (7.9 [5.5], the "PDF after image"
|
|
3
|
+
* stage — delivered this task, no longer deferred). PDFs are binary, so they
|
|
4
|
+
* route here before the binary reject (like images). Text is extracted via
|
|
5
|
+
* `unpdf` — a LAZY optional peer (absent ⇒ a clear `bun add unpdf` hint; the
|
|
6
|
+
* tool degrades, nothing else breaks), mirroring the `sharp` image peer. The
|
|
7
|
+
* extracted text is a READ-ONLY view (no `¶path#tag`): the model cannot
|
|
8
|
+
* line-edit a PDF.
|
|
9
|
+
*/
|
|
10
|
+
import type { ToolResult } from "../types.js";
|
|
11
|
+
/** Magic-byte sniff: a PDF starts with `%PDF`. */
|
|
12
|
+
export declare function sniffPdf(buf: Buffer): boolean;
|
|
13
|
+
/**
|
|
14
|
+
* Extract text from a PDF `buf` into a read-only tool result. Without the
|
|
15
|
+
* `unpdf` peer, returns an actionable `ok:false` instead of refusing as a
|
|
16
|
+
* generic binary file.
|
|
17
|
+
*/
|
|
18
|
+
export declare function readPdfAsText(buf: Buffer, displayPath: string): Promise<ToolResult>;
|
|
19
|
+
//# sourceMappingURL=_pdf.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"_pdf.d.ts","sourceRoot":"","sources":["../../../src/tools/builtins/_pdf.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAK9C,kDAAkD;AAClD,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAE7C;AAUD;;;;GAIG;AACH,wBAAsB,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CA4BzF"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/** Char budget for extracted PDF text before truncation (≈ read token cap). */
|
|
2
|
+
const MAX_TEXT_CHARS = 200_000;
|
|
3
|
+
/** Magic-byte sniff: a PDF starts with `%PDF`. */
|
|
4
|
+
export function sniffPdf(buf) {
|
|
5
|
+
return buf.length >= 5 && buf[0] === 0x25 && buf[1] === 0x50 && buf[2] === 0x44 && buf[3] === 0x46;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Extract text from a PDF `buf` into a read-only tool result. Without the
|
|
9
|
+
* `unpdf` peer, returns an actionable `ok:false` instead of refusing as a
|
|
10
|
+
* generic binary file.
|
|
11
|
+
*/
|
|
12
|
+
export async function readPdfAsText(buf, displayPath) {
|
|
13
|
+
// Lazy optional peer: a non-literal specifier keeps it out of the type graph
|
|
14
|
+
// (unpdf isn't a declared dependency), so a missing peer is a runtime null.
|
|
15
|
+
const specifier = "unpdf";
|
|
16
|
+
const mod = (await import(specifier).catch(() => null));
|
|
17
|
+
if (!mod || typeof mod.getDocumentProxy !== "function" || typeof mod.extractText !== "function") {
|
|
18
|
+
return {
|
|
19
|
+
ok: false,
|
|
20
|
+
output: `Cannot read PDF ${displayPath}: the optional 'unpdf' peer is not installed. Run \`bun add unpdf\` to enable PDF reading.`,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
try {
|
|
24
|
+
const doc = await mod.getDocumentProxy(new Uint8Array(buf));
|
|
25
|
+
const { totalPages, text } = await mod.extractText(doc, { mergePages: true });
|
|
26
|
+
let body = Array.isArray(text) ? text.join("\n\n") : String(text);
|
|
27
|
+
let truncated = false;
|
|
28
|
+
if (body.length > MAX_TEXT_CHARS) {
|
|
29
|
+
body = body.slice(0, MAX_TEXT_CHARS);
|
|
30
|
+
truncated = true;
|
|
31
|
+
}
|
|
32
|
+
const note = truncated ? `\n\n… [PDF text truncated at ${MAX_TEXT_CHARS} chars]` : "";
|
|
33
|
+
return {
|
|
34
|
+
ok: true,
|
|
35
|
+
output: `[pdf: ${displayPath}, ${totalPages} page(s), text extracted — read-only]\n\n${body}${note}`,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
catch (err) {
|
|
39
|
+
return { ok: false, output: `Failed to extract PDF text from ${displayPath}: ${err instanceof Error ? err.message : String(err)}` };
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=_pdf.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"_pdf.js","sourceRoot":"","sources":["../../../src/tools/builtins/_pdf.ts"],"names":[],"mappings":"AAWA,+EAA+E;AAC/E,MAAM,cAAc,GAAG,OAAO,CAAC;AAE/B,kDAAkD;AAClD,MAAM,UAAU,QAAQ,CAAC,GAAW;IAClC,OAAO,GAAG,CAAC,MAAM,IAAI,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,KAAK,IAAI,IAAI,GAAG,CAAC,CAAC,CAAC,KAAK,IAAI,IAAI,GAAG,CAAC,CAAC,CAAC,KAAK,IAAI,IAAI,GAAG,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC;AACrG,CAAC;AAUD;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,GAAW,EAAE,WAAmB;IAClE,6EAA6E;IAC7E,4EAA4E;IAC5E,MAAM,SAAS,GAAG,OAAO,CAAC;IAC1B,MAAM,GAAG,GAAG,CAAC,MAAM,MAAM,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAuB,CAAC;IAC9E,IAAI,CAAC,GAAG,IAAI,OAAO,GAAG,CAAC,gBAAgB,KAAK,UAAU,IAAI,OAAO,GAAG,CAAC,WAAW,KAAK,UAAU,EAAE,CAAC;QAChG,OAAO;YACL,EAAE,EAAE,KAAK;YACT,MAAM,EAAE,mBAAmB,WAAW,4FAA4F;SACnI,CAAC;IACJ,CAAC;IACD,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,GAAG,CAAC,gBAAgB,CAAC,IAAI,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC;QAC5D,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,GAAG,MAAM,GAAG,CAAC,WAAW,CAAC,GAAG,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC;QAC9E,IAAI,IAAI,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAClE,IAAI,SAAS,GAAG,KAAK,CAAC;QACtB,IAAI,IAAI,CAAC,MAAM,GAAG,cAAc,EAAE,CAAC;YACjC,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,cAAc,CAAC,CAAC;YACrC,SAAS,GAAG,IAAI,CAAC;QACnB,CAAC;QACD,MAAM,IAAI,GAAG,SAAS,CAAC,CAAC,CAAC,gCAAgC,cAAc,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC;QACtF,OAAO;YACL,EAAE,EAAE,IAAI;YACR,MAAM,EAAE,SAAS,WAAW,KAAK,UAAU,4CAA4C,IAAI,GAAG,IAAI,EAAE;SACrG,CAAC;IACJ,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,mCAAmC,WAAW,KAAK,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;IACtI,CAAC;AACH,CAAC"}
|