@provos/ironcurtain 0.6.0 → 0.7.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/README.md +21 -2
- package/dist/cli-help.d.ts +63 -0
- package/dist/cli-help.js +102 -0
- package/dist/cli-help.js.map +1 -0
- package/dist/cli.js +73 -56
- package/dist/cli.js.map +1 -1
- package/dist/config/config-command.js +136 -2
- package/dist/config/config-command.js.map +1 -1
- package/dist/config/generated/tool-annotations.json +487 -338
- package/dist/config/index.d.ts +21 -1
- package/dist/config/index.js +12 -4
- package/dist/config/index.js.map +1 -1
- package/dist/config/mcp-servers.json +2 -8
- package/dist/config/paths.d.ts +30 -0
- package/dist/config/paths.js +58 -0
- package/dist/config/paths.js.map +1 -1
- package/dist/config/tool-description-hints.json +15 -0
- package/dist/config/types.d.ts +7 -0
- package/dist/config/user-config.d.ts +21 -0
- package/dist/config/user-config.js +8 -0
- package/dist/config/user-config.js.map +1 -1
- package/dist/cron/compile-task-policy.d.ts +17 -0
- package/dist/cron/compile-task-policy.js +39 -0
- package/dist/cron/compile-task-policy.js.map +1 -0
- package/dist/cron/cron-scheduler.d.ts +65 -0
- package/dist/cron/cron-scheduler.js +184 -0
- package/dist/cron/cron-scheduler.js.map +1 -0
- package/dist/cron/file-lock.d.ts +41 -0
- package/dist/cron/file-lock.js +156 -0
- package/dist/cron/file-lock.js.map +1 -0
- package/dist/cron/format-utils.d.ts +18 -0
- package/dist/cron/format-utils.js +145 -0
- package/dist/cron/format-utils.js.map +1 -0
- package/dist/cron/git-sync.d.ts +22 -0
- package/dist/cron/git-sync.js +121 -0
- package/dist/cron/git-sync.js.map +1 -0
- package/dist/cron/headless-transport.d.ts +27 -0
- package/dist/cron/headless-transport.js +43 -0
- package/dist/cron/headless-transport.js.map +1 -0
- package/dist/cron/job-commands.d.ts +39 -0
- package/dist/cron/job-commands.js +522 -0
- package/dist/cron/job-commands.js.map +1 -0
- package/dist/cron/job-store.d.ts +35 -0
- package/dist/cron/job-store.js +111 -0
- package/dist/cron/job-store.js.map +1 -0
- package/dist/cron/types.d.ts +127 -0
- package/dist/cron/types.js +25 -0
- package/dist/cron/types.js.map +1 -0
- package/dist/daemon/control-socket.d.ts +127 -0
- package/dist/daemon/control-socket.js +261 -0
- package/dist/daemon/control-socket.js.map +1 -0
- package/dist/daemon/daemon-command.d.ts +13 -0
- package/dist/daemon/daemon-command.js +230 -0
- package/dist/daemon/daemon-command.js.map +1 -0
- package/dist/daemon/ironcurtain-daemon.d.ts +90 -0
- package/dist/daemon/ironcurtain-daemon.js +548 -0
- package/dist/daemon/ironcurtain-daemon.js.map +1 -0
- package/dist/docker/adapters/claude-code.js +7 -47
- package/dist/docker/adapters/claude-code.js.map +1 -1
- package/dist/docker/adapters/goose.d.ts +58 -0
- package/dist/docker/adapters/goose.js +250 -0
- package/dist/docker/adapters/goose.js.map +1 -0
- package/dist/docker/adapters/shared-scripts.d.ts +29 -0
- package/dist/docker/adapters/shared-scripts.js +80 -0
- package/dist/docker/adapters/shared-scripts.js.map +1 -0
- package/dist/docker/agent-adapter.d.ts +12 -0
- package/dist/docker/agent-adapter.js.map +1 -1
- package/dist/docker/agent-registry.d.ts +6 -1
- package/dist/docker/agent-registry.js +10 -1
- package/dist/docker/agent-registry.js.map +1 -1
- package/dist/docker/docker-agent-session.d.ts +2 -25
- package/dist/docker/docker-agent-session.js +7 -106
- package/dist/docker/docker-agent-session.js.map +1 -1
- package/dist/docker/docker-infrastructure.d.ts +8 -0
- package/dist/docker/docker-infrastructure.js +12 -11
- package/dist/docker/docker-infrastructure.js.map +1 -1
- package/dist/docker/pty-session.js +7 -4
- package/dist/docker/pty-session.js.map +1 -1
- package/dist/escalation/escalation-watcher.d.ts +2 -0
- package/dist/escalation/escalation-watcher.js +3 -0
- package/dist/escalation/escalation-watcher.js.map +1 -1
- package/dist/escalation/session-registry.js +1 -14
- package/dist/escalation/session-registry.js.map +1 -1
- package/dist/index.js +30 -1
- package/dist/index.js.map +1 -1
- package/dist/mux/mux-app.js +11 -6
- package/dist/mux/mux-app.js.map +1 -1
- package/dist/mux/mux-command.js +20 -9
- package/dist/mux/mux-command.js.map +1 -1
- package/dist/mux/mux-input-handler.d.ts +5 -0
- package/dist/mux/mux-input-handler.js +64 -9
- package/dist/mux/mux-input-handler.js.map +1 -1
- package/dist/mux/mux-renderer.d.ts +20 -0
- package/dist/mux/mux-renderer.js +127 -35
- package/dist/mux/mux-renderer.js.map +1 -1
- package/dist/mux/mux-splash.js +2 -1
- package/dist/mux/mux-splash.js.map +1 -1
- package/dist/mux/paste-interceptor.d.ts +22 -0
- package/dist/mux/paste-interceptor.js +143 -0
- package/dist/mux/paste-interceptor.js.map +1 -0
- package/dist/mux/pty-bridge.js +1 -1
- package/dist/mux/pty-bridge.js.map +1 -1
- package/dist/mux/types.d.ts +8 -1
- package/dist/mux/types.js +17 -5
- package/dist/mux/types.js.map +1 -1
- package/dist/pipeline/annotate.js +2 -1
- package/dist/pipeline/annotate.js.map +1 -1
- package/dist/pipeline/compile.d.ts +4 -34
- package/dist/pipeline/compile.js +29 -568
- package/dist/pipeline/compile.js.map +1 -1
- package/dist/pipeline/constitution-compiler.js +1 -1
- package/dist/pipeline/mcp-connections.d.ts +16 -0
- package/dist/pipeline/mcp-connections.js +61 -0
- package/dist/pipeline/mcp-connections.js.map +1 -0
- package/dist/pipeline/pipeline-runner.d.ts +86 -0
- package/dist/pipeline/pipeline-runner.js +554 -0
- package/dist/pipeline/pipeline-runner.js.map +1 -0
- package/dist/pipeline/pipeline-shared.d.ts +29 -2
- package/dist/pipeline/pipeline-shared.js +68 -12
- package/dist/pipeline/pipeline-shared.js.map +1 -1
- package/dist/pipeline/refresh-lists.js +38 -12
- package/dist/pipeline/refresh-lists.js.map +1 -1
- package/dist/pipeline/scenario-generator.js +2 -1
- package/dist/pipeline/scenario-generator.js.map +1 -1
- package/dist/pipeline/tool-annotator.d.ts +3 -3
- package/dist/pipeline/tool-annotator.js +96 -4
- package/dist/pipeline/tool-annotator.js.map +1 -1
- package/dist/pipeline/types.d.ts +52 -0
- package/dist/sandbox/index.js +36 -1
- package/dist/sandbox/index.js.map +1 -1
- package/dist/session/agent-session.d.ts +3 -0
- package/dist/session/agent-session.js +10 -1
- package/dist/session/agent-session.js.map +1 -1
- package/dist/session/index.js +54 -5
- package/dist/session/index.js.map +1 -1
- package/dist/session/preflight.js +26 -6
- package/dist/session/preflight.js.map +1 -1
- package/dist/session/prompts.d.ts +14 -0
- package/dist/session/prompts.js +39 -2
- package/dist/session/prompts.js.map +1 -1
- package/dist/session/session-manager.d.ts +105 -0
- package/dist/session/session-manager.js +134 -0
- package/dist/session/session-manager.js.map +1 -0
- package/dist/session/types.d.ts +27 -0
- package/dist/session/workspace-validation.d.ts +2 -0
- package/dist/session/workspace-validation.js +6 -5
- package/dist/session/workspace-validation.js.map +1 -1
- package/dist/signal/bot-command.d.ts +2 -0
- package/dist/signal/bot-command.js +8 -0
- package/dist/signal/bot-command.js.map +1 -1
- package/dist/signal/format.d.ts +27 -0
- package/dist/signal/format.js +59 -0
- package/dist/signal/format.js.map +1 -1
- package/dist/signal/signal-bot-daemon.d.ts +27 -25
- package/dist/signal/signal-bot-daemon.js +145 -130
- package/dist/signal/signal-bot-daemon.js.map +1 -1
- package/dist/signal/signal-container.js +63 -19
- package/dist/signal/signal-container.js.map +1 -1
- package/dist/signal/signal-transport.js +3 -8
- package/dist/signal/signal-transport.js.map +1 -1
- package/dist/trusted-process/domain-utils.d.ts +38 -4
- package/dist/trusted-process/domain-utils.js +118 -11
- package/dist/trusted-process/domain-utils.js.map +1 -1
- package/dist/trusted-process/index.js +6 -2
- package/dist/trusted-process/index.js.map +1 -1
- package/dist/trusted-process/mcp-client-manager.js +11 -5
- package/dist/trusted-process/mcp-client-manager.js.map +1 -1
- package/dist/trusted-process/mcp-proxy-server.d.ts +2 -0
- package/dist/trusted-process/mcp-proxy-server.js +59 -16
- package/dist/trusted-process/mcp-proxy-server.js.map +1 -1
- package/dist/trusted-process/permissive-output-validator.d.ts +23 -0
- package/dist/trusted-process/permissive-output-validator.js +10 -0
- package/dist/trusted-process/permissive-output-validator.js.map +1 -0
- package/dist/trusted-process/policy-engine.d.ts +27 -4
- package/dist/trusted-process/policy-engine.js +152 -57
- package/dist/trusted-process/policy-engine.js.map +1 -1
- package/dist/trusted-process/tool-description-hints.d.ts +19 -0
- package/dist/trusted-process/tool-description-hints.js +53 -0
- package/dist/trusted-process/tool-description-hints.js.map +1 -0
- package/dist/types/argument-roles.d.ts +33 -1
- package/dist/types/argument-roles.js +129 -1
- package/dist/types/argument-roles.js.map +1 -1
- package/docker/Dockerfile.goose +34 -0
- package/docker/entrypoint-goose.sh +30 -0
- package/package.json +1 -1
- package/src/config/generated/tool-annotations.json +487 -338
- package/src/config/mcp-servers.json +2 -8
package/README.md
CHANGED
|
@@ -152,7 +152,7 @@ Session IDs are printed on session start and stored under `~/.ironcurtain/sessio
|
|
|
152
152
|
|
|
153
153
|
### Terminal multiplexer (recommended for Docker Agent Mode)
|
|
154
154
|
|
|
155
|
-
The terminal multiplexer is the recommended way to use IronCurtain with Docker Agent Mode. It gives you the full power of
|
|
155
|
+
The terminal multiplexer is the recommended way to use IronCurtain with Docker Agent Mode. It gives you the full power of your agent's interactive TUI (Claude Code or Goose) while IronCurtain mediates every tool call through its policy engine. All in a single terminal.
|
|
156
156
|
|
|
157
157
|
```bash
|
|
158
158
|
ironcurtain mux
|
|
@@ -160,7 +160,7 @@ ironcurtain mux
|
|
|
160
160
|
|
|
161
161
|
**Key capabilities:**
|
|
162
162
|
|
|
163
|
-
- **Full agent TUI** — Claude Code runs in a PTY inside a Docker container with no network access. You interact with it exactly as if it were running locally.
|
|
163
|
+
- **Full agent TUI** — The agent (Claude Code or Goose) runs in a PTY inside a Docker container with no network access. You interact with it exactly as if it were running locally.
|
|
164
164
|
- **Inline escalation handling** — When a tool call needs approval, an escalation panel overlays the viewport. No separate terminal needed — press Ctrl-A to enter command mode, `/approve N` or `/deny N`, and return.
|
|
165
165
|
- **Trusted user input** — Text typed in command mode (Ctrl-A) is captured on the host side before entering the container. This creates a verified intent signal that the [auto-approver](#auto-approve-escalations) can use — e.g., typing "push my changes to origin" will auto-approve a subsequent `git_push` escalation.
|
|
166
166
|
- **Tab management** — Spawn multiple concurrent sessions (`/new`), switch between them (`/tab N`, Alt-1..9), close them (`/close`).
|
|
@@ -194,6 +194,22 @@ ironcurtain bot # Start the Signal bot daemon
|
|
|
194
194
|
|
|
195
195
|
See [TRANSPORT.md](TRANSPORT.md) for setup instructions, architecture details, and why we chose Signal over alternatives like Telegram.
|
|
196
196
|
|
|
197
|
+
### Daemon mode
|
|
198
|
+
|
|
199
|
+
A unified long-running daemon that combines Signal messaging with scheduled cron jobs. Define recurring tasks with per-job security policies, and IronCurtain runs them headlessly on a cron schedule.
|
|
200
|
+
|
|
201
|
+
```bash
|
|
202
|
+
ironcurtain daemon add-job # Interactive wizard to define a scheduled job
|
|
203
|
+
ironcurtain daemon # Start the daemon (Signal + cron)
|
|
204
|
+
ironcurtain daemon --no-signal # Cron-only mode (no Signal transport)
|
|
205
|
+
ironcurtain daemon list-jobs # List jobs with schedule and status
|
|
206
|
+
ironcurtain daemon logs <id> # Show recent run summaries
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
Each job has its own task description, security constitution (compiled into per-job policy rules), persistent workspace, optional git repo sync, and configurable resource budgets. Escalations are auto-denied in headless mode unless Signal is configured for approval routing.
|
|
210
|
+
|
|
211
|
+
See [DAEMON.md](DAEMON.md) for the full setup guide, job definition reference, and troubleshooting.
|
|
212
|
+
|
|
197
213
|
## Session Commands
|
|
198
214
|
|
|
199
215
|
Commands available during an **interactive** or **single-shot** session:
|
|
@@ -291,6 +307,7 @@ IronCurtain stores configuration and session data in `~/.ironcurtain/`:
|
|
|
291
307
|
├── generated/ # User-compiled policy artifacts (overrides package defaults)
|
|
292
308
|
├── signal-data/ # Signal transport persistent data (registration keys)
|
|
293
309
|
├── pty-registry/ # Active PTY session registrations (auto-managed)
|
|
310
|
+
├── jobs/ # Cron job definitions, workspaces, and run records
|
|
294
311
|
├── sessions/
|
|
295
312
|
│ └── {sessionId}/
|
|
296
313
|
│ ├── sandbox/ # Per-session filesystem sandbox
|
|
@@ -451,6 +468,8 @@ src/
|
|
|
451
468
|
├── escalation/ # Escalation listener: session registry, TUI dashboard, state
|
|
452
469
|
├── mux/ # Terminal multiplexer: PTY bridge, renderer, trusted input
|
|
453
470
|
├── signal/ # Signal messaging transport (bot daemon, setup, formatting)
|
|
471
|
+
├── daemon/ # Unified daemon (Signal + cron scheduler, control socket)
|
|
472
|
+
├── cron/ # Cron job management (scheduler, job store, git sync, policy)
|
|
454
473
|
├── docker/ # Docker agent mode, PTY session, MITM proxy, adapters
|
|
455
474
|
├── servers/ # Built-in MCP servers (fetch, web search providers)
|
|
456
475
|
└── types/ # Shared type definitions
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared CLI help formatting module.
|
|
3
|
+
*
|
|
4
|
+
* Provides a declarative CommandSpec interface and formatting utilities
|
|
5
|
+
* so every subcommand produces consistent, aligned help output.
|
|
6
|
+
*/
|
|
7
|
+
export interface CommandOption {
|
|
8
|
+
/** The long flag name, without dashes (e.g., 'agent'). */
|
|
9
|
+
readonly flag: string;
|
|
10
|
+
/** Optional single-character short alias (e.g., 'a'). */
|
|
11
|
+
readonly short?: string;
|
|
12
|
+
/** Human-readable description. */
|
|
13
|
+
readonly description: string;
|
|
14
|
+
/** Placeholder for the value (e.g., '<name>'). Omit for boolean flags. */
|
|
15
|
+
readonly placeholder?: string;
|
|
16
|
+
}
|
|
17
|
+
export interface CommandSpec {
|
|
18
|
+
/** The full command name as invoked (e.g., 'ironcurtain daemon'). */
|
|
19
|
+
readonly name: string;
|
|
20
|
+
/** One-line summary of what the command does. */
|
|
21
|
+
readonly description: string;
|
|
22
|
+
/** Usage lines shown at the top. Each string is a separate line. */
|
|
23
|
+
readonly usage: readonly string[];
|
|
24
|
+
/** Named subcommands, displayed in a table after the usage block. */
|
|
25
|
+
readonly subcommands?: readonly {
|
|
26
|
+
readonly name: string;
|
|
27
|
+
readonly description: string;
|
|
28
|
+
}[];
|
|
29
|
+
/** Command-line options, displayed in a table after subcommands. */
|
|
30
|
+
readonly options?: readonly CommandOption[];
|
|
31
|
+
/** Example invocations shown at the bottom. */
|
|
32
|
+
readonly examples?: readonly string[];
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Formats a CommandSpec into a complete help string.
|
|
36
|
+
*
|
|
37
|
+
* Layout:
|
|
38
|
+
* <name> - <description>
|
|
39
|
+
*
|
|
40
|
+
* Usage:
|
|
41
|
+
* <usage lines>
|
|
42
|
+
*
|
|
43
|
+
* Subcommands: (if any)
|
|
44
|
+
* <table>
|
|
45
|
+
*
|
|
46
|
+
* Options: (if any)
|
|
47
|
+
* <table>
|
|
48
|
+
*
|
|
49
|
+
* Examples: (if any)
|
|
50
|
+
* <lines>
|
|
51
|
+
*/
|
|
52
|
+
export declare function formatHelp(spec: CommandSpec): string;
|
|
53
|
+
/**
|
|
54
|
+
* Prints formatted help to stderr.
|
|
55
|
+
*/
|
|
56
|
+
export declare function printHelp(spec: CommandSpec): void;
|
|
57
|
+
/**
|
|
58
|
+
* Convenience: if `values.help` is truthy, prints help and returns true.
|
|
59
|
+
* Callers can use: `if (checkHelp(values, spec)) return;`
|
|
60
|
+
*/
|
|
61
|
+
export declare function checkHelp(values: {
|
|
62
|
+
help?: boolean;
|
|
63
|
+
}, spec: CommandSpec): boolean;
|
package/dist/cli-help.js
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared CLI help formatting module.
|
|
3
|
+
*
|
|
4
|
+
* Provides a declarative CommandSpec interface and formatting utilities
|
|
5
|
+
* so every subcommand produces consistent, aligned help output.
|
|
6
|
+
*/
|
|
7
|
+
// ---------------------------------------------------------------------------
|
|
8
|
+
// Formatting
|
|
9
|
+
// ---------------------------------------------------------------------------
|
|
10
|
+
/** Pads `text` with spaces on the right to reach at least `width` characters. */
|
|
11
|
+
function pad(text, width) {
|
|
12
|
+
return text.length >= width ? text : text + ' '.repeat(width - text.length);
|
|
13
|
+
}
|
|
14
|
+
/** Formats a single option into its flag string (e.g., '-a, --agent <name>'). */
|
|
15
|
+
function formatOptionFlag(opt) {
|
|
16
|
+
const parts = [];
|
|
17
|
+
if (opt.short) {
|
|
18
|
+
parts.push(`-${opt.short},`);
|
|
19
|
+
}
|
|
20
|
+
let longFlag = `--${opt.flag}`;
|
|
21
|
+
if (opt.placeholder) {
|
|
22
|
+
longFlag += ` ${opt.placeholder}`;
|
|
23
|
+
}
|
|
24
|
+
if (opt.short) {
|
|
25
|
+
parts.push(longFlag);
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
// Indent to align with flags that have a short alias.
|
|
29
|
+
// "-X, " is 4 chars, so we add 4 spaces of leading indent.
|
|
30
|
+
parts.push(` ${longFlag}`);
|
|
31
|
+
}
|
|
32
|
+
return parts.join(' ');
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Renders a two-column table (label + description) with consistent alignment.
|
|
36
|
+
* Each row is indented by 2 spaces.
|
|
37
|
+
*/
|
|
38
|
+
function formatTable(rows) {
|
|
39
|
+
const maxLabel = rows.reduce((max, r) => Math.max(max, r.label.length), 0);
|
|
40
|
+
const colWidth = maxLabel + 2; // 2 spaces between columns
|
|
41
|
+
return rows.map((r) => ` ${pad(r.label, colWidth)}${r.description}`).join('\n');
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Formats a CommandSpec into a complete help string.
|
|
45
|
+
*
|
|
46
|
+
* Layout:
|
|
47
|
+
* <name> - <description>
|
|
48
|
+
*
|
|
49
|
+
* Usage:
|
|
50
|
+
* <usage lines>
|
|
51
|
+
*
|
|
52
|
+
* Subcommands: (if any)
|
|
53
|
+
* <table>
|
|
54
|
+
*
|
|
55
|
+
* Options: (if any)
|
|
56
|
+
* <table>
|
|
57
|
+
*
|
|
58
|
+
* Examples: (if any)
|
|
59
|
+
* <lines>
|
|
60
|
+
*/
|
|
61
|
+
export function formatHelp(spec) {
|
|
62
|
+
const sections = [];
|
|
63
|
+
// Header
|
|
64
|
+
sections.push(`${spec.name} - ${spec.description}`);
|
|
65
|
+
// Usage
|
|
66
|
+
sections.push('Usage:\n' + spec.usage.map((u) => ` ${u}`).join('\n'));
|
|
67
|
+
// Subcommands
|
|
68
|
+
if (spec.subcommands && spec.subcommands.length > 0) {
|
|
69
|
+
const rows = spec.subcommands.map((s) => ({ label: s.name, description: s.description }));
|
|
70
|
+
sections.push('Subcommands:\n' + formatTable(rows));
|
|
71
|
+
}
|
|
72
|
+
// Options
|
|
73
|
+
if (spec.options && spec.options.length > 0) {
|
|
74
|
+
const rows = spec.options.map((o) => ({
|
|
75
|
+
label: formatOptionFlag(o),
|
|
76
|
+
description: o.description,
|
|
77
|
+
}));
|
|
78
|
+
sections.push('Options:\n' + formatTable(rows));
|
|
79
|
+
}
|
|
80
|
+
// Examples
|
|
81
|
+
if (spec.examples && spec.examples.length > 0) {
|
|
82
|
+
sections.push('Examples:\n' + spec.examples.map((e) => ` ${e}`).join('\n'));
|
|
83
|
+
}
|
|
84
|
+
return sections.join('\n\n');
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Prints formatted help to stderr.
|
|
88
|
+
*/
|
|
89
|
+
export function printHelp(spec) {
|
|
90
|
+
console.error(formatHelp(spec));
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Convenience: if `values.help` is truthy, prints help and returns true.
|
|
94
|
+
* Callers can use: `if (checkHelp(values, spec)) return;`
|
|
95
|
+
*/
|
|
96
|
+
export function checkHelp(values, spec) {
|
|
97
|
+
if (!values.help)
|
|
98
|
+
return false;
|
|
99
|
+
printHelp(spec);
|
|
100
|
+
return true;
|
|
101
|
+
}
|
|
102
|
+
//# sourceMappingURL=cli-help.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli-help.js","sourceRoot":"","sources":["../src/cli-help.ts"],"names":[],"mappings":"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"}
|
package/dist/cli.js
CHANGED
|
@@ -4,6 +4,7 @@ import { readFileSync } from 'node:fs';
|
|
|
4
4
|
import { dirname, resolve } from 'node:path';
|
|
5
5
|
import { fileURLToPath } from 'node:url';
|
|
6
6
|
import { parseArgs } from 'node:util';
|
|
7
|
+
import { checkHelp, printHelp as printSpecHelp } from './cli-help.js';
|
|
7
8
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
8
9
|
function getVersion() {
|
|
9
10
|
// Works from both dist/ and src/ since package.json is one level up in either case.
|
|
@@ -11,57 +12,48 @@ function getVersion() {
|
|
|
11
12
|
const pkg = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));
|
|
12
13
|
return pkg.version;
|
|
13
14
|
}
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
ironcurtain start --list-agents # List available agents
|
|
57
|
-
ironcurtain annotate-tools # Classify tool arguments
|
|
58
|
-
ironcurtain compile-policy # Compile policy from constitution
|
|
59
|
-
ironcurtain refresh-lists # Refresh all dynamic lists
|
|
60
|
-
ironcurtain refresh-lists --list major-news # Refresh a single list
|
|
61
|
-
ironcurtain refresh-lists --with-mcp # Include MCP-backed lists
|
|
62
|
-
ironcurtain customize-policy # Customize policy interactively
|
|
63
|
-
`.trim());
|
|
64
|
-
}
|
|
15
|
+
const topLevelSpec = {
|
|
16
|
+
name: 'ironcurtain',
|
|
17
|
+
description: 'Secure agent runtime with policy-driven tool mediation',
|
|
18
|
+
usage: ['ironcurtain <command> [options]'],
|
|
19
|
+
subcommands: [
|
|
20
|
+
{ name: 'start [task]', description: 'Run the agent (interactive or single-shot)' },
|
|
21
|
+
{ name: 'daemon', description: 'Unified Signal + cron daemon' },
|
|
22
|
+
{ name: 'mux', description: 'Terminal multiplexer for PTY sessions (requires node-pty)' },
|
|
23
|
+
{ name: 'escalation-listener', description: 'Aggregate escalation notifications from PTY sessions' },
|
|
24
|
+
{ name: 'bot', description: "Alias for 'daemon' (backward compatible)" },
|
|
25
|
+
{ name: 'setup', description: 'Run the first-start wizard (always runs)' },
|
|
26
|
+
{ name: 'setup-signal', description: 'Interactive Signal transport onboarding' },
|
|
27
|
+
{ name: 'annotate-tools', description: 'Classify MCP tool arguments via LLM' },
|
|
28
|
+
{ name: 'compile-policy', description: 'Compile constitution into enforceable policy rules' },
|
|
29
|
+
{ name: 'refresh-lists', description: 'Re-resolve dynamic lists without full recompilation' },
|
|
30
|
+
{ name: 'customize-policy', description: 'Customize your policy via LLM-assisted conversation' },
|
|
31
|
+
{ name: 'config', description: 'Edit configuration interactively' },
|
|
32
|
+
{ name: 'help', description: 'Show this help message' },
|
|
33
|
+
],
|
|
34
|
+
options: [
|
|
35
|
+
{ flag: 'help', short: 'h', description: 'Show this help message' },
|
|
36
|
+
{ flag: 'version', short: 'v', description: 'Show version number' },
|
|
37
|
+
],
|
|
38
|
+
examples: [
|
|
39
|
+
'ironcurtain start "Summarize files in ." # Single-shot task',
|
|
40
|
+
'ironcurtain start # Interactive session',
|
|
41
|
+
'ironcurtain start --resume <session-id> # Resume a session',
|
|
42
|
+
'ironcurtain start -w ./my-project "Fix bugs" # Work in existing directory',
|
|
43
|
+
'ironcurtain start --agent claude-code "task" # Docker: Claude Code',
|
|
44
|
+
'ironcurtain start --pty # PTY mode',
|
|
45
|
+
'ironcurtain daemon # Start the daemon',
|
|
46
|
+
'ironcurtain daemon list-jobs # List scheduled jobs',
|
|
47
|
+
'ironcurtain compile-policy # Compile policy',
|
|
48
|
+
'ironcurtain refresh-lists --with-mcp # Refresh dynamic lists',
|
|
49
|
+
],
|
|
50
|
+
};
|
|
51
|
+
const setupSignalSpec = {
|
|
52
|
+
name: 'ironcurtain setup-signal',
|
|
53
|
+
description: 'Interactive Signal transport onboarding',
|
|
54
|
+
usage: ['ironcurtain setup-signal [options]'],
|
|
55
|
+
options: [{ flag: 're-trust', description: 'Re-verify a changed identity key' }],
|
|
56
|
+
};
|
|
65
57
|
const { values, positionals } = parseArgs({
|
|
66
58
|
args: process.argv.slice(2),
|
|
67
59
|
options: {
|
|
@@ -76,8 +68,11 @@ if (values.version) {
|
|
|
76
68
|
process.exit(0);
|
|
77
69
|
}
|
|
78
70
|
const subcommand = positionals[0];
|
|
79
|
-
|
|
80
|
-
|
|
71
|
+
// Show top-level help when no subcommand is given or 'help' is the subcommand.
|
|
72
|
+
// When a recognized subcommand is present, --help passes through to the
|
|
73
|
+
// subcommand handler via process.argv.slice(3).
|
|
74
|
+
if (!subcommand || subcommand === 'help') {
|
|
75
|
+
printSpecHelp(topLevelSpec);
|
|
81
76
|
process.exit(0);
|
|
82
77
|
}
|
|
83
78
|
switch (subcommand) {
|
|
@@ -116,10 +111,30 @@ switch (subcommand) {
|
|
|
116
111
|
await runFirstStart();
|
|
117
112
|
break;
|
|
118
113
|
}
|
|
114
|
+
case 'daemon': {
|
|
115
|
+
const { runDaemonCommand } = await import('./daemon/daemon-command.js');
|
|
116
|
+
await runDaemonCommand(process.argv.slice(3));
|
|
117
|
+
break;
|
|
118
|
+
}
|
|
119
119
|
case 'bot': {
|
|
120
|
+
// 'bot' is an alias for 'daemon' (backward compatibility)
|
|
121
|
+
const botArgs = process.argv.slice(3);
|
|
122
|
+
if (botArgs.includes('--help') || botArgs.includes('-h')) {
|
|
123
|
+
const { botSpec } = await import('./signal/bot-command.js');
|
|
124
|
+
printSpecHelp(botSpec);
|
|
125
|
+
break;
|
|
126
|
+
}
|
|
120
127
|
const agentName = values.agent;
|
|
121
|
-
|
|
122
|
-
|
|
128
|
+
if (botArgs.some((a) => !a.startsWith('-'))) {
|
|
129
|
+
// Has subcommands -- route through daemon command
|
|
130
|
+
const { runDaemonCommand } = await import('./daemon/daemon-command.js');
|
|
131
|
+
await runDaemonCommand(botArgs);
|
|
132
|
+
}
|
|
133
|
+
else {
|
|
134
|
+
// No subcommands -- existing bot behavior
|
|
135
|
+
const { runBot } = await import('./signal/bot-command.js');
|
|
136
|
+
await runBot({ agent: agentName });
|
|
137
|
+
}
|
|
123
138
|
break;
|
|
124
139
|
}
|
|
125
140
|
case 'mux': {
|
|
@@ -133,6 +148,8 @@ switch (subcommand) {
|
|
|
133
148
|
break;
|
|
134
149
|
}
|
|
135
150
|
case 'setup-signal': {
|
|
151
|
+
if (checkHelp({ help: process.argv.includes('--help') || process.argv.includes('-h') }, setupSignalSpec))
|
|
152
|
+
break;
|
|
136
153
|
const reTrust = process.argv.includes('--re-trust');
|
|
137
154
|
const { runSignalSetup } = await import('./signal/setup-signal.js');
|
|
138
155
|
await runSignalSetup({ reTrust });
|
|
@@ -140,7 +157,7 @@ switch (subcommand) {
|
|
|
140
157
|
}
|
|
141
158
|
default:
|
|
142
159
|
console.error(`Unknown command: ${subcommand}\n`);
|
|
143
|
-
|
|
160
|
+
printSpecHelp(topLevelSpec);
|
|
144
161
|
process.exit(1);
|
|
145
162
|
}
|
|
146
163
|
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,OAAO,eAAe,CAAC;AACvB,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -9,7 +9,7 @@ import * as p from '@clack/prompts';
|
|
|
9
9
|
import { readFileSync } from 'node:fs';
|
|
10
10
|
import { resolve, dirname } from 'node:path';
|
|
11
11
|
import { fileURLToPath } from 'node:url';
|
|
12
|
-
import { loadUserConfig, saveUserConfig, validateModelId, ESCALATION_TIMEOUT_MIN, ESCALATION_TIMEOUT_MAX, WEB_SEARCH_PROVIDERS, WEB_SEARCH_PROVIDER_LABELS, WEB_SEARCH_PROVIDER_URLS, } from './user-config.js';
|
|
12
|
+
import { loadUserConfig, saveUserConfig, validateModelId, ESCALATION_TIMEOUT_MIN, ESCALATION_TIMEOUT_MAX, WEB_SEARCH_PROVIDERS, WEB_SEARCH_PROVIDER_LABELS, WEB_SEARCH_PROVIDER_URLS, GOOSE_PROVIDERS, DOCKER_AGENTS, } from './user-config.js';
|
|
13
13
|
import { getUserConfigPath } from './paths.js';
|
|
14
14
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
15
15
|
/** Known model options for selection prompts. */
|
|
@@ -70,7 +70,14 @@ function formatModelShort(id) {
|
|
|
70
70
|
}
|
|
71
71
|
export function computeDiff(resolved, pending) {
|
|
72
72
|
const diffs = [];
|
|
73
|
-
const topLevelKeys = [
|
|
73
|
+
const topLevelKeys = [
|
|
74
|
+
'agentModelId',
|
|
75
|
+
'policyModelId',
|
|
76
|
+
'escalationTimeoutSeconds',
|
|
77
|
+
'gooseProvider',
|
|
78
|
+
'gooseModel',
|
|
79
|
+
'preferredDockerAgent',
|
|
80
|
+
];
|
|
74
81
|
for (const key of topLevelKeys) {
|
|
75
82
|
if (key in pending && pending[key] !== undefined && pending[key] !== resolved[key]) {
|
|
76
83
|
diffs.push([key, { from: resolved[key], to: pending[key] }]);
|
|
@@ -615,6 +622,126 @@ async function handleServerCredentials(resolved, pending) {
|
|
|
615
622
|
}
|
|
616
623
|
}
|
|
617
624
|
}
|
|
625
|
+
// ─── Docker Agent Settings ────────────────────────────────────
|
|
626
|
+
/** Human-readable labels for Goose providers. */
|
|
627
|
+
const GOOSE_PROVIDER_LABELS = {
|
|
628
|
+
anthropic: 'Anthropic',
|
|
629
|
+
openai: 'OpenAI',
|
|
630
|
+
google: 'Google',
|
|
631
|
+
};
|
|
632
|
+
/** Human-readable labels for Docker agents. */
|
|
633
|
+
const DOCKER_AGENT_LABELS = {
|
|
634
|
+
'claude-code': 'Claude Code',
|
|
635
|
+
goose: 'Goose',
|
|
636
|
+
};
|
|
637
|
+
async function handleDockerAgent(resolved, pending) {
|
|
638
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- interactive loop exited via return
|
|
639
|
+
while (true) {
|
|
640
|
+
const currentPreferred = pending.preferredDockerAgent ?? resolved.preferredDockerAgent;
|
|
641
|
+
const options = [
|
|
642
|
+
{
|
|
643
|
+
value: 'preferredDockerAgent',
|
|
644
|
+
label: 'Preferred agent',
|
|
645
|
+
hint: DOCKER_AGENT_LABELS[currentPreferred],
|
|
646
|
+
},
|
|
647
|
+
{
|
|
648
|
+
value: 'configureGoose',
|
|
649
|
+
label: 'Configure Goose...',
|
|
650
|
+
hint: gooseConfigHint(resolved, pending),
|
|
651
|
+
},
|
|
652
|
+
{ value: 'back', label: 'Back' },
|
|
653
|
+
];
|
|
654
|
+
const field = await p.select({
|
|
655
|
+
message: 'Docker Agent Settings',
|
|
656
|
+
options,
|
|
657
|
+
});
|
|
658
|
+
if (isCancelled(field) || field === 'back')
|
|
659
|
+
return;
|
|
660
|
+
if (field === 'preferredDockerAgent') {
|
|
661
|
+
const agentOptions = DOCKER_AGENTS.map((agent) => ({
|
|
662
|
+
value: agent,
|
|
663
|
+
label: DOCKER_AGENT_LABELS[agent],
|
|
664
|
+
hint: agent === currentPreferred ? '(current)' : undefined,
|
|
665
|
+
}));
|
|
666
|
+
const selected = await p.select({
|
|
667
|
+
message: 'Select preferred Docker agent:',
|
|
668
|
+
options: agentOptions,
|
|
669
|
+
initialValue: currentPreferred,
|
|
670
|
+
});
|
|
671
|
+
if (isCancelled(selected))
|
|
672
|
+
continue;
|
|
673
|
+
const agent = selected;
|
|
674
|
+
if (agent !== currentPreferred) {
|
|
675
|
+
pending.preferredDockerAgent = agent;
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
else if (field === 'configureGoose') {
|
|
679
|
+
await handleGooseConfig(resolved, pending);
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
/** Goose-specific configuration submenu (provider + model). */
|
|
684
|
+
async function handleGooseConfig(resolved, pending) {
|
|
685
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- interactive loop exited via return
|
|
686
|
+
while (true) {
|
|
687
|
+
const currentProvider = pending.gooseProvider ?? resolved.gooseProvider;
|
|
688
|
+
const currentModel = pending.gooseModel ?? resolved.gooseModel;
|
|
689
|
+
const field = await p.select({
|
|
690
|
+
message: 'Goose Configuration',
|
|
691
|
+
options: [
|
|
692
|
+
{
|
|
693
|
+
value: 'gooseProvider',
|
|
694
|
+
label: 'LLM provider',
|
|
695
|
+
hint: GOOSE_PROVIDER_LABELS[currentProvider],
|
|
696
|
+
},
|
|
697
|
+
{
|
|
698
|
+
value: 'gooseModel',
|
|
699
|
+
label: 'Model',
|
|
700
|
+
hint: currentModel,
|
|
701
|
+
},
|
|
702
|
+
{ value: 'back', label: 'Back' },
|
|
703
|
+
],
|
|
704
|
+
});
|
|
705
|
+
if (isCancelled(field) || field === 'back')
|
|
706
|
+
return;
|
|
707
|
+
if (field === 'gooseProvider') {
|
|
708
|
+
const providerOptions = GOOSE_PROVIDERS.map((prov) => ({
|
|
709
|
+
value: prov,
|
|
710
|
+
label: GOOSE_PROVIDER_LABELS[prov],
|
|
711
|
+
hint: prov === currentProvider ? '(current)' : undefined,
|
|
712
|
+
}));
|
|
713
|
+
const selected = await p.select({
|
|
714
|
+
message: 'Select Goose LLM provider:',
|
|
715
|
+
options: providerOptions,
|
|
716
|
+
initialValue: currentProvider,
|
|
717
|
+
});
|
|
718
|
+
if (isCancelled(selected))
|
|
719
|
+
continue;
|
|
720
|
+
const provider = selected;
|
|
721
|
+
if (provider !== currentProvider) {
|
|
722
|
+
pending.gooseProvider = provider;
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
else if (field === 'gooseModel') {
|
|
726
|
+
const input = await p.text({
|
|
727
|
+
message: 'Goose model identifier:',
|
|
728
|
+
placeholder: currentModel,
|
|
729
|
+
validate: (val) => (!val ? 'Model ID is required' : undefined),
|
|
730
|
+
});
|
|
731
|
+
if (isCancelled(input))
|
|
732
|
+
continue;
|
|
733
|
+
const model = input;
|
|
734
|
+
if (model !== currentModel) {
|
|
735
|
+
pending.gooseModel = model;
|
|
736
|
+
}
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
function gooseConfigHint(resolved, pending) {
|
|
741
|
+
const provider = GOOSE_PROVIDER_LABELS[pending.gooseProvider ?? resolved.gooseProvider];
|
|
742
|
+
const model = pending.gooseModel ?? resolved.gooseModel;
|
|
743
|
+
return `${provider}, ${model}`;
|
|
744
|
+
}
|
|
618
745
|
// ─── Menu descriptions ───────────────────────────────────────
|
|
619
746
|
function modelsHint(resolved, pending) {
|
|
620
747
|
const agent = formatModelShort(pending.agentModelId ?? resolved.agentModelId);
|
|
@@ -645,6 +772,9 @@ function serverCredentialsHint(resolved, pending) {
|
|
|
645
772
|
return 'none';
|
|
646
773
|
return configured.map(([name]) => name).join(', ');
|
|
647
774
|
}
|
|
775
|
+
function dockerAgentHint(resolved, pending) {
|
|
776
|
+
return DOCKER_AGENT_LABELS[pending.preferredDockerAgent ?? resolved.preferredDockerAgent];
|
|
777
|
+
}
|
|
648
778
|
function changeCount(resolved, pending) {
|
|
649
779
|
const diffs = computeDiff(resolved, pending);
|
|
650
780
|
if (diffs.length === 0)
|
|
@@ -680,6 +810,7 @@ export async function runConfigCommand() {
|
|
|
680
810
|
{ value: 'compact', label: `Auto-Compact (${autoCompactHint(resolved, pending)})` },
|
|
681
811
|
{ value: 'websearch', label: `Web Search (${webSearchHint(resolved, pending)})` },
|
|
682
812
|
{ value: 'credentials', label: `Server Credentials (${serverCredentialsHint(resolved, pending)})` },
|
|
813
|
+
{ value: 'dockerAgent', label: `Docker Agent (${dockerAgentHint(resolved, pending)})` },
|
|
683
814
|
{ value: 'save', label: 'Save & Exit', hint: changeCount(resolved, pending) },
|
|
684
815
|
{ value: 'cancel', label: 'Cancel', hint: 'discard all changes' },
|
|
685
816
|
],
|
|
@@ -707,6 +838,9 @@ export async function runConfigCommand() {
|
|
|
707
838
|
case 'credentials':
|
|
708
839
|
await handleServerCredentials(resolved, pending);
|
|
709
840
|
break;
|
|
841
|
+
case 'dockerAgent':
|
|
842
|
+
await handleDockerAgent(resolved, pending);
|
|
843
|
+
break;
|
|
710
844
|
case 'cancel':
|
|
711
845
|
p.cancel('Changes discarded.');
|
|
712
846
|
return;
|