remote-access-mcp 3.1.2 → 4.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 (125) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/README.md +117 -2
  3. package/dist/cli/main.d.ts.map +1 -1
  4. package/dist/cli/main.js +5 -3
  5. package/dist/cli/main.js.map +1 -1
  6. package/dist/core/agent-contracts.d.ts +57 -0
  7. package/dist/core/agent-contracts.d.ts.map +1 -0
  8. package/dist/core/agent-contracts.js +35 -0
  9. package/dist/core/agent-contracts.js.map +1 -0
  10. package/dist/core/agent-profiles.d.ts +11 -0
  11. package/dist/core/agent-profiles.d.ts.map +1 -0
  12. package/dist/core/agent-profiles.js +12 -0
  13. package/dist/core/agent-profiles.js.map +1 -0
  14. package/dist/core/automation-engine.d.ts +53 -0
  15. package/dist/core/automation-engine.d.ts.map +1 -0
  16. package/dist/core/automation-engine.js +310 -0
  17. package/dist/core/automation-engine.js.map +1 -0
  18. package/dist/core/autonomy.d.ts +11 -0
  19. package/dist/core/autonomy.d.ts.map +1 -0
  20. package/dist/core/autonomy.js +30 -0
  21. package/dist/core/autonomy.js.map +1 -0
  22. package/dist/core/capability-router.d.ts +16 -0
  23. package/dist/core/capability-router.d.ts.map +1 -0
  24. package/dist/core/capability-router.js +83 -0
  25. package/dist/core/capability-router.js.map +1 -0
  26. package/dist/core/config.d.ts +1 -1
  27. package/dist/core/config.d.ts.map +1 -1
  28. package/dist/core/config.js +1 -1
  29. package/dist/core/config.js.map +1 -1
  30. package/dist/core/context-engine.d.ts +75 -0
  31. package/dist/core/context-engine.d.ts.map +1 -0
  32. package/dist/core/context-engine.js +330 -0
  33. package/dist/core/context-engine.js.map +1 -0
  34. package/dist/core/context.d.ts +5 -0
  35. package/dist/core/context.d.ts.map +1 -1
  36. package/dist/core/context.js.map +1 -1
  37. package/dist/core/policy.d.ts.map +1 -1
  38. package/dist/core/policy.js +15 -5
  39. package/dist/core/policy.js.map +1 -1
  40. package/dist/core/project-profiles.d.ts +17 -0
  41. package/dist/core/project-profiles.d.ts.map +1 -0
  42. package/dist/core/project-profiles.js +32 -0
  43. package/dist/core/project-profiles.js.map +1 -0
  44. package/dist/core/recovery-engine.d.ts +37 -0
  45. package/dist/core/recovery-engine.d.ts.map +1 -0
  46. package/dist/core/recovery-engine.js +99 -0
  47. package/dist/core/recovery-engine.js.map +1 -0
  48. package/dist/core/security-analysis.d.ts +19 -0
  49. package/dist/core/security-analysis.d.ts.map +1 -0
  50. package/dist/core/security-analysis.js +39 -0
  51. package/dist/core/security-analysis.js.map +1 -0
  52. package/dist/core/task-engine.d.ts +76 -0
  53. package/dist/core/task-engine.d.ts.map +1 -0
  54. package/dist/core/task-engine.js +319 -0
  55. package/dist/core/task-engine.js.map +1 -0
  56. package/dist/core/tunnel-providers.d.ts +12 -0
  57. package/dist/core/tunnel-providers.d.ts.map +1 -0
  58. package/dist/core/tunnel-providers.js +76 -0
  59. package/dist/core/tunnel-providers.js.map +1 -0
  60. package/dist/core/tunnel.d.ts +3 -0
  61. package/dist/core/tunnel.d.ts.map +1 -1
  62. package/dist/core/tunnel.js +9 -3
  63. package/dist/core/tunnel.js.map +1 -1
  64. package/dist/server/app.d.ts +2 -1
  65. package/dist/server/app.d.ts.map +1 -1
  66. package/dist/server/app.js +117 -5
  67. package/dist/server/app.js.map +1 -1
  68. package/dist/server/run.d.ts +2 -0
  69. package/dist/server/run.d.ts.map +1 -1
  70. package/dist/server/run.js +21 -3
  71. package/dist/server/run.js.map +1 -1
  72. package/dist/tools/agent.d.ts +4 -0
  73. package/dist/tools/agent.d.ts.map +1 -0
  74. package/dist/tools/agent.js +16 -0
  75. package/dist/tools/agent.js.map +1 -0
  76. package/dist/tools/automation.d.ts +4 -0
  77. package/dist/tools/automation.d.ts.map +1 -0
  78. package/dist/tools/automation.js +87 -0
  79. package/dist/tools/automation.js.map +1 -0
  80. package/dist/tools/autonomous.d.ts +4 -0
  81. package/dist/tools/autonomous.d.ts.map +1 -0
  82. package/dist/tools/autonomous.js +82 -0
  83. package/dist/tools/autonomous.js.map +1 -0
  84. package/dist/tools/browser.d.ts +4 -0
  85. package/dist/tools/browser.d.ts.map +1 -0
  86. package/dist/tools/browser.js +99 -0
  87. package/dist/tools/browser.js.map +1 -0
  88. package/dist/tools/context.d.ts +4 -0
  89. package/dist/tools/context.d.ts.map +1 -0
  90. package/dist/tools/context.js +53 -0
  91. package/dist/tools/context.js.map +1 -0
  92. package/dist/tools/index.d.ts +1 -1
  93. package/dist/tools/index.d.ts.map +1 -1
  94. package/dist/tools/index.js +20 -2
  95. package/dist/tools/index.js.map +1 -1
  96. package/dist/tools/infrastructure.d.ts +4 -0
  97. package/dist/tools/infrastructure.d.ts.map +1 -0
  98. package/dist/tools/infrastructure.js +124 -0
  99. package/dist/tools/infrastructure.js.map +1 -0
  100. package/dist/tools/intelligence.d.ts +9 -0
  101. package/dist/tools/intelligence.d.ts.map +1 -0
  102. package/dist/tools/intelligence.js +120 -0
  103. package/dist/tools/intelligence.js.map +1 -0
  104. package/dist/tools/planning.d.ts.map +1 -1
  105. package/dist/tools/planning.js +9 -0
  106. package/dist/tools/planning.js.map +1 -1
  107. package/dist/tools/plugin-host.d.ts +2 -0
  108. package/dist/tools/plugin-host.d.ts.map +1 -0
  109. package/dist/tools/plugin-host.js +54 -0
  110. package/dist/tools/plugin-host.js.map +1 -0
  111. package/dist/tools/plugin-network-blocker.cjs +39 -0
  112. package/dist/tools/plugins.d.ts.map +1 -1
  113. package/dist/tools/plugins.js +344 -30
  114. package/dist/tools/plugins.js.map +1 -1
  115. package/dist/tools/router.d.ts +4 -0
  116. package/dist/tools/router.d.ts.map +1 -0
  117. package/dist/tools/router.js +39 -0
  118. package/dist/tools/router.js.map +1 -0
  119. package/dist/tools/tasks.d.ts +4 -0
  120. package/dist/tools/tasks.d.ts.map +1 -0
  121. package/dist/tools/tasks.js +71 -0
  122. package/dist/tools/tasks.js.map +1 -0
  123. package/docs/ai/agent-architecture.md +145 -0
  124. package/docs/ai/decisions.md +119 -1
  125. package/package.json +2 -2
