pi-crew 0.9.55 → 0.9.57
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 +1 -1
- package/CHANGELOG.md +58 -0
- package/README.md +53 -5
- package/dist/index.mjs +5666 -4370
- package/docs/README.md +54 -0
- package/package.json +12 -13
- package/skills/real-test-pi-crew/SKILL.md +93 -3
- package/src/agents/discover-agents.ts +68 -10
- package/src/benchmark/feedback-loop.ts +1 -1
- package/src/config/config.ts +2 -1
- package/src/config/types.ts +12 -0
- package/src/extension/action-suggestions.ts +16 -63
- package/src/extension/async-notifier.ts +3 -3
- package/src/extension/command-completions.ts +2 -2
- package/src/extension/crew-cleanup.ts +3 -3
- package/src/extension/crew-vibes/footer.ts +4 -2
- package/src/extension/cross-extension-rpc.ts +10 -5
- package/src/extension/knowledge-injection.ts +57 -10
- package/src/extension/register.ts +2 -2
- package/src/extension/registration/artifact-cleanup.ts +41 -3
- package/src/extension/registration/commands.ts +4 -4
- package/src/extension/registration/context-builder.ts +10 -10
- package/src/extension/registration/crash-recovery-cache.ts +3 -3
- package/src/extension/registration/foreground-run-controller.ts +1 -1
- package/src/extension/registration/lazy-configurers.ts +2 -2
- package/src/extension/registration/lifecycle-handlers.ts +12 -12
- package/src/extension/registration/lifecycle.ts +2 -2
- package/src/extension/registration/observability.ts +2 -2
- package/src/extension/registration/registration-types.ts +3 -3
- package/src/extension/registration/runtime-cleanup.ts +1 -1
- package/src/extension/registration/subagent-helpers.ts +2 -2
- package/src/extension/registration/subagent-manager-setup.ts +2 -2
- package/src/extension/registration/subagent-tools.ts +21 -16
- package/src/extension/registration/team-tool.ts +109 -17
- package/src/extension/registration/viewers.ts +3 -4
- package/src/extension/registration/wire-cross-extension.ts +7 -7
- package/src/extension/rpc-hmac.ts +3 -2
- package/src/extension/run-bundle-schema.ts +13 -4
- package/src/extension/run-export.ts +2 -2
- package/src/extension/run-index.ts +2 -3
- package/src/extension/run-maintenance.ts +57 -1
- package/src/extension/team-manager-command.ts +3 -1
- package/src/extension/team-tool/anchor.ts +8 -2
- package/src/extension/team-tool/api.ts +117 -39
- package/src/extension/team-tool/cancel.ts +23 -8
- package/src/extension/team-tool/chain-executor.ts +1 -1
- package/src/extension/team-tool/dispatch/automate.ts +17 -2
- package/src/extension/team-tool/dispatch/control.ts +17 -2
- package/src/extension/team-tool/dispatch/manage.ts +34 -2
- package/src/extension/team-tool/dispatch/run.ts +17 -2
- package/src/extension/team-tool/dispatch/status.ts +37 -5
- package/src/extension/team-tool/doctor.ts +2 -2
- package/src/extension/team-tool/explain.ts +1 -1
- package/src/extension/team-tool/goal-wrap.ts +5 -5
- package/src/extension/team-tool/goal.ts +30 -9
- package/src/extension/team-tool/handle-schedule.ts +37 -19
- package/src/extension/team-tool/inspect.ts +21 -5
- package/src/extension/team-tool/lifecycle-actions.ts +53 -10
- package/src/extension/team-tool/parallel-dispatch.ts +14 -5
- package/src/extension/team-tool/param-error.ts +138 -0
- package/src/extension/team-tool/respond.ts +20 -6
- package/src/extension/team-tool/run.ts +27 -17
- package/src/extension/team-tool/status.ts +17 -6
- package/src/extension/team-tool.ts +26 -19
- package/src/hooks/registry.ts +1 -1
- package/src/i18n.ts +22 -0
- package/src/observability/event-bus.ts +1 -1
- package/src/prompt/prompt-runtime.ts +2 -2
- package/src/runtime/README.md +35 -0
- package/src/runtime/agent-control.ts +1 -1
- package/src/runtime/anchor-manager.ts +0 -2
- package/src/runtime/async-runner.ts +1 -1
- package/src/runtime/attention-events.ts +3 -2
- package/src/runtime/auto-summarize.ts +0 -2
- package/src/runtime/background-runner.ts +103 -30
- package/src/runtime/{crew-broker-child.ts → broker/crew-broker-child.ts} +2 -2
- package/src/runtime/{crew-broker-client.ts → broker/crew-broker-client.ts} +4 -7
- package/src/runtime/{crew-broker.ts → broker/crew-broker.ts} +13 -21
- package/src/runtime/chain-runner.ts +50 -5
- package/src/runtime/{child-pi-constants.ts → child-pi/child-pi-constants.ts} +1 -1
- package/src/runtime/{child-pi-kill.ts → child-pi/child-pi-kill.ts} +3 -3
- package/src/runtime/{child-pi-spawn.ts → child-pi/child-pi-spawn.ts} +28 -12
- package/src/runtime/{child-pi-steering.ts → child-pi/child-pi-steering.ts} +1 -1
- package/src/runtime/{child-pi-streams.ts → child-pi/child-pi-streams.ts} +23 -4
- package/src/runtime/{child-pi-transcript.ts → child-pi/child-pi-transcript.ts} +6 -6
- package/src/runtime/{child-pi.ts → child-pi/child-pi.ts} +47 -78
- package/src/runtime/compaction/compact-stages/bounded-tail.ts +84 -0
- package/src/runtime/{compact-stages → compaction/compact-stages}/index.ts +2 -2
- package/src/runtime/{compaction-summary.ts → compaction/compaction-summary.ts} +3 -3
- package/src/runtime/{tool-output-pruner.ts → compaction/tool-output-pruner.ts} +1 -1
- package/src/runtime/crew-agent-records.ts +48 -2
- package/src/runtime/custom-tools/irc-tool.ts +2 -2
- package/src/runtime/delivery-coordinator.ts +0 -3
- package/src/runtime/diagnostic-export.ts +5 -4
- package/src/runtime/foreground-control.ts +1 -1
- package/src/runtime/foreground-watchdog.ts +1 -1
- package/src/runtime/{adaptive-plan.ts → goal-workflow/adaptive-plan.ts} +8 -8
- package/src/runtime/{dynamic-workflow-context.ts → goal-workflow/dynamic-workflow-context.ts} +16 -16
- package/src/runtime/{dynamic-workflow-runner.ts → goal-workflow/dynamic-workflow-runner.ts} +10 -10
- package/src/runtime/{goal-achievement.ts → goal-workflow/goal-achievement.ts} +3 -3
- package/src/runtime/{goal-evaluator.ts → goal-workflow/goal-evaluator.ts} +8 -8
- package/src/runtime/{goal-loop-runner.ts → goal-workflow/goal-loop-runner.ts} +27 -25
- package/src/runtime/{goal-state-store.ts → goal-workflow/goal-state-store.ts} +8 -8
- package/src/runtime/{plan-templates.ts → goal-workflow/plan-templates.ts} +1 -1
- package/src/runtime/group-join.ts +3 -3
- package/src/runtime/handoff-manager.ts +0 -2
- package/src/runtime/{heartbeat-watcher.ts → heartbeat/heartbeat-watcher.ts} +7 -7
- package/src/runtime/iteration-hooks.ts +1 -1
- package/src/runtime/{live-agent-control.ts → live-session/live-agent-control.ts} +2 -2
- package/src/runtime/{live-agent-manager.ts → live-session/live-agent-manager.ts} +4 -4
- package/src/runtime/{live-session-runtime.ts → live-session/live-session-runtime.ts} +39 -41
- package/src/runtime/manifest-cache.ts +6 -2
- package/src/runtime/{model-fallback.ts → model/model-fallback.ts} +1 -1
- package/src/runtime/{pi-args.ts → model/pi-args.ts} +20 -5
- package/src/runtime/model/provider-extensions.ts +116 -0
- package/src/runtime/{runtime-policy.ts → model/runtime-policy.ts} +2 -2
- package/src/runtime/{runtime-resolver.ts → model/runtime-resolver.ts} +3 -3
- package/src/runtime/{runtime-warmup.ts → model/runtime-warmup.ts} +8 -8
- package/src/runtime/orphan-worker-registry.ts +1 -1
- package/src/runtime/{progress-tracker.ts → output/progress-tracker.ts} +1 -1
- package/src/runtime/{result-extractor.ts → output/result-extractor.ts} +4 -4
- package/src/runtime/{sidechain-output.ts → output/sidechain-output.ts} +2 -2
- package/src/runtime/{stream-preview.ts → output/stream-preview.ts} +1 -1
- package/src/runtime/{streaming-output.ts → output/streaming-output.ts} +2 -2
- package/src/runtime/{tool-progress.ts → output/tool-progress.ts} +1 -1
- package/src/runtime/parent-guard.ts +30 -10
- package/src/runtime/pipeline-runner.ts +2 -2
- package/src/runtime/policy-engine.ts +2 -2
- package/src/runtime/{cancellation.ts → process/cancellation.ts} +1 -1
- package/src/runtime/{post-exit-stdio-guard.ts → process/post-exit-stdio-guard.ts} +1 -1
- package/src/runtime/{process-lifecycle.ts → process/process-lifecycle.ts} +3 -3
- package/src/runtime/{checkpoint.ts → recovery/checkpoint.ts} +4 -4
- package/src/runtime/{crash-recovery.ts → recovery/crash-recovery.ts} +93 -21
- package/src/runtime/{overflow-recovery.ts → recovery/overflow-recovery.ts} +1 -1
- package/src/runtime/{recovery-recipes.ts → recovery/recovery-recipes.ts} +1 -1
- package/src/runtime/{retry-executor.ts → recovery/retry-executor.ts} +2 -2
- package/src/runtime/{retry-runner.ts → recovery/retry-runner.ts} +2 -8
- package/src/runtime/run-tracker.ts +1 -1
- package/src/runtime/run-worker.ts +3 -3
- package/src/runtime/{coalesce-tasks.ts → scheduling/coalesce-tasks.ts} +3 -3
- package/src/runtime/{concurrency.ts → scheduling/concurrency.ts} +9 -3
- package/src/runtime/{parallel-research.ts → scheduling/parallel-research.ts} +4 -2
- package/src/runtime/{run-coalesced-task-group.ts → scheduling/run-coalesced-task-group.ts} +95 -36
- package/src/runtime/{semaphore.ts → scheduling/semaphore.ts} +4 -1
- package/src/runtime/{task-graph-scheduler.ts → scheduling/task-graph-scheduler.ts} +1 -1
- package/src/runtime/session-resources.ts +1 -1
- package/src/runtime/settings-store.ts +1 -1
- package/src/runtime/single-agent-compose.ts +1 -0
- package/src/runtime/stale-reconciler.ts +1 -1
- package/src/runtime/subagent-manager.ts +1 -1
- package/src/runtime/supervisor-contact.ts +28 -13
- package/src/runtime/task-output-context.ts +7 -5
- package/src/runtime/task-runner/child-executor.ts +67 -31
- package/src/runtime/task-runner/live-executor.ts +8 -8
- package/src/runtime/task-runner/post-execution.ts +12 -12
- package/src/runtime/task-runner/pre-execution.ts +6 -6
- package/src/runtime/task-runner/progress.ts +1 -1
- package/src/runtime/task-runner/run-projection.ts +1 -1
- package/src/runtime/task-runner/scaffold-executor.ts +1 -1
- package/src/runtime/task-runner/state-helpers.ts +2 -2
- package/src/runtime/task-runner.ts +4 -4
- package/src/runtime/team-runner.ts +441 -175
- package/src/runtime/{completion-guard.ts → verification/completion-guard.ts} +1 -1
- package/src/runtime/{green-contract.ts → verification/green-contract.ts} +1 -1
- package/src/runtime/{post-checks.ts → verification/post-checks.ts} +4 -4
- package/src/runtime/{verification-gates.ts → verification/verification-gates.ts} +5 -5
- package/src/runtime/{verification-integrity.ts → verification/verification-integrity.ts} +1 -1
- package/src/schema/config-schema.ts +1 -0
- package/src/schema/team-tool-schema.ts +149 -185
- package/src/state/README.md +44 -0
- package/src/state/atomic-write.ts +24 -3
- package/src/state/{locks.ts → coordination/locks.ts} +118 -38
- package/src/state/{mailbox.ts → coordination/mailbox.ts} +14 -8
- package/src/state/{schedule.ts → coordination/schedule.ts} +3 -3
- package/src/state/{task-claims.ts → coordination/task-claims.ts} +1 -1
- package/src/state/decision-ledger.ts +1 -1
- package/src/state/{event-log-rotation.ts → event-log/event-log-rotation.ts} +189 -31
- package/src/state/{event-log.ts → event-log/event-log.ts} +77 -39
- package/src/state/{jsonl-writer.ts → event-log/jsonl-writer.ts} +14 -6
- package/src/state/hook-instinct-bridge.ts +2 -2
- package/src/state/{active-run-registry.ts → stores/active-run-registry.ts} +7 -7
- package/src/state/{artifact-store.ts → stores/artifact-store.ts} +62 -4
- package/src/state/{blob-store.ts → stores/blob-store.ts} +3 -3
- package/src/state/{health-store.ts → stores/health-store.ts} +3 -3
- package/src/state/{instinct-store.ts → stores/instinct-store.ts} +3 -3
- package/src/state/{observation-store.ts → stores/observation-store.ts} +2 -2
- package/src/state/{run-cache.ts → stores/run-cache.ts} +4 -4
- package/src/state/{run-graph.ts → stores/run-graph.ts} +4 -4
- package/src/state/{run-metrics.ts → stores/run-metrics.ts} +3 -3
- package/src/state/{state-store.ts → stores/state-store.ts} +254 -21
- package/src/state/types.ts +27 -3
- package/src/ui/component.ts +55 -0
- package/src/ui/crew-select-list.ts +3 -1
- package/src/ui/dashboard-panes/agents-pane.ts +1 -1
- package/src/ui/dwf-phase-display.ts +1 -1
- package/src/ui/heartbeat-aggregator.ts +1 -1
- package/src/ui/keybinding-map.ts +179 -6
- package/src/ui/layout-primitives.ts +9 -5
- package/src/ui/live-conversation-overlay.ts +1 -1
- package/src/ui/live-run-sidebar.ts +1 -1
- package/src/ui/overlay-stack.ts +148 -0
- package/src/ui/overlays/agent-picker-overlay.ts +1 -1
- package/src/ui/overlays/mailbox-compose-overlay.ts +1 -1
- package/src/ui/overlays/mailbox-detail-overlay.ts +2 -2
- package/src/ui/powerbar-publisher.ts +1 -1
- package/src/ui/render-scheduler.ts +1 -1
- package/src/ui/run-action-dispatcher.ts +3 -3
- package/src/ui/run-dashboard.ts +5 -33
- package/src/ui/run-event-bus.ts +3 -3
- package/src/ui/run-snapshot-cache.ts +37 -18
- package/src/ui/settings-overlay.ts +13 -21
- package/src/ui/snapshot-types.ts +1 -1
- package/src/ui/status-colors.ts +0 -2
- package/src/ui/terminal-status.ts +1 -1
- package/src/ui/theme-adapter.ts +33 -13
- package/src/ui/tool-renderers/index.ts +8 -0
- package/src/ui/transcript-viewer.ts +37 -13
- package/src/ui/widget/index.ts +32 -9
- package/src/ui/widget/widget-formatters.ts +62 -4
- package/src/ui/widget/widget-model.ts +2 -2
- package/src/ui/widget/widget-renderer.ts +1 -1
- package/src/utils/conflict-detect.ts +58 -5
- package/src/utils/ndjson.ts +2 -2
- package/src/utils/redaction.ts +39 -0
- package/src/utils/socket-path.ts +1 -1
- package/src/workflows/workflow-config.ts +1 -1
- package/src/worktree/cleanup.ts +1 -1
- package/src/worktree/worktree-manager.ts +111 -47
- package/workflows/chain.workflow.md +2 -2
- package/dist/build-meta.json +0 -16807
- package/index.bundle.ts +0 -25
- package/scripts/bench-check.mjs +0 -96
- package/scripts/bench-cold-start.mjs +0 -216
- package/scripts/build-bundle.mjs +0 -92
- package/scripts/check-all-skills.ts +0 -294
- package/scripts/check-bundle-size.mjs +0 -38
- package/scripts/check-bundle-staleness.mjs +0 -97
- package/scripts/check-conflict-markers.mjs +0 -91
- package/scripts/check-lazy-imports.mjs +0 -28
- package/scripts/dev-runner.mjs +0 -106
- package/scripts/profile-startup.mjs +0 -125
- package/scripts/release-smoke.mjs +0 -74
- package/scripts/run-bench.mjs +0 -47
- package/scripts/run-real-chain.ts +0 -41
- package/scripts/test-issue-29-crash.ts +0 -111
- package/scripts/test-issue-29-e2e.ts +0 -183
- package/scripts/test-issue-29-real-runtime.ts +0 -330
- package/scripts/test-issue-29-real-tasks.ts +0 -387
- package/scripts/test-issue-29-team-tool.ts +0 -105
- package/scripts/test-runner.mjs +0 -84
- package/scripts/verify-flicker-fix.ts +0 -109
- package/scripts/verify-skill.ts +0 -550
- package/scripts/watch-bundle.mjs +0 -259
- package/scripts/watchdog-harness.ts +0 -119
- package/src/adapters/claude-adapter.ts +0 -23
- package/src/adapters/codex-adapter.ts +0 -21
- package/src/adapters/cursor-adapter.ts +0 -17
- package/src/adapters/export-util.ts +0 -143
- package/src/adapters/index.ts +0 -15
- package/src/adapters/registry.ts +0 -18
- package/src/adapters/types.ts +0 -23
- package/src/runtime/code-summary.ts +0 -292
- package/src/runtime/cross-extension-rpc.ts +0 -143
- package/src/runtime/hidden-handoff.ts +0 -407
- package/src/runtime/prose-compressor.ts +0 -162
- package/src/subagents/async-entry.ts +0 -1
- package/src/subagents/index.ts +0 -3
- package/src/subagents/live/control.ts +0 -1
- package/src/subagents/live/manager.ts +0 -1
- package/src/subagents/live/realtime.ts +0 -1
- package/src/subagents/live/session-runtime.ts +0 -1
- package/src/subagents/manager.ts +0 -1
- package/src/subagents/spawn.ts +0 -1
- package/test-integration-check.ts +0 -118
- /package/src/runtime/{broker-issuer.ts → broker/broker-issuer.ts} +0 -0
- /package/src/runtime/{crew-broker-tokens.ts → broker/crew-broker-tokens.ts} +0 -0
- /package/src/runtime/{child-pi-pool.ts → child-pi/child-pi-pool.ts} +0 -0
- /package/src/runtime/{compact-pipeline.ts → compaction/compact-pipeline.ts} +0 -0
- /package/src/runtime/{compact-stages → compaction/compact-stages}/ansi-strip-stage.ts +0 -0
- /package/src/runtime/{compact-stages → compaction/compact-stages}/blank-collapse-stage.ts +0 -0
- /package/src/runtime/{compact-stages → compaction/compact-stages}/deduplicate-stage.ts +0 -0
- /package/src/runtime/{compact-stages → compaction/compact-stages}/head-snap-stage.ts +0 -0
- /package/src/runtime/{compact-stages → compaction/compact-stages}/tail-capture-stage.ts +0 -0
- /package/src/runtime/{compact-stages → compaction/compact-stages}/truncation-stage.ts +0 -0
- /package/src/runtime/{important-line-classifier.ts → compaction/important-line-classifier.ts} +0 -0
- /package/src/runtime/{heartbeat-gradient.ts → heartbeat/heartbeat-gradient.ts} +0 -0
- /package/src/runtime/{worker-heartbeat.ts → heartbeat/worker-heartbeat.ts} +0 -0
- /package/src/runtime/{worker-startup.ts → heartbeat/worker-startup.ts} +0 -0
- /package/src/runtime/{intercom-bridge.ts → live-session/intercom-bridge.ts} +0 -0
- /package/src/runtime/{live-control-realtime.ts → live-session/live-control-realtime.ts} +0 -0
- /package/src/runtime/{live-extension-bridge.ts → live-session/live-extension-bridge.ts} +0 -0
- /package/src/runtime/{live-irc.ts → live-session/live-irc.ts} +0 -0
- /package/src/runtime/{live-session-health.ts → live-session/live-session-health.ts} +0 -0
- /package/src/runtime/{model-resolver.ts → model/model-resolver.ts} +0 -0
- /package/src/runtime/{model-scope.ts → model/model-scope.ts} +0 -0
- /package/src/runtime/{output-validator.ts → output/output-validator.ts} +0 -0
- /package/src/runtime/{pi-json-output.ts → output/pi-json-output.ts} +0 -0
- /package/src/runtime/{progress-event-coalescer.ts → output/progress-event-coalescer.ts} +0 -0
- /package/src/runtime/{cancellation-token.ts → process/cancellation-token.ts} +0 -0
- /package/src/runtime/{zombie-scanner.ts → process/zombie-scanner.ts} +0 -0
- /package/src/runtime/{crash-classification.ts → recovery/crash-classification.ts} +0 -0
- /package/src/runtime/{batch-barrier.ts → scheduling/batch-barrier.ts} +0 -0
- /package/src/runtime/{global-worker-cap.ts → scheduling/global-worker-cap.ts} +0 -0
- /package/src/runtime/{parallel-utils.ts → scheduling/parallel-utils.ts} +0 -0
- /package/src/runtime/{scheduler.ts → scheduling/scheduler.ts} +0 -0
- /package/src/runtime/{task-graph.ts → scheduling/task-graph.ts} +0 -0
- /package/src/runtime/{verification-worktree.ts → verification/verification-worktree.ts} +0 -0
- /package/src/state/{event-reconstructor.ts → event-log/event-reconstructor.ts} +0 -0
- /package/src/state/{worker-atomic-writer.ts → event-log/worker-atomic-writer.ts} +0 -0
|
@@ -1,292 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Structural code summary — regex-based summarizer that elides function bodies,
|
|
3
|
-
* long arrays, block comments, and import groups, keeping signatures.
|
|
4
|
-
* Pure TypeScript fallback (no tree-sitter / Rust native dependency).
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
// ── Public types ──
|
|
8
|
-
|
|
9
|
-
export interface SummarySegment {
|
|
10
|
-
kind: "kept" | "elided";
|
|
11
|
-
startLine: number;
|
|
12
|
-
endLine: number;
|
|
13
|
-
/** Verbatim text for kept segments; absent for elided */
|
|
14
|
-
text?: string;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export interface SummaryResult {
|
|
18
|
-
language: string | null;
|
|
19
|
-
totalLines: number;
|
|
20
|
-
elided: boolean;
|
|
21
|
-
segments: SummarySegment[];
|
|
22
|
-
rendered: string;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export interface SummaryOptions {
|
|
26
|
-
minBodyLines?: number; // default 4
|
|
27
|
-
minCommentLines?: number; // default 6
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
// ── Language detection ──
|
|
31
|
-
|
|
32
|
-
const EXT_MAP: ReadonlyMap<string, string> = new Map([
|
|
33
|
-
[".ts", "typescript"],
|
|
34
|
-
[".tsx", "typescript"],
|
|
35
|
-
[".js", "javascript"],
|
|
36
|
-
[".jsx", "javascript"],
|
|
37
|
-
[".mjs", "javascript"],
|
|
38
|
-
[".cjs", "javascript"],
|
|
39
|
-
[".py", "python"],
|
|
40
|
-
[".rs", "rust"],
|
|
41
|
-
]);
|
|
42
|
-
|
|
43
|
-
export function detectLanguage(filePath: string): string | null {
|
|
44
|
-
const dot = filePath.lastIndexOf(".");
|
|
45
|
-
if (dot === -1) return null;
|
|
46
|
-
return EXT_MAP.get(filePath.slice(dot).toLowerCase()) ?? null;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
// ── Internal range helpers ──
|
|
50
|
-
|
|
51
|
-
interface Range {
|
|
52
|
-
start: number;
|
|
53
|
-
end: number;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
function mergeRanges(ranges: Range[]): Range[] {
|
|
57
|
-
if (ranges.length === 0) return [];
|
|
58
|
-
const sorted = [...ranges].sort((a, b) => a.start - b.start || a.end - b.end);
|
|
59
|
-
const merged: Range[] = [sorted[0]];
|
|
60
|
-
for (let i = 1; i < sorted.length; i++) {
|
|
61
|
-
const last = merged[merged.length - 1];
|
|
62
|
-
if (sorted[i].start <= last.end + 1) last.end = Math.max(last.end, sorted[i].end);
|
|
63
|
-
else merged.push({ ...sorted[i] });
|
|
64
|
-
}
|
|
65
|
-
return merged;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
// ── Brace-based elision (TS/JS/Rust) ──
|
|
69
|
-
// NOTE: This is a regex heuristic, not a parser. Braces inside string literals,
|
|
70
|
-
// template strings, regex, and comments are counted, which can produce incorrect
|
|
71
|
-
// elision for edge cases like `const s = "{...}"` or `${expr}`. Acceptable for
|
|
72
|
-
// summaries; do not use for correctness-sensitive parsing.
|
|
73
|
-
|
|
74
|
-
function findBraceRanges(lines: string[], openPattern: RegExp, minBody: number): Range[] {
|
|
75
|
-
const ranges: Range[] = [];
|
|
76
|
-
for (let i = 0; i < lines.length; i++) {
|
|
77
|
-
if (!openPattern.test(lines[i])) continue;
|
|
78
|
-
let depth = 0;
|
|
79
|
-
let foundOpen = false;
|
|
80
|
-
const start = i;
|
|
81
|
-
for (let j = i; j < lines.length; j++) {
|
|
82
|
-
for (const ch of lines[j]) {
|
|
83
|
-
if (ch === "{") {
|
|
84
|
-
depth++;
|
|
85
|
-
foundOpen = true;
|
|
86
|
-
} else if (ch === "}") {
|
|
87
|
-
depth--;
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
if (foundOpen && depth <= 0) {
|
|
91
|
-
if (j - start - 1 >= minBody) ranges.push({ start: start + 1, end: j - 1 });
|
|
92
|
-
break;
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
return ranges;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
// ── TypeScript / JavaScript ──
|
|
100
|
-
|
|
101
|
-
const TS_FN_SIG =
|
|
102
|
-
/^\s*(export\s+)?(async\s+)?function\s|^\s*(export\s+)?(static\s+|get\s+|set\s+|private\s+|public\s+|protected\s+|readonly\s+)*\*?\s*\w+\s*[(<]/;
|
|
103
|
-
const TS_CLASS_SIG = /^\s*(export\s+)?(default\s+)?(abstract\s+)?class\s/;
|
|
104
|
-
const TS_STRUCT_SIG = /^\s*(export\s+)?(default\s+)?(const|let|var)\s+\w+\s*=\s*(\[[\s]*$|\{[\s]*$)/;
|
|
105
|
-
|
|
106
|
-
function tsRanges(lines: string[], minBody: number): Range[] {
|
|
107
|
-
return [
|
|
108
|
-
...findBraceRanges(lines, TS_FN_SIG, minBody),
|
|
109
|
-
...findBraceRanges(lines, TS_CLASS_SIG, minBody),
|
|
110
|
-
...findBraceRanges(lines, TS_STRUCT_SIG, minBody),
|
|
111
|
-
];
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
// ── Block comments ──
|
|
115
|
-
|
|
116
|
-
function blockCommentRanges(lines: string[], minComment: number): Range[] {
|
|
117
|
-
const ranges: Range[] = [];
|
|
118
|
-
let i = 0;
|
|
119
|
-
while (i < lines.length) {
|
|
120
|
-
const idx = lines[i].indexOf("/*");
|
|
121
|
-
if (idx === -1 || lines[i].includes("*/", idx + 2)) {
|
|
122
|
-
i++;
|
|
123
|
-
continue;
|
|
124
|
-
}
|
|
125
|
-
const openLine = i;
|
|
126
|
-
let j = i + 1;
|
|
127
|
-
while (j < lines.length && !lines[j].includes("*/")) j++;
|
|
128
|
-
if (j < lines.length && j - openLine - 1 >= minComment) ranges.push({ start: openLine + 1, end: j - 1 });
|
|
129
|
-
i = j + 1;
|
|
130
|
-
}
|
|
131
|
-
return ranges;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
// ── Import groups ──
|
|
135
|
-
|
|
136
|
-
const IMPORT_RE = /^\s*import\s/;
|
|
137
|
-
const PY_IMPORT_RE = /^\s*(import\s|from\s+\S+\s+import\s)/;
|
|
138
|
-
|
|
139
|
-
function importGroupRanges(lines: string[], pattern: RegExp): Range[] {
|
|
140
|
-
const groups: Array<{ start: number; end: number }> = [];
|
|
141
|
-
let gs = -1,
|
|
142
|
-
last = -1;
|
|
143
|
-
for (let i = 0; i < lines.length; i++) {
|
|
144
|
-
if (pattern.test(lines[i])) {
|
|
145
|
-
if (gs === -1) gs = i;
|
|
146
|
-
last = i;
|
|
147
|
-
} else if (gs !== -1 && i > last) {
|
|
148
|
-
groups.push({ start: gs, end: last });
|
|
149
|
-
gs = -1;
|
|
150
|
-
last = -1;
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
if (gs !== -1) groups.push({ start: gs, end: last });
|
|
154
|
-
const ranges: Range[] = [];
|
|
155
|
-
for (const g of groups) {
|
|
156
|
-
if (g.end - g.start >= 2) ranges.push({ start: g.start + 1, end: g.end - 1 });
|
|
157
|
-
}
|
|
158
|
-
return ranges;
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
// ── Python ──
|
|
162
|
-
|
|
163
|
-
function pythonRanges(lines: string[], minBody: number): Range[] {
|
|
164
|
-
const ranges: Range[] = [];
|
|
165
|
-
for (let i = 0; i < lines.length; i++) {
|
|
166
|
-
const m = /^(\s*)(async\s+)?def\s/.exec(lines[i]) || /^(\s*)class\s/.exec(lines[i]);
|
|
167
|
-
if (!m) continue;
|
|
168
|
-
const base = m[1].length;
|
|
169
|
-
let bs = -1,
|
|
170
|
-
be = -1;
|
|
171
|
-
for (let j = i + 1; j < lines.length; j++) {
|
|
172
|
-
if (lines[j].trim() === "") continue;
|
|
173
|
-
const indent = lines[j].length - lines[j].trimStart().length;
|
|
174
|
-
if (indent <= base) break;
|
|
175
|
-
if (bs === -1) bs = j;
|
|
176
|
-
be = j;
|
|
177
|
-
}
|
|
178
|
-
if (bs !== -1 && be - bs + 1 >= minBody) ranges.push({ start: bs, end: be });
|
|
179
|
-
}
|
|
180
|
-
ranges.push(...importGroupRanges(lines, PY_IMPORT_RE));
|
|
181
|
-
return ranges;
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
// ── Rust ──
|
|
185
|
-
|
|
186
|
-
const RS_FN_SIG = /^\s*(pub\s+)?(async\s+)?(unsafe\s+)?fn\s/;
|
|
187
|
-
const RS_STRUCT_SIG = /^\s*(pub\s+)?struct\s+\w+.*\{$/;
|
|
188
|
-
const RS_ENUM_SIG = /^\s*(pub\s+)?enum\s+\w+.*\{$/;
|
|
189
|
-
const RS_MOD_SIG = /^\s*(pub\s+)?mod\s+\w+.*\{$/;
|
|
190
|
-
|
|
191
|
-
function rustRanges(lines: string[], minBody: number): Range[] {
|
|
192
|
-
return [
|
|
193
|
-
...findBraceRanges(lines, RS_FN_SIG, minBody),
|
|
194
|
-
...findBraceRanges(lines, RS_STRUCT_SIG, minBody),
|
|
195
|
-
...findBraceRanges(lines, RS_ENUM_SIG, minBody),
|
|
196
|
-
...findBraceRanges(lines, RS_MOD_SIG, minBody),
|
|
197
|
-
];
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
// ── Main entry ──
|
|
201
|
-
|
|
202
|
-
function fullResult(language: string | null, totalLines: number, code: string): SummaryResult {
|
|
203
|
-
return {
|
|
204
|
-
language,
|
|
205
|
-
totalLines,
|
|
206
|
-
elided: false,
|
|
207
|
-
segments: [{ kind: "kept", startLine: 1, endLine: totalLines, text: code }],
|
|
208
|
-
rendered: code,
|
|
209
|
-
};
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
export function summarizeCode(code: string, language: string | null, options?: SummaryOptions): SummaryResult {
|
|
213
|
-
const minBody = options?.minBodyLines ?? 4;
|
|
214
|
-
const minComment = options?.minCommentLines ?? 6;
|
|
215
|
-
|
|
216
|
-
if (!code || code.trim() === "") {
|
|
217
|
-
return {
|
|
218
|
-
language,
|
|
219
|
-
totalLines: 0,
|
|
220
|
-
elided: false,
|
|
221
|
-
segments: [],
|
|
222
|
-
rendered: "",
|
|
223
|
-
};
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
const lines = code.split("\n");
|
|
227
|
-
const totalLines = lines.length;
|
|
228
|
-
|
|
229
|
-
if (!language) return fullResult(null, totalLines, code);
|
|
230
|
-
|
|
231
|
-
const rawRanges: Range[] = [];
|
|
232
|
-
switch (language) {
|
|
233
|
-
case "typescript":
|
|
234
|
-
case "javascript":
|
|
235
|
-
rawRanges.push(...tsRanges(lines, minBody), ...blockCommentRanges(lines, minComment), ...importGroupRanges(lines, IMPORT_RE));
|
|
236
|
-
break;
|
|
237
|
-
case "python":
|
|
238
|
-
rawRanges.push(...pythonRanges(lines, minBody));
|
|
239
|
-
break;
|
|
240
|
-
case "rust":
|
|
241
|
-
rawRanges.push(...rustRanges(lines, minBody), ...blockCommentRanges(lines, minComment));
|
|
242
|
-
break;
|
|
243
|
-
default:
|
|
244
|
-
return fullResult(language, totalLines, code);
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
const ranges = mergeRanges(rawRanges);
|
|
248
|
-
if (ranges.length === 0) return fullResult(language, totalLines, code);
|
|
249
|
-
|
|
250
|
-
// Build segments
|
|
251
|
-
const segments: SummarySegment[] = [];
|
|
252
|
-
let cursor = 0;
|
|
253
|
-
for (const r of ranges) {
|
|
254
|
-
if (cursor < r.start) {
|
|
255
|
-
segments.push({
|
|
256
|
-
kind: "kept",
|
|
257
|
-
startLine: cursor + 1,
|
|
258
|
-
endLine: r.start,
|
|
259
|
-
text: lines.slice(cursor, r.start).join("\n"),
|
|
260
|
-
});
|
|
261
|
-
}
|
|
262
|
-
segments.push({
|
|
263
|
-
kind: "elided",
|
|
264
|
-
startLine: r.start + 1,
|
|
265
|
-
endLine: r.end + 1,
|
|
266
|
-
});
|
|
267
|
-
cursor = r.end + 1;
|
|
268
|
-
}
|
|
269
|
-
if (cursor < totalLines) {
|
|
270
|
-
segments.push({
|
|
271
|
-
kind: "kept",
|
|
272
|
-
startLine: cursor + 1,
|
|
273
|
-
endLine: totalLines,
|
|
274
|
-
text: lines.slice(cursor).join("\n"),
|
|
275
|
-
});
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
// Render
|
|
279
|
-
const parts: string[] = [];
|
|
280
|
-
for (const seg of segments) {
|
|
281
|
-
if (seg.kind === "kept") parts.push(seg.text ?? "");
|
|
282
|
-
else parts.push(` ... ${seg.endLine - seg.startLine + 1} lines elided ...`);
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
return {
|
|
286
|
-
language,
|
|
287
|
-
totalLines,
|
|
288
|
-
elided: true,
|
|
289
|
-
segments,
|
|
290
|
-
rendered: parts.join("\n"),
|
|
291
|
-
};
|
|
292
|
-
}
|
|
@@ -1,143 +0,0 @@
|
|
|
1
|
-
import * as crypto from "node:crypto";
|
|
2
|
-
import { extractSignaturePayload, isHmacEnabled, verifyRpcSignature } from "../extension/rpc-hmac.ts";
|
|
3
|
-
|
|
4
|
-
export interface EventBus {
|
|
5
|
-
on(event: string, handler: (data: unknown) => void): () => void;
|
|
6
|
-
emit(event: string, data: unknown): void;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
export type RpcReply<T = void> = { success: true; data?: T } | { success: false; error: string };
|
|
10
|
-
|
|
11
|
-
export const PROTOCOL_VERSION = 1;
|
|
12
|
-
|
|
13
|
-
// H-2 fix (code-review 2026-06-23): the old authorization relied on a
|
|
14
|
-
// self-declared `source === "pi-crew"` field, which any co-installed
|
|
15
|
-
// extension on the shared event bus can spoof. We now also require an
|
|
16
|
-
// unguessable per-process token. Only in-process pi-crew code can obtain it
|
|
17
|
-
// via getCrewRpcToken(); a cross-extension attacker cannot forge a UUID it
|
|
18
|
-
// has never seen. (A full fix still needs event-bus-level origin signing, but
|
|
19
|
-
// this closes the trivial spoof.)
|
|
20
|
-
let CREW_RPC_TOKEN: string | undefined;
|
|
21
|
-
/** @internal Per-process token that legitimate in-process RPC callers must include. */
|
|
22
|
-
export function getCrewRpcToken(): string {
|
|
23
|
-
if (!CREW_RPC_TOKEN) CREW_RPC_TOKEN = crypto.randomUUID();
|
|
24
|
-
return CREW_RPC_TOKEN;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export interface RpcDeps {
|
|
28
|
-
events: EventBus;
|
|
29
|
-
getCtx: () => unknown | undefined;
|
|
30
|
-
spawn: (type: string, prompt: string, options?: Record<string, unknown>) => string;
|
|
31
|
-
abort: (agentId: string) => boolean;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
export interface RpcHandle {
|
|
35
|
-
unsubPing: () => void;
|
|
36
|
-
unsubSpawn: () => void;
|
|
37
|
-
unsubStop: () => void;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
function handleRpc<P extends { requestId: string }>(
|
|
41
|
-
events: EventBus,
|
|
42
|
-
channel: string,
|
|
43
|
-
fn: (params: P) => unknown | Promise<unknown>,
|
|
44
|
-
): () => void {
|
|
45
|
-
return events.on(channel, async (raw: unknown) => {
|
|
46
|
-
const params = raw as P;
|
|
47
|
-
// SECURITY: Validate requestId format to prevent channel injection.
|
|
48
|
-
if (!/^[a-zA-Z0-9_-]+$/.test(params.requestId)) {
|
|
49
|
-
throw new Error("Security: invalid requestId format");
|
|
50
|
-
}
|
|
51
|
-
// SECURITY: HMAC signature verification (when enabled).
|
|
52
|
-
if (isHmacEnabled()) {
|
|
53
|
-
const sigPayload = extractSignaturePayload(params);
|
|
54
|
-
if (!sigPayload) {
|
|
55
|
-
throw new Error("[pi-crew HMAC] Missing HMAC signature in RPC request.");
|
|
56
|
-
}
|
|
57
|
-
// Strip HMAC fields before verification (HMAC was signed over original params)
|
|
58
|
-
const originalParams = { ...params };
|
|
59
|
-
delete (originalParams as Record<string, unknown>).hmacVersion;
|
|
60
|
-
delete (originalParams as Record<string, unknown>).hmacOrigin;
|
|
61
|
-
delete (originalParams as Record<string, unknown>).hmacTimestamp;
|
|
62
|
-
delete (originalParams as Record<string, unknown>).hmacChannel;
|
|
63
|
-
delete (originalParams as Record<string, unknown>).hmacNonce;
|
|
64
|
-
delete (originalParams as Record<string, unknown>).hmacSignature;
|
|
65
|
-
const verification = verifyRpcSignature(sigPayload, originalParams);
|
|
66
|
-
if (!verification.valid) {
|
|
67
|
-
throw new Error(`[pi-crew HMAC] ${verification.reason}`);
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
try {
|
|
71
|
-
const data = await fn(params);
|
|
72
|
-
const reply: { success: true; data?: unknown } = { success: true };
|
|
73
|
-
if (data !== undefined) reply.data = data;
|
|
74
|
-
events.emit(`${channel}:reply:${params.requestId}`, reply);
|
|
75
|
-
} catch (err: unknown) {
|
|
76
|
-
events.emit(`${channel}:reply:${params.requestId}`, {
|
|
77
|
-
success: false,
|
|
78
|
-
error: err instanceof Error ? err.message : String(err),
|
|
79
|
-
});
|
|
80
|
-
}
|
|
81
|
-
});
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
export function registerCrewRpcHandlers(deps: RpcDeps): RpcHandle {
|
|
85
|
-
const { events, getCtx, spawn, abort } = deps;
|
|
86
|
-
|
|
87
|
-
const unsubPing = handleRpc(events, "crew:rpc:ping", () => {
|
|
88
|
-
return { version: PROTOCOL_VERSION };
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
// SECURITY TRUST BOUNDARY: crew:rpc:spawn and crew:rpc:stop are privileged
|
|
92
|
-
// operations that create or terminate child processes. Any subscriber on
|
|
93
|
-
// the shared event bus can emit these events. In a multi-extension
|
|
94
|
-
// environment, this means a malicious extension could spawn/stop agents.
|
|
95
|
-
// Mitigations: HMAC origin signing (see rpc-hmac.ts) + per-process token
|
|
96
|
-
// (H-2) + legacy `source` identifier.
|
|
97
|
-
const CREW_RPC_SOURCE = "pi-crew";
|
|
98
|
-
const EXPECTED_TOKEN = getCrewRpcToken();
|
|
99
|
-
|
|
100
|
-
function validateRpcSource(params: { requestId: string; source?: string; token?: string }): boolean {
|
|
101
|
-
if (params.token !== EXPECTED_TOKEN) {
|
|
102
|
-
console.warn(
|
|
103
|
-
`[pi-crew SECURITY] RPC invocation rejected: missing/invalid token (source=${params.source ?? "(none)"}). ` +
|
|
104
|
-
`Privileged RPC requires the in-process token. Request may be from an untrusted extension.`,
|
|
105
|
-
);
|
|
106
|
-
return false;
|
|
107
|
-
}
|
|
108
|
-
if (!params.source || params.source !== CREW_RPC_SOURCE) {
|
|
109
|
-
console.warn(
|
|
110
|
-
`[pi-crew SECURITY] RPC invocation from unexpected source: ${params.source ?? "(none)"}. ` +
|
|
111
|
-
`Expected '${CREW_RPC_SOURCE}'. Request may be from an untrusted extension.`,
|
|
112
|
-
);
|
|
113
|
-
return false;
|
|
114
|
-
}
|
|
115
|
-
return true;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
const unsubSpawn = handleRpc<{
|
|
119
|
-
requestId: string;
|
|
120
|
-
type: string;
|
|
121
|
-
prompt: string;
|
|
122
|
-
options?: Record<string, unknown>;
|
|
123
|
-
source?: string;
|
|
124
|
-
token?: string;
|
|
125
|
-
}>(events, "crew:rpc:spawn", (params) => {
|
|
126
|
-
if (!validateRpcSource(params)) throw new Error("Unauthorized: RPC spawn requires valid token and source='pi-crew'");
|
|
127
|
-
const ctx = getCtx();
|
|
128
|
-
if (!ctx) throw new Error("No active session");
|
|
129
|
-
return { id: spawn(params.type, params.prompt, params.options ?? {}) };
|
|
130
|
-
});
|
|
131
|
-
|
|
132
|
-
const unsubStop = handleRpc<{
|
|
133
|
-
requestId: string;
|
|
134
|
-
agentId: string;
|
|
135
|
-
source?: string;
|
|
136
|
-
token?: string;
|
|
137
|
-
}>(events, "crew:rpc:stop", (params) => {
|
|
138
|
-
if (!validateRpcSource(params)) throw new Error("Unauthorized: RPC stop requires valid token and source='pi-crew'");
|
|
139
|
-
if (!abort(params.agentId)) throw new Error("Agent not found");
|
|
140
|
-
});
|
|
141
|
-
|
|
142
|
-
return { unsubPing, unsubSpawn, unsubStop };
|
|
143
|
-
}
|