@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
|
@@ -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,6 +180,12 @@ 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).
|
|
@@ -192,6 +198,27 @@ export interface SessionOptions {
|
|
|
192
198
|
* Must be validated via validateWorkspacePath() before passing here.
|
|
193
199
|
*/
|
|
194
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;
|
|
195
222
|
}
|
|
196
223
|
/**
|
|
197
224
|
* The core session contract. A session is a stateful conversation
|
|
@@ -6,6 +6,8 @@
|
|
|
6
6
|
* as the allowedDirectory, so it must not overlap with protected paths
|
|
7
7
|
* or sensitive system directories.
|
|
8
8
|
*/
|
|
9
|
+
/** Returns true when `child` is equal to or nested inside `parent`. */
|
|
10
|
+
export declare function isEqualOrInside(child: string, parent: string): boolean;
|
|
9
11
|
/**
|
|
10
12
|
* Validates and canonicalizes a workspace path.
|
|
11
13
|
*
|
|
@@ -12,7 +12,7 @@ import { resolve } from 'node:path';
|
|
|
12
12
|
import { expandTilde, resolveRealPath } from '../types/argument-roles.js';
|
|
13
13
|
import { getIronCurtainHome } from '../config/paths.js';
|
|
14
14
|
/** Returns true when `child` is equal to or nested inside `parent`. */
|
|
15
|
-
function isEqualOrInside(child, parent) {
|
|
15
|
+
export function isEqualOrInside(child, parent) {
|
|
16
16
|
if (child === parent)
|
|
17
17
|
return true;
|
|
18
18
|
const prefix = parent === '/' ? '/' : parent + '/';
|
|
@@ -50,15 +50,16 @@ export function validateWorkspacePath(rawPath, protectedPaths) {
|
|
|
50
50
|
if (isEqualOrInside(canonical, ironCurtainHome)) {
|
|
51
51
|
throw new Error(`Workspace path is inside the IronCurtain home directory: ${canonical}`);
|
|
52
52
|
}
|
|
53
|
-
//
|
|
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.
|
|
54
58
|
for (const pp of protectedPaths) {
|
|
55
59
|
const protectedCanonical = resolveRealPath(pp);
|
|
56
60
|
if (isEqualOrInside(canonical, protectedCanonical)) {
|
|
57
61
|
throw new Error(`Workspace path overlaps with protected path: ${protectedCanonical}`);
|
|
58
62
|
}
|
|
59
|
-
if (isEqualOrInside(protectedCanonical, canonical)) {
|
|
60
|
-
throw new Error(`Workspace would contain protected path ${protectedCanonical} — ` + `use a more specific subdirectory`);
|
|
61
|
-
}
|
|
62
63
|
}
|
|
63
64
|
return canonical;
|
|
64
65
|
}
|
|
@@ -1 +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,
|
|
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":"AAAA;;;;;;GAMG;AAGH,OAAO,EAAE,sBAAsB,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAErF,kDAAkD;AAClD,MAAM,CAAC,MAAM,yBAAyB,GAAG,IAAI,CAAC;AAE9C;;;;;;;GAOG;AACH,MAAM,UAAU,sBAAsB,CAAC,OAA0B,EAAE,YAAqB;IACtF,MAAM,SAAS,GAAG,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,+BAA+B;IACtE,MAAM,QAAQ,GAAG,YAAY,IAAI,IAAI,CAAC,CAAC,CAAC,MAAM,YAAY,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;IACnE,MAAM,MAAM,GAAG,eAAe,QAAQ,6BAA6B,CAAC;IACpE,MAAM,QAAQ,GAAG,WAAW,OAAO,CAAC,UAAU,IAAI,OAAO,CAAC,QAAQ,IAAI,CAAC;IACvE,MAAM,QAAQ,GAAG,gBAAgB,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,SAAS,CAAC,IAAI,CAAC;IACvE,MAAM,YAAY,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAC9G,MAAM,UAAU,GAAG,YAAY,OAAO,CAAC,MAAM,GAAG,CAAC;IACjD,MAAM,YAAY,GAAG,+BAA+B,CAAC;IAErD,OAAO;QACL,SAAS;QACT,MAAM;QACN,SAAS;QACT,QAAQ;QACR,QAAQ;QACR,GAAG,YAAY;QACf,UAAU;QACV,SAAS;QACT,YAAY;QACZ,SAAS;KACV,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CAAC,MAAoB;IACtD,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,GAAG,MAAM,CAAC;IACtC,MAAM,KAAK,GAAa,CAAC,0BAA0B,CAAC,CAAC;IAErD,IAAI,MAAM,CAAC,sBAAsB,EAAE,CAAC;QAClC,KAAK,CAAC,IAAI,CAAC,gBAAgB,CAAC,QAAQ,EAAE,MAAM,CAAC,WAAW,EAAE,MAAM,CAAC,cAAc,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC;IAC/G,CAAC;SAAM,CAAC;QACN,KAAK,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;IAC9B,CAAC;IACD,KAAK,CAAC,IAAI,CAAC,gBAAgB,CAAC,OAAO,EAAE,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC;IACjF,KAAK,CAAC,IAAI,CAAC,gBAAgB,CAAC,MAAM,EAAE,MAAM,CAAC,cAAc,EAAE,MAAM,CAAC,iBAAiB,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IAClH,KAAK,CAAC,IAAI,CACR,gBAAgB,CAAC,WAAW,EAAE,MAAM,CAAC,gBAAgB,EAAE,MAAM,CAAC,mBAAmB,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAC9G,CAAC;IAEF,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,KAAK,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC;IAClC,IAAI,MAAM,CAAC,sBAAsB,EAAE,CAAC;QAClC,KAAK,CAAC,IAAI,CAAC,aAAa,UAAU,CAAC,WAAW,CAAC,cAAc,EAAE,EAAE,CAAC,CAAC;IACrE,CAAC;SAAM,CAAC;QACN,KAAK,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;IAC9B,CAAC;IACD,KAAK,CAAC,IAAI,CAAC,YAAY,UAAU,CAAC,SAAS,EAAE,CAAC,CAAC;IAC/C,KAAK,CAAC,IAAI,CAAC,kBAAkB,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC;IACtE,KAAK,CAAC,IAAI,CAAC,iBAAiB,UAAU,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IAEtE,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,mBAAmB,CAAC,MAAoB;IACtD,MAAM,EAAE,UAAU,EAAE,GAAG,MAAM,CAAC;IAC9B,MAAM,UAAU,GAAG,MAAM,CAAC,sBAAsB,CAAC,CAAC,CAAC,GAAG,UAAU,CAAC,WAAW,CAAC,cAAc,EAAE,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC;IAC9G,OAAO,CACL,YAAY,UAAU,EAAE;QACxB,GAAG,UAAU,CAAC,SAAS,QAAQ;QAC/B,KAAK,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,aAAa,CAAC,GAAG;QAC5C,OAAO,UAAU,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAChD,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,YAAY,CAAC,IAAY,EAAE,SAAiB;IAC1D,IAAI,IAAI,CAAC,MAAM,IAAI,SAAS;QAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IAE5C,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,IAAI,SAAS,GAAG,IAAI,CAAC;IAErB,OAAO,SAAS,CAAC,MAAM,GAAG,SAAS,EAAE,CAAC;QACpC,iDAAiD;QACjD,IAAI,QAAQ,GAAG,SAAS,CAAC,WAAW,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;QACxD,IAAI,QAAQ,IAAI,CAAC,EAAE,CAAC;YAClB,0BAA0B;YAC1B,QAAQ,GAAG,SAAS,CAAC,WAAW,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;QACpD,CAAC;QACD,IAAI,QAAQ,IAAI,CAAC,EAAE,CAAC;YAClB,2BAA2B;YAC3B,QAAQ,GAAG,SAAS,CAAC;QACvB,CAAC;QAED,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;QACxD,SAAS,GAAG,SAAS,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,SAAS,EAAE,CAAC;IACxD,CAAC;IAED,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACzB,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IACzB,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAWD;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAAC,QAA4B,EAAE,YAA2B;IACzF,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,qBAAqB,CAAC;IAExD,MAAM,KAAK,GAAG,CAAC,sBAAsB,CAAC,CAAC;IACvC,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;QACzB,MAAM,MAAM,GAAG,CAAC,CAAC,KAAK,KAAK,YAAY,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;QACpD,KAAK,CAAC,IAAI,CAAC,GAAG,MAAM,KAAK,CAAC,CAAC,KAAK,YAAY,CAAC,CAAC,SAAS,aAAa,CAAC,CAAC,aAAa,GAAG,CAAC,CAAC;IAC1F,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,eAAe,CAAC,IAAY,EAAE,KAAa,EAAE,YAAoB;IAC/E,IAAI,YAAY,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IACnC,OAAO,KAAK,KAAK,KAAK,IAAI,EAAE,CAAC;AAC/B,CAAC;AAyBD;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,IAAoB;IAChD,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,oBAAoB,CAAC;IAEnD,MAAM,KAAK,GAAG,CAAC,qBAAqB,CAAC,CAAC;IACtC,KAAK,MAAM,KAAK,IAAI,IAAI,EAAE,CAAC;QACzB,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACf,KAAK,CAAC,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC,CAAC;IACpC,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED,SAAS,cAAc,CAAC,KAAmB;IACzC,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,GAAG,KAAK,CAAC;IACnD,MAAM,KAAK,GAAa,EAAE,CAAC;IAE3B,6BAA6B;IAC7B,MAAM,IAAI,GAAa,EAAE,CAAC;IAC1B,IAAI,SAAS;QAAE,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IACtC,IAAI,CAAC,GAAG,CAAC,OAAO;QAAE,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IAC1C,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAC9D,KAAK,CAAC,IAAI,CAAC,KAAK,GAAG,CAAC,IAAI,SAAS,GAAG,CAAC,EAAE,MAAM,SAAS,EAAE,CAAC,CAAC;IAE1D,WAAW;IACX,MAAM,YAAY,GAAG,sBAAsB,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IAC1D,KAAK,CAAC,IAAI,CAAC,eAAe,YAAY,EAAE,CAAC,CAAC;IAE1C,WAAW;IACX,IAAI,OAAO,EAAE,CAAC;QACZ,KAAK,CAAC,IAAI,CAAC,eAAe,kBAAkB,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC;IACrE,CAAC;SAAM,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;QACxB,KAAK,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC;IACrC,CAAC;SAAM,CAAC;QACN,KAAK,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;IAC/B,CAAC;IAED,WAAW;IACX,IAAI,OAAO,EAAE,CAAC;QACZ,MAAM,UAAU,GAAG,gBAAgB,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QACrD,MAAM,OAAO,GAAG,kBAAkB,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC;QAChE,KAAK,CAAC,IAAI,CAAC,eAAe,UAAU,KAAK,OAAO,EAAE,CAAC,CAAC;IACtD,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED,SAAS,gBAAgB,CAAC,OAA+D;IACvF,QAAQ,OAAO,CAAC,IAAI,EAAE,CAAC;QACrB,KAAK,SAAS;YACZ,OAAO,SAAS,CAAC;QACnB,KAAK,kBAAkB;YACrB,OAAO,qBAAqB,OAAO,CAAC,SAAS,IAAI,SAAS,GAAG,CAAC;QAChE,KAAK,OAAO;YACV,OAAO,UAAU,OAAO,CAAC,OAAO,IAAI,SAAS,EAAE,CAAC;QAClD;YACE,OAAO,OAAO,CAAC,IAAI,CAAC;IACxB,CAAC;AACH,CAAC;AAED,0BAA0B;AAE1B,SAAS,gBAAgB,CAAC,KAAa,EAAE,OAAe,EAAE,KAAoB,EAAE,MAA6B;IAC3G,MAAM,UAAU,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC;IACnC,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,KAAK,KAAK,KAAK,UAAU,aAAa,CAAC;IAClE,MAAM,GAAG,GAAG,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,OAAO,GAAG,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAChE,OAAO,KAAK,KAAK,KAAK,UAAU,MAAM,MAAM,CAAC,KAAK,CAAC,KAAK,GAAG,IAAI,CAAC;AAClE,CAAC"}
|
|
@@ -9,10 +9,15 @@
|
|
|
9
9
|
* - Identity verification with TTL cache (5 min), fail-closed
|
|
10
10
|
* - Escalation state with race prevention (per-session)
|
|
11
11
|
* - Message sending via POST /v2/send with text_mode: "styled"
|
|
12
|
+
*
|
|
13
|
+
* Session state is owned by SessionManager (injected via constructor).
|
|
14
|
+
* This class only handles Signal-specific concerns: WebSocket, identity,
|
|
15
|
+
* message parsing, and command dispatch.
|
|
12
16
|
*/
|
|
13
17
|
import { type ResolvedSignalConfig } from './signal-config.js';
|
|
14
18
|
import type { SessionMode } from '../session/types.js';
|
|
15
19
|
import type { SignalContainerManager } from './signal-container.js';
|
|
20
|
+
import { SessionManager } from '../session/session-manager.js';
|
|
16
21
|
/**
|
|
17
22
|
* Signal message envelope received via WebSocket.
|
|
18
23
|
* Only the fields relevant to IronCurtain are typed here;
|
|
@@ -46,20 +51,19 @@ export interface SignalBotDaemonOptions {
|
|
|
46
51
|
readonly config: ResolvedSignalConfig;
|
|
47
52
|
readonly containerManager: SignalContainerManager;
|
|
48
53
|
readonly mode: SessionMode;
|
|
54
|
+
readonly sessionManager?: SessionManager;
|
|
49
55
|
}
|
|
50
56
|
export declare class SignalBotDaemon {
|
|
51
57
|
private config;
|
|
52
58
|
private readonly containerManager;
|
|
53
59
|
private readonly mode;
|
|
60
|
+
private readonly sessionManager;
|
|
54
61
|
private ws;
|
|
55
62
|
private baseUrl;
|
|
56
63
|
private closed;
|
|
57
64
|
private reconnectAttempts;
|
|
58
65
|
private static readonly MAX_RECONNECT_DELAY_MS;
|
|
59
66
|
private static readonly BASE_RECONNECT_DELAY_MS;
|
|
60
|
-
private sessions;
|
|
61
|
-
private currentLabel;
|
|
62
|
-
private nextLabel;
|
|
63
67
|
private readonly maxConcurrentSessions;
|
|
64
68
|
private identityLocked;
|
|
65
69
|
private lastIdentityCheckMs;
|
|
@@ -74,12 +78,23 @@ export declare class SignalBotDaemon {
|
|
|
74
78
|
*/
|
|
75
79
|
private scheduleSessionOp;
|
|
76
80
|
/**
|
|
77
|
-
*
|
|
78
|
-
*
|
|
81
|
+
* Connects the daemon: starts the Docker container, waits for
|
|
82
|
+
* health, connects WebSocket, and sends the online greeting.
|
|
83
|
+
* Throws if any step fails (container won't start, health timeout, etc.).
|
|
84
|
+
*/
|
|
85
|
+
connect(): Promise<void>;
|
|
86
|
+
/**
|
|
87
|
+
* Blocks until shutdown() is called (e.g., SIGTERM/SIGINT).
|
|
88
|
+
* Call connect() first to establish the connection.
|
|
89
|
+
*/
|
|
90
|
+
run(): Promise<void>;
|
|
91
|
+
/**
|
|
92
|
+
* Convenience: connects and then blocks until shutdown.
|
|
93
|
+
* Used by the standalone `ironcurtain bot` command.
|
|
79
94
|
*/
|
|
80
95
|
start(): Promise<void>;
|
|
81
96
|
/**
|
|
82
|
-
* Initiates graceful shutdown. Ends all
|
|
97
|
+
* Initiates graceful shutdown. Ends all Signal sessions,
|
|
83
98
|
* closes the WebSocket, and unblocks start().
|
|
84
99
|
*/
|
|
85
100
|
shutdown(): Promise<void>;
|
|
@@ -93,12 +108,13 @@ export declare class SignalBotDaemon {
|
|
|
93
108
|
private scheduleReconnect;
|
|
94
109
|
private handleIncomingMessage;
|
|
95
110
|
/**
|
|
96
|
-
* Routes a user message to the current session. Creates a new
|
|
111
|
+
* Routes a user message to the current Signal session. Creates a new
|
|
97
112
|
* session if none exists. Handles BudgetExhaustedError by ending
|
|
98
113
|
* the exhausted session and notifying the user.
|
|
99
114
|
*
|
|
100
115
|
* Supports one-shot `#N` prefix routing: `#2 do something` routes
|
|
101
116
|
* "do something" to session #2 without changing currentLabel.
|
|
117
|
+
* Only Signal sessions accept forwarded messages.
|
|
102
118
|
*/
|
|
103
119
|
private routeToSession;
|
|
104
120
|
/**
|
|
@@ -107,34 +123,20 @@ export declare class SignalBotDaemon {
|
|
|
107
123
|
*/
|
|
108
124
|
private forwardToSession;
|
|
109
125
|
/**
|
|
110
|
-
* Creates a new session with a fresh SignalSessionTransport.
|
|
126
|
+
* Creates a new Signal session with a fresh SignalSessionTransport.
|
|
111
127
|
* Follows the same pattern as index.ts: create transport,
|
|
112
128
|
* wire callbacks, create session, start transport.
|
|
113
129
|
* Returns the label of the new session.
|
|
114
130
|
*/
|
|
115
131
|
private startNewSession;
|
|
116
|
-
/**
|
|
117
|
-
* Ends a specific session by label and cleans up.
|
|
118
|
-
* If it was the current session, auto-switches to the most recent remaining.
|
|
119
|
-
*/
|
|
120
|
-
endSession(label: number): Promise<void>;
|
|
121
|
-
/**
|
|
122
|
-
* Convenience method: ends the current session (if any).
|
|
123
|
-
*/
|
|
124
|
-
endCurrentSession(): Promise<void>;
|
|
125
|
-
/**
|
|
126
|
-
* Auto-switches currentLabel to the highest remaining label (most recent),
|
|
127
|
-
* or null if no sessions remain.
|
|
128
|
-
*/
|
|
129
|
-
private autoSwitchCurrent;
|
|
130
132
|
/**
|
|
131
133
|
* Checks if the message is an escalation reply.
|
|
132
134
|
* Accepts: approve, deny, /approve, /deny (case-insensitive).
|
|
133
135
|
* Optionally with a session label: "approve #2", "/approve 2".
|
|
134
136
|
*
|
|
135
|
-
* Routes to the session with a pending escalation.
|
|
136
|
-
*
|
|
137
|
-
*
|
|
137
|
+
* Routes to the session with a pending escalation.
|
|
138
|
+
* Works across ALL session types (signal + cron) so that
|
|
139
|
+
* `approve #3` from Signal can approve a cron job's escalation.
|
|
138
140
|
*/
|
|
139
141
|
private handleEscalationReply;
|
|
140
142
|
/** Called by SignalSessionTransport when the session surfaces an escalation. */
|