@@ -0,0 +1,37 @@
1
+ export interface RecoveryRule {
2
+ id: string;
3
+ tokenFingerprint: string;
4
+ name: string;
5
+ failureType: string;
6
+ risk: 'low' | 'medium' | 'high' | 'critical';
7
+ action: {
8
+ tool: string;
9
+ args: Record<string, unknown>;
10
+ };
11
+ enabled: boolean;
12
+ maxAttempts: number;
13
+ cooldownSeconds: number;
14
+ attempts: number;
15
+ lastAttempt?: string;
16
+ }
17
+ export interface RecoveryIncident {
18
+ id: string;
19
+ tokenFingerprint: string;
20
+ ruleId: string;
21
+ failureType: string;
22
+ status: 'open' | 'recovered' | 'failed';
23
+ created: string;
24
+ updated: string;
25
+ error?: string;
26
+ }
27
+ export declare function createRecoveryRule(rule: Omit<RecoveryRule, 'id' | 'attempts'>): RecoveryRule;
28
+ export declare function listRecoveryRules(token: string): RecoveryRule[];
29
+ export declare function deleteRecoveryRule(token: string, id: string): boolean;
30
+ export declare function listIncidents(token: string): RecoveryIncident[];
31
+ export declare function markIncident(token: string, rule: RecoveryRule, status: RecoveryIncident['status'], error?: string): void;
32
+ export declare function claimRecovery(token: string, id: string): RecoveryRule | undefined;
33
+ export declare function resetRecoveryAttempts(token: string, id: string): void;
34
+ export declare function recoveryCandidates(token: string, failureType: string): RecoveryRule[];
35
+ export declare function attemptRecoveryForFailure(token: string, failureType: string, invoke: (tool: string, args: Record<string, unknown>) => Promise<any>, authorize: (rule: RecoveryRule) => boolean): Promise<number>;
36
+ export declare function clearRecoveryForTests(): void;
37
+ //# sourceMappingURL=recovery-engine.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recovery-engine.d.ts","sourceRoot":"","sources":["../../src/core/recovery-engine.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,YAAY;IAAG,EAAE,EAAE,MAAM,CAAC;IAAC,gBAAgB,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,KAAK,GAAC,QAAQ,GAAC,MAAM,GAAC,UAAU,CAAC;IAAC,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,CAAC;IAAC,OAAO,EAAE,OAAO,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,eAAe,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAC;CAAE;AACnT,MAAM,WAAW,gBAAgB;IAAG,EAAE,EAAE,MAAM,CAAC;IAAC,gBAAgB,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,GAAC,WAAW,GAAC,QAAQ,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;CAAE;AAcvM,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,IAAI,CAAC,YAAY,EAAE,IAAI,GAAC,UAAU,CAAC,GAAG,YAAY,CAAsM;AACjS,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,YAAY,EAAE,CAAqE;AACrI,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAgL;AACtP,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,gBAAgB,EAAE,CAA2H;AAC3L,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,EAAE,gBAAgB,CAAC,QAAQ,CAAC,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAsb;AAC/iB,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS,CAA8Z;AAChf,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI,CAAwH;AAE9L,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,YAAY,EAAE,CAA8I;AAEpO,wBAAsB,yBAAyB,CAAC,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,GAAG,CAAC,EAAE,SAAS,EAAE,CAAC,IAAI,EAAE,YAAY,KAAK,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAiBtN;AAED,wBAAgB,qBAAqB,IAAI,IAAI,CAA2H"}
@@ -0,0 +1,99 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import crypto from 'node:crypto';
4
+ import { dataDir } from './platform.js';
5
+ const file = path.join(dataDir(), 'recovery.json');
6
+ const lock = `${file}.lock`;
7
+ const MAX_RULES = 200;
8
+ const MAX_INCIDENTS = 1000;
9
+ function fpRows() { try {
10
+ const x = JSON.parse(fs.readFileSync(file, 'utf8'));
11
+ return { rules: Array.isArray(x.rules) ? x.rules : [], incidents: Array.isArray(x.incidents) ? x.incidents : [] };
12
+ }
13
+ catch {
14
+ return { rules: [], incidents: [] };
15
+ } }
16
+ function persist(mut) {
17
+ fs.mkdirSync(dataDir(), { recursive: true, mode: 0o700 });
18
+ const start = Date.now();
19
+ while (true) {
20
+ try {
21
+ fs.mkdirSync(lock, { mode: 0o700 });
22
+ break;
23
+ }
24
+ catch (e) {
25
+ if (e?.code !== 'EEXIST')
26
+ throw e;
27
+ try {
28
+ if (Date.now() - fs.statSync(lock).mtimeMs > 30_000) {
29
+ fs.rmSync(lock, { recursive: true, force: true });
30
+ continue;
31
+ }
32
+ }
33
+ catch { }
34
+ if (Date.now() - start > 5000)
35
+ throw new Error('timed out waiting for recovery persistence lock');
36
+ const until = Date.now() + 10;
37
+ while (Date.now() < until) { }
38
+ }
39
+ }
40
+ try {
41
+ const x = fpRows();
42
+ mut(x);
43
+ const tmp = `${file}.${process.pid}.${crypto.randomUUID()}.tmp`;
44
+ fs.writeFileSync(tmp, JSON.stringify({ rules: x.rules.slice(-MAX_RULES), incidents: x.incidents.slice(-MAX_INCIDENTS) }, null, 2), { mode: 0o600 });
45
+ fs.renameSync(tmp, file);
46
+ }
47
+ finally {
48
+ fs.rmSync(lock, { recursive: true, force: true });
49
+ }
50
+ }
51
+ export function createRecoveryRule(rule) { const out = { ...rule, id: crypto.randomUUID(), attempts: 0 }; persist(x => { if (x.rules.length >= MAX_RULES)
52
+ throw new Error('recovery rule limit reached'); x.rules.push(out); }); return out; }
53
+ export function listRecoveryRules(token) { return fpRows().rules.filter(r => r.tokenFingerprint === token); }
54
+ export function deleteRecoveryRule(token, id) { let ok = false; persist(x => { const n = x.rules.filter(r => !(r.id === id && r.tokenFingerprint === token)); ok = n.length !== x.rules.length; x.rules = n; }); return ok; }
55
+ export function listIncidents(token) { return fpRows().incidents.filter(i => i.tokenFingerprint === token).sort((a, b) => b.updated.localeCompare(a.updated)); }
56
+ export function markIncident(token, rule, status, error) { persist(x => { const existing = x.incidents.find(i => i.ruleId === rule.id && i.tokenFingerprint === token && i.status === 'open'); const now = new Date().toISOString(); if (existing) {
57
+ existing.status = status;
58
+ existing.updated = now;
59
+ existing.error = error;
60
+ }
61
+ else
62
+ x.incidents.push({ id: crypto.randomUUID(), tokenFingerprint: token, ruleId: rule.id, failureType: rule.failureType, status, created: now, updated: now, error }); }); }
63
+ export function claimRecovery(token, id) { let claimed; persist(x => { const r = x.rules.find(v => v.id === id && v.tokenFingerprint === token && v.enabled); if (!r)
64
+ return; const now = Date.now(); if (r.attempts >= r.maxAttempts)
65
+ return; if (r.lastAttempt && now - Date.parse(r.lastAttempt) < r.cooldownSeconds * 1000)
66
+ return; r.attempts++; r.lastAttempt = new Date(now).toISOString(); claimed = { ...r }; }); return claimed; }
67
+ export function resetRecoveryAttempts(token, id) { persist(x => { const r = x.rules.find(v => v.id === id && v.tokenFingerprint === token); if (r)
68
+ r.attempts = 0; }); }
69
+ export function recoveryCandidates(token, failureType) { return fpRows().rules.filter(r => r.enabled && r.tokenFingerprint === token && (r.failureType === failureType || r.failureType === '*')); }
70
+ export async function attemptRecoveryForFailure(token, failureType, invoke, authorize) {
71
+ let recovered = 0;
72
+ for (const candidate of recoveryCandidates(token, failureType)) {
73
+ if (!authorize(candidate))
74
+ continue;
75
+ const claimed = claimRecovery(token, candidate.id);
76
+ if (!claimed)
77
+ continue;
78
+ markIncident(token, claimed, 'open');
79
+ try {
80
+ const result = await invoke(claimed.action.tool, claimed.action.args);
81
+ if (result?.isError)
82
+ throw new Error('recovery action returned an error');
83
+ markIncident(token, claimed, 'recovered');
84
+ recovered++;
85
+ }
86
+ catch (e) {
87
+ markIncident(token, claimed, 'failed', e?.message || String(e));
88
+ }
89
+ }
90
+ return recovered;
91
+ }
92
+ export function clearRecoveryForTests() { try {
93
+ fs.rmSync(file, { force: true });
94
+ }
95
+ catch { } try {
96
+ fs.rmSync(lock, { recursive: true, force: true });
97
+ }
98
+ catch { } }
99
+ //# sourceMappingURL=recovery-engine.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recovery-engine.js","sourceRoot":"","sources":["../../src/core/recovery-engine.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ export interface SecurityFinding {
2
+ id: string;
3
+ severity: 'info' | 'low' | 'medium' | 'high' | 'critical';
4
+ message: string;
5
+ }
6
+ export interface SecurityReport {
7
+ score: number;
8
+ findings: SecurityFinding[];
9
+ checkedAt: string;
10
+ }
11
+ export declare function analyzeSecurity(input: {
12
+ scopes: string[];
13
+ readOnly: boolean;
14
+ shellEnabled: boolean;
15
+ allowedPaths: string[];
16
+ deniedPaths: string[];
17
+ configDir?: string;
18
+ }): SecurityReport;
19
+ //# sourceMappingURL=security-analysis.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"security-analysis.d.ts","sourceRoot":"","sources":["../../src/core/security-analysis.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,eAAe;IAAG,EAAE,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,GAAC,KAAK,GAAC,QAAQ,GAAC,MAAM,GAAC,UAAU,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;CAAE;AACpH,MAAM,WAAW,cAAc;IAAG,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,eAAe,EAAE,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;CAAE;AAIlG,wBAAgB,eAAe,CAAC,KAAK,EAAE;IAAE,MAAM,EAAE,MAAM,EAAE,CAAC;IAAC,QAAQ,EAAE,OAAO,CAAC;IAAC,YAAY,EAAE,OAAO,CAAC;IAAC,YAAY,EAAE,MAAM,EAAE,CAAC;IAAC,WAAW,EAAE,MAAM,EAAE,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,cAAc,CAkBxL"}
@@ -0,0 +1,39 @@
1
+ import fs from 'node:fs';
2
+ import os from 'node:os';
3
+ import { dataDir } from './platform.js';
4
+ import { TOOL_SCOPES, MUTATING_TOOLS } from './policy.js';
5
+ function clamp(n) { return Math.max(0, Math.min(100, n)); }
6
+ export function analyzeSecurity(input) {
7
+ const findings = [];
8
+ const scopes = input.scopes;
9
+ const mutating = Object.entries(TOOL_SCOPES).filter(([group, tools]) => (scopes.length === 0 || scopes.includes(group)) && tools.some(t => MUTATING_TOOLS.has(t))).map(([g]) => g);
10
+ if (scopes.length === 0)
11
+ findings.push({ id: 'broad-scope', severity: 'high', message: 'Token has unrestricted tool scopes.' });
12
+ if (mutating.length && !input.readOnly)
13
+ findings.push({ id: 'mutation-enabled', severity: mutating.includes('shell') ? 'high' : 'medium', message: `Mutating capability groups enabled: ${mutating.join(', ')}.` });
14
+ if (input.shellEnabled && !input.readOnly && !input.allowedPaths.length)
15
+ findings.push({ id: 'shell-without-paths', severity: 'medium', message: 'Shell is enabled while the filesystem allowlist is empty.' });
16
+ if (!input.deniedPaths.length && input.allowedPaths.length)
17
+ findings.push({ id: 'no-deny-paths', severity: 'low', message: 'No explicit denied paths are configured.' });
18
+ const config = input.configDir || dataDir();
19
+ try {
20
+ const st = fs.statSync(config);
21
+ if ((st.mode & 0o077) !== 0)
22
+ findings.push({ id: 'data-dir-permissions', severity: 'high', message: `RAMCP data directory permissions are broader than 0700: ${((st.mode & 0o777).toString(8))}.` });
23
+ }
24
+ catch {
25
+ findings.push({ id: 'data-dir-missing', severity: 'low', message: 'RAMCP data directory does not exist yet.' });
26
+ }
27
+ const listeners = (() => { try {
28
+ return os.networkInterfaces();
29
+ }
30
+ catch {
31
+ return {};
32
+ } })();
33
+ const external = Object.values(listeners).flatMap(x => x || []).some(i => !i.internal);
34
+ if (external)
35
+ findings.push({ id: 'external-interface', severity: 'info', message: 'Host has non-loopback network interfaces; gateway binding should remain loopback.' });
36
+ const penalty = findings.reduce((n, f) => n + { info: 0, low: 3, medium: 10, high: 25, critical: 50 }[f.severity], 0);
37
+ return { score: clamp(100 - penalty), findings, checkedAt: new Date().toISOString() };
38
+ }
39
+ //# sourceMappingURL=security-analysis.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"security-analysis.js","sourceRoot":"","sources":["../../src/core/security-analysis.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AAEzB,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACxC,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAK1D,SAAS,KAAK,CAAC,CAAS,IAAY,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAE3E,MAAM,UAAU,eAAe,CAAC,KAAwI;IACtK,MAAM,QAAQ,GAAsB,EAAE,CAAC;IACvC,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC;IAC5B,MAAM,QAAQ,GAAG,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC,IAAI,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC;IACnL,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,qCAAqC,EAAE,CAAC,CAAC;IAChI,IAAI,QAAQ,CAAC,MAAM,IAAI,CAAC,KAAK,CAAC,QAAQ;QAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,kBAAkB,EAAE,QAAQ,EAAE,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,EAAE,OAAO,EAAE,uCAAuC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;IACpN,IAAI,KAAK,CAAC,YAAY,IAAI,CAAC,KAAK,CAAC,QAAQ,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,MAAM;QAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,qBAAqB,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,2DAA2D,EAAE,CAAC,CAAC;IAChN,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,MAAM,IAAI,KAAK,CAAC,YAAY,CAAC,MAAM;QAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,eAAe,EAAE,QAAQ,EAAE,KAAK,EAAE,OAAO,EAAE,0CAA0C,EAAE,CAAC,CAAC;IACzK,MAAM,MAAM,GAAG,KAAK,CAAC,SAAS,IAAI,OAAO,EAAE,CAAC;IAC5C,IAAI,CAAC;QACH,MAAM,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;QAC/B,IAAI,CAAC,EAAE,CAAC,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC;YAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,sBAAsB,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,2DAA2D,CAAC,CAAC,EAAE,CAAC,IAAI,GAAG,KAAK,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;IACvM,CAAC;IAAC,MAAM,CAAC;QAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,kBAAkB,EAAE,QAAQ,EAAE,KAAK,EAAE,OAAO,EAAE,0CAA0C,EAAE,CAAC,CAAC;IAAC,CAAC;IAC5H,MAAM,SAAS,GAAG,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC;QAAC,OAAO,EAAE,CAAC,iBAAiB,EAAE,CAAC;IAAC,CAAC;IAAC,MAAM,CAAC;QAAC,OAAO,EAAE,CAAC;IAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAC5F,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;IACvF,IAAI,QAAQ;QAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,oBAAoB,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,mFAAmF,EAAE,CAAC,CAAC;IAC1K,MAAM,OAAO,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAI,EAAE,IAAI,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAY,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC;IACjI,OAAO,EAAE,KAAK,EAAE,KAAK,CAAC,GAAG,GAAG,OAAO,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,CAAC;AACxF,CAAC"}
@@ -0,0 +1,76 @@
1
+ import { type AgentProfileId } from './agent-profiles.js';
2
+ import type { AgentResult, AutonomyLevel, TaskContext, TaskState } from './agent-contracts.js';
3
+ export interface TaskAction {
4
+ id: string;
5
+ agent?: AgentProfileId;
6
+ tool: string;
7
+ arguments?: Record<string, unknown>;
8
+ dependsOn?: string[];
9
+ condition?: 'always' | 'on_success' | 'on_failure';
10
+ timeoutMs?: number;
11
+ retries?: number;
12
+ rollback?: {
13
+ tool: string;
14
+ arguments?: Record<string, unknown>;
15
+ };
16
+ verify?: {
17
+ tool: string;
18
+ arguments?: Record<string, unknown>;
19
+ };
20
+ }
21
+ export interface TaskDefinition {
22
+ goal: string;
23
+ actions: TaskAction[];
24
+ autonomy: AutonomyLevel;
25
+ dryRun?: boolean;
26
+ }
27
+ export interface TaskActionRecord extends TaskAction {
28
+ status: 'pending' | 'running' | 'succeeded' | 'failed' | 'skipped' | 'rolled_back';
29
+ attempts: number;
30
+ startedAt?: string;
31
+ finishedAt?: string;
32
+ result?: unknown;
33
+ error?: string;
34
+ }
35
+ export interface TaskRecord {
36
+ id: string;
37
+ tokenId: string;
38
+ goal: string;
39
+ autonomy: AutonomyLevel;
40
+ state: TaskState;
41
+ dryRun: boolean;
42
+ createdAt: string;
43
+ updatedAt: string;
44
+ actions: TaskActionRecord[];
45
+ error?: string;
46
+ approvalId?: string;
47
+ context: TaskContext;
48
+ }
49
+ type Invoke = (name: string, args: Record<string, unknown>) => Promise<any>;
50
+ export declare class TaskEngine {
51
+ private readonly token;
52
+ private readonly invoke;
53
+ private readonly dir;
54
+ constructor(token: string, invoke: Invoke, options?: {
55
+ dataDirectory?: string;
56
+ });
57
+ create(def: TaskDefinition): TaskRecord;
58
+ get(id: string): TaskRecord | undefined;
59
+ list(limit?: number): TaskRecord[];
60
+ private save;
61
+ approve(id: string): Promise<TaskRecord>;
62
+ reject(id: string): TaskRecord;
63
+ resume(id: string): Promise<TaskRecord>;
64
+ private require;
65
+ run(id: string): Promise<TaskRecord>;
66
+ private execute;
67
+ private executeAction;
68
+ private rollback;
69
+ }
70
+ export declare function taskSummary(row: TaskRecord): AgentResult<{
71
+ id: string;
72
+ state: TaskState;
73
+ actions: TaskActionRecord[];
74
+ }>;
75
+ export {};
76
+ //# sourceMappingURL=task-engine.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"task-engine.d.ts","sourceRoot":"","sources":["../../src/core/task-engine.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,319 @@
1
+ import crypto from 'node:crypto';
2
+ import fs from 'node:fs';
3
+ import path from 'node:path';
4
+ import { dataDir } from './platform.js';
5
+ import { AuditLog } from './audit.js';
6
+ import { getAgentProfile } from './agent-profiles.js';
7
+ import { scopeOf } from './policy.js';
8
+ const MAX_TASKS = 500;
9
+ const MAX_ACTIONS = 64;
10
+ function storePath(dir) { return path.join(dir, 'tasks.json'); }
11
+ function lockPath(dir) { return path.join(dir, 'tasks.lock'); }
12
+ function load(dir) {
13
+ try {
14
+ const value = JSON.parse(fs.readFileSync(storePath(dir), 'utf8'));
15
+ return Array.isArray(value) ? value : [];
16
+ }
17
+ catch {
18
+ return [];
19
+ }
20
+ }
21
+ function save(rows, dir = dataDir()) {
22
+ fs.mkdirSync(dir, { recursive: true, mode: 0o700 });
23
+ const store = storePath(dir);
24
+ const lock = lockPath(dir);
25
+ const start = Date.now();
26
+ while (true) {
27
+ try {
28
+ fs.mkdirSync(lock, { mode: 0o700 });
29
+ try {
30
+ const current = new Map(load(dir).map(t => [t.id, t]));
31
+ for (const row of rows)
32
+ current.set(row.id, row);
33
+ const retained = [...current.values()].sort((a, b) => a.createdAt.localeCompare(b.createdAt)).slice(-MAX_TASKS);
34
+ const tmp = `${store}.${process.pid}-${crypto.randomUUID()}.tmp`;
35
+ fs.writeFileSync(tmp, JSON.stringify(retained, null, 2), { mode: 0o600 });
36
+ fs.renameSync(tmp, store);
37
+ }
38
+ finally {
39
+ fs.rmSync(lock, { recursive: true, force: true });
40
+ }
41
+ return;
42
+ }
43
+ catch (e) {
44
+ if (e?.code !== 'EEXIST')
45
+ throw e;
46
+ try {
47
+ if (Date.now() - fs.statSync(lock).mtimeMs > 30_000)
48
+ fs.rmSync(lock, { recursive: true, force: true });
49
+ }
50
+ catch { }
51
+ if (Date.now() - start > 10_000)
52
+ throw new Error('timed out waiting for task persistence lock');
53
+ const until = Date.now() + 10;
54
+ while (Date.now() < until) { }
55
+ }
56
+ }
57
+ }
58
+ function clone(v) { return v === undefined ? v : JSON.parse(JSON.stringify(v)); }
59
+ function now() { return new Date().toISOString(); }
60
+ function tokenId(token) { return AuditLog.fingerprint(token); }
61
+ function validate(def) {
62
+ if (!def.goal.trim())
63
+ throw new Error('task goal must not be empty');
64
+ if (!Array.isArray(def.actions) || def.actions.length < 1 || def.actions.length > MAX_ACTIONS)
65
+ throw new Error(`task actions must contain 1-${MAX_ACTIONS} actions`);
66
+ const ids = new Set();
67
+ for (const a of def.actions) {
68
+ if (!a.id || !/^[A-Za-z0-9_-]{1,64}$/.test(a.id))
69
+ throw new Error(`invalid action id: ${a.id}`);
70
+ if (ids.has(a.id))
71
+ throw new Error(`duplicate action id: ${a.id}`);
72
+ ids.add(a.id);
73
+ if (!a.tool || a.tool === 'task' || a.tool === 'task_approve')
74
+ throw new Error(`invalid task action tool: ${a.tool}`);
75
+ if (a.agent) {
76
+ const profile = getAgentProfile(a.agent);
77
+ if (!profile)
78
+ throw new Error(`unknown agent profile: ${a.agent}`);
79
+ const scope = scopeOf(a.tool);
80
+ if (scope && !profile.allowedScopes.includes(scope))
81
+ throw new Error(`agent ${a.agent} is not permitted to use ${a.tool}`);
82
+ if (autonomyRank(def.autonomy) > autonomyRank(profile.defaultAutonomy))
83
+ throw new Error(`agent ${a.agent} cannot run at ${def.autonomy} autonomy`);
84
+ }
85
+ if (a.retries !== undefined && (!Number.isInteger(a.retries) || a.retries < 0 || a.retries > 5))
86
+ throw new Error(`invalid retries for ${a.id}`);
87
+ if (a.timeoutMs !== undefined && (!Number.isInteger(a.timeoutMs) || a.timeoutMs < 100 || a.timeoutMs > 600_000))
88
+ throw new Error(`invalid timeout for ${a.id}`);
89
+ for (const dep of a.dependsOn || [])
90
+ if (!ids.has(dep) && !def.actions.some(x => x.id === dep))
91
+ throw new Error(`unknown dependency ${dep} for ${a.id}`);
92
+ }
93
+ const graph = new Map(def.actions.map(a => [a.id, a.dependsOn || []]));
94
+ const visiting = new Set();
95
+ const visited = new Set();
96
+ const visit = (id) => {
97
+ if (visiting.has(id))
98
+ throw new Error('task dependency graph contains a cycle');
99
+ if (visited.has(id))
100
+ return;
101
+ visiting.add(id);
102
+ for (const dep of graph.get(id) || [])
103
+ visit(dep);
104
+ visiting.delete(id);
105
+ visited.add(id);
106
+ };
107
+ for (const a of def.actions)
108
+ visit(a.id);
109
+ }
110
+ function autonomyRank(value) { return { readonly: 0, safe: 1, supervised: 2, autonomous: 3 }[value]; }
111
+ function isMutationLike(tool) {
112
+ return new Set(['write_file', 'edit_file', 'delete_path', 'run_command', 'kill_process', 'git', 'sqlite_query', 'allow_path', 'deny_path', 'package_install', 'package_remove', 'service_action', 'schedule_command', 'cancel_scheduled_task', 'workspace_snapshot', 'rollback_changes', 'run_background', 'job_cancel', 'run_parallel', 'upload_file', 'change_set_begin', 'change_set_add', 'change_set_commit', 'change_set_rollback', 'health_watch', 'health_stop', 'plugin_install', 'plugin_remove', 'context_snapshot', 'context_clear', 'approval_decide', 'task_approve']).has(tool);
113
+ }
114
+ export class TaskEngine {
115
+ token;
116
+ invoke;
117
+ dir;
118
+ constructor(token, invoke, options = {}) {
119
+ this.token = token;
120
+ this.invoke = invoke;
121
+ this.dir = options.dataDirectory || dataDir();
122
+ }
123
+ create(def) {
124
+ validate(def);
125
+ const id = crypto.randomUUID();
126
+ const created = now();
127
+ const actions = def.actions.map(a => ({ ...clone(a), status: 'pending', attempts: 0 }));
128
+ const context = {
129
+ taskId: id, goal: def.goal, autonomy: def.autonomy,
130
+ budget: { total: 32_000, history: 4_000, tools: 12_000, memory: 8_000, reserved: 8_000 },
131
+ facts: [], decisions: [], constraints: [], completedActions: [],
132
+ };
133
+ const row = { id, tokenId: tokenId(this.token), goal: def.goal, autonomy: def.autonomy, state: def.dryRun ? 'completed' : 'queued', dryRun: Boolean(def.dryRun), createdAt: created, updatedAt: created, actions, context };
134
+ if (def.dryRun)
135
+ row.context.decisions.push('dry-run: no action executed');
136
+ this.save(row);
137
+ return clone(row);
138
+ }
139
+ get(id) {
140
+ const row = load(this.dir).find(t => t.id === id && t.tokenId === tokenId(this.token));
141
+ return row ? clone(row) : undefined;
142
+ }
143
+ list(limit = 20) { return load(this.dir).filter(t => t.tokenId === tokenId(this.token)).sort((a, b) => b.createdAt.localeCompare(a.createdAt)).slice(0, Math.min(100, Math.max(1, limit))).map(clone); }
144
+ save(row) { save([row], this.dir); }
145
+ async approve(id) {
146
+ const row = this.require(id);
147
+ if (row.state !== 'awaiting_approval')
148
+ throw new Error(`task ${id} is not awaiting approval`);
149
+ row.state = 'executing';
150
+ row.updatedAt = now();
151
+ row.approvalId = undefined;
152
+ this.save(row);
153
+ return this.execute(row);
154
+ }
155
+ reject(id) {
156
+ const row = this.require(id);
157
+ if (row.state !== 'awaiting_approval')
158
+ throw new Error(`task ${id} is not awaiting approval`);
159
+ row.state = 'cancelled';
160
+ row.error = 'task rejected during approval';
161
+ row.approvalId = undefined;
162
+ row.updatedAt = now();
163
+ this.save(row);
164
+ return clone(row);
165
+ }
166
+ async resume(id) {
167
+ const row = this.require(id);
168
+ if (!['queued', 'executing', 'verifying', 'failed'].includes(row.state))
169
+ throw new Error(`task ${id} cannot be resumed from ${row.state}`);
170
+ row.state = row.state === 'failed' ? 'planning' : row.state;
171
+ row.updatedAt = now();
172
+ this.save(row);
173
+ return this.execute(row);
174
+ }
175
+ require(id) { const row = this.get(id); if (!row)
176
+ throw new Error(`Task ${id} not found`); return row; }
177
+ async run(id) {
178
+ const row = this.require(id);
179
+ if (row.dryRun)
180
+ return row;
181
+ if (row.state !== 'queued' && row.state !== 'planning')
182
+ throw new Error(`task ${id} cannot run from ${row.state}`);
183
+ const hasMutation = row.actions.some(a => isMutationLike(a.tool));
184
+ if (row.autonomy === 'readonly' && hasMutation) {
185
+ row.state = 'failed';
186
+ row.error = 'readonly autonomy cannot execute mutating actions';
187
+ row.updatedAt = now();
188
+ this.save(row);
189
+ return clone(row);
190
+ }
191
+ if (row.autonomy === 'supervised' && hasMutation) {
192
+ row.state = 'awaiting_approval';
193
+ row.approvalId = `task-${crypto.randomUUID().slice(0, 12)}`;
194
+ row.updatedAt = now();
195
+ row.context.decisions.push(`approval required: ${row.approvalId}`);
196
+ this.save(row);
197
+ return clone(row);
198
+ }
199
+ row.state = 'executing';
200
+ row.updatedAt = now();
201
+ this.save(row);
202
+ return this.execute(row);
203
+ }
204
+ async execute(row) {
205
+ try {
206
+ while (row.actions.some(a => a.status === 'pending' || a.status === 'running')) {
207
+ const ready = row.actions.filter(a => a.status === 'pending' && (a.dependsOn || []).every(dep => {
208
+ const status = row.actions.find(x => x.id === dep)?.status;
209
+ if (a.condition === 'on_failure')
210
+ return status === 'failed';
211
+ if (a.condition === 'always')
212
+ return ['succeeded', 'failed', 'skipped', 'rolled_back'].includes(status || '');
213
+ return status === 'succeeded' || status === 'skipped';
214
+ }));
215
+ const blocked = row.actions.filter(a => a.status === 'pending' && (a.dependsOn || []).some(dep => {
216
+ const status = row.actions.find(x => x.id === dep)?.status;
217
+ return ['failed', 'rolled_back'].includes(status || '') && a.condition !== 'on_failure';
218
+ }));
219
+ for (const a of blocked) {
220
+ a.status = 'skipped';
221
+ a.finishedAt = now();
222
+ }
223
+ if (!ready.length) {
224
+ if (row.actions.some(a => a.status === 'running')) {
225
+ await new Promise(r => setTimeout(r, 10));
226
+ continue;
227
+ }
228
+ if (row.actions.some(a => a.status === 'pending'))
229
+ throw new Error('task graph is blocked by unresolved dependencies');
230
+ break;
231
+ }
232
+ row.state = 'executing';
233
+ row.updatedAt = now();
234
+ this.save(row);
235
+ await Promise.all(ready.map(a => this.executeAction(row, a)));
236
+ row.context.completedActions = row.actions.filter(a => a.status === 'succeeded').map(a => a.id);
237
+ this.save(row);
238
+ }
239
+ row.state = 'verifying';
240
+ row.updatedAt = now();
241
+ this.save(row);
242
+ const failed = row.actions.some(a => a.status === 'failed');
243
+ if (failed)
244
+ throw new Error('task verification failed');
245
+ row.state = 'completed';
246
+ row.updatedAt = now();
247
+ this.save(row);
248
+ return clone(row);
249
+ }
250
+ catch (e) {
251
+ row.error = e?.message || String(e);
252
+ row.state = 'failed';
253
+ row.updatedAt = now();
254
+ this.save(row);
255
+ await this.rollback(row, row.actions.filter(a => a.status === 'succeeded'));
256
+ return clone(row);
257
+ }
258
+ }
259
+ async executeAction(row, action) {
260
+ action.status = 'running';
261
+ action.startedAt = now();
262
+ action.attempts += 1;
263
+ this.save(row);
264
+ const max = 1 + (action.retries || 0);
265
+ while (action.attempts <= max) {
266
+ try {
267
+ const result = await withTimeout(this.invoke(action.tool, action.arguments || {}), action.timeoutMs || 600_000);
268
+ if (result?.isError)
269
+ throw new Error(extractText(result) || `tool ${action.tool} returned an error`);
270
+ if (action.verify) {
271
+ const verification = await withTimeout(this.invoke(action.verify.tool, action.verify.arguments || {}), action.timeoutMs || 600_000);
272
+ if (verification?.isError)
273
+ throw new Error(extractText(verification) || `verification failed for ${action.id}`);
274
+ row.context.decisions.push(`verified: ${action.id} via ${action.verify.tool}`);
275
+ }
276
+ action.status = 'succeeded';
277
+ action.result = result;
278
+ action.finishedAt = now();
279
+ this.save(row);
280
+ return;
281
+ }
282
+ catch (e) {
283
+ action.error = e?.message || String(e);
284
+ if (action.attempts >= max) {
285
+ action.status = 'failed';
286
+ action.finishedAt = now();
287
+ this.save(row);
288
+ return;
289
+ }
290
+ action.attempts += 1;
291
+ this.save(row);
292
+ }
293
+ }
294
+ }
295
+ async rollback(row, succeeded) {
296
+ row.context.decisions.push('rollback started after task failure');
297
+ for (const action of [...succeeded].reverse()) {
298
+ if (!action.rollback)
299
+ continue;
300
+ try {
301
+ await withTimeout(this.invoke(action.rollback.tool, action.rollback.arguments || {}), action.timeoutMs || 600_000);
302
+ action.status = 'rolled_back';
303
+ }
304
+ catch (e) {
305
+ row.context.decisions.push(`rollback failed for ${action.id}: ${e?.message || e}`);
306
+ }
307
+ }
308
+ row.updatedAt = now();
309
+ this.save(row);
310
+ }
311
+ }
312
+ export function taskSummary(row) {
313
+ return { ok: row.state === 'completed', summary: `Task ${row.id} is ${row.state}`, data: { id: row.id, state: row.state, actions: clone(row.actions) }, warnings: row.state === 'failed' ? [row.error || 'task failed'] : [], errors: row.state === 'failed' ? [row.error || 'task failed'] : [], nextActions: row.state === 'awaiting_approval' ? ['approve the task'] : row.state === 'failed' ? ['resume the task or inspect the failed action'] : [] };
314
+ }
315
+ function extractText(result) { return Array.isArray(result?.content) ? result.content.filter((x) => x?.type === 'text').map((x) => x.text).join('\n').slice(0, 2000) : ''; }
316
+ function withTimeout(promise, ms) {
317
+ return new Promise((resolve, reject) => { const timer = setTimeout(() => reject(new Error(`action timed out after ${ms}ms`)), ms); promise.then(v => { clearTimeout(timer); resolve(v); }, e => { clearTimeout(timer); reject(e); }); });
318
+ }
319
+ //# sourceMappingURL=task-engine.js.map