@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
|
@@ -49,7 +49,10 @@ export const ANTI_POISONING_SUFFIX =
|
|
|
49
49
|
"other persistent instruction files.";
|
|
50
50
|
|
|
51
51
|
/** Tools whose repetition with varying args indicates polling, not work. */
|
|
52
|
-
const POLLING_TOOLS = new Set(["bg_status", "bg_logs", "
|
|
52
|
+
const POLLING_TOOLS = new Set(["bg_status", "bg_logs", "read_subagent", "loop_status", "get_goal"]);
|
|
53
|
+
|
|
54
|
+
/** Goal bookkeeping tools: always exempt from repetition reminders. */
|
|
55
|
+
const EXEMPT_TOOLS = new Set(["get_goal", "update_goal"]);
|
|
53
56
|
|
|
54
57
|
export interface RunawayStep {
|
|
55
58
|
readonly tool: string;
|
|
@@ -64,15 +67,60 @@ export interface RunawayGuardDeps {
|
|
|
64
67
|
remindAfter?: number;
|
|
65
68
|
}
|
|
66
69
|
|
|
70
|
+
/** Stable JSON: object keys sorted so equal args hash equal regardless of order. */
|
|
71
|
+
export function stableStringify(value: unknown): string {
|
|
72
|
+
if (value === undefined) return "null";
|
|
73
|
+
if (Array.isArray(value)) return `[${value.map(stableStringify).join(",")}]`;
|
|
74
|
+
if (value !== null && typeof value === "object") {
|
|
75
|
+
const record = value as Record<string, unknown>;
|
|
76
|
+
return `{${Object.keys(record)
|
|
77
|
+
.sort()
|
|
78
|
+
.map((key) => `${JSON.stringify(key)}:${stableStringify(record[key])}`)
|
|
79
|
+
.join(",")}}`;
|
|
80
|
+
}
|
|
81
|
+
try {
|
|
82
|
+
return JSON.stringify(value) ?? "null";
|
|
83
|
+
} catch {
|
|
84
|
+
return String(value);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
67
88
|
function fingerprint(value: unknown): string {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
89
|
+
return createHash("sha256").update(stableStringify(value)).digest("hex").slice(0, 16);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function commandOf(input: unknown): string {
|
|
93
|
+
if (typeof input === "string") return input;
|
|
94
|
+
if (typeof input !== "object" || input === null) return "";
|
|
95
|
+
const record = input as Record<string, unknown>;
|
|
96
|
+
for (const key of ["command", "cmd", "script"]) {
|
|
97
|
+
if (typeof record[key] === "string" && record[key].length > 0) return record[key] as string;
|
|
98
|
+
}
|
|
99
|
+
return "";
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/** bash rg/grep that found nothing (exit 1) is expected work, not a loop. */
|
|
103
|
+
export function isExpectedShellSearchNoMatch(input: unknown, isError: boolean, resultText: string): boolean {
|
|
104
|
+
if (!isError) return false;
|
|
105
|
+
const command = commandOf(input);
|
|
106
|
+
if (!/\b(?:rg|grep|findstr)\b/.test(command)) return false;
|
|
107
|
+
return /exit (?:code |status )?1\b|^no matches|^no match|^$/i.test(resultText.trim()) || resultText.trim() === "";
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/** kanboard read subcommands via bash never count as repeated work. */
|
|
111
|
+
function isKanboardRead(command: string): boolean {
|
|
112
|
+
return /(?:^|[\s/"'])unipi-kanboard(?:\.exe)?\s+(?:--\S+\s+)*(?:list|show|search|next|chain|attachments|status)\b/.test(command);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/** Steps that reflect legitimate state inspection, not loops. */
|
|
116
|
+
export function isExemptStep(step: RunawayStep): boolean {
|
|
117
|
+
if (EXEMPT_TOOLS.has(step.tool)) return true;
|
|
118
|
+
if (step.tool === "bash" || step.tool === "powershell") {
|
|
119
|
+
const command = commandOf(step.input);
|
|
120
|
+
if (isKanboardRead(command)) return true;
|
|
121
|
+
if (isExpectedShellSearchNoMatch(step.input, step.isError, step.resultText)) return true;
|
|
122
|
+
}
|
|
123
|
+
return false;
|
|
76
124
|
}
|
|
77
125
|
|
|
78
126
|
/** Errors normalize to their family: first line, digits and paths removed. */
|
|
@@ -93,13 +141,22 @@ export interface RunawayObservation {
|
|
|
93
141
|
|
|
94
142
|
/** Pure detector: returns the highest-priority qualifying signal, if any. */
|
|
95
143
|
export function detectRunaway(
|
|
96
|
-
|
|
144
|
+
allSteps: readonly RunawayStep[],
|
|
97
145
|
remindAfter: number = DEFAULT_REMIND_AFTER,
|
|
98
146
|
): RunawayObservation | null {
|
|
147
|
+
// Exempt steps (goal bookkeeping, search no-matches, kanboard reads) never
|
|
148
|
+
// count toward any repeat.
|
|
149
|
+
const steps = allSteps.filter((step) => !isExemptStep(step));
|
|
99
150
|
if (steps.length < remindAfter) return null;
|
|
100
151
|
|
|
152
|
+
// Action identity = tool + stable-sorted args: "identical arguments" must
|
|
153
|
+
// mean actually identical arguments.
|
|
101
154
|
const actionKeys = steps.map((step) => `${step.tool}:${fingerprint(step.input)}`);
|
|
102
|
-
|
|
155
|
+
// Result identity is bound to the action: identical output under different
|
|
156
|
+
// args is not a repeat (e.g. two different reads returning empty).
|
|
157
|
+
const resultKeys = steps.map(
|
|
158
|
+
(step) => `${step.tool}:${fingerprint(step.input)}:${fingerprint(step.resultText.slice(0, 400))}`,
|
|
159
|
+
);
|
|
103
160
|
const errorKeys = steps.map((step) => (step.isError ? errorFamily(step.resultText) : null));
|
|
104
161
|
|
|
105
162
|
const count = (keys: readonly string[]): { key: string; count: number } => {
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
*/
|
|
19
19
|
|
|
20
20
|
import { createHash } from "node:crypto";
|
|
21
|
+
import { gatherEvidence } from "@pi-unipi/core";
|
|
21
22
|
|
|
22
23
|
export const MAX_CHANGE_CHARS = 4_000;
|
|
23
24
|
export const MAX_CHANGE_ITEMS = 100;
|
|
@@ -49,6 +50,8 @@ export interface VerifierDeps {
|
|
|
49
50
|
readonly timeoutMs?: number;
|
|
50
51
|
readonly setTimeout?: (fn: () => void, ms: number) => unknown;
|
|
51
52
|
readonly clearTimeout?: (handle: unknown) => void;
|
|
53
|
+
/** Cross-module evidence (kanboard claims, …); defaults to core's registry. */
|
|
54
|
+
readonly gather?: typeof gatherEvidence;
|
|
52
55
|
}
|
|
53
56
|
|
|
54
57
|
const VERIFIER_SYSTEM = `You are the completion verifier for an autonomous coding agent. Given an OBJECTIVE and an EVIDENCE BRIEF, judge whether the objective is fully satisfied.
|
|
@@ -161,6 +164,22 @@ export async function verifyCompletion(
|
|
|
161
164
|
brief: string,
|
|
162
165
|
abortSignal?: AbortSignal,
|
|
163
166
|
): Promise<VerificationVerdict> {
|
|
167
|
+
// Cross-module evidence first: any blocking item forces not_met WITHOUT
|
|
168
|
+
// paying for an evaluator call (the evidence is already conclusive).
|
|
169
|
+
const gather = deps.gather ?? gatherEvidence;
|
|
170
|
+
const evidence = await gather();
|
|
171
|
+
if (evidence.blocking.length > 0) {
|
|
172
|
+
return {
|
|
173
|
+
verdict: "not_met",
|
|
174
|
+
reason: "board: open work remains",
|
|
175
|
+
missing: [...evidence.blocking],
|
|
176
|
+
evaluatorFailed: false,
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
if (evidence.notes.length > 0) {
|
|
180
|
+
brief = `${brief}\n--- MODULE EVIDENCE ---\n${evidence.notes.join("\n")}`;
|
|
181
|
+
}
|
|
182
|
+
|
|
164
183
|
const prompt = buildVerificationPrompt(objective, brief);
|
|
165
184
|
const timeoutMs = deps.timeoutMs ?? DEFAULT_VERIFIER_TIMEOUT_MS;
|
|
166
185
|
const setT = deps.setTimeout ?? ((fn, ms) => setTimeout(fn, ms));
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
19
|
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
20
|
-
import { emitEvent, UNIPI_EVENTS, setSharedLongHorizonMode } from "@pi-unipi/core";
|
|
20
|
+
import { emitEvent, isChildProcess, UNIPI_EVENTS, setSharedLongHorizonMode } from "@pi-unipi/core";
|
|
21
21
|
import { LH_MODES, MODE_REGISTRY, modeForOwnerKind, type LhMode } from "./modes.js";
|
|
22
22
|
import type { OwnerCoordinator, OwnerState } from "./owner.js";
|
|
23
23
|
import { resolveMode, type ResolutionSource } from "./judge/resolve.js";
|
|
@@ -30,6 +30,8 @@ export interface GateState {
|
|
|
30
30
|
readonly mode: LhMode;
|
|
31
31
|
readonly source: ResolutionSource;
|
|
32
32
|
readonly confidence?: number;
|
|
33
|
+
/** Resolved from the sticky session mode (/unipi:regular, goal stop), not a one-shot. */
|
|
34
|
+
readonly sticky?: boolean;
|
|
33
35
|
}
|
|
34
36
|
|
|
35
37
|
export interface GateDeps {
|
|
@@ -48,12 +50,9 @@ export interface GateDeps {
|
|
|
48
50
|
}
|
|
49
51
|
|
|
50
52
|
/** Delegation tools governed by the exposure matrix (design §8). */
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
"bg_delegate",
|
|
55
|
-
"bg_result",
|
|
56
|
-
];
|
|
53
|
+
// Devin-model subagents are first-class: run_subagent is available in every
|
|
54
|
+
// mode. The delegation matrix mechanism is kept for future mode tools.
|
|
55
|
+
export const DELEGATION_TOOLS: readonly string[] = [];
|
|
57
56
|
|
|
58
57
|
/** Every mode-control tool name across modes (todowrite rides all four). */
|
|
59
58
|
export const ALL_MODE_TOOLS: readonly string[] = [
|
|
@@ -122,7 +121,7 @@ export function renderModeFragment(state: GateState, owner?: OwnerState, parked?
|
|
|
122
121
|
`Available long-horizon tools: ${definition.controlTools.join(", ")}.` +
|
|
123
122
|
(definition.delegation === "full"
|
|
124
123
|
? " Delegation tools are available for parallel work."
|
|
125
|
-
: "
|
|
124
|
+
: ""),
|
|
126
125
|
);
|
|
127
126
|
}
|
|
128
127
|
const status = ownerPresenceLine(owner, parked);
|
|
@@ -137,6 +136,8 @@ export function renderModeFragment(state: GateState, owner?: OwnerState, parked?
|
|
|
137
136
|
export class Gate {
|
|
138
137
|
private turn: GateState | null = null;
|
|
139
138
|
private pendingExplicit: LhMode | null = null;
|
|
139
|
+
/** Sticky per-session mode (/unipi:regular): judge/default skip until an explicit command clears it. */
|
|
140
|
+
private sessionOverride: LhMode | null = null;
|
|
140
141
|
/** Mode of the last badge shown, so only mode TRANSITIONS reprint. */
|
|
141
142
|
private lastBadge: LhMode | null = null;
|
|
142
143
|
private readonly deps: GateDeps;
|
|
@@ -145,9 +146,17 @@ export class Gate {
|
|
|
145
146
|
this.deps = deps;
|
|
146
147
|
}
|
|
147
148
|
|
|
148
|
-
/** Commands call this before sendUserMessage to force next-turn mode
|
|
149
|
+
/** Commands call this before sendUserMessage to force next-turn mode (one-shot;
|
|
150
|
+
* an explicit command also escapes a sticky session mode). */
|
|
149
151
|
setExplicit(mode: LhMode): void {
|
|
150
152
|
this.pendingExplicit = mode;
|
|
153
|
+
this.sessionOverride = null;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/** Pin the session to a mode (/unipi:regular, goal stop): every later turn resolves to it. */
|
|
157
|
+
setSessionMode(mode: LhMode): void {
|
|
158
|
+
this.sessionOverride = mode;
|
|
159
|
+
this.pendingExplicit = null;
|
|
151
160
|
}
|
|
152
161
|
|
|
153
162
|
current(): GateState | null {
|
|
@@ -155,10 +164,17 @@ export class Gate {
|
|
|
155
164
|
}
|
|
156
165
|
|
|
157
166
|
async resolveForTurn(prompt: string): Promise<GateState> {
|
|
167
|
+
// Children are the hands, the lead is the voice: no LH modes, no judge,
|
|
168
|
+
// no owners in fusion/subagent children (escape hatch: UNIPI_LH_ALLOW_CHILD).
|
|
169
|
+
if (isChildProcess() && process.env.UNIPI_LH_ALLOW_CHILD !== "1") {
|
|
170
|
+
this.pendingExplicit = null;
|
|
171
|
+
this.turn = { mode: "none", source: "child" };
|
|
172
|
+
return this.turn;
|
|
173
|
+
}
|
|
158
174
|
const settings = this.deps.loadSettings?.() ?? loadSettings();
|
|
159
175
|
// Explicit switch away from an active owner suspends it first (max-1
|
|
160
176
|
// park slot; a held slot refuses the override and the owner keeps mode).
|
|
161
|
-
let explicit = this.pendingExplicit;
|
|
177
|
+
let explicit = this.sessionOverride ?? this.pendingExplicit;
|
|
162
178
|
if (explicit) {
|
|
163
179
|
const active = this.deps.owner.getActive();
|
|
164
180
|
if (active && modeForOwnerKind(active.kind) !== explicit) {
|
|
@@ -184,6 +200,7 @@ export class Gate {
|
|
|
184
200
|
mode: resolution.mode,
|
|
185
201
|
source: resolution.source,
|
|
186
202
|
...(resolution.confidence !== undefined ? { confidence: resolution.confidence } : {}),
|
|
203
|
+
...(this.sessionOverride !== null && explicit === this.sessionOverride ? { sticky: true } : {}),
|
|
187
204
|
};
|
|
188
205
|
return this.turn;
|
|
189
206
|
}
|
|
@@ -212,7 +229,7 @@ export class Gate {
|
|
|
212
229
|
// - mode changed from last → worth showing
|
|
213
230
|
// - same mode as last shown → silent (footer already reflects it)
|
|
214
231
|
const showBadge =
|
|
215
|
-
state.source === "explicit" || this.lastBadge !== state.mode;
|
|
232
|
+
(state.source === "explicit" && !state.sticky) || this.lastBadge !== state.mode;
|
|
216
233
|
this.lastBadge = state.mode;
|
|
217
234
|
if (showBadge) {
|
|
218
235
|
try {
|
|
@@ -230,7 +247,15 @@ export class Gate {
|
|
|
230
247
|
this.deps.owner.getActive(),
|
|
231
248
|
this.deps.owner.getParked(),
|
|
232
249
|
);
|
|
233
|
-
|
|
250
|
+
// A named section, not a systemPrompt replacement: a forced prompt is
|
|
251
|
+
// opaque to pi (forceSystemPrompt) and would drop sections other modules
|
|
252
|
+
// added — e.g. fusion's lead policy. renderModeFragment already emits
|
|
253
|
+
// the <long-horizon> wrapper; strip it, pi re-wraps the section.
|
|
254
|
+
const inner = fragment
|
|
255
|
+
.replace(/^<long-horizon[^>]*>\n?/, "")
|
|
256
|
+
.replace(/\n?<\/long-horizon>(\n|$)/, "$1");
|
|
257
|
+
event.systemPromptOptions.sections["long-horizon"] = inner;
|
|
258
|
+
return undefined;
|
|
234
259
|
});
|
|
235
260
|
|
|
236
261
|
pi.on("before_provider_request", (event) => {
|
|
@@ -12,9 +12,13 @@
|
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
14
|
import { randomUUID } from "node:crypto";
|
|
15
|
-
import { ensureDir, tryRead, writeJson } from "@pi-unipi/core";
|
|
15
|
+
import { ensureDir, isChildProcess, markSharedOwnerStopped, setSharedOwner, tryRead, writeJson } from "@pi-unipi/core";
|
|
16
16
|
import type { OwnerKind } from "./modes.js";
|
|
17
17
|
|
|
18
|
+
/** Surfaced by create_goal / ralph / swarm / graph tools inside children. */
|
|
19
|
+
export const CHILD_OWNER_REFUSAL =
|
|
20
|
+
"Long-horizon owners are not available inside a child agent — do the work and report back to the lead.";
|
|
21
|
+
|
|
18
22
|
export type OwnerStatus = "active" | "parked";
|
|
19
23
|
|
|
20
24
|
export interface OwnerLease {
|
|
@@ -109,9 +113,13 @@ export class OwnerCoordinator {
|
|
|
109
113
|
|
|
110
114
|
/**
|
|
111
115
|
* Create and activate a new owner. Refuses while another owner is active —
|
|
112
|
-
* callers surface "finish or suspend the current owner first".
|
|
116
|
+
* callers surface "finish or suspend the current owner first". In child
|
|
117
|
+
* processes owning is refused outright (throw — tool failures must throw).
|
|
113
118
|
*/
|
|
114
119
|
activate(kind: OwnerKind, label: string): OwnerState | undefined {
|
|
120
|
+
if (isChildProcess() && process.env.UNIPI_LH_ALLOW_CHILD !== "1") {
|
|
121
|
+
throw new Error(CHILD_OWNER_REFUSAL);
|
|
122
|
+
}
|
|
115
123
|
if (this.active) return undefined;
|
|
116
124
|
const ownerId = randomUUID();
|
|
117
125
|
const now = new Date(this.deps.now?.() ?? Date.now()).toISOString();
|
|
@@ -216,15 +224,32 @@ export class OwnerCoordinator {
|
|
|
216
224
|
}
|
|
217
225
|
const snapshot = this.snapshot();
|
|
218
226
|
this.deps.onChange?.(snapshot, { type: "restored", snapshot });
|
|
227
|
+
this.publishStatus({ type: "restored", snapshot });
|
|
219
228
|
return snapshot;
|
|
220
229
|
}
|
|
221
230
|
|
|
222
231
|
private commit(event: OwnerEvent): OwnerState | undefined {
|
|
223
232
|
this.persist();
|
|
233
|
+
this.publishStatus(event);
|
|
224
234
|
this.deps.onChange?.(this.snapshot(), event);
|
|
225
235
|
return "owner" in event ? event.owner : undefined;
|
|
226
236
|
}
|
|
227
237
|
|
|
238
|
+
/** Publish the transition to the shared holder kanboard's monitor reads. */
|
|
239
|
+
private publishStatus(event: OwnerEvent): void {
|
|
240
|
+
try {
|
|
241
|
+
if (event.type === "finished") markSharedOwnerStopped(stopKindOf(event.reason));
|
|
242
|
+
// Parked (paused) goals go through suspend, not finish — kanboard must
|
|
243
|
+
// see them as a stop of kind "paused" this run, same as finish would.
|
|
244
|
+
if (event.type === "suspended") markSharedOwnerStopped("paused");
|
|
245
|
+
if (this.active) setSharedOwner({ kind: this.active.kind, status: "active" });
|
|
246
|
+
else if (this.parked) setSharedOwner({ kind: this.parked.kind, status: "parked" });
|
|
247
|
+
else setSharedOwner(undefined);
|
|
248
|
+
} catch {
|
|
249
|
+
// Status publishing must never roll back a committed transition.
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
228
253
|
private commitActive(patch: Partial<OwnerState>): OwnerState {
|
|
229
254
|
if (!this.active) throw new Error("commitActive without an active owner");
|
|
230
255
|
const next = this.withOwner(this.active, patch);
|
|
@@ -253,3 +278,11 @@ function renewLease(owner: OwnerState): OwnerLease {
|
|
|
253
278
|
generation: owner.lease.generation + 1,
|
|
254
279
|
});
|
|
255
280
|
}
|
|
281
|
+
|
|
282
|
+
/** Map a terminal reason to the coarse stop kind kanboard's monitor needs. */
|
|
283
|
+
export function stopKindOf(reason: string): "complete" | "paused" | "budget" | "other" {
|
|
284
|
+
if (reason === "complete" || reason.startsWith("complete(")) return "complete";
|
|
285
|
+
if (reason === "paused" || reason.startsWith("paused(")) return "paused";
|
|
286
|
+
if (reason.includes("budget")) return "budget";
|
|
287
|
+
return "other";
|
|
288
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* User-only progress bars for long-horizon owners.
|
|
3
|
+
*
|
|
4
|
+
* ↻ Ralph · docs-cleanup ████████▒▒░░░░░░░░░░ 4/10 items iteration 3/20
|
|
5
|
+
* ◎ Goal ███████████▒▒░░░░░░░ ~55% turn 4/30
|
|
6
|
+
* Parser and CLI flags done; tests for the error paths are left.
|
|
7
|
+
*
|
|
8
|
+
* Ralph counts its checklist. A goal has no countable progress, so a one-off
|
|
9
|
+
* side call (never in the session context) estimates % done + a summary.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import type { ProgressData } from "@pi-unipi/core";
|
|
13
|
+
import type { GoalState } from "./engine/goal-state.js";
|
|
14
|
+
import type { RalphLoop } from "./engine/ralph.js";
|
|
15
|
+
|
|
16
|
+
export function ralphProgressData(ralph: Pick<RalphLoop, "get" | "progressSummary">): ProgressData | undefined {
|
|
17
|
+
const st = ralph.get();
|
|
18
|
+
if (!st) return undefined;
|
|
19
|
+
const p = ralph.progressSummary();
|
|
20
|
+
const live = st.status === "active";
|
|
21
|
+
const active = live ? Math.min(st.itemsPerIteration, Math.max(0, p.total - p.checked)) : 0;
|
|
22
|
+
return {
|
|
23
|
+
icon: "↻",
|
|
24
|
+
label: `Ralph · ${st.name}`,
|
|
25
|
+
done: p.checked,
|
|
26
|
+
active,
|
|
27
|
+
total: p.total,
|
|
28
|
+
unit: "items",
|
|
29
|
+
detail: `iteration ${String(st.iteration)}/${String(st.maxIterations)}${live ? "" : ` · ${st.status}`}`,
|
|
30
|
+
summary: live && p.next.length > 0 ? `next: ${p.next.slice(0, 3).join(" · ")}` : undefined,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface GoalEvidence {
|
|
35
|
+
commands: readonly string[];
|
|
36
|
+
changedFiles: readonly string[];
|
|
37
|
+
recentTail: ReadonlyArray<{ role: string; text: string }>;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function goalEstimatePrompt(goal: Pick<GoalState, "objective" | "turn" | "maxTurns">, evidence: GoalEvidence | undefined, previous: number | undefined): string {
|
|
41
|
+
const lines = [
|
|
42
|
+
"Estimate progress on a goal for a progress bar shown to the user. Be honest and conservative: 100 only when the objective is fully met.",
|
|
43
|
+
"",
|
|
44
|
+
`Objective: ${goal.objective}`,
|
|
45
|
+
`Turn ${String(goal.turn)} of at most ${String(goal.maxTurns)}.`,
|
|
46
|
+
];
|
|
47
|
+
if (previous !== undefined) lines.push(`Previous estimate: ${String(previous)}%.`);
|
|
48
|
+
if (evidence) {
|
|
49
|
+
if (evidence.changedFiles.length) lines.push(`Files touched recently: ${[...new Set(evidence.changedFiles)].slice(-12).join(", ")}`);
|
|
50
|
+
if (evidence.commands.length) lines.push(`Commands run recently: ${evidence.commands.slice(-8).join(" | ")}`);
|
|
51
|
+
if (evidence.recentTail.length) {
|
|
52
|
+
lines.push("", "Latest messages:");
|
|
53
|
+
for (const m of evidence.recentTail.slice(-4)) lines.push(`[${m.role}] ${m.text.slice(0, 600)}`);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
lines.push("", 'Reply with JSON only: {"percent": <integer 0-100>, "summary": "<one or two short sentences: what is done, what is left>"}');
|
|
57
|
+
return lines.join("\n");
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** Pull `{percent, summary}` out of a model reply (tolerates fences and prose). */
|
|
61
|
+
export function parseEstimate(text: string): { percent: number; summary: string } | undefined {
|
|
62
|
+
const match = text.match(/\{[\s\S]*\}/u);
|
|
63
|
+
if (!match) return undefined;
|
|
64
|
+
try {
|
|
65
|
+
const raw = JSON.parse(match[0]) as { percent?: unknown; summary?: unknown };
|
|
66
|
+
const n = typeof raw.percent === "number" ? raw.percent : Number(raw.percent);
|
|
67
|
+
if (!Number.isFinite(n)) return undefined;
|
|
68
|
+
return { percent: Math.max(0, Math.min(100, Math.round(n))), summary: typeof raw.summary === "string" ? raw.summary.trim() : "" };
|
|
69
|
+
} catch {
|
|
70
|
+
return undefined;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/** Shade = the slice in progress; a live goal always shows one. */
|
|
75
|
+
export function goalProgressData(goal: Pick<GoalState, "turn" | "maxTurns" | "status">, percent: number, summary: string): ProgressData {
|
|
76
|
+
const live = goal.status === "active" || goal.status === "waiting";
|
|
77
|
+
return {
|
|
78
|
+
icon: "◎",
|
|
79
|
+
label: "Goal",
|
|
80
|
+
done: goal.status === "complete" ? 100 : percent,
|
|
81
|
+
active: live ? Math.max(1, Math.min(10, 100 - percent)) : 0,
|
|
82
|
+
total: 100,
|
|
83
|
+
estimated: goal.status !== "complete",
|
|
84
|
+
detail: `turn ${String(goal.turn)}/${String(goal.maxTurns)}${live ? "" : ` · ${goal.status}`}`,
|
|
85
|
+
summary: summary || undefined,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
@@ -96,7 +96,7 @@ export function renderContinuationHint(goal: GoalState, verifierReason?: string)
|
|
|
96
96
|
goal.noProgressStreak > 0 ? `, ${goal.noProgressStreak}/${goal.stallCap} no-progress` : "";
|
|
97
97
|
const budget =
|
|
98
98
|
goal.tokenBudget !== null && !goal.tokensBaselinePending
|
|
99
|
-
? `, ${Math.max(0, goal.tokensNow - goal.tokensAtStart)}/${goal.tokenBudget} tok`
|
|
99
|
+
? `, ${Math.max(0, goal.tokensNow - goal.tokensAtStart)}/${goal.tokenBudget} tok${goal.tokensEstimated ? " (est.)" : ""}`
|
|
100
100
|
: "";
|
|
101
101
|
return (
|
|
102
102
|
`${CONTINUATION_HINT}` +
|