@myagentroam/node 0.9.116 → 0.9.117
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/connector.js +223 -224
- package/dist/native-session-history.js +2 -2
- package/dist/runner/abstract-runner.js +3 -3
- package/dist/runner/codex/conversation-parser.js +2 -2
- package/dist/runner/codex/managed-run-controller.js +6 -6
- package/dist/runner/mar-agent/history-projection.js +2 -2
- package/dist/runner/mar-agent-runner.js +5 -5
- package/dist/runner/opencode/conversation-parser.js +3 -3
- package/dist/runner-command-engine.js +1 -1
- package/dist/runner-profiles.js +8 -8
- package/dist/runtime-state.js +1 -1
- package/dist/service/continuous-run-coordinator.js +20 -21
- package/dist/service/{mission-mcp-server.js → goal-mcp-server.js} +28 -28
- package/dist/service/{mission-mcp-stdio.js → goal-mcp-stdio.js} +8 -8
- package/dist/service/goal-runtime.js +250 -0
- package/dist/service/mar-agent-model-transport-test-service.js +2 -19
- package/dist/service/session-command-service.js +4 -4
- package/dist/service/session-identity-service.js +1 -1
- package/dist/service/session-message-service.js +25 -29
- package/dist/service/workspace-queue-workbench-service.js +1 -1
- package/dist/util/runner-native-session-parsers.js +3 -3
- package/package.json +4 -4
- package/dist/service/mission-runtime.js +0 -225
|
@@ -5,7 +5,7 @@ import { basename, join, resolve } from 'node:path';
|
|
|
5
5
|
import { forEachJsonlRecord, listJsonlFiles, mapConcurrent, readJsonlBackwardWindow, readJsonlFileAnchor, readJsonlWindow } from './native-jsonl-reader.js';
|
|
6
6
|
import { nodeLog } from './operational.js';
|
|
7
7
|
import { stripClaudePlanTag } from './runner-command-engine.js';
|
|
8
|
-
import {
|
|
8
|
+
import { stripGoalStartPrompt } from './service/goal-runtime.js';
|
|
9
9
|
import { parseCodexComposerImageMarkers } from './runner/codex/composer-image-markers.js';
|
|
10
10
|
const DISCOVERY_READ_BYTES = 32 * 1024;
|
|
11
11
|
const TRANSCRIPT_HEADER_READ_BYTES = 32 * 1024;
|
|
@@ -490,7 +490,7 @@ async function readTranscript(path, runner, byteLimit, page, targetLines = Numbe
|
|
|
490
490
|
return undefined;
|
|
491
491
|
const title = items.find((item) => item.kind === 'message' && item.role === 'USER')?.text;
|
|
492
492
|
// Tagged Plan Mode instruction labels do not form a session title.
|
|
493
|
-
const strippedTitle = title === undefined ? undefined : stripClaudePlanTag(
|
|
493
|
+
const strippedTitle = title === undefined ? undefined : stripClaudePlanTag(stripGoalStartPrompt(title));
|
|
494
494
|
return {
|
|
495
495
|
runner,
|
|
496
496
|
externalSessionId: id ?? basename(path, '.jsonl'),
|
|
@@ -169,7 +169,7 @@ function resolvedMcpServers(raw, secrets) {
|
|
|
169
169
|
const record = value;
|
|
170
170
|
if (typeof record['serverName'] !== 'string' || record['enabled'] !== true)
|
|
171
171
|
continue;
|
|
172
|
-
if (record['
|
|
172
|
+
if (record['__marGoal'] === true &&
|
|
173
173
|
typeof record['command'] === 'string' &&
|
|
174
174
|
Array.isArray(record['args']) &&
|
|
175
175
|
record['args'].every((value) => typeof value === 'string') &&
|
|
@@ -183,8 +183,8 @@ function resolvedMcpServers(raw, secrets) {
|
|
|
183
183
|
command: record['command'],
|
|
184
184
|
args: record['args'],
|
|
185
185
|
environment: {
|
|
186
|
-
|
|
187
|
-
|
|
186
|
+
MAR_GOAL_MCP_ENDPOINT: record['endpoint'],
|
|
187
|
+
MAR_GOAL_MCP_TOKEN: secrets[record['secretName']]
|
|
188
188
|
}
|
|
189
189
|
});
|
|
190
190
|
continue;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { parseCodexComposerImageMarkers } from './composer-image-markers.js';
|
|
2
2
|
import { normalizeCodexTool } from './tool-normalizer.js';
|
|
3
|
-
import {
|
|
3
|
+
import { stripGoalStartPrompt } from '../../service/goal-runtime.js';
|
|
4
4
|
const MAX_COMPOSER_ATTACHMENT_BYTES = 5 * 1024 * 1024;
|
|
5
5
|
const MAX_COMPOSER_ATTACHMENTS_BYTES = 10 * 1024 * 1024;
|
|
6
6
|
const MAX_ASSISTANT_MESSAGE_CHARACTERS = 64 * 1024;
|
|
@@ -355,7 +355,7 @@ export function codexOfficialItem(session, nativeTurnId, value, turnSequence, it
|
|
|
355
355
|
completedAt
|
|
356
356
|
};
|
|
357
357
|
if (value.type === 'userMessage') {
|
|
358
|
-
const text =
|
|
358
|
+
const text = stripGoalStartPrompt(codexContentText(value.content));
|
|
359
359
|
return text.length === 0
|
|
360
360
|
? undefined
|
|
361
361
|
: {
|
|
@@ -158,8 +158,8 @@ export class CodexManagedRunController {
|
|
|
158
158
|
}
|
|
159
159
|
if (notification.requestId !== undefined &&
|
|
160
160
|
notification.method === 'mcpServer/elicitation/request' &&
|
|
161
|
-
activeRun.
|
|
162
|
-
params.serverName === '
|
|
161
|
+
activeRun.goalMcp === true &&
|
|
162
|
+
params.serverName === 'myagentroam_goal' &&
|
|
163
163
|
isPlainRecord(params._meta) &&
|
|
164
164
|
params._meta.codex_approval_kind === 'mcp_tool_call') {
|
|
165
165
|
this.runner.respond(notification.requestId, {
|
|
@@ -431,7 +431,7 @@ export class CodexManagedRunController {
|
|
|
431
431
|
sessionId,
|
|
432
432
|
threadId,
|
|
433
433
|
cwd,
|
|
434
|
-
|
|
434
|
+
goalMcp: hasGoalMcp(payload.mcpServers)
|
|
435
435
|
});
|
|
436
436
|
turnResult = await this.runner.startTurn(threadId, input, cwd, turnConfiguration, materializedAttachments);
|
|
437
437
|
break;
|
|
@@ -457,7 +457,7 @@ export class CodexManagedRunController {
|
|
|
457
457
|
threadId,
|
|
458
458
|
turnId,
|
|
459
459
|
cwd,
|
|
460
|
-
|
|
460
|
+
goalMcp: hasGoalMcp(payload.mcpServers)
|
|
461
461
|
});
|
|
462
462
|
this.runner.execution.managedTurns.set(turnId, { sessionId: publicSessionId, runId });
|
|
463
463
|
if (this.host.runStatus(runId) === 'CANCELLING') {
|
|
@@ -489,6 +489,6 @@ export class CodexManagedRunController {
|
|
|
489
489
|
});
|
|
490
490
|
}
|
|
491
491
|
}
|
|
492
|
-
function
|
|
493
|
-
return isPlainRecord(value) && isPlainRecord(value.
|
|
492
|
+
function hasGoalMcp(value) {
|
|
493
|
+
return isPlainRecord(value) && isPlainRecord(value.myagentroam_goal);
|
|
494
494
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { MarAgentConversationNormalizer } from './conversation-normalizer.js';
|
|
2
|
-
import {
|
|
2
|
+
import { publicGoalHistoryText } from '../../service/goal-runtime.js';
|
|
3
3
|
export function projectMarAgentHistory(session, entries, options = {}) {
|
|
4
4
|
const turns = new Map();
|
|
5
5
|
const normalizer = new MarAgentConversationNormalizer();
|
|
@@ -47,7 +47,7 @@ export function projectMarAgentHistory(session, entries, options = {}) {
|
|
|
47
47
|
const registeredImages = images === undefined ? [] : (options.registerInputImages?.(entry) ?? []);
|
|
48
48
|
replace(turn, historyItem(session, turn, id, 'user_message', 'COMPLETED', {
|
|
49
49
|
clientMessageId: entry.clientMessageId ?? null,
|
|
50
|
-
text:
|
|
50
|
+
text: publicGoalHistoryText(entry.text),
|
|
51
51
|
contexts: [],
|
|
52
52
|
delivery: 'ACCEPTED',
|
|
53
53
|
...(images?.length
|
|
@@ -130,12 +130,12 @@ export class MarAgentRunner extends AbstractRunner {
|
|
|
130
130
|
reasonCode: null
|
|
131
131
|
},
|
|
132
132
|
{
|
|
133
|
-
id: '
|
|
133
|
+
id: 'goal',
|
|
134
134
|
runner: 'mar-agent',
|
|
135
|
-
label: '/
|
|
136
|
-
stateLabel: '
|
|
137
|
-
description: 'Enter persistent
|
|
138
|
-
inputHint: '/
|
|
135
|
+
label: '/goal',
|
|
136
|
+
stateLabel: 'Goal',
|
|
137
|
+
description: 'Enter persistent Goal mode.',
|
|
138
|
+
inputHint: '/goal',
|
|
139
139
|
source: 'MAR_RUNTIME',
|
|
140
140
|
interaction: 'TOGGLE',
|
|
141
141
|
available: true,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { boundedConversationItemId, compactRunnerText } from '../codex/conversation-parser.js';
|
|
2
|
-
import {
|
|
2
|
+
import { stripGoalStartPrompt } from '../../service/goal-runtime.js';
|
|
3
3
|
import { normalizeOpenCodeTool } from './tool-normalizer.js';
|
|
4
4
|
export function openCodeConversationPage(session, messages, input, managedTurn) {
|
|
5
5
|
const records = messages.flatMap((value) => {
|
|
@@ -49,9 +49,9 @@ function openCodeTurn(session, user, userParts, assistants, sequence, managed) {
|
|
|
49
49
|
const localUser = managed?.items.find((item) => item.kind === 'user_message');
|
|
50
50
|
if (localUser !== undefined)
|
|
51
51
|
items.push({ ...localUser, turnId: managed.id });
|
|
52
|
-
else if (
|
|
52
|
+
else if (stripGoalStartPrompt(userText).length > 0)
|
|
53
53
|
items.push(item(session, nativeTurnId, `user-${nativeTurnId}`, 'user_message', 'COMPLETED', {
|
|
54
|
-
text: compactRunnerText(
|
|
54
|
+
text: compactRunnerText(stripGoalStartPrompt(userText), 20_000),
|
|
55
55
|
attachments: []
|
|
56
56
|
}, startedAt, startedAt, sequence));
|
|
57
57
|
for (const part of compactionParts) {
|
|
@@ -39,7 +39,7 @@ export function parseCommandInvocation(definition, input) {
|
|
|
39
39
|
export class CommandStateStore {
|
|
40
40
|
states = new Map();
|
|
41
41
|
list(sessionId) {
|
|
42
|
-
return [...(this.states.get(sessionId)?.values() ?? [])].filter((state) => state.active || state.commandId === '
|
|
42
|
+
return [...(this.states.get(sessionId)?.values() ?? [])].filter((state) => state.active || state.commandId === 'goal');
|
|
43
43
|
}
|
|
44
44
|
set(sessionId, state) {
|
|
45
45
|
const values = this.states.get(sessionId) ?? new Map();
|
package/dist/runner-profiles.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
const COMMON_COMMAND_DESCRIPTIONS = {
|
|
2
2
|
compact: 'Compact the current session context.',
|
|
3
3
|
plan: 'Toggle collaborative Plan Mode.',
|
|
4
|
-
|
|
4
|
+
goal: 'Enter persistent Goal mode.'
|
|
5
5
|
};
|
|
6
6
|
const CLAUDE_MODEL_ENVIRONMENT = {
|
|
7
7
|
opus: 'ANTHROPIC_DEFAULT_OPUS_MODEL',
|
|
@@ -298,13 +298,13 @@ function validModelName(value) {
|
|
|
298
298
|
: undefined;
|
|
299
299
|
}
|
|
300
300
|
function withCapabilities(profile, available) {
|
|
301
|
-
const
|
|
302
|
-
id: '
|
|
301
|
+
const goal = {
|
|
302
|
+
id: 'goal',
|
|
303
303
|
runner: profile.runner,
|
|
304
|
-
label: '/
|
|
305
|
-
stateLabel: '
|
|
306
|
-
description: COMMON_COMMAND_DESCRIPTIONS.
|
|
307
|
-
inputHint: '/
|
|
304
|
+
label: '/goal',
|
|
305
|
+
stateLabel: 'Goal',
|
|
306
|
+
description: COMMON_COMMAND_DESCRIPTIONS.goal,
|
|
307
|
+
inputHint: '/goal',
|
|
308
308
|
source: 'MAR_RUNTIME',
|
|
309
309
|
interaction: 'TOGGLE',
|
|
310
310
|
available,
|
|
@@ -314,7 +314,7 @@ function withCapabilities(profile, available) {
|
|
|
314
314
|
...profile,
|
|
315
315
|
commands: [
|
|
316
316
|
...profile.commands.map((command) => available ? command : { ...command, available: false, reasonCode: 'RUNNER_UNAVAILABLE' }),
|
|
317
|
-
|
|
317
|
+
goal
|
|
318
318
|
],
|
|
319
319
|
capabilities: available
|
|
320
320
|
? ['history.read', 'events.live', 'turn.start', 'turn.queue', 'turn.interrupt']
|
package/dist/runtime-state.js
CHANGED
|
@@ -1041,7 +1041,7 @@ export class NodeRuntimeState {
|
|
|
1041
1041
|
const clientMessageId = isRecord(payload) && typeof payload.clientMessageId === 'string'
|
|
1042
1042
|
? payload.clientMessageId
|
|
1043
1043
|
: undefined;
|
|
1044
|
-
const userMessage = clientMessageId?.startsWith('
|
|
1044
|
+
const userMessage = clientMessageId?.startsWith('goal:')
|
|
1045
1045
|
? ''
|
|
1046
1046
|
: (this.recentUserMessages.get(run.id) ?? this.currentRunMessageText(run.id));
|
|
1047
1047
|
this.onRunChanged?.(run, session, userMessage.length === 0 ? undefined : userMessage);
|
|
@@ -242,7 +242,7 @@ export class ContinuousRunCoordinator {
|
|
|
242
242
|
const item = this.options.runtime.getQueueItem(itemId);
|
|
243
243
|
if (item === undefined)
|
|
244
244
|
return;
|
|
245
|
-
if (!this.
|
|
245
|
+
if (!this.goalCurrent(pending)) {
|
|
246
246
|
this.deleteQueueItem(item.id);
|
|
247
247
|
this.schedule(sessionId);
|
|
248
248
|
return;
|
|
@@ -262,8 +262,8 @@ export class ContinuousRunCoordinator {
|
|
|
262
262
|
this.options.emitConversation(turn);
|
|
263
263
|
}
|
|
264
264
|
else if (executionId === undefined && pending !== undefined) {
|
|
265
|
-
if (!this.
|
|
266
|
-
this.
|
|
265
|
+
if (!this.goalCurrent(pending)) {
|
|
266
|
+
this.rejectStaleGoal(active.id);
|
|
267
267
|
return;
|
|
268
268
|
}
|
|
269
269
|
const execution = this.options.runtime.createExecution(active.id);
|
|
@@ -277,18 +277,18 @@ export class ContinuousRunCoordinator {
|
|
|
277
277
|
return;
|
|
278
278
|
if (this.dispatchedExecutions.has(executionId))
|
|
279
279
|
return;
|
|
280
|
-
if (!this.
|
|
281
|
-
this.
|
|
280
|
+
if (!this.goalCurrent(pending)) {
|
|
281
|
+
this.rejectStaleGoal(executionId);
|
|
282
282
|
return;
|
|
283
283
|
}
|
|
284
284
|
this.dispatchedExecutions.add(executionId);
|
|
285
285
|
try {
|
|
286
|
-
const
|
|
286
|
+
const goalMcp = pending.goal === undefined
|
|
287
287
|
? undefined
|
|
288
|
-
: await this.options.
|
|
289
|
-
if (!this.
|
|
288
|
+
: await this.options.goalMcp?.(pending);
|
|
289
|
+
if (!this.goalCurrent(pending)) {
|
|
290
290
|
this.dispatchedExecutions.delete(executionId);
|
|
291
|
-
this.
|
|
291
|
+
this.rejectStaleGoal(executionId);
|
|
292
292
|
return;
|
|
293
293
|
}
|
|
294
294
|
this.options.control('run.start', {
|
|
@@ -311,7 +311,7 @@ export class ContinuousRunCoordinator {
|
|
|
311
311
|
collaborationMode: pending.collaborationMode,
|
|
312
312
|
...(pending.serviceTier === undefined ? {} : { serviceTier: pending.serviceTier }),
|
|
313
313
|
secretEnvironment: pending.secretEnvironment,
|
|
314
|
-
...(
|
|
314
|
+
...(goalMcp === undefined ? {} : { mcpSecretEnvironment: goalMcp.secrets }),
|
|
315
315
|
...(pending.personalInstructions === undefined
|
|
316
316
|
? {}
|
|
317
317
|
: { personalInstructions: pending.personalInstructions }),
|
|
@@ -323,7 +323,7 @@ export class ContinuousRunCoordinator {
|
|
|
323
323
|
...(pending.computerUse === undefined ? {} : { computerUse: pending.computerUse }),
|
|
324
324
|
mcpInstallations: [
|
|
325
325
|
...this.options.mcps(pending.workspaceId),
|
|
326
|
-
...(
|
|
326
|
+
...(goalMcp === undefined ? [] : [goalMcp.installation])
|
|
327
327
|
]
|
|
328
328
|
});
|
|
329
329
|
}
|
|
@@ -369,12 +369,11 @@ export class ContinuousRunCoordinator {
|
|
|
369
369
|
if (lease !== undefined)
|
|
370
370
|
this.environmentLeases.set(nextId, lease);
|
|
371
371
|
}
|
|
372
|
-
|
|
372
|
+
removeGoalQueue(sessionId, preservedGoal) {
|
|
373
373
|
for (const [id, pending] of this.preparedInputs) {
|
|
374
|
-
if (pending.sessionId !== sessionId || pending.
|
|
374
|
+
if (pending.sessionId !== sessionId || pending.goal === undefined)
|
|
375
375
|
continue;
|
|
376
|
-
if (pending.
|
|
377
|
-
pending.mission.revision === preservedMission.revision)
|
|
376
|
+
if (pending.goal.id === preservedGoal?.id && pending.goal.revision === preservedGoal.revision)
|
|
378
377
|
continue;
|
|
379
378
|
const item = this.options.runtime.getQueueItem(id);
|
|
380
379
|
if (item !== undefined)
|
|
@@ -414,7 +413,7 @@ export class ContinuousRunCoordinator {
|
|
|
414
413
|
const item = this.options.runtime.getQueueItem(itemId);
|
|
415
414
|
if (item === undefined)
|
|
416
415
|
throw new Error('QUEUE_ITEM_INVALID');
|
|
417
|
-
if (!this.
|
|
416
|
+
if (!this.goalCurrent(pending)) {
|
|
418
417
|
this.deleteQueueItem(item.id);
|
|
419
418
|
this.startIdleQueue(sessionId);
|
|
420
419
|
return;
|
|
@@ -434,13 +433,13 @@ export class ContinuousRunCoordinator {
|
|
|
434
433
|
throw new Error('QUEUE_INPUT_LOST');
|
|
435
434
|
return item;
|
|
436
435
|
}
|
|
437
|
-
|
|
438
|
-
return (pending.
|
|
439
|
-
this.options.
|
|
436
|
+
goalCurrent(pending) {
|
|
437
|
+
return (pending.goal === undefined ||
|
|
438
|
+
this.options.goalCurrent?.(pending) !== false);
|
|
440
439
|
}
|
|
441
|
-
|
|
440
|
+
rejectStaleGoal(runId) {
|
|
442
441
|
this.remove(runId);
|
|
443
|
-
this.options.emitRun(runId, 'run.completed', { code: '
|
|
442
|
+
this.options.emitRun(runId, 'run.completed', { code: 'GOAL_SUBMISSION_STALE' }, 'INTERRUPTED');
|
|
444
443
|
}
|
|
445
444
|
isMessageRun(run) {
|
|
446
445
|
return this.options.runtime.findMessageRun(run.sessionId, run.clientMessageId)?.id === run.id;
|
|
@@ -5,16 +5,16 @@ import { tmpdir } from 'node:os';
|
|
|
5
5
|
import { join } from 'node:path';
|
|
6
6
|
import { unlink } from 'node:fs/promises';
|
|
7
7
|
import { fileURLToPath } from 'node:url';
|
|
8
|
-
export class
|
|
9
|
-
|
|
8
|
+
export class GoalMcpServer {
|
|
9
|
+
goals;
|
|
10
10
|
changed;
|
|
11
11
|
capabilities = new Map();
|
|
12
12
|
endpoint = process.platform === 'win32'
|
|
13
|
-
? `\\\\.\\pipe\\mar-
|
|
14
|
-
: join(tmpdir(), `mar-
|
|
13
|
+
? `\\\\.\\pipe\\mar-goal-${process.pid}-${randomUUID()}`
|
|
14
|
+
: join(tmpdir(), `mar-goal-${process.pid}-${randomUUID()}.sock`);
|
|
15
15
|
listening;
|
|
16
|
-
constructor(
|
|
17
|
-
this.
|
|
16
|
+
constructor(goals, changed) {
|
|
17
|
+
this.goals = goals;
|
|
18
18
|
this.changed = changed;
|
|
19
19
|
}
|
|
20
20
|
listen() {
|
|
@@ -28,15 +28,15 @@ export class MissionMcpServer {
|
|
|
28
28
|
async installation(capability) {
|
|
29
29
|
await this.listen();
|
|
30
30
|
const token = randomBytes(32).toString('base64url');
|
|
31
|
-
const secretName = `
|
|
31
|
+
const secretName = `MAR_GOAL_MCP_${randomBytes(16).toString('hex').toUpperCase()}`;
|
|
32
32
|
this.capabilities.set(token, capability);
|
|
33
33
|
return {
|
|
34
34
|
installation: {
|
|
35
|
-
|
|
36
|
-
serverName: '
|
|
35
|
+
__marGoal: true,
|
|
36
|
+
serverName: 'myagentroam_goal',
|
|
37
37
|
enabled: true,
|
|
38
38
|
command: process.execPath,
|
|
39
|
-
args:
|
|
39
|
+
args: goalMcpStdioArgs(),
|
|
40
40
|
endpoint: this.endpoint,
|
|
41
41
|
secretName
|
|
42
42
|
},
|
|
@@ -81,44 +81,44 @@ export class MissionMcpServer {
|
|
|
81
81
|
const request = JSON.parse(body);
|
|
82
82
|
const capability = typeof request.token === 'string' ? this.capabilities.get(request.token) : undefined;
|
|
83
83
|
if (capability === undefined)
|
|
84
|
-
throw new Error('
|
|
84
|
+
throw new Error('GOAL_CAPABILITY_INVALID');
|
|
85
85
|
const current = this.current(capability);
|
|
86
|
-
if (request.tool === '
|
|
86
|
+
if (request.tool === 'mar_get_goal') {
|
|
87
87
|
socket.end(`${JSON.stringify({ result: current })}\n`);
|
|
88
88
|
return;
|
|
89
89
|
}
|
|
90
|
-
if (request.tool !== '
|
|
91
|
-
throw new Error('
|
|
90
|
+
if (request.tool !== 'mar_update_goal')
|
|
91
|
+
throw new Error('GOAL_TOOL_INVALID');
|
|
92
92
|
const status = request.arguments !== null &&
|
|
93
93
|
typeof request.arguments === 'object' &&
|
|
94
94
|
'status' in request.arguments
|
|
95
95
|
? request.arguments.status
|
|
96
96
|
: undefined;
|
|
97
97
|
if (status !== 'completed' && status !== 'blocked')
|
|
98
|
-
throw new Error('
|
|
99
|
-
const
|
|
98
|
+
throw new Error('GOAL_STATUS_INVALID');
|
|
99
|
+
const goal = this.goals.update(capability.sessionId, capability.goalId, capability.revision, status);
|
|
100
100
|
this.changed(capability.sessionId);
|
|
101
|
-
socket.end(`${JSON.stringify({ result:
|
|
101
|
+
socket.end(`${JSON.stringify({ result: goal })}\n`);
|
|
102
102
|
}
|
|
103
103
|
catch (error) {
|
|
104
|
-
socket.end(`${JSON.stringify({ error: error instanceof Error ? error.message : '
|
|
104
|
+
socket.end(`${JSON.stringify({ error: error instanceof Error ? error.message : 'GOAL_IPC_FAILED' })}\n`);
|
|
105
105
|
}
|
|
106
106
|
}
|
|
107
107
|
current(capability) {
|
|
108
|
-
const
|
|
109
|
-
if (
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
throw new Error('
|
|
113
|
-
return
|
|
108
|
+
const goal = this.goals.get(capability.sessionId);
|
|
109
|
+
if (goal === undefined ||
|
|
110
|
+
goal.id !== capability.goalId ||
|
|
111
|
+
goal.revision !== capability.revision)
|
|
112
|
+
throw new Error('GOAL_CAPABILITY_STALE');
|
|
113
|
+
return goal;
|
|
114
114
|
}
|
|
115
115
|
}
|
|
116
|
-
function
|
|
117
|
-
const javascript = fileURLToPath(new URL('./
|
|
116
|
+
function goalMcpStdioArgs() {
|
|
117
|
+
const javascript = fileURLToPath(new URL('./goal-mcp-stdio.js', import.meta.url));
|
|
118
118
|
if (existsSync(javascript))
|
|
119
119
|
return [javascript];
|
|
120
|
-
const typescript = fileURLToPath(new URL('./
|
|
120
|
+
const typescript = fileURLToPath(new URL('./goal-mcp-stdio.ts', import.meta.url));
|
|
121
121
|
if (!existsSync(typescript))
|
|
122
|
-
throw new Error('
|
|
122
|
+
throw new Error('GOAL_MCP_STDIO_ENTRY_UNAVAILABLE');
|
|
123
123
|
return ['--import', import.meta.resolve('tsx'), typescript];
|
|
124
124
|
}
|
|
@@ -2,16 +2,16 @@ import { connect } from 'node:net';
|
|
|
2
2
|
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
3
3
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
4
4
|
import { z } from 'zod';
|
|
5
|
-
const endpoint = process.env['
|
|
6
|
-
const token = process.env['
|
|
5
|
+
const endpoint = process.env['MAR_GOAL_MCP_ENDPOINT'];
|
|
6
|
+
const token = process.env['MAR_GOAL_MCP_TOKEN'];
|
|
7
7
|
if (endpoint === undefined || token === undefined)
|
|
8
|
-
throw new Error('
|
|
9
|
-
const server = new McpServer({ name: '
|
|
10
|
-
server.registerTool('
|
|
11
|
-
server.registerTool('
|
|
12
|
-
description: 'Explicitly mark the current
|
|
8
|
+
throw new Error('GOAL_CAPABILITY_INVALID');
|
|
9
|
+
const server = new McpServer({ name: 'myagentroam_goal', version: '1.0.0' });
|
|
10
|
+
server.registerTool('mar_get_goal', { description: 'Get the authoritative current Goal, status, and objective.' }, async () => result(await request('mar_get_goal', {})));
|
|
11
|
+
server.registerTool('mar_update_goal', {
|
|
12
|
+
description: 'Explicitly mark the current Goal completed or blocked.',
|
|
13
13
|
inputSchema: { status: z.enum(['completed', 'blocked']) }
|
|
14
|
-
}, async ({ status }) => result(await request('
|
|
14
|
+
}, async ({ status }) => result(await request('mar_update_goal', { status })));
|
|
15
15
|
await server.connect(new StdioServerTransport());
|
|
16
16
|
function request(tool, args) {
|
|
17
17
|
return new Promise((resolve, reject) => {
|