@pi-unipi/unipi 3.0.0-alpha.2 → 3.0.0-alpha.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +292 -0
- package/README.md +8 -11
- package/docs/prefix-cache-architecture.md +14 -0
- package/package.json +22 -24
- package/packages/ask-user/README.md +55 -107
- package/packages/ask-user/ask-ui.ts +306 -732
- package/packages/ask-user/clipboard.ts +50 -0
- package/packages/ask-user/config.ts +74 -78
- package/packages/ask-user/package.json +2 -2
- package/packages/ask-user/questions.ts +151 -0
- package/packages/ask-user/skills/ask-user/SKILL.md +59 -133
- package/packages/ask-user/tools.ts +198 -432
- package/packages/autocomplete/package.json +1 -1
- package/packages/autocomplete/src/constants.ts +38 -43
- package/packages/autocomplete/src/sorting.ts +8 -0
- package/packages/background-tasks/package.json +2 -2
- package/packages/background-tasks/src/config.ts +0 -73
- package/packages/background-tasks/src/index.ts +20 -16
- package/packages/background-tasks/src/registry.ts +1 -171
- package/packages/background-tasks/src/types.ts +0 -32
- package/packages/btw/README.md +13 -56
- package/packages/btw/extensions/btw.ts +403 -1796
- package/packages/btw/package.json +5 -2
- package/packages/btw/skills/btw/SKILL.md +7 -143
- package/packages/compactor/README.md +56 -287
- package/packages/compactor/package.json +5 -9
- package/packages/compactor/skills/compactor/SKILL.md +13 -20
- package/packages/compactor/src/card.ts +90 -0
- package/packages/compactor/src/commands/index.ts +73 -130
- package/packages/compactor/src/compaction/compact-args.ts +5 -3
- package/packages/compactor/src/compaction/filter-noise.ts +1 -1
- package/packages/compactor/src/compaction/hooks.ts +487 -311
- package/packages/compactor/src/compaction/source.ts +178 -0
- package/packages/compactor/src/compaction/summarize.ts +586 -52
- package/packages/compactor/src/config/manager.ts +130 -127
- package/packages/compactor/src/config/schema.ts +32 -48
- package/packages/compactor/src/index.ts +40 -431
- package/packages/compactor/src/info-screen.ts +44 -190
- package/packages/compactor/src/session/recall-blocks.ts +1 -1
- package/packages/compactor/src/stats.ts +76 -0
- package/packages/compactor/src/tools/context-budget.ts +17 -34
- package/packages/compactor/src/tools/ctx-doctor.ts +45 -36
- package/packages/compactor/src/tools/register.ts +29 -269
- package/packages/compactor/src/types.ts +47 -186
- package/packages/core/README.md +25 -0
- package/packages/core/child-agent.ts +1 -0
- package/packages/core/command-echo.ts +63 -0
- package/packages/core/compaction-context.ts +41 -0
- package/packages/core/constants.ts +8 -38
- package/packages/core/events.ts +0 -53
- package/packages/core/fusion-status.ts +4 -0
- package/packages/core/global.d.ts +10 -0
- package/packages/core/harness-messages.ts +392 -0
- package/packages/core/index.ts +14 -0
- package/packages/core/kanboard-status.ts +49 -0
- package/packages/core/long-horizon-owner-status.ts +46 -0
- package/packages/core/model-cache.ts +81 -7
- package/packages/core/package.json +6 -3
- package/packages/core/src/attach/detect.ts +163 -0
- package/packages/core/src/child-agent/child-args.ts +31 -0
- package/packages/core/src/child-agent/delivery.ts +41 -0
- package/packages/core/src/child-agent/index.ts +5 -0
- package/packages/core/src/child-agent/readers.ts +203 -0
- package/packages/core/src/child-agent/runtime.ts +584 -0
- package/packages/core/src/evidence.ts +78 -0
- package/packages/core/src/hints/browser.ts +278 -0
- package/packages/core/src/hints/crab-data.ts +19 -0
- package/packages/core/src/hints/index.ts +865 -0
- package/packages/core/src/hints/lines.ts +607 -0
- package/packages/core/src/hints/store.ts +120 -0
- package/packages/core/src/jev/chatter.ts +24 -0
- package/packages/core/src/jev/settings.ts +177 -14
- package/packages/core/src/package-colors.ts +2 -0
- package/packages/core/src/settings/catalog.ts +39 -15
- package/packages/core/src/settings/engine.ts +48 -2
- package/packages/core/src/settings/hub.ts +83 -20
- package/packages/core/src/settings/open.ts +49 -0
- package/packages/core/src/settings/schema.ts +27 -7
- package/packages/core/src/tui/hub-kit.ts +18 -5
- package/packages/core/src/tui/kit.ts +198 -0
- package/packages/core/src/tui/progress.ts +73 -0
- package/packages/core/src/turn/arbiter.ts +290 -0
- package/packages/footer/README.md +4 -6
- package/packages/footer/package.json +3 -3
- package/packages/footer/src/glance-editor.ts +19 -11
- package/packages/footer/src/help.ts +1 -1
- package/packages/footer/src/index.ts +36 -3
- package/packages/footer/src/presets.ts +3 -4
- package/packages/footer/src/rendering/icons.ts +0 -20
- package/packages/footer/src/segments/compactor.ts +52 -142
- package/packages/footer/src/segments/status-ext.ts +0 -1
- package/packages/fusion/README.md +14 -4
- package/packages/fusion/package.json +4 -3
- package/packages/fusion/src/child-args.ts +1 -0
- package/packages/fusion/src/index.ts +161 -8
- package/packages/fusion/src/pi-settings.ts +57 -0
- package/packages/fusion/src/picker.ts +186 -51
- package/packages/fusion/src/preset.ts +56 -2
- package/packages/fusion/src/prompts.ts +1 -1
- package/packages/fusion/src/sidekick-runtime.ts +1 -420
- package/packages/fusion/src/tools.ts +107 -128
- package/packages/fusion/src/transcript.ts +27 -85
- package/packages/info-screen/package.json +2 -2
- package/packages/input-shortcuts/README.md +18 -30
- package/packages/input-shortcuts/package.json +2 -2
- package/packages/input-shortcuts/src/burst.ts +88 -0
- package/packages/input-shortcuts/src/chord-overlay.ts +20 -70
- package/packages/input-shortcuts/src/cleared-input.ts +97 -0
- package/packages/input-shortcuts/src/index.ts +99 -193
- package/packages/input-shortcuts/src/last-response.ts +40 -0
- package/packages/input-shortcuts/src/registers.ts +8 -23
- package/packages/input-shortcuts/src/types.ts +4 -16
- package/packages/input-shortcuts/src/undo-redo.ts +59 -47
- package/packages/kanboard/README.md +51 -47
- package/packages/kanboard/index.ts +293 -55
- package/packages/kanboard/package.json +8 -8
- package/packages/kanboard/skills/kanboard/SKILL.md +61 -27
- package/packages/kanboard/src/badges.ts +93 -0
- package/packages/kanboard/src/bin.ts +4 -2
- package/packages/kanboard/src/commands.ts +218 -84
- package/packages/kanboard/src/debug.ts +20 -0
- package/packages/kanboard/src/guard.ts +267 -109
- package/packages/kanboard/src/monitor.ts +330 -0
- package/packages/kanboard/src/notice-buffer.ts +74 -0
- package/packages/kanboard/src/progress.ts +27 -0
- package/packages/kanboard/src/reminders.ts +234 -0
- package/packages/kanboard/src/settings.ts +69 -15
- package/packages/kanboard/src/shapes.ts +5 -0
- package/packages/long-horizon/index.ts +190 -13
- package/packages/long-horizon/package.json +3 -3
- package/packages/long-horizon/src/commands.ts +103 -7
- package/packages/long-horizon/src/compaction-brief.ts +35 -0
- package/packages/long-horizon/src/engine/continuation.ts +84 -15
- package/packages/long-horizon/src/engine/goal-state.ts +64 -13
- package/packages/long-horizon/src/engine/nudge-stash.ts +71 -0
- package/packages/long-horizon/src/engine/ralph.ts +3 -2
- package/packages/long-horizon/src/engine/runaway.ts +68 -11
- package/packages/long-horizon/src/engine/verifier.ts +19 -0
- package/packages/long-horizon/src/gate.ts +37 -12
- package/packages/long-horizon/src/judge/resolve.ts +1 -0
- package/packages/long-horizon/src/owner.ts +35 -2
- package/packages/long-horizon/src/progress.ts +87 -0
- package/packages/long-horizon/src/prompts/goal.ts +1 -1
- package/packages/long-horizon/src/runtime.ts +172 -18
- package/packages/long-horizon/src/settings.ts +54 -39
- package/packages/long-horizon/src/tools/goal.ts +6 -0
- package/packages/long-horizon/src/tools/graph.ts +1 -1
- package/packages/long-horizon/src/tools/swarm.ts +3 -3
- package/packages/mcp/package.json +2 -2
- package/packages/memory/commands.ts +7 -2
- package/packages/memory/index.ts +210 -32
- package/packages/memory/package.json +3 -3
- package/packages/memory/save-session.ts +264 -0
- package/packages/memory/settings.ts +17 -0
- package/packages/memory/tools.ts +253 -203
- package/packages/notify/package.json +2 -2
- package/packages/skill-registry/README.md +53 -16
- package/packages/skill-registry/index.ts +230 -0
- package/packages/skill-registry/package.json +19 -8
- package/packages/skill-registry/src/editor.ts +206 -0
- package/packages/skill-registry/src/judge.ts +289 -0
- package/packages/skill-registry/src/registry.ts +87 -0
- package/packages/skill-registry/src/settings.ts +259 -0
- package/packages/skill-registry/src/vault.ts +80 -0
- package/packages/subagents/README.md +39 -119
- package/packages/subagents/package.json +6 -13
- package/packages/subagents/skills/subagents/SKILL.md +18 -42
- package/packages/subagents/src/agents.ts +213 -0
- package/packages/subagents/src/cards.ts +182 -0
- package/packages/subagents/src/index.ts +609 -1084
- package/packages/subagents/src/manager.ts +429 -0
- package/packages/subagents/src/profiles.ts +130 -0
- package/packages/subagents/src/transcript.ts +154 -0
- package/packages/subagents/src/ui.ts +389 -0
- package/packages/unipi/bundled.js +39756 -45569
- package/packages/unipi/index.ts +55 -10
- package/packages/updater/package.json +2 -2
- package/packages/utility/README.md +76 -69
- package/packages/utility/package.json +2 -2
- package/packages/utility/skills/image/SKILL.md +37 -0
- package/packages/utility/skills/utility/SKILL.md +17 -60
- package/packages/utility/src/answer/extract.ts +128 -0
- package/packages/utility/src/answer/index.ts +213 -0
- package/packages/utility/src/answer/reply.ts +133 -0
- package/packages/utility/src/answer/web.ts +167 -0
- package/packages/utility/src/attach/index.ts +205 -0
- package/packages/utility/src/commands.ts +38 -142
- package/packages/utility/src/diagnostics/engine.ts +50 -5
- package/packages/utility/src/image/index.ts +33 -0
- package/packages/utility/src/image/models.ts +221 -0
- package/packages/{image/src → utility/src/image}/recognize.ts +2 -2
- package/packages/utility/src/image/settings.ts +178 -0
- package/packages/{image/src/image-source.ts → utility/src/image/source.ts} +1 -1
- package/packages/utility/src/image/tools.ts +168 -0
- package/packages/utility/src/image/transports.ts +186 -0
- package/packages/utility/src/index.ts +68 -389
- package/packages/utility/src/lifecycle/cleanup.ts +116 -311
- package/packages/utility/src/rename/gate.ts +102 -0
- package/packages/utility/src/rename/index.ts +191 -0
- package/packages/utility/src/rename/session.ts +170 -0
- package/packages/utility/src/render/delegated.ts +285 -0
- package/packages/utility/src/render/harness.ts +683 -0
- package/packages/utility/src/render/parse.ts +156 -0
- package/packages/utility/src/render/pi-settings.ts +38 -0
- package/packages/utility/src/render/reply-bg.ts +307 -0
- package/packages/utility/src/render/simple.ts +724 -0
- package/packages/utility/src/render/spacing.ts +235 -0
- package/packages/utility/src/render/styled.ts +251 -0
- package/packages/utility/src/render/tools.ts +353 -0
- package/packages/utility/src/settings.ts +166 -233
- package/packages/utility/src/types.ts +1 -222
- package/packages/watchdog/index.ts +17 -6
- package/packages/watchdog/package.json +3 -3
- package/packages/watchdog/src/config.ts +3 -2
- package/packages/web-api/package.json +2 -2
- package/packages/workflow/README.md +3 -0
- package/packages/workflow/index.ts +0 -2
- package/packages/workflow/package.json +2 -2
- package/packages/workflow/src/permission/decide.ts +6 -4
- package/packages/workflow/src/permission/index.ts +17 -7
- package/packages/workflow/src/permission/settings.ts +39 -4
- package/packages/workflow/src/plan/index.ts +19 -4
- package/packages/background-tasks/extensions/delegate-child.ts +0 -1
- package/packages/background-tasks/src/context-parent-snapshot.ts +0 -142
- package/packages/background-tasks/src/context-token-budget.ts +0 -903
- package/packages/background-tasks/src/context-visible-conversation-v2.ts +0 -551
- package/packages/background-tasks/src/delegate/artifacts.ts +0 -487
- package/packages/background-tasks/src/delegate/budget.ts +0 -415
- package/packages/background-tasks/src/delegate/hook-contract-evidence.json +0 -18
- package/packages/background-tasks/src/delegate/hook-contract.ts +0 -154
- package/packages/background-tasks/src/delegate/launch.ts +0 -484
- package/packages/background-tasks/src/delegate/result-package.ts +0 -459
- package/packages/background-tasks/src/delegate/runner.ts +0 -430
- package/packages/background-tasks/src/delegate/seed.ts +0 -423
- package/packages/background-tasks/src/delegate/types.ts +0 -323
- package/packages/background-tasks/src/delegate-child-extension.ts +0 -978
- package/packages/background-tasks/src/delegate-extension.ts +0 -654
- package/packages/background-tasks/src/fixtures/delegate-context-incident.json +0 -17
- package/packages/compactor/skills/compactor-detail/SKILL.md +0 -116
- package/packages/compactor/skills/compactor-doctor/SKILL.md +0 -71
- package/packages/compactor/skills/compactor-stats/SKILL.md +0 -51
- package/packages/compactor/src/compaction/build-sections.ts +0 -76
- package/packages/compactor/src/compaction/extract/goals.ts +0 -36
- package/packages/compactor/src/compaction/extract/preferences.ts +0 -40
- package/packages/compactor/src/compaction/format.ts +0 -53
- package/packages/compactor/src/compaction/merge.ts +0 -143
- package/packages/compactor/src/config/presets.ts +0 -160
- package/packages/compactor/src/executor/executor.ts +0 -233
- package/packages/compactor/src/executor/runtime.ts +0 -115
- package/packages/compactor/src/security/evaluator.ts +0 -89
- package/packages/compactor/src/security/policy.ts +0 -96
- package/packages/compactor/src/security/scanner.ts +0 -65
- package/packages/compactor/src/session/auto-inject.ts +0 -60
- package/packages/compactor/src/session/db.ts +0 -325
- package/packages/compactor/src/session/extract.ts +0 -144
- package/packages/compactor/src/session/resume-inject.ts +0 -64
- package/packages/compactor/src/session/snapshot.ts +0 -327
- package/packages/compactor/src/tools/ctx-batch-execute.ts +0 -41
- package/packages/compactor/src/tools/ctx-execute-file.ts +0 -23
- package/packages/compactor/src/tools/ctx-execute.ts +0 -23
- package/packages/compactor/src/tools/ctx-stats.ts +0 -96
- package/packages/image/README.md +0 -99
- package/packages/image/package.json +0 -61
- package/packages/image/skills/image/SKILL.md +0 -76
- package/packages/image/src/generate.ts +0 -256
- package/packages/image/src/index.ts +0 -135
- package/packages/image/src/models.ts +0 -519
- package/packages/image/src/openai-images-api.ts +0 -282
- package/packages/image/src/register-providers.ts +0 -209
- package/packages/image/src/settings.ts +0 -173
- package/packages/image/src/tools.ts +0 -326
- package/packages/input-shortcuts/src/clipboard.ts +0 -119
- package/packages/kanboard/src/runner.ts +0 -817
- package/packages/skill-registry/skills/auto/SKILL.md +0 -465
- package/packages/skill-registry/skills/brainstorm/SKILL.md +0 -219
- package/packages/skill-registry/skills/chore-create/SKILL.md +0 -315
- package/packages/skill-registry/skills/chore-execute/SKILL.md +0 -314
- package/packages/skill-registry/skills/consolidate/SKILL.md +0 -142
- package/packages/skill-registry/skills/consultant/SKILL.md +0 -97
- package/packages/skill-registry/skills/debug/SKILL.md +0 -228
- package/packages/skill-registry/skills/document/SKILL.md +0 -120
- package/packages/skill-registry/skills/fix/SKILL.md +0 -212
- package/packages/skill-registry/skills/gather-context/SKILL.md +0 -145
- package/packages/skill-registry/skills/plan/SKILL.md +0 -231
- package/packages/skill-registry/skills/quick-fix/SKILL.md +0 -135
- package/packages/skill-registry/skills/quick-work/SKILL.md +0 -110
- package/packages/skill-registry/skills/research/SKILL.md +0 -251
- package/packages/skill-registry/skills/review-work/SKILL.md +0 -187
- package/packages/skill-registry/skills/scan-issues/SKILL.md +0 -195
- package/packages/skill-registry/skills/work/SKILL.md +0 -218
- package/packages/skill-registry/skills/worktree-create/SKILL.md +0 -69
- package/packages/skill-registry/skills/worktree-list/SKILL.md +0 -78
- package/packages/skill-registry/skills/worktree-merge/SKILL.md +0 -89
- package/packages/subagents/agents/delegate.md +0 -14
- package/packages/subagents/agents/oracle.md +0 -78
- package/packages/subagents/agents/researcher.md +0 -52
- package/packages/subagents/agents/reviewer.md +0 -80
- package/packages/subagents/agents/scout.md +0 -50
- package/packages/subagents/agents/worker.md +0 -59
- package/packages/subagents/prompts/council.md +0 -48
- package/packages/subagents/prompts/gather-context-and-clarify.md +0 -13
- package/packages/subagents/prompts/parallel-cleanup.md +0 -59
- package/packages/subagents/prompts/parallel-research.md +0 -50
- package/packages/subagents/prompts/parallel-review.md +0 -54
- package/packages/subagents/prompts/review-loop.md +0 -43
- package/packages/subagents/skills/council-mode/SKILL.md +0 -230
- package/packages/subagents/skills/subagents/references/constraints-and-recipes.md +0 -259
- package/packages/subagents/skills/subagents/references/execution-controls.md +0 -454
- package/packages/subagents/skills/subagents/references/management-authoring-rpc.md +0 -161
- package/packages/subagents/skills/subagents/references/multi-lane-orchestration.md +0 -39
- package/packages/subagents/skills/subagents/references/prompting-and-roles.md +0 -267
- package/packages/subagents/src/acceptance.ts +0 -331
- package/packages/subagents/src/agent-manager.ts +0 -405
- package/packages/subagents/src/agent-memory.ts +0 -300
- package/packages/subagents/src/agent-overrides.ts +0 -183
- package/packages/subagents/src/agent-runner.ts +0 -271
- package/packages/subagents/src/async-runner.ts +0 -422
- package/packages/subagents/src/authority-policy.ts +0 -47
- package/packages/subagents/src/budgets.ts +0 -285
- package/packages/subagents/src/child-safety.ts +0 -140
- package/packages/subagents/src/config.ts +0 -249
- package/packages/subagents/src/conversation-viewer.ts +0 -281
- package/packages/subagents/src/core-compat.ts +0 -94
- package/packages/subagents/src/custom-agents.ts +0 -343
- package/packages/subagents/src/file-system-retry.ts +0 -50
- package/packages/subagents/src/fleet-data.ts +0 -105
- package/packages/subagents/src/fleet-view.ts +0 -322
- package/packages/subagents/src/foreground-detach.ts +0 -59
- package/packages/subagents/src/fork-context.ts +0 -285
- package/packages/subagents/src/global.d.ts +0 -7
- package/packages/subagents/src/guide.ts +0 -129
- package/packages/subagents/src/mission-state.ts +0 -133
- package/packages/subagents/src/mission-store.ts +0 -436
- package/packages/subagents/src/output-limits.ts +0 -142
- package/packages/subagents/src/parity-types.ts +0 -315
- package/packages/subagents/src/pi-args.ts +0 -167
- package/packages/subagents/src/result-files.ts +0 -232
- package/packages/subagents/src/result-watcher.ts +0 -221
- package/packages/subagents/src/retained-children.ts +0 -176
- package/packages/subagents/src/run-fanout-budget.ts +0 -356
- package/packages/subagents/src/scheduled-runs.ts +0 -349
- package/packages/subagents/src/schemas.ts +0 -263
- package/packages/subagents/src/slash-commands.ts +0 -80
- package/packages/subagents/src/supervisor-channel.ts +0 -249
- package/packages/subagents/src/tool-handler.ts +0 -1144
- package/packages/subagents/src/types.ts +0 -238
- package/packages/subagents/src/widget.ts +0 -457
- package/packages/subagents/src/workflow-script.ts +0 -737
- package/packages/subagents/src/workflow-worker.ts +0 -384
- package/packages/subagents/src/worktree.ts +0 -614
- package/packages/utility/src/analytics/collector.ts +0 -293
- package/packages/utility/src/info-screen.ts +0 -80
- package/packages/utility/src/lifecycle/process.ts +0 -162
- package/packages/utility/src/prefix-cache.ts +0 -263
- package/packages/utility/src/skill-discovery.ts +0 -542
- package/packages/utility/src/tools/env.ts +0 -113
- package/packages/utility/src/tui/name-badge-state.ts +0 -315
- package/packages/utility/src/tui/name-badge.ts +0 -109
- /package/packages/{subagents/src → core/src/child-agent}/pi-spawn.ts +0 -0
|
@@ -35,13 +35,8 @@ export interface IconSet {
|
|
|
35
35
|
directory: string;
|
|
36
36
|
|
|
37
37
|
// Compactor segments
|
|
38
|
-
sessionEvents: string;
|
|
39
|
-
compactions: string;
|
|
40
|
-
tokensSaved: string;
|
|
41
|
-
compressionRatio: string;
|
|
42
38
|
indexedDocs: string;
|
|
43
39
|
sandboxRuns: string;
|
|
44
|
-
searchQueries: string;
|
|
45
40
|
|
|
46
41
|
// Memory segments
|
|
47
42
|
projectCount: string;
|
|
@@ -106,13 +101,8 @@ export const NERD_ICONS: IconSet = {
|
|
|
106
101
|
thinkingLevel: "\uF400", //
|
|
107
102
|
|
|
108
103
|
// Compactor
|
|
109
|
-
sessionEvents: "\uEA86", //
|
|
110
|
-
compactions: "\u{F0C8F}", //
|
|
111
|
-
tokensSaved: "\uF155", // (kept — missing from customization)
|
|
112
|
-
compressionRatio:"\u{F0C8F}", //
|
|
113
104
|
indexedDocs: "\u{F0219}", //
|
|
114
105
|
sandboxRuns: "\uF233", //
|
|
115
|
-
searchQueries: "\uF002", //
|
|
116
106
|
|
|
117
107
|
// Memory
|
|
118
108
|
projectCount: "\uEE9C", //
|
|
@@ -177,13 +167,8 @@ export const EMOJI_ICONS: IconSet = {
|
|
|
177
167
|
directory: "📁",
|
|
178
168
|
|
|
179
169
|
// Compactor
|
|
180
|
-
sessionEvents: "📈",
|
|
181
|
-
compactions: "🗜️",
|
|
182
|
-
tokensSaved: "💲",
|
|
183
|
-
compressionRatio:"📐",
|
|
184
170
|
indexedDocs: "📑",
|
|
185
171
|
sandboxRuns: "▶️",
|
|
186
|
-
searchQueries: "🔍",
|
|
187
172
|
|
|
188
173
|
// Memory
|
|
189
174
|
projectCount: "🧠",
|
|
@@ -248,13 +233,8 @@ export const TEXT_ICONS: IconSet = {
|
|
|
248
233
|
directory: "DIR",
|
|
249
234
|
|
|
250
235
|
// Compactor
|
|
251
|
-
sessionEvents: "EVT",
|
|
252
|
-
compactions: "CMP",
|
|
253
|
-
tokensSaved: "SVD",
|
|
254
|
-
compressionRatio:"RAT",
|
|
255
236
|
indexedDocs: "IDX",
|
|
256
237
|
sandboxRuns: "SBX",
|
|
257
|
-
searchQueries: "QRY",
|
|
258
238
|
|
|
259
239
|
// Memory
|
|
260
240
|
projectCount: "MEM",
|
|
@@ -1,23 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @pi-unipi/footer — Compactor
|
|
2
|
+
* @pi-unipi/footer — Compactor segment
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
* tokens_saved, compression_ratio, sandbox_runs, search_queries.
|
|
4
|
+
* One dense, icon-free segment, shown once the session has compacted:
|
|
6
5
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
6
|
+
* cmp 4× 39k→13k · 3m
|
|
7
|
+
*
|
|
8
|
+
* count, tokens before → after across all compactions, time since the last.
|
|
9
|
+
* Read from the session branch (Pi's compaction entries).
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
12
|
import type { FooterSegment, FooterSegmentContext, RenderedSegment } from "../types.js";
|
|
13
|
-
import { applyColor
|
|
14
|
-
import { getIcon } from "../rendering/icons.js";
|
|
15
|
-
import { isSegmentEnabled } from "../config.js";
|
|
16
|
-
|
|
17
|
-
function withIcon(segmentId: string, text: string): string {
|
|
18
|
-
const icon = getIcon(segmentId);
|
|
19
|
-
return icon ? `${icon} ${text}` : text;
|
|
20
|
-
}
|
|
13
|
+
import { applyColor } from "../rendering/theme.js";
|
|
21
14
|
|
|
22
15
|
function formatTokens(n: number): string {
|
|
23
16
|
if (n < 1000) return n.toString();
|
|
@@ -26,149 +19,66 @@ function formatTokens(n: number): string {
|
|
|
26
19
|
return `${(n / 1000000).toFixed(1)}M`;
|
|
27
20
|
}
|
|
28
21
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
22
|
+
function ago(ms: number): string {
|
|
23
|
+
const s = Math.max(0, Math.round(ms / 1000));
|
|
24
|
+
if (s < 60) return "now";
|
|
25
|
+
if (s < 3600) return `${Math.round(s / 60)}m`;
|
|
26
|
+
if (s < 86400) return `${Math.round(s / 3600)}h`;
|
|
27
|
+
return `${Math.round(s / 86400)}d`;
|
|
32
28
|
}
|
|
33
29
|
|
|
34
|
-
/**
|
|
35
|
-
function
|
|
36
|
-
const
|
|
37
|
-
|
|
30
|
+
/** Tokens left after a compaction: our recorded estimate, else the summary size. */
|
|
31
|
+
function tokensAfterOf(entry: any, before: number): number {
|
|
32
|
+
const recorded = Number(entry?.details?.tokensAfter ?? 0);
|
|
33
|
+
if (recorded > 0) return Math.min(recorded, before);
|
|
34
|
+
const summaryChars = typeof entry?.summary === "string" ? entry.summary.length : 0;
|
|
35
|
+
return Math.min(before, Math.ceil(summaryChars / 4));
|
|
38
36
|
}
|
|
39
37
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
const sm = getSessionManager(ctx);
|
|
43
|
-
if (!sm || typeof sm.getBranch !== "function") return [];
|
|
38
|
+
function branchOf(ctx: FooterSegmentContext): any[] {
|
|
39
|
+
const sm = (ctx.piContext as Record<string, unknown> | undefined)?.sessionManager as any;
|
|
44
40
|
try {
|
|
45
|
-
return sm.getBranch() ?? [];
|
|
41
|
+
return typeof sm?.getBranch === "function" ? (sm.getBranch() ?? []) : [];
|
|
46
42
|
} catch {
|
|
47
43
|
return [];
|
|
48
44
|
}
|
|
49
45
|
}
|
|
50
46
|
|
|
51
|
-
function
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
47
|
+
export function compactionSummary(branch: readonly any[], now = Date.now()): { count: number; before: number; after: number; lastAt?: number } {
|
|
48
|
+
let count = 0;
|
|
49
|
+
let before = 0;
|
|
50
|
+
let after = 0;
|
|
51
|
+
let lastAt: number | undefined;
|
|
52
|
+
for (const e of branch) {
|
|
53
|
+
if (e?.type !== "compaction") continue;
|
|
54
|
+
count++;
|
|
55
|
+
const b = Number(e.tokensBefore ?? 0);
|
|
56
|
+
before += b;
|
|
57
|
+
after += tokensAfterOf(e, b);
|
|
58
|
+
const at = Date.parse(e.timestamp ?? "");
|
|
59
|
+
if (Number.isFinite(at) && at <= now) lastAt = at;
|
|
59
60
|
}
|
|
60
|
-
|
|
61
|
-
const content = withIcon("sessionEvents", `${count}`);
|
|
62
|
-
return { content: applyColor("compactor", content, ctx.theme, ctx.colors), visible: true };
|
|
61
|
+
return { count, before, after, ...(lastAt != null ? { lastAt } : {}) };
|
|
63
62
|
}
|
|
64
63
|
|
|
65
64
|
function renderCompactionsSegment(ctx: FooterSegmentContext): RenderedSegment {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
if (compactionCount === 0) {
|
|
76
|
-
if (isSegmentEnabled("compactor", "compactions")) {
|
|
77
|
-
return { content: mutedPlaceholder(withIcon("compactions", "0")), visible: true };
|
|
78
|
-
}
|
|
79
|
-
return hidden();
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
const content = withIcon("compactions", `${compactionCount}`);
|
|
83
|
-
return { content: applyColor("compactor", content, ctx.theme, ctx.colors), visible: true };
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
function renderTokensSavedSegment(ctx: FooterSegmentContext): RenderedSegment {
|
|
87
|
-
// Sum tokens saved from compaction entries.
|
|
88
|
-
// Pi's CompactionEntry has tokensBefore (total tokens before compaction).
|
|
89
|
-
// Compaction keeps ~10-15% of context, so tokens saved ≈ tokensBefore × 0.85.
|
|
90
|
-
const events = getSessionEvents(ctx);
|
|
91
|
-
let tokensSaved = 0;
|
|
92
|
-
let hasCompaction = false;
|
|
93
|
-
for (const e of events) {
|
|
94
|
-
if (!e || typeof e !== "object") continue;
|
|
95
|
-
if (e.type === "compaction") {
|
|
96
|
-
hasCompaction = true;
|
|
97
|
-
const tokensBefore = Number(e.tokensBefore ?? 0);
|
|
98
|
-
// Estimate tokens kept at ~12% (compaction summary + recent messages)
|
|
99
|
-
const tokensAfter = Math.round(tokensBefore * 0.12);
|
|
100
|
-
tokensSaved += Math.max(0, tokensBefore - tokensAfter);
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
if (!hasCompaction || tokensSaved === 0) return hidden();
|
|
104
|
-
|
|
105
|
-
const content = withIcon("tokensSaved", formatTokens(tokensSaved));
|
|
106
|
-
return { content: applyColor("compactor", content, ctx.theme, ctx.colors), visible: true };
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
function renderCompressionRatioSegment(ctx: FooterSegmentContext): RenderedSegment {
|
|
110
|
-
// Calculate compression ratio from Pi's CompactionEntry.tokensBefore.
|
|
111
|
-
// Compaction keeps ~12% of context, giving ~8:1 compression.
|
|
112
|
-
const events = getSessionEvents(ctx);
|
|
113
|
-
let totalBefore = 0;
|
|
114
|
-
let totalAfter = 0;
|
|
115
|
-
for (const e of events) {
|
|
116
|
-
if (!e || typeof e !== "object") continue;
|
|
117
|
-
if (e.type === "compaction") {
|
|
118
|
-
const before = Number(e.tokensBefore ?? 0);
|
|
119
|
-
if (before > 0) {
|
|
120
|
-
totalBefore += before;
|
|
121
|
-
totalAfter += Math.round(before * 0.12);
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
if (totalBefore === 0 || totalAfter === 0) return hidden();
|
|
126
|
-
|
|
127
|
-
const ratio = totalBefore / totalAfter;
|
|
128
|
-
const content = withIcon("compressionRatio", `${ratio.toFixed(1)}x`);
|
|
129
|
-
return { content: applyColor("compactor", content, ctx.theme, ctx.colors), visible: true };
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
function renderSandboxRunsSegment(ctx: FooterSegmentContext): RenderedSegment {
|
|
133
|
-
// Count sandbox events from session manager branch
|
|
134
|
-
const events = getSessionEvents(ctx);
|
|
135
|
-
let sandboxCount = 0;
|
|
136
|
-
for (const e of events) {
|
|
137
|
-
if (!e || typeof e !== "object") continue;
|
|
138
|
-
// Count tool calls that are sandbox/execute tools
|
|
139
|
-
const name = String((e as any).name ?? "").toLowerCase();
|
|
140
|
-
if (name.includes("sandbox") || name.includes("ctx_execute") || name === "execute") {
|
|
141
|
-
sandboxCount++;
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
if (sandboxCount === 0) return hidden();
|
|
145
|
-
|
|
146
|
-
const content = withIcon("sandboxRuns", `${sandboxCount}`);
|
|
147
|
-
return { content: applyColor("compactor", content, ctx.theme, ctx.colors), visible: true };
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
function renderSearchQueriesSegment(ctx: FooterSegmentContext): RenderedSegment {
|
|
151
|
-
// Count search events from session manager branch
|
|
152
|
-
const events = getSessionEvents(ctx);
|
|
153
|
-
let searchCount = 0;
|
|
154
|
-
for (const e of events) {
|
|
155
|
-
if (!e || typeof e !== "object") continue;
|
|
156
|
-
const name = String((e as any).name ?? "").toLowerCase();
|
|
157
|
-
if (name.includes("search") || name.includes("ctx_search")) {
|
|
158
|
-
searchCount++;
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
if (searchCount === 0) return hidden();
|
|
162
|
-
|
|
163
|
-
const content = withIcon("searchQueries", `${searchCount}`);
|
|
164
|
-
return { content: applyColor("compactor", content, ctx.theme, ctx.colors), visible: true };
|
|
65
|
+
const s = compactionSummary(branchOf(ctx));
|
|
66
|
+
if (s.count === 0) return { content: "", visible: false };
|
|
67
|
+
const dim = (t: string) => `\x1b[2m${t}\x1b[22m`;
|
|
68
|
+
const sizes = s.before > 0 ? ` ${formatTokens(s.before)}→${formatTokens(s.after)}` : "";
|
|
69
|
+
const age = s.lastAt != null ? dim(` · ${ago(Date.now() - s.lastAt)}`) : "";
|
|
70
|
+
const content = `${dim("cmp")} ${applyColor("compactor", `${s.count}×${sizes}`, ctx.theme, ctx.colors)}${age}`;
|
|
71
|
+
return { content, visible: true };
|
|
165
72
|
}
|
|
166
73
|
|
|
167
74
|
export const COMPACTOR_SEGMENTS: FooterSegment[] = [
|
|
168
|
-
{
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
75
|
+
{
|
|
76
|
+
id: "compactions",
|
|
77
|
+
label: "Compactions",
|
|
78
|
+
shortLabel: "CMP",
|
|
79
|
+
description: "Compactions this session: count, tokens before → after, time since the last (hidden until the first)",
|
|
80
|
+
zone: "center",
|
|
81
|
+
render: renderCompactionsSegment,
|
|
82
|
+
defaultShow: true,
|
|
83
|
+
},
|
|
174
84
|
];
|
|
@@ -23,7 +23,6 @@ const STATUS_DISPLAY: Record<string, { short: string; segmentId: string }> = {
|
|
|
23
23
|
workflow: { short: "WF", segmentId: "currentCommand" },
|
|
24
24
|
ralph: { short: "RL", segmentId: "activeLoops" },
|
|
25
25
|
memory: { short: "MEM", segmentId: "projectCount" },
|
|
26
|
-
compactor: { short: "CMP", segmentId: "compactions" },
|
|
27
26
|
mcp: { short: "MCP", segmentId: "serversTotal" },
|
|
28
27
|
notify: { short: "NTF", segmentId: "platformsEnabled" },
|
|
29
28
|
kanboard: { short: "KB", segmentId: "docsCount" },
|
|
@@ -23,7 +23,7 @@ pi's extension and RPC APIs natively.
|
|
|
23
23
|
│ Model key openrouter/deepseek/deepseek-v4.1-flash │
|
|
24
24
|
│ │
|
|
25
25
|
│ ✱ New ✱ Promotion ✱ Beta · Pairs frontier intelligence with cost-efficient execution │
|
|
26
|
-
│↑↓ select · tab lead · ←→ effort · ↵ confirm · esc
|
|
26
|
+
│↑↓ select · tab lead · ←→ lead effort · space → side · ↵ confirm · esc │
|
|
27
27
|
╰───────────────────────────────────────────────────────────────────────╯
|
|
28
28
|
```
|
|
29
29
|
|
|
@@ -41,6 +41,11 @@ pi's extension and RPC APIs natively.
|
|
|
41
41
|
- **`tab`** on the Fusion row cycles focus: effort → lead → sidekick
|
|
42
42
|
(`shift+tab` reverses). Focused columns open an inline dropdown over the
|
|
43
43
|
preset lists; `↵` applies, `esc` collapses.
|
|
44
|
+
- **`space`** on the Fusion row toggles which side `←`/`→` adjusts: lead
|
|
45
|
+
effort (default) ↔ sidekick effort. The row shows both levels (`Lead … ▸High`,
|
|
46
|
+
`Sidekick … Low` — `▸` marks the side `←`/`→` moves) and the hint line names
|
|
47
|
+
the target. A changed sidekick effort reaches a running sidekick over rpc
|
|
48
|
+
(`set_thinking_level`) and lands in the spawn args for the next process.
|
|
44
49
|
- **Price panel**: the highlighted model's blended price is marked on a
|
|
45
50
|
logarithmic red→orange→yellow→green→cyan→blue→violet slider. Fusion shows
|
|
46
51
|
`Input`, `Cached input`, `Output`, `Sidekick input`, `Sidekick cached input`,
|
|
@@ -109,9 +114,14 @@ notification and any follow-up turn, so the report is not released at an
|
|
|
109
114
|
intermediate checkpoint. If a prompt arrives while the child is processing,
|
|
110
115
|
Fusion retries it once with pi's `followUp` streaming behavior. Sidekick work
|
|
111
116
|
renders as ordinary tool activity — handoff ids, `agent_id`, and
|
|
112
|
-
`read_subagent` protocol text never reach the terminal. Sidekick
|
|
113
|
-
|
|
114
|
-
|
|
117
|
+
`read_subagent` protocol text never reach the terminal. Sidekick steps draw in
|
|
118
|
+
the active render style — mcode rows in simple, `◆` + guttered output in
|
|
119
|
+
advanced, pi's own finished-call card (its exported `ToolExecutionComponent` +
|
|
120
|
+
per-tool defs) in regular — each line marked as sidekick-origin by a `▏` rail
|
|
121
|
+
on the custom-message background. Consecutive steps join into one rail block
|
|
122
|
+
with no blank separator; in simple mode a run of tool steps draws the same
|
|
123
|
+
`├…├…└` tree the lead's tools get, and prose steps stay `●`-anchored inside
|
|
124
|
+
the block. While the sidekick works and the lead's turn is over, an animated
|
|
115
125
|
`sidekick working` line above the editor shows the live tool count and elapsed
|
|
116
126
|
time until the report lands.
|
|
117
127
|
`read_subagent({agent_id?, block?, timeout?})` reads or waits for a handoff.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pi-unipi/fusion",
|
|
3
|
-
"version": "3.0.0-alpha.
|
|
3
|
+
"version": "3.0.0-alpha.21",
|
|
4
4
|
"description": "Devin-style model picker, fusion presets (lead + sidekick), and Local Fusion runtime for UniPi",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.ts",
|
|
@@ -32,8 +32,9 @@
|
|
|
32
32
|
"access": "public"
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"@pi-unipi/core": "3.0.0-alpha.
|
|
36
|
-
"@pi-unipi/subagents": "3.0.0-alpha.
|
|
35
|
+
"@pi-unipi/core": "3.0.0-alpha.21",
|
|
36
|
+
"@pi-unipi/subagents": "3.0.0-alpha.21",
|
|
37
|
+
"@pi-unipi/utility": "3.0.0-alpha.21"
|
|
37
38
|
},
|
|
38
39
|
"peerDependencies": {
|
|
39
40
|
"@earendil-works/pi-ai": "^0.87.1",
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { leadExtensionArgs } from "@pi-unipi/core/child-agent.js";
|
|
@@ -16,13 +16,14 @@
|
|
|
16
16
|
import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
17
17
|
import type { Api, Model } from "@earendil-works/pi-ai";
|
|
18
18
|
import type { AutocompleteProvider, AutocompleteSuggestions } from "@earendil-works/pi-tui";
|
|
19
|
-
import { createSpinnerLine, registerCommandRunner, setHerdrWorking, setSharedFusionStatus, stateDir, UNIPI_PREFIX, HUB_OVERLAY_OPTIONS } from "@pi-unipi/core";
|
|
19
|
+
import { createSpinnerLine, harnessToolResultDetails, registerCommandRunner, setHerdrWorking, setSharedFusionStatus, stateDir, UNIPI_PREFIX, HUB_OVERLAY_OPTIONS, HUB_PICKER_OVERLAY_OPTIONS } from "@pi-unipi/core";
|
|
20
20
|
import { join } from "node:path";
|
|
21
21
|
import {
|
|
22
22
|
effortLabel,
|
|
23
23
|
globalPresetPath,
|
|
24
24
|
isEffortLevel,
|
|
25
25
|
loadPreset,
|
|
26
|
+
mirrorStartupFromPi,
|
|
26
27
|
modelKey,
|
|
27
28
|
pushRecent,
|
|
28
29
|
saveCuration,
|
|
@@ -39,7 +40,10 @@ import { estimateSavings } from "./savings.js";
|
|
|
39
40
|
import { EDIT_NUDGE, bashNudge, leadPolicy, sidekickSystemPrompt, type FusionIdentity } from "./prompts.js";
|
|
40
41
|
import { isTrivialShell, BASH_NUDGE_EVERY } from "./nudge.js";
|
|
41
42
|
import { registerFusionTools } from "./tools.js";
|
|
42
|
-
import { duration } from "./transcript.js";
|
|
43
|
+
import { duration, renderSidekickStep } from "./transcript.js";
|
|
44
|
+
import { persistDefaultModel, piSettingsPath } from "./pi-settings.js";
|
|
45
|
+
import { ensureReadSubagentTool, setReadSubagentDemand } from "@pi-unipi/core/child-agent.js";
|
|
46
|
+
import { readFileSync } from "node:fs";
|
|
43
47
|
|
|
44
48
|
export const MODEL_COMMAND = `${UNIPI_PREFIX}model`;
|
|
45
49
|
|
|
@@ -125,6 +129,15 @@ export function createSidekickWakeLine(deps: {
|
|
|
125
129
|
|
|
126
130
|
type Registry = { getAvailable(): Model<Api>[]; find(provider: string, id: string): Model<Api> | undefined };
|
|
127
131
|
|
|
132
|
+
/** Keep /unipi:settings → Fusion → Startup showing pi's real default. */
|
|
133
|
+
function mirrorStartup(cwd: string): void {
|
|
134
|
+
try {
|
|
135
|
+
mirrorStartupFromPi(cwd);
|
|
136
|
+
} catch {
|
|
137
|
+
/* display mirror only */
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
128
141
|
function registryOf(ctx: ExtensionContext): Registry | undefined {
|
|
129
142
|
const r = (ctx as unknown as { modelRegistry?: Registry }).modelRegistry;
|
|
130
143
|
return r && typeof r.getAvailable === "function" ? r : undefined;
|
|
@@ -133,7 +146,11 @@ function registryOf(ctx: ExtensionContext): Registry | undefined {
|
|
|
133
146
|
/** Key-based lookup (provider ids can contain slashes, so splitModelKey+find is unreliable). */
|
|
134
147
|
const modelBykey = new Map<string, Model<Api>>();
|
|
135
148
|
function findModel(reg: Registry | undefined, key: string): Model<Api> | undefined {
|
|
136
|
-
|
|
149
|
+
// Refill on a miss too: providers (e.g. bridges) can register models after the first lookup.
|
|
150
|
+
if (!modelBykey.has(key) && reg) {
|
|
151
|
+
modelBykey.clear();
|
|
152
|
+
for (const m of reg.getAvailable()) modelBykey.set(modelKey(m), m);
|
|
153
|
+
}
|
|
137
154
|
return modelBykey.get(key);
|
|
138
155
|
}
|
|
139
156
|
|
|
@@ -184,6 +201,27 @@ export function createModelBoostProvider(current: AutocompleteProvider): Autocom
|
|
|
184
201
|
};
|
|
185
202
|
}
|
|
186
203
|
|
|
204
|
+
export const FUSION_TOOLS = ["sidekick"] as const;
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Adds the fusion tools to pi's active set while Fusion is active, removes
|
|
208
|
+
* them otherwise — touching ONLY `sidekick`/`read_subagent`, never another
|
|
209
|
+
* module's tools. Compares against the live active set (pi rebuilds it on
|
|
210
|
+
* session changes), and skips `setActiveTools` when nothing would change.
|
|
211
|
+
*/
|
|
212
|
+
export function makeFusionToolSync(pi: Pick<ExtensionAPI, "getActiveTools" | "setActiveTools">): (want: boolean) => void {
|
|
213
|
+
return (want: boolean) => {
|
|
214
|
+
const current = pi.getActiveTools();
|
|
215
|
+
if (FUSION_TOOLS.every((tool) => current.includes(tool) === want)) return;
|
|
216
|
+
const set = new Set(current);
|
|
217
|
+
for (const tool of FUSION_TOOLS) {
|
|
218
|
+
if (want) set.add(tool);
|
|
219
|
+
else set.delete(tool);
|
|
220
|
+
}
|
|
221
|
+
pi.setActiveTools([...set]);
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
|
|
187
225
|
export default function fusionExtension(pi: ExtensionAPI): void {
|
|
188
226
|
if (process.env.UNIPI_FUSION_CHILD === "1") return;
|
|
189
227
|
|
|
@@ -203,6 +241,16 @@ export default function fusionExtension(pi: ExtensionAPI): void {
|
|
|
203
241
|
onHeld: (label) => setHerdrWorking(pi, "fusion-sidekick", label),
|
|
204
242
|
});
|
|
205
243
|
|
|
244
|
+
const syncTools = makeFusionToolSync(pi);
|
|
245
|
+
// `read_subagent` presence is demand-driven across owners (core registry):
|
|
246
|
+
// fusion wants it only while a Fusion pair is active.
|
|
247
|
+
const syncFusionTools = () => {
|
|
248
|
+
const fusion = active?.kind === "fusion";
|
|
249
|
+
syncTools(fusion);
|
|
250
|
+
setReadSubagentDemand(pi, "fusion", fusion);
|
|
251
|
+
};
|
|
252
|
+
ensureReadSubagentTool(pi);
|
|
253
|
+
|
|
206
254
|
function identity(ctx: ExtensionContext): FusionIdentity {
|
|
207
255
|
const reg = registryOf(ctx);
|
|
208
256
|
const names = (k: string) => findModel(reg, k)?.name || splitModelKey(k)?.id || k;
|
|
@@ -232,6 +280,8 @@ export default function fusionExtension(pi: ExtensionAPI): void {
|
|
|
232
280
|
// the working lead lit, the sidekick muted.
|
|
233
281
|
setSharedFusionStatus({
|
|
234
282
|
leadName: names(active.lead),
|
|
283
|
+
leadKey: active.lead,
|
|
284
|
+
sidekickKey: active.sidekick,
|
|
235
285
|
leadEffort: active.leadEffort ?? "",
|
|
236
286
|
sidekickName: names(active.sidekick),
|
|
237
287
|
sidekickEffort: active.sidekickEffort ?? "",
|
|
@@ -268,6 +318,17 @@ export default function fusionExtension(pi: ExtensionAPI): void {
|
|
|
268
318
|
sessionFile: sidekickSessionPath(leadSessionId(ctx)),
|
|
269
319
|
systemPrompt: sidekickSystemPrompt(identity(ctx)),
|
|
270
320
|
onProgress: () => publishStatusLater(),
|
|
321
|
+
onStep: (step) => {
|
|
322
|
+
try {
|
|
323
|
+
// Group per handoff so resumed handoffs render as separate panels
|
|
324
|
+
// even with no lead turn between them; old entries without a
|
|
325
|
+
// group fall back to the shared "sidekick" run.
|
|
326
|
+
const handoffId = runtime?.latest()?.id;
|
|
327
|
+
pi.appendEntry("sidekick-step", { ...step, group: `sidekick:${handoffId ?? "default"}`, label: "Sidekick" });
|
|
328
|
+
} catch {
|
|
329
|
+
/* entry rendering never affects the handoff */
|
|
330
|
+
}
|
|
331
|
+
},
|
|
271
332
|
});
|
|
272
333
|
}
|
|
273
334
|
return runtime;
|
|
@@ -293,6 +354,14 @@ export default function fusionExtension(pi: ExtensionAPI): void {
|
|
|
293
354
|
return `Sidekick tokens: in ${String(runtime.usage.input)} · out ${String(runtime.usage.output)} · cached ${String(runtime.usage.cacheRead)} · cache write ${String(runtime.usage.cacheWrite)}\nSidekick cost: $${savings.sidekickUsd.toFixed(2)} · at lead prices: $${savings.atLeadUsd.toFixed(2)} · saved: $${savings.savedUsd.toFixed(2)}\nHandoffs: ${String(runtime.reports.size)} · runtime alive: ${String(runtime.isAlive())} · busy: ${String(runtime.isBusy())}${pricing}`;
|
|
294
355
|
}
|
|
295
356
|
|
|
357
|
+
pi.registerEntryRenderer("sidekick-step", (entry: { data?: { group?: string; label?: string } }, options: { expanded?: boolean }, theme) =>
|
|
358
|
+
renderSidekickStep(
|
|
359
|
+
entry.data as never,
|
|
360
|
+
options.expanded === true,
|
|
361
|
+
theme as never,
|
|
362
|
+
{ group: entry.data?.group ?? "sidekick", label: entry.data?.label },
|
|
363
|
+
));
|
|
364
|
+
|
|
296
365
|
registerFusionTools(pi, {
|
|
297
366
|
getRuntime,
|
|
298
367
|
onReport: (ctx) => publishStatusLater(ctx),
|
|
@@ -304,7 +373,19 @@ export default function fusionExtension(pi: ExtensionAPI): void {
|
|
|
304
373
|
description: "Estimated Fusion savings (sidekick tokens priced at lead rates)",
|
|
305
374
|
handler: async (_args, ctx) => ctx.ui.notify(savingsStats(ctx), "info"),
|
|
306
375
|
});
|
|
307
|
-
|
|
376
|
+
// Lead policy rides as a named system-prompt SECTION so pi records the
|
|
377
|
+
// section diff in the transcript (docs/extensions.md prefers sections over
|
|
378
|
+
// replacing `systemPrompt`, which nukes the cached prefix). The section is
|
|
379
|
+
// present only while Fusion is active.
|
|
380
|
+
pi.on("before_agent_start", (event, ctx) => {
|
|
381
|
+
syncFusionTools(); // safety net: re-sync after any module re-juggled tools
|
|
382
|
+
if (active?.kind === "fusion") {
|
|
383
|
+
event.systemPromptOptions.sections["fusion-lead-policy"] = leadPolicy(identity(ctx));
|
|
384
|
+
} else {
|
|
385
|
+
delete event.systemPromptOptions.sections["fusion-lead-policy"];
|
|
386
|
+
}
|
|
387
|
+
return undefined;
|
|
388
|
+
});
|
|
308
389
|
pi.on("turn_start", () => {
|
|
309
390
|
editNudgedThisTurn = false;
|
|
310
391
|
});
|
|
@@ -324,16 +405,34 @@ export default function fusionExtension(pi: ExtensionAPI): void {
|
|
|
324
405
|
if (toolName === "edit" || toolName === "write") {
|
|
325
406
|
if (editNudgedThisTurn) return;
|
|
326
407
|
editNudgedThisTurn = true;
|
|
327
|
-
return {
|
|
408
|
+
return {
|
|
409
|
+
content: [...event.content, { type: "text" as const, text: EDIT_NUDGE }],
|
|
410
|
+
details: harnessToolResultDetails(
|
|
411
|
+
(event as { details?: unknown }).details,
|
|
412
|
+
{ source: "Fusion", title: "Delegate edits", synopsis: "Direct edit instead of sidekick delegation", severity: "warning" },
|
|
413
|
+
"boundary",
|
|
414
|
+
EDIT_NUDGE,
|
|
415
|
+
),
|
|
416
|
+
};
|
|
328
417
|
}
|
|
329
418
|
if (toolName !== "bash") return;
|
|
330
419
|
const command = typeof event.input.command === "string" ? event.input.command : "";
|
|
331
420
|
if (isTrivialShell(command)) return;
|
|
332
421
|
bashStreak += 1;
|
|
333
422
|
if (bashStreak < BASH_NUDGE_EVERY) return;
|
|
334
|
-
const
|
|
423
|
+
const annotation = bashNudge(bashStreak);
|
|
424
|
+
const synopsis = "Non-trivial shell work since last handoff";
|
|
425
|
+
const content = [...event.content, { type: "text" as const, text: annotation }];
|
|
335
426
|
bashStreak = 0;
|
|
336
|
-
return {
|
|
427
|
+
return {
|
|
428
|
+
content,
|
|
429
|
+
details: harnessToolResultDetails(
|
|
430
|
+
(event as { details?: unknown }).details,
|
|
431
|
+
{ source: "Fusion", title: "Delegate shell work", synopsis, severity: "warning" },
|
|
432
|
+
"boundary",
|
|
433
|
+
annotation,
|
|
434
|
+
),
|
|
435
|
+
};
|
|
337
436
|
});
|
|
338
437
|
|
|
339
438
|
async function applyResult(ctx: ExtensionContext, result: PickerResult, preset: FusionPreset, loaded: { globalPath: string; projectPath: string; hasProjectLayer: boolean }): Promise<void> {
|
|
@@ -352,6 +451,16 @@ export default function fusionExtension(pi: ExtensionAPI): void {
|
|
|
352
451
|
return;
|
|
353
452
|
}
|
|
354
453
|
if (!samePair) stopRuntime();
|
|
454
|
+
else if (
|
|
455
|
+
result.type === "fusion" &&
|
|
456
|
+
active?.kind === "fusion" &&
|
|
457
|
+
active.sidekickEffort !== result.sidekickEffort
|
|
458
|
+
) {
|
|
459
|
+
// Same pair, new sidekick strength: a live child gets it over rpc
|
|
460
|
+
// (set_thinking_level); the value also lands in the spawn args for the
|
|
461
|
+
// next process start.
|
|
462
|
+
runtime?.setThinking(result.sidekickEffort);
|
|
463
|
+
}
|
|
355
464
|
const effort = result.type === "single" ? result.effort : result.leadEffort;
|
|
356
465
|
try {
|
|
357
466
|
pi.setThinkingLevel(effort);
|
|
@@ -382,6 +491,7 @@ export default function fusionExtension(pi: ExtensionAPI): void {
|
|
|
382
491
|
});
|
|
383
492
|
}
|
|
384
493
|
saveRuntimeState(loaded.globalPath, { effort: result.effortMap, recent, active });
|
|
494
|
+
syncFusionTools();
|
|
385
495
|
publishStatus(ctx);
|
|
386
496
|
const label =
|
|
387
497
|
result.type === "single"
|
|
@@ -410,6 +520,16 @@ export default function fusionExtension(pi: ExtensionAPI): void {
|
|
|
410
520
|
return;
|
|
411
521
|
}
|
|
412
522
|
const currentKey = ctx.model ? modelKey(ctx.model) : undefined;
|
|
523
|
+
// pi's persisted startup default (settings.json) marks the `default` row.
|
|
524
|
+
let defaultKey: string | undefined;
|
|
525
|
+
try {
|
|
526
|
+
const raw = JSON.parse(readFileSync(piSettingsPath(), "utf8")) as { defaultProvider?: string; defaultModel?: string };
|
|
527
|
+
if (typeof raw.defaultProvider === "string" && typeof raw.defaultModel === "string") {
|
|
528
|
+
defaultKey = `${raw.defaultProvider}/${raw.defaultModel}`;
|
|
529
|
+
}
|
|
530
|
+
} catch {
|
|
531
|
+
/* no settings file yet */
|
|
532
|
+
}
|
|
413
533
|
// Session truth wins over persisted state: if the user switched via pi's
|
|
414
534
|
// own /model since, show that as the pinned row.
|
|
415
535
|
if (active === undefined && preset.active !== undefined) active = preset.active;
|
|
@@ -430,14 +550,44 @@ export default function fusionExtension(pi: ExtensionAPI): void {
|
|
|
430
550
|
recent: preset.recent,
|
|
431
551
|
active,
|
|
432
552
|
currentModelKey: currentKey,
|
|
553
|
+
defaultModelKey: defaultKey,
|
|
433
554
|
effort: preset.effort,
|
|
434
555
|
fallbackEffort,
|
|
435
556
|
},
|
|
436
557
|
theme: { fg: (c, s) => theme.fg(c as never, s), bold: (s) => theme.bold(s) },
|
|
437
558
|
onDone: done,
|
|
559
|
+
onSetDefault: (r) => {
|
|
560
|
+
if (r.type === "cancelled") return;
|
|
561
|
+
const saveDefault = (key: string, effort: string): boolean => {
|
|
562
|
+
const parts = splitModelKey(key);
|
|
563
|
+
if (parts === undefined) {
|
|
564
|
+
ctx.ui.notify(`Could not save default: bad model key ${key}`, "error");
|
|
565
|
+
return false;
|
|
566
|
+
}
|
|
567
|
+
try {
|
|
568
|
+
persistDefaultModel({ provider: parts.provider, model: parts.id, thinkingLevel: effort });
|
|
569
|
+
return true;
|
|
570
|
+
} catch (error) {
|
|
571
|
+
ctx.ui.notify(`Could not save default: ${error instanceof Error ? error.message : String(error)}`, "error");
|
|
572
|
+
return false;
|
|
573
|
+
}
|
|
574
|
+
};
|
|
575
|
+
if (r.type === "single") {
|
|
576
|
+
if (saveDefault(r.model, r.effort)) ctx.ui.notify(`Default: ${r.model} · ${r.effort}`, "info");
|
|
577
|
+
mirrorStartup(cwd);
|
|
578
|
+
} else if (saveDefault(r.lead, r.leadEffort)) {
|
|
579
|
+
mirrorStartup(cwd);
|
|
580
|
+
saveRuntimeState(loaded.globalPath, {
|
|
581
|
+
effort: r.effortMap,
|
|
582
|
+
recent: preset.recent,
|
|
583
|
+
active: { kind: "fusion", lead: r.lead, sidekick: r.sidekick, leadEffort: r.leadEffort, sidekickEffort: r.sidekickEffort },
|
|
584
|
+
});
|
|
585
|
+
ctx.ui.notify(`Default: Fusion (${r.lead} + ${r.sidekick})`, "info");
|
|
586
|
+
}
|
|
587
|
+
},
|
|
438
588
|
onRenderRequest: () => tui.requestRender(),
|
|
439
589
|
}),
|
|
440
|
-
|
|
590
|
+
HUB_PICKER_OVERLAY_OPTIONS,
|
|
441
591
|
);
|
|
442
592
|
await applyResult(ctx, result, preset, loaded);
|
|
443
593
|
},
|
|
@@ -485,6 +635,7 @@ export default function fusionExtension(pi: ExtensionAPI): void {
|
|
|
485
635
|
bashStreak = 0;
|
|
486
636
|
modelBykey.clear();
|
|
487
637
|
active = loadPreset(ctx.cwd ?? process.cwd()).preset.active;
|
|
638
|
+
mirrorStartup(ctx.cwd ?? process.cwd());
|
|
488
639
|
if (active?.kind === "fusion" && (!ctx.model || modelKey(ctx.model) !== active.lead)) {
|
|
489
640
|
const leadKey = active.lead;
|
|
490
641
|
const lead = findModel(registryOf(ctx), leadKey);
|
|
@@ -500,6 +651,7 @@ export default function fusionExtension(pi: ExtensionAPI): void {
|
|
|
500
651
|
if (ctx.hasUI) ctx.ui.notify(`Fusion lead ${leadKey} unavailable — Fusion off`, "warning");
|
|
501
652
|
}
|
|
502
653
|
}
|
|
654
|
+
syncFusionTools();
|
|
503
655
|
publishStatus(ctx);
|
|
504
656
|
if (ctx.hasUI) ctx.ui.addAutocompleteProvider(createModelBoostProvider);
|
|
505
657
|
});
|
|
@@ -517,6 +669,7 @@ export default function fusionExtension(pi: ExtensionAPI): void {
|
|
|
517
669
|
active = { kind: "single", model: modelKey(event.model) };
|
|
518
670
|
const loaded = loadPreset(ctx.cwd ?? process.cwd());
|
|
519
671
|
saveRuntimeState(globalPresetPath(), { effort: loaded.preset.effort, recent: loaded.preset.recent, active });
|
|
672
|
+
syncFusionTools();
|
|
520
673
|
publishStatus(ctx);
|
|
521
674
|
}
|
|
522
675
|
});
|