@opentag/runner 0.1.0 → 0.2.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Amplift
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,11 @@
1
+ import { type CommandRunner } from "./command.js";
2
+ import { type ExecutorAdapter } from "./executor.js";
3
+ export type ClaudeCodeExecutorOptions = {
4
+ runner?: CommandRunner;
5
+ claudeCommand?: string;
6
+ model?: string;
7
+ permissionMode?: "acceptEdits" | "auto" | "bypassPermissions" | "default" | "plan";
8
+ dangerouslySkipPermissions?: boolean;
9
+ };
10
+ export declare function createClaudeCodeExecutor(options?: ClaudeCodeExecutorOptions): ExecutorAdapter;
11
+ //# sourceMappingURL=claude-code.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claude-code.d.ts","sourceRoot":"","sources":["../src/claude-code.ts"],"names":[],"mappings":"AACA,OAAO,EAA6C,KAAK,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7F,OAAO,EAAgC,KAAK,eAAe,EAAE,MAAM,eAAe,CAAC;AAInF,MAAM,MAAM,yBAAyB,GAAG;IACtC,MAAM,CAAC,EAAE,aAAa,CAAC;IACvB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,cAAc,CAAC,EAAE,aAAa,GAAG,MAAM,GAAG,mBAAmB,GAAG,SAAS,GAAG,MAAM,CAAC;IACnF,0BAA0B,CAAC,EAAE,OAAO,CAAC;CACtC,CAAC;AA8BF,wBAAgB,wBAAwB,CAAC,OAAO,GAAE,yBAA8B,GAAG,eAAe,CAiGjG"}
package/dist/codex.d.ts CHANGED
@@ -1,9 +1,11 @@
1
1
  import { type CommandRunner } from "./command.js";
2
- import type { ExecutorAdapter } from "./executor.js";
2
+ import { type ExecutorAdapter } from "./executor.js";
3
+ import { type RunnerSecurityPolicy } from "./security.js";
3
4
  export type CodexExecutorOptions = {
4
5
  runner?: CommandRunner;
5
6
  codexCommand?: string;
6
7
  model?: string;
8
+ security?: RunnerSecurityPolicy;
7
9
  };
8
10
  export declare function createCodexExecutor(options?: CodexExecutorOptions): ExecutorAdapter;
9
11
  //# sourceMappingURL=codex.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"codex.d.ts","sourceRoot":"","sources":["../src/codex.ts"],"names":[],"mappings":"AACA,OAAO,EAA6C,KAAK,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7F,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAGrD,MAAM,MAAM,oBAAoB,GAAG;IACjC,MAAM,CAAC,EAAE,aAAa,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AA0BF,wBAAgB,mBAAmB,CAAC,OAAO,GAAE,oBAAyB,GAAG,eAAe,CA2FvF"}
1
+ {"version":3,"file":"codex.d.ts","sourceRoot":"","sources":["../src/codex.ts"],"names":[],"mappings":"AACA,OAAO,EAA6C,KAAK,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7F,OAAO,EAAgC,KAAK,eAAe,EAAE,MAAM,eAAe,CAAC;AAYnF,OAAO,EAAoE,KAAK,oBAAoB,EAAE,MAAM,eAAe,CAAC;AAE5H,MAAM,MAAM,oBAAoB,GAAG;IACjC,MAAM,CAAC,EAAE,aAAa,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,oBAAoB,CAAC;CACjC,CAAC;AA6BF,wBAAgB,mBAAmB,CAAC,OAAO,GAAE,oBAAyB,GAAG,eAAe,CAsKvF"}
package/dist/command.d.ts CHANGED
@@ -3,10 +3,12 @@ export type CommandResult = {
3
3
  stdout: string;
4
4
  stderr: string;
5
5
  };
6
+ export type CommandEnvironment = Record<string, string | undefined>;
6
7
  export type CommandRunner = {
7
8
  run(command: string, args: string[], options?: {
8
9
  cwd?: string;
9
10
  input?: string;
11
+ env?: CommandEnvironment;
10
12
  }): Promise<CommandResult>;
11
13
  };
12
14
  export declare const nodeCommandRunner: CommandRunner;
