pi-crew 0.2.3 → 0.2.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/AGENTS.md +57 -32
- package/CHANGELOG.md +466 -448
- package/LICENSE +21 -21
- package/NOTICE.md +16 -16
- package/README.md +323 -323
- package/docs/FEATURE_INTAKE.md +126 -0
- package/docs/HARNESS.md +86 -0
- package/docs/HARNESS_BACKLOG.md +41 -0
- package/docs/TEST_MATRIX.md +49 -0
- package/docs/actions-reference.md +595 -595
- package/docs/architecture.md +180 -180
- package/docs/code-review-2026-05-11.md +592 -592
- package/docs/commands-reference.md +347 -347
- package/docs/comparison-pi-subagents-vs-pi-crew.md +303 -0
- package/docs/decisions/0001-durable-state.md +41 -0
- package/docs/decisions/0002-child-process-for-async.md +42 -0
- package/docs/decisions/0003-depth-guard.md +36 -0
- package/docs/decisions/0004-execfile-over-exec.md +34 -0
- package/docs/decisions/0005-no-parameter-properties.md +49 -0
- package/docs/decisions/0006-publish-bundled-esm.md +63 -0
- package/docs/decisions/0007-active-run-binary-index.md +54 -0
- package/docs/decisions/0008-child-pi-warm-pool.md +61 -0
- package/docs/decisions/README.md +23 -0
- package/docs/followup-review-round4-2026-05-13.md +107 -0
- package/docs/implementation-plan-top3.md +333 -0
- package/docs/live-mailbox-runtime.md +36 -36
- package/docs/next-upgrade-roadmap.md +808 -808
- package/docs/oh-my-pi-research.md +509 -0
- package/docs/perf/baseline-2026-05.md +113 -0
- package/docs/perf/final-report-2026-05.md +206 -0
- package/docs/perf/sprint-1-report.md +71 -0
- package/docs/perf/sprint-2-report.md +81 -0
- package/docs/perf/sprint-2.5-report.md +53 -0
- package/docs/perf/sprint-3-report.md +36 -0
- package/docs/perf/sprint-4-report.md +47 -0
- package/docs/perf/sprint-5-report.md +51 -0
- package/docs/perf/sprint-6-report.md +94 -0
- package/docs/perf/sprint-7-report.md +74 -0
- package/docs/perf/upgrade-plan-2026-05.md +147 -0
- package/docs/pi-subagents3-deep-analysis.md +508 -0
- package/docs/product/README.md +31 -0
- package/docs/product/platform.md +27 -0
- package/docs/product/runtime-safety.md +37 -0
- package/docs/product/team-run.md +39 -0
- package/docs/product/team-tool.md +37 -0
- package/docs/publishing.md +65 -65
- package/docs/resource-formats.md +134 -134
- package/docs/runtime-analysis-child-vs-live.md +171 -0
- package/docs/runtime-flow.md +148 -148
- package/docs/runtime-migration-in-process-analysis.md +250 -0
- package/docs/stories/README.md +30 -0
- package/docs/stories/backlog.md +36 -0
- package/docs/templates/decision.md +27 -0
- package/docs/templates/story.md +44 -0
- package/docs/templates/validation-report.md +32 -0
- package/docs/usage.md +238 -238
- package/index.ts +7 -6
- package/install.mjs +65 -65
- package/package.json +107 -100
- package/schema.json +222 -222
- package/skills/child-pi-spawning/SKILL.md +213 -0
- package/skills/context-artifact-hygiene/SKILL.md +32 -0
- package/skills/event-log-tracing/SKILL.md +299 -0
- package/skills/git-master/SKILL.md +225 -24
- package/skills/live-agent-lifecycle/SKILL.md +192 -0
- package/skills/mailbox-interactive/SKILL.md +300 -19
- package/skills/model-routing-context/SKILL.md +94 -0
- package/skills/multi-perspective-review/SKILL.md +88 -0
- package/skills/read-only-explorer/SKILL.md +250 -26
- package/skills/safe-bash/SKILL.md +307 -21
- package/skills/verification-before-done/SKILL.md +11 -2
- package/skills/widget-rendering/SKILL.md +258 -0
- package/skills/workspace-isolation/SKILL.md +202 -0
- package/skills/worktree-isolation/SKILL.md +202 -18
- package/src/adapters/claude-adapter.ts +25 -25
- package/src/adapters/codex-adapter.ts +21 -21
- package/src/adapters/cursor-adapter.ts +17 -17
- package/src/adapters/export-util.ts +137 -137
- package/src/adapters/index.ts +15 -15
- package/src/adapters/registry.ts +18 -18
- package/src/adapters/types.ts +23 -23
- package/src/agents/agent-config.ts +38 -38
- package/src/agents/agent-serializer.ts +38 -38
- package/src/agents/discover-agents.ts +121 -118
- package/src/config/config.ts +740 -858
- package/src/config/defaults.ts +96 -96
- package/src/config/drift-detector.ts +211 -211
- package/src/config/markers.ts +327 -327
- package/src/config/resilient-parser.ts +109 -108
- package/src/config/suggestions.ts +74 -74
- package/src/config/types.ts +199 -0
- package/src/extension/async-notifier.ts +123 -89
- package/src/extension/autonomous-policy.ts +169 -169
- package/src/extension/cross-extension-rpc.ts +104 -104
- package/src/extension/help.ts +47 -47
- package/src/extension/import-index.ts +69 -69
- package/src/extension/management.ts +395 -382
- package/src/extension/notification-router.ts +116 -116
- package/src/extension/notification-sink.ts +51 -51
- package/src/extension/project-init.ts +168 -168
- package/src/extension/register.ts +859 -668
- package/src/extension/registration/artifact-cleanup.ts +15 -15
- package/src/extension/registration/command-utils.ts +54 -54
- package/src/extension/registration/commands.ts +559 -452
- package/src/extension/registration/compaction-guard.ts +125 -125
- package/src/extension/registration/subagent-helpers.ts +102 -102
- package/src/extension/registration/subagent-tools.ts +220 -159
- package/src/extension/registration/team-tool.ts +159 -99
- package/src/extension/registration/viewers.ts +29 -0
- package/src/extension/result-watcher.ts +128 -128
- package/src/extension/run-bundle-schema.ts +89 -89
- package/src/extension/run-export.ts +73 -73
- package/src/extension/run-import.ts +84 -84
- package/src/extension/run-index.ts +94 -94
- package/src/extension/run-maintenance.ts +142 -142
- package/src/extension/session-summary.ts +8 -8
- package/src/extension/team-manager-command.ts +96 -96
- package/src/extension/team-recommendation.ts +188 -188
- package/src/extension/team-tool/api.ts +5 -2
- package/src/extension/team-tool/cancel.ts +224 -209
- package/src/extension/team-tool/config-patch.ts +36 -36
- package/src/extension/team-tool/context.ts +60 -60
- package/src/extension/team-tool/doctor.ts +242 -242
- package/src/extension/team-tool/handle-settings.ts +421 -195
- package/src/extension/team-tool/inspect.ts +41 -41
- package/src/extension/team-tool/lifecycle-actions.ts +139 -139
- package/src/extension/team-tool/parallel-dispatch.ts +156 -156
- package/src/extension/team-tool/plan.ts +19 -19
- package/src/extension/team-tool/respond.ts +112 -111
- package/src/extension/team-tool/run.ts +246 -229
- package/src/extension/team-tool/status.ts +110 -110
- package/src/extension/team-tool-types.ts +13 -13
- package/src/extension/team-tool.ts +344 -344
- package/src/extension/tool-result.ts +16 -16
- package/src/extension/validate-resources.ts +77 -77
- package/src/hooks/registry.ts +61 -61
- package/src/hooks/types.ts +40 -40
- package/src/i18n.ts +184 -184
- package/src/observability/correlation.ts +35 -35
- package/src/observability/event-to-metric.ts +68 -68
- package/src/observability/exporters/adapter.ts +30 -30
- package/src/observability/exporters/otlp-exporter.ts +106 -92
- package/src/observability/exporters/prometheus-exporter.ts +54 -54
- package/src/observability/metric-registry.ts +87 -87
- package/src/observability/metric-retention.ts +54 -54
- package/src/observability/metric-sink.ts +81 -56
- package/src/observability/metrics-primitives.ts +167 -167
- package/src/prompt/prompt-runtime.ts +72 -72
- package/src/runtime/adaptive-plan.ts +338 -0
- package/src/runtime/agent-control.ts +169 -169
- package/src/runtime/agent-memory.ts +72 -72
- package/src/runtime/agent-observability.ts +114 -114
- package/src/runtime/async-marker.ts +26 -26
- package/src/runtime/async-runner.ts +153 -153
- package/src/runtime/attention-events.ts +28 -28
- package/src/runtime/auto-resume.ts +100 -100
- package/src/runtime/background-runner.ts +122 -89
- package/src/runtime/cancellation.ts +61 -61
- package/src/runtime/capability-inventory.ts +116 -116
- package/src/runtime/child-pi-pool.ts +68 -0
- package/src/runtime/child-pi.ts +541 -461
- package/src/runtime/code-summary.ts +247 -247
- package/src/runtime/compaction-summary.ts +271 -271
- package/src/runtime/concurrency.ts +58 -58
- package/src/runtime/crash-recovery.ts +317 -301
- package/src/runtime/crew-agent-records.ts +379 -281
- package/src/runtime/crew-agent-runtime.ts +60 -60
- package/src/runtime/cross-extension-rpc.ts +72 -0
- package/src/runtime/custom-tools/irc-tool.ts +201 -201
- package/src/runtime/custom-tools/submit-result-tool.ts +90 -90
- package/src/runtime/deadletter.ts +47 -47
- package/src/runtime/delivery-coordinator.ts +176 -176
- package/src/runtime/delta-conflict.ts +360 -360
- package/src/runtime/diagnostic-export.ts +102 -102
- package/src/runtime/direct-run.ts +35 -35
- package/src/runtime/effectiveness.ts +82 -81
- package/src/runtime/errors/crew-errors.ts +166 -0
- package/src/runtime/event-stream-bridge.ts +92 -92
- package/src/runtime/foreground-control.ts +82 -82
- package/src/runtime/green-contract.ts +46 -46
- package/src/runtime/group-join.ts +234 -106
- package/src/runtime/heartbeat-watcher.ts +145 -124
- package/src/runtime/iteration-hooks.ts +267 -267
- package/src/runtime/live-agent-control.ts +88 -88
- package/src/runtime/live-agent-manager.ts +377 -179
- package/src/runtime/live-control-realtime.ts +36 -36
- package/src/runtime/live-session-runtime.ts +676 -600
- package/src/runtime/loop-gates.ts +129 -129
- package/src/runtime/manifest-cache.ts +263 -263
- package/src/runtime/mcp-proxy.ts +113 -113
- package/src/runtime/metric-parser.ts +40 -40
- package/src/runtime/model-fallback.ts +282 -274
- package/src/runtime/model-resolver.ts +118 -0
- package/src/runtime/output-validator.ts +187 -187
- package/src/runtime/overflow-recovery.ts +175 -175
- package/src/runtime/parallel-research.ts +44 -44
- package/src/runtime/parallel-utils.ts +156 -156
- package/src/runtime/parent-guard.ts +80 -80
- package/src/runtime/phase-progress.ts +217 -217
- package/src/runtime/pi-args.ts +165 -165
- package/src/runtime/pi-json-output.ts +111 -111
- package/src/runtime/pi-spawn.ts +167 -167
- package/src/runtime/policy-engine.ts +79 -79
- package/src/runtime/post-checks.ts +125 -125
- package/src/runtime/post-exit-stdio-guard.ts +86 -86
- package/src/runtime/process-status.ts +97 -73
- package/src/runtime/progress-event-coalescer.ts +43 -43
- package/src/runtime/recovery-recipes.ts +74 -74
- package/src/runtime/retry-executor.ts +81 -81
- package/src/runtime/role-permission.ts +39 -39
- package/src/runtime/run-tracker.ts +99 -0
- package/src/runtime/runtime-policy.ts +21 -0
- package/src/runtime/runtime-resolver.ts +94 -91
- package/src/runtime/scheduler.ts +294 -0
- package/src/runtime/semaphore.ts +131 -131
- package/src/runtime/sensitive-paths.ts +92 -92
- package/src/runtime/session-usage.ts +79 -79
- package/src/runtime/settings-store.ts +103 -0
- package/src/runtime/sidechain-output.ts +29 -29
- package/src/runtime/skill-instructions.ts +222 -222
- package/src/runtime/stale-reconciler.ts +198 -189
- package/src/runtime/streaming-output.ts +47 -0
- package/src/runtime/subagent-manager.ts +404 -400
- package/src/runtime/subprocess-tool-registry.ts +67 -67
- package/src/runtime/task-display.ts +38 -38
- package/src/runtime/task-graph-scheduler.ts +122 -122
- package/src/runtime/task-graph.ts +207 -207
- package/src/runtime/task-output-context.ts +177 -177
- package/src/runtime/task-packet.ts +93 -93
- package/src/runtime/task-quality.ts +207 -207
- package/src/runtime/task-runner/capabilities.ts +78 -78
- package/src/runtime/task-runner/live-executor.ts +131 -113
- package/src/runtime/task-runner/progress.ts +119 -119
- package/src/runtime/task-runner/prompt-builder.ts +139 -139
- package/src/runtime/task-runner/prompt-pipeline.ts +64 -64
- package/src/runtime/task-runner/result-utils.ts +14 -14
- package/src/runtime/task-runner/run-projection.ts +103 -103
- package/src/runtime/task-runner/state-helpers.ts +22 -22
- package/src/runtime/task-runner.ts +469 -459
- package/src/runtime/team-runner.ts +693 -945
- package/src/runtime/usage-tracker.ts +71 -0
- package/src/runtime/worker-heartbeat.ts +21 -21
- package/src/runtime/worker-startup.ts +57 -57
- package/src/runtime/workflow-state.ts +187 -187
- package/src/runtime/yield-handler.ts +190 -190
- package/src/schema/config-schema.ts +172 -168
- package/src/schema/team-tool-schema.ts +126 -126
- package/src/schema/validation-types.ts +151 -148
- package/src/skills/discover-skills.ts +67 -67
- package/src/skills/skill-templates.ts +374 -374
- package/src/state/active-run-registry.ts +227 -191
- package/src/state/artifact-store.ts +130 -129
- package/src/state/atomic-write.ts +262 -195
- package/src/state/blob-store.ts +116 -116
- package/src/state/contracts.ts +111 -111
- package/src/state/event-log-rotation.ts +161 -158
- package/src/state/event-log.ts +383 -303
- package/src/state/event-reconstructor.ts +217 -217
- package/src/state/jsonl-writer.ts +82 -82
- package/src/state/locks.ts +146 -146
- package/src/state/mailbox.ts +446 -405
- package/src/state/state-store.ts +364 -351
- package/src/state/task-claims.ts +44 -44
- package/src/state/types.ts +285 -285
- package/src/state/usage.ts +29 -29
- package/src/subagents/async-entry.ts +1 -1
- package/src/subagents/index.ts +3 -3
- package/src/subagents/live/control.ts +1 -1
- package/src/subagents/live/manager.ts +1 -1
- package/src/subagents/live/realtime.ts +1 -1
- package/src/subagents/live/session-runtime.ts +1 -1
- package/src/subagents/manager.ts +1 -1
- package/src/subagents/spawn.ts +1 -1
- package/src/teams/discover-teams.ts +116 -116
- package/src/teams/team-config.ts +27 -27
- package/src/teams/team-serializer.ts +38 -38
- package/src/types/diff.d.ts +18 -18
- package/src/ui/agent-management-overlay.ts +144 -144
- package/src/ui/crew-widget.ts +487 -370
- package/src/ui/dashboard-panes/agents-pane.ts +109 -28
- package/src/ui/dashboard-panes/cancellation-pane.ts +42 -42
- package/src/ui/dashboard-panes/capability-pane.ts +59 -59
- package/src/ui/dashboard-panes/health-pane.ts +30 -30
- package/src/ui/dashboard-panes/mailbox-pane.ts +35 -35
- package/src/ui/dashboard-panes/progress-pane.ts +30 -30
- package/src/ui/dashboard-panes/transcript-pane.ts +10 -10
- package/src/ui/heartbeat-aggregator.ts +63 -63
- package/src/ui/keybinding-map.ts +97 -94
- package/src/ui/live-conversation-overlay.ts +152 -0
- package/src/ui/live-run-sidebar.ts +180 -180
- package/src/ui/mascot.ts +442 -442
- package/src/ui/overlays/agent-picker-overlay.ts +57 -57
- package/src/ui/overlays/confirm-overlay.ts +58 -58
- package/src/ui/overlays/mailbox-compose-overlay.ts +144 -144
- package/src/ui/overlays/mailbox-compose-preview.ts +63 -63
- package/src/ui/overlays/mailbox-detail-overlay.ts +122 -122
- package/src/ui/pi-ui-compat.ts +57 -57
- package/src/ui/powerbar-publisher.ts +221 -197
- package/src/ui/render-scheduler.ts +216 -143
- package/src/ui/run-action-dispatcher.ts +118 -118
- package/src/ui/run-dashboard.ts +526 -464
- package/src/ui/run-event-bus.ts +208 -208
- package/src/ui/run-snapshot-cache.ts +826 -777
- package/src/ui/settings-overlay.ts +721 -0
- package/src/ui/snapshot-types.ts +86 -70
- package/src/ui/theme-adapter.ts +190 -190
- package/src/ui/tool-progress-formatter.ts +89 -0
- package/src/ui/transcript-cache.ts +94 -94
- package/src/ui/transcript-viewer.ts +335 -335
- package/src/utils/conflict-detect.ts +662 -0
- package/src/utils/file-coalescer.ts +86 -86
- package/src/utils/frontmatter.ts +68 -68
- package/src/utils/fs-watch.ts +88 -31
- package/src/utils/gh-protocol.ts +479 -0
- package/src/utils/ids.ts +17 -17
- package/src/utils/incremental-reader.ts +104 -104
- package/src/utils/internal-error.ts +6 -6
- package/src/utils/names.ts +27 -27
- package/src/utils/paths.ts +102 -63
- package/src/utils/redaction.ts +44 -44
- package/src/utils/safe-paths.ts +47 -47
- package/src/utils/scan-cache.ts +136 -136
- package/src/utils/sse-parser.ts +134 -134
- package/src/utils/task-name-generator.ts +337 -337
- package/src/utils/timings.ts +33 -33
- package/src/utils/visual.ts +243 -198
- package/src/workflows/discover-workflows.ts +139 -139
- package/src/workflows/validate-workflow.ts +40 -40
- package/src/workflows/workflow-config.ts +26 -26
- package/src/workflows/workflow-serializer.ts +32 -32
- package/src/worktree/branch-freshness.ts +45 -45
- package/src/worktree/cleanup.ts +75 -75
- package/src/worktree/worktree-manager.ts +188 -188
- package/teams/default.team.md +12 -12
- package/teams/fast-fix.team.md +11 -11
- package/teams/implementation.team.md +18 -18
- package/teams/parallel-research.team.md +14 -14
- package/teams/research.team.md +11 -11
- package/teams/review.team.md +12 -12
- package/tsconfig.json +19 -19
- package/workflows/default.workflow.md +30 -30
- package/workflows/fast-fix.workflow.md +23 -23
- package/workflows/implementation.workflow.md +43 -43
- package/workflows/parallel-research.workflow.md +46 -46
- package/workflows/research.workflow.md +22 -22
- package/workflows/review.workflow.md +30 -30
- package/skills/task-packet/SKILL.md +0 -28
- package/skills/verify-evidence/SKILL.md +0 -27
|
@@ -1,60 +1,60 @@
|
|
|
1
|
-
import type { TeamTaskStatus } from "../state/contracts.ts";
|
|
2
|
-
import type { CrewActivityState, ModelRoutingState, UsageState } from "../state/types.ts";
|
|
3
|
-
|
|
4
|
-
export type CrewRuntimeKind = "scaffold" | "child-process" | "live-session";
|
|
5
|
-
export type CrewAgentStatus = "queued" | "running" | "waiting" | "completed" | "failed" | "cancelled" | "stopped";
|
|
6
|
-
|
|
7
|
-
export interface CrewAgentRecentTool {
|
|
8
|
-
tool: string;
|
|
9
|
-
args?: string;
|
|
10
|
-
endedAt: string;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export interface CrewAgentProgress {
|
|
14
|
-
currentTool?: string;
|
|
15
|
-
currentToolArgs?: string;
|
|
16
|
-
currentToolStartedAt?: string;
|
|
17
|
-
recentTools: CrewAgentRecentTool[];
|
|
18
|
-
recentOutput: string[];
|
|
19
|
-
toolCount: number;
|
|
20
|
-
tokens?: number;
|
|
21
|
-
turns?: number;
|
|
22
|
-
durationMs?: number;
|
|
23
|
-
lastActivityAt?: string;
|
|
24
|
-
activityState?: CrewActivityState;
|
|
25
|
-
failedTool?: string;
|
|
26
|
-
consecutiveFailures?: number;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export interface CrewAgentRecord {
|
|
30
|
-
id: string;
|
|
31
|
-
runId: string;
|
|
32
|
-
taskId: string;
|
|
33
|
-
agent: string;
|
|
34
|
-
role: string;
|
|
35
|
-
runtime: CrewRuntimeKind;
|
|
36
|
-
status: CrewAgentStatus;
|
|
37
|
-
startedAt: string;
|
|
38
|
-
completedAt?: string;
|
|
39
|
-
resultArtifactPath?: string;
|
|
40
|
-
transcriptPath?: string;
|
|
41
|
-
statusPath?: string;
|
|
42
|
-
eventsPath?: string;
|
|
43
|
-
outputPath?: string;
|
|
44
|
-
toolUses?: number;
|
|
45
|
-
jsonEvents?: number;
|
|
46
|
-
model?: string;
|
|
47
|
-
routing?: ModelRoutingState;
|
|
48
|
-
usage?: UsageState;
|
|
49
|
-
progress?: CrewAgentProgress;
|
|
50
|
-
error?: string;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
export function taskStatusToAgentStatus(status: TeamTaskStatus): CrewAgentStatus {
|
|
54
|
-
if (status === "completed") return "completed";
|
|
55
|
-
if (status === "failed") return "failed";
|
|
56
|
-
if (status === "cancelled" || status === "skipped") return "cancelled";
|
|
57
|
-
if (status === "running") return "running";
|
|
58
|
-
if (status === "waiting") return "waiting";
|
|
59
|
-
return "queued";
|
|
60
|
-
}
|
|
1
|
+
import type { TeamTaskStatus } from "../state/contracts.ts";
|
|
2
|
+
import type { CrewActivityState, ModelRoutingState, UsageState } from "../state/types.ts";
|
|
3
|
+
|
|
4
|
+
export type CrewRuntimeKind = "scaffold" | "child-process" | "live-session";
|
|
5
|
+
export type CrewAgentStatus = "queued" | "running" | "waiting" | "completed" | "failed" | "cancelled" | "stopped";
|
|
6
|
+
|
|
7
|
+
export interface CrewAgentRecentTool {
|
|
8
|
+
tool: string;
|
|
9
|
+
args?: string;
|
|
10
|
+
endedAt: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface CrewAgentProgress {
|
|
14
|
+
currentTool?: string;
|
|
15
|
+
currentToolArgs?: string;
|
|
16
|
+
currentToolStartedAt?: string;
|
|
17
|
+
recentTools: CrewAgentRecentTool[];
|
|
18
|
+
recentOutput: string[];
|
|
19
|
+
toolCount: number;
|
|
20
|
+
tokens?: number;
|
|
21
|
+
turns?: number;
|
|
22
|
+
durationMs?: number;
|
|
23
|
+
lastActivityAt?: string;
|
|
24
|
+
activityState?: CrewActivityState;
|
|
25
|
+
failedTool?: string;
|
|
26
|
+
consecutiveFailures?: number;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface CrewAgentRecord {
|
|
30
|
+
id: string;
|
|
31
|
+
runId: string;
|
|
32
|
+
taskId: string;
|
|
33
|
+
agent: string;
|
|
34
|
+
role: string;
|
|
35
|
+
runtime: CrewRuntimeKind;
|
|
36
|
+
status: CrewAgentStatus;
|
|
37
|
+
startedAt: string;
|
|
38
|
+
completedAt?: string;
|
|
39
|
+
resultArtifactPath?: string;
|
|
40
|
+
transcriptPath?: string;
|
|
41
|
+
statusPath?: string;
|
|
42
|
+
eventsPath?: string;
|
|
43
|
+
outputPath?: string;
|
|
44
|
+
toolUses?: number;
|
|
45
|
+
jsonEvents?: number;
|
|
46
|
+
model?: string;
|
|
47
|
+
routing?: ModelRoutingState;
|
|
48
|
+
usage?: UsageState;
|
|
49
|
+
progress?: CrewAgentProgress;
|
|
50
|
+
error?: string;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function taskStatusToAgentStatus(status: TeamTaskStatus): CrewAgentStatus {
|
|
54
|
+
if (status === "completed") return "completed";
|
|
55
|
+
if (status === "failed") return "failed";
|
|
56
|
+
if (status === "cancelled" || status === "skipped") return "cancelled";
|
|
57
|
+
if (status === "running") return "running";
|
|
58
|
+
if (status === "waiting") return "waiting";
|
|
59
|
+
return "queued";
|
|
60
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
export interface EventBus {
|
|
2
|
+
on(event: string, handler: (data: unknown) => void): () => void;
|
|
3
|
+
emit(event: string, data: unknown): void;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export type RpcReply<T = void> =
|
|
7
|
+
| { success: true; data?: T }
|
|
8
|
+
| { success: false; error: string };
|
|
9
|
+
|
|
10
|
+
export const PROTOCOL_VERSION = 1;
|
|
11
|
+
|
|
12
|
+
export interface RpcDeps {
|
|
13
|
+
events: EventBus;
|
|
14
|
+
getCtx: () => unknown | undefined;
|
|
15
|
+
spawn: (type: string, prompt: string, options?: Record<string, unknown>) => string;
|
|
16
|
+
abort: (agentId: string) => boolean;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface RpcHandle {
|
|
20
|
+
unsubPing: () => void;
|
|
21
|
+
unsubSpawn: () => void;
|
|
22
|
+
unsubStop: () => void;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function handleRpc<P extends { requestId: string }>(
|
|
26
|
+
events: EventBus,
|
|
27
|
+
channel: string,
|
|
28
|
+
fn: (params: P) => unknown | Promise<unknown>,
|
|
29
|
+
): () => void {
|
|
30
|
+
return events.on(channel, async (raw: unknown) => {
|
|
31
|
+
const params = raw as P;
|
|
32
|
+
try {
|
|
33
|
+
const data = await fn(params);
|
|
34
|
+
const reply: { success: true; data?: unknown } = { success: true };
|
|
35
|
+
if (data !== undefined) reply.data = data;
|
|
36
|
+
events.emit(`${channel}:reply:${params.requestId}`, reply);
|
|
37
|
+
} catch (err: any) {
|
|
38
|
+
events.emit(`${channel}:reply:${params.requestId}`, {
|
|
39
|
+
success: false,
|
|
40
|
+
error: err?.message ?? String(err),
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function registerCrewRpcHandlers(deps: RpcDeps): RpcHandle {
|
|
47
|
+
const { events, getCtx, spawn, abort } = deps;
|
|
48
|
+
|
|
49
|
+
const unsubPing = handleRpc(events, "crew:rpc:ping", () => {
|
|
50
|
+
return { version: PROTOCOL_VERSION };
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
const unsubSpawn = handleRpc<{ requestId: string; type: string; prompt: string; options?: Record<string, unknown> }>(
|
|
54
|
+
events,
|
|
55
|
+
"crew:rpc:spawn",
|
|
56
|
+
({ type, prompt, options }) => {
|
|
57
|
+
const ctx = getCtx();
|
|
58
|
+
if (!ctx) throw new Error("No active session");
|
|
59
|
+
return { id: spawn(type, prompt, options ?? {}) };
|
|
60
|
+
},
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
const unsubStop = handleRpc<{ requestId: string; agentId: string }>(
|
|
64
|
+
events,
|
|
65
|
+
"crew:rpc:stop",
|
|
66
|
+
({ agentId }) => {
|
|
67
|
+
if (!abort(agentId)) throw new Error("Agent not found");
|
|
68
|
+
},
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
return { unsubPing, unsubSpawn, unsubStop };
|
|
72
|
+
}
|
|
@@ -1,201 +1,201 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* G1: Custom tool — irc.
|
|
3
|
-
*
|
|
4
|
-
* Registers a real `irc` tool in the Pi SDK session so that
|
|
5
|
-
* live-session workers can send messages to other live agents.
|
|
6
|
-
*
|
|
7
|
-
* Operations:
|
|
8
|
-
* - `list`: List currently visible peer agents
|
|
9
|
-
* - `send`: Send a message to a specific agent or broadcast to all
|
|
10
|
-
*
|
|
11
|
-
* Adapted from oh-my-pi's `IrcTool` pattern. Uses the live-agent-manager
|
|
12
|
-
* for routing messages between in-process workers.
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
import { defineTool, type ToolDefinition } from "@mariozechner/pi-coding-agent";
|
|
16
|
-
import { Type, type Static } from "@sinclair/typebox";
|
|
17
|
-
import { listLiveAgents, sendIrcMessage, broadcastIrcMessage } from "../live-agent-manager.ts";
|
|
18
|
-
import type { IrcMessage } from "../live-irc.ts";
|
|
19
|
-
|
|
20
|
-
const IrcParams = Type.Object({
|
|
21
|
-
op: Type.Union(
|
|
22
|
-
[
|
|
23
|
-
Type.Literal("send", { description: "Send a message to one peer or to all peers." }),
|
|
24
|
-
Type.Literal("list", { description: "List currently visible peers." }),
|
|
25
|
-
],
|
|
26
|
-
{ description: "IRC operation." },
|
|
27
|
-
),
|
|
28
|
-
to: Type.Optional(
|
|
29
|
-
Type.String({
|
|
30
|
-
description: 'Recipient agent ID or "all" to broadcast.',
|
|
31
|
-
}),
|
|
32
|
-
),
|
|
33
|
-
message: Type.Optional(
|
|
34
|
-
Type.String({
|
|
35
|
-
description: "Message body to deliver.",
|
|
36
|
-
}),
|
|
37
|
-
),
|
|
38
|
-
awaitReply: Type.Optional(
|
|
39
|
-
Type.Boolean({
|
|
40
|
-
description: "Wait for a reply (default: true for DM, false for broadcast). Not yet supported — messages are fire-and-forget.",
|
|
41
|
-
}),
|
|
42
|
-
),
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
type IrcParams = Static<typeof IrcParams>;
|
|
46
|
-
|
|
47
|
-
interface IrcDetails {
|
|
48
|
-
op: "send" | "list";
|
|
49
|
-
from?: string;
|
|
50
|
-
to?: string;
|
|
51
|
-
delivered?: string[];
|
|
52
|
-
notFound?: string[];
|
|
53
|
-
peers?: Array<{ id: string; status: string }>;
|
|
54
|
-
error?: string;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* Create an `irc` tool definition for a specific agent.
|
|
59
|
-
*
|
|
60
|
-
* @param selfId — This agent's ID (runId:taskId format)
|
|
61
|
-
*/
|
|
62
|
-
export function createIrcTool(
|
|
63
|
-
selfId: string,
|
|
64
|
-
): ToolDefinition<typeof IrcParams, IrcDetails> {
|
|
65
|
-
return defineTool({
|
|
66
|
-
name: "irc",
|
|
67
|
-
label: "IRC",
|
|
68
|
-
description:
|
|
69
|
-
"Send messages to other live agents in same team. " +
|
|
70
|
-
'Use `op: "list"` to see peers, `op: "send"` with `to` (agent ID or "all") and `message` to communicate.',
|
|
71
|
-
parameters: IrcParams,
|
|
72
|
-
promptSnippet: "Send messages to other live agents via the irc tool",
|
|
73
|
-
promptGuidelines: [
|
|
74
|
-
"Use irc to coordinate with other agents when you need information or want to share findings.",
|
|
75
|
-
'Use `op: "list"` first to discover available peers.',
|
|
76
|
-
],
|
|
77
|
-
async execute(
|
|
78
|
-
_toolCallId: string,
|
|
79
|
-
params: IrcParams,
|
|
80
|
-
_signal: AbortSignal | undefined,
|
|
81
|
-
_onUpdate: unknown,
|
|
82
|
-
_ctx: unknown,
|
|
83
|
-
): Promise<{ content: Array<{ type: "text"; text: string }>; details: IrcDetails }> {
|
|
84
|
-
if (params.op === "list") {
|
|
85
|
-
return executeList(selfId);
|
|
86
|
-
}
|
|
87
|
-
if (params.op === "send") {
|
|
88
|
-
return executeSend(selfId, params);
|
|
89
|
-
}
|
|
90
|
-
return {
|
|
91
|
-
content: [{ type: "text", text: "Unknown irc op." }],
|
|
92
|
-
details: { op: params.op, from: selfId, error: "Unknown operation." },
|
|
93
|
-
};
|
|
94
|
-
},
|
|
95
|
-
});
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
function executeList(selfId: string): { content: Array<{ type: "text"; text: string }>; details: IrcDetails } {
|
|
99
|
-
const agents = listLiveAgents();
|
|
100
|
-
const peers = agents
|
|
101
|
-
.filter((a) => a.agentId !== selfId && (a.status === "running" || a.status === "queued"))
|
|
102
|
-
.map((a) => ({ id: a.agentId, status: a.status }));
|
|
103
|
-
|
|
104
|
-
const lines: string[] = [];
|
|
105
|
-
if (peers.length === 0) {
|
|
106
|
-
lines.push("No other live agents.");
|
|
107
|
-
} else {
|
|
108
|
-
lines.push(`${peers.length} peer(s):`);
|
|
109
|
-
for (const peer of peers) {
|
|
110
|
-
lines.push(`- ${peer.id} (${peer.status})`);
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
return {
|
|
115
|
-
content: [{ type: "text", text: lines.join("\n") }],
|
|
116
|
-
details: { op: "list", from: selfId, peers },
|
|
117
|
-
};
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
function executeSend(
|
|
121
|
-
selfId: string,
|
|
122
|
-
params: IrcParams,
|
|
123
|
-
): { content: Array<{ type: "text"; text: string }>; details: IrcDetails } {
|
|
124
|
-
const to = params.to?.trim();
|
|
125
|
-
const message = params.message?.trim();
|
|
126
|
-
|
|
127
|
-
if (!to) {
|
|
128
|
-
return {
|
|
129
|
-
content: [{ type: "text", text: '`to` is required for op="send".' }],
|
|
130
|
-
details: { op: "send", from: selfId, error: "Missing 'to' field." },
|
|
131
|
-
};
|
|
132
|
-
}
|
|
133
|
-
if (!message) {
|
|
134
|
-
return {
|
|
135
|
-
content: [{ type: "text", text: '`message` is required for op="send".' }],
|
|
136
|
-
details: { op: "send", from: selfId, to, error: "Missing 'message' field." },
|
|
137
|
-
};
|
|
138
|
-
}
|
|
139
|
-
if (to === selfId) {
|
|
140
|
-
return {
|
|
141
|
-
content: [{ type: "text", text: "Cannot send a message to yourself." }],
|
|
142
|
-
details: { op: "send", from: selfId, to, error: "Self-message not allowed." },
|
|
143
|
-
};
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
const ircMessage: IrcMessage = {
|
|
147
|
-
from: selfId,
|
|
148
|
-
to,
|
|
149
|
-
content: message,
|
|
150
|
-
timestamp: new Date().toISOString(),
|
|
151
|
-
awaitReply: params.awaitReply,
|
|
152
|
-
};
|
|
153
|
-
|
|
154
|
-
const notFound: string[] = [];
|
|
155
|
-
const delivered: string[] = [];
|
|
156
|
-
|
|
157
|
-
try {
|
|
158
|
-
if (to === "all") {
|
|
159
|
-
const recipients = broadcastIrcMessage(selfId, ircMessage);
|
|
160
|
-
delivered.push(...recipients);
|
|
161
|
-
} else {
|
|
162
|
-
// DM to specific agent
|
|
163
|
-
const agents = listLiveAgents();
|
|
164
|
-
const target = agents.find((a) => a.agentId === to);
|
|
165
|
-
if (!target || (target.status !== "running" && target.status !== "queued")) {
|
|
166
|
-
notFound.push(to);
|
|
167
|
-
} else {
|
|
168
|
-
try {
|
|
169
|
-
sendIrcMessage(to, ircMessage);
|
|
170
|
-
delivered.push(to);
|
|
171
|
-
} catch {
|
|
172
|
-
notFound.push(to);
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
} catch {
|
|
177
|
-
// Agent deregistered during routing — treat as not found
|
|
178
|
-
notFound.push(to);
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
const lines: string[] = [];
|
|
182
|
-
if (delivered.length > 0) {
|
|
183
|
-
lines.push(`Delivered to ${delivered.length} peer(s): ${delivered.join(", ")}`);
|
|
184
|
-
} else {
|
|
185
|
-
lines.push("No recipients received the message.");
|
|
186
|
-
}
|
|
187
|
-
if (notFound.length > 0) {
|
|
188
|
-
lines.push(`Unknown / unavailable peers: ${notFound.join(", ")}`);
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
return {
|
|
192
|
-
content: [{ type: "text", text: lines.join("\n") }],
|
|
193
|
-
details: {
|
|
194
|
-
op: "send",
|
|
195
|
-
from: selfId,
|
|
196
|
-
to,
|
|
197
|
-
delivered: delivered.length > 0 ? delivered : undefined,
|
|
198
|
-
notFound: notFound.length > 0 ? notFound : undefined,
|
|
199
|
-
},
|
|
200
|
-
};
|
|
201
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* G1: Custom tool — irc.
|
|
3
|
+
*
|
|
4
|
+
* Registers a real `irc` tool in the Pi SDK session so that
|
|
5
|
+
* live-session workers can send messages to other live agents.
|
|
6
|
+
*
|
|
7
|
+
* Operations:
|
|
8
|
+
* - `list`: List currently visible peer agents
|
|
9
|
+
* - `send`: Send a message to a specific agent or broadcast to all
|
|
10
|
+
*
|
|
11
|
+
* Adapted from oh-my-pi's `IrcTool` pattern. Uses the live-agent-manager
|
|
12
|
+
* for routing messages between in-process workers.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { defineTool, type ToolDefinition } from "@mariozechner/pi-coding-agent";
|
|
16
|
+
import { Type, type Static } from "@sinclair/typebox";
|
|
17
|
+
import { listLiveAgents, sendIrcMessage, broadcastIrcMessage } from "../live-agent-manager.ts";
|
|
18
|
+
import type { IrcMessage } from "../live-irc.ts";
|
|
19
|
+
|
|
20
|
+
const IrcParams = Type.Object({
|
|
21
|
+
op: Type.Union(
|
|
22
|
+
[
|
|
23
|
+
Type.Literal("send", { description: "Send a message to one peer or to all peers." }),
|
|
24
|
+
Type.Literal("list", { description: "List currently visible peers." }),
|
|
25
|
+
],
|
|
26
|
+
{ description: "IRC operation." },
|
|
27
|
+
),
|
|
28
|
+
to: Type.Optional(
|
|
29
|
+
Type.String({
|
|
30
|
+
description: 'Recipient agent ID or "all" to broadcast.',
|
|
31
|
+
}),
|
|
32
|
+
),
|
|
33
|
+
message: Type.Optional(
|
|
34
|
+
Type.String({
|
|
35
|
+
description: "Message body to deliver.",
|
|
36
|
+
}),
|
|
37
|
+
),
|
|
38
|
+
awaitReply: Type.Optional(
|
|
39
|
+
Type.Boolean({
|
|
40
|
+
description: "Wait for a reply (default: true for DM, false for broadcast). Not yet supported — messages are fire-and-forget.",
|
|
41
|
+
}),
|
|
42
|
+
),
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
type IrcParams = Static<typeof IrcParams>;
|
|
46
|
+
|
|
47
|
+
interface IrcDetails {
|
|
48
|
+
op: "send" | "list";
|
|
49
|
+
from?: string;
|
|
50
|
+
to?: string;
|
|
51
|
+
delivered?: string[];
|
|
52
|
+
notFound?: string[];
|
|
53
|
+
peers?: Array<{ id: string; status: string }>;
|
|
54
|
+
error?: string;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Create an `irc` tool definition for a specific agent.
|
|
59
|
+
*
|
|
60
|
+
* @param selfId — This agent's ID (runId:taskId format)
|
|
61
|
+
*/
|
|
62
|
+
export function createIrcTool(
|
|
63
|
+
selfId: string,
|
|
64
|
+
): ToolDefinition<typeof IrcParams, IrcDetails> {
|
|
65
|
+
return defineTool({
|
|
66
|
+
name: "irc",
|
|
67
|
+
label: "IRC",
|
|
68
|
+
description:
|
|
69
|
+
"Send messages to other live agents in same team. " +
|
|
70
|
+
'Use `op: "list"` to see peers, `op: "send"` with `to` (agent ID or "all") and `message` to communicate.',
|
|
71
|
+
parameters: IrcParams,
|
|
72
|
+
promptSnippet: "Send messages to other live agents via the irc tool",
|
|
73
|
+
promptGuidelines: [
|
|
74
|
+
"Use irc to coordinate with other agents when you need information or want to share findings.",
|
|
75
|
+
'Use `op: "list"` first to discover available peers.',
|
|
76
|
+
],
|
|
77
|
+
async execute(
|
|
78
|
+
_toolCallId: string,
|
|
79
|
+
params: IrcParams,
|
|
80
|
+
_signal: AbortSignal | undefined,
|
|
81
|
+
_onUpdate: unknown,
|
|
82
|
+
_ctx: unknown,
|
|
83
|
+
): Promise<{ content: Array<{ type: "text"; text: string }>; details: IrcDetails }> {
|
|
84
|
+
if (params.op === "list") {
|
|
85
|
+
return executeList(selfId);
|
|
86
|
+
}
|
|
87
|
+
if (params.op === "send") {
|
|
88
|
+
return executeSend(selfId, params);
|
|
89
|
+
}
|
|
90
|
+
return {
|
|
91
|
+
content: [{ type: "text", text: "Unknown irc op." }],
|
|
92
|
+
details: { op: params.op, from: selfId, error: "Unknown operation." },
|
|
93
|
+
};
|
|
94
|
+
},
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function executeList(selfId: string): { content: Array<{ type: "text"; text: string }>; details: IrcDetails } {
|
|
99
|
+
const agents = listLiveAgents();
|
|
100
|
+
const peers = agents
|
|
101
|
+
.filter((a) => a.agentId !== selfId && (a.status === "running" || a.status === "queued"))
|
|
102
|
+
.map((a) => ({ id: a.agentId, status: a.status }));
|
|
103
|
+
|
|
104
|
+
const lines: string[] = [];
|
|
105
|
+
if (peers.length === 0) {
|
|
106
|
+
lines.push("No other live agents.");
|
|
107
|
+
} else {
|
|
108
|
+
lines.push(`${peers.length} peer(s):`);
|
|
109
|
+
for (const peer of peers) {
|
|
110
|
+
lines.push(`- ${peer.id} (${peer.status})`);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return {
|
|
115
|
+
content: [{ type: "text", text: lines.join("\n") }],
|
|
116
|
+
details: { op: "list", from: selfId, peers },
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function executeSend(
|
|
121
|
+
selfId: string,
|
|
122
|
+
params: IrcParams,
|
|
123
|
+
): { content: Array<{ type: "text"; text: string }>; details: IrcDetails } {
|
|
124
|
+
const to = params.to?.trim();
|
|
125
|
+
const message = params.message?.trim();
|
|
126
|
+
|
|
127
|
+
if (!to) {
|
|
128
|
+
return {
|
|
129
|
+
content: [{ type: "text", text: '`to` is required for op="send".' }],
|
|
130
|
+
details: { op: "send", from: selfId, error: "Missing 'to' field." },
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
if (!message) {
|
|
134
|
+
return {
|
|
135
|
+
content: [{ type: "text", text: '`message` is required for op="send".' }],
|
|
136
|
+
details: { op: "send", from: selfId, to, error: "Missing 'message' field." },
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
if (to === selfId) {
|
|
140
|
+
return {
|
|
141
|
+
content: [{ type: "text", text: "Cannot send a message to yourself." }],
|
|
142
|
+
details: { op: "send", from: selfId, to, error: "Self-message not allowed." },
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
const ircMessage: IrcMessage = {
|
|
147
|
+
from: selfId,
|
|
148
|
+
to,
|
|
149
|
+
content: message,
|
|
150
|
+
timestamp: new Date().toISOString(),
|
|
151
|
+
awaitReply: params.awaitReply,
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
const notFound: string[] = [];
|
|
155
|
+
const delivered: string[] = [];
|
|
156
|
+
|
|
157
|
+
try {
|
|
158
|
+
if (to === "all") {
|
|
159
|
+
const recipients = broadcastIrcMessage(selfId, ircMessage);
|
|
160
|
+
delivered.push(...recipients);
|
|
161
|
+
} else {
|
|
162
|
+
// DM to specific agent
|
|
163
|
+
const agents = listLiveAgents();
|
|
164
|
+
const target = agents.find((a) => a.agentId === to);
|
|
165
|
+
if (!target || (target.status !== "running" && target.status !== "queued")) {
|
|
166
|
+
notFound.push(to);
|
|
167
|
+
} else {
|
|
168
|
+
try {
|
|
169
|
+
sendIrcMessage(to, ircMessage);
|
|
170
|
+
delivered.push(to);
|
|
171
|
+
} catch {
|
|
172
|
+
notFound.push(to);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
} catch {
|
|
177
|
+
// Agent deregistered during routing — treat as not found
|
|
178
|
+
notFound.push(to);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
const lines: string[] = [];
|
|
182
|
+
if (delivered.length > 0) {
|
|
183
|
+
lines.push(`Delivered to ${delivered.length} peer(s): ${delivered.join(", ")}`);
|
|
184
|
+
} else {
|
|
185
|
+
lines.push("No recipients received the message.");
|
|
186
|
+
}
|
|
187
|
+
if (notFound.length > 0) {
|
|
188
|
+
lines.push(`Unknown / unavailable peers: ${notFound.join(", ")}`);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
return {
|
|
192
|
+
content: [{ type: "text", text: lines.join("\n") }],
|
|
193
|
+
details: {
|
|
194
|
+
op: "send",
|
|
195
|
+
from: selfId,
|
|
196
|
+
to,
|
|
197
|
+
delivered: delivered.length > 0 ? delivered : undefined,
|
|
198
|
+
notFound: notFound.length > 0 ? notFound : undefined,
|
|
199
|
+
},
|
|
200
|
+
};
|
|
201
|
+
}
|