@s-gw/s-gw 0.1.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.
Files changed (123) hide show
  1. package/.codex-plugin/plugin.json +35 -0
  2. package/.mcp.json +16 -0
  3. package/LICENSE +201 -0
  4. package/NOTICE +7 -0
  5. package/README.md +197 -0
  6. package/TRADEMARKS.md +9 -0
  7. package/assets/icons/aws-ec2.png +0 -0
  8. package/assets/icons/lucide/bot.svg +8 -0
  9. package/assets/icons/lucide/monitor.svg +5 -0
  10. package/assets/icons/lucide/server.svg +6 -0
  11. package/assets/icons/lucide/terminal.svg +4 -0
  12. package/assets/icons/s-gw-128.png +0 -0
  13. package/assets/icons/s-gw-16.png +0 -0
  14. package/assets/icons/s-gw-180.png +0 -0
  15. package/assets/icons/s-gw-192.png +0 -0
  16. package/assets/icons/s-gw-32.png +0 -0
  17. package/assets/icons/s-gw-64.png +0 -0
  18. package/assets/icons/s-gw-menu-bar-template.png +0 -0
  19. package/dist/agent-context.d.ts +17 -0
  20. package/dist/agent-context.js +207 -0
  21. package/dist/agents.d.ts +64 -0
  22. package/dist/agents.js +763 -0
  23. package/dist/cli.d.ts +2 -0
  24. package/dist/cli.js +1385 -0
  25. package/dist/command-suggest.d.ts +3 -0
  26. package/dist/command-suggest.js +131 -0
  27. package/dist/console-server.d.ts +16 -0
  28. package/dist/console-server.js +978 -0
  29. package/dist/console-ui/assets/codex-DYTPdPxi.png +0 -0
  30. package/dist/console-ui/assets/cursor-CBrUTJD-.png +0 -0
  31. package/dist/console-ui/assets/geist-cyrillic-ext-wght-normal-DjL33-gN.woff2 +0 -0
  32. package/dist/console-ui/assets/geist-cyrillic-wght-normal-BEAKL7Jp.woff2 +0 -0
  33. package/dist/console-ui/assets/geist-latin-ext-wght-normal-DC-KSUi6.woff2 +0 -0
  34. package/dist/console-ui/assets/geist-latin-wght-normal-BgDaEnEv.woff2 +0 -0
  35. package/dist/console-ui/assets/geist-vietnamese-wght-normal-6IgcOCM7.woff2 +0 -0
  36. package/dist/console-ui/assets/hermes-B8hNbJPm.png +0 -0
  37. package/dist/console-ui/assets/index-BxUf0Sye.js +96 -0
  38. package/dist/console-ui/assets/index-CmTiBR_w.css +2 -0
  39. package/dist/console-ui/assets/omnigent-Cxa4p2Mq.png +0 -0
  40. package/dist/console-ui/assets/openclaw-C5wL4ZVW.png +0 -0
  41. package/dist/console-ui/assets/opencode-D_wFATSC.png +0 -0
  42. package/dist/console-ui/assets/openhands-DnrlGgev.svg +9 -0
  43. package/dist/console-ui/assets/s-gw-64-ByMUGQ3K.png +0 -0
  44. package/dist/console-ui/assets/vscode-Bdtr9eyf.png +0 -0
  45. package/dist/console-ui/assets/zeptoclaw-DztQW8Sw.png +0 -0
  46. package/dist/console-ui/index.html +13 -0
  47. package/dist/crypto.d.ts +6 -0
  48. package/dist/crypto.js +53 -0
  49. package/dist/executor.d.ts +7 -0
  50. package/dist/executor.js +297 -0
  51. package/dist/gateway.d.ts +31 -0
  52. package/dist/gateway.js +114 -0
  53. package/dist/guard.d.ts +61 -0
  54. package/dist/guard.js +247 -0
  55. package/dist/install.d.ts +146 -0
  56. package/dist/install.js +629 -0
  57. package/dist/mcp-server.d.ts +2 -0
  58. package/dist/mcp-server.js +119 -0
  59. package/dist/native/s-gw-core +0 -0
  60. package/dist/native/s-gw-keychain-helper +0 -0
  61. package/dist/onepassword.d.ts +48 -0
  62. package/dist/onepassword.js +412 -0
  63. package/dist/paths.d.ts +4 -0
  64. package/dist/paths.js +22 -0
  65. package/dist/s-gw Menu Bar.app/Contents/Info.plist +28 -0
  66. package/dist/s-gw Menu Bar.app/Contents/MacOS/s-gw-menu-bar-helper +0 -0
  67. package/dist/s-gw Menu Bar.app/Contents/Resources/AppIcon.icns +0 -0
  68. package/dist/s-gw Menu Bar.app/Contents/Resources/AwsEc2.png +0 -0
  69. package/dist/s-gw Menu Bar.app/Contents/Resources/Lucide-bot.svg +8 -0
  70. package/dist/s-gw Menu Bar.app/Contents/Resources/Lucide-monitor.svg +5 -0
  71. package/dist/s-gw Menu Bar.app/Contents/Resources/Lucide-server.svg +6 -0
  72. package/dist/s-gw Menu Bar.app/Contents/Resources/Lucide-terminal.svg +4 -0
  73. package/dist/s-gw Menu Bar.app/Contents/Resources/MenuBarTemplate.png +0 -0
  74. package/dist/s-gw Menu Bar.app/Contents/_CodeSignature/CodeResources +194 -0
  75. package/dist/s-gw.app/Contents/Info.plist +28 -0
  76. package/dist/s-gw.app/Contents/MacOS/s-gw +0 -0
  77. package/dist/s-gw.app/Contents/Resources/AppIcon.icns +0 -0
  78. package/dist/s-gw.app/Contents/Resources/MenuBarTemplate.png +0 -0
  79. package/dist/s-gw.app/Contents/_CodeSignature/CodeResources +139 -0
  80. package/dist/scanner.d.ts +9 -0
  81. package/dist/scanner.js +437 -0
  82. package/dist/ssh.d.ts +31 -0
  83. package/dist/ssh.js +286 -0
  84. package/dist/store.d.ts +131 -0
  85. package/dist/store.js +1611 -0
  86. package/dist/types.d.ts +196 -0
  87. package/dist/types.js +2 -0
  88. package/dist/unlock.d.ts +29 -0
  89. package/dist/unlock.js +274 -0
  90. package/dist/windows/VERSION.txt +1 -0
  91. package/dist/windows/s-gw-client.cmd +4 -0
  92. package/dist/windows/s-gw-client.ps1 +106 -0
  93. package/dist/windows/s-gw-credential.cmd +4 -0
  94. package/dist/windows/s-gw-credential.ps1 +167 -0
  95. package/dist/windows/s-gw-helper.cmd +4 -0
  96. package/dist/windows/s-gw-helper.ps1 +180 -0
  97. package/docs/README.md +23 -0
  98. package/docs/agents.md +160 -0
  99. package/docs/architecture.md +72 -0
  100. package/docs/deployment.md +447 -0
  101. package/docs/detection.md +44 -0
  102. package/docs/images/s-gw-overview.png +0 -0
  103. package/docs/integrations.md +195 -0
  104. package/docs/keychain.md +39 -0
  105. package/docs/onepassword.md +84 -0
  106. package/docs/quickstart.md +104 -0
  107. package/docs/threat-model.md +100 -0
  108. package/docs/ui/THIRD_PARTY_NOTICES.md +111 -0
  109. package/docs/ui/apple-touch-icon.png +0 -0
  110. package/docs/ui/favicon-32.png +0 -0
  111. package/docs/ui/local-console.html +4477 -0
  112. package/docs/ui/vendor/d3-sankey/d3-array.LICENSE.txt +27 -0
  113. package/docs/ui/vendor/d3-sankey/d3-array.min.js +2 -0
  114. package/docs/ui/vendor/d3-sankey/d3-path.LICENSE.txt +27 -0
  115. package/docs/ui/vendor/d3-sankey/d3-path.min.js +2 -0
  116. package/docs/ui/vendor/d3-sankey/d3-sankey.LICENSE.txt +27 -0
  117. package/docs/ui/vendor/d3-sankey/d3-sankey.min.js +2 -0
  118. package/docs/ui/vendor/d3-sankey/d3-shape.LICENSE.txt +27 -0
  119. package/docs/ui/vendor/d3-sankey/d3-shape.min.js +2 -0
  120. package/docs/ui/vendor/sankeymatic/LICENSE.txt +17 -0
  121. package/docs/ui/vendor/sankeymatic/sankey.js +897 -0
  122. package/package.json +117 -0
  123. package/skills/s-gw/SKILL.md +19 -0
