@iaforged/context-code 1.2.9 → 1.2.12

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 (172) hide show
  1. package/README.md +119 -119
  2. package/context-bootstrap.js +28 -26
  3. package/dist/src/QueryEngine.js +394 -327
  4. package/dist/src/bridge/bridgeUI.js +1 -1
  5. package/dist/src/buddy/prompt.js +4 -4
  6. package/dist/src/cli/handlers/auth.js +126 -9
  7. package/dist/src/cli/print.js +35 -1
  8. package/dist/src/commands/agent/agent.js +28 -2
  9. package/dist/src/commands/agent/agentStore.js +8 -1
  10. package/dist/src/commands/agent/index.js +1 -1
  11. package/dist/src/commands/bridge-kick.js +9 -9
  12. package/dist/src/commands/commit.js +34 -34
  13. package/dist/src/commands/init-verifiers.js +3 -3
  14. package/dist/src/commands/init.js +88 -88
  15. package/dist/src/commands/insights.js +787 -787
  16. package/dist/src/commands/install.js +19 -19
  17. package/dist/src/commands/login/login.js +21 -12
  18. package/dist/src/commands/logout/logout.js +9 -0
  19. package/dist/src/commands/model/model.js +9 -4
  20. package/dist/src/commands/orchestrate/SwarmUI.js +50 -0
  21. package/dist/src/commands/orchestrate/index.js +2 -2
  22. package/dist/src/commands/orchestrate/orchestrate.js +708 -12
  23. package/dist/src/commands/pr_comments/index.js +33 -33
  24. package/dist/src/commands/profile/index.js +1 -1
  25. package/dist/src/commands/profile/profile.js +52 -3
  26. package/dist/src/commands/provider/index.js +1 -1
  27. package/dist/src/commands/provider/provider.js +117 -45
  28. package/dist/src/commands/resumen/index.js +9 -0
  29. package/dist/src/commands/resumen/resumen.js +29 -0
  30. package/dist/src/commands/security-review.js +190 -190
  31. package/dist/src/commands/swarm-auto/index.js +9 -0
  32. package/dist/src/commands/swarm-auto/swarmAuto.js +111 -0
  33. package/dist/src/commands/swarm-init/index.js +9 -0
  34. package/dist/src/commands/swarm-init/swarmInit.js +72 -0
  35. package/dist/src/commands/team/team.js +39 -6
  36. package/dist/src/commands.js +14 -0
  37. package/dist/src/components/LogoV2/CondensedLogo.js +2 -2
  38. package/dist/src/components/PromptInput/PromptInputQueuedCommands.js +3 -3
  39. package/dist/src/components/agents/agentFileUtils.js +6 -6
  40. package/dist/src/components/permissions/hooks.js +5 -5
  41. package/dist/src/constants/outputStyles.js +83 -83
  42. package/dist/src/core/agents/blueprints.js +58 -0
  43. package/dist/src/core/agents/cliAdapter.js +61 -0
  44. package/dist/src/core/agents/registry.js +93 -0
  45. package/dist/src/core/agents/runtime.js +4 -0
  46. package/dist/src/core/agents/runtime.smoke.js +42 -0
  47. package/dist/src/core/agents/swarm.smoke.js +48 -0
  48. package/dist/src/core/agents/swarmTools.js +38 -0
  49. package/dist/src/core/auth/index.js +2 -0
  50. package/dist/src/core/auth/loginCliAdapter.js +24 -0
  51. package/dist/src/core/auth/loginCore.js +67 -0
  52. package/dist/src/core/auth/logoutCliAdapter.js +34 -0
  53. package/dist/src/core/auth/logoutCore.js +52 -0
  54. package/dist/src/core/auth/preflight.smoke.js +151 -0
  55. package/dist/src/core/index.js +21 -0
  56. package/dist/src/core/mcp/blueprints.js +27 -0
  57. package/dist/src/core/mcp/common.js +14 -0
  58. package/dist/src/core/mcp/runtime.js +67 -0
  59. package/dist/src/core/mcp/runtime.smoke.js +50 -0
  60. package/dist/src/core/mcp/swarmClient.js +40 -0
  61. package/dist/src/core/mcp/swarmSetup.js +43 -0
  62. package/dist/src/core/providers/cliAdapter.js +39 -0
  63. package/dist/src/core/providers/contracts.js +1 -0
  64. package/dist/src/core/providers/index.js +3 -0
  65. package/dist/src/core/providers/llmCore.js +123 -0
  66. package/dist/src/core/providers/providerCore.js +141 -0
  67. package/dist/src/core/providers/providerModelCompatibility.js +98 -0
  68. package/dist/src/core/providers/providerParitySmoke.js +83 -0
  69. package/dist/src/core/providers/providerProfileModelSmoke.js +80 -0
  70. package/dist/src/core/query/contracts.js +1 -0
  71. package/dist/src/core/query/runtime.js +117 -0
  72. package/dist/src/core/query/runtime.smoke.js +39 -0
  73. package/dist/src/core/query/timelineThinking.smoke.js +25 -0
  74. package/dist/src/core/query/wiring.smoke.js +76 -0
  75. package/dist/src/core/skills/cliAdapter.js +38 -0
  76. package/dist/src/core/skills/index.js +52 -0
  77. package/dist/src/core/skills/runtime.smoke.js +53 -0
  78. package/dist/src/core/tasks/runtime.js +205 -0
  79. package/dist/src/core/tasks/runtime.smoke.js +63 -0
  80. package/dist/src/core/tasks/sdkAdapter.js +4 -0
  81. package/dist/src/core/tools/contracts.js +3 -0
  82. package/dist/src/core/tools/fileResolution.js +112 -0
  83. package/dist/src/core/tools/fileResolution.smoke.js +33 -0
  84. package/dist/src/core/tools/filesCore.js +51 -0
  85. package/dist/src/core/tools/filesCore.smoke.js +108 -0
  86. package/dist/src/core/tools/gitCore.js +20 -0
  87. package/dist/src/core/tools/imageParity.smoke.js +36 -0
  88. package/dist/src/core/tools/notebookParity.smoke.js +68 -0
  89. package/dist/src/core/tools/registry.js +22 -0
  90. package/dist/src/core/tools/runtime.smoke.js +32 -0
  91. package/dist/src/core/tools/shellCore.js +60 -0
  92. package/dist/src/core/types/agentContext.js +9 -0
  93. package/dist/src/core/types/auth.js +3 -0
  94. package/dist/src/core/types/command.js +13 -0
  95. package/dist/src/core/types/provider.js +3 -0
  96. package/dist/src/core/types/sdkEvent.js +10 -0
  97. package/dist/src/core/types/swarm.js +1 -0
  98. package/dist/src/cost-tracker.js +3 -3
  99. package/dist/src/hooks/useAwaySummary.js +22 -9
  100. package/dist/src/main.js +32 -2
  101. package/dist/src/screens/REPL.js +9 -0
  102. package/dist/src/services/AgentSummary/agentSummary.js +10 -10
  103. package/dist/src/services/autoDream/autoDream.js +5 -5
  104. package/dist/src/services/autoDream/consolidationPrompt.js +49 -49
  105. package/dist/src/services/compact/prompt.js +238 -238
  106. package/dist/src/services/limits/sessionCounter.js +17 -17
  107. package/dist/src/services/mcp/client.js +27 -1
  108. package/dist/src/services/orchestration/execution/AgentTaskExecutor.js +39 -20
  109. package/dist/src/services/orchestration/execution/OrchestrationExecutionRuntime.js +65 -58
  110. package/dist/src/skills/bundled/loop.js +57 -57
  111. package/dist/src/skills/bundled/remember.js +53 -53
  112. package/dist/src/skills/bundled/simplify.js +49 -49
  113. package/dist/src/skills/bundled/skillify.js +2 -2
  114. package/dist/src/state/onChangeAppState.js +6 -0
  115. package/dist/src/tasks/LocalAgentTask/LocalAgentTask.js +5 -5
  116. package/dist/src/tasks/LocalMainSessionTask.js +5 -5
  117. package/dist/src/tasks/LocalShellTask/LocalShellTask.js +13 -13
  118. package/dist/src/tools/AgentTool/forkSubagent.js +25 -25
  119. package/dist/src/tools/AskUserQuestionTool/prompt.js +29 -29
  120. package/dist/src/tools/BashTool/BashTool.js +27 -2
  121. package/dist/src/tools/BriefTool/prompt.js +14 -14
  122. package/dist/src/tools/EnterPlanModeTool/EnterPlanModeTool.js +12 -12
  123. package/dist/src/tools/EnterPlanModeTool/prompt.js +140 -140
  124. package/dist/src/tools/ExitPlanModeTool/ExitPlanModeV2Tool.js +18 -18
  125. package/dist/src/tools/ExitPlanModeTool/prompt.js +23 -23
  126. package/dist/src/tools/ExitWorktreeTool/prompt.js +29 -29
  127. package/dist/src/tools/FileEditTool/prompt.js +7 -7
  128. package/dist/src/tools/FileReadTool/FileReadTool.js +18 -1
  129. package/dist/src/tools/FileWriteTool/prompt.js +6 -6
  130. package/dist/src/tools/GlobTool/prompt.js +4 -4
  131. package/dist/src/tools/GrepTool/prompt.js +10 -10
  132. package/dist/src/tools/LSPTool/prompt.js +18 -18
  133. package/dist/src/tools/ListMcpResourcesTool/prompt.js +15 -15
  134. package/dist/src/tools/PowerShellTool/PowerShellTool.js +25 -2
  135. package/dist/src/tools/ReadMcpResourceTool/prompt.js +13 -13
  136. package/dist/src/tools/SendMessageTool/prompt.js +36 -36
  137. package/dist/src/tools/SkillTool/prompt.js +21 -21
  138. package/dist/src/tools/SleepTool/prompt.js +10 -10
  139. package/dist/src/tools/TaskCreateTool/prompt.js +41 -41
  140. package/dist/src/tools/TaskGetTool/prompt.js +21 -21
  141. package/dist/src/tools/TaskListTool/prompt.js +30 -30
  142. package/dist/src/tools/TaskOutputTool/TaskOutputTool.js +8 -8
  143. package/dist/src/tools/TaskStopTool/prompt.js +5 -5
  144. package/dist/src/tools/TaskUpdateTool/prompt.js +74 -74
  145. package/dist/src/tools/TodoWriteTool/prompt.js +178 -178
  146. package/dist/src/tools/ToolSearchTool/prompt.js +9 -9
  147. package/dist/src/tools/WebFetchTool/WebFetchTool.js +9 -9
  148. package/dist/src/tools/WebFetchTool/prompt.js +31 -31
  149. package/dist/src/tools/WebSearchTool/prompt.js +26 -26
  150. package/dist/src/utils/agentContext.js +2 -0
  151. package/dist/src/utils/agenticSessionSearch.js +38 -38
  152. package/dist/src/utils/config.js +2 -0
  153. package/dist/src/utils/genericProcessUtils.js +21 -21
  154. package/dist/src/utils/heapDumpService.js +4 -4
  155. package/dist/src/utils/mcpValidation.js +2 -2
  156. package/dist/src/utils/model/modelStrings.js +1 -1
  157. package/dist/src/utils/model/providers.js +5 -0
  158. package/dist/src/utils/orchestration/store/providerAgentStore.js +22 -22
  159. package/dist/src/utils/orchestration/store/providerWorkspaceStore.js +10 -10
  160. package/dist/src/utils/orchestration/store/runStore.js +68 -68
  161. package/dist/src/utils/orchestration/store/teamStore.js +28 -28
  162. package/dist/src/utils/permissions/permissionExplainer.js +6 -6
  163. package/dist/src/utils/permissions/permissionsDb.js +43 -43
  164. package/dist/src/utils/sdkEventQueue.js +2 -0
  165. package/dist/src/utils/secureStorage/sqliteStorage.js +12 -12
  166. package/dist/src/utils/standardMcp/common.js +15 -0
  167. package/dist/src/utils/standardMcp/setup.js +52 -0
  168. package/dist/src/utils/swarm/teammatePromptAddendum.js +10 -10
  169. package/dist/src/utils/task/framework.js +6 -6
  170. package/package.json +1 -1
  171. package/dist/src/commands/usage/index.js +0 -7
  172. package/dist/src/commands/usage/usage.js +0 -5
