tsci-agent 0.1.0 → 0.1.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/README.md +21 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +50 -28
- package/dist/diagnostics.d.ts +4 -0
- package/dist/do-command.d.ts +21 -0
- package/dist/interactive.d.ts +1 -0
- package/dist/lib.d.ts +41 -0
- package/dist/lib.js +280061 -0
- package/dist/model.d.ts +2 -0
- package/dist/paths.d.ts +5 -0
- package/dist/pi-sdk-options.d.ts +21 -0
- package/dist/render-events.d.ts +2 -0
- package/dist/usage.d.ts +1 -0
- package/package.json +8 -2
package/README.md
CHANGED
|
@@ -38,6 +38,27 @@ tsci-agent do --prompt "Try this refactor" --dir ./somedir --sandbox
|
|
|
38
38
|
|
|
39
39
|
`--sandbox` protects the original directory from ordinary writes by using a copy, but it is not a security boundary or container.
|
|
40
40
|
|
|
41
|
+
## Library usage
|
|
42
|
+
|
|
43
|
+
You can also run the agent from another Bun/TypeScript program and inspect the sandbox after the prompt completes:
|
|
44
|
+
|
|
45
|
+
```ts
|
|
46
|
+
import { runPromptInSandbox } from "tsci-agent/lib";
|
|
47
|
+
|
|
48
|
+
await using result = await runPromptInSandbox("Review this tscircuit project", {
|
|
49
|
+
dir: "./somedir",
|
|
50
|
+
// Optional Pi SDK CLI-style args:
|
|
51
|
+
// piArgs: ["--model", "openai/gpt-4.1"],
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
console.log(result.output);
|
|
55
|
+
console.log(await result.files.ls());
|
|
56
|
+
console.log(await result.files.read("index.circuit.tsx"));
|
|
57
|
+
console.log(result.sandboxDir);
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
`runPromptInSandbox` copies `dir` to a temporary workspace, runs the prompt there, and returns `output`, `sandboxDir`, `originalDir`, `sessionId`, and `files` helpers scoped to the sandbox. Use `await using` as shown, or call `await result.dispose()`, to remove the temporary sandbox when you are done reading it. Like CLI `--sandbox`, this is a temporary filesystem copy, not a security boundary.
|
|
61
|
+
|
|
41
62
|
## Build
|
|
42
63
|
|
|
43
64
|
```bash
|
package/dist/cli.d.ts
ADDED
package/dist/cli.js
CHANGED
|
@@ -244812,7 +244812,7 @@ function applyExifOrientation(photon, image, originalBytes) {
|
|
|
244812
244812
|
|
|
244813
244813
|
// node_modules/@silvia-odwyer/photon-node/photon_rs.js
|
|
244814
244814
|
var require_photon_rs = __commonJS((exports, module3) => {
|
|
244815
|
-
var __dirname = "/
|
|
244815
|
+
var __dirname = "/home/runner/work/tsci-agent/tsci-agent/node_modules/@silvia-odwyer/photon-node";
|
|
244816
244816
|
var imports = {};
|
|
244817
244817
|
imports["__wbindgen_placeholder__"] = exports;
|
|
244818
244818
|
var wasm;
|
|
@@ -279831,11 +279831,13 @@ function renderEvent(event2) {
|
|
|
279831
279831
|
// src/do-command.ts
|
|
279832
279832
|
var exports_do_command = {};
|
|
279833
279833
|
__export(exports_do_command, {
|
|
279834
|
-
runDoCommand: () => runDoCommand
|
|
279834
|
+
runDoCommand: () => runDoCommand,
|
|
279835
|
+
runAgentPrompt: () => runAgentPrompt,
|
|
279836
|
+
prepareWorkingDirectory: () => prepareWorkingDirectory
|
|
279835
279837
|
});
|
|
279836
279838
|
import { cp, mkdtemp, realpath as realpath3 } from "fs/promises";
|
|
279837
279839
|
import { tmpdir as tmpdir6 } from "os";
|
|
279838
|
-
import { join as join37, resolve as resolve17 } from "path";
|
|
279840
|
+
import { join as join37, relative as relative9, resolve as resolve17 } from "path";
|
|
279839
279841
|
function readValue(args, index2, option) {
|
|
279840
279842
|
const value2 = args[index2 + 1];
|
|
279841
279843
|
if (!value2 || value2.startsWith("--")) {
|
|
@@ -279888,32 +279890,33 @@ function parseDoCommand(args) {
|
|
|
279888
279890
|
}
|
|
279889
279891
|
return options3;
|
|
279890
279892
|
}
|
|
279891
|
-
async function prepareWorkingDirectory(dir, sandbox) {
|
|
279893
|
+
async function prepareWorkingDirectory(dir, sandbox, report = false) {
|
|
279892
279894
|
const sourceDir = await realpath3(resolve17(dir));
|
|
279893
279895
|
if (!sandbox)
|
|
279894
|
-
return sourceDir;
|
|
279896
|
+
return { cwd: sourceDir, sourceDir };
|
|
279895
279897
|
const sandboxRoot = await mkdtemp(join37(tmpdir6(), "tsci-agent-"));
|
|
279896
279898
|
const sandboxDir = join37(sandboxRoot, "workspace");
|
|
279897
279899
|
await cp(sourceDir, sandboxDir, {
|
|
279898
279900
|
recursive: true,
|
|
279899
|
-
filter: (path16) => !path16.includes("
|
|
279901
|
+
filter: (path16) => !relative9(sourceDir, path16).split(/[\\/]/).includes(".git")
|
|
279900
279902
|
});
|
|
279901
|
-
|
|
279902
|
-
|
|
279903
|
-
|
|
279903
|
+
if (report) {
|
|
279904
|
+
console.error(`[tsci-agent] sandbox copy: ${sourceDir} -> ${sandboxDir}`);
|
|
279905
|
+
console.error("[tsci-agent] sandbox is a temporary filesystem copy, not a security boundary.");
|
|
279906
|
+
}
|
|
279907
|
+
return { cwd: sandboxDir, sourceDir, sandboxRoot };
|
|
279904
279908
|
}
|
|
279905
|
-
async function
|
|
279906
|
-
const
|
|
279907
|
-
const prompt = options3.prompt;
|
|
279908
|
-
if (!prompt)
|
|
279909
|
-
throw new Error("`tsci-agent do` requires --prompt <text>.");
|
|
279910
|
-
const cwd = await prepareWorkingDirectory(options3.dir, options3.sandbox);
|
|
279909
|
+
async function runAgentPrompt(options3) {
|
|
279910
|
+
const { cwd } = await prepareWorkingDirectory(options3.dir, options3.sandbox ?? false, options3.report ?? false);
|
|
279911
279911
|
const skillPath = await findTscircuitSkill();
|
|
279912
|
-
const parsed = parseArgs(options3.piArgs);
|
|
279913
|
-
|
|
279912
|
+
const parsed = parseArgs(options3.piArgs ?? []);
|
|
279913
|
+
if (options3.report)
|
|
279914
|
+
reportDiagnostics2(parsed.diagnostics);
|
|
279914
279915
|
const fatalDiagnostics = parsed.diagnostics.filter((diagnostic) => diagnostic.type === "error");
|
|
279915
|
-
if (fatalDiagnostics.length > 0)
|
|
279916
|
-
|
|
279916
|
+
if (fatalDiagnostics.length > 0) {
|
|
279917
|
+
throw new Error(fatalDiagnostics.map((diagnostic) => diagnostic.message).join(`
|
|
279918
|
+
`));
|
|
279919
|
+
}
|
|
279917
279920
|
const agentDir = getAgentDir();
|
|
279918
279921
|
const authStorage = createAuthStorage(parsed);
|
|
279919
279922
|
const modelRegistry = ModelRegistry.create(authStorage);
|
|
@@ -279937,22 +279940,41 @@ async function runDoCommand(args) {
|
|
|
279937
279940
|
model,
|
|
279938
279941
|
...createSessionOptionOverrides(parsed)
|
|
279939
279942
|
});
|
|
279940
|
-
if (
|
|
279941
|
-
|
|
279942
|
-
|
|
279943
|
-
|
|
279944
|
-
|
|
279943
|
+
if (options3.report) {
|
|
279944
|
+
if (modelFallbackMessage)
|
|
279945
|
+
console.error(`[warning] ${modelFallbackMessage}`);
|
|
279946
|
+
reportDiagnostics2(loader.getSkills().diagnostics);
|
|
279947
|
+
for (const error54 of extensionsResult.errors) {
|
|
279948
|
+
console.error(`[warning] extension ${error54.path}: ${error54.error}`);
|
|
279949
|
+
}
|
|
279945
279950
|
}
|
|
279946
279951
|
await session2.bindExtensions({});
|
|
279947
|
-
const
|
|
279952
|
+
const subscriptions = [options3.onEvent ? session2.subscribe(options3.onEvent) : undefined];
|
|
279948
279953
|
try {
|
|
279949
|
-
|
|
279950
|
-
|
|
279954
|
+
if (options3.report)
|
|
279955
|
+
console.error(`[session] ${session2.sessionId} cwd=${cwd}`);
|
|
279956
|
+
await session2.prompt(options3.prompt, { expandPromptTemplates: true });
|
|
279957
|
+
return { cwd, sessionId: session2.sessionId };
|
|
279951
279958
|
} finally {
|
|
279952
|
-
unsubscribe
|
|
279959
|
+
for (const unsubscribe of subscriptions)
|
|
279960
|
+
unsubscribe?.();
|
|
279953
279961
|
session2.dispose();
|
|
279954
279962
|
}
|
|
279955
279963
|
}
|
|
279964
|
+
async function runDoCommand(args) {
|
|
279965
|
+
const options3 = parseDoCommand(args);
|
|
279966
|
+
const prompt = options3.prompt;
|
|
279967
|
+
if (!prompt)
|
|
279968
|
+
throw new Error("`tsci-agent do` requires --prompt <text>.");
|
|
279969
|
+
await runAgentPrompt({
|
|
279970
|
+
prompt,
|
|
279971
|
+
dir: options3.dir,
|
|
279972
|
+
sandbox: options3.sandbox,
|
|
279973
|
+
piArgs: options3.piArgs,
|
|
279974
|
+
report: true,
|
|
279975
|
+
onEvent: renderEvent
|
|
279976
|
+
});
|
|
279977
|
+
}
|
|
279956
279978
|
var init_do_command = __esm(() => {
|
|
279957
279979
|
init_dist5();
|
|
279958
279980
|
init_paths();
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { type AgentSessionEvent } from "@earendil-works/pi-coding-agent";
|
|
2
|
+
export interface PreparedWorkingDirectory {
|
|
3
|
+
cwd: string;
|
|
4
|
+
sourceDir: string;
|
|
5
|
+
sandboxRoot?: string;
|
|
6
|
+
}
|
|
7
|
+
export interface AgentPromptResult {
|
|
8
|
+
cwd: string;
|
|
9
|
+
sessionId: string;
|
|
10
|
+
}
|
|
11
|
+
export interface AgentPromptOptions {
|
|
12
|
+
prompt: string;
|
|
13
|
+
dir: string;
|
|
14
|
+
sandbox?: boolean;
|
|
15
|
+
piArgs?: string[];
|
|
16
|
+
report?: boolean;
|
|
17
|
+
onEvent?: (event: AgentSessionEvent) => void;
|
|
18
|
+
}
|
|
19
|
+
export declare function prepareWorkingDirectory(dir: string, sandbox: boolean, report?: boolean): Promise<PreparedWorkingDirectory>;
|
|
20
|
+
export declare function runAgentPrompt(options: AgentPromptOptions): Promise<AgentPromptResult>;
|
|
21
|
+
export declare function runDoCommand(args: string[]): Promise<void>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function runInteractive(args: string[]): Promise<void>;
|
package/dist/lib.d.ts
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { AgentSessionEvent } from "@earendil-works/pi-coding-agent";
|
|
2
|
+
export interface SandboxFiles {
|
|
3
|
+
/** Return an absolute path inside the sandbox workspace. */
|
|
4
|
+
path(path: string): string;
|
|
5
|
+
/** List a directory inside the sandbox workspace. */
|
|
6
|
+
ls(path?: string): Promise<string[]>;
|
|
7
|
+
/** Read a UTF-8 file inside the sandbox workspace. */
|
|
8
|
+
read(path: string): Promise<string>;
|
|
9
|
+
/** Write a UTF-8 file inside the sandbox workspace, creating parent directories. */
|
|
10
|
+
write(path: string, content: string): Promise<void>;
|
|
11
|
+
}
|
|
12
|
+
export interface RunPromptInSandboxOptions {
|
|
13
|
+
/** Directory to copy into the sandbox. Defaults to process.cwd(). */
|
|
14
|
+
dir?: string;
|
|
15
|
+
/** Additional Pi SDK CLI-style args, for example ["--model", "openai/gpt-4.1"]. */
|
|
16
|
+
piArgs?: string[];
|
|
17
|
+
/** Observe raw Pi SDK session events while the prompt runs. */
|
|
18
|
+
onEvent?: (event: AgentSessionEvent) => void;
|
|
19
|
+
}
|
|
20
|
+
export interface SandboxPromptResult extends AsyncDisposable {
|
|
21
|
+
/** Assistant text emitted by the run. */
|
|
22
|
+
output: string;
|
|
23
|
+
/** Original directory copied into the sandbox. */
|
|
24
|
+
originalDir: string;
|
|
25
|
+
/** Temporary workspace directory where the prompt ran. */
|
|
26
|
+
sandboxDir: string;
|
|
27
|
+
/** Pi SDK session id used for the run. */
|
|
28
|
+
sessionId: string;
|
|
29
|
+
/** Convenience helpers scoped to sandboxDir. */
|
|
30
|
+
files: SandboxFiles;
|
|
31
|
+
/** Remove the temporary sandbox directory. Safe to call more than once. */
|
|
32
|
+
dispose(): Promise<void>;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Run a prompt against a temporary copy of a workspace and return helpers for
|
|
36
|
+
* inspecting that sandbox after the agent finishes.
|
|
37
|
+
*
|
|
38
|
+
* The sandbox is a filesystem copy, not a security boundary. Call dispose(), or
|
|
39
|
+
* use `await using`, to remove the temporary files when you are done reading them.
|
|
40
|
+
*/
|
|
41
|
+
export declare function runPromptInSandbox(prompt: string, options?: RunPromptInSandboxOptions): Promise<SandboxPromptResult>;
|