package/dist/ssh.js ADDED
@@ -0,0 +1,286 @@
1
+ import { spawn } from "node:child_process";
2
+ import { createHash } from "node:crypto";
3
+ import { constants } from "node:fs";
4
+ import { access, chmod, mkdir, mkdtemp, rm, writeFile } from "node:fs/promises";
5
+ import os from "node:os";
6
+ import path from "node:path";
7
+ import { getSgwHome } from "./paths.js";
8
+ import { sanitizeKnownSecrets } from "./scanner.js";
9
+ export const SGW_SSH_SESSION_COMMAND = "s-gw:ssh-session";
10
+ export function buildSshSessionAction(input) {
11
+ const target = normalizeSshTarget(input.target);
12
+ const port = normalizeSshPort(input.port);
13
+ return {
14
+ kind: "ssh_session",
15
+ command: SGW_SSH_SESSION_COMMAND,
16
+ args: input.args || [],
17
+ injectEnv: input.injectEnv || "SGW_SSH_CREDENTIAL",
18
+ workingDir: input.workingDir,
19
+ timeoutMs: input.timeoutMs ?? 30_000,
20
+ ssh: { target, port }
21
+ };
22
+ }
23
+ export function defaultSshInjectEnv(secret) {
24
+ if (secret.policy.injectEnv) {
25
+ return secret.policy.injectEnv;
26
+ }
27
+ if (secret.type === "ssh-key" || secret.type === "private-key") {
28
+ return "SGW_SSH_PRIVATE_KEY";
29
+ }
30
+ return "SGW_SSH_PASSWORD";
31
+ }
32
+ export function normalizeSshTarget(target) {
33
+ const trimmed = String(target || "").trim();
34
+ if (!trimmed || trimmed.includes("\0") || /[\r\n]/.test(trimmed)) {
35
+ throw new Error("SSH target is required and cannot contain control characters.");
36
+ }
37
+ if (trimmed.startsWith("-") || /\s/.test(trimmed)) {
38
+ throw new Error(`Invalid SSH target: ${trimmed}`);
39
+ }
40
+ return trimmed;
41
+ }
42
+ export function normalizeSshPort(port) {
43
+ const value = port ?? 22;
44
+ if (!Number.isInteger(value) || value < 1 || value > 65535) {
45
+ throw new Error("SSH port must be an integer from 1 to 65535.");
46
+ }
47
+ return value;
48
+ }
49
+ export function sshSessionIdentity(action) {
50
+ const target = action.ssh?.target ? normalizeSshTarget(action.ssh.target) : "";
51
+ const port = normalizeSshPort(action.ssh?.port);
52
+ return `${target}:${port}`;
53
+ }
54
+ export async function runOwnedSshSession(request, secretRecord, secretValue, home = getSgwHome()) {
55
+ if (request.action.kind !== "ssh_session") {
56
+ throw new Error("runOwnedSshSession requires an ssh_session action.");
57
+ }
58
+ const target = normalizeSshTarget(request.action.ssh?.target || "");
59
+ const port = normalizeSshPort(request.action.ssh?.port);
60
+ const sshPath = process.env.SGW_SSH_CLI || "ssh";
61
+ const maxOutput = secretRecord.policy.maxOutputBytes || 16_384;
62
+ const captureCap = maxOutput + Math.max(secretValue.length, 0);
63
+ const socketPath = await controlSocketPath(home, request.handle, target, port);
64
+ const auth = await prepareSshAuth(secretRecord, secretValue);
65
+ try {
66
+ if (!(await controlMasterIsActive(sshPath, socketPath, target, port, request.action.timeoutMs, captureCap))) {
67
+ await openControlMaster(sshPath, socketPath, target, port, request.action.timeoutMs, auth, captureCap);
68
+ }
69
+ const remoteArgs = request.action.args.length > 0 ? request.action.args : ["true"];
70
+ const result = await runProcess(sshPath, [
71
+ "-S", socketPath,
72
+ "-o", "ControlMaster=no",
73
+ "-o", "BatchMode=yes",
74
+ "-p", String(port),
75
+ target,
76
+ ...remoteArgs
77
+ ], { timeoutMs: request.action.timeoutMs, env: baseSshEnv(), maxOutputBytes: captureCap });
78
+ const cleanStdout = capBytes(sanitizeKnownSecrets(result.stdout, [{ handle: request.handle, value: secretValue }]), maxOutput);
79
+ const cleanStderr = capBytes(sanitizeKnownSecrets(result.stderr, [{ handle: request.handle, value: secretValue }]), maxOutput);
80
+ return {
81
+ exitCode: result.timedOut ? 124 : result.exitCode,
82
+ signal: result.signal,
83
+ stdout: cleanStdout,
84
+ stderr: cleanStderr,
85
+ proof: proofFor(request, cleanStdout, cleanStderr),
86
+ durationMs: result.durationMs,
87
+ timeoutMs: request.action.timeoutMs,
88
+ timedOut: result.timedOut,
89
+ sanitized: cleanStdout !== result.stdout || cleanStderr !== result.stderr
90
+ };
91
+ }
92
+ finally {
93
+ await auth.cleanup();
94
+ }
95
+ }
96
+ export async function closeOwnedSshSession(input) {
97
+ const target = normalizeSshTarget(input.target);
98
+ const port = normalizeSshPort(input.port);
99
+ const socketPath = await controlSocketPath(input.home || getSgwHome(), input.handle, target, port);
100
+ return runProcess(process.env.SGW_SSH_CLI || "ssh", ["-S", socketPath, "-O", "exit", "-p", String(port), target], {
101
+ timeoutMs: 10_000,
102
+ env: baseSshEnv(),
103
+ maxOutputBytes: 16_384,
104
+ rejectOnNonZero: false
105
+ });
106
+ }
107
+ async function controlMasterIsActive(sshPath, socketPath, target, port, timeoutMs, maxOutputBytes) {
108
+ const exists = await fileExists(socketPath);
109
+ if (!exists) {
110
+ return false;
111
+ }
112
+ const result = await runProcess(sshPath, ["-S", socketPath, "-O", "check", "-p", String(port), target], {
113
+ timeoutMs: timeoutMs > 0 ? Math.min(timeoutMs, 10_000) : 10_000,
114
+ env: baseSshEnv(),
115
+ maxOutputBytes,
116
+ rejectOnNonZero: false
117
+ });
118
+ return result.exitCode === 0;
119
+ }
120
+ async function openControlMaster(sshPath, socketPath, target, port, timeoutMs, auth, maxOutputBytes) {
121
+ const result = await runProcess(sshPath, [
122
+ "-M",
123
+ "-N",
124
+ "-f",
125
+ "-o", "ControlMaster=yes",
126
+ "-o", `ControlPath=${socketPath}`,
127
+ "-o", "ControlPersist=10m",
128
+ "-o", "ServerAliveInterval=30",
129
+ "-o", "ServerAliveCountMax=2",
130
+ "-o", "StrictHostKeyChecking=accept-new",
131
+ "-o", "BatchMode=no",
132
+ "-p", String(port),
133
+ ...auth.args,
134
+ target
135
+ ], { timeoutMs, env: auth.env, maxOutputBytes, rejectOnNonZero: false });
136
+ if (result.exitCode !== 0) {
137
+ const detail = result.stderr || result.stdout || `ssh exited ${result.exitCode}`;
138
+ throw new Error(`Could not open s-gw-owned SSH session to ${target}: ${detail.trim()}`);
139
+ }
140
+ }
141
+ async function prepareSshAuth(secret, value) {
142
+ const env = baseSshEnv();
143
+ const tmpDir = await mkdtemp(path.join(os.tmpdir(), "sgw-ssh-"));
144
+ let cleaned = false;
145
+ const cleanup = async () => {
146
+ if (cleaned) {
147
+ return;
148
+ }
149
+ cleaned = true;
150
+ await rm(tmpDir, { recursive: true, force: true });
151
+ };
152
+ if (secret.type === "ssh-key" || secret.type === "private-key" || looksLikePrivateKey(value)) {
153
+ const keyPath = path.join(tmpDir, "identity");
154
+ await writeFile(keyPath, value.endsWith("\n") ? value : `${value}\n`, { mode: 0o600 });
155
+ await chmod(keyPath, 0o600);
156
+ return {
157
+ args: ["-i", keyPath, "-o", "IdentitiesOnly=yes"],
158
+ env,
159
+ cleanup
160
+ };
161
+ }
162
+ const passPath = path.join(tmpDir, "password");
163
+ const askpassPath = path.join(tmpDir, "askpass.sh");
164
+ await writeFile(passPath, value, { mode: 0o600 });
165
+ await chmod(passPath, 0o600);
166
+ await writeFile(askpassPath, '#!/bin/sh\ncat "$SGW_ASKPASS_FILE"\n', { mode: 0o700 });
167
+ await chmod(askpassPath, 0o700);
168
+ return {
169
+ args: ["-o", "PreferredAuthentications=password,keyboard-interactive", "-o", "PubkeyAuthentication=no"],
170
+ env: {
171
+ ...env,
172
+ DISPLAY: env.DISPLAY || "sgw-local",
173
+ SSH_ASKPASS_REQUIRE: "force",
174
+ SSH_ASKPASS: askpassPath,
175
+ SGW_ASKPASS_FILE: passPath
176
+ },
177
+ cleanup
178
+ };
179
+ }
180
+ function looksLikePrivateKey(value) {
181
+ return /-----BEGIN [A-Z0-9 ]*PRIVATE KEY-----/.test(value);
182
+ }
183
+ async function controlSocketPath(home, handle, target, port) {
184
+ const dir = process.env.SGW_SSH_CONTROL_DIR || path.join(home, "ssh-sessions");
185
+ await mkdir(dir, { recursive: true, mode: 0o700 });
186
+ const digest = createHash("sha256")
187
+ .update(handle)
188
+ .update("\0")
189
+ .update(target)
190
+ .update("\0")
191
+ .update(String(port))
192
+ .digest("base64url")
193
+ .slice(0, 32);
194
+ return path.join(dir, `ctl-${digest}`);
195
+ }
196
+ function baseSshEnv() {
197
+ const env = {};
198
+ for (const key of ["HOME", "LANG", "LC_ALL", "LC_CTYPE", "LOGNAME", "PATH", "SHELL", "TERM", "TMPDIR", "USER"]) {
199
+ const value = process.env[key];
200
+ if (value) {
201
+ env[key] = value;
202
+ }
203
+ }
204
+ env.PATH ||= "/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin";
205
+ return env;
206
+ }
207
+ async function runProcess(command, args, options) {
208
+ const started = Date.now();
209
+ const child = spawn(command, args, {
210
+ env: options.env,
211
+ shell: false,
212
+ stdio: ["ignore", "pipe", "pipe"]
213
+ });
214
+ let stdout = "";
215
+ let stderr = "";
216
+ let timedOut = false;
217
+ let killTimer;
218
+ const timeout = options.timeoutMs > 0
219
+ ? setTimeout(() => {
220
+ timedOut = true;
221
+ child.kill("SIGTERM");
222
+ killTimer = setTimeout(() => child.kill("SIGKILL"), 1_500);
223
+ }, options.timeoutMs)
224
+ : undefined;
225
+ child.stdout.on("data", (chunk) => {
226
+ stdout = appendBounded(stdout, chunk.toString("utf8"), options.maxOutputBytes);
227
+ });
228
+ child.stderr.on("data", (chunk) => {
229
+ stderr = appendBounded(stderr, chunk.toString("utf8"), options.maxOutputBytes);
230
+ });
231
+ const status = await new Promise((resolve, reject) => {
232
+ child.on("error", reject);
233
+ child.on("close", (code, signal) => resolve({ code, signal }));
234
+ });
235
+ if (timeout) {
236
+ clearTimeout(timeout);
237
+ }
238
+ if (killTimer) {
239
+ clearTimeout(killTimer);
240
+ }
241
+ const result = {
242
+ exitCode: timedOut ? 124 : status.code,
243
+ signal: status.signal,
244
+ stdout,
245
+ stderr,
246
+ durationMs: Date.now() - started,
247
+ timedOut
248
+ };
249
+ if (options.rejectOnNonZero !== false && result.exitCode !== 0) {
250
+ throw new Error(stderr || stdout || `Command exited ${result.exitCode}`);
251
+ }
252
+ return result;
253
+ }
254
+ function appendBounded(current, extra, maxBytes) {
255
+ const combined = current + extra;
256
+ if (Buffer.byteLength(combined, "utf8") <= maxBytes) {
257
+ return combined;
258
+ }
259
+ return capBytes(combined, maxBytes);
260
+ }
261
+ function capBytes(text, maxBytes) {
262
+ if (Buffer.byteLength(text, "utf8") <= maxBytes) {
263
+ return text;
264
+ }
265
+ return text.slice(0, maxBytes) + "\n<<SGW_OUTPUT_TRUNCATED>>";
266
+ }
267
+ function proofFor(request, stdout, stderr) {
268
+ const digest = createHash("sha256")
269
+ .update(request.id)
270
+ .update(request.handle)
271
+ .update(stdout)
272
+ .update(stderr)
273
+ .digest("base64url")
274
+ .slice(0, 24);
275
+ return `s-gw-proof:${request.id}:${digest}`;
276
+ }
277
+ async function fileExists(filePath) {
278
+ try {
279
+ await access(filePath, constants.F_OK);
280
+ return true;
281
+ }
282
+ catch {
283
+ return false;
284
+ }
285
+ }
286
+ //# sourceMappingURL=ssh.js.map
@@ -0,0 +1,131 @@
1
+ import { type AgentIdentityContext } from "./agent-context.js";
2
+ import type { ApprovalGrant, ApprovalAgentScope, ApprovalMode, ApprovalPolicyConditions, ApprovalPolicyDecision, ApprovalPolicyRule, ApprovalSettings, AuditEvent, CommandAction, ExecutionSummary, HandleSummary, RequestRecord, RequestState, SecretPolicy, SecretRecord, SecretSeverity, SecretType } from "./types.js";
3
+ export interface AddSecretInput {
4
+ name: string;
5
+ type: SecretType;
6
+ provider?: string;
7
+ ruleId?: string;
8
+ severity?: SecretSeverity;
9
+ confidence?: number;
10
+ value: string;
11
+ source?: string;
12
+ policy?: Partial<SecretPolicy>;
13
+ }
14
+ export interface AddOnePasswordReferenceInput {
15
+ name: string;
16
+ type: SecretType;
17
+ reference: string;
18
+ source?: string;
19
+ policy?: Partial<SecretPolicy>;
20
+ }
21
+ export interface AddKeychainSecretInput extends AddSecretInput {
22
+ service?: string;
23
+ }
24
+ export interface SetApprovalSettingsInput {
25
+ mode: ApprovalMode;
26
+ durationMs?: number;
27
+ }
28
+ export interface AddApprovalPolicyRuleInput {
29
+ name?: string;
30
+ enabled?: boolean;
31
+ priority?: number;
32
+ decision: ApprovalPolicyDecision;
33
+ conditions?: Partial<ApprovalPolicyConditions>;
34
+ expiresAt?: string;
35
+ durationMs?: number;
36
+ }
37
+ export interface SetApprovalPolicyRuleEnabledResult {
38
+ id: string;
39
+ enabled: boolean;
40
+ }
41
+ export interface ApproveRequestOptions {
42
+ mode?: ApprovalMode;
43
+ durationMs?: number;
44
+ agentScope?: ApprovalAgentScope;
45
+ }
46
+ export interface DeleteSecretResult {
47
+ handle: string;
48
+ name: string;
49
+ revokedApprovalGrants: number;
50
+ revokedApprovalPolicies: number;
51
+ failedRequests: RequestRecord[];
52
+ }
53
+ export interface ClearApprovalGrantsResult {
54
+ revokedCount: number;
55
+ revoked: ApprovalGrant[];
56
+ }
57
+ export interface RequestListOptions {
58
+ state?: RequestState;
59
+ active?: boolean;
60
+ limit?: number;
61
+ }
62
+ export interface CleanupRequestsOptions {
63
+ pendingOlderThanMs?: number;
64
+ approvedOlderThanMs?: number;
65
+ duplicatePending?: boolean;
66
+ }
67
+ export interface CleanupRequestsResult {
68
+ cleanedCount: number;
69
+ requests: RequestRecord[];
70
+ }
71
+ export interface StoreBackupSummary {
72
+ path: string;
73
+ bytes: number;
74
+ modifiedAt: string;
75
+ }
76
+ export declare class SecretStore {
77
+ readonly home: string;
78
+ readonly storePath: string;
79
+ constructor(home?: string);
80
+ init(): Promise<void>;
81
+ addSecret(input: AddSecretInput): Promise<SecretRecord>;
82
+ addKeychainSecret(input: AddKeychainSecretInput): Promise<SecretRecord>;
83
+ addOnePasswordReference(input: AddOnePasswordReferenceInput): Promise<SecretRecord>;
84
+ listHandles(): Promise<HandleSummary[]>;
85
+ getHandle(handle: string): Promise<HandleSummary | undefined>;
86
+ allowCommand(handle: string, command: string): Promise<HandleSummary>;
87
+ getSecretRecord(handle: string): Promise<SecretRecord>;
88
+ revealSecretForLocalUse(handle: string, request?: RequestRecord): Promise<string>;
89
+ private storeOnePasswordCache;
90
+ deleteSecret(handle: string): Promise<DeleteSecretResult>;
91
+ getApprovalSettings(): Promise<ApprovalSettings>;
92
+ setApprovalSettings(input: SetApprovalSettingsInput): Promise<ApprovalSettings>;
93
+ listApprovalGrants(): Promise<ApprovalGrant[]>;
94
+ revokeApprovalGrant(id: string): Promise<ApprovalGrant>;
95
+ clearApprovalGrants(): Promise<ClearApprovalGrantsResult>;
96
+ listApprovalPolicyRules(): Promise<ApprovalPolicyRule[]>;
97
+ addApprovalPolicyRule(input: AddApprovalPolicyRuleInput): Promise<ApprovalPolicyRule>;
98
+ deleteApprovalPolicyRule(id: string): Promise<ApprovalPolicyRule>;
99
+ setApprovalPolicyRuleEnabled(id: string, enabled: boolean): Promise<SetApprovalPolicyRuleEnabledResult>;
100
+ createRequest(handle: string, action: CommandAction, reason: string, agentContext?: AgentIdentityContext): Promise<RequestRecord>;
101
+ listRequests(stateOrOptions?: RequestState | RequestListOptions): Promise<RequestRecord[]>;
102
+ cleanupRequests(options?: CleanupRequestsOptions): Promise<CleanupRequestsResult>;
103
+ listStoreBackups(): Promise<StoreBackupSummary[]>;
104
+ getRequest(id: string): Promise<RequestRecord>;
105
+ approveRequest(id: string, options?: ApproveRequestOptions): Promise<RequestRecord>;
106
+ denyRequest(id: string): Promise<RequestRecord>;
107
+ claimApprovedRequest(id: string): Promise<RequestRecord>;
108
+ /**
109
+ * Mark requests stranded in "executing" (runner crashed/killed before reporting back) as
110
+ * failed so the store self-heals. Returns the requests that were recovered.
111
+ */
112
+ recoverStaleExecutions(): Promise<RequestRecord[]>;
113
+ /**
114
+ * Explicit user-driven recovery for requests stuck in "executing". Unlike the time-gated
115
+ * automatic sweep, this fails them immediately — the operator has told us the runner is gone
116
+ * (laptop slept, command was Ctrl-C'd, etc.). Pass a request id to recover just that one;
117
+ * omit it to clear every stranded execution.
118
+ */
119
+ forceRecoverExecutions(requestId?: string): Promise<RequestRecord[]>;
120
+ markExecuted(id: string, summary: ExecutionSummary): Promise<RequestRecord>;
121
+ markFailed(id: string, errorMessage: string): Promise<RequestRecord>;
122
+ auditLog(): Promise<AuditEvent[]>;
123
+ private updateRequest;
124
+ private exists;
125
+ private read;
126
+ private readUnlocked;
127
+ private writeUnlocked;
128
+ private mutate;
129
+ private withStoreLock;
130
+ }
131
+ export declare function assertActionAllowed(secret: SecretRecord, action: CommandAction): void;