@theokit/sdk-tools 0.15.0 → 0.16.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/CHANGELOG.md +21 -0
- package/dist/index.cjs +60 -12
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +22 -1
- package/dist/index.d.ts +22 -1
- package/dist/index.js +60 -13
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,26 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.16.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- ef00db3: Add `createCurrentTimeTool` — a built-in `current_time` tool. Codex-faithful at the core (Codex's
|
|
8
|
+
`clock.curr_time` returns UTC as `YYYY-MM-DD HH:MM:SS UTC`); this keeps that as the default and adds an
|
|
9
|
+
optional IANA `timezone` (additive superset — omitted ⇒ UTC) plus an unambiguous `iso` instant. Returns
|
|
10
|
+
`{ ok, current_time, iso, timezone }` or `{ ok: false, error: 'invalid_timezone' }`. The clock is
|
|
11
|
+
injectable (`{ clock }`) so the tool is deterministic under test.
|
|
12
|
+
|
|
13
|
+
## 0.15.1
|
|
14
|
+
|
|
15
|
+
### Patch Changes
|
|
16
|
+
|
|
17
|
+
- 4c5bd35: M15 review fixes (injected fs path only; local path unaffected): (1) the backend directory walk in
|
|
18
|
+
`glob_files`/`search_text` decides entry type via `stat` (which follows symlinks), so an in-boundary
|
|
19
|
+
symlink cycle could recurse until PATH_MAX — now depth-capped so it terminates; (2) `edit_file`'s
|
|
20
|
+
backend read mapped every failure to `not_found` — now only a genuinely missing file (`FileNotFoundError`)
|
|
21
|
+
maps to `not_found`; any other read error (e.g. a directory, a permission error) propagates (fail-loud),
|
|
22
|
+
matching the local path's ENOENT-only classification.
|
|
23
|
+
|
|
3
24
|
## 0.15.0
|
|
4
25
|
|
|
5
26
|
### Minor Changes
|
package/dist/index.cjs
CHANGED
|
@@ -267,6 +267,46 @@ function createSessionArtifactStore(options) {
|
|
|
267
267
|
}
|
|
268
268
|
return { write, read, has, list, path };
|
|
269
269
|
}
|
|
270
|
+
function formatInTimezone(now, tz) {
|
|
271
|
+
const parts = new Intl.DateTimeFormat("en-US", {
|
|
272
|
+
timeZone: tz,
|
|
273
|
+
year: "numeric",
|
|
274
|
+
month: "2-digit",
|
|
275
|
+
day: "2-digit",
|
|
276
|
+
hour: "2-digit",
|
|
277
|
+
minute: "2-digit",
|
|
278
|
+
second: "2-digit",
|
|
279
|
+
hour12: false
|
|
280
|
+
}).formatToParts(now);
|
|
281
|
+
const p = {};
|
|
282
|
+
for (const { type, value } of parts) p[type] = value;
|
|
283
|
+
const hour = p.hour === "24" ? "00" : p.hour;
|
|
284
|
+
return `${p.year}-${p.month}-${p.day} ${hour}:${p.minute}:${p.second} ${tz}`;
|
|
285
|
+
}
|
|
286
|
+
function createCurrentTimeTool(opts = {}) {
|
|
287
|
+
const clock = opts.clock ?? (() => /* @__PURE__ */ new Date());
|
|
288
|
+
return sdk.Tool.create({
|
|
289
|
+
name: "current_time",
|
|
290
|
+
description: "Get the current date and time. Returns { current_time, iso, timezone } as a JSON string, where current_time is 'YYYY-MM-DD HH:MM:SS <timezone>' and iso is the ISO-8601 instant. Pass an optional IANA timezone (e.g. 'America/Sao_Paulo', 'Europe/Lisbon'); defaults to UTC. Never state the date or time from memory \u2014 always call this. Returns { ok: false, error: 'invalid_timezone' } for an unknown timezone.",
|
|
291
|
+
inputSchema: zod.z.object({
|
|
292
|
+
timezone: zod.z.string().optional().describe("IANA timezone, e.g. 'America/Sao_Paulo' or 'Europe/Lisbon'. Defaults to UTC.")
|
|
293
|
+
}),
|
|
294
|
+
handler: ({ timezone }) => {
|
|
295
|
+
const tz = timezone ?? "UTC";
|
|
296
|
+
const now = clock();
|
|
297
|
+
try {
|
|
298
|
+
return JSON.stringify({
|
|
299
|
+
ok: true,
|
|
300
|
+
current_time: formatInTimezone(now, tz),
|
|
301
|
+
iso: now.toISOString(),
|
|
302
|
+
timezone: tz
|
|
303
|
+
});
|
|
304
|
+
} catch {
|
|
305
|
+
return JSON.stringify({ ok: false, error: "invalid_timezone", timezone: tz });
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
});
|
|
309
|
+
}
|
|
270
310
|
|
|
271
311
|
// src/internal/context-match.ts
|
|
272
312
|
var ContextMatchError = class extends Error {
|
|
@@ -381,8 +421,11 @@ async function editViaBackend(filesystem$1, ctx, path, old_string, new_string) {
|
|
|
381
421
|
let content;
|
|
382
422
|
try {
|
|
383
423
|
content = await backend.readFile(path);
|
|
384
|
-
} catch {
|
|
385
|
-
|
|
424
|
+
} catch (err) {
|
|
425
|
+
if (err instanceof filesystem.FileNotFoundError) {
|
|
426
|
+
return JSON.stringify({ ok: false, error: "not_found", path });
|
|
427
|
+
}
|
|
428
|
+
throw err;
|
|
386
429
|
}
|
|
387
430
|
const outcome = computeEdit(content, old_string, new_string);
|
|
388
431
|
if (!outcome.ok) return JSON.stringify({ ok: false, error: "no_match", path });
|
|
@@ -656,6 +699,7 @@ function runGitProcess(cwd, args, timeoutMs, maxStdoutBytes) {
|
|
|
656
699
|
});
|
|
657
700
|
}
|
|
658
701
|
var DEFAULT_EXCLUDES = /* @__PURE__ */ new Set(["node_modules", ".git", "dist", ".theo"]);
|
|
702
|
+
var MAX_BACKEND_WALK_DEPTH = 64;
|
|
659
703
|
function createGlobTool(opts) {
|
|
660
704
|
const { projectRoot, filesystem: filesystem$1 } = opts;
|
|
661
705
|
return sdk.Tool.create({
|
|
@@ -673,7 +717,7 @@ function createGlobTool(opts) {
|
|
|
673
717
|
const backend = await filesystem.resolveFilesystem(filesystem$1, ctx ?? {});
|
|
674
718
|
const searchRel = cwd ?? "";
|
|
675
719
|
const found = [];
|
|
676
|
-
await walkDirBackend(backend, searchRel, searchRel, regex, found);
|
|
720
|
+
await walkDirBackend(backend, searchRel, searchRel, regex, found, 0);
|
|
677
721
|
return JSON.stringify({ ok: true, files: found.sort(), count: found.length });
|
|
678
722
|
}
|
|
679
723
|
const searchRoot = cwd ? safePathJoin(projectRoot, cwd) : projectRoot;
|
|
@@ -714,7 +758,8 @@ async function walkDir(base, dir, pattern, results) {
|
|
|
714
758
|
}
|
|
715
759
|
}
|
|
716
760
|
}
|
|
717
|
-
async function walkDirBackend(backend, base, dir, pattern, results) {
|
|
761
|
+
async function walkDirBackend(backend, base, dir, pattern, results, depth) {
|
|
762
|
+
if (depth > MAX_BACKEND_WALK_DEPTH) return;
|
|
718
763
|
let names;
|
|
719
764
|
try {
|
|
720
765
|
names = await backend.list(dir);
|
|
@@ -722,10 +767,10 @@ async function walkDirBackend(backend, base, dir, pattern, results) {
|
|
|
722
767
|
return;
|
|
723
768
|
}
|
|
724
769
|
for (const name of names) {
|
|
725
|
-
await walkBackendEntry(backend, base, dir, name, pattern, results);
|
|
770
|
+
await walkBackendEntry(backend, base, dir, name, pattern, results, depth);
|
|
726
771
|
}
|
|
727
772
|
}
|
|
728
|
-
async function walkBackendEntry(backend, base, dir, name, pattern, results) {
|
|
773
|
+
async function walkBackendEntry(backend, base, dir, name, pattern, results, depth) {
|
|
729
774
|
if (DEFAULT_EXCLUDES.has(name)) return;
|
|
730
775
|
const fullRel = dir === "" ? name : `${dir}/${name}`;
|
|
731
776
|
const relPath = base === "" ? fullRel : path.relative(base, fullRel);
|
|
@@ -736,7 +781,7 @@ async function walkBackendEntry(backend, base, dir, name, pattern, results) {
|
|
|
736
781
|
return;
|
|
737
782
|
}
|
|
738
783
|
if (st.isDirectory) {
|
|
739
|
-
await walkDirBackend(backend, base, fullRel, pattern, results);
|
|
784
|
+
await walkDirBackend(backend, base, fullRel, pattern, results, depth + 1);
|
|
740
785
|
} else if (st.isFile && pattern.test(relPath)) {
|
|
741
786
|
results.push(fullRel);
|
|
742
787
|
}
|
|
@@ -1808,6 +1853,7 @@ var DEFAULT_MAX_MATCHES = 100;
|
|
|
1808
1853
|
var DEFAULT_MAX_FILE_SIZE = 1024 * 1024;
|
|
1809
1854
|
var BINARY_PROBE_BYTES2 = 8 * 1024;
|
|
1810
1855
|
var PREVIEW_MAX = 200;
|
|
1856
|
+
var MAX_BACKEND_WALK_DEPTH2 = 64;
|
|
1811
1857
|
function createSearchTextTool(opts) {
|
|
1812
1858
|
const {
|
|
1813
1859
|
projectRoot,
|
|
@@ -1836,7 +1882,7 @@ function createSearchTextTool(opts) {
|
|
|
1836
1882
|
const scopeRel = resolveScopeRel(path, projectRoot);
|
|
1837
1883
|
if ("error" in scopeRel) return scopeRel.error;
|
|
1838
1884
|
const backend = await filesystem.resolveFilesystem(filesystem$1, ctx ?? {});
|
|
1839
|
-
await walkBackend(backend, scopeRel.rel, state);
|
|
1885
|
+
await walkBackend(backend, scopeRel.rel, state, 0);
|
|
1840
1886
|
return JSON.stringify({
|
|
1841
1887
|
ok: true,
|
|
1842
1888
|
matches: state.matches,
|
|
@@ -1946,8 +1992,9 @@ function resolveScopeRel(path, projectRoot) {
|
|
|
1946
1992
|
throw err;
|
|
1947
1993
|
}
|
|
1948
1994
|
}
|
|
1949
|
-
async function walkBackend(backend, dirRel, state) {
|
|
1995
|
+
async function walkBackend(backend, dirRel, state, depth) {
|
|
1950
1996
|
if (state.truncated) return;
|
|
1997
|
+
if (depth > MAX_BACKEND_WALK_DEPTH2) return;
|
|
1951
1998
|
let names;
|
|
1952
1999
|
try {
|
|
1953
2000
|
names = await backend.list(dirRel);
|
|
@@ -1956,10 +2003,10 @@ async function walkBackend(backend, dirRel, state) {
|
|
|
1956
2003
|
}
|
|
1957
2004
|
for (const name of names) {
|
|
1958
2005
|
if (state.truncated) return;
|
|
1959
|
-
await handleBackendEntry(backend, dirRel, name, state);
|
|
2006
|
+
await handleBackendEntry(backend, dirRel, name, state, depth);
|
|
1960
2007
|
}
|
|
1961
2008
|
}
|
|
1962
|
-
async function handleBackendEntry(backend, dirRel, name, state) {
|
|
2009
|
+
async function handleBackendEntry(backend, dirRel, name, state, depth) {
|
|
1963
2010
|
const entryRel = dirRel === "" ? name : `${dirRel}/${name}`;
|
|
1964
2011
|
if (isForbiddenPath(entryRel)) return;
|
|
1965
2012
|
let st;
|
|
@@ -1969,7 +2016,7 @@ async function handleBackendEntry(backend, dirRel, name, state) {
|
|
|
1969
2016
|
return;
|
|
1970
2017
|
}
|
|
1971
2018
|
if (st.isDirectory) {
|
|
1972
|
-
await walkBackend(backend, entryRel, state);
|
|
2019
|
+
await walkBackend(backend, entryRel, state, depth + 1);
|
|
1973
2020
|
} else if (st.isFile) {
|
|
1974
2021
|
await scanFileBackend(backend, entryRel, st.size, state);
|
|
1975
2022
|
}
|
|
@@ -2565,6 +2612,7 @@ exports.catastrophicShellReason = catastrophicShellReason;
|
|
|
2565
2612
|
exports.commandDenialReason = commandDenialReason;
|
|
2566
2613
|
exports.createApplyPatchTool = createApplyPatchTool;
|
|
2567
2614
|
exports.createBraveWebSearchAdapter = createBraveWebSearchAdapter;
|
|
2615
|
+
exports.createCurrentTimeTool = createCurrentTimeTool;
|
|
2568
2616
|
exports.createEditFileTool = createEditFileTool;
|
|
2569
2617
|
exports.createGenericHttpSearchAdapter = createGenericHttpSearchAdapter;
|
|
2570
2618
|
exports.createGitDiffTool = createGitDiffTool;
|