ultimate-pi 0.18.1 → 0.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agents/skills/harness-debate-plan/SKILL.md +1 -1
- package/.agents/skills/harness-decisions/SKILL.md +1 -2
- package/.agents/skills/harness-governor/SKILL.md +6 -5
- package/.pi/PACKAGING.md +4 -4
- package/.pi/SYSTEM.md +54 -120
- package/.pi/agents/harness/incident-recorder.md +0 -1
- package/.pi/agents/harness/planning/decompose.md +0 -2
- package/.pi/agents/harness/planning/execution-plan-author.md +0 -2
- package/.pi/agents/harness/planning/hypothesis-validator.md +0 -2
- package/.pi/agents/harness/planning/hypothesis.md +0 -2
- package/.pi/agents/harness/planning/implementation-researcher.md +0 -2
- package/.pi/agents/harness/planning/plan-adversary.md +0 -2
- package/.pi/agents/harness/planning/plan-evaluator.md +1 -3
- package/.pi/agents/harness/planning/planning-context.md +0 -2
- package/.pi/agents/harness/planning/review-integrator.md +0 -2
- package/.pi/agents/harness/planning/sprint-contract-auditor.md +0 -2
- package/.pi/agents/harness/planning/stack-researcher.md +0 -2
- package/.pi/agents/harness/reviewing/adversary.md +0 -2
- package/.pi/agents/harness/reviewing/evaluator.md +0 -2
- package/.pi/agents/harness/reviewing/tie-breaker.md +0 -2
- package/.pi/agents/harness/running/executor.md +0 -2
- package/.pi/agents/harness/sentrux-bootstrap.md +0 -1
- package/.pi/agents/harness/sentrux-steward.md +0 -2
- package/.pi/agents/harness/trace-librarian.md +0 -1
- package/.pi/extensions/00-posthog-network-bootstrap.ts +1 -1
- package/.pi/extensions/agt-kill-switch.ts +57 -0
- package/.pi/extensions/agt-prompt-guard.ts +32 -0
- package/.pi/extensions/custom-footer.ts +46 -145
- package/.pi/extensions/custom-header.ts +1 -1
- package/.pi/extensions/custom-system-prompt.ts +1 -1
- package/.pi/extensions/debate-orchestrator.ts +6 -6
- package/.pi/extensions/harness-ask-user.ts +7 -7
- package/.pi/extensions/harness-debate-tools.ts +26 -42
- package/.pi/extensions/harness-lens.ts +94 -0
- package/.pi/extensions/harness-plan-approval.ts +11 -11
- package/.pi/extensions/harness-run-context.ts +1070 -876
- package/.pi/extensions/harness-subagent-governance.ts +8 -0
- package/.pi/extensions/harness-subagent-submit.ts +34 -163
- package/.pi/extensions/harness-subagents.ts +3 -3
- package/.pi/extensions/harness-telemetry.ts +2 -2
- package/.pi/extensions/harness-web-tools.ts +2 -2
- package/.pi/extensions/policy-gate.ts +25 -5
- package/.pi/extensions/sentrux-rules-sync.ts +1 -1
- package/.pi/extensions/subagent-governance.ts +92 -0
- package/.pi/extensions/trace-recorder.ts +1 -1
- package/.pi/extensions/{ultimate-pi-vcc.ts → vcc-compaction.ts} +1 -1
- package/.pi/harness/README.md +6 -2
- package/.pi/harness/agents.manifest.json +22 -25
- package/.pi/harness/agents.policy.yaml +275 -0
- package/.pi/harness/docs/adrs/0030-inhouse-vcc-compaction.md +1 -1
- package/.pi/harness/docs/adrs/0035-plan-phase-review-gate.md +1 -1
- package/.pi/harness/docs/adrs/0045-harness-lens-minimal-contract.md +49 -0
- package/.pi/harness/docs/adrs/0046-agt-policy-engine.md +51 -0
- package/.pi/harness/docs/adrs/0047-agt-layered-security.md +39 -0
- package/.pi/harness/docs/adrs/0048-tool-call-hook-order.md +25 -0
- package/.pi/harness/docs/adrs/0049-agents-policy-manifest.md +36 -0
- package/.pi/harness/docs/adrs/README.md +5 -0
- package/.pi/harness/evolution/README.md +1 -2
- package/.pi/harness/examples/agents.policy.project.yaml +19 -0
- package/.pi/harness/examples/policies/custom-deny-bash.yaml +9 -0
- package/.pi/harness/policies/bash-denylists.yaml +5 -0
- package/.pi/harness/policies/defaults.yaml +51 -0
- package/.pi/harness/policies/orchestrator.yaml +18 -0
- package/.pi/harness/policies/phases.yaml +10 -0
- package/.pi/harness/policies/roles.yaml +5 -0
- package/.pi/harness/policies/web-guard.yaml +5 -0
- package/.pi/harness/policies/workflow-sequences.yaml +9 -0
- package/.pi/harness/sentrux/architecture.manifest.json +26 -4
- package/.pi/harness/specs/observation.schema.json +2 -1
- package/.pi/lib/agents-policy.d.mts +70 -0
- package/.pi/lib/agents-policy.mjs +325 -0
- package/.pi/lib/agents-policy.ts +19 -0
- package/.pi/lib/agt/audit-run-sink.ts +52 -0
- package/.pi/lib/agt/build-evaluation-context.ts +285 -0
- package/.pi/lib/agt/config.ts +28 -0
- package/.pi/lib/agt/delegation.ts +69 -0
- package/.pi/lib/agt/evaluate-policy.ts +56 -0
- package/.pi/lib/agt/identity-registry.ts +41 -0
- package/.pi/lib/agt/index.ts +55 -0
- package/.pi/lib/agt/kill-switch-state.ts +11 -0
- package/.pi/lib/agt/legacy-evaluate.ts +101 -0
- package/.pi/lib/agt/policy-engine.ts +154 -0
- package/.pi/lib/agt/rings.ts +21 -0
- package/.pi/lib/agt/sre-hooks.ts +45 -0
- package/.pi/lib/agt/trust-run-store.ts +26 -0
- package/.pi/lib/agt/workflow-history.ts +29 -0
- package/.pi/lib/agt-governance-active.ts +14 -0
- package/.pi/lib/agt-tool-guard.ts +78 -0
- package/.pi/lib/ask-user/dialog.ts +314 -0
- package/.pi/{extensions/lib → lib}/debate-bus-core.ts +10 -10
- package/.pi/{extensions/lib → lib}/debate-bus-state.ts +1 -1
- package/.pi/{extensions/lib → lib}/extension-load-guard.ts +13 -2
- package/.pi/lib/harness-agt-tool-guard.ts +5 -0
- package/.pi/{extensions/lib → lib}/harness-artifact-gate.ts +1 -1
- package/.pi/lib/harness-debate-core-deps.ts +14 -0
- package/.pi/lib/harness-debate-workflow-deps.ts +43 -0
- package/.pi/lib/harness-lens/.gitattributes +1 -0
- package/.pi/lib/harness-lens/clients/edit-autopatch.ts +88 -0
- package/.pi/lib/harness-lens/clients/file-kinds.ts +380 -0
- package/.pi/lib/harness-lens/clients/file-time.ts +215 -0
- package/.pi/lib/harness-lens/clients/file-utils.ts +484 -0
- package/.pi/lib/harness-lens/clients/format-service.ts +276 -0
- package/.pi/lib/harness-lens/clients/formatters.ts +1000 -0
- package/.pi/lib/harness-lens/clients/git-guard.ts +31 -0
- package/.pi/lib/harness-lens/clients/indent-retarget.ts +90 -0
- package/.pi/lib/harness-lens/clients/installer/index.ts +2368 -0
- package/.pi/lib/harness-lens/clients/latency-logger.ts +80 -0
- package/.pi/lib/harness-lens/clients/lens-config.ts +43 -0
- package/.pi/lib/harness-lens/clients/lens-events.ts +164 -0
- package/.pi/lib/harness-lens/clients/lsp/aggregation.ts +91 -0
- package/.pi/lib/harness-lens/clients/lsp/client.ts +1466 -0
- package/.pi/lib/harness-lens/clients/lsp/config.ts +216 -0
- package/.pi/lib/harness-lens/clients/lsp/edits.ts +297 -0
- package/.pi/lib/harness-lens/clients/lsp/index.ts +1355 -0
- package/.pi/lib/harness-lens/clients/lsp/interactive-install.ts +424 -0
- package/.pi/lib/harness-lens/clients/lsp/language.ts +223 -0
- package/.pi/lib/harness-lens/clients/lsp/launch.ts +939 -0
- package/.pi/lib/harness-lens/clients/lsp/lsp-index.ts +11 -0
- package/.pi/lib/harness-lens/clients/lsp/path-utils.ts +12 -0
- package/.pi/lib/harness-lens/clients/lsp/server-strategies.ts +81 -0
- package/.pi/lib/harness-lens/clients/lsp/server.ts +1971 -0
- package/.pi/lib/harness-lens/clients/path-utils.ts +182 -0
- package/.pi/lib/harness-lens/clients/pipeline.ts +360 -0
- package/.pi/lib/harness-lens/clients/project-profile.ts +117 -0
- package/.pi/lib/harness-lens/clients/runtime-agent-end.ts +112 -0
- package/.pi/lib/harness-lens/clients/runtime-config.ts +33 -0
- package/.pi/lib/harness-lens/clients/runtime-coordinator.ts +186 -0
- package/.pi/lib/harness-lens/clients/runtime-tool-result.ts +171 -0
- package/.pi/lib/harness-lens/clients/safe-spawn.ts +339 -0
- package/.pi/lib/harness-lens/clients/secrets-scanner.ts +214 -0
- package/.pi/lib/harness-lens/clients/tool-policy.ts +2072 -0
- package/.pi/lib/harness-lens/clients/types.ts +59 -0
- package/.pi/lib/harness-lens/clients/widget-state.ts +283 -0
- package/.pi/lib/harness-lens/index.ts +532 -0
- package/.pi/lib/harness-lens/tools/lsp-diagnostics.ts +706 -0
- package/.pi/lib/harness-lens/tools/lsp-navigation.ts +1246 -0
- package/.pi/{extensions/lib → lib}/harness-posthog.ts +3 -0
- package/.pi/lib/harness-run-context-responses.ts +9 -0
- package/.pi/lib/harness-run-context.ts +0 -2
- package/.pi/{extensions/lib/spawn-policy.ts → lib/harness-spawn-policy.ts} +1 -0
- package/.pi/{extensions/lib → lib}/harness-spawn-topology.ts +1 -1
- package/.pi/lib/harness-subagent-auth.ts +51 -0
- package/.pi/{extensions/lib → lib}/harness-subagent-precheck.ts +10 -7
- package/.pi/{extensions/lib → lib}/harness-subagent-submit-pipeline.ts +3 -3
- package/.pi/lib/harness-subagent-submit-register.ts +163 -0
- package/.pi/{extensions/lib → lib}/harness-subagent-submit-registry.ts +1 -37
- package/.pi/{extensions/lib → lib}/harness-subagents-bridge.ts +53 -14
- package/.pi/{extensions/lib → lib}/harness-subprocess-bootstrap.ts +1 -1
- package/.pi/{extensions/lib → lib}/plan-approval/create-plan.ts +2 -2
- package/.pi/{extensions/lib → lib}/plan-approval/format-plan.ts +2 -2
- package/.pi/{extensions/lib → lib}/plan-approval/plan-review.ts +162 -201
- package/.pi/{extensions/lib → lib}/plan-approval/render.ts +1 -1
- package/.pi/{extensions/lib → lib}/plan-approval/resolve-disk.ts +2 -2
- package/.pi/{extensions/lib → lib}/plan-approval/types.ts +1 -1
- package/.pi/{extensions/lib → lib}/plan-approval/validate.ts +3 -3
- package/.pi/{extensions/lib → lib}/plan-debate-envelope.ts +1 -1
- package/.pi/{extensions/lib → lib}/plan-debate-gate.ts +1 -1
- package/.pi/{extensions/lib → lib}/plan-debate-lane.ts +1 -4
- package/.pi/{extensions/lib → lib}/plan-messenger.ts +1 -1
- package/.pi/prompts/harness-plan.md +1 -1
- package/.pi/prompts/harness-setup.md +37 -64
- package/.pi/scripts/README.md +2 -5
- package/.pi/scripts/generate-agents-policy-yaml.mjs +148 -0
- package/.pi/scripts/harness-agents-manifest.mjs +60 -3
- package/.pi/scripts/harness-agt-doctor.ts +36 -0
- package/.pi/scripts/harness-cli-verify.sh +9 -2
- package/.pi/scripts/harness-verify.mjs +113 -39
- package/.pi/scripts/harness-web-policy-guard.mjs +2 -2
- package/.pi/scripts/validate-plan-dag.mjs +65 -74
- package/.pi/scripts/vendor-pi-vcc-settings.stub.ts +2 -2
- package/.pi/scripts/vendor-sync-pi-vcc.sh +1 -1
- package/.pi/skills/architecture/broker-domain/SKILL.md +65 -0
- package/.pi/skills/architecture/cqrs/SKILL.md +63 -0
- package/.pi/skills/architecture/event-driven/SKILL.md +60 -0
- package/.pi/skills/architecture/hexagonal-ports-adapters/SKILL.md +66 -0
- package/.pi/skills/architecture/layered/SKILL.md +68 -0
- package/.pi/skills/architecture/microkernel/SKILL.md +62 -0
- package/.pi/skills/architecture/microservices/SKILL.md +64 -0
- package/.pi/skills/architecture/modular-monolith/SKILL.md +65 -0
- package/.pi/skills/architecture/orchestration-driven-soa/SKILL.md +61 -0
- package/.pi/skills/architecture/pipeline/SKILL.md +63 -0
- package/.pi/skills/architecture/service-based/SKILL.md +64 -0
- package/.pi/skills/architecture/service-mesh/SKILL.md +60 -0
- package/.pi/skills/architecture/space-based/SKILL.md +60 -0
- package/.pi/skills/ast-grep/SKILL.md +40 -321
- package/.pi/skills/delivery/debugging-discipline/SKILL.md +36 -0
- package/.pi/skills/delivery/documentation-update/SKILL.md +33 -0
- package/.pi/skills/delivery/requirements-to-implementation/SKILL.md +34 -0
- package/.pi/skills/delivery/risk-based-verification/SKILL.md +43 -0
- package/.pi/skills/delivery/tradeoff-analysis/SKILL.md +34 -0
- package/.pi/skills/engineering/api-contract-design/SKILL.md +38 -0
- package/.pi/skills/engineering/cohesion-coupling/SKILL.md +43 -0
- package/.pi/skills/engineering/complexity-control/SKILL.md +31 -0
- package/.pi/skills/engineering/defensive-programming/SKILL.md +38 -0
- package/.pi/skills/engineering/dependency-management/SKILL.md +29 -0
- package/.pi/skills/engineering/domain-modeling/SKILL.md +32 -0
- package/.pi/skills/engineering/error-handling/SKILL.md +37 -0
- package/.pi/skills/engineering/legacy-code-seams/SKILL.md +35 -0
- package/.pi/skills/engineering/naming-and-intent/SKILL.md +29 -0
- package/.pi/skills/engineering/refactoring-safe-evolution/SKILL.md +35 -0
- package/.pi/skills/engineering/routine-function-design/SKILL.md +34 -0
- package/.pi/skills/engineering/small-change-discipline/SKILL.md +35 -0
- package/.pi/skills/lsp-navigation/SKILL.md +89 -0
- package/.pi/skills/quality/code-review-self-check/SKILL.md +35 -0
- package/.pi/skills/quality/privacy-data-handling/SKILL.md +26 -0
- package/.pi/skills/quality/security-review/SKILL.md +34 -0
- package/.pi/skills/quality/test-strategy/SKILL.md +33 -0
- package/.pi/skills/quality/testability-design/SKILL.md +33 -0
- package/.pi/skills/systems/concurrency-safety/SKILL.md +32 -0
- package/.pi/skills/systems/data-modeling-migrations/SKILL.md +31 -0
- package/.pi/skills/systems/observability-instrumentation/SKILL.md +32 -0
- package/.pi/skills/systems/performance-measurement/SKILL.md +35 -0
- package/.pi/skills/systems/reliability-design/SKILL.md +32 -0
- package/.sentrux/rules.toml +20 -4
- package/AGENTS.md +5 -0
- package/CHANGELOG.md +14 -0
- package/README.md +3 -12
- package/THIRD_PARTY_NOTICES.md +12 -21
- package/package.json +15 -7
- package/vendor/pi-subagents/src/agents.ts +45 -1
- package/vendor/pi-subagents/src/subagents.ts +866 -811
- package/vendor/pi-vcc/src/core/brief.ts +68 -99
- package/vendor/pi-vcc/src/core/settings.ts +2 -2
- package/.agents/skills/caveman/SKILL.md +0 -67
- package/.pi/agents/harness/meta-optimizer.md +0 -36
- package/.pi/extensions/lib/ask-user/dialog.ts +0 -260
- package/.pi/extensions/lib/harness-subagent-auth.ts +0 -207
- package/.pi/extensions/lib/harness-subagent-policy.ts +0 -236
- package/.pi/extensions/pi-model-router-harness.ts +0 -42
- package/.pi/harness/evolution/meta-optimizer.mjs +0 -99
- package/.pi/harness/specs/router-tuning-proposal.schema.json +0 -114
- package/.pi/model-router.example.json +0 -36
- package/.pi/prompts/harness-critic.md +0 -10
- package/.pi/prompts/harness-eval.md +0 -10
- package/.pi/prompts/harness-router-tune.md +0 -52
- package/.pi/scripts/harness-generate-model-router.mjs +0 -327
- package/.pi/scripts/harness-model-router-routing.test.mjs +0 -97
- package/.pi/scripts/harness-sync-model-router.mjs +0 -97
- package/.pi/scripts/vendor-sync-pi-model-router.sh +0 -47
- package/vendor/pi-model-router/.prettierignore +0 -4
- package/vendor/pi-model-router/.prettierrc +0 -5
- package/vendor/pi-model-router/AGENTS.md +0 -39
- package/vendor/pi-model-router/LICENSE +0 -21
- package/vendor/pi-model-router/README.md +0 -99
- package/vendor/pi-model-router/UPSTREAM_PIN.md +0 -10
- package/vendor/pi-model-router/docs/ARCHITECTURE.md +0 -54
- package/vendor/pi-model-router/extensions/commands.ts +0 -720
- package/vendor/pi-model-router/extensions/config.ts +0 -348
- package/vendor/pi-model-router/extensions/constants.ts +0 -1
- package/vendor/pi-model-router/extensions/index.ts +0 -478
- package/vendor/pi-model-router/extensions/provider.ts +0 -580
- package/vendor/pi-model-router/extensions/routing.ts +0 -564
- package/vendor/pi-model-router/extensions/state.ts +0 -52
- package/vendor/pi-model-router/extensions/types.ts +0 -95
- package/vendor/pi-model-router/extensions/ui.ts +0 -144
- package/vendor/pi-model-router/model-router.example.json +0 -48
- package/vendor/pi-model-router/package.json +0 -48
- package/vendor/pi-model-router/tsconfig.json +0 -16
- /package/.pi/{prompts → harness/docs}/planning-rubrics.md +0 -0
- /package/.pi/{extensions/lib → lib}/ask-user/fallback.ts +0 -0
- /package/.pi/{extensions/lib → lib}/ask-user/render.ts +0 -0
- /package/.pi/{extensions/lib → lib}/ask-user/schema.ts +0 -0
- /package/.pi/{extensions/lib → lib}/ask-user/types.ts +0 -0
- /package/.pi/{extensions/lib → lib}/ask-user/validate-core.mjs +0 -0
- /package/.pi/{extensions/lib → lib}/ask-user/validate.ts +0 -0
- /package/.pi/{extensions/lib → lib}/harness-cocoindex-refresh.ts +0 -0
- /package/.pi/{extensions/lib → lib}/harness-paths.ts +0 -0
- /package/.pi/{extensions/lib → lib}/harness-spawn-budget.ts +0 -0
- /package/.pi/{extensions/lib → lib}/harness-vcc-settings.ts +0 -0
- /package/.pi/{extensions/lib → lib}/harness-web/run-cli.ts +0 -0
- /package/.pi/{extensions/lib → lib}/plan-approval/dialog.ts +0 -0
- /package/.pi/{extensions/lib → lib}/plan-approval/schema.ts +0 -0
- /package/.pi/{extensions/lib → lib}/plan-approval-readiness.ts +0 -0
- /package/.pi/{extensions/lib → lib}/plan-debate-eligibility.ts +0 -0
- /package/.pi/{extensions/lib → lib}/plan-debate-focus.ts +0 -0
- /package/.pi/{extensions/lib → lib}/plan-debate-id.ts +0 -0
- /package/.pi/{extensions/lib → lib}/plan-debate-lanes.ts +0 -0
- /package/.pi/{extensions/lib → lib}/plan-debate-round-status.ts +0 -0
- /package/.pi/{extensions/lib → lib}/plan-debate-write-guard.ts +0 -0
- /package/.pi/{extensions/lib → lib}/plan-review-gate.ts +0 -0
- /package/.pi/{extensions/lib → lib}/plan-review-integrator-rules.ts +0 -0
- /package/.pi/{extensions/lib → lib}/plan-scope-guard.ts +0 -0
- /package/.pi/{extensions/lib → lib}/posthog-client.ts +0 -0
- /package/.pi/{extensions/lib → lib}/posthog-node.d.ts +0 -0
|
@@ -128,75 +128,47 @@ export interface TranscriptEntry {
|
|
|
128
128
|
count?: number;
|
|
129
129
|
}
|
|
130
130
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
sections[sections.length - 1].lines.push(line);
|
|
141
|
-
return;
|
|
142
|
-
}
|
|
143
|
-
sections.push({ header, lines: [line] });
|
|
144
|
-
lastHeader = header;
|
|
145
|
-
};
|
|
131
|
+
const stripAssistantSelfTalk = (text: string): string => {
|
|
132
|
+
let raw = text;
|
|
133
|
+
for (let i = 0; i < 2; i++) {
|
|
134
|
+
const stripped = raw.replace(SELF_TALK_PREFIX_RE, "");
|
|
135
|
+
if (stripped === raw) break;
|
|
136
|
+
raw = stripped;
|
|
137
|
+
}
|
|
138
|
+
return raw;
|
|
139
|
+
};
|
|
146
140
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
}
|
|
167
|
-
const text = truncateTokens(raw, TRUNCATE_ASSISTANT);
|
|
168
|
-
if (text) {
|
|
169
|
-
const ref = b.sourceIndex != null ? ` (#${b.sourceIndex})` : "";
|
|
170
|
-
push("[assistant]", text + ref);
|
|
171
|
-
}
|
|
172
|
-
break;
|
|
173
|
-
}
|
|
174
|
-
case "tool_call": {
|
|
175
|
-
// Skip malformed tool calls from streaming providers (empty name / fragmented args).
|
|
176
|
-
if (!b.name || b.name.trim() === "") break;
|
|
177
|
-
const ref = b.sourceIndex != null ? ` (#${b.sourceIndex})` : "";
|
|
178
|
-
const summary = toolOneLiner(b.name, b.args) + ref;
|
|
179
|
-
push("[assistant]", summary);
|
|
180
|
-
break;
|
|
181
|
-
}
|
|
182
|
-
case "tool_result": {
|
|
183
|
-
if (b.isError) {
|
|
184
|
-
const body = firstLine(b.text, 150);
|
|
185
|
-
// Drop empty/placeholder error bodies — keep the line only if it carries info.
|
|
186
|
-
if (!body || body === "(no output)") break;
|
|
187
|
-
const ref = b.sourceIndex != null ? ` (#${b.sourceIndex})` : "";
|
|
188
|
-
const header = `[tool_error] ${b.name}${ref}`;
|
|
189
|
-
push(header, body);
|
|
190
|
-
lastHeader = header;
|
|
191
|
-
}
|
|
192
|
-
break;
|
|
193
|
-
}
|
|
194
|
-
case "thinking":
|
|
195
|
-
break;
|
|
196
|
-
}
|
|
141
|
+
const appendBlockSection = (
|
|
142
|
+
b: NormalizedBlock,
|
|
143
|
+
push: (header: string, line: string) => void,
|
|
144
|
+
): string | null => {
|
|
145
|
+
if (b.kind === "user") {
|
|
146
|
+
if (isNoiseUser(b.text)) return null;
|
|
147
|
+
const text = truncateTokens(collapseSkillText(b.text), TRUNCATE_USER);
|
|
148
|
+
if (text) push("[user]", text + (b.sourceIndex != null ? ` (#${b.sourceIndex})` : ""));
|
|
149
|
+
return "[user]";
|
|
150
|
+
}
|
|
151
|
+
if (b.kind === "assistant") {
|
|
152
|
+
const text = truncateTokens(stripAssistantSelfTalk(b.text), TRUNCATE_ASSISTANT);
|
|
153
|
+
if (text) push("[assistant]", text + (b.sourceIndex != null ? ` (#${b.sourceIndex})` : ""));
|
|
154
|
+
return null;
|
|
155
|
+
}
|
|
156
|
+
if (b.kind === "tool_call") {
|
|
157
|
+
if (!b.name || b.name.trim() === "") return null;
|
|
158
|
+
push("[assistant]", toolOneLiner(b.name, b.args) + (b.sourceIndex != null ? ` (#${b.sourceIndex})` : ""));
|
|
159
|
+
return null;
|
|
197
160
|
}
|
|
161
|
+
if (b.kind === "tool_result" && b.isError) {
|
|
162
|
+
const body = firstLine(b.text, 150);
|
|
163
|
+
if (!body || body === "(no output)") return null;
|
|
164
|
+
const header = `[tool_error] ${b.name}${b.sourceIndex != null ? ` (#${b.sourceIndex})` : ""}`;
|
|
165
|
+
push(header, body);
|
|
166
|
+
return header;
|
|
167
|
+
}
|
|
168
|
+
return null;
|
|
169
|
+
};
|
|
198
170
|
|
|
199
|
-
|
|
171
|
+
const collapseAssistantToolLines = (sections: BriefLine[]): void => {
|
|
200
172
|
for (const sec of sections) {
|
|
201
173
|
if (sec.header !== "[assistant]") continue;
|
|
202
174
|
const out: string[] = [];
|
|
@@ -206,26 +178,19 @@ export const buildBriefSections = (blocks: NormalizedBlock[]): BriefLine[] => {
|
|
|
206
178
|
const base = ref ? line.slice(0, -(ref.length + 3)).trimEnd() : line;
|
|
207
179
|
const last = out.length > 0 ? out[out.length - 1] : "";
|
|
208
180
|
const m = last.match(/^(.*) \((#[\d, #]+)\) x(\d+)$/);
|
|
209
|
-
if (m && m[1] === base) {
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
const prevRef = last.match(/\(#(\d+)\)$/)?.[1];
|
|
213
|
-
out[out.length - 1] = `${base} (#${prevRef}, #${ref}) x2`;
|
|
214
|
-
} else {
|
|
215
|
-
out.push(line);
|
|
216
|
-
}
|
|
181
|
+
if (m && m[1] === base) out[out.length - 1] = `${base} (${m[2]}, #${ref}) x${parseInt(m[3]) + 1}`;
|
|
182
|
+
else if (last.match(/\(#\d+\)$/) && last.replace(/\s*\(#\d+\)$/, "") === base) out[out.length - 1] = `${base} (#${last.match(/\(#(\d+)\)$/)?.[1]}, #${ref}) x2`;
|
|
183
|
+
else out.push(line);
|
|
217
184
|
}
|
|
218
185
|
sec.lines = out;
|
|
219
186
|
}
|
|
187
|
+
};
|
|
220
188
|
|
|
221
|
-
|
|
222
|
-
// be the deciding edits/writes; head is usually exploration noise).
|
|
189
|
+
const capAssistantToolLines = (sections: BriefLine[]): void => {
|
|
223
190
|
const TOOL_CALLS_PER_TURN = 8;
|
|
224
191
|
for (const sec of sections) {
|
|
225
192
|
if (sec.header !== "[assistant]") continue;
|
|
226
|
-
const toolIdxs = sec.lines
|
|
227
|
-
.map((l, i) => (l.startsWith("* ") ? i : -1))
|
|
228
|
-
.filter((i) => i >= 0);
|
|
193
|
+
const toolIdxs = sec.lines.map((l, i) => (l.startsWith("* ") ? i : -1)).filter((i) => i >= 0);
|
|
229
194
|
if (toolIdxs.length <= TOOL_CALLS_PER_TURN) continue;
|
|
230
195
|
const dropCount = toolIdxs.length - TOOL_CALLS_PER_TURN;
|
|
231
196
|
const dropSet = new Set(toolIdxs.slice(0, dropCount));
|
|
@@ -242,36 +207,40 @@ export const buildBriefSections = (blocks: NormalizedBlock[]): BriefLine[] => {
|
|
|
242
207
|
}
|
|
243
208
|
sec.lines = next;
|
|
244
209
|
}
|
|
210
|
+
};
|
|
245
211
|
|
|
246
|
-
|
|
247
|
-
// E.g. 20 back-to-back `[tool_error] bash (#N) ... Command aborted` become one
|
|
248
|
-
// `[tool_error] bash (#refs...) x20` entry.
|
|
212
|
+
const collapseConsecutiveToolErrors = (sections: BriefLine[]): BriefLine[] => {
|
|
249
213
|
const collapsedErrors: BriefLine[] = [];
|
|
250
214
|
for (const sec of sections) {
|
|
251
215
|
const m = sec.header.match(/^\[tool_error\]\s+(\S+?)(?:\s*\(#(\d+)\))?$/);
|
|
252
|
-
if (!m || sec.lines.length !== 1) {
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
}
|
|
256
|
-
const tool = m[1];
|
|
257
|
-
const ref = m[2];
|
|
258
|
-
const body = sec.lines[0];
|
|
259
|
-
const prev = collapsedErrors[collapsedErrors.length - 1];
|
|
260
|
-
const prevMatch = prev?.header.match(
|
|
261
|
-
/^\[tool_error\]\s+(\S+?)\s*\(((?:#\d+(?:,\s*)?)+)\)(?:\s*x(\d+))?$/,
|
|
262
|
-
);
|
|
216
|
+
if (!m || sec.lines.length !== 1) { collapsedErrors.push(sec); continue; }
|
|
217
|
+
const [tool, ref, body, prev] = [m[1], m[2], sec.lines[0], collapsedErrors[collapsedErrors.length - 1]];
|
|
218
|
+
const prevMatch = prev?.header.match(/^\[tool_error\]\s+(\S+?)\s*\(((?:#\d+(?:,\s*)?)+)\)(?:\s*x(\d+))?$/);
|
|
263
219
|
if (prev && prevMatch && prevMatch[1] === tool && prev.lines.length === 1 && prev.lines[0] === body) {
|
|
264
220
|
const refs = prevMatch[2] + (ref ? `, #${ref}` : "");
|
|
265
221
|
const count = prevMatch[3] ? parseInt(prevMatch[3]) + 1 : 2;
|
|
266
222
|
prev.header = `[tool_error] ${tool} (${refs}) x${count}`;
|
|
267
|
-
} else
|
|
268
|
-
collapsedErrors.push(sec);
|
|
269
|
-
}
|
|
223
|
+
} else collapsedErrors.push(sec);
|
|
270
224
|
}
|
|
271
|
-
|
|
272
|
-
|
|
225
|
+
return collapsedErrors;
|
|
226
|
+
};
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Build BriefLine sections from NormalizedBlocks.
|
|
230
|
+
*/
|
|
231
|
+
export const buildBriefSections = (blocks: NormalizedBlock[]): BriefLine[] => {
|
|
232
|
+
let lastHeader = "";
|
|
233
|
+
const sections: BriefLine[] = [];
|
|
234
|
+
const push = (header: string, line: string) => {
|
|
235
|
+
if (header === lastHeader && sections.length > 0) sections[sections.length - 1].lines.push(line);
|
|
236
|
+
else sections.push({ header, lines: [line] });
|
|
237
|
+
lastHeader = header;
|
|
238
|
+
};
|
|
273
239
|
|
|
274
|
-
|
|
240
|
+
for (const b of blocks) lastHeader = appendBlockSection(b, push) ?? lastHeader;
|
|
241
|
+
collapseAssistantToolLines(sections);
|
|
242
|
+
capAssistantToolLines(sections);
|
|
243
|
+
return collapseConsecutiveToolErrors(sections);
|
|
275
244
|
};
|
|
276
245
|
|
|
277
246
|
/**
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* ultimate-pi harness settings (env-only). Re-exported for vendored pi-vcc layout.
|
|
3
3
|
*/
|
|
4
|
-
export type { PiVccSettings } from "../../../../.pi/
|
|
4
|
+
export type { PiVccSettings } from "../../../../.pi/lib/harness-vcc-settings.js";
|
|
5
5
|
export {
|
|
6
6
|
loadSettings,
|
|
7
7
|
scaffoldSettings,
|
|
8
|
-
} from "../../../../.pi/
|
|
8
|
+
} from "../../../../.pi/lib/harness-vcc-settings.js";
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: caveman
|
|
3
|
-
description: >
|
|
4
|
-
Ultra-compressed communication mode. Cuts token usage ~75% by speaking like caveman
|
|
5
|
-
while keeping full technical accuracy. Supports intensity levels: lite, full (default), ultra,
|
|
6
|
-
wenyan-lite, wenyan-full, wenyan-ultra.
|
|
7
|
-
Use when user says "caveman mode", "talk like caveman", "use caveman", "less tokens",
|
|
8
|
-
"be brief", or invokes /caveman. Also auto-triggers when token efficiency is requested.
|
|
9
|
-
---
|
|
10
|
-
|
|
11
|
-
Respond terse like smart caveman. All technical substance stay. Only fluff die.
|
|
12
|
-
|
|
13
|
-
## Persistence
|
|
14
|
-
|
|
15
|
-
ACTIVE EVERY RESPONSE. No revert after many turns. No filler drift. Still active if unsure. Off only: "stop caveman" / "normal mode".
|
|
16
|
-
|
|
17
|
-
Default: **full**. Switch: `/caveman lite|full|ultra`.
|
|
18
|
-
|
|
19
|
-
## Rules
|
|
20
|
-
|
|
21
|
-
Drop: articles (a/an/the), filler (just/really/basically/actually/simply), pleasantries (sure/certainly/of course/happy to), hedging. Fragments OK. Short synonyms (big not extensive, fix not "implement a solution for"). Technical terms exact. Code blocks unchanged. Errors quoted exact.
|
|
22
|
-
|
|
23
|
-
Pattern: `[thing] [action] [reason]. [next step].`
|
|
24
|
-
|
|
25
|
-
Not: "Sure! I'd be happy to help you with that. The issue you're experiencing is likely caused by..."
|
|
26
|
-
Yes: "Bug in auth middleware. Token expiry check use `<` not `<=`. Fix:"
|
|
27
|
-
|
|
28
|
-
## Intensity
|
|
29
|
-
|
|
30
|
-
| Level | What change |
|
|
31
|
-
|-------|------------|
|
|
32
|
-
| **lite** | No filler/hedging. Keep articles + full sentences. Professional but tight |
|
|
33
|
-
| **full** | Drop articles, fragments OK, short synonyms. Classic caveman |
|
|
34
|
-
| **ultra** | Abbreviate (DB/auth/config/req/res/fn/impl), strip conjunctions, arrows for causality (X → Y), one word when one word enough |
|
|
35
|
-
| **wenyan-lite** | Semi-classical. Drop filler/hedging but keep grammar structure, classical register |
|
|
36
|
-
| **wenyan-full** | Maximum classical terseness. Fully 文言文. 80-90% character reduction. Classical sentence patterns, verbs precede objects, subjects often omitted, classical particles (之/乃/為/其) |
|
|
37
|
-
| **wenyan-ultra** | Extreme abbreviation while keeping classical Chinese feel. Maximum compression, ultra terse |
|
|
38
|
-
|
|
39
|
-
Example — "Why React component re-render?"
|
|
40
|
-
- lite: "Your component re-renders because you create a new object reference each render. Wrap it in `useMemo`."
|
|
41
|
-
- full: "New object ref each render. Inline object prop = new ref = re-render. Wrap in `useMemo`."
|
|
42
|
-
- ultra: "Inline obj prop → new ref → re-render. `useMemo`."
|
|
43
|
-
- wenyan-lite: "組件頻重繪,以每繪新生對象參照故。以 useMemo 包之。"
|
|
44
|
-
- wenyan-full: "物出新參照,致重繪。useMemo .Wrap之。"
|
|
45
|
-
- wenyan-ultra: "新參照→重繪。useMemo Wrap。"
|
|
46
|
-
|
|
47
|
-
Example — "Explain database connection pooling."
|
|
48
|
-
- lite: "Connection pooling reuses open connections instead of creating new ones per request. Avoids repeated handshake overhead."
|
|
49
|
-
- full: "Pool reuse open DB connections. No new connection per request. Skip handshake overhead."
|
|
50
|
-
- ultra: "Pool = reuse DB conn. Skip handshake → fast under load."
|
|
51
|
-
- wenyan-full: "池reuse open connection。不每req新開。skip handshake overhead。"
|
|
52
|
-
- wenyan-ultra: "池reuse conn。skip handshake → fast。"
|
|
53
|
-
|
|
54
|
-
## Auto-Clarity
|
|
55
|
-
|
|
56
|
-
Drop caveman for: security warnings, irreversible action confirmations, multi-step sequences where fragment order risks misread, user asks to clarify or repeats question. Resume caveman after clear part done.
|
|
57
|
-
|
|
58
|
-
Example — destructive op:
|
|
59
|
-
> **Warning:** This will permanently delete all rows in the `users` table and cannot be undone.
|
|
60
|
-
> ```sql
|
|
61
|
-
> DROP TABLE users;
|
|
62
|
-
> ```
|
|
63
|
-
> Caveman resume. Verify backup exist first.
|
|
64
|
-
|
|
65
|
-
## Boundaries
|
|
66
|
-
|
|
67
|
-
Code/commits/PRs: write normal. "stop caveman" or "normal mode": revert. Level persist until changed or session end.
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: Harness meta optimizer proposing policy/prompt/router improvements from trace evidence.
|
|
3
|
-
tools: read, grep, find, ls, submit_human_required
|
|
4
|
-
extensions: false
|
|
5
|
-
disallowed_tools: ask_user
|
|
6
|
-
thinking: high
|
|
7
|
-
max_turns: 25
|
|
8
|
-
---
|
|
9
|
-
|
|
10
|
-
You are the Harness Meta Optimizer.
|
|
11
|
-
|
|
12
|
-
## Mission
|
|
13
|
-
|
|
14
|
-
Generate conservative, evidence-backed router-tuning proposals from spawn context (`mode: tune`). Never write `.pi/model-router.json` or call `ask_user` — parent runs proposal scripts and approval.
|
|
15
|
-
|
|
16
|
-
## Process
|
|
17
|
-
|
|
18
|
-
1. Validate evidence completeness: sample count, success-rate delta, cost-per-task delta, regression guard status.
|
|
19
|
-
2. Rank proposals by quality/cost impact and implementation risk.
|
|
20
|
-
3. Emit proposal JSON compatible with router-tuning workflow; reject incomplete evidence with `tuning_status: human_required`.
|
|
21
|
-
|
|
22
|
-
## Guardrails
|
|
23
|
-
|
|
24
|
-
- Read-only — no live router mutation.
|
|
25
|
-
- Never speculate without concrete benchmark evidence.
|
|
26
|
-
- Never set `inherit_context: true` on harness agents.
|
|
27
|
-
|
|
28
|
-
## Output
|
|
29
|
-
|
|
30
|
-
```json
|
|
31
|
-
{
|
|
32
|
-
"tuning_status": "proposed",
|
|
33
|
-
"proposal_summary": "…",
|
|
34
|
-
"evidence_gates": { "sample_ok": true, "regression_guard": "pass" }
|
|
35
|
-
}
|
|
36
|
-
```
|
|
@@ -1,260 +0,0 @@
|
|
|
1
|
-
import type { ExtensionUIContext } from "@earendil-works/pi-coding-agent";
|
|
2
|
-
import {
|
|
3
|
-
Editor,
|
|
4
|
-
type EditorTheme,
|
|
5
|
-
Key,
|
|
6
|
-
matchesKey,
|
|
7
|
-
truncateToWidth,
|
|
8
|
-
} from "@earendil-works/pi-tui";
|
|
9
|
-
import type { AskResponse, DialogResult, ValidatedAskParams } from "./types.js";
|
|
10
|
-
|
|
11
|
-
type DisplayOption = {
|
|
12
|
-
title: string;
|
|
13
|
-
description?: string;
|
|
14
|
-
isFreeform?: boolean;
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
interface CustomAnswer {
|
|
18
|
-
response: AskResponse;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
function withTimeout<T>(
|
|
22
|
-
promise: Promise<T | null>,
|
|
23
|
-
ms: number | undefined,
|
|
24
|
-
): Promise<T | null> {
|
|
25
|
-
if (!ms) return promise;
|
|
26
|
-
return Promise.race([
|
|
27
|
-
promise,
|
|
28
|
-
new Promise<null>((resolve) => {
|
|
29
|
-
setTimeout(() => resolve(null), ms);
|
|
30
|
-
}),
|
|
31
|
-
]);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
export async function runAskDialog(
|
|
35
|
-
ui: ExtensionUIContext,
|
|
36
|
-
validated: ValidatedAskParams,
|
|
37
|
-
): Promise<DialogResult> {
|
|
38
|
-
const { question, context, options, allowMultiple, allowFreeform } =
|
|
39
|
-
validated;
|
|
40
|
-
|
|
41
|
-
const displayOptions: DisplayOption[] = [...options];
|
|
42
|
-
if (allowFreeform) {
|
|
43
|
-
displayOptions.push({
|
|
44
|
-
title: "Type something…",
|
|
45
|
-
isFreeform: true,
|
|
46
|
-
});
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
// Freeform-only: no listed options
|
|
50
|
-
if (displayOptions.length === 0) {
|
|
51
|
-
const text = await ui.input(question, "");
|
|
52
|
-
if (!text?.trim()) {
|
|
53
|
-
return { response: null, cancelled: true };
|
|
54
|
-
}
|
|
55
|
-
return {
|
|
56
|
-
response: { kind: "freeform", text: text.trim() },
|
|
57
|
-
cancelled: false,
|
|
58
|
-
};
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
const result = await withTimeout(
|
|
62
|
-
ui.custom<CustomAnswer | null>((tui, theme, _kb, done) => {
|
|
63
|
-
let optionIndex = 0;
|
|
64
|
-
let editMode = false;
|
|
65
|
-
const selected = new Set<number>();
|
|
66
|
-
let cachedLines: string[] | undefined;
|
|
67
|
-
|
|
68
|
-
const editorTheme: EditorTheme = {
|
|
69
|
-
borderColor: (s) => theme.fg("accent", s),
|
|
70
|
-
selectList: {
|
|
71
|
-
selectedPrefix: (t) => theme.fg("accent", t),
|
|
72
|
-
selectedText: (t) => theme.fg("accent", t),
|
|
73
|
-
description: (t) => theme.fg("muted", t),
|
|
74
|
-
scrollInfo: (t) => theme.fg("dim", t),
|
|
75
|
-
noMatch: (t) => theme.fg("warning", t),
|
|
76
|
-
},
|
|
77
|
-
};
|
|
78
|
-
const editor = new Editor(tui, editorTheme);
|
|
79
|
-
|
|
80
|
-
editor.onSubmit = (value) => {
|
|
81
|
-
const trimmed = value.trim();
|
|
82
|
-
if (trimmed) {
|
|
83
|
-
done({ response: { kind: "freeform", text: trimmed } });
|
|
84
|
-
} else {
|
|
85
|
-
editMode = false;
|
|
86
|
-
editor.setText("");
|
|
87
|
-
refresh();
|
|
88
|
-
}
|
|
89
|
-
};
|
|
90
|
-
|
|
91
|
-
function refresh() {
|
|
92
|
-
cachedLines = undefined;
|
|
93
|
-
tui.requestRender();
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
function submitSelection() {
|
|
97
|
-
if (allowMultiple) {
|
|
98
|
-
const titles = [...selected]
|
|
99
|
-
.sort((a, b) => a - b)
|
|
100
|
-
.map((i) => displayOptions[i].title)
|
|
101
|
-
.filter((t) => t !== "Type something…");
|
|
102
|
-
if (titles.length === 0) return;
|
|
103
|
-
done({ response: { kind: "selection", selections: titles } });
|
|
104
|
-
return;
|
|
105
|
-
}
|
|
106
|
-
const opt = displayOptions[optionIndex];
|
|
107
|
-
if (opt.isFreeform) {
|
|
108
|
-
editMode = true;
|
|
109
|
-
refresh();
|
|
110
|
-
return;
|
|
111
|
-
}
|
|
112
|
-
done({
|
|
113
|
-
response: { kind: "selection", selections: [opt.title] },
|
|
114
|
-
});
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
function handleInput(data: string) {
|
|
118
|
-
if (editMode) {
|
|
119
|
-
if (matchesKey(data, Key.escape)) {
|
|
120
|
-
editMode = false;
|
|
121
|
-
editor.setText("");
|
|
122
|
-
refresh();
|
|
123
|
-
return;
|
|
124
|
-
}
|
|
125
|
-
editor.handleInput(data);
|
|
126
|
-
refresh();
|
|
127
|
-
return;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
if (matchesKey(data, Key.up)) {
|
|
131
|
-
optionIndex = Math.max(0, optionIndex - 1);
|
|
132
|
-
refresh();
|
|
133
|
-
return;
|
|
134
|
-
}
|
|
135
|
-
if (matchesKey(data, Key.down)) {
|
|
136
|
-
optionIndex = Math.min(displayOptions.length - 1, optionIndex + 1);
|
|
137
|
-
refresh();
|
|
138
|
-
return;
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
if (allowMultiple && matchesKey(data, Key.space)) {
|
|
142
|
-
const opt = displayOptions[optionIndex];
|
|
143
|
-
if (!opt.isFreeform) {
|
|
144
|
-
if (selected.has(optionIndex)) {
|
|
145
|
-
selected.delete(optionIndex);
|
|
146
|
-
} else {
|
|
147
|
-
selected.add(optionIndex);
|
|
148
|
-
}
|
|
149
|
-
refresh();
|
|
150
|
-
}
|
|
151
|
-
return;
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
if (matchesKey(data, Key.enter)) {
|
|
155
|
-
submitSelection();
|
|
156
|
-
return;
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
if (matchesKey(data, Key.escape)) {
|
|
160
|
-
done(null);
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
function render(width: number): string[] {
|
|
165
|
-
if (cachedLines) return cachedLines;
|
|
166
|
-
|
|
167
|
-
const lines: string[] = [];
|
|
168
|
-
const add = (s: string) => lines.push(truncateToWidth(s, width));
|
|
169
|
-
const useOverlay = validated.displayMode !== "inline";
|
|
170
|
-
|
|
171
|
-
if (useOverlay) {
|
|
172
|
-
add(theme.fg("accent", "─".repeat(width)));
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
if (context) {
|
|
176
|
-
for (const line of context.split("\n")) {
|
|
177
|
-
add(theme.fg("muted", ` ${line}`));
|
|
178
|
-
}
|
|
179
|
-
lines.push("");
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
add(theme.fg("text", ` ${question}`));
|
|
183
|
-
lines.push("");
|
|
184
|
-
|
|
185
|
-
for (let i = 0; i < displayOptions.length; i++) {
|
|
186
|
-
const opt = displayOptions[i];
|
|
187
|
-
const isFreeform = opt.isFreeform === true;
|
|
188
|
-
const focused = i === optionIndex;
|
|
189
|
-
const checked = selected.has(i);
|
|
190
|
-
let prefix = " ";
|
|
191
|
-
if (allowMultiple && !isFreeform) {
|
|
192
|
-
prefix = checked ? theme.fg("accent", "[x] ") : "[ ] ";
|
|
193
|
-
} else if (focused) {
|
|
194
|
-
prefix = theme.fg("accent", "> ");
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
const num = `${i + 1}. `;
|
|
198
|
-
const label = opt.title;
|
|
199
|
-
if (isFreeform && editMode && focused) {
|
|
200
|
-
add(prefix + theme.fg("accent", `${num}${label} ✎`));
|
|
201
|
-
} else if (focused && !allowMultiple) {
|
|
202
|
-
add(prefix + theme.fg("accent", `${num}${label}`));
|
|
203
|
-
} else {
|
|
204
|
-
add(`${prefix}${theme.fg("text", `${num}${label}`)}`);
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
if (opt.description) {
|
|
208
|
-
add(` ${theme.fg("muted", opt.description)}`);
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
if (editMode) {
|
|
213
|
-
lines.push("");
|
|
214
|
-
add(theme.fg("muted", " Your answer:"));
|
|
215
|
-
for (const line of editor.render(width - 2)) {
|
|
216
|
-
add(` ${line}`);
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
lines.push("");
|
|
221
|
-
if (editMode) {
|
|
222
|
-
add(theme.fg("dim", " Enter to submit • Esc to go back"));
|
|
223
|
-
} else if (allowMultiple) {
|
|
224
|
-
add(
|
|
225
|
-
theme.fg(
|
|
226
|
-
"dim",
|
|
227
|
-
" ↑↓ navigate • Space toggle • Enter confirm • Esc cancel",
|
|
228
|
-
),
|
|
229
|
-
);
|
|
230
|
-
} else {
|
|
231
|
-
add(
|
|
232
|
-
theme.fg("dim", " ↑↓ navigate • Enter to select • Esc to cancel"),
|
|
233
|
-
);
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
if (useOverlay) {
|
|
237
|
-
add(theme.fg("accent", "─".repeat(width)));
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
cachedLines = lines;
|
|
241
|
-
return lines;
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
return {
|
|
245
|
-
render,
|
|
246
|
-
invalidate: () => {
|
|
247
|
-
cachedLines = undefined;
|
|
248
|
-
},
|
|
249
|
-
handleInput,
|
|
250
|
-
};
|
|
251
|
-
}),
|
|
252
|
-
validated.timeout,
|
|
253
|
-
);
|
|
254
|
-
|
|
255
|
-
if (!result) {
|
|
256
|
-
return { response: null, cancelled: true };
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
return { response: result.response, cancelled: false };
|
|
260
|
-
}
|