@provos/ironcurtain 0.5.1 → 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 +85 -66
- 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 +78 -52
- 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 +13 -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 +8 -48
- 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 +22 -14
- package/dist/docker/docker-infrastructure.js.map +1 -1
- package/dist/docker/mitm-proxy.d.ts +5 -2
- package/dist/docker/mitm-proxy.js +169 -46
- package/dist/docker/mitm-proxy.js.map +1 -1
- package/dist/docker/oauth-credentials.d.ts +15 -2
- package/dist/docker/oauth-credentials.js +92 -8
- package/dist/docker/oauth-credentials.js.map +1 -1
- package/dist/docker/oauth-token-manager.d.ts +80 -0
- package/dist/docker/oauth-token-manager.js +133 -0
- package/dist/docker/oauth-token-manager.js.map +1 -0
- package/dist/docker/pty-session.d.ts +2 -0
- package/dist/docker/pty-session.js +17 -8
- package/dist/docker/pty-session.js.map +1 -1
- package/dist/escalation/escalation-watcher.d.ts +2 -0
- package/dist/escalation/escalation-watcher.js +5 -0
- package/dist/escalation/escalation-watcher.js.map +1 -1
- package/dist/escalation/listener-command.js +9 -58
- package/dist/escalation/listener-command.js.map +1 -1
- package/dist/escalation/listener-lock.d.ts +20 -0
- package/dist/escalation/listener-lock.js +69 -0
- package/dist/escalation/listener-lock.js.map +1 -0
- package/dist/escalation/session-registry.js +1 -14
- package/dist/escalation/session-registry.js.map +1 -1
- package/dist/index.js +51 -2
- package/dist/index.js.map +1 -1
- package/dist/mux/mux-app.d.ts +24 -0
- package/dist/mux/mux-app.js +450 -0
- package/dist/mux/mux-app.js.map +1 -0
- package/dist/mux/mux-command.d.ts +7 -0
- package/dist/mux/mux-command.js +104 -0
- package/dist/mux/mux-command.js.map +1 -0
- package/dist/mux/mux-escalation-manager.d.ts +48 -0
- package/dist/mux/mux-escalation-manager.js +162 -0
- package/dist/mux/mux-escalation-manager.js.map +1 -0
- package/dist/mux/mux-input-handler.d.ts +54 -0
- package/dist/mux/mux-input-handler.js +512 -0
- package/dist/mux/mux-input-handler.js.map +1 -0
- package/dist/mux/mux-renderer.d.ts +106 -0
- package/dist/mux/mux-renderer.js +850 -0
- package/dist/mux/mux-renderer.js.map +1 -0
- package/dist/mux/mux-splash.d.ts +17 -0
- package/dist/mux/mux-splash.js +323 -0
- package/dist/mux/mux-splash.js.map +1 -0
- 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.d.ts +79 -0
- package/dist/mux/pty-bridge.js +151 -0
- package/dist/mux/pty-bridge.js.map +1 -0
- package/dist/mux/trusted-input.d.ts +27 -0
- package/dist/mux/trusted-input.js +27 -0
- package/dist/mux/trusted-input.js.map +1 -0
- package/dist/mux/types.d.ts +99 -0
- package/dist/mux/types.js +57 -0
- package/dist/mux/types.js.map +1 -0
- 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 +40 -1
- package/dist/sandbox/index.js.map +1 -1
- package/dist/session/agent-session.d.ts +3 -0
- package/dist/session/agent-session.js +13 -1
- package/dist/session/agent-session.js.map +1 -1
- package/dist/session/index.js +65 -9
- 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 +33 -0
- package/dist/session/workspace-validation.d.ts +19 -0
- package/dist/session/workspace-validation.js +66 -0
- package/dist/session/workspace-validation.js.map +1 -0
- 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/auto-approver.d.ts +13 -4
- package/dist/trusted-process/auto-approver.js +12 -5
- package/dist/trusted-process/auto-approver.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/escalation.js +5 -0
- package/dist/trusted-process/escalation.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 +98 -32
- 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 +6 -1
- package/src/config/generated/tool-annotations.json +487 -338
- package/src/config/mcp-servers.json +2 -8
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SessionManager -- Unified session state management.
|
|
3
|
+
*
|
|
4
|
+
* Extracted from SignalBotDaemon to serve as the single owner of all
|
|
5
|
+
* managed session state. Both Signal-initiated and cron-initiated
|
|
6
|
+
* sessions register here for unified lifecycle management and
|
|
7
|
+
* escalation routing.
|
|
8
|
+
*
|
|
9
|
+
* This is the canonical location for SessionSource and ManagedSession
|
|
10
|
+
* types. The daemon module re-exports them for convenience.
|
|
11
|
+
*/
|
|
12
|
+
import type { Session } from './types.js';
|
|
13
|
+
import type { Transport } from './transport.js';
|
|
14
|
+
import type { JobId } from '../cron/types.js';
|
|
15
|
+
/**
|
|
16
|
+
* Source discriminant for managed sessions.
|
|
17
|
+
* Determines cleanup behavior, notification routing, and
|
|
18
|
+
* message forwarding eligibility.
|
|
19
|
+
*
|
|
20
|
+
* - 'signal': interactive session created via Signal message.
|
|
21
|
+
* Accepts follow-up messages via forwardToSession().
|
|
22
|
+
* - 'cron': headless session created by the cron scheduler.
|
|
23
|
+
* Does NOT accept follow-up messages.
|
|
24
|
+
*/
|
|
25
|
+
export type SessionSource = {
|
|
26
|
+
readonly kind: 'signal';
|
|
27
|
+
} | {
|
|
28
|
+
readonly kind: 'cron';
|
|
29
|
+
readonly jobId: JobId;
|
|
30
|
+
readonly jobName: string;
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* Unified managed session entry. Used for both Signal-initiated
|
|
34
|
+
* interactive sessions and cron-initiated headless sessions.
|
|
35
|
+
*
|
|
36
|
+
* The transport field uses the base Transport interface because
|
|
37
|
+
* cron sessions use HeadlessTransport. Code that needs
|
|
38
|
+
* Signal-specific methods must guard on source.kind === 'signal'.
|
|
39
|
+
*/
|
|
40
|
+
export interface ManagedSession {
|
|
41
|
+
readonly label: number;
|
|
42
|
+
readonly session: Session;
|
|
43
|
+
readonly transport: Transport;
|
|
44
|
+
readonly source: SessionSource;
|
|
45
|
+
messageInFlight: boolean;
|
|
46
|
+
pendingEscalationId: string | null;
|
|
47
|
+
escalationResolving: boolean;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Owns all managed session state. Both SignalBotDaemon and
|
|
51
|
+
* CronScheduler delegate to this class for session registration,
|
|
52
|
+
* lookup, and teardown.
|
|
53
|
+
*
|
|
54
|
+
* Invariants:
|
|
55
|
+
* - Labels are monotonically increasing integers starting at 1.
|
|
56
|
+
* - At most one session exists per label.
|
|
57
|
+
* - currentLabel is always either null or a valid label in the map.
|
|
58
|
+
*/
|
|
59
|
+
export declare class SessionManager {
|
|
60
|
+
private sessions;
|
|
61
|
+
private nextLabel;
|
|
62
|
+
/**
|
|
63
|
+
* The currently "focused" session label for Signal message routing.
|
|
64
|
+
* When a Signal message arrives without an explicit #N prefix, it
|
|
65
|
+
* is routed to this session.
|
|
66
|
+
*
|
|
67
|
+
* Only updated by register() for Signal sessions. Cron sessions
|
|
68
|
+
* do not steal Signal focus.
|
|
69
|
+
*/
|
|
70
|
+
currentLabel: number | null;
|
|
71
|
+
/**
|
|
72
|
+
* Registers a new session and returns its assigned label.
|
|
73
|
+
*
|
|
74
|
+
* For Signal sessions: sets currentLabel to the new session.
|
|
75
|
+
* For cron sessions: currentLabel is NOT changed.
|
|
76
|
+
*/
|
|
77
|
+
register(session: Session, transport: Transport, source: SessionSource): number;
|
|
78
|
+
/**
|
|
79
|
+
* Ends a session by label: closes the transport, closes the
|
|
80
|
+
* session, and removes it from the map.
|
|
81
|
+
*
|
|
82
|
+
* If the ended session was currentLabel, switches to the most
|
|
83
|
+
* recently registered remaining Signal session, or null if none.
|
|
84
|
+
*/
|
|
85
|
+
end(label: number): Promise<void>;
|
|
86
|
+
/** Returns the ManagedSession for a label, or undefined. */
|
|
87
|
+
get(label: number): ManagedSession | undefined;
|
|
88
|
+
/** Returns all managed sessions (snapshot). */
|
|
89
|
+
all(): readonly ManagedSession[];
|
|
90
|
+
/** Returns managed sessions filtered by source kind. */
|
|
91
|
+
byKind(kind: SessionSource['kind']): readonly ManagedSession[];
|
|
92
|
+
/** Returns the number of active sessions. */
|
|
93
|
+
get size(): number;
|
|
94
|
+
/** Records that a session has a pending escalation. */
|
|
95
|
+
setPendingEscalation(label: number, escalationId: string): void;
|
|
96
|
+
/** Clears a session's pending escalation. */
|
|
97
|
+
clearPendingEscalation(label: number): void;
|
|
98
|
+
/** Returns sessions that have pending escalations. */
|
|
99
|
+
withPendingEscalation(): readonly ManagedSession[];
|
|
100
|
+
/**
|
|
101
|
+
* Finds the most recently registered Signal session label.
|
|
102
|
+
* Returns null if no Signal sessions exist.
|
|
103
|
+
*/
|
|
104
|
+
private findMostRecentSignalLabel;
|
|
105
|
+
}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SessionManager -- Unified session state management.
|
|
3
|
+
*
|
|
4
|
+
* Extracted from SignalBotDaemon to serve as the single owner of all
|
|
5
|
+
* managed session state. Both Signal-initiated and cron-initiated
|
|
6
|
+
* sessions register here for unified lifecycle management and
|
|
7
|
+
* escalation routing.
|
|
8
|
+
*
|
|
9
|
+
* This is the canonical location for SessionSource and ManagedSession
|
|
10
|
+
* types. The daemon module re-exports them for convenience.
|
|
11
|
+
*/
|
|
12
|
+
import * as logger from '../logger.js';
|
|
13
|
+
/**
|
|
14
|
+
* Owns all managed session state. Both SignalBotDaemon and
|
|
15
|
+
* CronScheduler delegate to this class for session registration,
|
|
16
|
+
* lookup, and teardown.
|
|
17
|
+
*
|
|
18
|
+
* Invariants:
|
|
19
|
+
* - Labels are monotonically increasing integers starting at 1.
|
|
20
|
+
* - At most one session exists per label.
|
|
21
|
+
* - currentLabel is always either null or a valid label in the map.
|
|
22
|
+
*/
|
|
23
|
+
export class SessionManager {
|
|
24
|
+
sessions = new Map();
|
|
25
|
+
nextLabel = 1;
|
|
26
|
+
/**
|
|
27
|
+
* The currently "focused" session label for Signal message routing.
|
|
28
|
+
* When a Signal message arrives without an explicit #N prefix, it
|
|
29
|
+
* is routed to this session.
|
|
30
|
+
*
|
|
31
|
+
* Only updated by register() for Signal sessions. Cron sessions
|
|
32
|
+
* do not steal Signal focus.
|
|
33
|
+
*/
|
|
34
|
+
currentLabel = null;
|
|
35
|
+
/**
|
|
36
|
+
* Registers a new session and returns its assigned label.
|
|
37
|
+
*
|
|
38
|
+
* For Signal sessions: sets currentLabel to the new session.
|
|
39
|
+
* For cron sessions: currentLabel is NOT changed.
|
|
40
|
+
*/
|
|
41
|
+
register(session, transport, source) {
|
|
42
|
+
const label = this.nextLabel++;
|
|
43
|
+
const managed = {
|
|
44
|
+
label,
|
|
45
|
+
session,
|
|
46
|
+
transport,
|
|
47
|
+
source,
|
|
48
|
+
messageInFlight: false,
|
|
49
|
+
pendingEscalationId: null,
|
|
50
|
+
escalationResolving: false,
|
|
51
|
+
};
|
|
52
|
+
this.sessions.set(label, managed);
|
|
53
|
+
// Only Signal sessions update currentLabel
|
|
54
|
+
if (source.kind === 'signal') {
|
|
55
|
+
this.currentLabel = label;
|
|
56
|
+
}
|
|
57
|
+
return label;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Ends a session by label: closes the transport, closes the
|
|
61
|
+
* session, and removes it from the map.
|
|
62
|
+
*
|
|
63
|
+
* If the ended session was currentLabel, switches to the most
|
|
64
|
+
* recently registered remaining Signal session, or null if none.
|
|
65
|
+
*/
|
|
66
|
+
async end(label) {
|
|
67
|
+
const managed = this.sessions.get(label);
|
|
68
|
+
if (!managed)
|
|
69
|
+
return;
|
|
70
|
+
try {
|
|
71
|
+
managed.transport.close();
|
|
72
|
+
}
|
|
73
|
+
catch (err) {
|
|
74
|
+
logger.warn(`[SessionManager] Error closing transport for session #${label}: ${String(err)}`);
|
|
75
|
+
}
|
|
76
|
+
try {
|
|
77
|
+
await managed.session.close();
|
|
78
|
+
}
|
|
79
|
+
catch (err) {
|
|
80
|
+
logger.warn(`[SessionManager] Error closing session #${label}: ${String(err)}`);
|
|
81
|
+
}
|
|
82
|
+
this.sessions.delete(label);
|
|
83
|
+
// If the ended session was the current label, find a replacement
|
|
84
|
+
if (this.currentLabel === label) {
|
|
85
|
+
this.currentLabel = this.findMostRecentSignalLabel();
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
/** Returns the ManagedSession for a label, or undefined. */
|
|
89
|
+
get(label) {
|
|
90
|
+
return this.sessions.get(label);
|
|
91
|
+
}
|
|
92
|
+
/** Returns all managed sessions (snapshot). */
|
|
93
|
+
all() {
|
|
94
|
+
return [...this.sessions.values()];
|
|
95
|
+
}
|
|
96
|
+
/** Returns managed sessions filtered by source kind. */
|
|
97
|
+
byKind(kind) {
|
|
98
|
+
return [...this.sessions.values()].filter((m) => m.source.kind === kind);
|
|
99
|
+
}
|
|
100
|
+
/** Returns the number of active sessions. */
|
|
101
|
+
get size() {
|
|
102
|
+
return this.sessions.size;
|
|
103
|
+
}
|
|
104
|
+
/** Records that a session has a pending escalation. */
|
|
105
|
+
setPendingEscalation(label, escalationId) {
|
|
106
|
+
const managed = this.sessions.get(label);
|
|
107
|
+
if (managed) {
|
|
108
|
+
managed.pendingEscalationId = escalationId;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
/** Clears a session's pending escalation. */
|
|
112
|
+
clearPendingEscalation(label) {
|
|
113
|
+
const managed = this.sessions.get(label);
|
|
114
|
+
if (managed) {
|
|
115
|
+
managed.pendingEscalationId = null;
|
|
116
|
+
managed.escalationResolving = false;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
/** Returns sessions that have pending escalations. */
|
|
120
|
+
withPendingEscalation() {
|
|
121
|
+
return [...this.sessions.values()].filter((m) => m.pendingEscalationId !== null);
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Finds the most recently registered Signal session label.
|
|
125
|
+
* Returns null if no Signal sessions exist.
|
|
126
|
+
*/
|
|
127
|
+
findMostRecentSignalLabel() {
|
|
128
|
+
const signalSessions = this.byKind('signal');
|
|
129
|
+
if (signalSessions.length === 0)
|
|
130
|
+
return null;
|
|
131
|
+
return Math.max(...signalSessions.map((m) => m.label));
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
//# sourceMappingURL=session-manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-manager.js","sourceRoot":"","sources":["../../src/session/session-manager.ts"],"names":[],"mappings":"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"}
|
package/dist/session/types.d.ts
CHANGED
|
@@ -180,12 +180,45 @@ export interface SessionOptions {
|
|
|
180
180
|
* The transport uses this to clear the escalation banner and notify the user.
|
|
181
181
|
*/
|
|
182
182
|
onEscalationExpired?: () => void;
|
|
183
|
+
/**
|
|
184
|
+
* Callback invoked when a pending escalation is resolved (approved or denied).
|
|
185
|
+
* Fires after the response file is written, regardless of whether the resolution
|
|
186
|
+
* was initiated by the transport or by the proxy (e.g., Signal approve command).
|
|
187
|
+
*/
|
|
188
|
+
onEscalationResolved?: (escalationId: string, decision: 'approved' | 'denied') => void;
|
|
183
189
|
/**
|
|
184
190
|
* Callback invoked during message processing with diagnostic events.
|
|
185
191
|
* Transports use this to display progress (e.g., tool call previews).
|
|
186
192
|
* If not provided, diagnostics are silently dropped.
|
|
187
193
|
*/
|
|
188
194
|
onDiagnostic?: (event: DiagnosticEvent) => void;
|
|
195
|
+
/**
|
|
196
|
+
* Validated workspace path. When provided, this existing directory replaces
|
|
197
|
+
* the session sandbox as the agent's working area (allowedDirectory).
|
|
198
|
+
* Must be validated via validateWorkspacePath() before passing here.
|
|
199
|
+
*/
|
|
200
|
+
workspacePath?: string;
|
|
201
|
+
/**
|
|
202
|
+
* When set, loads compiled-policy.json (and optionally
|
|
203
|
+
* dynamic-lists.json) from this directory instead of the global
|
|
204
|
+
* generated directory. Tool annotations are always loaded from
|
|
205
|
+
* the global location regardless of this setting.
|
|
206
|
+
*
|
|
207
|
+
* Used by cron sessions to load task-scoped policy.
|
|
208
|
+
*/
|
|
209
|
+
policyDir?: string;
|
|
210
|
+
/**
|
|
211
|
+
* Additional content appended to the system prompt.
|
|
212
|
+
* Used by cron sessions to inject task context and workspace
|
|
213
|
+
* conventions.
|
|
214
|
+
*/
|
|
215
|
+
systemPromptAugmentation?: string;
|
|
216
|
+
/**
|
|
217
|
+
* When true, disables the auto-approver for this session even if
|
|
218
|
+
* enabled in user config. Used by cron/headless sessions where there
|
|
219
|
+
* is no interactive user context to match escalations against.
|
|
220
|
+
*/
|
|
221
|
+
disableAutoApprove?: boolean;
|
|
189
222
|
}
|
|
190
223
|
/**
|
|
191
224
|
* The core session contract. A session is a stateful conversation
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Workspace path validation for the --workspace CLI flag.
|
|
3
|
+
*
|
|
4
|
+
* Validates that a user-provided workspace path is safe to use as the
|
|
5
|
+
* agent's working directory. The workspace replaces the session sandbox
|
|
6
|
+
* as the allowedDirectory, so it must not overlap with protected paths
|
|
7
|
+
* or sensitive system directories.
|
|
8
|
+
*/
|
|
9
|
+
/** Returns true when `child` is equal to or nested inside `parent`. */
|
|
10
|
+
export declare function isEqualOrInside(child: string, parent: string): boolean;
|
|
11
|
+
/**
|
|
12
|
+
* Validates and canonicalizes a workspace path.
|
|
13
|
+
*
|
|
14
|
+
* @param rawPath - The user-provided path (may be relative, contain ~, etc.)
|
|
15
|
+
* @param protectedPaths - The list of protected paths from config
|
|
16
|
+
* @returns The canonical absolute path
|
|
17
|
+
* @throws {Error} if the path fails any validation check
|
|
18
|
+
*/
|
|
19
|
+
export declare function validateWorkspacePath(rawPath: string, protectedPaths: string[]): string;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Workspace path validation for the --workspace CLI flag.
|
|
3
|
+
*
|
|
4
|
+
* Validates that a user-provided workspace path is safe to use as the
|
|
5
|
+
* agent's working directory. The workspace replaces the session sandbox
|
|
6
|
+
* as the allowedDirectory, so it must not overlap with protected paths
|
|
7
|
+
* or sensitive system directories.
|
|
8
|
+
*/
|
|
9
|
+
import { statSync } from 'node:fs';
|
|
10
|
+
import { homedir } from 'node:os';
|
|
11
|
+
import { resolve } from 'node:path';
|
|
12
|
+
import { expandTilde, resolveRealPath } from '../types/argument-roles.js';
|
|
13
|
+
import { getIronCurtainHome } from '../config/paths.js';
|
|
14
|
+
/** Returns true when `child` is equal to or nested inside `parent`. */
|
|
15
|
+
export function isEqualOrInside(child, parent) {
|
|
16
|
+
if (child === parent)
|
|
17
|
+
return true;
|
|
18
|
+
const prefix = parent === '/' ? '/' : parent + '/';
|
|
19
|
+
return child.startsWith(prefix);
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Validates and canonicalizes a workspace path.
|
|
23
|
+
*
|
|
24
|
+
* @param rawPath - The user-provided path (may be relative, contain ~, etc.)
|
|
25
|
+
* @param protectedPaths - The list of protected paths from config
|
|
26
|
+
* @returns The canonical absolute path
|
|
27
|
+
* @throws {Error} if the path fails any validation check
|
|
28
|
+
*/
|
|
29
|
+
export function validateWorkspacePath(rawPath, protectedPaths) {
|
|
30
|
+
const absolute = resolve(expandTilde(rawPath));
|
|
31
|
+
const canonical = resolveRealPath(absolute);
|
|
32
|
+
// Must exist and be a directory
|
|
33
|
+
let stat;
|
|
34
|
+
try {
|
|
35
|
+
stat = statSync(canonical);
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
throw new Error(`Workspace path does not exist: ${canonical}`);
|
|
39
|
+
}
|
|
40
|
+
if (!stat.isDirectory()) {
|
|
41
|
+
throw new Error(`Workspace path is not a directory: ${canonical}`);
|
|
42
|
+
}
|
|
43
|
+
if (canonical === '/') {
|
|
44
|
+
throw new Error('Cannot use root directory as workspace');
|
|
45
|
+
}
|
|
46
|
+
if (canonical === resolveRealPath(homedir())) {
|
|
47
|
+
throw new Error('Cannot use home directory as workspace');
|
|
48
|
+
}
|
|
49
|
+
const ironCurtainHome = resolveRealPath(getIronCurtainHome());
|
|
50
|
+
if (isEqualOrInside(canonical, ironCurtainHome)) {
|
|
51
|
+
throw new Error(`Workspace path is inside the IronCurtain home directory: ${canonical}`);
|
|
52
|
+
}
|
|
53
|
+
// Check that workspace is not inside a protected path.
|
|
54
|
+
// The reverse direction (protected path inside workspace) is intentionally
|
|
55
|
+
// NOT checked here — the PolicyEngine already protects those paths at
|
|
56
|
+
// runtime regardless of the allowedDirectory, so a workspace that happens
|
|
57
|
+
// to contain e.g. src/config/generated/ is perfectly safe.
|
|
58
|
+
for (const pp of protectedPaths) {
|
|
59
|
+
const protectedCanonical = resolveRealPath(pp);
|
|
60
|
+
if (isEqualOrInside(canonical, protectedCanonical)) {
|
|
61
|
+
throw new Error(`Workspace path overlaps with protected path: ${protectedCanonical}`);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return canonical;
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=workspace-validation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workspace-validation.js","sourceRoot":"","sources":["../../src/session/workspace-validation.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACnC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAC1E,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAExD,uEAAuE;AACvE,MAAM,UAAU,eAAe,CAAC,KAAa,EAAE,MAAc;IAC3D,IAAI,KAAK,KAAK,MAAM;QAAE,OAAO,IAAI,CAAC;IAClC,MAAM,MAAM,GAAG,MAAM,KAAK,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,GAAG,GAAG,CAAC;IACnD,OAAO,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;AAClC,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,qBAAqB,CAAC,OAAe,EAAE,cAAwB;IAC7E,MAAM,QAAQ,GAAG,OAAO,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC;IAC/C,MAAM,SAAS,GAAG,eAAe,CAAC,QAAQ,CAAC,CAAC;IAE5C,gCAAgC;IAChC,IAAI,IAAiC,CAAC;IACtC,IAAI,CAAC;QACH,IAAI,GAAG,QAAQ,CAAC,SAAS,CAAC,CAAC;IAC7B,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,KAAK,CAAC,kCAAkC,SAAS,EAAE,CAAC,CAAC;IACjE,CAAC;IACD,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CAAC,sCAAsC,SAAS,EAAE,CAAC,CAAC;IACrE,CAAC;IAED,IAAI,SAAS,KAAK,GAAG,EAAE,CAAC;QACtB,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAC;IAC5D,CAAC;IAED,IAAI,SAAS,KAAK,eAAe,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC;QAC7C,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAC;IAC5D,CAAC;IAED,MAAM,eAAe,GAAG,eAAe,CAAC,kBAAkB,EAAE,CAAC,CAAC;IAC9D,IAAI,eAAe,CAAC,SAAS,EAAE,eAAe,CAAC,EAAE,CAAC;QAChD,MAAM,IAAI,KAAK,CAAC,4DAA4D,SAAS,EAAE,CAAC,CAAC;IAC3F,CAAC;IAED,uDAAuD;IACvD,2EAA2E;IAC3E,sEAAsE;IACtE,0EAA0E;IAC1E,2DAA2D;IAC3D,KAAK,MAAM,EAAE,IAAI,cAAc,EAAE,CAAC;QAChC,MAAM,kBAAkB,GAAG,eAAe,CAAC,EAAE,CAAC,CAAC;QAE/C,IAAI,eAAe,CAAC,SAAS,EAAE,kBAAkB,CAAC,EAAE,CAAC;YACnD,MAAM,IAAI,KAAK,CAAC,gDAAgD,kBAAkB,EAAE,CAAC,CAAC;QACxF,CAAC;IACH,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC"}
|
|
@@ -6,6 +6,8 @@
|
|
|
6
6
|
* indefinitely. Sessions are created on demand when the user sends a
|
|
7
7
|
* Signal message and destroyed when they end.
|
|
8
8
|
*/
|
|
9
|
+
import type { CommandSpec } from '../cli-help.js';
|
|
10
|
+
export declare const botSpec: CommandSpec;
|
|
9
11
|
export interface BotOptions {
|
|
10
12
|
/** Explicit agent selection (e.g., 'claude-code'). */
|
|
11
13
|
agent?: string;
|
|
@@ -15,6 +15,14 @@ import { SignalBotDaemon } from './signal-bot-daemon.js';
|
|
|
15
15
|
import { createSignalContainerManager } from './signal-container.js';
|
|
16
16
|
import { resolveSignalConfig } from './signal-config.js';
|
|
17
17
|
import * as logger from '../logger.js';
|
|
18
|
+
export const botSpec = {
|
|
19
|
+
name: 'ironcurtain bot',
|
|
20
|
+
description: 'Run the Signal transport (standalone, without cron scheduler)',
|
|
21
|
+
usage: ['ironcurtain bot [options]'],
|
|
22
|
+
options: [
|
|
23
|
+
{ flag: 'agent', short: 'a', description: 'Agent mode: builtin or claude-code (Docker)', placeholder: '<name>' },
|
|
24
|
+
],
|
|
25
|
+
};
|
|
18
26
|
export async function runBot(options = {}) {
|
|
19
27
|
const userConfig = loadUserConfig();
|
|
20
28
|
const signalConfig = resolveSignalConfig(userConfig);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bot-command.js","sourceRoot":"","sources":["../../src/signal/bot-command.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC1D,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAClE,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,4BAA4B,EAAE,MAAM,uBAAuB,CAAC;AACrE,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,KAAK,MAAM,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"bot-command.js","sourceRoot":"","sources":["../../src/signal/bot-command.ts"],"names":[],"mappings":"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"}
|
package/dist/signal/format.d.ts
CHANGED
|
@@ -49,3 +49,30 @@ export declare function formatSessionList(sessions: SessionListEntry[], currentL
|
|
|
49
49
|
* Prefixes a message with `[#N]` when multiple sessions are active.
|
|
50
50
|
*/
|
|
51
51
|
export declare function prefixWithLabel(text: string, label: number, sessionCount: number): string;
|
|
52
|
+
/**
|
|
53
|
+
* Information about a scheduled job for display in Signal.
|
|
54
|
+
* Dates are ISO strings (serialized by the control socket).
|
|
55
|
+
*/
|
|
56
|
+
export interface JobListEntry {
|
|
57
|
+
readonly job: {
|
|
58
|
+
readonly id: string;
|
|
59
|
+
readonly name: string;
|
|
60
|
+
readonly schedule: string;
|
|
61
|
+
readonly enabled: boolean;
|
|
62
|
+
};
|
|
63
|
+
readonly nextRun: string | null;
|
|
64
|
+
readonly lastRun: {
|
|
65
|
+
readonly outcome: {
|
|
66
|
+
readonly kind: string;
|
|
67
|
+
readonly message?: string;
|
|
68
|
+
readonly dimension?: string;
|
|
69
|
+
};
|
|
70
|
+
readonly startedAt: string;
|
|
71
|
+
} | undefined;
|
|
72
|
+
readonly isRunning: boolean;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Formats the /jobs command output.
|
|
76
|
+
* Shows each job with schedule, status, next run, and last run outcome.
|
|
77
|
+
*/
|
|
78
|
+
export declare function formatJobList(jobs: JobListEntry[]): string;
|
package/dist/signal/format.js
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* (**bold**, *italic*, `mono`, ~strike~). Output is intended
|
|
6
6
|
* to be sent with `text_mode: "styled"`.
|
|
7
7
|
*/
|
|
8
|
+
import { describeCronExpression, formatRelativeTime } from '../cron/format-utils.js';
|
|
8
9
|
/** Maximum length for a single Signal message. */
|
|
9
10
|
export const SIGNAL_MAX_MESSAGE_LENGTH = 2000;
|
|
10
11
|
/**
|
|
@@ -128,6 +129,64 @@ export function prefixWithLabel(text, label, sessionCount) {
|
|
|
128
129
|
return text;
|
|
129
130
|
return `[#${label}] ${text}`;
|
|
130
131
|
}
|
|
132
|
+
/**
|
|
133
|
+
* Formats the /jobs command output.
|
|
134
|
+
* Shows each job with schedule, status, next run, and last run outcome.
|
|
135
|
+
*/
|
|
136
|
+
export function formatJobList(jobs) {
|
|
137
|
+
if (jobs.length === 0)
|
|
138
|
+
return 'No scheduled jobs.';
|
|
139
|
+
const lines = ['**Scheduled jobs:**'];
|
|
140
|
+
for (const entry of jobs) {
|
|
141
|
+
lines.push('');
|
|
142
|
+
lines.push(formatJobEntry(entry));
|
|
143
|
+
}
|
|
144
|
+
return lines.join('\n');
|
|
145
|
+
}
|
|
146
|
+
function formatJobEntry(entry) {
|
|
147
|
+
const { job, nextRun, lastRun, isRunning } = entry;
|
|
148
|
+
const lines = [];
|
|
149
|
+
// Header: name + status tags
|
|
150
|
+
const tags = [];
|
|
151
|
+
if (isRunning)
|
|
152
|
+
tags.push('[RUNNING]');
|
|
153
|
+
if (!job.enabled)
|
|
154
|
+
tags.push('[DISABLED]');
|
|
155
|
+
const tagSuffix = tags.length > 0 ? ' ' + tags.join(' ') : '';
|
|
156
|
+
lines.push(`**${job.name}** (\`${job.id}\`)${tagSuffix}`);
|
|
157
|
+
// Schedule
|
|
158
|
+
const scheduleDesc = describeCronExpression(job.schedule);
|
|
159
|
+
lines.push(` Schedule: ${scheduleDesc}`);
|
|
160
|
+
// Next run
|
|
161
|
+
if (nextRun) {
|
|
162
|
+
lines.push(` Next run: ${formatRelativeTime(new Date(nextRun))}`);
|
|
163
|
+
}
|
|
164
|
+
else if (!job.enabled) {
|
|
165
|
+
lines.push(' Next run: disabled');
|
|
166
|
+
}
|
|
167
|
+
else {
|
|
168
|
+
lines.push(' Next run: --');
|
|
169
|
+
}
|
|
170
|
+
// Last run
|
|
171
|
+
if (lastRun) {
|
|
172
|
+
const outcomeStr = formatRunOutcome(lastRun.outcome);
|
|
173
|
+
const timeStr = formatRelativeTime(new Date(lastRun.startedAt));
|
|
174
|
+
lines.push(` Last run: ${outcomeStr}, ${timeStr}`);
|
|
175
|
+
}
|
|
176
|
+
return lines.join('\n');
|
|
177
|
+
}
|
|
178
|
+
function formatRunOutcome(outcome) {
|
|
179
|
+
switch (outcome.kind) {
|
|
180
|
+
case 'success':
|
|
181
|
+
return 'success';
|
|
182
|
+
case 'budget_exhausted':
|
|
183
|
+
return `budget exhausted (${outcome.dimension ?? 'unknown'})`;
|
|
184
|
+
case 'error':
|
|
185
|
+
return `error: ${outcome.message ?? 'unknown'}`;
|
|
186
|
+
default:
|
|
187
|
+
return outcome.kind;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
131
190
|
// --- Private helpers ---
|
|
132
191
|
function formatBudgetLine(label, current, limit, format) {
|
|
133
192
|
const currentStr = format(current);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"format.js","sourceRoot":"","sources":["../../src/signal/format.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;
|
|
1
|
+
{"version":3,"file":"format.js","sourceRoot":"","sources":["../../src/signal/format.ts"],"names":[],"mappings":"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"}
|