@@ -1 +1 @@
1
- {"version":3,"file":"command.d.ts","sourceRoot":"","sources":["../src/command.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,aAAa,GAAG;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,OAAO,CAAC,EAAE;QAAE,GAAG,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;CAC1G,CAAC;AAEF,eAAO,MAAM,iBAAiB,EAAE,aA2B/B,CAAC;AAEF,wBAAsB,sBAAsB,CAAC,MAAM,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAIhG"}
1
+ {"version":3,"file":"command.d.ts","sourceRoot":"","sources":["../src/command.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,aAAa,GAAG;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;AAEpE,MAAM,MAAM,aAAa,GAAG;IAC1B,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,OAAO,CAAC,EAAE;QAAE,GAAG,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,GAAG,CAAC,EAAE,kBAAkB,CAAA;KAAE,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;CACpI,CAAC;AAEF,eAAO,MAAM,iBAAiB,EAAE,aA4B/B,CAAC;AAEF,wBAAsB,sBAAsB,CAAC,MAAM,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAIhG"}
@@ -1 +1 @@
1
- {"version":3,"file":"echo.d.ts","sourceRoot":"","sources":["../src/echo.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAMrD,wBAAgB,kBAAkB,IAAI,eAAe,CAkCpD"}
1
+ {"version":3,"file":"echo.d.ts","sourceRoot":"","sources":["../src/echo.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAMrD,wBAAgB,kBAAkB,IAAI,eAAe,CAsCpD"}
@@ -1,4 +1,4 @@
1
- import type { ContextPointer, OpenTagCommand, OpenTagRunResult } from "@opentag/core";
1
+ import { type ContextPacket, type ContextPointer, type OpenTagCommand, type OpenTagRunResult, type PermissionGrant } from "@opentag/core";
2
2
  export type ExecutorEvent = {
3
3
  type: "executor.started" | "executor.progress" | "executor.completed" | "executor.failed";
4
4
  message: string;
@@ -12,7 +12,13 @@ export type ExecutorRunInput = {
12
12
  workspacePath: string;
13
13
  command: OpenTagCommand;
14
14
  context: ContextPointer[];
15
+ contextPacket?: ContextPacket;
16
+ permissions?: PermissionGrant[];
17
+ baseBranch?: string;
18
+ worktreeRoot?: string;
19
+ keepWorktree?: "always" | "on_failure" | "never";
15
20
  };
21
+ export declare function renderContextPacketForPrompt(packet?: ContextPacket): string[];
16
22
  export type ExecutorReadiness = {
17
23
  ready: boolean;
18
24
  reason?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"executor.d.ts","sourceRoot":"","sources":["../src/executor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAEtF,MAAM,MAAM,aAAa,GAAG;IAC1B,IAAI,EAAE,kBAAkB,GAAG,mBAAmB,GAAG,oBAAoB,GAAG,iBAAiB,CAAC;IAC1F,OAAO,EAAE,MAAM,CAAC;IAChB,EAAE,EAAE,MAAM,CAAC;CACZ,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,IAAI,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3C,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,cAAc,CAAC;IACxB,OAAO,EAAE,cAAc,EAAE,CAAC;CAC3B,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAC;IAC5D,GAAG,CAAC,KAAK,EAAE,gBAAgB,EAAE,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAAC;IACjF,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACtC,CAAC"}
1
+ {"version":3,"file":"executor.d.ts","sourceRoot":"","sources":["../src/executor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAuB,KAAK,aAAa,EAAE,KAAK,cAAc,EAAE,KAAK,cAAc,EAAE,KAAK,gBAAgB,EAAE,KAAK,eAAe,EAAE,MAAM,eAAe,CAAC;AAE/J,MAAM,MAAM,aAAa,GAAG;IAC1B,IAAI,EAAE,kBAAkB,GAAG,mBAAmB,GAAG,oBAAoB,GAAG,iBAAiB,CAAC;IAC1F,OAAO,EAAE,MAAM,CAAC;IAChB,EAAE,EAAE,MAAM,CAAC;CACZ,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,IAAI,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3C,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,cAAc,CAAC;IACxB,OAAO,EAAE,cAAc,EAAE,CAAC;IAC1B,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,WAAW,CAAC,EAAE,eAAe,EAAE,CAAC;IAChC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,QAAQ,GAAG,YAAY,GAAG,OAAO,CAAC;CAClD,CAAC;AAEF,wBAAgB,4BAA4B,CAAC,MAAM,CAAC,EAAE,aAAa,GAAG,MAAM,EAAE,CAiC7E;AAED,MAAM,MAAM,iBAAiB,GAAG;IAC9B,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAC;IAC5D,GAAG,CAAC,KAAK,EAAE,gBAAgB,EAAE,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAAC;IACjF,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACtC,CAAC"}
package/dist/git.d.ts CHANGED
@@ -11,6 +11,29 @@ export declare function createRunBranch(input: {
11
11
  runner: CommandRunner;
12
12
  workspacePath: string;
13
13
  branchName: string;
14
+ startPoint?: string;
15
+ }): Promise<void>;
16
+ export declare function worktreePathForRun(input: {
17
+ workspacePath: string;
18
+ runId: string;
19
+ worktreeRoot?: string;
20
+ }): string;
21
+ export declare function createRunWorktree(input: {
22
+ runner: CommandRunner;
23
+ workspacePath: string;
24
+ worktreePath: string;
25
+ branchName: string;
26
+ baseBranch: string;
27
+ }): Promise<void>;
28
+ export declare function removeRunWorktree(input: {
29
+ runner: CommandRunner;
30
+ workspacePath: string;
31
+ worktreePath: string;
32
+ }): Promise<void>;
33
+ export declare function deleteRunBranch(input: {
34
+ runner: CommandRunner;
35
+ workspacePath: string;
36
+ branchName: string;
14
37
  }): Promise<void>;
15
38
  export declare function changedFiles(input: {
16
39
  runner: CommandRunner;
@@ -20,6 +43,17 @@ export declare function cleanupInternalArtifacts(input: {
20
43
  runner: CommandRunner;
21
44
  workspacePath: string;
22
45
  }): Promise<string[]>;
46
+ export declare function commitRunChanges(input: {
47
+ runner: CommandRunner;
48
+ workspacePath: string;
49
+ message: string;
50
+ }): Promise<boolean>;
51
+ export declare function commitChangedFiles(input: {
52
+ runner: CommandRunner;
53
+ workspacePath: string;
54
+ files: string[];
55
+ message: string;
56
+ }): Promise<void>;
23
57
  export declare function pushBranch(input: {
24
58
  runner: CommandRunner;
25
59
  workspacePath: string;
package/dist/git.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"git.d.ts","sourceRoot":"","sources":["../src/git.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAGlD,MAAM,MAAM,cAAc,GAAG;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAIF,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAGtD;AAED,wBAAgB,kBAAkB,CAAC,YAAY,EAAE,MAAM,GAAG,cAAc,EAAE,CAUzE;AAED,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAE5D;AAED,wBAAgB,iBAAiB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,EAAE,CAIhE;AAED,wBAAsB,eAAe,CAAC,KAAK,EAAE;IAC3C,MAAM,EAAE,aAAa,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;CACpB,GAAG,OAAO,CAAC,IAAI,CAAC,CAGhB;AAED,wBAAsB,YAAY,CAAC,KAAK,EAAE;IAAE,MAAM,EAAE,aAAa,CAAC;IAAC,aAAa,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAI7G;AAED,wBAAsB,wBAAwB,CAAC,KAAK,EAAE;IAAE,MAAM,EAAE,aAAa,CAAC;IAAC,aAAa,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAiBzH;AAED,wBAAsB,UAAU,CAAC,KAAK,EAAE;IACtC,MAAM,EAAE,aAAa,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;CACpB,GAAG,OAAO,CAAC,IAAI,CAAC,CAGhB"}
1
+ {"version":3,"file":"git.d.ts","sourceRoot":"","sources":["../src/git.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAGlD,MAAM,MAAM,cAAc,GAAG;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAIF,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAGtD;AAED,wBAAgB,kBAAkB,CAAC,YAAY,EAAE,MAAM,GAAG,cAAc,EAAE,CAUzE;AAED,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAE5D;AAED,wBAAgB,iBAAiB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,EAAE,CAIhE;AAED,wBAAsB,eAAe,CAAC,KAAK,EAAE;IAC3C,MAAM,EAAE,aAAa,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,GAAG,OAAO,CAAC,IAAI,CAAC,CAGhB;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE;IACxC,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,GAAG,MAAM,CAIT;AAED,wBAAsB,iBAAiB,CAAC,KAAK,EAAE;IAC7C,MAAM,EAAE,aAAa,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB,GAAG,OAAO,CAAC,IAAI,CAAC,CAQhB;AAED,wBAAsB,iBAAiB,CAAC,KAAK,EAAE;IAC7C,MAAM,EAAE,aAAa,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;CACtB,GAAG,OAAO,CAAC,IAAI,CAAC,CAKhB;AAED,wBAAsB,eAAe,CAAC,KAAK,EAAE;IAAE,MAAM,EAAE,aAAa,CAAC;IAAC,aAAa,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAKhI;AAED,wBAAsB,YAAY,CAAC,KAAK,EAAE;IAAE,MAAM,EAAE,aAAa,CAAC;IAAC,aAAa,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAI7G;AAED,wBAAsB,wBAAwB,CAAC,KAAK,EAAE;IAAE,MAAM,EAAE,aAAa,CAAC;IAAC,aAAa,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAiBzH;AAED,wBAAsB,gBAAgB,CAAC,KAAK,EAAE;IAC5C,MAAM,EAAE,aAAa,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;CACjB,GAAG,OAAO,CAAC,OAAO,CAAC,CAcnB;AAED,wBAAsB,kBAAkB,CAAC,KAAK,EAAE;IAC9C,MAAM,EAAE,aAAa,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CACjB,GAAG,OAAO,CAAC,IAAI,CAAC,CAMhB;AAED,wBAAsB,UAAU,CAAC,KAAK,EAAE;IACtC,MAAM,EAAE,aAAa,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;CACpB,GAAG,OAAO,CAAC,IAAI,CAAC,CAGhB"}
package/dist/index.d.ts CHANGED
@@ -1,6 +1,9 @@
1
+ export * from "./claude-code.js";
1
2
  export * from "./codex.js";
2
3
  export * from "./command.js";
3
4
  export * from "./echo.js";
4
5
  export * from "./executor.js";
5
6
  export * from "./git.js";
7
+ export * from "./result.js";
8
+ export * from "./security.js";
6
9
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,cAAc,CAAC;AAC7B,cAAc,WAAW,CAAC;AAC1B,cAAc,eAAe,CAAC;AAC9B,cAAc,UAAU,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAC;AACjC,cAAc,YAAY,CAAC;AAC3B,cAAc,cAAc,CAAC;AAC7B,cAAc,WAAW,CAAC;AAC1B,cAAc,eAAe,CAAC;AAC9B,cAAc,UAAU,CAAC;AACzB,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC"}
package/dist/index.js CHANGED
@@ -1,10 +1,14 @@
1
+ // src/claude-code.ts
2
+ import { contextPointerLabel as contextPointerLabel2 } from "@opentag/core";
3
+
1
4
  // src/command.ts
2
5
  import { spawn } from "child_process";
3
6
  var nodeCommandRunner = {
4
7
  run(command, args, options = {}) {
5
- return new Promise((resolve, reject) => {
8
+ return new Promise((resolve2, reject) => {
6
9
  const child = spawn(command, args, {
7
10
  cwd: options.cwd,
11
+ env: options.env,
8
12
  stdio: ["pipe", "pipe", "pipe"]
9
13
  });
10
14
  const stdout = [];
@@ -13,7 +17,7 @@ var nodeCommandRunner = {
13
17
  child.stderr.on("data", (chunk) => stderr.push(chunk));
14
18
  child.on("error", reject);
15
19
  child.on("close", (exitCode) => {
16
- resolve({
20
+ resolve2({
17
21
  exitCode: exitCode ?? 1,
18
22
  stdout: Buffer.concat(stdout).toString("utf8"),
19
23
  stderr: Buffer.concat(stderr).toString("utf8")
@@ -32,7 +36,40 @@ async function assertCommandSucceeded(result, label) {
32
36
  }
33
37
  }
34
38
 
39
+ // src/executor.ts
40
+ import { contextPointerLabel } from "@opentag/core";
41
+ function renderContextPacketForPrompt(packet) {
42
+ if (!packet) return [];
43
+ const lines = ["OpenTag context packet:", `- summary: ${packet.summary}`];
44
+ if (packet.intent) {
45
+ lines.push(`- intent: ${packet.intent.normalizedIntent}`);
46
+ lines.push(`- requested by: ${packet.intent.requestedBy.provider}:${packet.intent.requestedBy.providerUserId}`);
47
+ }
48
+ if (packet.sources?.length) {
49
+ lines.push("- selected sources:");
50
+ for (const source of packet.sources) {
51
+ lines.push(` - [${source.role}] ${contextPointerLabel(source.pointer)}: ${source.pointer.uri}`);
52
+ lines.push(` reason: ${source.reason}`);
53
+ }
54
+ }
55
+ if (packet.facts?.length) {
56
+ lines.push("- facts:");
57
+ for (const fact of packet.facts) {
58
+ lines.push(` - ${fact.text}`);
59
+ }
60
+ }
61
+ if (packet.exclusions?.length) {
62
+ lines.push("- exclusions:");
63
+ for (const exclusion of packet.exclusions) {
64
+ lines.push(` - ${exclusion}`);
65
+ }
66
+ }
67
+ return lines;
68
+ }
69
+
35
70
  // src/git.ts
71
+ import { mkdirSync } from "fs";
72
+ import { dirname } from "path";
36
73
  var INTERNAL_ARTIFACT_ROOTS = [".omx", ".codex", ".claude"];
37
74
  function branchNameForRun(runId) {
38
75
  const safeRunId = runId.replace(/[^a-zA-Z0-9._-]/g, "-");
@@ -51,9 +88,35 @@ function parseChangedFiles(statusOutput) {
51
88
  return parseStatusEntries(statusOutput).map((entry) => entry.path).filter((path) => !isInternalArtifactPath(path));
52
89
  }
53
90
  async function createRunBranch(input) {
54
- const result = await input.runner.run("git", ["checkout", "-B", input.branchName], { cwd: input.workspacePath });
91
+ const result = await input.runner.run("git", ["checkout", "-B", input.branchName, ...input.startPoint ? [input.startPoint] : []], { cwd: input.workspacePath });
55
92
  await assertCommandSucceeded(result, "create run branch");
56
93
  }
94
+ function worktreePathForRun(input) {
95
+ const safeRunId = input.runId.replace(/[^a-zA-Z0-9._-]/g, "-");
96
+ const root = input.worktreeRoot ?? `${input.workspacePath.replace(/\/$/, "")}/.worktrees/opentag`;
97
+ return `${root.replace(/\/$/, "")}/${safeRunId}`;
98
+ }
99
+ async function createRunWorktree(input) {
100
+ mkdirSync(dirname(input.worktreePath), { recursive: true });
101
+ const result = await input.runner.run(
102
+ "git",
103
+ ["worktree", "add", "-B", input.branchName, input.worktreePath, input.baseBranch],
104
+ { cwd: input.workspacePath }
105
+ );
106
+ await assertCommandSucceeded(result, "create run worktree");
107
+ }
108
+ async function removeRunWorktree(input) {
109
+ const result = await input.runner.run("git", ["worktree", "remove", "--force", input.worktreePath], {
110
+ cwd: input.workspacePath
111
+ });
112
+ await assertCommandSucceeded(result, "remove run worktree");
113
+ }
114
+ async function deleteRunBranch(input) {
115
+ const result = await input.runner.run("git", ["branch", "-D", input.branchName], {
116
+ cwd: input.workspacePath
117
+ });
118
+ await assertCommandSucceeded(result, "delete empty run branch");
119
+ }
57
120
  async function changedFiles(input) {
58
121
  const result = await input.runner.run("git", ["status", "--porcelain"], { cwd: input.workspacePath });
59
122
  await assertCommandSucceeded(result, "read changed files");
@@ -74,15 +137,103 @@ async function cleanupInternalArtifacts(input) {
74
137
  await assertCommandSucceeded(cleanResult, "clean internal artifacts");
75
138
  return untrackedRoots;
76
139
  }
140
+ async function commitRunChanges(input) {
141
+ const files = await changedFiles({ runner: input.runner, workspacePath: input.workspacePath });
142
+ if (files.length === 0) return false;
143
+ const addResult = await input.runner.run("git", ["add", "--", ...files], {
144
+ cwd: input.workspacePath
145
+ });
146
+ await assertCommandSucceeded(addResult, "stage run changes");
147
+ const commitResult = await input.runner.run("git", ["commit", "-m", input.message], {
148
+ cwd: input.workspacePath
149
+ });
150
+ await assertCommandSucceeded(commitResult, "commit run changes");
151
+ return true;
152
+ }
153
+ async function commitChangedFiles(input) {
154
+ if (input.files.length === 0) return;
155
+ const addResult = await input.runner.run("git", ["add", "--", ...input.files], { cwd: input.workspacePath });
156
+ await assertCommandSucceeded(addResult, "stage changed files");
157
+ const commitResult = await input.runner.run("git", ["commit", "-m", input.message], { cwd: input.workspacePath });
158
+ await assertCommandSucceeded(commitResult, "commit changed files");
159
+ }
77
160
  async function pushBranch(input) {
78
161
  const result = await input.runner.run("git", ["push", "-u", input.remote, input.branchName], { cwd: input.workspacePath });
79
162
  await assertCommandSucceeded(result, "push run branch");
80
163
  }
81
164
 
82
- // src/codex.ts
165
+ // src/result.ts
166
+ function createExecutorRunResult(input) {
167
+ const proposalId = `proposal_${input.runId}`;
168
+ const summary = input.output.slice(-4e3);
169
+ const suggestedChanges = input.changedFiles.length > 0 ? [
170
+ {
171
+ proposalId,
172
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
173
+ sourceRunId: input.runId,
174
+ summary: `${input.executorName} changed ${input.changedFiles.length} file(s) on branch ${input.branchName}.`,
175
+ intents: [
176
+ {
177
+ intentId: `${proposalId}_create_pr`,
178
+ domain: "pull_request",
179
+ action: "create_pull_request",
180
+ summary: `Create a pull request for branch ${input.branchName}.`,
181
+ params: {
182
+ title: `OpenTag run ${input.runId}`,
183
+ body: [
184
+ "## Summary",
185
+ "",
186
+ summary
187
+ ].join("\n"),
188
+ head: input.branchName,
189
+ base: input.baseBranch ?? "main",
190
+ changedFiles: input.changedFiles,
191
+ risks: ["Creates a pull request from the executor-produced branch; review the diff before merging."],
192
+ executorConditions: ["isolated branch exists"]
193
+ }
194
+ },
195
+ {
196
+ intentId: `${proposalId}_link_branch`,
197
+ domain: "artifact_links",
198
+ action: "link_artifact",
199
+ summary: `Link the run branch ${input.branchName} to the work item.`,
200
+ params: { title: "Run branch", uri: input.branchName }
201
+ },
202
+ {
203
+ intentId: `${proposalId}_request_review`,
204
+ domain: "review",
205
+ action: "request_review",
206
+ summary: "Request human review of the generated code changes.",
207
+ params: { changedFiles: input.changedFiles }
208
+ }
209
+ ],
210
+ preconditions: ["The local branch was generated from the checkout state available to the runner."]
211
+ }
212
+ ] : void 0;
213
+ return {
214
+ conclusion: "success",
215
+ summary,
216
+ changedFiles: input.changedFiles,
217
+ artifacts: [
218
+ ...input.changedFiles.length > 0 ? [{ kind: "patch", title: "Run branch", uri: input.branchName }] : [],
219
+ ...input.extraArtifacts ?? []
220
+ ],
221
+ ...suggestedChanges ? { suggestedChanges } : {},
222
+ nextAction: input.changedFiles.length > 0 ? {
223
+ summary: "Review the proposed pull request action and reply `apply 1` if the branch should become a PR.",
224
+ hint: {
225
+ kind: "create_pull_request",
226
+ targetId: proposalId,
227
+ selectedIntentIds: [`${proposalId}_create_pr`]
228
+ }
229
+ } : "No file changes were detected."
230
+ };
231
+ }
232
+
233
+ // src/claude-code.ts
83
234
  function contextLines(context) {
84
235
  if (!context.length) return "No additional context pointers were provided.";
85
- return context.map((pointer) => `- ${pointer.kind}: ${pointer.uri}`).join("\n");
236
+ return context.map((pointer) => `- ${contextPointerLabel2(pointer)}: ${pointer.uri}`).join("\n");
86
237
  }
87
238
  function buildPrompt(input) {
88
239
  return [
@@ -92,29 +243,36 @@ function buildPrompt(input) {
92
243
  "User request:",
93
244
  input.rawText,
94
245
  "",
246
+ ...renderContextPacketForPrompt(input.contextPacket),
247
+ ...input.contextPacket ? [""] : [],
95
248
  "Context pointers:",
96
249
  contextLines(input.context),
97
250
  "",
98
- "Work autonomously but keep the change narrow. Run relevant verification if you modify files. End with a concise summary."
251
+ "Work autonomously but keep the change narrow. Run relevant verification if you modify files.",
252
+ "End with a concise summary of what changed, what was verified, and the recommended next action."
99
253
  ].join("\n");
100
254
  }
101
- function createCodexExecutor(options = {}) {
255
+ function createClaudeCodeExecutor(options = {}) {
102
256
  const runner = options.runner ?? nodeCommandRunner;
103
- const codexCommand = options.codexCommand ?? "codex";
257
+ const claudeCommand = options.claudeCommand ?? "claude";
104
258
  return {
105
- id: "codex",
106
- displayName: "Codex Executor",
259
+ id: "claude-code",
260
+ displayName: "Claude Code Executor",
107
261
  async canRun(input) {
108
- const codexVersion = await runner.run(codexCommand, ["--version"], { cwd: input.workspacePath });
109
- if (codexVersion.exitCode !== 0) {
110
- return { ready: false, reason: `Codex CLI is not available: ${codexVersion.stderr || codexVersion.stdout}` };
262
+ try {
263
+ const claudeVersion = await runner.run(claudeCommand, ["--version"], { cwd: input.workspacePath });
264
+ if (claudeVersion.exitCode !== 0) {
265
+ return { ready: false, reason: `Claude Code CLI is not available: ${claudeVersion.stderr || claudeVersion.stdout}` };
266
+ }
267
+ } catch (error) {
268
+ return { ready: false, reason: `Claude Code CLI is not available: ${error instanceof Error ? error.message : String(error)}` };
111
269
  }
112
270
  const gitStatus = await runner.run("git", ["status", "--porcelain"], { cwd: input.workspacePath });
113
271
  if (gitStatus.exitCode !== 0) {
114
272
  return { ready: false, reason: `Workspace is not a git checkout: ${gitStatus.stderr || gitStatus.stdout}` };
115
273
  }
116
274
  if (gitStatus.stdout.trim().length > 0) {
117
- return { ready: false, reason: "Workspace has uncommitted changes; refusing to run Codex executor." };
275
+ return { ready: false, reason: "Workspace has uncommitted changes; refusing to run Claude Code executor." };
118
276
  }
119
277
  return { ready: true };
120
278
  },
@@ -125,30 +283,38 @@ function createCodexExecutor(options = {}) {
125
283
  message: `Creating isolated branch ${branchName}`,
126
284
  at: (/* @__PURE__ */ new Date()).toISOString()
127
285
  });
128
- await createRunBranch({ runner, workspacePath: input.workspacePath, branchName });
286
+ await createRunBranch({
287
+ runner,
288
+ workspacePath: input.workspacePath,
289
+ branchName,
290
+ ...input.baseBranch ? { startPoint: input.baseBranch } : {}
291
+ });
129
292
  await sink.emit({
130
293
  type: "executor.progress",
131
- message: "Starting codex exec",
294
+ message: "Starting claude --print",
132
295
  at: (/* @__PURE__ */ new Date()).toISOString()
133
296
  });
134
297
  const args = [
135
- "exec",
136
- "--cd",
137
- input.workspacePath,
138
- "--full-auto",
139
- "--ephemeral",
298
+ "--print",
299
+ "--input-format",
300
+ "text",
301
+ "--output-format",
302
+ "text",
303
+ "--no-session-persistence",
140
304
  ...options.model ? ["--model", options.model] : [],
141
- "-"
305
+ ...options.permissionMode ? ["--permission-mode", options.permissionMode] : [],
306
+ ...options.dangerouslySkipPermissions ? ["--dangerously-skip-permissions"] : []
142
307
  ];
143
- const codexResult = await runner.run(codexCommand, args, {
308
+ const claudeResult = await runner.run(claudeCommand, args, {
144
309
  cwd: input.workspacePath,
145
310
  input: buildPrompt({
146
311
  runId: input.runId,
147
312
  rawText: input.command.rawText,
148
- context: input.context
313
+ context: input.context,
314
+ contextPacket: input.contextPacket
149
315
  })
150
316
  });
151
- await assertCommandSucceeded(codexResult, "codex exec");
317
+ await assertCommandSucceeded(claudeResult, "claude --print");
152
318
  const cleanedArtifacts = await cleanupInternalArtifacts({ runner, workspacePath: input.workspacePath });
153
319
  if (cleanedArtifacts.length > 0) {
154
320
  await sink.emit({
@@ -160,24 +326,396 @@ function createCodexExecutor(options = {}) {
160
326
  const files = await changedFiles({ runner, workspacePath: input.workspacePath });
161
327
  await sink.emit({
162
328
  type: "executor.completed",
163
- message: `Codex executor completed with ${files.length} changed file(s)`,
329
+ message: `Claude Code executor completed with ${files.length} changed file(s)`,
164
330
  at: (/* @__PURE__ */ new Date()).toISOString()
165
331
  });
166
- const output = codexResult.stdout.trim() || codexResult.stderr.trim() || "Codex completed without textual output.";
167
- return {
168
- conclusion: "success",
169
- summary: output.slice(-4e3),
170
- changedFiles: files,
171
- artifacts: [{ title: "Run branch", uri: branchName }],
172
- verification: [
173
- {
174
- command: "codex exec",
175
- outcome: "passed",
176
- excerpt: output.slice(-1e3)
332
+ const output = claudeResult.stdout.trim() || claudeResult.stderr.trim() || "Claude Code completed without textual output.";
333
+ return createExecutorRunResult({
334
+ executorName: "Claude Code",
335
+ runId: input.runId,
336
+ branchName,
337
+ ...input.baseBranch ? { baseBranch: input.baseBranch } : {},
338
+ output,
339
+ changedFiles: files
340
+ });
341
+ },
342
+ async cancel() {
343
+ return;
344
+ }
345
+ };
346
+ }
347
+
348
+ // src/codex.ts
349
+ import { contextPointerLabel as contextPointerLabel3 } from "@opentag/core";
350
+
351
+ // src/security.ts
352
+ import { fileURLToPath } from "url";
353
+ import { isAbsolute, relative, resolve } from "path";
354
+ var DEFAULT_SAFE_ENV_NAMES = [
355
+ "CI",
356
+ "COLORTERM",
357
+ "CODEX_HOME",
358
+ "FORCE_COLOR",
359
+ "HOME",
360
+ "LANG",
361
+ "LOGNAME",
362
+ "NO_COLOR",
363
+ "PATH",
364
+ "PWD",
365
+ "SHELL",
366
+ "SSL_CERT_DIR",
367
+ "SSL_CERT_FILE",
368
+ "TERM",
369
+ "TMP",
370
+ "TMPDIR",
371
+ "TEMP",
372
+ "USER",
373
+ "XDG_CACHE_HOME",
374
+ "XDG_CONFIG_HOME",
375
+ "XDG_DATA_HOME"
376
+ ];
377
+ var SAFE_ENV_PREFIXES = ["LC_"];
378
+ var SENSITIVE_ENV_PATTERNS = [
379
+ /TOKEN/,
380
+ /SECRET/,
381
+ /PASSWORD/,
382
+ /PASS$/,
383
+ /API[_-]?KEY/,
384
+ /CREDENTIAL/,
385
+ /COOKIE/,
386
+ /SESSION/,
387
+ /AUTH/,
388
+ /^AWS_/,
389
+ /^AZURE_/,
390
+ /^GCP_/,
391
+ /^GOOGLE_/,
392
+ /^OPENAI_/,
393
+ /^ANTHROPIC_/,
394
+ /^SLACK_/,
395
+ /^GITHUB_TOKEN$/,
396
+ /^GH_TOKEN$/,
397
+ /^SSH_/
398
+ ];
399
+ var HIGH_RISK_TEXT_PATTERNS = [
400
+ {
401
+ code: "prompt.instruction_override",
402
+ pattern: /\b(ignore|disregard|forget)\s+(all\s+)?(previous|prior|system|developer|safety)\s+instructions\b/i,
403
+ message: "Request contains an instruction override pattern commonly used in prompt injection."
404
+ },
405
+ {
406
+ code: "prompt.secret_exfiltration",
407
+ pattern: /\b(print|dump|show|reveal|exfiltrate|send|upload|post|copy)\b[\s\S]{0,100}\b(secret|token|password|api[\s_-]?key|credential|environment variables?|env vars?)\b/i,
408
+ message: "Request appears to ask the runner to expose secrets or environment variables."
409
+ },
410
+ {
411
+ code: "prompt.sensitive_file_access",
412
+ pattern: /\b(cat|open|read|print|dump)\b[\s\S]{0,80}(~\/\.ssh|~\/\.aws|\.env\b|id_rsa|known_hosts|credentials\b)/i,
413
+ message: "Request appears to ask the runner to read sensitive local credential files."
414
+ }
415
+ ];
416
+ function securityMode(policy) {
417
+ return policy?.mode ?? "enforce";
418
+ }
419
+ function isPathInside(childPath, parentPath) {
420
+ const child = resolve(childPath);
421
+ const parent = resolve(parentPath);
422
+ const pathFromParent = relative(parent, child);
423
+ return pathFromParent === "" || !pathFromParent.startsWith("..") && !isAbsolute(pathFromParent);
424
+ }
425
+ function fileContextPath(pointer, workspacePath) {
426
+ if (pointer.kind !== "file") return null;
427
+ if (pointer.uri.startsWith("file://")) {
428
+ return fileURLToPath(pointer.uri);
429
+ }
430
+ if (isAbsolute(pointer.uri)) {
431
+ return pointer.uri;
432
+ }
433
+ return resolve(workspacePath, pointer.uri);
434
+ }
435
+ function hasPermission(permissions, scope) {
436
+ return permissions?.some((permission) => permission.scope === scope) ?? false;
437
+ }
438
+ function needsWritePermission(command, executorId) {
439
+ if (executorId === "echo") return false;
440
+ return command.intent === "fix" || command.intent === "run";
441
+ }
442
+ function scanTextForHighRiskPatterns(input) {
443
+ const sources = [
444
+ { label: "command", text: input.command.rawText },
445
+ ...input.context.filter((pointer) => pointer.kind === "text").map((pointer) => ({ label: pointer.title ?? "text context", text: pointer.uri }))
446
+ ];
447
+ const findings = [];
448
+ for (const source of sources) {
449
+ for (const rule of HIGH_RISK_TEXT_PATTERNS) {
450
+ if (rule.pattern.test(source.text)) {
451
+ findings.push({
452
+ code: rule.code,
453
+ severity: "block",
454
+ message: `${rule.message} Source: ${source.label}.`
455
+ });
456
+ }
457
+ }
458
+ }
459
+ return findings;
460
+ }
461
+ function assessRunnerSecurity(input) {
462
+ const mode = securityMode(input.policy);
463
+ if (mode === "off") {
464
+ return { allowed: true, mode, findings: [] };
465
+ }
466
+ const findings = [];
467
+ if (!isAbsolute(input.workspacePath)) {
468
+ findings.push({
469
+ code: "workspace.relative_path",
470
+ severity: "block",
471
+ message: "Workspace path must be absolute before a local executor can run."
472
+ });
473
+ }
474
+ const workspacePath = resolve(input.workspacePath);
475
+ const executionPath = resolve(input.executionPath ?? input.workspacePath);
476
+ if (input.policy?.allowedWorkspaceRoot && !isPathInside(workspacePath, input.policy.allowedWorkspaceRoot)) {
477
+ findings.push({
478
+ code: "workspace.outside_allowed_root",
479
+ severity: "block",
480
+ message: "Workspace path is outside the configured allowed workspace root."
481
+ });
482
+ }
483
+ if (input.policy?.allowedWorkspaceRoot && !isPathInside(executionPath, input.policy.allowedWorkspaceRoot)) {
484
+ findings.push({
485
+ code: "execution.outside_allowed_root",
486
+ severity: "block",
487
+ message: "Execution path is outside the configured allowed workspace root."
488
+ });
489
+ }
490
+ for (const pointer of input.context) {
491
+ const filePath = fileContextPath(pointer, workspacePath);
492
+ if (filePath && !isPathInside(filePath, workspacePath)) {
493
+ findings.push({
494
+ code: "context.file_outside_workspace",
495
+ severity: "block",
496
+ message: `File context is outside the mapped workspace: ${pointer.uri}`
497
+ });
498
+ }
499
+ }
500
+ if (needsWritePermission(input.command, input.executorId) && !hasPermission(input.permissions, "repo:write")) {
501
+ findings.push({
502
+ code: "permission.repo_write_required",
503
+ severity: "block",
504
+ message: "Write-capable commands require an explicit repo:write permission grant."
505
+ });
506
+ }
507
+ if (!input.policy?.allowUnsafePrompts) {
508
+ findings.push(...scanTextForHighRiskPatterns({ command: input.command, context: input.context }));
509
+ }
510
+ const hasBlockingFinding = findings.some((finding) => finding.severity === "block");
511
+ return {
512
+ allowed: mode === "audit" || !hasBlockingFinding,
513
+ mode,
514
+ findings
515
+ };
516
+ }
517
+ function isSensitiveEnvName(name) {
518
+ const upperName = name.toUpperCase();
519
+ return SENSITIVE_ENV_PATTERNS.some((pattern) => pattern.test(upperName));
520
+ }
521
+ function isSafeEnvName(name, policy) {
522
+ const upperName = name.toUpperCase();
523
+ const safeNames = new Set([...DEFAULT_SAFE_ENV_NAMES, ...policy?.extraSafeEnv ?? []].map((envName) => envName.toUpperCase()));
524
+ return safeNames.has(upperName) || SAFE_ENV_PREFIXES.some((prefix) => upperName.startsWith(prefix));
525
+ }
526
+ function scrubEnvironment(env = process.env, policy) {
527
+ if (securityMode(policy) === "off") return { ...env };
528
+ const scrubbed = {};
529
+ for (const [name, value] of Object.entries(env)) {
530
+ if (typeof value !== "string") continue;
531
+ if (isSensitiveEnvName(name)) continue;
532
+ if (!isSafeEnvName(name, policy)) continue;
533
+ scrubbed[name] = value;
534
+ }
535
+ return scrubbed;
536
+ }
537
+ function formatSecurityAssessment(assessment) {
538
+ if (assessment.findings.length === 0) {
539
+ return `OpenTag runner security assessment passed in ${assessment.mode} mode.`;
540
+ }
541
+ const prefix = assessment.allowed ? `OpenTag runner security assessment reported ${assessment.findings.length} finding(s) in ${assessment.mode} mode.` : "OpenTag runner security blocked this run.";
542
+ const details = assessment.findings.map((finding) => `${finding.code}: ${finding.message}`).join(" ");
543
+ return `${prefix} ${details}`;
544
+ }
545
+
546
+ // src/codex.ts
547
+ function contextLines2(context) {
548
+ if (!context.length) return "No additional context pointers were provided.";
549
+ return context.map((pointer) => `- ${contextPointerLabel3(pointer)}: ${pointer.uri}`).join("\n");
550
+ }
551
+ function buildPrompt2(input) {
552
+ return [
553
+ "You are executing an OpenTag run in a local checkout.",
554
+ `Run ID: ${input.runId}`,
555
+ "",
556
+ "User request:",
557
+ input.rawText,
558
+ "",
559
+ ...renderContextPacketForPrompt(input.contextPacket),
560
+ ...input.contextPacket ? [""] : [],
561
+ "Context pointers:",
562
+ contextLines2(input.context),
563
+ "",
564
+ "Work autonomously but keep the change narrow. Run relevant verification if you modify files. End with a concise summary."
565
+ ].join("\n");
566
+ }
567
+ function createCodexExecutor(options = {}) {
568
+ const runner = options.runner ?? nodeCommandRunner;
569
+ const codexCommand = options.codexCommand ?? "codex";
570
+ return {
571
+ id: "codex",
572
+ displayName: "Codex Executor",
573
+ async canRun(input) {
574
+ const codexVersion = await runner.run(codexCommand, ["--version"], { cwd: input.workspacePath });
575
+ if (codexVersion.exitCode !== 0) {
576
+ return { ready: false, reason: `Codex CLI is not available: ${codexVersion.stderr || codexVersion.stdout}` };
577
+ }
578
+ const gitRepo = await runner.run("git", ["rev-parse", "--show-toplevel"], { cwd: input.workspacePath });
579
+ if (gitRepo.exitCode !== 0) {
580
+ return { ready: false, reason: `Workspace is not a git checkout: ${gitRepo.stderr || gitRepo.stdout}` };
581
+ }
582
+ const baseBranch = input.baseBranch ?? "main";
583
+ const baseRef = await runner.run("git", ["rev-parse", "--verify", `${baseBranch}^{commit}`], {
584
+ cwd: input.workspacePath
585
+ });
586
+ if (baseRef.exitCode !== 0) {
587
+ return { ready: false, reason: `Base branch '${baseBranch}' is not available: ${baseRef.stderr || baseRef.stdout}` };
588
+ }
589
+ return { ready: true };
590
+ },
591
+ async run(input, sink) {
592
+ const security = options.security;
593
+ const worktreePath = worktreePathForRun({
594
+ workspacePath: input.workspacePath,
595
+ runId: input.runId,
596
+ ...input.worktreeRoot ? { worktreeRoot: input.worktreeRoot } : {}
597
+ });
598
+ const assessment = assessRunnerSecurity({
599
+ executorId: "codex",
600
+ workspacePath: input.workspacePath,
601
+ executionPath: worktreePath,
602
+ command: input.command,
603
+ context: input.context,
604
+ ...input.permissions ? { permissions: input.permissions } : {},
605
+ ...security ? { policy: security } : {}
606
+ });
607
+ if (assessment.findings.length > 0) {
608
+ await sink.emit({
609
+ type: assessment.allowed ? "executor.progress" : "executor.failed",
610
+ message: formatSecurityAssessment(assessment),
611
+ at: (/* @__PURE__ */ new Date()).toISOString()
612
+ });
613
+ }
614
+ if (!assessment.allowed) {
615
+ return {
616
+ conclusion: "needs_human",
617
+ summary: formatSecurityAssessment(assessment),
618
+ nextAction: "Review the request and rerun with a narrower prompt or an explicit local policy override if appropriate."
619
+ };
620
+ }
621
+ const branchName = branchNameForRun(input.runId);
622
+ const baseBranch = input.baseBranch ?? "main";
623
+ const keepWorktree = input.keepWorktree ?? "on_failure";
624
+ let completed = false;
625
+ let changedFileCount;
626
+ await sink.emit({
627
+ type: "executor.started",
628
+ message: `Creating isolated worktree ${worktreePath} on ${branchName}`,
629
+ at: (/* @__PURE__ */ new Date()).toISOString()
630
+ });
631
+ try {
632
+ await createRunWorktree({
633
+ runner,
634
+ workspacePath: input.workspacePath,
635
+ worktreePath,
636
+ branchName,
637
+ baseBranch
638
+ });
639
+ await sink.emit({
640
+ type: "executor.progress",
641
+ message: "Starting codex exec",
642
+ at: (/* @__PURE__ */ new Date()).toISOString()
643
+ });
644
+ const args = [
645
+ "exec",
646
+ "--cd",
647
+ worktreePath,
648
+ "--full-auto",
649
+ "--ephemeral",
650
+ ...options.model ? ["--model", options.model] : [],
651
+ "-"
652
+ ];
653
+ const codexResult = await runner.run(codexCommand, args, {
654
+ cwd: worktreePath,
655
+ env: scrubEnvironment(void 0, security),
656
+ input: buildPrompt2({
657
+ runId: input.runId,
658
+ rawText: input.command.rawText,
659
+ context: input.context,
660
+ contextPacket: input.contextPacket
661
+ })
662
+ });
663
+ await assertCommandSucceeded(codexResult, "codex exec");
664
+ const cleanedArtifacts = await cleanupInternalArtifacts({ runner, workspacePath: worktreePath });
665
+ if (cleanedArtifacts.length > 0) {
666
+ await sink.emit({
667
+ type: "executor.progress",
668
+ message: `Cleaned internal artifacts: ${cleanedArtifacts.join(", ")}`,
669
+ at: (/* @__PURE__ */ new Date()).toISOString()
670
+ });
671
+ }
672
+ const files = await changedFiles({ runner, workspacePath: worktreePath });
673
+ changedFileCount = files.length;
674
+ if (files.length > 0) {
675
+ await sink.emit({
676
+ type: "executor.progress",
677
+ message: `Committing ${files.length} changed file(s) to ${branchName}`,
678
+ at: (/* @__PURE__ */ new Date()).toISOString()
679
+ });
680
+ await commitRunChanges({
681
+ runner,
682
+ workspacePath: worktreePath,
683
+ message: `OpenTag run ${input.runId}`
684
+ });
685
+ }
686
+ completed = true;
687
+ await sink.emit({
688
+ type: "executor.completed",
689
+ message: `Codex executor completed with ${files.length} changed file(s)`,
690
+ at: (/* @__PURE__ */ new Date()).toISOString()
691
+ });
692
+ const output = codexResult.stdout.trim() || codexResult.stderr.trim() || "Codex completed without textual output.";
693
+ return createExecutorRunResult({
694
+ executorName: "Codex",
695
+ runId: input.runId,
696
+ branchName,
697
+ ...input.baseBranch ? { baseBranch: input.baseBranch } : {},
698
+ output,
699
+ changedFiles: files,
700
+ extraArtifacts: keepWorktree === "always" ? [{ title: "Run worktree", uri: worktreePath }] : []
701
+ });
702
+ } finally {
703
+ const shouldRemove = keepWorktree === "never" || keepWorktree === "on_failure" && completed;
704
+ if (shouldRemove) {
705
+ try {
706
+ await removeRunWorktree({ runner, workspacePath: input.workspacePath, worktreePath });
707
+ if (completed && changedFileCount === 0) {
708
+ await deleteRunBranch({ runner, workspacePath: input.workspacePath, branchName });
709
+ }
710
+ } catch (error) {
711
+ await sink.emit({
712
+ type: "executor.progress",
713
+ message: `Could not clean up run worktree or branch for ${worktreePath}: ${error instanceof Error ? error.message : String(error)}`,
714
+ at: (/* @__PURE__ */ new Date()).toISOString()
715
+ });
177
716
  }
178
- ],
179
- nextAction: files.length > 0 ? "Review the local branch and create a pull request." : "No file changes were detected."
180
- };
717
+ }
718
+ }
181
719
  },
182
720
  async cancel() {
183
721
  return;
@@ -216,7 +754,11 @@ function createEchoExecutor() {
216
754
  outcome: "passed",
217
755
  excerpt: input.command.rawText
218
756
  }
219
- ]
757
+ ],
758
+ nextAction: {
759
+ summary: "No external state change is suggested for the echo executor result.",
760
+ hint: { kind: "none" }
761
+ }
220
762
  };
221
763
  },
222
764
  async cancel() {
@@ -225,17 +767,30 @@ function createEchoExecutor() {
225
767
  };
226
768
  }
227
769
  export {
770
+ DEFAULT_SAFE_ENV_NAMES,
228
771
  assertCommandSucceeded,
772
+ assessRunnerSecurity,
229
773
  branchNameForRun,
230
774
  changedFiles,
231
775
  cleanupInternalArtifacts,
776
+ commitChangedFiles,
777
+ commitRunChanges,
778
+ createClaudeCodeExecutor,
232
779
  createCodexExecutor,
233
780
  createEchoExecutor,
781
+ createExecutorRunResult,
234
782
  createRunBranch,
783
+ createRunWorktree,
784
+ deleteRunBranch,
785
+ formatSecurityAssessment,
235
786
  isInternalArtifactPath,
236
787
  nodeCommandRunner,
237
788
  parseChangedFiles,
238
789
  parseStatusEntries,
239
- pushBranch
790
+ pushBranch,
791
+ removeRunWorktree,
792
+ renderContextPacketForPrompt,
793
+ scrubEnvironment,
794
+ worktreePathForRun
240
795
  };
241
796
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/command.ts","../src/git.ts","../src/codex.ts","../src/echo.ts"],"sourcesContent":["import { spawn } from \"node:child_process\";\n\nexport type CommandResult = {\n exitCode: number;\n stdout: string;\n stderr: string;\n};\n\nexport type CommandRunner = {\n run(command: string, args: string[], options?: { cwd?: string; input?: string }): Promise<CommandResult>;\n};\n\nexport const nodeCommandRunner: CommandRunner = {\n run(command, args, options = {}) {\n return new Promise((resolve, reject) => {\n const child = spawn(command, args, {\n cwd: options.cwd,\n stdio: [\"pipe\", \"pipe\", \"pipe\"]\n });\n const stdout: Buffer[] = [];\n const stderr: Buffer[] = [];\n\n child.stdout.on(\"data\", (chunk: Buffer) => stdout.push(chunk));\n child.stderr.on(\"data\", (chunk: Buffer) => stderr.push(chunk));\n child.on(\"error\", reject);\n child.on(\"close\", (exitCode) => {\n resolve({\n exitCode: exitCode ?? 1,\n stdout: Buffer.concat(stdout).toString(\"utf8\"),\n stderr: Buffer.concat(stderr).toString(\"utf8\")\n });\n });\n\n if (options.input) {\n child.stdin.write(options.input);\n }\n child.stdin.end();\n });\n }\n};\n\nexport async function assertCommandSucceeded(result: CommandResult, label: string): Promise<void> {\n if (result.exitCode !== 0) {\n throw new Error(`${label} failed with exit code ${result.exitCode}: ${result.stderr || result.stdout}`);\n }\n}\n","import type { CommandRunner } from \"./command.js\";\nimport { assertCommandSucceeded } from \"./command.js\";\n\nexport type GitStatusEntry = {\n status: string;\n path: string;\n};\n\nconst INTERNAL_ARTIFACT_ROOTS = [\".omx\", \".codex\", \".claude\"];\n\nexport function branchNameForRun(runId: string): string {\n const safeRunId = runId.replace(/[^a-zA-Z0-9._-]/g, \"-\");\n return `opentag/${safeRunId}`;\n}\n\nexport function parseStatusEntries(statusOutput: string): GitStatusEntry[] {\n return statusOutput\n .split(\"\\n\")\n .map((line) => line.replace(/\\r$/, \"\"))\n .filter(Boolean)\n .map((line) => ({\n status: line.slice(0, 2),\n path: line.slice(3).trim()\n }))\n .filter((entry) => entry.path.length > 0);\n}\n\nexport function isInternalArtifactPath(path: string): boolean {\n return INTERNAL_ARTIFACT_ROOTS.some((root) => path === root || path.startsWith(`${root}/`));\n}\n\nexport function parseChangedFiles(statusOutput: string): string[] {\n return parseStatusEntries(statusOutput)\n .map((entry) => entry.path)\n .filter((path) => !isInternalArtifactPath(path));\n}\n\nexport async function createRunBranch(input: {\n runner: CommandRunner;\n workspacePath: string;\n branchName: string;\n}): Promise<void> {\n const result = await input.runner.run(\"git\", [\"checkout\", \"-B\", input.branchName], { cwd: input.workspacePath });\n await assertCommandSucceeded(result, \"create run branch\");\n}\n\nexport async function changedFiles(input: { runner: CommandRunner; workspacePath: string }): Promise<string[]> {\n const result = await input.runner.run(\"git\", [\"status\", \"--porcelain\"], { cwd: input.workspacePath });\n await assertCommandSucceeded(result, \"read changed files\");\n return parseChangedFiles(result.stdout);\n}\n\nexport async function cleanupInternalArtifacts(input: { runner: CommandRunner; workspacePath: string }): Promise<string[]> {\n const statusResult = await input.runner.run(\"git\", [\"status\", \"--porcelain\"], { cwd: input.workspacePath });\n await assertCommandSucceeded(statusResult, \"scan internal artifacts\");\n const untrackedRoots = Array.from(\n new Set(\n parseStatusEntries(statusResult.stdout)\n .filter((entry) => entry.status === \"??\" && isInternalArtifactPath(entry.path))\n .map((entry) => entry.path.split(\"/\", 1)[0] ?? entry.path)\n )\n );\n if (untrackedRoots.length === 0) return [];\n\n const cleanResult = await input.runner.run(\"git\", [\"clean\", \"-fd\", \"--\", ...untrackedRoots], {\n cwd: input.workspacePath\n });\n await assertCommandSucceeded(cleanResult, \"clean internal artifacts\");\n return untrackedRoots;\n}\n\nexport async function pushBranch(input: {\n runner: CommandRunner;\n workspacePath: string;\n remote: string;\n branchName: string;\n}): Promise<void> {\n const result = await input.runner.run(\"git\", [\"push\", \"-u\", input.remote, input.branchName], { cwd: input.workspacePath });\n await assertCommandSucceeded(result, \"push run branch\");\n}\n","import type { ContextPointer } from \"@opentag/core\";\nimport { assertCommandSucceeded, nodeCommandRunner, type CommandRunner } from \"./command.js\";\nimport type { ExecutorAdapter } from \"./executor.js\";\nimport { branchNameForRun, changedFiles, cleanupInternalArtifacts, createRunBranch } from \"./git.js\";\n\nexport type CodexExecutorOptions = {\n runner?: CommandRunner;\n codexCommand?: string;\n model?: string;\n};\n\nfunction contextLines(context: ContextPointer[]): string {\n if (!context.length) return \"No additional context pointers were provided.\";\n return context.map((pointer) => `- ${pointer.kind}: ${pointer.uri}`).join(\"\\n\");\n}\n\nfunction buildPrompt(input: {\n runId: string;\n rawText: string;\n context: ContextPointer[];\n}): string {\n return [\n \"You are executing an OpenTag run in a local checkout.\",\n `Run ID: ${input.runId}`,\n \"\",\n \"User request:\",\n input.rawText,\n \"\",\n \"Context pointers:\",\n contextLines(input.context),\n \"\",\n \"Work autonomously but keep the change narrow. Run relevant verification if you modify files. End with a concise summary.\"\n ].join(\"\\n\");\n}\n\nexport function createCodexExecutor(options: CodexExecutorOptions = {}): ExecutorAdapter {\n const runner = options.runner ?? nodeCommandRunner;\n const codexCommand = options.codexCommand ?? \"codex\";\n\n return {\n id: \"codex\",\n displayName: \"Codex Executor\",\n async canRun(input) {\n const codexVersion = await runner.run(codexCommand, [\"--version\"], { cwd: input.workspacePath });\n if (codexVersion.exitCode !== 0) {\n return { ready: false, reason: `Codex CLI is not available: ${codexVersion.stderr || codexVersion.stdout}` };\n }\n const gitStatus = await runner.run(\"git\", [\"status\", \"--porcelain\"], { cwd: input.workspacePath });\n if (gitStatus.exitCode !== 0) {\n return { ready: false, reason: `Workspace is not a git checkout: ${gitStatus.stderr || gitStatus.stdout}` };\n }\n if (gitStatus.stdout.trim().length > 0) {\n return { ready: false, reason: \"Workspace has uncommitted changes; refusing to run Codex executor.\" };\n }\n return { ready: true };\n },\n async run(input, sink) {\n const branchName = branchNameForRun(input.runId);\n await sink.emit({\n type: \"executor.started\",\n message: `Creating isolated branch ${branchName}`,\n at: new Date().toISOString()\n });\n await createRunBranch({ runner, workspacePath: input.workspacePath, branchName });\n\n await sink.emit({\n type: \"executor.progress\",\n message: \"Starting codex exec\",\n at: new Date().toISOString()\n });\n\n const args = [\n \"exec\",\n \"--cd\",\n input.workspacePath,\n \"--full-auto\",\n \"--ephemeral\",\n ...(options.model ? [\"--model\", options.model] : []),\n \"-\"\n ];\n const codexResult = await runner.run(codexCommand, args, {\n cwd: input.workspacePath,\n input: buildPrompt({\n runId: input.runId,\n rawText: input.command.rawText,\n context: input.context\n })\n });\n await assertCommandSucceeded(codexResult, \"codex exec\");\n\n const cleanedArtifacts = await cleanupInternalArtifacts({ runner, workspacePath: input.workspacePath });\n if (cleanedArtifacts.length > 0) {\n await sink.emit({\n type: \"executor.progress\",\n message: `Cleaned internal artifacts: ${cleanedArtifacts.join(\", \")}`,\n at: new Date().toISOString()\n });\n }\n\n const files = await changedFiles({ runner, workspacePath: input.workspacePath });\n await sink.emit({\n type: \"executor.completed\",\n message: `Codex executor completed with ${files.length} changed file(s)`,\n at: new Date().toISOString()\n });\n\n const output = codexResult.stdout.trim() || codexResult.stderr.trim() || \"Codex completed without textual output.\";\n return {\n conclusion: \"success\",\n summary: output.slice(-4000),\n changedFiles: files,\n artifacts: [{ title: \"Run branch\", uri: branchName }],\n verification: [\n {\n command: \"codex exec\",\n outcome: \"passed\",\n excerpt: output.slice(-1000)\n }\n ],\n nextAction: files.length > 0 ? \"Review the local branch and create a pull request.\" : \"No file changes were detected.\"\n };\n },\n async cancel() {\n return;\n }\n };\n}\n","import type { ExecutorAdapter } from \"./executor.js\";\n\nfunction nowIso(): string {\n return new Date().toISOString();\n}\n\nexport function createEchoExecutor(): ExecutorAdapter {\n return {\n id: \"echo\",\n displayName: \"Echo Executor\",\n async canRun() {\n return { ready: true };\n },\n async run(input, sink) {\n await sink.emit({\n type: \"executor.started\",\n message: `Echo executor started for ${input.runId}`,\n at: nowIso()\n });\n await sink.emit({\n type: \"executor.completed\",\n message: `Echo executor completed for ${input.runId}`,\n at: nowIso()\n });\n return {\n conclusion: \"success\",\n summary: `Echoed OpenTag command: ${input.command.rawText}`,\n verification: [\n {\n command: \"echo\",\n outcome: \"passed\",\n excerpt: input.command.rawText\n }\n ]\n };\n },\n async cancel() {\n return;\n }\n };\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/claude-code.ts","../src/command.ts","../src/executor.ts","../src/git.ts","../src/result.ts","../src/codex.ts","../src/security.ts","../src/echo.ts"],"sourcesContent":["import { contextPointerLabel, type ContextPacket, type ContextPointer } from \"@opentag/core\";\nimport { assertCommandSucceeded, nodeCommandRunner, type CommandRunner } from \"./command.js\";\nimport { renderContextPacketForPrompt, type ExecutorAdapter } from \"./executor.js\";\nimport { branchNameForRun, changedFiles, cleanupInternalArtifacts, createRunBranch } from \"./git.js\";\nimport { createExecutorRunResult } from \"./result.js\";\n\nexport type ClaudeCodeExecutorOptions = {\n runner?: CommandRunner;\n claudeCommand?: string;\n model?: string;\n permissionMode?: \"acceptEdits\" | \"auto\" | \"bypassPermissions\" | \"default\" | \"plan\";\n dangerouslySkipPermissions?: boolean;\n};\n\nfunction contextLines(context: ContextPointer[]): string {\n if (!context.length) return \"No additional context pointers were provided.\";\n return context.map((pointer) => `- ${contextPointerLabel(pointer)}: ${pointer.uri}`).join(\"\\n\");\n}\n\nfunction buildPrompt(input: {\n runId: string;\n rawText: string;\n context: ContextPointer[];\n contextPacket: ContextPacket | undefined;\n}): string {\n return [\n \"You are executing an OpenTag run in a local checkout.\",\n `Run ID: ${input.runId}`,\n \"\",\n \"User request:\",\n input.rawText,\n \"\",\n ...renderContextPacketForPrompt(input.contextPacket),\n ...(input.contextPacket ? [\"\"] : []),\n \"Context pointers:\",\n contextLines(input.context),\n \"\",\n \"Work autonomously but keep the change narrow. Run relevant verification if you modify files.\",\n \"End with a concise summary of what changed, what was verified, and the recommended next action.\"\n ].join(\"\\n\");\n}\n\nexport function createClaudeCodeExecutor(options: ClaudeCodeExecutorOptions = {}): ExecutorAdapter {\n const runner = options.runner ?? nodeCommandRunner;\n const claudeCommand = options.claudeCommand ?? \"claude\";\n\n return {\n id: \"claude-code\",\n displayName: \"Claude Code Executor\",\n async canRun(input) {\n try {\n const claudeVersion = await runner.run(claudeCommand, [\"--version\"], { cwd: input.workspacePath });\n if (claudeVersion.exitCode !== 0) {\n return { ready: false, reason: `Claude Code CLI is not available: ${claudeVersion.stderr || claudeVersion.stdout}` };\n }\n } catch (error) {\n return { ready: false, reason: `Claude Code CLI is not available: ${error instanceof Error ? error.message : String(error)}` };\n }\n const gitStatus = await runner.run(\"git\", [\"status\", \"--porcelain\"], { cwd: input.workspacePath });\n if (gitStatus.exitCode !== 0) {\n return { ready: false, reason: `Workspace is not a git checkout: ${gitStatus.stderr || gitStatus.stdout}` };\n }\n if (gitStatus.stdout.trim().length > 0) {\n return { ready: false, reason: \"Workspace has uncommitted changes; refusing to run Claude Code executor.\" };\n }\n return { ready: true };\n },\n async run(input, sink) {\n const branchName = branchNameForRun(input.runId);\n await sink.emit({\n type: \"executor.started\",\n message: `Creating isolated branch ${branchName}`,\n at: new Date().toISOString()\n });\n await createRunBranch({\n runner,\n workspacePath: input.workspacePath,\n branchName,\n ...(input.baseBranch ? { startPoint: input.baseBranch } : {})\n });\n\n await sink.emit({\n type: \"executor.progress\",\n message: \"Starting claude --print\",\n at: new Date().toISOString()\n });\n\n const args = [\n \"--print\",\n \"--input-format\",\n \"text\",\n \"--output-format\",\n \"text\",\n \"--no-session-persistence\",\n ...(options.model ? [\"--model\", options.model] : []),\n ...(options.permissionMode ? [\"--permission-mode\", options.permissionMode] : []),\n ...(options.dangerouslySkipPermissions ? [\"--dangerously-skip-permissions\"] : [])\n ];\n const claudeResult = await runner.run(claudeCommand, args, {\n cwd: input.workspacePath,\n input: buildPrompt({\n runId: input.runId,\n rawText: input.command.rawText,\n context: input.context,\n contextPacket: input.contextPacket\n })\n });\n await assertCommandSucceeded(claudeResult, \"claude --print\");\n\n const cleanedArtifacts = await cleanupInternalArtifacts({ runner, workspacePath: input.workspacePath });\n if (cleanedArtifacts.length > 0) {\n await sink.emit({\n type: \"executor.progress\",\n message: `Cleaned internal artifacts: ${cleanedArtifacts.join(\", \")}`,\n at: new Date().toISOString()\n });\n }\n\n const files = await changedFiles({ runner, workspacePath: input.workspacePath });\n await sink.emit({\n type: \"executor.completed\",\n message: `Claude Code executor completed with ${files.length} changed file(s)`,\n at: new Date().toISOString()\n });\n\n const output = claudeResult.stdout.trim() || claudeResult.stderr.trim() || \"Claude Code completed without textual output.\";\n return createExecutorRunResult({\n executorName: \"Claude Code\",\n runId: input.runId,\n branchName,\n ...(input.baseBranch ? { baseBranch: input.baseBranch } : {}),\n output,\n changedFiles: files\n });\n },\n async cancel() {\n return;\n }\n };\n}\n","import { spawn } from \"node:child_process\";\n\nexport type CommandResult = {\n exitCode: number;\n stdout: string;\n stderr: string;\n};\n\nexport type CommandEnvironment = Record<string, string | undefined>;\n\nexport type CommandRunner = {\n run(command: string, args: string[], options?: { cwd?: string; input?: string; env?: CommandEnvironment }): Promise<CommandResult>;\n};\n\nexport const nodeCommandRunner: CommandRunner = {\n run(command, args, options = {}) {\n return new Promise((resolve, reject) => {\n const child = spawn(command, args, {\n cwd: options.cwd,\n env: options.env,\n stdio: [\"pipe\", \"pipe\", \"pipe\"]\n });\n const stdout: Buffer[] = [];\n const stderr: Buffer[] = [];\n\n child.stdout.on(\"data\", (chunk: Buffer) => stdout.push(chunk));\n child.stderr.on(\"data\", (chunk: Buffer) => stderr.push(chunk));\n child.on(\"error\", reject);\n child.on(\"close\", (exitCode) => {\n resolve({\n exitCode: exitCode ?? 1,\n stdout: Buffer.concat(stdout).toString(\"utf8\"),\n stderr: Buffer.concat(stderr).toString(\"utf8\")\n });\n });\n\n if (options.input) {\n child.stdin.write(options.input);\n }\n child.stdin.end();\n });\n }\n};\n\nexport async function assertCommandSucceeded(result: CommandResult, label: string): Promise<void> {\n if (result.exitCode !== 0) {\n throw new Error(`${label} failed with exit code ${result.exitCode}: ${result.stderr || result.stdout}`);\n }\n}\n","import { contextPointerLabel, type ContextPacket, type ContextPointer, type OpenTagCommand, type OpenTagRunResult, type PermissionGrant } from \"@opentag/core\";\n\nexport type ExecutorEvent = {\n type: \"executor.started\" | \"executor.progress\" | \"executor.completed\" | \"executor.failed\";\n message: string;\n at: string;\n};\n\nexport type ExecutorEventSink = {\n emit(event: ExecutorEvent): Promise<void>;\n};\n\nexport type ExecutorRunInput = {\n runId: string;\n workspacePath: string;\n command: OpenTagCommand;\n context: ContextPointer[];\n contextPacket?: ContextPacket;\n permissions?: PermissionGrant[];\n baseBranch?: string;\n worktreeRoot?: string;\n keepWorktree?: \"always\" | \"on_failure\" | \"never\";\n};\n\nexport function renderContextPacketForPrompt(packet?: ContextPacket): string[] {\n if (!packet) return [];\n\n const lines = [\"OpenTag context packet:\", `- summary: ${packet.summary}`];\n\n if (packet.intent) {\n lines.push(`- intent: ${packet.intent.normalizedIntent}`);\n lines.push(`- requested by: ${packet.intent.requestedBy.provider}:${packet.intent.requestedBy.providerUserId}`);\n }\n\n if (packet.sources?.length) {\n lines.push(\"- selected sources:\");\n for (const source of packet.sources) {\n lines.push(` - [${source.role}] ${contextPointerLabel(source.pointer)}: ${source.pointer.uri}`);\n lines.push(` reason: ${source.reason}`);\n }\n }\n\n if (packet.facts?.length) {\n lines.push(\"- facts:\");\n for (const fact of packet.facts) {\n lines.push(` - ${fact.text}`);\n }\n }\n\n if (packet.exclusions?.length) {\n lines.push(\"- exclusions:\");\n for (const exclusion of packet.exclusions) {\n lines.push(` - ${exclusion}`);\n }\n }\n\n return lines;\n}\n\nexport type ExecutorReadiness = {\n ready: boolean;\n reason?: string;\n};\n\nexport type ExecutorAdapter = {\n id: string;\n displayName: string;\n canRun(input: ExecutorRunInput): Promise<ExecutorReadiness>;\n run(input: ExecutorRunInput, sink: ExecutorEventSink): Promise<OpenTagRunResult>;\n cancel(runId: string): Promise<void>;\n};\n","import { mkdirSync } from \"node:fs\";\nimport { dirname } from \"node:path\";\nimport type { CommandRunner } from \"./command.js\";\nimport { assertCommandSucceeded } from \"./command.js\";\n\nexport type GitStatusEntry = {\n status: string;\n path: string;\n};\n\nconst INTERNAL_ARTIFACT_ROOTS = [\".omx\", \".codex\", \".claude\"];\n\nexport function branchNameForRun(runId: string): string {\n const safeRunId = runId.replace(/[^a-zA-Z0-9._-]/g, \"-\");\n return `opentag/${safeRunId}`;\n}\n\nexport function parseStatusEntries(statusOutput: string): GitStatusEntry[] {\n return statusOutput\n .split(\"\\n\")\n .map((line) => line.replace(/\\r$/, \"\"))\n .filter(Boolean)\n .map((line) => ({\n status: line.slice(0, 2),\n path: line.slice(3).trim()\n }))\n .filter((entry) => entry.path.length > 0);\n}\n\nexport function isInternalArtifactPath(path: string): boolean {\n return INTERNAL_ARTIFACT_ROOTS.some((root) => path === root || path.startsWith(`${root}/`));\n}\n\nexport function parseChangedFiles(statusOutput: string): string[] {\n return parseStatusEntries(statusOutput)\n .map((entry) => entry.path)\n .filter((path) => !isInternalArtifactPath(path));\n}\n\nexport async function createRunBranch(input: {\n runner: CommandRunner;\n workspacePath: string;\n branchName: string;\n startPoint?: string;\n}): Promise<void> {\n const result = await input.runner.run(\"git\", [\"checkout\", \"-B\", input.branchName, ...(input.startPoint ? [input.startPoint] : [])], { cwd: input.workspacePath });\n await assertCommandSucceeded(result, \"create run branch\");\n}\n\nexport function worktreePathForRun(input: {\n workspacePath: string;\n runId: string;\n worktreeRoot?: string;\n}): string {\n const safeRunId = input.runId.replace(/[^a-zA-Z0-9._-]/g, \"-\");\n const root = input.worktreeRoot ?? `${input.workspacePath.replace(/\\/$/, \"\")}/.worktrees/opentag`;\n return `${root.replace(/\\/$/, \"\")}/${safeRunId}`;\n}\n\nexport async function createRunWorktree(input: {\n runner: CommandRunner;\n workspacePath: string;\n worktreePath: string;\n branchName: string;\n baseBranch: string;\n}): Promise<void> {\n mkdirSync(dirname(input.worktreePath), { recursive: true });\n const result = await input.runner.run(\n \"git\",\n [\"worktree\", \"add\", \"-B\", input.branchName, input.worktreePath, input.baseBranch],\n { cwd: input.workspacePath }\n );\n await assertCommandSucceeded(result, \"create run worktree\");\n}\n\nexport async function removeRunWorktree(input: {\n runner: CommandRunner;\n workspacePath: string;\n worktreePath: string;\n}): Promise<void> {\n const result = await input.runner.run(\"git\", [\"worktree\", \"remove\", \"--force\", input.worktreePath], {\n cwd: input.workspacePath\n });\n await assertCommandSucceeded(result, \"remove run worktree\");\n}\n\nexport async function deleteRunBranch(input: { runner: CommandRunner; workspacePath: string; branchName: string }): Promise<void> {\n const result = await input.runner.run(\"git\", [\"branch\", \"-D\", input.branchName], {\n cwd: input.workspacePath\n });\n await assertCommandSucceeded(result, \"delete empty run branch\");\n}\n\nexport async function changedFiles(input: { runner: CommandRunner; workspacePath: string }): Promise<string[]> {\n const result = await input.runner.run(\"git\", [\"status\", \"--porcelain\"], { cwd: input.workspacePath });\n await assertCommandSucceeded(result, \"read changed files\");\n return parseChangedFiles(result.stdout);\n}\n\nexport async function cleanupInternalArtifacts(input: { runner: CommandRunner; workspacePath: string }): Promise<string[]> {\n const statusResult = await input.runner.run(\"git\", [\"status\", \"--porcelain\"], { cwd: input.workspacePath });\n await assertCommandSucceeded(statusResult, \"scan internal artifacts\");\n const untrackedRoots = Array.from(\n new Set(\n parseStatusEntries(statusResult.stdout)\n .filter((entry) => entry.status === \"??\" && isInternalArtifactPath(entry.path))\n .map((entry) => entry.path.split(\"/\", 1)[0] ?? entry.path)\n )\n );\n if (untrackedRoots.length === 0) return [];\n\n const cleanResult = await input.runner.run(\"git\", [\"clean\", \"-fd\", \"--\", ...untrackedRoots], {\n cwd: input.workspacePath\n });\n await assertCommandSucceeded(cleanResult, \"clean internal artifacts\");\n return untrackedRoots;\n}\n\nexport async function commitRunChanges(input: {\n runner: CommandRunner;\n workspacePath: string;\n message: string;\n}): Promise<boolean> {\n const files = await changedFiles({ runner: input.runner, workspacePath: input.workspacePath });\n if (files.length === 0) return false;\n\n const addResult = await input.runner.run(\"git\", [\"add\", \"--\", ...files], {\n cwd: input.workspacePath\n });\n await assertCommandSucceeded(addResult, \"stage run changes\");\n\n const commitResult = await input.runner.run(\"git\", [\"commit\", \"-m\", input.message], {\n cwd: input.workspacePath\n });\n await assertCommandSucceeded(commitResult, \"commit run changes\");\n return true;\n}\n\nexport async function commitChangedFiles(input: {\n runner: CommandRunner;\n workspacePath: string;\n files: string[];\n message: string;\n}): Promise<void> {\n if (input.files.length === 0) return;\n const addResult = await input.runner.run(\"git\", [\"add\", \"--\", ...input.files], { cwd: input.workspacePath });\n await assertCommandSucceeded(addResult, \"stage changed files\");\n const commitResult = await input.runner.run(\"git\", [\"commit\", \"-m\", input.message], { cwd: input.workspacePath });\n await assertCommandSucceeded(commitResult, \"commit changed files\");\n}\n\nexport async function pushBranch(input: {\n runner: CommandRunner;\n workspacePath: string;\n remote: string;\n branchName: string;\n}): Promise<void> {\n const result = await input.runner.run(\"git\", [\"push\", \"-u\", input.remote, input.branchName], { cwd: input.workspacePath });\n await assertCommandSucceeded(result, \"push run branch\");\n}\n","import type { OpenTagRunResult } from \"@opentag/core\";\n\nexport function createExecutorRunResult(input: {\n executorName: string;\n runId: string;\n branchName: string;\n baseBranch?: string;\n output: string;\n changedFiles: string[];\n extraArtifacts?: NonNullable<OpenTagRunResult[\"artifacts\"]>;\n}): OpenTagRunResult {\n const proposalId = `proposal_${input.runId}`;\n const summary = input.output.slice(-4000);\n const suggestedChanges =\n input.changedFiles.length > 0\n ? [\n {\n proposalId,\n createdAt: new Date().toISOString(),\n sourceRunId: input.runId,\n summary: `${input.executorName} changed ${input.changedFiles.length} file(s) on branch ${input.branchName}.`,\n intents: [\n {\n intentId: `${proposalId}_create_pr`,\n domain: \"pull_request\" as const,\n action: \"create_pull_request\",\n summary: `Create a pull request for branch ${input.branchName}.`,\n params: {\n title: `OpenTag run ${input.runId}`,\n body: [\n \"## Summary\",\n \"\",\n summary\n ].join(\"\\n\"),\n head: input.branchName,\n base: input.baseBranch ?? \"main\",\n changedFiles: input.changedFiles,\n risks: [\"Creates a pull request from the executor-produced branch; review the diff before merging.\"],\n executorConditions: [\"isolated branch exists\"]\n }\n },\n {\n intentId: `${proposalId}_link_branch`,\n domain: \"artifact_links\" as const,\n action: \"link_artifact\",\n summary: `Link the run branch ${input.branchName} to the work item.`,\n params: { title: \"Run branch\", uri: input.branchName }\n },\n {\n intentId: `${proposalId}_request_review`,\n domain: \"review\" as const,\n action: \"request_review\",\n summary: \"Request human review of the generated code changes.\",\n params: { changedFiles: input.changedFiles }\n }\n ],\n preconditions: [\"The local branch was generated from the checkout state available to the runner.\"]\n }\n ]\n : undefined;\n\n return {\n conclusion: \"success\",\n summary,\n changedFiles: input.changedFiles,\n artifacts: [\n ...(input.changedFiles.length > 0 ? [{ kind: \"patch\" as const, title: \"Run branch\", uri: input.branchName }] : []),\n ...(input.extraArtifacts ?? [])\n ],\n ...(suggestedChanges ? { suggestedChanges } : {}),\n nextAction:\n input.changedFiles.length > 0\n ? {\n summary: \"Review the proposed pull request action and reply `apply 1` if the branch should become a PR.\",\n hint: {\n kind: \"create_pull_request\",\n targetId: proposalId,\n selectedIntentIds: [`${proposalId}_create_pr`]\n }\n }\n : \"No file changes were detected.\"\n };\n}\n","import { contextPointerLabel, type ContextPacket, type ContextPointer } from \"@opentag/core\";\nimport { assertCommandSucceeded, nodeCommandRunner, type CommandRunner } from \"./command.js\";\nimport { renderContextPacketForPrompt, type ExecutorAdapter } from \"./executor.js\";\nimport {\n branchNameForRun,\n changedFiles,\n cleanupInternalArtifacts,\n commitRunChanges,\n createRunWorktree,\n deleteRunBranch,\n removeRunWorktree,\n worktreePathForRun\n} from \"./git.js\";\nimport { createExecutorRunResult } from \"./result.js\";\nimport { assessRunnerSecurity, formatSecurityAssessment, scrubEnvironment, type RunnerSecurityPolicy } from \"./security.js\";\n\nexport type CodexExecutorOptions = {\n runner?: CommandRunner;\n codexCommand?: string;\n model?: string;\n security?: RunnerSecurityPolicy;\n};\n\nfunction contextLines(context: ContextPointer[]): string {\n if (!context.length) return \"No additional context pointers were provided.\";\n return context.map((pointer) => `- ${contextPointerLabel(pointer)}: ${pointer.uri}`).join(\"\\n\");\n}\n\nfunction buildPrompt(input: {\n runId: string;\n rawText: string;\n context: ContextPointer[];\n contextPacket: ContextPacket | undefined;\n}): string {\n return [\n \"You are executing an OpenTag run in a local checkout.\",\n `Run ID: ${input.runId}`,\n \"\",\n \"User request:\",\n input.rawText,\n \"\",\n ...renderContextPacketForPrompt(input.contextPacket),\n ...(input.contextPacket ? [\"\"] : []),\n \"Context pointers:\",\n contextLines(input.context),\n \"\",\n \"Work autonomously but keep the change narrow. Run relevant verification if you modify files. End with a concise summary.\"\n ].join(\"\\n\");\n}\n\nexport function createCodexExecutor(options: CodexExecutorOptions = {}): ExecutorAdapter {\n const runner = options.runner ?? nodeCommandRunner;\n const codexCommand = options.codexCommand ?? \"codex\";\n\n return {\n id: \"codex\",\n displayName: \"Codex Executor\",\n async canRun(input) {\n const codexVersion = await runner.run(codexCommand, [\"--version\"], { cwd: input.workspacePath });\n if (codexVersion.exitCode !== 0) {\n return { ready: false, reason: `Codex CLI is not available: ${codexVersion.stderr || codexVersion.stdout}` };\n }\n const gitRepo = await runner.run(\"git\", [\"rev-parse\", \"--show-toplevel\"], { cwd: input.workspacePath });\n if (gitRepo.exitCode !== 0) {\n return { ready: false, reason: `Workspace is not a git checkout: ${gitRepo.stderr || gitRepo.stdout}` };\n }\n const baseBranch = input.baseBranch ?? \"main\";\n const baseRef = await runner.run(\"git\", [\"rev-parse\", \"--verify\", `${baseBranch}^{commit}`], {\n cwd: input.workspacePath\n });\n if (baseRef.exitCode !== 0) {\n return { ready: false, reason: `Base branch '${baseBranch}' is not available: ${baseRef.stderr || baseRef.stdout}` };\n }\n return { ready: true };\n },\n async run(input, sink) {\n const security = options.security;\n const worktreePath = worktreePathForRun({\n workspacePath: input.workspacePath,\n runId: input.runId,\n ...(input.worktreeRoot ? { worktreeRoot: input.worktreeRoot } : {})\n });\n const assessment = assessRunnerSecurity({\n executorId: \"codex\",\n workspacePath: input.workspacePath,\n executionPath: worktreePath,\n command: input.command,\n context: input.context,\n ...(input.permissions ? { permissions: input.permissions } : {}),\n ...(security ? { policy: security } : {})\n });\n if (assessment.findings.length > 0) {\n await sink.emit({\n type: assessment.allowed ? \"executor.progress\" : \"executor.failed\",\n message: formatSecurityAssessment(assessment),\n at: new Date().toISOString()\n });\n }\n if (!assessment.allowed) {\n return {\n conclusion: \"needs_human\",\n summary: formatSecurityAssessment(assessment),\n nextAction: \"Review the request and rerun with a narrower prompt or an explicit local policy override if appropriate.\"\n };\n }\n\n const branchName = branchNameForRun(input.runId);\n const baseBranch = input.baseBranch ?? \"main\";\n const keepWorktree = input.keepWorktree ?? \"on_failure\";\n let completed = false;\n let changedFileCount: number | undefined;\n\n await sink.emit({\n type: \"executor.started\",\n message: `Creating isolated worktree ${worktreePath} on ${branchName}`,\n at: new Date().toISOString()\n });\n try {\n await createRunWorktree({\n runner,\n workspacePath: input.workspacePath,\n worktreePath,\n branchName,\n baseBranch\n });\n\n await sink.emit({\n type: \"executor.progress\",\n message: \"Starting codex exec\",\n at: new Date().toISOString()\n });\n\n const args = [\n \"exec\",\n \"--cd\",\n worktreePath,\n \"--full-auto\",\n \"--ephemeral\",\n ...(options.model ? [\"--model\", options.model] : []),\n \"-\"\n ];\n const codexResult = await runner.run(codexCommand, args, {\n cwd: worktreePath,\n env: scrubEnvironment(undefined, security),\n input: buildPrompt({\n runId: input.runId,\n rawText: input.command.rawText,\n context: input.context,\n contextPacket: input.contextPacket\n })\n });\n await assertCommandSucceeded(codexResult, \"codex exec\");\n\n const cleanedArtifacts = await cleanupInternalArtifacts({ runner, workspacePath: worktreePath });\n if (cleanedArtifacts.length > 0) {\n await sink.emit({\n type: \"executor.progress\",\n message: `Cleaned internal artifacts: ${cleanedArtifacts.join(\", \")}`,\n at: new Date().toISOString()\n });\n }\n\n const files = await changedFiles({ runner, workspacePath: worktreePath });\n changedFileCount = files.length;\n if (files.length > 0) {\n await sink.emit({\n type: \"executor.progress\",\n message: `Committing ${files.length} changed file(s) to ${branchName}`,\n at: new Date().toISOString()\n });\n await commitRunChanges({\n runner,\n workspacePath: worktreePath,\n message: `OpenTag run ${input.runId}`\n });\n }\n completed = true;\n\n await sink.emit({\n type: \"executor.completed\",\n message: `Codex executor completed with ${files.length} changed file(s)`,\n at: new Date().toISOString()\n });\n\n const output = codexResult.stdout.trim() || codexResult.stderr.trim() || \"Codex completed without textual output.\";\n return createExecutorRunResult({\n executorName: \"Codex\",\n runId: input.runId,\n branchName,\n ...(input.baseBranch ? { baseBranch: input.baseBranch } : {}),\n output,\n changedFiles: files,\n extraArtifacts: keepWorktree === \"always\" ? [{ title: \"Run worktree\", uri: worktreePath }] : []\n });\n } finally {\n const shouldRemove = keepWorktree === \"never\" || (keepWorktree === \"on_failure\" && completed);\n if (shouldRemove) {\n try {\n await removeRunWorktree({ runner, workspacePath: input.workspacePath, worktreePath });\n if (completed && changedFileCount === 0) {\n await deleteRunBranch({ runner, workspacePath: input.workspacePath, branchName });\n }\n } catch (error) {\n await sink.emit({\n type: \"executor.progress\",\n message: `Could not clean up run worktree or branch for ${worktreePath}: ${error instanceof Error ? error.message : String(error)}`,\n at: new Date().toISOString()\n });\n }\n }\n }\n },\n async cancel() {\n return;\n }\n };\n}\n","import { fileURLToPath } from \"node:url\";\nimport { isAbsolute, relative, resolve } from \"node:path\";\nimport type { ContextPointer, OpenTagCommand, PermissionGrant } from \"@opentag/core\";\nimport type { CommandEnvironment } from \"./command.js\";\n\nexport type RunnerSecurityMode = \"enforce\" | \"audit\" | \"off\";\n\nexport type RunnerSecurityPolicy = {\n mode?: RunnerSecurityMode;\n allowedWorkspaceRoot?: string;\n allowUnsafePrompts?: boolean;\n extraSafeEnv?: string[];\n};\n\nexport type RunnerSecurityFinding = {\n code: string;\n severity: \"block\" | \"warn\";\n message: string;\n};\n\nexport type RunnerSecurityAssessment = {\n allowed: boolean;\n mode: RunnerSecurityMode;\n findings: RunnerSecurityFinding[];\n};\n\nexport const DEFAULT_SAFE_ENV_NAMES = [\n \"CI\",\n \"COLORTERM\",\n \"CODEX_HOME\",\n \"FORCE_COLOR\",\n \"HOME\",\n \"LANG\",\n \"LOGNAME\",\n \"NO_COLOR\",\n \"PATH\",\n \"PWD\",\n \"SHELL\",\n \"SSL_CERT_DIR\",\n \"SSL_CERT_FILE\",\n \"TERM\",\n \"TMP\",\n \"TMPDIR\",\n \"TEMP\",\n \"USER\",\n \"XDG_CACHE_HOME\",\n \"XDG_CONFIG_HOME\",\n \"XDG_DATA_HOME\"\n];\n\nconst SAFE_ENV_PREFIXES = [\"LC_\"];\n\nconst SENSITIVE_ENV_PATTERNS = [\n /TOKEN/,\n /SECRET/,\n /PASSWORD/,\n /PASS$/,\n /API[_-]?KEY/,\n /CREDENTIAL/,\n /COOKIE/,\n /SESSION/,\n /AUTH/,\n /^AWS_/,\n /^AZURE_/,\n /^GCP_/,\n /^GOOGLE_/,\n /^OPENAI_/,\n /^ANTHROPIC_/,\n /^SLACK_/,\n /^GITHUB_TOKEN$/,\n /^GH_TOKEN$/,\n /^SSH_/\n];\n\nconst HIGH_RISK_TEXT_PATTERNS: Array<{ code: string; pattern: RegExp; message: string }> = [\n {\n code: \"prompt.instruction_override\",\n pattern: /\\b(ignore|disregard|forget)\\s+(all\\s+)?(previous|prior|system|developer|safety)\\s+instructions\\b/i,\n message: \"Request contains an instruction override pattern commonly used in prompt injection.\"\n },\n {\n code: \"prompt.secret_exfiltration\",\n pattern:\n /\\b(print|dump|show|reveal|exfiltrate|send|upload|post|copy)\\b[\\s\\S]{0,100}\\b(secret|token|password|api[\\s_-]?key|credential|environment variables?|env vars?)\\b/i,\n message: \"Request appears to ask the runner to expose secrets or environment variables.\"\n },\n {\n code: \"prompt.sensitive_file_access\",\n pattern: /\\b(cat|open|read|print|dump)\\b[\\s\\S]{0,80}(~\\/\\.ssh|~\\/\\.aws|\\.env\\b|id_rsa|known_hosts|credentials\\b)/i,\n message: \"Request appears to ask the runner to read sensitive local credential files.\"\n }\n];\n\nfunction securityMode(policy: RunnerSecurityPolicy | undefined): RunnerSecurityMode {\n return policy?.mode ?? \"enforce\";\n}\n\nfunction isPathInside(childPath: string, parentPath: string): boolean {\n const child = resolve(childPath);\n const parent = resolve(parentPath);\n const pathFromParent = relative(parent, child);\n return pathFromParent === \"\" || (!pathFromParent.startsWith(\"..\") && !isAbsolute(pathFromParent));\n}\n\nfunction fileContextPath(pointer: ContextPointer, workspacePath: string): string | null {\n if (pointer.kind !== \"file\") return null;\n if (pointer.uri.startsWith(\"file://\")) {\n return fileURLToPath(pointer.uri);\n }\n if (isAbsolute(pointer.uri)) {\n return pointer.uri;\n }\n return resolve(workspacePath, pointer.uri);\n}\n\nfunction hasPermission(permissions: PermissionGrant[] | undefined, scope: string): boolean {\n return permissions?.some((permission) => permission.scope === scope) ?? false;\n}\n\nfunction needsWritePermission(command: OpenTagCommand, executorId: string): boolean {\n if (executorId === \"echo\") return false;\n return command.intent === \"fix\" || command.intent === \"run\";\n}\n\nfunction scanTextForHighRiskPatterns(input: { command: OpenTagCommand; context: ContextPointer[] }): RunnerSecurityFinding[] {\n const sources = [\n { label: \"command\", text: input.command.rawText },\n ...input.context\n .filter((pointer) => pointer.kind === \"text\")\n .map((pointer) => ({ label: pointer.title ?? \"text context\", text: pointer.uri }))\n ];\n\n const findings: RunnerSecurityFinding[] = [];\n for (const source of sources) {\n for (const rule of HIGH_RISK_TEXT_PATTERNS) {\n if (rule.pattern.test(source.text)) {\n findings.push({\n code: rule.code,\n severity: \"block\",\n message: `${rule.message} Source: ${source.label}.`\n });\n }\n }\n }\n return findings;\n}\n\nexport function assessRunnerSecurity(input: {\n executorId: string;\n workspacePath: string;\n executionPath?: string;\n command: OpenTagCommand;\n context: ContextPointer[];\n permissions?: PermissionGrant[];\n policy?: RunnerSecurityPolicy;\n}): RunnerSecurityAssessment {\n const mode = securityMode(input.policy);\n if (mode === \"off\") {\n return { allowed: true, mode, findings: [] };\n }\n\n const findings: RunnerSecurityFinding[] = [];\n if (!isAbsolute(input.workspacePath)) {\n findings.push({\n code: \"workspace.relative_path\",\n severity: \"block\",\n message: \"Workspace path must be absolute before a local executor can run.\"\n });\n }\n\n const workspacePath = resolve(input.workspacePath);\n const executionPath = resolve(input.executionPath ?? input.workspacePath);\n if (input.policy?.allowedWorkspaceRoot && !isPathInside(workspacePath, input.policy.allowedWorkspaceRoot)) {\n findings.push({\n code: \"workspace.outside_allowed_root\",\n severity: \"block\",\n message: \"Workspace path is outside the configured allowed workspace root.\"\n });\n }\n if (input.policy?.allowedWorkspaceRoot && !isPathInside(executionPath, input.policy.allowedWorkspaceRoot)) {\n findings.push({\n code: \"execution.outside_allowed_root\",\n severity: \"block\",\n message: \"Execution path is outside the configured allowed workspace root.\"\n });\n }\n\n for (const pointer of input.context) {\n const filePath = fileContextPath(pointer, workspacePath);\n if (filePath && !isPathInside(filePath, workspacePath)) {\n findings.push({\n code: \"context.file_outside_workspace\",\n severity: \"block\",\n message: `File context is outside the mapped workspace: ${pointer.uri}`\n });\n }\n }\n\n if (needsWritePermission(input.command, input.executorId) && !hasPermission(input.permissions, \"repo:write\")) {\n findings.push({\n code: \"permission.repo_write_required\",\n severity: \"block\",\n message: \"Write-capable commands require an explicit repo:write permission grant.\"\n });\n }\n\n if (!input.policy?.allowUnsafePrompts) {\n findings.push(...scanTextForHighRiskPatterns({ command: input.command, context: input.context }));\n }\n\n const hasBlockingFinding = findings.some((finding) => finding.severity === \"block\");\n return {\n allowed: mode === \"audit\" || !hasBlockingFinding,\n mode,\n findings\n };\n}\n\nfunction isSensitiveEnvName(name: string): boolean {\n const upperName = name.toUpperCase();\n return SENSITIVE_ENV_PATTERNS.some((pattern) => pattern.test(upperName));\n}\n\nfunction isSafeEnvName(name: string, policy: RunnerSecurityPolicy | undefined): boolean {\n const upperName = name.toUpperCase();\n const safeNames = new Set([...DEFAULT_SAFE_ENV_NAMES, ...(policy?.extraSafeEnv ?? [])].map((envName) => envName.toUpperCase()));\n return safeNames.has(upperName) || SAFE_ENV_PREFIXES.some((prefix) => upperName.startsWith(prefix));\n}\n\nexport function scrubEnvironment(env: CommandEnvironment = process.env, policy?: RunnerSecurityPolicy): CommandEnvironment {\n if (securityMode(policy) === \"off\") return { ...env };\n\n const scrubbed: CommandEnvironment = {};\n for (const [name, value] of Object.entries(env)) {\n if (typeof value !== \"string\") continue;\n if (isSensitiveEnvName(name)) continue;\n if (!isSafeEnvName(name, policy)) continue;\n scrubbed[name] = value;\n }\n return scrubbed;\n}\n\nexport function formatSecurityAssessment(assessment: RunnerSecurityAssessment): string {\n if (assessment.findings.length === 0) {\n return `OpenTag runner security assessment passed in ${assessment.mode} mode.`;\n }\n\n const prefix = assessment.allowed\n ? `OpenTag runner security assessment reported ${assessment.findings.length} finding(s) in ${assessment.mode} mode.`\n : \"OpenTag runner security blocked this run.\";\n const details = assessment.findings.map((finding) => `${finding.code}: ${finding.message}`).join(\" \");\n return `${prefix} ${details}`;\n}\n","import type { ExecutorAdapter } from \"./executor.js\";\n\nfunction nowIso(): string {\n return new Date().toISOString();\n}\n\nexport function createEchoExecutor(): ExecutorAdapter {\n return {\n id: \"echo\",\n displayName: \"Echo Executor\",\n async canRun() {\n return { ready: true };\n },\n async run(input, sink) {\n await sink.emit({\n type: \"executor.started\",\n message: `Echo executor started for ${input.runId}`,\n at: nowIso()\n });\n await sink.emit({\n type: \"executor.completed\",\n message: `Echo executor completed for ${input.runId}`,\n at: nowIso()\n });\n return {\n conclusion: \"success\",\n summary: `Echoed OpenTag command: ${input.command.rawText}`,\n verification: [\n {\n command: \"echo\",\n outcome: \"passed\",\n excerpt: input.command.rawText\n }\n ],\n nextAction: {\n summary: \"No external state change is suggested for the echo executor result.\",\n hint: { kind: \"none\" }\n }\n };\n },\n async cancel() {\n return;\n }\n };\n}\n"],"mappings":"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","names":["contextPointerLabel","resolve","contextPointerLabel","contextPointerLabel","contextLines","contextPointerLabel","buildPrompt"]}
@@ -0,0 +1,11 @@
1
+ import type { OpenTagRunResult } from "@opentag/core";
2
+ export declare function createExecutorRunResult(input: {
3
+ executorName: string;
4
+ runId: string;
5
+ branchName: string;
6
+ baseBranch?: string;
7
+ output: string;
8
+ changedFiles: string[];
9
+ extraArtifacts?: NonNullable<OpenTagRunResult["artifacts"]>;
10
+ }): OpenTagRunResult;
11
+ //# sourceMappingURL=result.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"result.d.ts","sourceRoot":"","sources":["../src/result.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAEtD,wBAAgB,uBAAuB,CAAC,KAAK,EAAE;IAC7C,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,cAAc,CAAC,EAAE,WAAW,CAAC,gBAAgB,CAAC,WAAW,CAAC,CAAC,CAAC;CAC7D,GAAG,gBAAgB,CAwEnB"}
@@ -0,0 +1,32 @@
1
+ import type { ContextPointer, OpenTagCommand, PermissionGrant } from "@opentag/core";
2
+ import type { CommandEnvironment } from "./command.js";
3
+ export type RunnerSecurityMode = "enforce" | "audit" | "off";
4
+ export type RunnerSecurityPolicy = {
5
+ mode?: RunnerSecurityMode;
6
+ allowedWorkspaceRoot?: string;
7
+ allowUnsafePrompts?: boolean;
8
+ extraSafeEnv?: string[];
9
+ };
10
+ export type RunnerSecurityFinding = {
11
+ code: string;
12
+ severity: "block" | "warn";
13
+ message: string;
14
+ };
15
+ export type RunnerSecurityAssessment = {
16
+ allowed: boolean;
17
+ mode: RunnerSecurityMode;
18
+ findings: RunnerSecurityFinding[];
19
+ };
20
+ export declare const DEFAULT_SAFE_ENV_NAMES: string[];
21
+ export declare function assessRunnerSecurity(input: {
22
+ executorId: string;
23
+ workspacePath: string;
24
+ executionPath?: string;
25
+ command: OpenTagCommand;
26
+ context: ContextPointer[];
27
+ permissions?: PermissionGrant[];
28
+ policy?: RunnerSecurityPolicy;
29
+ }): RunnerSecurityAssessment;
30
+ export declare function scrubEnvironment(env?: CommandEnvironment, policy?: RunnerSecurityPolicy): CommandEnvironment;
31
+ export declare function formatSecurityAssessment(assessment: RunnerSecurityAssessment): string;
32
+ //# sourceMappingURL=security.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"security.d.ts","sourceRoot":"","sources":["../src/security.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AACrF,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAEvD,MAAM,MAAM,kBAAkB,GAAG,SAAS,GAAG,OAAO,GAAG,KAAK,CAAC;AAE7D,MAAM,MAAM,oBAAoB,GAAG;IACjC,IAAI,CAAC,EAAE,kBAAkB,CAAC;IAC1B,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,OAAO,GAAG,MAAM,CAAC;IAC3B,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,wBAAwB,GAAG;IACrC,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,kBAAkB,CAAC;IACzB,QAAQ,EAAE,qBAAqB,EAAE,CAAC;CACnC,CAAC;AAEF,eAAO,MAAM,sBAAsB,UAsBlC,CAAC;AAmGF,wBAAgB,oBAAoB,CAAC,KAAK,EAAE;IAC1C,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,OAAO,EAAE,cAAc,CAAC;IACxB,OAAO,EAAE,cAAc,EAAE,CAAC;IAC1B,WAAW,CAAC,EAAE,eAAe,EAAE,CAAC;IAChC,MAAM,CAAC,EAAE,oBAAoB,CAAC;CAC/B,GAAG,wBAAwB,CA6D3B;AAaD,wBAAgB,gBAAgB,CAAC,GAAG,GAAE,kBAAgC,EAAE,MAAM,CAAC,EAAE,oBAAoB,GAAG,kBAAkB,CAWzH;AAED,wBAAgB,wBAAwB,CAAC,UAAU,EAAE,wBAAwB,GAAG,MAAM,CAUrF"}
package/package.json CHANGED
@@ -1,8 +1,11 @@
1
1
  {
2
2
  "name": "@opentag/runner",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Executor contracts and built-in runner adapters for OpenTag.",
5
5
  "type": "module",
6
+ "engines": {
7
+ "node": ">=20"
8
+ },
6
9
  "main": "./dist/index.js",
7
10
  "types": "./dist/index.d.ts",
8
11
  "exports": {
@@ -26,9 +29,9 @@
26
29
  "codex",
27
30
  "agents"
28
31
  ],
29
- "license": "Apache-2.0",
32
+ "license": "MIT",
30
33
  "dependencies": {
31
- "@opentag/core": "0.1.0"
34
+ "@opentag/core": "0.2.0"
32
35
  },
33
36
  "devDependencies": {
34
37
  "tsup": "^8.3.5",