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 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
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env bun
2
+ export {};
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 = "/Users/seve/w/tsc/tsci-agent/node_modules/@silvia-odwyer/photon-node";
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("/.git/")
279901
+ filter: (path16) => !relative9(sourceDir, path16).split(/[\\/]/).includes(".git")
279900
279902
  });
279901
- console.error(`[tsci-agent] sandbox copy: ${sourceDir} -> ${sandboxDir}`);
279902
- console.error("[tsci-agent] sandbox is a temporary filesystem copy, not a security boundary.");
279903
- return sandboxDir;
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 runDoCommand(args) {
279906
- const options3 = parseDoCommand(args);
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
- reportDiagnostics2(parsed.diagnostics);
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
- process.exit(1);
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 (modelFallbackMessage)
279941
- console.error(`[warning] ${modelFallbackMessage}`);
279942
- reportDiagnostics2(loader.getSkills().diagnostics);
279943
- for (const error54 of extensionsResult.errors) {
279944
- console.error(`[warning] extension ${error54.path}: ${error54.error}`);
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 unsubscribe = session2.subscribe(renderEvent);
279952
+ const subscriptions = [options3.onEvent ? session2.subscribe(options3.onEvent) : undefined];
279948
279953
  try {
279949
- console.error(`[session] ${session2.sessionId} cwd=${cwd}`);
279950
- await session2.prompt(prompt, { expandPromptTemplates: true });
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,4 @@
1
+ export declare function reportDiagnostics(diagnostics: Array<{
2
+ type: string;
3
+ message: string;
4
+ }>): void;
@@ -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>;