@superjackfruitlabs/salaam 0.0.3 → 0.0.5
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/CHANGELOG.md +86 -0
- package/README.md +12 -11
- package/dist/src/acp-desk.js +140 -0
- package/dist/src/acp-outcome.js +182 -18
- package/dist/src/acp.js +296 -15
- package/dist/src/agent-profiles.js +45 -0
- package/dist/src/agentpod-authority.js +169 -11
- package/dist/src/agentpod-default-config.js +12 -0
- package/dist/src/agentpod-work-decision-protocol.js +40 -6
- package/dist/src/agentpod-work-decisions.js +108 -4
- package/dist/src/agentpod-work.js +1214 -127
- package/dist/src/approval-rules.js +287 -0
- package/dist/src/attach.js +3 -1
- package/dist/src/autonomy.js +80 -9
- package/dist/src/board-reads.js +106 -0
- package/dist/src/children.js +83 -0
- package/dist/src/cli-help.js +61 -6
- package/dist/src/cli.js +140 -4
- package/dist/src/command-danger.js +797 -0
- package/dist/src/command-network.js +200 -0
- package/dist/src/command-sandbox.js +327 -0
- package/dist/src/custom-commands.js +159 -0
- package/dist/src/danger-classifier.js +286 -0
- package/dist/src/execution-evidence.js +33 -1
- package/dist/src/git-helpers.js +160 -0
- package/dist/src/hooks.js +351 -0
- package/dist/src/host-bind.js +111 -0
- package/dist/src/host-breaker.js +88 -0
- package/dist/src/host-start.js +41 -1
- package/dist/src/host.js +284 -6
- package/dist/src/house-extension.js +292 -61
- package/dist/src/local-coding.js +726 -35
- package/dist/src/local-edit-helper.js +25 -0
- package/dist/src/local-edits.js +168 -6
- package/dist/src/local-undo.js +25 -16
- package/dist/src/managed.js +1 -1
- package/dist/src/mentions.js +277 -0
- package/dist/src/operator-mcp-cli.js +107 -0
- package/dist/src/operator-mcp.js +342 -0
- package/dist/src/persona.js +31 -0
- package/dist/src/pi-sessions.js +5 -1
- package/dist/src/pi.js +22 -1
- package/dist/src/project-instructions.js +195 -0
- package/dist/src/protocol.js +9 -3
- package/dist/src/rate-limit-retries.js +62 -0
- package/dist/src/recurring-work.js +1 -0
- package/dist/src/repository-snapshots.js +5 -2
- package/dist/src/run-grants.js +62 -0
- package/dist/src/service.js +482 -10
- package/dist/src/session-pick.js +77 -0
- package/dist/src/shell-passthrough.js +39 -0
- package/dist/src/station-checkpoints.js +139 -0
- package/dist/src/station-config.js +8 -1
- package/dist/src/station-files.js +20 -1
- package/dist/src/station-task-verification.js +6 -3
- package/dist/src/station-work.js +315 -22
- package/dist/src/store.js +70 -4
- package/dist/src/supervisor.js +408 -25
- package/dist/src/task-budget.js +39 -3
- package/dist/src/task-context.js +8 -2
- package/dist/src/task-critic.js +115 -0
- package/dist/src/task-driver.js +46 -2
- package/dist/src/task-policy.js +44 -12
- package/dist/src/task-verification.js +42 -9
- package/dist/src/task-work.js +47 -0
- package/dist/src/terminal-status.js +88 -0
- package/dist/src/tool-identity.js +69 -0
- package/dist/src/tui-activity.js +99 -0
- package/dist/src/tui-classifier.js +25 -0
- package/dist/src/tui-client.js +186 -5
- package/dist/src/tui-commands.js +23 -5
- package/dist/src/tui-composer.js +113 -0
- package/dist/src/tui-keymap.js +116 -0
- package/dist/src/tui-mentions.js +38 -0
- package/dist/src/tui-modals.js +157 -34
- package/dist/src/tui-notify.js +62 -0
- package/dist/src/tui-review.js +55 -0
- package/dist/src/tui-turn-keys.js +52 -0
- package/dist/src/tui-view.js +243 -69
- package/dist/src/tui.js +875 -118
- package/dist/src/turn-checkpoints.js +221 -0
- package/dist/src/turn-rewind.js +168 -0
- package/dist/src/usage.js +1 -1
- package/dist/src/web-fetch.js +114 -0
- package/dist/src/web-guard.js +163 -0
- package/dist/src/web-search.js +302 -0
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
- package/src/acp-desk.ts +155 -0
- package/src/acp-outcome.ts +174 -20
- package/src/acp.ts +386 -30
- package/src/agent-profiles.ts +48 -0
- package/src/agentpod-authority.ts +234 -15
- package/src/agentpod-default-config.ts +16 -0
- package/src/agentpod-work-decision-protocol.ts +69 -8
- package/src/agentpod-work-decisions.ts +123 -5
- package/src/agentpod-work.ts +1455 -152
- package/src/approval-rules.ts +360 -0
- package/src/attach.ts +4 -1
- package/src/autonomy.ts +111 -10
- package/src/board-reads.ts +148 -0
- package/src/children.ts +112 -0
- package/src/cli-help.ts +60 -6
- package/src/cli.ts +174 -4
- package/src/command-danger.ts +886 -0
- package/src/command-network.ts +215 -0
- package/src/command-sandbox.ts +393 -0
- package/src/custom-commands.ts +175 -0
- package/src/danger-classifier.ts +321 -0
- package/src/execution-evidence.ts +31 -1
- package/src/git-helpers.ts +177 -0
- package/src/hooks.ts +425 -0
- package/src/host-bind.ts +156 -0
- package/src/host-breaker.ts +89 -0
- package/src/host-start.ts +51 -1
- package/src/host.ts +365 -6
- package/src/house-extension.ts +313 -60
- package/src/local-coding.ts +894 -43
- package/src/local-edit-helper.ts +26 -0
- package/src/local-edits.ts +191 -8
- package/src/local-undo.ts +29 -14
- package/src/managed.ts +2 -2
- package/src/mentions.ts +304 -0
- package/src/operator-mcp-cli.ts +108 -0
- package/src/operator-mcp.ts +420 -0
- package/src/persona.ts +37 -0
- package/src/pi-sessions.ts +9 -1
- package/src/pi.ts +23 -1
- package/src/project-instructions.ts +229 -0
- package/src/protocol.ts +25 -3
- package/src/rate-limit-retries.ts +69 -0
- package/src/recurring-work.ts +1 -0
- package/src/repository-snapshots.ts +5 -2
- package/src/run-grants.ts +107 -0
- package/src/service.ts +709 -10
- package/src/session-pick.ts +102 -0
- package/src/shell-passthrough.ts +38 -0
- package/src/station-checkpoints.ts +183 -0
- package/src/station-config.ts +10 -1
- package/src/station-files.ts +20 -1
- package/src/station-task-verification.ts +6 -3
- package/src/station-work.ts +369 -20
- package/src/store.ts +70 -3
- package/src/supervisor.ts +463 -26
- package/src/task-budget.ts +48 -3
- package/src/task-context.ts +9 -2
- package/src/task-critic.ts +171 -0
- package/src/task-driver.ts +49 -2
- package/src/task-policy.ts +65 -13
- package/src/task-verification.ts +53 -9
- package/src/task-work.ts +75 -0
- package/src/terminal-status.ts +103 -0
- package/src/tool-identity.ts +110 -0
- package/src/tui-activity.ts +133 -0
- package/src/tui-classifier.ts +38 -0
- package/src/tui-client.ts +239 -8
- package/src/tui-commands.ts +49 -10
- package/src/tui-composer.ts +124 -0
- package/src/tui-keymap.ts +152 -0
- package/src/tui-mentions.ts +43 -0
- package/src/tui-modals.ts +173 -43
- package/src/tui-notify.ts +77 -0
- package/src/tui-review.ts +76 -0
- package/src/tui-turn-keys.ts +77 -0
- package/src/tui-view.ts +341 -88
- package/src/tui.ts +1047 -137
- package/src/turn-checkpoints.ts +253 -0
- package/src/turn-rewind.ts +258 -0
- package/src/usage.ts +1 -1
- package/src/web-fetch.ts +140 -0
- package/src/web-guard.ts +195 -0
- package/src/web-search.ts +402 -0
package/src/acp-outcome.ts
CHANGED
|
@@ -312,6 +312,123 @@ export function acpFailure(
|
|
|
312
312
|
...(kind === 'unknown' ? {} : { retryable: false }),
|
|
313
313
|
};
|
|
314
314
|
}
|
|
315
|
+
/** ACP tool kind for an approval, so a client's modes can tell edits apart:
|
|
316
|
+
* AgentPod's accept-edits approves only kind "edit"; full-auto approves all; ask none. */
|
|
317
|
+
export function permissionKind(operationKind: string): 'edit' | 'execute' | 'other' {
|
|
318
|
+
if (operationKind === 'workspace') return 'edit';
|
|
319
|
+
if (operationKind === 'harness') return 'execute';
|
|
320
|
+
return 'other';
|
|
321
|
+
}
|
|
322
|
+
/** An operator MCP catalog read is a read; a server's `fetch` tool is a fetch; others stay other. */
|
|
323
|
+
function operatorMcpKind(action: string, tool: unknown): string {
|
|
324
|
+
if (action === 'catalog') return 'read';
|
|
325
|
+
return action === 'call' && tool === 'fetch' ? 'fetch' : 'other';
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
function toolArgs(input: unknown): Record<string, unknown> {
|
|
329
|
+
try {
|
|
330
|
+
const value = typeof input === 'string' ? JSON.parse(input) : input;
|
|
331
|
+
if (value && typeof value === 'object' && !Array.isArray(value))
|
|
332
|
+
return value as Record<string, unknown>;
|
|
333
|
+
} catch {}
|
|
334
|
+
return {};
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
const label = (v: unknown) => (typeof v === 'string' && /^[\w.-]{1,128}$/.test(v) ? v : undefined);
|
|
338
|
+
|
|
339
|
+
/** One line of what a tool acted on, for a card title: no control characters, at most `max`. */
|
|
340
|
+
function shown(v: unknown, max: number): string | undefined {
|
|
341
|
+
if (typeof v !== 'string') return undefined;
|
|
342
|
+
const t = v
|
|
343
|
+
.replace(/[\u0000-\u001f\u007f]+/g, ' ')
|
|
344
|
+
.replace(/\s+/g, ' ')
|
|
345
|
+
.trim();
|
|
346
|
+
if (!t) return undefined;
|
|
347
|
+
return t.length > max ? t.slice(0, max - 1) + '…' : t;
|
|
348
|
+
}
|
|
349
|
+
/** A URL as host and path only: never its login, query or fragment (they may carry a secret). */
|
|
350
|
+
function shownUrl(v: unknown): string | undefined {
|
|
351
|
+
if (typeof v !== 'string') return undefined;
|
|
352
|
+
try {
|
|
353
|
+
const u = new URL(v);
|
|
354
|
+
if (u.protocol !== 'http:' && u.protocol !== 'https:') return undefined;
|
|
355
|
+
return u.host + (u.pathname === '/' ? '' : u.pathname);
|
|
356
|
+
} catch {
|
|
357
|
+
return undefined;
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
const titled = (verb: string, what: string | undefined) => {
|
|
361
|
+
if (!what) return verb;
|
|
362
|
+
const t = `${verb}: ${what}`;
|
|
363
|
+
return t.length > 80 ? t.slice(0, 79) + '…' : t;
|
|
364
|
+
};
|
|
365
|
+
|
|
366
|
+
/**
|
|
367
|
+
* The ACP title for a tool call, the way a board agent's card reads: the tool and what it acted on
|
|
368
|
+
* ("fetch: host/path", "write: runs/r/answer.md"). Every operator MCP call goes through one wrapper
|
|
369
|
+
* tool, so it is titled by the MCP tool itself. Only plain identifiers, URL host and path, paths,
|
|
370
|
+
* queries and commands are echoed, clipped to one line of 80 characters.
|
|
371
|
+
*/
|
|
372
|
+
/** A clipped input no longer parses: read the leading plain string fields it still carries. */
|
|
373
|
+
function clippedArgs(input: unknown): Record<string, unknown> {
|
|
374
|
+
if (typeof input !== 'string') return {};
|
|
375
|
+
const out: Record<string, unknown> = {};
|
|
376
|
+
for (const key of [
|
|
377
|
+
'action',
|
|
378
|
+
'path',
|
|
379
|
+
'query',
|
|
380
|
+
'pattern',
|
|
381
|
+
'command',
|
|
382
|
+
'server',
|
|
383
|
+
'tool',
|
|
384
|
+
'item_id',
|
|
385
|
+
]) {
|
|
386
|
+
const m = new RegExp(`"${key}"\\s*:\\s*"((?:[^"\\\\]|\\\\.){0,512})"`).exec(input);
|
|
387
|
+
if (m) {
|
|
388
|
+
try {
|
|
389
|
+
out[key] = JSON.parse(`"${m[1]}"`);
|
|
390
|
+
} catch {}
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
// A clipped patch is a long one, so a write: a delete (content null) is short and never clipped.
|
|
394
|
+
return out;
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
export function toolTitle(name: string, input: unknown): string {
|
|
398
|
+
const parsed = toolArgs(input);
|
|
399
|
+
const args = Object.keys(parsed).length ? parsed : clippedArgs(input);
|
|
400
|
+
const action = typeof args.action === 'string' ? args.action : '';
|
|
401
|
+
if (name === 'salaam_operator_mcp') {
|
|
402
|
+
const server = label(args.server);
|
|
403
|
+
const tool = label(args.tool);
|
|
404
|
+
if (action === 'call' && server && tool) {
|
|
405
|
+
const a = toolArgs(args.arguments);
|
|
406
|
+
return titled(tool, shownUrl(a.url) ?? shown(a.query ?? a.path ?? a.pattern, 80));
|
|
407
|
+
}
|
|
408
|
+
if (action === 'catalog') return titled('MCP catalog', server);
|
|
409
|
+
if (action === 'call') return titled('MCP call', server ?? tool);
|
|
410
|
+
return action ? titled('MCP request', label(action)) : 'MCP request (no input)';
|
|
411
|
+
}
|
|
412
|
+
if (name === 'salaam_board') {
|
|
413
|
+
if (action === 'card') return 'read this card';
|
|
414
|
+
if (action === 'attempts') return 'read this card’s runs';
|
|
415
|
+
if (action === 'library_search') return titled('library_search', shown(args.query, 80));
|
|
416
|
+
if (action === 'library_get') return titled('library_get', shown(args.item_id, 32));
|
|
417
|
+
return name;
|
|
418
|
+
}
|
|
419
|
+
if (['salaam_station', 'salaam_files', 'salaam_repository'].includes(name)) {
|
|
420
|
+
if (action === 'patch')
|
|
421
|
+
return titled(args.content === null ? 'delete' : 'write', shown(args.path, 80));
|
|
422
|
+
if (action === 'inspect' && args.path === undefined) return 'inspect workspace';
|
|
423
|
+
if (action === 'check') return titled('check', shown(args.command, 80));
|
|
424
|
+
if (['read', 'list', 'inspect', 'diff'].includes(action))
|
|
425
|
+
return titled(action, shown(args.path, 80));
|
|
426
|
+
if (action === 'search') return titled('search', shown(args.query ?? args.pattern, 80));
|
|
427
|
+
if (action) return action;
|
|
428
|
+
}
|
|
429
|
+
return name;
|
|
430
|
+
}
|
|
431
|
+
|
|
315
432
|
export function toolMetadata(
|
|
316
433
|
name: string,
|
|
317
434
|
input: unknown,
|
|
@@ -324,27 +441,35 @@ export function toolMetadata(
|
|
|
324
441
|
} catch {}
|
|
325
442
|
const action = String(args.action ?? '');
|
|
326
443
|
const kind =
|
|
327
|
-
name === '
|
|
328
|
-
?
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
? '
|
|
332
|
-
: '
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
: ['salaam_files', 'salaam_repository', 'salaam_station'].includes(name) &&
|
|
338
|
-
['search', 'list'].includes(action)
|
|
339
|
-
? 'search'
|
|
340
|
-
: ['salaam_files', 'salaam_repository', 'salaam_station'].includes(name) &&
|
|
341
|
-
['read', 'inspect', ...(name === 'salaam_repository' ? ['diff'] : [])].includes(
|
|
342
|
-
action,
|
|
343
|
-
)
|
|
344
|
-
? 'read'
|
|
345
|
-
: ['salaam_history', 'inspect_child', 'consume_child_result'].includes(name)
|
|
444
|
+
name === 'salaam_board'
|
|
445
|
+
? 'read'
|
|
446
|
+
: name === 'salaam_local' && ['edit', 'command'].includes(action)
|
|
447
|
+
? action === 'edit'
|
|
448
|
+
? 'edit'
|
|
449
|
+
: 'execute'
|
|
450
|
+
: name === 'salaam_command' || (name === 'salaam_station' && action === 'check')
|
|
451
|
+
? ['start', 'cancel', 'check'].includes(action)
|
|
452
|
+
? 'execute'
|
|
453
|
+
: ['status', 'logs'].includes(action)
|
|
346
454
|
? 'read'
|
|
347
|
-
: 'other'
|
|
455
|
+
: 'other'
|
|
456
|
+
: ['salaam_files', 'salaam_station'].includes(name) && action === 'patch'
|
|
457
|
+
? args.content === null
|
|
458
|
+
? 'delete'
|
|
459
|
+
: 'edit'
|
|
460
|
+
: ['salaam_files', 'salaam_repository', 'salaam_station'].includes(name) &&
|
|
461
|
+
['search', 'list'].includes(action)
|
|
462
|
+
? 'search'
|
|
463
|
+
: ['salaam_files', 'salaam_repository', 'salaam_station'].includes(name) &&
|
|
464
|
+
['read', 'inspect', ...(name === 'salaam_repository' ? ['diff'] : [])].includes(
|
|
465
|
+
action,
|
|
466
|
+
)
|
|
467
|
+
? 'read'
|
|
468
|
+
: ['salaam_history', 'inspect_child', 'consume_child_result'].includes(name)
|
|
469
|
+
? 'read'
|
|
470
|
+
: name === 'salaam_operator_mcp'
|
|
471
|
+
? operatorMcpKind(action, args.tool)
|
|
472
|
+
: 'other';
|
|
348
473
|
const locations: { path: string; line?: number }[] = [];
|
|
349
474
|
if (
|
|
350
475
|
['salaam_files', 'salaam_station'].includes(name) &&
|
|
@@ -361,3 +486,32 @@ export function toolMetadata(
|
|
|
361
486
|
}
|
|
362
487
|
return { kind, locations };
|
|
363
488
|
}
|
|
489
|
+
|
|
490
|
+
/** A durable task's steps as the ACP `plan` session update: the whole list, replaced on every
|
|
491
|
+
* change (https://agentclientprotocol.com/protocol/agent-plan). ACP has only pending,
|
|
492
|
+
* in_progress and completed, so a step that stopped says so in its text instead. */
|
|
493
|
+
export function planUpdate(
|
|
494
|
+
task: { steps: { title: string; state: string }[] } | null | undefined,
|
|
495
|
+
): {
|
|
496
|
+
sessionUpdate: 'plan';
|
|
497
|
+
entries: { content: string; priority: 'medium'; status: string }[];
|
|
498
|
+
} | null {
|
|
499
|
+
if (!task?.steps.length) return null;
|
|
500
|
+
return {
|
|
501
|
+
sessionUpdate: 'plan',
|
|
502
|
+
entries: task.steps.map((step) => {
|
|
503
|
+
const status =
|
|
504
|
+
step.state === 'completed'
|
|
505
|
+
? 'completed'
|
|
506
|
+
: step.state === 'running' || step.state === 'awaiting_review'
|
|
507
|
+
? 'in_progress'
|
|
508
|
+
: 'pending';
|
|
509
|
+
const stopped = ['cancelled', 'failed', 'interrupted'].includes(step.state);
|
|
510
|
+
return {
|
|
511
|
+
content: stopped ? `${step.title} (${step.state})` : step.title,
|
|
512
|
+
priority: 'medium' as const,
|
|
513
|
+
status,
|
|
514
|
+
};
|
|
515
|
+
}),
|
|
516
|
+
};
|
|
517
|
+
}
|