@theokit/sdk-tools 0.26.2 → 0.26.3
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 +20 -0
- package/dist/index.cjs +11 -11
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +14 -14
- package/dist/index.d.ts +14 -14
- package/dist/index.js +11 -11
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/index.d.cts
CHANGED
|
@@ -130,7 +130,7 @@ declare function createCurrentTimeTool(opts?: CreateCurrentTimeToolOptions): Cus
|
|
|
130
130
|
|
|
131
131
|
interface CreateEditFileToolOptions {
|
|
132
132
|
/**
|
|
133
|
-
* M76 —
|
|
133
|
+
* M76 — the name exposed to the model. Omitted ⇒ today's literal (additive).
|
|
134
134
|
*
|
|
135
135
|
* It exists because, in Codex, the name is BORN in the tool definition and is the approval decision
|
|
136
136
|
* key — three consumers (model, approval, telemetry) of a string decided in one place. Renaming
|
|
@@ -226,15 +226,15 @@ interface CreateGitStatusToolOptions {
|
|
|
226
226
|
maxStdoutBytes?: number;
|
|
227
227
|
/**
|
|
228
228
|
* Injected execution backend (`@theokit/sdk/sandbox`) — when present, `git status` runs via
|
|
229
|
-
* `SandboxBackend.execute`;
|
|
229
|
+
* `SandboxBackend.execute`; omitted ⇒ the local `git` (unchanged).
|
|
230
230
|
*
|
|
231
231
|
* Symmetry with `createGitDiffTool`, flagged by the M76 review: without it `git_diff` would run
|
|
232
232
|
* confined and `git_status` not, in the same session — and the asymmetry would be invisible until someone
|
|
233
|
-
*
|
|
233
|
+
* notice that one of the two escapes the sandbox.
|
|
234
234
|
*/
|
|
235
235
|
sandbox?: SandboxProvider;
|
|
236
236
|
/**
|
|
237
|
-
* M76 —
|
|
237
|
+
* M76 — the name exposed to the model. Omitted ⇒ `"git_status"` (additive).
|
|
238
238
|
*
|
|
239
239
|
* The name is a contract: the approval key, what the model sees and what telemetry records.
|
|
240
240
|
*/
|
|
@@ -490,7 +490,7 @@ declare function buildRepoMap(cwd: string, opts?: RepoMapOptions): string;
|
|
|
490
490
|
* This is a heuristic GUARDRAIL, NOT a sandbox: it is bypassable by deep obfuscation
|
|
491
491
|
* (base64/env-indirection) and is best-effort. POSIX `/bin/sh` only; Windows
|
|
492
492
|
* PowerShell is out of scope. True isolation needs a container.
|
|
493
|
-
*
|
|
493
|
+
* reference: .claude/knowledge-base/references/theocode-shell-guard/server-lib/shell-guard.ts
|
|
494
494
|
*/
|
|
495
495
|
|
|
496
496
|
/** Thrown / reported when a command matches the catastrophic deny-list. */
|
|
@@ -616,7 +616,7 @@ declare function withShellExitGuidance(tool: CustomTool): CustomTool;
|
|
|
616
616
|
|
|
617
617
|
interface CreateListDirToolOptions {
|
|
618
618
|
/**
|
|
619
|
-
* M76 —
|
|
619
|
+
* M76 — the name exposed to the model. Omitted ⇒ today's literal (additive).
|
|
620
620
|
*
|
|
621
621
|
* It exists because, in Codex, the name is BORN in the tool definition and is the approval decision key —
|
|
622
622
|
* three consumers (model, approval, telemetry) of a string decided in one place. Renaming
|
|
@@ -627,8 +627,8 @@ interface CreateListDirToolOptions {
|
|
|
627
627
|
/** M76 — description exposed to the model. Omitted => today's literal (additive). */
|
|
628
628
|
description?: string;
|
|
629
629
|
/**
|
|
630
|
-
* M76 — opt-in "
|
|
631
|
-
* (
|
|
630
|
+
* M76 — opt-in "list anywhere": honours an ABSOLUTE `path` outside `projectRoot`
|
|
631
|
+
* (parity with `createReadFileTool`/`createSearchTextTool`, Codex's read-only sandbox).
|
|
632
632
|
*
|
|
633
633
|
* The ANY-segment secret guard still applies, and is not separable: `isForbiddenPath`
|
|
634
634
|
* only blocks the sensitive item when it is the FIRST segment, so a `/home/u/proj/.env/sub`
|
|
@@ -720,9 +720,9 @@ interface QuestionToolOptions {
|
|
|
720
720
|
/**
|
|
721
721
|
* Callback that presents the question to the user and resolves with the answer.
|
|
722
722
|
*
|
|
723
|
-
* M76 —
|
|
723
|
+
* M76 — became OPTIONAL: the preferred asker comes from the run context
|
|
724
724
|
* (`ctx.context.askUser`), because a value pinned here is the "baked into each factory" that the
|
|
725
|
-
* `CustomTool.handler`
|
|
725
|
+
* `CustomTool.handler` names as the problem `ctx.context` exists to solve. This field
|
|
726
726
|
* remains as a fallback, for callers building the tool with a fixed asker (backward-compatible).
|
|
727
727
|
*/
|
|
728
728
|
askUser?: (question: string, threadId?: string) => Promise<string>;
|
|
@@ -735,11 +735,11 @@ interface QuestionToolOptions {
|
|
|
735
735
|
/** Maximum time to wait for user response in ms. Default: 300_000 (5 min). */
|
|
736
736
|
timeoutMs?: number;
|
|
737
737
|
/**
|
|
738
|
-
* M76 —
|
|
738
|
+
* M76 — the name exposed to the model. Omitted ⇒ `"question"` (additive).
|
|
739
739
|
*
|
|
740
740
|
* The consumer needed this: Codex calls the tool `request_user_input`, and without the option it
|
|
741
741
|
* had to rebuild the whole object by hand — the two-cast adapter T3.3
|
|
742
|
-
*
|
|
742
|
+
* removed.
|
|
743
743
|
*/
|
|
744
744
|
name?: string;
|
|
745
745
|
/** M76 — description exposed to the model. Omitted => today's literal (additive). */
|
|
@@ -945,7 +945,7 @@ declare function createRunVitestTool(opts: CreateRunVitestToolOptions): CustomTo
|
|
|
945
945
|
|
|
946
946
|
interface CreateSearchTextToolOptions {
|
|
947
947
|
/**
|
|
948
|
-
* M76 —
|
|
948
|
+
* M76 — the name exposed to the model. Omitted ⇒ today's literal (additive).
|
|
949
949
|
*
|
|
950
950
|
* It exists because, in Codex, the name is BORN in the tool definition and is the approval decision
|
|
951
951
|
* key — three consumers (model, approval, telemetry) of a string decided in one place. Renaming
|
|
@@ -985,7 +985,7 @@ declare function createSearchTextTool(opts: CreateSearchTextToolOptions): Custom
|
|
|
985
985
|
|
|
986
986
|
interface CreateShellToolOptions {
|
|
987
987
|
/**
|
|
988
|
-
* M76 —
|
|
988
|
+
* M76 — the name exposed to the model. Omitted ⇒ today's literal (additive).
|
|
989
989
|
*
|
|
990
990
|
* It exists because, in Codex, the name is BORN in the tool definition and is the approval decision
|
|
991
991
|
* key — three consumers (model, approval, telemetry) of a string decided in one place. Renaming
|
package/dist/index.d.ts
CHANGED
|
@@ -130,7 +130,7 @@ declare function createCurrentTimeTool(opts?: CreateCurrentTimeToolOptions): Cus
|
|
|
130
130
|
|
|
131
131
|
interface CreateEditFileToolOptions {
|
|
132
132
|
/**
|
|
133
|
-
* M76 —
|
|
133
|
+
* M76 — the name exposed to the model. Omitted ⇒ today's literal (additive).
|
|
134
134
|
*
|
|
135
135
|
* It exists because, in Codex, the name is BORN in the tool definition and is the approval decision
|
|
136
136
|
* key — three consumers (model, approval, telemetry) of a string decided in one place. Renaming
|
|
@@ -226,15 +226,15 @@ interface CreateGitStatusToolOptions {
|
|
|
226
226
|
maxStdoutBytes?: number;
|
|
227
227
|
/**
|
|
228
228
|
* Injected execution backend (`@theokit/sdk/sandbox`) — when present, `git status` runs via
|
|
229
|
-
* `SandboxBackend.execute`;
|
|
229
|
+
* `SandboxBackend.execute`; omitted ⇒ the local `git` (unchanged).
|
|
230
230
|
*
|
|
231
231
|
* Symmetry with `createGitDiffTool`, flagged by the M76 review: without it `git_diff` would run
|
|
232
232
|
* confined and `git_status` not, in the same session — and the asymmetry would be invisible until someone
|
|
233
|
-
*
|
|
233
|
+
* notice that one of the two escapes the sandbox.
|
|
234
234
|
*/
|
|
235
235
|
sandbox?: SandboxProvider;
|
|
236
236
|
/**
|
|
237
|
-
* M76 —
|
|
237
|
+
* M76 — the name exposed to the model. Omitted ⇒ `"git_status"` (additive).
|
|
238
238
|
*
|
|
239
239
|
* The name is a contract: the approval key, what the model sees and what telemetry records.
|
|
240
240
|
*/
|
|
@@ -490,7 +490,7 @@ declare function buildRepoMap(cwd: string, opts?: RepoMapOptions): string;
|
|
|
490
490
|
* This is a heuristic GUARDRAIL, NOT a sandbox: it is bypassable by deep obfuscation
|
|
491
491
|
* (base64/env-indirection) and is best-effort. POSIX `/bin/sh` only; Windows
|
|
492
492
|
* PowerShell is out of scope. True isolation needs a container.
|
|
493
|
-
*
|
|
493
|
+
* reference: .claude/knowledge-base/references/theocode-shell-guard/server-lib/shell-guard.ts
|
|
494
494
|
*/
|
|
495
495
|
|
|
496
496
|
/** Thrown / reported when a command matches the catastrophic deny-list. */
|
|
@@ -616,7 +616,7 @@ declare function withShellExitGuidance(tool: CustomTool): CustomTool;
|
|
|
616
616
|
|
|
617
617
|
interface CreateListDirToolOptions {
|
|
618
618
|
/**
|
|
619
|
-
* M76 —
|
|
619
|
+
* M76 — the name exposed to the model. Omitted ⇒ today's literal (additive).
|
|
620
620
|
*
|
|
621
621
|
* It exists because, in Codex, the name is BORN in the tool definition and is the approval decision key —
|
|
622
622
|
* three consumers (model, approval, telemetry) of a string decided in one place. Renaming
|
|
@@ -627,8 +627,8 @@ interface CreateListDirToolOptions {
|
|
|
627
627
|
/** M76 — description exposed to the model. Omitted => today's literal (additive). */
|
|
628
628
|
description?: string;
|
|
629
629
|
/**
|
|
630
|
-
* M76 — opt-in "
|
|
631
|
-
* (
|
|
630
|
+
* M76 — opt-in "list anywhere": honours an ABSOLUTE `path` outside `projectRoot`
|
|
631
|
+
* (parity with `createReadFileTool`/`createSearchTextTool`, Codex's read-only sandbox).
|
|
632
632
|
*
|
|
633
633
|
* The ANY-segment secret guard still applies, and is not separable: `isForbiddenPath`
|
|
634
634
|
* only blocks the sensitive item when it is the FIRST segment, so a `/home/u/proj/.env/sub`
|
|
@@ -720,9 +720,9 @@ interface QuestionToolOptions {
|
|
|
720
720
|
/**
|
|
721
721
|
* Callback that presents the question to the user and resolves with the answer.
|
|
722
722
|
*
|
|
723
|
-
* M76 —
|
|
723
|
+
* M76 — became OPTIONAL: the preferred asker comes from the run context
|
|
724
724
|
* (`ctx.context.askUser`), because a value pinned here is the "baked into each factory" that the
|
|
725
|
-
* `CustomTool.handler`
|
|
725
|
+
* `CustomTool.handler` names as the problem `ctx.context` exists to solve. This field
|
|
726
726
|
* remains as a fallback, for callers building the tool with a fixed asker (backward-compatible).
|
|
727
727
|
*/
|
|
728
728
|
askUser?: (question: string, threadId?: string) => Promise<string>;
|
|
@@ -735,11 +735,11 @@ interface QuestionToolOptions {
|
|
|
735
735
|
/** Maximum time to wait for user response in ms. Default: 300_000 (5 min). */
|
|
736
736
|
timeoutMs?: number;
|
|
737
737
|
/**
|
|
738
|
-
* M76 —
|
|
738
|
+
* M76 — the name exposed to the model. Omitted ⇒ `"question"` (additive).
|
|
739
739
|
*
|
|
740
740
|
* The consumer needed this: Codex calls the tool `request_user_input`, and without the option it
|
|
741
741
|
* had to rebuild the whole object by hand — the two-cast adapter T3.3
|
|
742
|
-
*
|
|
742
|
+
* removed.
|
|
743
743
|
*/
|
|
744
744
|
name?: string;
|
|
745
745
|
/** M76 — description exposed to the model. Omitted => today's literal (additive). */
|
|
@@ -945,7 +945,7 @@ declare function createRunVitestTool(opts: CreateRunVitestToolOptions): CustomTo
|
|
|
945
945
|
|
|
946
946
|
interface CreateSearchTextToolOptions {
|
|
947
947
|
/**
|
|
948
|
-
* M76 —
|
|
948
|
+
* M76 — the name exposed to the model. Omitted ⇒ today's literal (additive).
|
|
949
949
|
*
|
|
950
950
|
* It exists because, in Codex, the name is BORN in the tool definition and is the approval decision
|
|
951
951
|
* key — three consumers (model, approval, telemetry) of a string decided in one place. Renaming
|
|
@@ -985,7 +985,7 @@ declare function createSearchTextTool(opts: CreateSearchTextToolOptions): Custom
|
|
|
985
985
|
|
|
986
986
|
interface CreateShellToolOptions {
|
|
987
987
|
/**
|
|
988
|
-
* M76 —
|
|
988
|
+
* M76 — the name exposed to the model. Omitted ⇒ today's literal (additive).
|
|
989
989
|
*
|
|
990
990
|
* It exists because, in Codex, the name is BORN in the tool definition and is the approval decision
|
|
991
991
|
* key — three consumers (model, approval, telemetry) of a string decided in one place. Renaming
|
package/dist/index.js
CHANGED
|
@@ -791,12 +791,12 @@ function checkPathScope(path, projectRoot) {
|
|
|
791
791
|
throw err;
|
|
792
792
|
}
|
|
793
793
|
}
|
|
794
|
-
var
|
|
795
|
-
function
|
|
794
|
+
var SENSITIVE_SEGMENTS = /* @__PURE__ */ new Set([".env", ".git", "node_modules", ".theo"]);
|
|
795
|
+
function isForbiddenAtAnyDepth(path) {
|
|
796
796
|
const segs = path.replace(/\\/g, "/").split("/").filter(Boolean);
|
|
797
797
|
return segs.some((s) => {
|
|
798
798
|
if (s === ".env.example") return false;
|
|
799
|
-
return
|
|
799
|
+
return SENSITIVE_SEGMENTS.has(s) || /^\.env\./.test(s);
|
|
800
800
|
});
|
|
801
801
|
}
|
|
802
802
|
|
|
@@ -1584,7 +1584,7 @@ function createListDirTool(opts) {
|
|
|
1584
1584
|
}),
|
|
1585
1585
|
handler: async ({ path }, ctx) => {
|
|
1586
1586
|
const relative3 = path === "" || path === "." ? "." : path;
|
|
1587
|
-
const verdict =
|
|
1587
|
+
const verdict = decideScope(relative3, path, opts.allowAbsolute === true);
|
|
1588
1588
|
if (verdict.error !== void 0) return verdict.error;
|
|
1589
1589
|
if (verdict.absoluteRoot !== void 0) {
|
|
1590
1590
|
return listViaLocalFs(verdict.absoluteRoot, ".", path, max);
|
|
@@ -1597,14 +1597,14 @@ function createListDirTool(opts) {
|
|
|
1597
1597
|
}
|
|
1598
1598
|
});
|
|
1599
1599
|
}
|
|
1600
|
-
function
|
|
1600
|
+
function decideScope(relative3, original, allowAbsolute) {
|
|
1601
1601
|
const refuse = (error) => ({
|
|
1602
1602
|
error: JSON.stringify({ ok: false, error, path: original })
|
|
1603
1603
|
});
|
|
1604
1604
|
if (relative3 !== "." && isForbiddenPath(relative3)) return refuse("forbidden_path");
|
|
1605
1605
|
if (!isAbsolute(relative3)) return {};
|
|
1606
1606
|
if (!allowAbsolute) return refuse("path_traversal");
|
|
1607
|
-
if (
|
|
1607
|
+
if (isForbiddenAtAnyDepth(relative3)) return refuse("forbidden_path");
|
|
1608
1608
|
return { absoluteRoot: relative3 };
|
|
1609
1609
|
}
|
|
1610
1610
|
async function listViaLocalFs(projectRoot, relative3, originalPath, max) {
|
|
@@ -1767,10 +1767,10 @@ function createPlanModeTool(options) {
|
|
|
1767
1767
|
}
|
|
1768
1768
|
|
|
1769
1769
|
// src/question.ts
|
|
1770
|
-
function
|
|
1770
|
+
function askerFromContext(context) {
|
|
1771
1771
|
if (typeof context !== "object" || context === null) return void 0;
|
|
1772
|
-
const
|
|
1773
|
-
return typeof
|
|
1772
|
+
const candidate = context.askUser;
|
|
1773
|
+
return typeof candidate === "function" ? candidate : void 0;
|
|
1774
1774
|
}
|
|
1775
1775
|
function createQuestionTool(opts) {
|
|
1776
1776
|
const timeoutMs = opts.timeoutMs ?? 3e5;
|
|
@@ -1785,7 +1785,7 @@ function createQuestionTool(opts) {
|
|
|
1785
1785
|
required: ["question"]
|
|
1786
1786
|
},
|
|
1787
1787
|
handler: async (input, ctx) => {
|
|
1788
|
-
const askUser =
|
|
1788
|
+
const askUser = askerFromContext(ctx?.context) ?? opts.askUser;
|
|
1789
1789
|
if (askUser === void 0) {
|
|
1790
1790
|
return JSON.stringify({
|
|
1791
1791
|
ok: false,
|
|
@@ -1822,7 +1822,7 @@ function forbiddenReadError(path, allowAbsolute) {
|
|
|
1822
1822
|
if (isForbiddenPath(path)) {
|
|
1823
1823
|
return JSON.stringify({ ok: false, error: "forbidden_path", path });
|
|
1824
1824
|
}
|
|
1825
|
-
if (allowAbsolute && isAbsolute(path) &&
|
|
1825
|
+
if (allowAbsolute && isAbsolute(path) && isForbiddenAtAnyDepth(path)) {
|
|
1826
1826
|
return JSON.stringify({ ok: false, error: "forbidden_path", path });
|
|
1827
1827
|
}
|
|
1828
1828
|
return null;
|