pi-crew 0.2.3 → 0.2.4
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,104 +1,104 @@
|
|
|
1
|
-
import type { ExtensionContext } from "@mariozechner/pi-coding-agent";
|
|
2
|
-
import type { TeamToolParamsValue } from "../schema/team-tool-schema.ts";
|
|
3
|
-
// Lazy-loaded to avoid pulling team-tool.ts (and its entire runtime chain) into module load.
|
|
4
|
-
import type { handleTeamTool as HandleTeamToolFn } from "./team-tool.ts";
|
|
5
|
-
let _cachedHandleTeamTool: typeof HandleTeamToolFn | undefined;
|
|
6
|
-
async function handleTeamTool(params: Parameters<typeof HandleTeamToolFn>[0], ctx: Parameters<typeof HandleTeamToolFn>[1]): Promise<Awaited<ReturnType<typeof HandleTeamToolFn>>> {
|
|
7
|
-
if (!_cachedHandleTeamTool) {
|
|
8
|
-
// LAZY: avoid pulling team-tool.ts (and its entire runtime chain) into module load.
|
|
9
|
-
const mod = await import("./team-tool.ts");
|
|
10
|
-
_cachedHandleTeamTool = mod.handleTeamTool;
|
|
11
|
-
}
|
|
12
|
-
return _cachedHandleTeamTool(params, ctx);
|
|
13
|
-
}
|
|
14
|
-
import { parseLiveControlRealtimeMessage, publishLiveControlRealtime } from "../runtime/live-control-realtime.ts";
|
|
15
|
-
|
|
16
|
-
export interface EventBusLike {
|
|
17
|
-
on(event: string, handler: (data: unknown) => void): (() => void) | void;
|
|
18
|
-
emit(event: string, data: unknown): void;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export type RpcReply<T = unknown> = { success: true; data?: T } | { success: false; error: string };
|
|
22
|
-
export const PI_CREW_RPC_VERSION = 1;
|
|
23
|
-
|
|
24
|
-
export interface PiCrewRpcHandle {
|
|
25
|
-
unsubscribe(): void;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
function requestId(raw: unknown): string | undefined {
|
|
29
|
-
return raw && typeof raw === "object" && !Array.isArray(raw) && typeof (raw as { requestId?: unknown }).requestId === "string" ? (raw as { requestId: string }).requestId : undefined;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
function reply(events: EventBusLike, channel: string, id: string | undefined, payload: RpcReply): void {
|
|
33
|
-
if (!id) return;
|
|
34
|
-
events.emit(`${channel}:reply:${id}`, payload);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
function textOf(result: Awaited<ReturnType<typeof handleTeamTool>>): string {
|
|
38
|
-
return result.content?.map((item) => item.type === "text" ? item.text : "").join("\n") ?? "";
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
function on(events: EventBusLike, channel: string, handler: (raw: unknown) => void): () => void {
|
|
42
|
-
const unsub = events.on(channel, handler);
|
|
43
|
-
return typeof unsub === "function" ? unsub : () => {};
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export function registerPiCrewRpc(events: EventBusLike | undefined, getCtx: () => ExtensionContext | undefined): PiCrewRpcHandle | undefined {
|
|
47
|
-
if (!events) return undefined;
|
|
48
|
-
const unsubs = [
|
|
49
|
-
on(events, "pi-crew:rpc:ping", (raw) => reply(events, "pi-crew:rpc:ping", requestId(raw), { success: true, data: { version: PI_CREW_RPC_VERSION } })),
|
|
50
|
-
on(events, "pi-crew:rpc:run", async (raw) => {
|
|
51
|
-
const id = requestId(raw);
|
|
52
|
-
try {
|
|
53
|
-
const ctx = getCtx();
|
|
54
|
-
if (!ctx) throw new Error("No active pi-crew session context.");
|
|
55
|
-
// Validate payload: only allow known fields from TeamToolParamsValue
|
|
56
|
-
const ALLOWED_RPC_RUN_KEYS = new Set(["goal", "team", "workflow", "async", "cwd", "config", "skill", "model"]);
|
|
57
|
-
let params: TeamToolParamsValue;
|
|
58
|
-
if (raw && typeof raw === "object" && !Array.isArray(raw)) {
|
|
59
|
-
const filtered: Record<string, unknown> = { ...(raw as object) };
|
|
60
|
-
// Strip any keys not in the allowlist to prevent injection of unexpected fields
|
|
61
|
-
for (const key of Object.keys(filtered)) {
|
|
62
|
-
if (!ALLOWED_RPC_RUN_KEYS.has(key)) delete filtered[key];
|
|
63
|
-
}
|
|
64
|
-
params = { ...filtered, action: "run" } as TeamToolParamsValue;
|
|
65
|
-
} else {
|
|
66
|
-
params = { action: "run" };
|
|
67
|
-
}
|
|
68
|
-
const result = await handleTeamTool(params, ctx);
|
|
69
|
-
reply(events, "pi-crew:rpc:run", id, result.isError ? { success: false, error: textOf(result) } : { success: true, data: result.details });
|
|
70
|
-
} catch (error) {
|
|
71
|
-
reply(events, "pi-crew:rpc:run", id, { success: false, error: error instanceof Error ? error.message : String(error) });
|
|
72
|
-
}
|
|
73
|
-
}),
|
|
74
|
-
on(events, "pi-crew:rpc:status", async (raw) => {
|
|
75
|
-
const id = requestId(raw);
|
|
76
|
-
try {
|
|
77
|
-
const ctx = getCtx();
|
|
78
|
-
if (!ctx) throw new Error("No active pi-crew session context.");
|
|
79
|
-
const runId = raw && typeof raw === "object" && !Array.isArray(raw) ? (raw as { runId?: string }).runId : undefined;
|
|
80
|
-
const result = await handleTeamTool({ action: "status", runId }, ctx);
|
|
81
|
-
reply(events, "pi-crew:rpc:status", id, result.isError ? { success: false, error: textOf(result) } : { success: true, data: { text: textOf(result), details: result.details } });
|
|
82
|
-
} catch (error) {
|
|
83
|
-
reply(events, "pi-crew:rpc:status", id, { success: false, error: error instanceof Error ? error.message : String(error) });
|
|
84
|
-
}
|
|
85
|
-
}),
|
|
86
|
-
on(events, "pi-crew:live-control", (raw) => {
|
|
87
|
-
const request = parseLiveControlRealtimeMessage(raw);
|
|
88
|
-
if (request) publishLiveControlRealtime(request);
|
|
89
|
-
}),
|
|
90
|
-
on(events, "pi-crew:rpc:live-control", async (raw) => {
|
|
91
|
-
const id = requestId(raw);
|
|
92
|
-
try {
|
|
93
|
-
const ctx = getCtx();
|
|
94
|
-
if (!ctx) throw new Error("No active pi-crew session context.");
|
|
95
|
-
const obj = raw && typeof raw === "object" && !Array.isArray(raw) ? raw as Record<string, unknown> : {};
|
|
96
|
-
const result = await handleTeamTool({ action: "api", runId: typeof obj.runId === "string" ? obj.runId : undefined, config: { operation: typeof obj.operation === "string" ? obj.operation : "steer-agent", agentId: obj.agentId, message: obj.message, prompt: obj.prompt } }, ctx);
|
|
97
|
-
reply(events, "pi-crew:rpc:live-control", id, result.isError ? { success: false, error: textOf(result) } : { success: true, data: { text: textOf(result), details: result.details } });
|
|
98
|
-
} catch (error) {
|
|
99
|
-
reply(events, "pi-crew:rpc:live-control", id, { success: false, error: error instanceof Error ? error.message : String(error) });
|
|
100
|
-
}
|
|
101
|
-
}),
|
|
102
|
-
];
|
|
103
|
-
return { unsubscribe: () => unsubs.forEach((unsub) => unsub()) };
|
|
104
|
-
}
|
|
1
|
+
import type { ExtensionContext } from "@mariozechner/pi-coding-agent";
|
|
2
|
+
import type { TeamToolParamsValue } from "../schema/team-tool-schema.ts";
|
|
3
|
+
// Lazy-loaded to avoid pulling team-tool.ts (and its entire runtime chain) into module load.
|
|
4
|
+
import type { handleTeamTool as HandleTeamToolFn } from "./team-tool.ts";
|
|
5
|
+
let _cachedHandleTeamTool: typeof HandleTeamToolFn | undefined;
|
|
6
|
+
async function handleTeamTool(params: Parameters<typeof HandleTeamToolFn>[0], ctx: Parameters<typeof HandleTeamToolFn>[1]): Promise<Awaited<ReturnType<typeof HandleTeamToolFn>>> {
|
|
7
|
+
if (!_cachedHandleTeamTool) {
|
|
8
|
+
// LAZY: avoid pulling team-tool.ts (and its entire runtime chain) into module load.
|
|
9
|
+
const mod = await import("./team-tool.ts");
|
|
10
|
+
_cachedHandleTeamTool = mod.handleTeamTool;
|
|
11
|
+
}
|
|
12
|
+
return _cachedHandleTeamTool(params, ctx);
|
|
13
|
+
}
|
|
14
|
+
import { parseLiveControlRealtimeMessage, publishLiveControlRealtime } from "../runtime/live-control-realtime.ts";
|
|
15
|
+
|
|
16
|
+
export interface EventBusLike {
|
|
17
|
+
on(event: string, handler: (data: unknown) => void): (() => void) | void;
|
|
18
|
+
emit(event: string, data: unknown): void;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export type RpcReply<T = unknown> = { success: true; data?: T } | { success: false; error: string };
|
|
22
|
+
export const PI_CREW_RPC_VERSION = 1;
|
|
23
|
+
|
|
24
|
+
export interface PiCrewRpcHandle {
|
|
25
|
+
unsubscribe(): void;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function requestId(raw: unknown): string | undefined {
|
|
29
|
+
return raw && typeof raw === "object" && !Array.isArray(raw) && typeof (raw as { requestId?: unknown }).requestId === "string" ? (raw as { requestId: string }).requestId : undefined;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function reply(events: EventBusLike, channel: string, id: string | undefined, payload: RpcReply): void {
|
|
33
|
+
if (!id) return;
|
|
34
|
+
events.emit(`${channel}:reply:${id}`, payload);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function textOf(result: Awaited<ReturnType<typeof handleTeamTool>>): string {
|
|
38
|
+
return result.content?.map((item) => item.type === "text" ? item.text : "").join("\n") ?? "";
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function on(events: EventBusLike, channel: string, handler: (raw: unknown) => void): () => void {
|
|
42
|
+
const unsub = events.on(channel, handler);
|
|
43
|
+
return typeof unsub === "function" ? unsub : () => {};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function registerPiCrewRpc(events: EventBusLike | undefined, getCtx: () => ExtensionContext | undefined): PiCrewRpcHandle | undefined {
|
|
47
|
+
if (!events) return undefined;
|
|
48
|
+
const unsubs = [
|
|
49
|
+
on(events, "pi-crew:rpc:ping", (raw) => reply(events, "pi-crew:rpc:ping", requestId(raw), { success: true, data: { version: PI_CREW_RPC_VERSION } })),
|
|
50
|
+
on(events, "pi-crew:rpc:run", async (raw) => {
|
|
51
|
+
const id = requestId(raw);
|
|
52
|
+
try {
|
|
53
|
+
const ctx = getCtx();
|
|
54
|
+
if (!ctx) throw new Error("No active pi-crew session context.");
|
|
55
|
+
// Validate payload: only allow known fields from TeamToolParamsValue
|
|
56
|
+
const ALLOWED_RPC_RUN_KEYS = new Set(["goal", "team", "workflow", "async", "cwd", "config", "skill", "model"]);
|
|
57
|
+
let params: TeamToolParamsValue;
|
|
58
|
+
if (raw && typeof raw === "object" && !Array.isArray(raw)) {
|
|
59
|
+
const filtered: Record<string, unknown> = { ...(raw as object) };
|
|
60
|
+
// Strip any keys not in the allowlist to prevent injection of unexpected fields
|
|
61
|
+
for (const key of Object.keys(filtered)) {
|
|
62
|
+
if (!ALLOWED_RPC_RUN_KEYS.has(key)) delete filtered[key];
|
|
63
|
+
}
|
|
64
|
+
params = { ...filtered, action: "run" } as TeamToolParamsValue;
|
|
65
|
+
} else {
|
|
66
|
+
params = { action: "run" };
|
|
67
|
+
}
|
|
68
|
+
const result = await handleTeamTool(params, ctx);
|
|
69
|
+
reply(events, "pi-crew:rpc:run", id, result.isError ? { success: false, error: textOf(result) } : { success: true, data: result.details });
|
|
70
|
+
} catch (error) {
|
|
71
|
+
reply(events, "pi-crew:rpc:run", id, { success: false, error: error instanceof Error ? error.message : String(error) });
|
|
72
|
+
}
|
|
73
|
+
}),
|
|
74
|
+
on(events, "pi-crew:rpc:status", async (raw) => {
|
|
75
|
+
const id = requestId(raw);
|
|
76
|
+
try {
|
|
77
|
+
const ctx = getCtx();
|
|
78
|
+
if (!ctx) throw new Error("No active pi-crew session context.");
|
|
79
|
+
const runId = raw && typeof raw === "object" && !Array.isArray(raw) ? (raw as { runId?: string }).runId : undefined;
|
|
80
|
+
const result = await handleTeamTool({ action: "status", runId }, ctx);
|
|
81
|
+
reply(events, "pi-crew:rpc:status", id, result.isError ? { success: false, error: textOf(result) } : { success: true, data: { text: textOf(result), details: result.details } });
|
|
82
|
+
} catch (error) {
|
|
83
|
+
reply(events, "pi-crew:rpc:status", id, { success: false, error: error instanceof Error ? error.message : String(error) });
|
|
84
|
+
}
|
|
85
|
+
}),
|
|
86
|
+
on(events, "pi-crew:live-control", (raw) => {
|
|
87
|
+
const request = parseLiveControlRealtimeMessage(raw);
|
|
88
|
+
if (request) publishLiveControlRealtime(request);
|
|
89
|
+
}),
|
|
90
|
+
on(events, "pi-crew:rpc:live-control", async (raw) => {
|
|
91
|
+
const id = requestId(raw);
|
|
92
|
+
try {
|
|
93
|
+
const ctx = getCtx();
|
|
94
|
+
if (!ctx) throw new Error("No active pi-crew session context.");
|
|
95
|
+
const obj = raw && typeof raw === "object" && !Array.isArray(raw) ? raw as Record<string, unknown> : {};
|
|
96
|
+
const result = await handleTeamTool({ action: "api", runId: typeof obj.runId === "string" ? obj.runId : undefined, config: { operation: typeof obj.operation === "string" ? obj.operation : "steer-agent", agentId: obj.agentId, message: obj.message, prompt: obj.prompt } }, ctx);
|
|
97
|
+
reply(events, "pi-crew:rpc:live-control", id, result.isError ? { success: false, error: textOf(result) } : { success: true, data: { text: textOf(result), details: result.details } });
|
|
98
|
+
} catch (error) {
|
|
99
|
+
reply(events, "pi-crew:rpc:live-control", id, { success: false, error: error instanceof Error ? error.message : String(error) });
|
|
100
|
+
}
|
|
101
|
+
}),
|
|
102
|
+
];
|
|
103
|
+
return { unsubscribe: () => unsubs.forEach((unsub) => unsub()) };
|
|
104
|
+
}
|
package/src/extension/help.ts
CHANGED
|
@@ -1,47 +1,47 @@
|
|
|
1
|
-
export function piTeamsHelp(): string {
|
|
2
|
-
return [
|
|
3
|
-
"pi-crew commands:",
|
|
4
|
-
"",
|
|
5
|
-
"Core:",
|
|
6
|
-
"- Agent can use the `team` tool autonomously; slash commands are manual controls.",
|
|
7
|
-
"- Tool action `recommend` suggests the best team/workflow for a goal.",
|
|
8
|
-
"- /teams — list teams, workflows, agents, recent runs",
|
|
9
|
-
"- /team-run [--team=name] [--workflow=name] [--async] [--worktree] <goal>",
|
|
10
|
-
"- /team-status <runId>",
|
|
11
|
-
"- /team-summary <runId>",
|
|
12
|
-
"- /team-resume <runId>",
|
|
13
|
-
"- /team-cancel <runId>",
|
|
14
|
-
"- /team-retry <runId> [taskId]",
|
|
15
|
-
"",
|
|
16
|
-
"Inspection:",
|
|
17
|
-
"- /team-events <runId>",
|
|
18
|
-
"- /team-artifacts <runId>",
|
|
19
|
-
"- /team-worktrees <runId>",
|
|
20
|
-
"- /team-api <runId> <operation> [taskId=<taskId>] [body=<message>]",
|
|
21
|
-
"- /team-dashboard",
|
|
22
|
-
"- /team-mascot",
|
|
23
|
-
"- /team-transcript <runId> [taskId]",
|
|
24
|
-
"- /team-result <runId> [taskId]",
|
|
25
|
-
"- /team-manager",
|
|
26
|
-
"",
|
|
27
|
-
"Maintenance:",
|
|
28
|
-
"- /team-cleanup <runId> [--force]",
|
|
29
|
-
"- /team-forget <runId> --confirm [--force]",
|
|
30
|
-
"- /team-prune --keep=20 --confirm",
|
|
31
|
-
"",
|
|
32
|
-
"Portability:",
|
|
33
|
-
"- /team-export <runId>",
|
|
34
|
-
"- /team-import <path-to-run-export.json> [--user]",
|
|
35
|
-
"- /team-imports",
|
|
36
|
-
"",
|
|
37
|
-
"Diagnostics:",
|
|
38
|
-
"- /team-doctor",
|
|
39
|
-
"- /team-init [--copy-builtins] [--overwrite]",
|
|
40
|
-
"- /team-config [key=value] [--unset=key.path] [--project]",
|
|
41
|
-
"- /team-autonomy [status|on|off|manual|suggested|assisted|aggressive] [--prefer-async] [--no-worktree-suggest]",
|
|
42
|
-
"- /team-validate",
|
|
43
|
-
"- /team-help",
|
|
44
|
-
"",
|
|
45
|
-
"Real child workers are enabled by default. Use runtime.mode=scaffold or executeWorkers=false only for dry runs.",
|
|
46
|
-
].join("\n");
|
|
47
|
-
}
|
|
1
|
+
export function piTeamsHelp(): string {
|
|
2
|
+
return [
|
|
3
|
+
"pi-crew commands:",
|
|
4
|
+
"",
|
|
5
|
+
"Core:",
|
|
6
|
+
"- Agent can use the `team` tool autonomously; slash commands are manual controls.",
|
|
7
|
+
"- Tool action `recommend` suggests the best team/workflow for a goal.",
|
|
8
|
+
"- /teams — list teams, workflows, agents, recent runs",
|
|
9
|
+
"- /team-run [--team=name] [--workflow=name] [--async] [--worktree] <goal>",
|
|
10
|
+
"- /team-status <runId>",
|
|
11
|
+
"- /team-summary <runId>",
|
|
12
|
+
"- /team-resume <runId>",
|
|
13
|
+
"- /team-cancel <runId>",
|
|
14
|
+
"- /team-retry <runId> [taskId]",
|
|
15
|
+
"",
|
|
16
|
+
"Inspection:",
|
|
17
|
+
"- /team-events <runId>",
|
|
18
|
+
"- /team-artifacts <runId>",
|
|
19
|
+
"- /team-worktrees <runId>",
|
|
20
|
+
"- /team-api <runId> <operation> [taskId=<taskId>] [body=<message>]",
|
|
21
|
+
"- /team-dashboard",
|
|
22
|
+
"- /team-mascot",
|
|
23
|
+
"- /team-transcript <runId> [taskId]",
|
|
24
|
+
"- /team-result <runId> [taskId]",
|
|
25
|
+
"- /team-manager",
|
|
26
|
+
"",
|
|
27
|
+
"Maintenance:",
|
|
28
|
+
"- /team-cleanup <runId> [--force]",
|
|
29
|
+
"- /team-forget <runId> --confirm [--force]",
|
|
30
|
+
"- /team-prune --keep=20 --confirm",
|
|
31
|
+
"",
|
|
32
|
+
"Portability:",
|
|
33
|
+
"- /team-export <runId>",
|
|
34
|
+
"- /team-import <path-to-run-export.json> [--user]",
|
|
35
|
+
"- /team-imports",
|
|
36
|
+
"",
|
|
37
|
+
"Diagnostics:",
|
|
38
|
+
"- /team-doctor",
|
|
39
|
+
"- /team-init [--copy-builtins] [--overwrite]",
|
|
40
|
+
"- /team-config [key=value] [--unset=key.path] [--project]",
|
|
41
|
+
"- /team-autonomy [status|on|off|manual|suggested|assisted|aggressive] [--prefer-async] [--no-worktree-suggest]",
|
|
42
|
+
"- /team-validate",
|
|
43
|
+
"- /team-help",
|
|
44
|
+
"",
|
|
45
|
+
"Real child workers are enabled by default. Use runtime.mode=scaffold or executeWorkers=false only for dry runs.",
|
|
46
|
+
].join("\n");
|
|
47
|
+
}
|
|
@@ -1,69 +1,69 @@
|
|
|
1
|
-
import * as fs from "node:fs";
|
|
2
|
-
import * as path from "node:path";
|
|
3
|
-
import { projectCrewRoot, userCrewRoot } from "../utils/paths.ts";
|
|
4
|
-
import { DEFAULT_PATHS } from "../config/defaults.ts";
|
|
5
|
-
import { isSafePathId, resolveRealContainedPath } from "../utils/safe-paths.ts";
|
|
6
|
-
|
|
7
|
-
export interface ImportedRunIndexEntry {
|
|
8
|
-
runId: string;
|
|
9
|
-
scope: "project" | "user";
|
|
10
|
-
bundlePath: string;
|
|
11
|
-
summaryPath: string;
|
|
12
|
-
importedAt?: string;
|
|
13
|
-
status?: string;
|
|
14
|
-
team?: string;
|
|
15
|
-
workflow?: string;
|
|
16
|
-
goal?: string;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
function readEntry(root: string, scope: "project" | "user", runId: string): ImportedRunIndexEntry | undefined {
|
|
20
|
-
if (!isSafePathId(runId)) return undefined;
|
|
21
|
-
let bundlePath: string;
|
|
22
|
-
let summaryPath: string;
|
|
23
|
-
try {
|
|
24
|
-
const entryRoot = resolveRealContainedPath(root, runId);
|
|
25
|
-
bundlePath = resolveRealContainedPath(root, path.join(runId, "run-export.json"));
|
|
26
|
-
summaryPath = path.join(entryRoot, "README.md");
|
|
27
|
-
} catch {
|
|
28
|
-
return undefined;
|
|
29
|
-
}
|
|
30
|
-
if (!fs.existsSync(bundlePath)) return undefined;
|
|
31
|
-
try {
|
|
32
|
-
const raw = JSON.parse(fs.readFileSync(bundlePath, "utf-8")) as Record<string, unknown>;
|
|
33
|
-
const manifest = raw.manifest && typeof raw.manifest === "object" && !Array.isArray(raw.manifest) ? raw.manifest as Record<string, unknown> : {};
|
|
34
|
-
return {
|
|
35
|
-
runId,
|
|
36
|
-
scope,
|
|
37
|
-
bundlePath,
|
|
38
|
-
summaryPath,
|
|
39
|
-
importedAt: typeof raw.importedAt === "string" ? raw.importedAt : undefined,
|
|
40
|
-
status: typeof manifest.status === "string" ? manifest.status : undefined,
|
|
41
|
-
team: typeof manifest.team === "string" ? manifest.team : undefined,
|
|
42
|
-
workflow: typeof manifest.workflow === "string" ? manifest.workflow : undefined,
|
|
43
|
-
goal: typeof manifest.goal === "string" ? manifest.goal : undefined,
|
|
44
|
-
};
|
|
45
|
-
} catch {
|
|
46
|
-
return { runId, scope, bundlePath, summaryPath };
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
function collect(root: string, scope: "project" | "user"): ImportedRunIndexEntry[] {
|
|
51
|
-
if (!fs.existsSync(root)) return [];
|
|
52
|
-
try {
|
|
53
|
-
if (fs.lstatSync(root).isSymbolicLink()) return [];
|
|
54
|
-
resolveRealContainedPath(path.dirname(root), path.basename(root));
|
|
55
|
-
} catch {
|
|
56
|
-
return [];
|
|
57
|
-
}
|
|
58
|
-
return fs.readdirSync(root)
|
|
59
|
-
.filter((entry) => isSafePathId(entry))
|
|
60
|
-
.map((entry) => readEntry(root, scope, entry))
|
|
61
|
-
.filter((entry): entry is ImportedRunIndexEntry => entry !== undefined);
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
export function listImportedRuns(cwd: string): ImportedRunIndexEntry[] {
|
|
65
|
-
const projectRoot = path.join(projectCrewRoot(cwd), DEFAULT_PATHS.state.importsSubdir);
|
|
66
|
-
const userRoot = path.join(userCrewRoot(), DEFAULT_PATHS.state.importsSubdir);
|
|
67
|
-
return [...collect(userRoot, "user"), ...collect(projectRoot, "project")]
|
|
68
|
-
.sort((a, b) => (b.importedAt ?? "").localeCompare(a.importedAt ?? ""));
|
|
69
|
-
}
|
|
1
|
+
import * as fs from "node:fs";
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
import { projectCrewRoot, userCrewRoot } from "../utils/paths.ts";
|
|
4
|
+
import { DEFAULT_PATHS } from "../config/defaults.ts";
|
|
5
|
+
import { isSafePathId, resolveRealContainedPath } from "../utils/safe-paths.ts";
|
|
6
|
+
|
|
7
|
+
export interface ImportedRunIndexEntry {
|
|
8
|
+
runId: string;
|
|
9
|
+
scope: "project" | "user";
|
|
10
|
+
bundlePath: string;
|
|
11
|
+
summaryPath: string;
|
|
12
|
+
importedAt?: string;
|
|
13
|
+
status?: string;
|
|
14
|
+
team?: string;
|
|
15
|
+
workflow?: string;
|
|
16
|
+
goal?: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function readEntry(root: string, scope: "project" | "user", runId: string): ImportedRunIndexEntry | undefined {
|
|
20
|
+
if (!isSafePathId(runId)) return undefined;
|
|
21
|
+
let bundlePath: string;
|
|
22
|
+
let summaryPath: string;
|
|
23
|
+
try {
|
|
24
|
+
const entryRoot = resolveRealContainedPath(root, runId);
|
|
25
|
+
bundlePath = resolveRealContainedPath(root, path.join(runId, "run-export.json"));
|
|
26
|
+
summaryPath = path.join(entryRoot, "README.md");
|
|
27
|
+
} catch {
|
|
28
|
+
return undefined;
|
|
29
|
+
}
|
|
30
|
+
if (!fs.existsSync(bundlePath)) return undefined;
|
|
31
|
+
try {
|
|
32
|
+
const raw = JSON.parse(fs.readFileSync(bundlePath, "utf-8")) as Record<string, unknown>;
|
|
33
|
+
const manifest = raw.manifest && typeof raw.manifest === "object" && !Array.isArray(raw.manifest) ? raw.manifest as Record<string, unknown> : {};
|
|
34
|
+
return {
|
|
35
|
+
runId,
|
|
36
|
+
scope,
|
|
37
|
+
bundlePath,
|
|
38
|
+
summaryPath,
|
|
39
|
+
importedAt: typeof raw.importedAt === "string" ? raw.importedAt : undefined,
|
|
40
|
+
status: typeof manifest.status === "string" ? manifest.status : undefined,
|
|
41
|
+
team: typeof manifest.team === "string" ? manifest.team : undefined,
|
|
42
|
+
workflow: typeof manifest.workflow === "string" ? manifest.workflow : undefined,
|
|
43
|
+
goal: typeof manifest.goal === "string" ? manifest.goal : undefined,
|
|
44
|
+
};
|
|
45
|
+
} catch {
|
|
46
|
+
return { runId, scope, bundlePath, summaryPath };
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function collect(root: string, scope: "project" | "user"): ImportedRunIndexEntry[] {
|
|
51
|
+
if (!fs.existsSync(root)) return [];
|
|
52
|
+
try {
|
|
53
|
+
if (fs.lstatSync(root).isSymbolicLink()) return [];
|
|
54
|
+
resolveRealContainedPath(path.dirname(root), path.basename(root));
|
|
55
|
+
} catch {
|
|
56
|
+
return [];
|
|
57
|
+
}
|
|
58
|
+
return fs.readdirSync(root)
|
|
59
|
+
.filter((entry) => isSafePathId(entry))
|
|
60
|
+
.map((entry) => readEntry(root, scope, entry))
|
|
61
|
+
.filter((entry): entry is ImportedRunIndexEntry => entry !== undefined);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export function listImportedRuns(cwd: string): ImportedRunIndexEntry[] {
|
|
65
|
+
const projectRoot = path.join(projectCrewRoot(cwd), DEFAULT_PATHS.state.importsSubdir);
|
|
66
|
+
const userRoot = path.join(userCrewRoot(), DEFAULT_PATHS.state.importsSubdir);
|
|
67
|
+
return [...collect(userRoot, "user"), ...collect(projectRoot, "project")]
|
|
68
|
+
.sort((a, b) => (b.importedAt ?? "").localeCompare(a.importedAt ?? ""));
|
|
69
|
+
}
|