@@ -0,0 +1,117 @@
1
+ import { getSessionId } from '../../bootstrap/state.js';
2
+ function now() {
3
+ return Date.now();
4
+ }
5
+ function asArray(value) {
6
+ return Array.isArray(value) ? value : [];
7
+ }
8
+ function readTextFromAssistantContent(content) {
9
+ const parts = asArray(content);
10
+ const text = parts
11
+ .filter(part => part && typeof part === 'object' && part.type === 'text')
12
+ .map(part => String(part.text ?? '').trim())
13
+ .filter(Boolean)
14
+ .join('\n')
15
+ .trim();
16
+ return text || undefined;
17
+ }
18
+ export class CoreQueryRuntimeEmitter {
19
+ sink;
20
+ turn = 1;
21
+ hasEmittedRunning = false;
22
+ constructor(sink) {
23
+ this.sink = sink;
24
+ }
25
+ setTurn(turn) {
26
+ this.turn = turn;
27
+ }
28
+ emit(event) {
29
+ this.sink?.(event);
30
+ }
31
+ emitRunning() {
32
+ if (this.hasEmittedRunning) {
33
+ return;
34
+ }
35
+ this.hasEmittedRunning = true;
36
+ this.emitSessionState('running');
37
+ }
38
+ emitSessionState(state, reason) {
39
+ this.emit({
40
+ type: 'session_state',
41
+ timestamp: now(),
42
+ sessionId: getSessionId(),
43
+ turn: this.turn,
44
+ state,
45
+ reason,
46
+ });
47
+ }
48
+ emitError(message, code) {
49
+ this.emit({
50
+ type: 'error',
51
+ timestamp: now(),
52
+ sessionId: getSessionId(),
53
+ turn: this.turn,
54
+ code,
55
+ message,
56
+ });
57
+ }
58
+ emitResult(isError, stopReason, result) {
59
+ this.emit({
60
+ type: 'result',
61
+ timestamp: now(),
62
+ sessionId: getSessionId(),
63
+ turn: this.turn,
64
+ isError,
65
+ result,
66
+ stopReason: stopReason ?? null,
67
+ });
68
+ }
69
+ emitFromQueryMessage(message) {
70
+ if (!message || typeof message !== 'object') {
71
+ return;
72
+ }
73
+ if (message.type === 'assistant') {
74
+ const content = message.message?.content;
75
+ this.emit({
76
+ type: 'assistant_message',
77
+ timestamp: now(),
78
+ sessionId: getSessionId(),
79
+ turn: this.turn,
80
+ text: readTextFromAssistantContent(content),
81
+ });
82
+ for (const part of asArray(content)) {
83
+ if (!part || typeof part !== 'object' || part.type !== 'tool_use') {
84
+ continue;
85
+ }
86
+ this.emit({
87
+ type: 'tool_call',
88
+ timestamp: now(),
89
+ sessionId: getSessionId(),
90
+ turn: this.turn,
91
+ toolName: String(part.name ?? 'unknown'),
92
+ toolUseId: part.id,
93
+ input: part.input,
94
+ });
95
+ }
96
+ return;
97
+ }
98
+ if (message.type === 'user') {
99
+ const content = message.message?.content;
100
+ for (const part of asArray(content)) {
101
+ if (!part || typeof part !== 'object' || part.type !== 'tool_result') {
102
+ continue;
103
+ }
104
+ this.emit({
105
+ type: 'tool_result',
106
+ timestamp: now(),
107
+ sessionId: getSessionId(),
108
+ turn: this.turn,
109
+ toolUseId: part.tool_use_id,
110
+ isError: Boolean(part.is_error),
111
+ content: part.content,
112
+ });
113
+ }
114
+ return;
115
+ }
116
+ }
117
+ }
@@ -0,0 +1,39 @@
1
+ import assert from 'node:assert/strict';
2
+ import { CoreQueryRuntimeEmitter } from './runtime.js';
3
+ const events = [];
4
+ const emitter = new CoreQueryRuntimeEmitter(event => {
5
+ events.push(event);
6
+ });
7
+ emitter.emitSessionState('started');
8
+ emitter.emitRunning();
9
+ emitter.emitFromQueryMessage({
10
+ type: 'assistant',
11
+ message: {
12
+ content: [
13
+ { type: 'text', text: 'hello' },
14
+ { type: 'tool_use', id: 'tool-1', name: 'shell', input: { command: 'pwd' } },
15
+ ],
16
+ },
17
+ });
18
+ emitter.emitFromQueryMessage({
19
+ type: 'user',
20
+ message: {
21
+ content: [{ type: 'tool_result', tool_use_id: 'tool-1', is_error: false, content: 'ok' }],
22
+ },
23
+ });
24
+ emitter.emitError('cancelled by user', 'cancelled');
25
+ emitter.emitResult(true, 'end_turn', 'partial result');
26
+ emitter.emitSessionState('failed', 'cancelled');
27
+ assert.equal(events[0]?.type, 'session_state');
28
+ assert.equal(events[0]?.state, 'started');
29
+ assert.equal(events[1]?.type, 'session_state');
30
+ assert.equal(events[1]?.state, 'running');
31
+ assert.equal(events[2]?.type, 'assistant_message');
32
+ assert.equal(events[3]?.type, 'tool_call');
33
+ assert.equal(events[4]?.type, 'tool_result');
34
+ assert.equal(events[5]?.type, 'error');
35
+ assert.equal(events[6]?.type, 'result');
36
+ assert.equal(events[6]?.result, 'partial result');
37
+ assert.equal(events[7]?.type, 'session_state');
38
+ assert.equal(events[7]?.reason, 'cancelled');
39
+ console.log('runtime.smoke PASS');
@@ -0,0 +1,25 @@
1
+ import assert from 'node:assert/strict';
2
+ import { readFileSync } from 'node:fs';
3
+ import { resolve } from 'node:path';
4
+ function readText(absolutePath) {
5
+ return readFileSync(absolutePath, 'utf8');
6
+ }
7
+ const desktopRoot = resolve(process.cwd(), '..', 'apps', 'desktop', 'src');
8
+ try {
9
+ readFileSync(resolve(desktopRoot, 'App.tsx'), 'utf8');
10
+ }
11
+ catch {
12
+ console.error('timeline-thinking smoke: no se encontro apps/desktop/src/App.tsx');
13
+ process.exit(1);
14
+ }
15
+ const appSrc = readText(resolve(desktopRoot, 'App.tsx'));
16
+ const cliEventsSrc = readText(resolve(desktopRoot, 'lib', 'cliEvents.ts'));
17
+ assert.ok(appSrc.includes('function isCoreQueryTerminalPayload('), 'App.tsx: falta detector terminal core_query para apagar thinking/spinner');
18
+ assert.ok(appSrc.includes("payload.eventType === \"result\""), 'App.tsx: terminal detector debe tratar result como fin de turno');
19
+ assert.ok(appSrc.includes('payload.eventType === "session_state"'), 'App.tsx: terminal detector debe revisar session_state');
20
+ assert.ok(appSrc.includes('reason === "cancelled"') && appSrc.includes('reason === "canceled"'), 'App.tsx: session_state terminal debe cubrir reason cancelled/canceled');
21
+ assert.ok(appSrc.includes('setThinkingByChat((prev) => {'), 'App.tsx: falta efecto de cierre de thinking por eventos terminales');
22
+ assert.ok(cliEventsSrc.includes('case "core_query_event"'), 'cliEvents.ts: falta parser core_query_event para timeline Desktop');
23
+ assert.ok(cliEventsSrc.includes('Sesi') && cliEventsSrc.includes('cancelada'), 'cliEvents.ts: timeline no refleja cancelacion de sesion');
24
+ assert.ok(cliEventsSrc.includes('Resultado con error') && cliEventsSrc.includes('Resultado'), 'cliEvents.ts: timeline debe cubrir result success/error');
25
+ console.log('timeline-thinking smoke PASS');
@@ -0,0 +1,76 @@
1
+ // Smoke estatico que valida el wiring del adapter Core Query → stream-json.
2
+ //
3
+ // Por que estatico (grep guard):
4
+ // Un E2E real requiere CLI compilado, credenciales y red. Para gate de
5
+ // regresion en CI/local basta con verificar que el codigo que conecta el
6
+ // sink y la emision NDJSON sigue presente. Si alguien borra el wiring por
7
+ // refactor, este smoke falla con un mensaje accionable.
8
+ //
9
+ // Que valida:
10
+ // 1. `QueryEngine.ask()` declara y propaga `onCoreQueryEvent` al engine.
11
+ // 2. `cli/print.ts` arma el sink condicional a `CORE_QUERY_ENABLED=1` y
12
+ // `outputFormat === 'stream-json'`, escribiendo NDJSON con el campo
13
+ // `type: "core_query_event"`.
14
+ // 3. El emitter sigue traduciendo eventos del loop a la forma neutral.
15
+ import assert from 'node:assert/strict';
16
+ import { readFileSync } from 'node:fs';
17
+ import { dirname, resolve } from 'node:path';
18
+ import { fileURLToPath } from 'node:url';
19
+ import { CoreQueryRuntimeEmitter } from './runtime.js';
20
+ const here = dirname(fileURLToPath(import.meta.url));
21
+ // Soporta dos invocaciones:
22
+ // - tsx src/core/query/wiring.smoke.ts (here = .../CLI/src/core/query)
23
+ // - node dist/src/core/query/wiring.smoke.js (here = .../CLI/dist/src/core/query)
24
+ const candidates = [
25
+ resolve(here, '..', '..'), // src
26
+ resolve(here, '..', '..', '..', '..', 'src'),
27
+ ];
28
+ let repoSrc = '';
29
+ for (const candidate of candidates) {
30
+ try {
31
+ readFileSync(resolve(candidate, 'QueryEngine.ts'), 'utf8');
32
+ repoSrc = candidate;
33
+ break;
34
+ }
35
+ catch {
36
+ // probar siguiente candidato
37
+ }
38
+ }
39
+ if (!repoSrc) {
40
+ console.error('wiring.smoke: no se encontro CLI/src/QueryEngine.ts');
41
+ process.exit(1);
42
+ }
43
+ function readSource(relative) {
44
+ const full = resolve(repoSrc, relative);
45
+ return readFileSync(full, 'utf8');
46
+ }
47
+ // 1) ask() declara onCoreQueryEvent y lo pasa al engine.
48
+ const queryEngineSrc = readSource('QueryEngine.ts');
49
+ assert.ok(queryEngineSrc.includes('onCoreQueryEvent?: CoreQueryEventSink'), 'QueryEngine.ts: tipo onCoreQueryEvent no declarado en ask() / config');
50
+ assert.ok(/onCoreQueryEvent[\s,]/.test(queryEngineSrc.split('new QueryEngine({')[1] ?? ''), 'QueryEngine.ts: ask() ya no propaga onCoreQueryEvent al engine');
51
+ // 2) print.ts arma el sink con los dos flags activos.
52
+ const printSrc = readSource('cli/print.ts');
53
+ assert.ok(printSrc.includes("CORE_QUERY_ENABLED === '1'"), 'cli/print.ts: feature flag CORE_QUERY_ENABLED ya no controla el sink');
54
+ assert.ok(printSrc.includes("options.outputFormat === 'stream-json'"), 'cli/print.ts: gate por outputFormat=stream-json no esta presente');
55
+ assert.ok(/type:\s*['"]core_query_event['"]/.test(printSrc), 'cli/print.ts: envelope no marca type:"core_query_event"');
56
+ assert.ok(printSrc.includes('process.stdout.write(jsonStringify(envelope)'), 'cli/print.ts: el sink ya no escribe NDJSON al stdout');
57
+ // 3) Emitter sigue traduciendo eventos del loop a la forma neutral.
58
+ const events = [];
59
+ const emitter = new CoreQueryRuntimeEmitter(event => {
60
+ events.push(event);
61
+ });
62
+ emitter.emitSessionState('started');
63
+ emitter.emitFromQueryMessage({
64
+ type: 'assistant',
65
+ message: {
66
+ content: [{ type: 'text', text: 'hi' }],
67
+ },
68
+ });
69
+ emitter.emitResult(false, 'end_turn');
70
+ emitter.emitSessionState('completed');
71
+ assert.equal(events.length, 4, 'emitter deberia haber producido 4 eventos');
72
+ assert.equal(events[0]?.type, 'session_state');
73
+ assert.equal(events[1]?.type, 'assistant_message');
74
+ assert.equal(events[2]?.type, 'result');
75
+ assert.equal(events[3]?.type, 'session_state');
76
+ console.log('core-query-wiring smoke PASS');
@@ -0,0 +1,38 @@
1
+ import { getBuiltinPluginSkillCommands } from '../../plugins/builtinPlugins.js';
2
+ import { getBundledSkills } from '../../skills/bundledSkills.js';
3
+ import { clearSkillCaches, getSkillDirCommands } from '../../skills/loadSkillsDir.js';
4
+ import { clearPluginSkillsCache, getPluginSkills, } from '../../utils/plugins/loadPluginCommands.js';
5
+ import { logForDebugging } from '../../utils/debug.js';
6
+ import { toError } from '../../utils/errors.js';
7
+ import { logError } from '../../utils/log.js';
8
+ import { CoreSkillsIndex, registerDefaultCoreSkillsIndex, } from './index.js';
9
+ const cliSkillSourcesLoader = {
10
+ loadSkillDirCommands: async (cwd) => {
11
+ try {
12
+ return await getSkillDirCommands(cwd);
13
+ }
14
+ catch (err) {
15
+ logError(toError(err));
16
+ logForDebugging('Core skill directory commands failed to load, continuing without them');
17
+ return [];
18
+ }
19
+ },
20
+ loadPluginSkills: async () => {
21
+ try {
22
+ return await getPluginSkills();
23
+ }
24
+ catch (err) {
25
+ logError(toError(err));
26
+ logForDebugging('Core plugin skills failed to load, continuing without them');
27
+ return [];
28
+ }
29
+ },
30
+ loadBundledSkills: getBundledSkills,
31
+ loadBuiltinPluginCommands: getBuiltinPluginSkillCommands,
32
+ };
33
+ const cliSkillCacheManager = {
34
+ clearSkillCaches,
35
+ clearPluginSkillsCache,
36
+ };
37
+ export const coreSkillsIndex = new CoreSkillsIndex(cliSkillSourcesLoader, cliSkillCacheManager);
38
+ registerDefaultCoreSkillsIndex(coreSkillsIndex);
@@ -0,0 +1,52 @@
1
+ import { getBuiltinPluginSkillCommands } from '../../plugins/builtinPlugins.js';
2
+ import { getBundledSkills } from '../../skills/bundledSkills.js';
3
+ import { clearSkillCaches, getSkillDirCommands, } from '../../skills/loadSkillsDir.js';
4
+ import { logForDebugging } from '../../utils/debug.js';
5
+ import { toError } from '../../utils/errors.js';
6
+ import { logError } from '../../utils/log.js';
7
+ import { clearPluginSkillsCache, getPluginSkills, } from '../../utils/plugins/loadPluginCommands.js';
8
+ export function isCoreSkillsEnabled() {
9
+ return process.env.CORE_SKILLS_ENABLED === '1';
10
+ }
11
+ export async function loadCoreSkillCommandSources(cwd) {
12
+ const [skillDirCommands, pluginSkills] = await Promise.all([
13
+ getSkillDirCommands(cwd).catch(err => {
14
+ logError(toError(err));
15
+ logForDebugging('Core skill directory commands failed to load, continuing without them');
16
+ return [];
17
+ }),
18
+ getPluginSkills().catch(err => {
19
+ logError(toError(err));
20
+ logForDebugging('Core plugin skills failed to load, continuing without them');
21
+ return [];
22
+ }),
23
+ ]);
24
+ return {
25
+ skillDirCommands,
26
+ pluginSkills,
27
+ bundledSkills: getBundledSkills(),
28
+ builtinPluginSkills: getBuiltinPluginSkillCommands(),
29
+ };
30
+ }
31
+ export async function listCoreSkillCommands(cwd) {
32
+ const { skillDirCommands, pluginSkills, bundledSkills, builtinPluginSkills, } = await loadCoreSkillCommandSources(cwd);
33
+ return [
34
+ ...bundledSkills,
35
+ ...builtinPluginSkills,
36
+ ...skillDirCommands,
37
+ ...pluginSkills,
38
+ ];
39
+ }
40
+ export function clearCoreSkillsCaches() {
41
+ clearSkillCaches();
42
+ clearPluginSkillsCache();
43
+ }
44
+ export class CoreSkillsIndex {
45
+ async listSkills(cwd) {
46
+ return listCoreSkillCommands(cwd);
47
+ }
48
+ async listSkillSources(cwd) {
49
+ return loadCoreSkillCommandSources(cwd);
50
+ }
51
+ }
52
+ export const coreSkillsIndex = new CoreSkillsIndex();
@@ -0,0 +1,53 @@
1
+ import assert from 'node:assert/strict';
2
+ import { CoreSkillsIndex } from './index.js';
3
+ const makeCommand = (name) => ({
4
+ type: 'prompt',
5
+ name,
6
+ description: `smoke ${name}`,
7
+ isEnabled: () => true,
8
+ userFacingName() {
9
+ return name;
10
+ },
11
+ });
12
+ const loader = {
13
+ async loadSkillDirCommands(_cwd) {
14
+ return [makeCommand('skill-dir')];
15
+ },
16
+ async loadPluginSkills() {
17
+ return [makeCommand('plugin-skill')];
18
+ },
19
+ loadBundledSkills() {
20
+ return [makeCommand('bundled-skill')];
21
+ },
22
+ loadBuiltinPluginCommands() {
23
+ return [makeCommand('builtin-plugin-skill')];
24
+ },
25
+ };
26
+ let clearSkillCachesCalls = 0;
27
+ let clearPluginSkillsCacheCalls = 0;
28
+ const cacheManager = {
29
+ clearSkillCaches: () => {
30
+ clearSkillCachesCalls += 1;
31
+ },
32
+ clearPluginSkillsCache: () => {
33
+ clearPluginSkillsCacheCalls += 1;
34
+ },
35
+ };
36
+ const index = new CoreSkillsIndex(loader, cacheManager);
37
+ const listed = await index.listSkills(process.cwd());
38
+ const names = listed.map(command => command.name);
39
+ assert.deepEqual(names, [
40
+ 'bundled-skill',
41
+ 'builtin-plugin-skill',
42
+ 'skill-dir',
43
+ 'plugin-skill',
44
+ ]);
45
+ const sources = await index.listSkillSources(process.cwd());
46
+ assert.equal(sources.skillDirCommands.length, 1);
47
+ assert.equal(sources.pluginSkills.length, 1);
48
+ assert.equal(sources.bundledSkills.length, 1);
49
+ assert.equal(sources.builtinPluginSkills.length, 1);
50
+ index.clearCaches();
51
+ assert.equal(clearSkillCachesCalls, 1);
52
+ assert.equal(clearPluginSkillsCacheCalls, 1);
53
+ console.log('skills.runtime.smoke PASS');
@@ -0,0 +1,205 @@
1
+ import { coreAgentsRegistry } from '../agents/registry.js';
2
+ function now() {
3
+ return Date.now();
4
+ }
5
+ function asCoreTaskStatus(status) {
6
+ return status === 'stopped' ? 'killed' : status;
7
+ }
8
+ function inferAgentKind(taskId, taskType) {
9
+ if (taskType === 'in_process_teammate') {
10
+ return 'teammate';
11
+ }
12
+ if (taskType === 'local_agent') {
13
+ return taskId.startsWith('s') ? 'main-session' : 'subagent';
14
+ }
15
+ return 'unknown';
16
+ }
17
+ function buildAgentName(taskId, description, taskType) {
18
+ if (taskType === 'in_process_teammate') {
19
+ return description || taskId;
20
+ }
21
+ if (taskType === 'local_agent' && taskId.startsWith('s')) {
22
+ return 'main-session';
23
+ }
24
+ return description || taskId;
25
+ }
26
+ function toUsage(usage) {
27
+ if (!usage) {
28
+ return undefined;
29
+ }
30
+ return {
31
+ totalTokens: usage.total_tokens,
32
+ toolUses: usage.tool_uses,
33
+ durationMs: usage.duration_ms,
34
+ };
35
+ }
36
+ export class CoreTasksRuntime {
37
+ tasks = new Map();
38
+ agents;
39
+ constructor(agents = coreAgentsRegistry) {
40
+ this.agents = agents;
41
+ }
42
+ createTask(id, description, input = {}) {
43
+ const timestamp = now();
44
+ const task = {
45
+ id,
46
+ description,
47
+ taskType: input.taskType,
48
+ status: 'pending',
49
+ assignedAgentId: input.assignedAgentId,
50
+ assignedAgent: input.assignedAgentId
51
+ ? this.agents.getAgent(input.assignedAgentId)
52
+ : undefined,
53
+ toolUseId: input.toolUseId,
54
+ prompt: input.prompt,
55
+ startedAt: timestamp,
56
+ updatedAt: timestamp,
57
+ source: input.source ?? 'manual',
58
+ };
59
+ this.tasks.set(id, task);
60
+ return task;
61
+ }
62
+ assignAgent(taskId, agent) {
63
+ const task = this.tasks.get(taskId);
64
+ if (!task) {
65
+ return undefined;
66
+ }
67
+ const resolved = typeof agent === 'string' ? this.agents.getAgent(agent) : agent;
68
+ const assignedAgentId = typeof agent === 'string' ? agent : agent.id;
69
+ const next = {
70
+ ...task,
71
+ assignedAgentId,
72
+ assignedAgent: resolved,
73
+ updatedAt: now(),
74
+ };
75
+ this.tasks.set(taskId, next);
76
+ return next;
77
+ }
78
+ updateStatus(taskId, status, result) {
79
+ const task = this.tasks.get(taskId);
80
+ if (!task) {
81
+ return undefined;
82
+ }
83
+ const timestamp = now();
84
+ const next = {
85
+ ...task,
86
+ status,
87
+ result: result ?? task.result,
88
+ updatedAt: timestamp,
89
+ completedAt: status === 'completed' || status === 'failed' || status === 'killed'
90
+ ? timestamp
91
+ : task.completedAt,
92
+ };
93
+ this.tasks.set(taskId, next);
94
+ return next;
95
+ }
96
+ ingestSdkEvent(event) {
97
+ if (event.type !== 'system') {
98
+ return undefined;
99
+ }
100
+ switch (event.subtype) {
101
+ case 'task_started':
102
+ return this.upsertStartedTask(event);
103
+ case 'task_progress':
104
+ return this.upsertProgressTask(event);
105
+ case 'task_notification':
106
+ return this.completeTaskFromSdk(event);
107
+ default:
108
+ return undefined;
109
+ }
110
+ }
111
+ getTask(id) {
112
+ return this.tasks.get(id);
113
+ }
114
+ listTasks() {
115
+ return Array.from(this.tasks.values());
116
+ }
117
+ clear() {
118
+ this.tasks.clear();
119
+ }
120
+ upsertStartedTask(event) {
121
+ const assignedAgentId = event.task_type === 'local_agent' || event.task_type === 'in_process_teammate'
122
+ ? event.task_id
123
+ : undefined;
124
+ if (assignedAgentId && !this.agents.getAgent(assignedAgentId)) {
125
+ this.agents.registerAgent({
126
+ id: assignedAgentId,
127
+ kind: inferAgentKind(event.task_id, event.task_type),
128
+ name: buildAgentName(event.task_id, event.description, event.task_type),
129
+ allowedTools: [],
130
+ source: 'task-runtime',
131
+ metadata: {
132
+ taskType: event.task_type,
133
+ prompt: event.prompt,
134
+ },
135
+ });
136
+ }
137
+ const existing = this.tasks.get(event.task_id);
138
+ const timestamp = now();
139
+ const next = {
140
+ id: event.task_id,
141
+ description: event.description,
142
+ taskType: event.task_type,
143
+ status: 'running',
144
+ assignedAgentId,
145
+ assignedAgent: assignedAgentId
146
+ ? this.agents.getAgent(assignedAgentId)
147
+ : undefined,
148
+ toolUseId: event.tool_use_id,
149
+ prompt: event.prompt,
150
+ summary: existing?.summary,
151
+ lastToolName: existing?.lastToolName,
152
+ usage: existing?.usage,
153
+ result: existing?.result,
154
+ startedAt: existing?.startedAt ?? timestamp,
155
+ updatedAt: timestamp,
156
+ completedAt: undefined,
157
+ source: 'sdk_event',
158
+ };
159
+ this.tasks.set(event.task_id, next);
160
+ return next;
161
+ }
162
+ upsertProgressTask(event) {
163
+ const existing = this.tasks.get(event.task_id) ??
164
+ this.createTask(event.task_id, event.description, {
165
+ taskType: 'local_agent',
166
+ toolUseId: event.tool_use_id,
167
+ source: 'sdk_event',
168
+ });
169
+ const next = {
170
+ ...existing,
171
+ status: 'running',
172
+ description: event.description,
173
+ toolUseId: event.tool_use_id ?? existing.toolUseId,
174
+ usage: toUsage(event.usage),
175
+ summary: event.summary ?? existing.summary,
176
+ lastToolName: event.last_tool_name ?? existing.lastToolName,
177
+ updatedAt: now(),
178
+ source: 'sdk_event',
179
+ };
180
+ this.tasks.set(event.task_id, next);
181
+ return next;
182
+ }
183
+ completeTaskFromSdk(event) {
184
+ const existing = this.tasks.get(event.task_id) ??
185
+ this.createTask(event.task_id, event.summary || event.task_id, {
186
+ toolUseId: event.tool_use_id,
187
+ source: 'sdk_event',
188
+ });
189
+ const timestamp = now();
190
+ const next = {
191
+ ...existing,
192
+ status: asCoreTaskStatus(event.status),
193
+ toolUseId: event.tool_use_id ?? existing.toolUseId,
194
+ summary: event.summary || existing.summary,
195
+ result: event.summary || existing.result,
196
+ usage: toUsage(event.usage) ?? existing.usage,
197
+ updatedAt: timestamp,
198
+ completedAt: timestamp,
199
+ source: 'sdk_event',
200
+ };
201
+ this.tasks.set(event.task_id, next);
202
+ return next;
203
+ }
204
+ }
205
+ export const coreTasksRuntime = new CoreTasksRuntime();
@@ -0,0 +1,63 @@
1
+ import assert from 'node:assert/strict';
2
+ import { coreAgentsRegistry } from '../agents/registry.js';
3
+ import { coreTasksRuntime } from './runtime.js';
4
+ import { runWithAgentContext } from '../../utils/agentContext.js';
5
+ import { enqueueSdkEvent } from '../../utils/sdkEventQueue.js';
6
+ coreAgentsRegistry.clear();
7
+ coreTasksRuntime.clear();
8
+ runWithAgentContext({
9
+ agentId: 'a123',
10
+ agentType: 'subagent',
11
+ subagentName: 'Explore',
12
+ parentSessionId: 'parent-1',
13
+ isBuiltIn: true,
14
+ invokingRequestId: 'req-1',
15
+ invocationKind: 'spawn',
16
+ }, () => {
17
+ enqueueSdkEvent({
18
+ type: 'system',
19
+ subtype: 'task_started',
20
+ task_id: 'a123',
21
+ tool_use_id: 'tool-1',
22
+ description: 'Explore auth flow',
23
+ task_type: 'local_agent',
24
+ prompt: 'Trace the auth flow',
25
+ });
26
+ enqueueSdkEvent({
27
+ type: 'system',
28
+ subtype: 'task_progress',
29
+ task_id: 'a123',
30
+ tool_use_id: 'tool-1',
31
+ description: 'Explore auth flow',
32
+ summary: 'Reading auth sources',
33
+ last_tool_name: 'Read',
34
+ usage: {
35
+ total_tokens: 128,
36
+ tool_uses: 3,
37
+ duration_ms: 5000,
38
+ },
39
+ });
40
+ enqueueSdkEvent({
41
+ type: 'system',
42
+ subtype: 'task_notification',
43
+ task_id: 'a123',
44
+ tool_use_id: 'tool-1',
45
+ status: 'completed',
46
+ output_file: '',
47
+ summary: 'Auth flow mapped',
48
+ });
49
+ });
50
+ const task = coreTasksRuntime.getTask('a123');
51
+ assert.ok(task);
52
+ assert.equal(task.status, 'completed');
53
+ assert.equal(task.assignedAgentId, 'a123');
54
+ assert.equal(task.lastToolName, 'Read');
55
+ assert.equal(task.usage?.toolUses, 3);
56
+ assert.equal(task.result, 'Auth flow mapped');
57
+ const agent = coreAgentsRegistry.getAgent('a123');
58
+ assert.ok(agent);
59
+ assert.equal(agent.kind, 'subagent');
60
+ assert.equal(agent.source, 'subagent-context');
61
+ assert.equal(agent.parentSessionId, 'parent-1');
62
+ assert.equal(agent.metadata?.invocationKind, 'spawn');
63
+ console.log('tasks.runtime.smoke PASS');
@@ -0,0 +1,4 @@
1
+ import { coreTasksRuntime } from './runtime.js';
2
+ export function recordSdkEvent(event) {
3
+ coreTasksRuntime.ingestSdkEvent(event);
4
+ }
@@ -0,0 +1,3 @@
1
+ export function isCoreToolsEnabled() {
2
+ return process.env.CORE_TOOLS_ENABLED === '1';
3
+ }