ultimate-pi 0.1.7 → 0.2.2
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/graphify/.graphify_version +1 -0
- package/.agents/skills/graphify/SKILL.md +1204 -0
- package/.agents/skills/wiki-autoresearch/SKILL.md +225 -97
- package/.agents/skills/wiki-autoresearch/references/program.md +28 -62
- package/.agents/skills/wiki-autoresearch/references/quality-sites.md +32 -0
- package/.env.example +5 -1
- package/.gitattributes +1 -0
- package/.github/workflows/publish-github-packages.yml +1 -1
- package/.pi/SYSTEM.md +72 -18
- package/.pi/agents/harness/adversary.md +32 -0
- package/.pi/agents/harness/evaluator.md +32 -0
- package/.pi/agents/harness/executor.md +34 -0
- package/.pi/agents/harness/meta-optimizer.md +33 -0
- package/.pi/agents/harness/planner.md +33 -0
- package/.pi/agents/harness/tie-breaker.md +35 -0
- package/.pi/agents/harness/trace-librarian.md +32 -0
- package/.pi/extensions/banner.png +0 -0
- package/.pi/extensions/budget-guard.ts +265 -0
- package/.pi/extensions/custom-footer.ts +194 -22
- package/.pi/extensions/custom-header.ts +47 -9
- package/.pi/extensions/debate-orchestrator.ts +479 -0
- package/.pi/extensions/harness-live-widget.ts +438 -0
- package/.pi/extensions/policy-gate.ts +349 -0
- package/.pi/extensions/review-integrity.ts +198 -0
- package/.pi/extensions/test-diff-integrity.ts +240 -0
- package/.pi/extensions/trace-recorder.ts +315 -0
- package/.pi/harness/README.md +23 -0
- package/.pi/harness/router/README.md +35 -0
- package/.pi/harness/router/apply-router-proposal.mjs +153 -0
- package/.pi/harness/router/propose-router-tuning.mjs +149 -0
- package/.pi/harness/specs/README.md +37 -0
- package/.pi/harness/specs/adversary-report.schema.json +53 -0
- package/.pi/harness/specs/budget-exhausted-event.schema.json +93 -0
- package/.pi/harness/specs/consensus-packet.schema.json +175 -0
- package/.pi/harness/specs/eval-verdict.schema.json +59 -0
- package/.pi/harness/specs/incident-record.schema.json +84 -0
- package/.pi/harness/specs/plan-packet.schema.json +90 -0
- package/.pi/harness/specs/round-result.schema.json +126 -0
- package/.pi/harness/specs/router-tuning-proposal.schema.json +114 -0
- package/.pi/harness/specs/run-trace.schema.json +107 -0
- package/.pi/lib/harness-ui-state.ts +311 -0
- package/.pi/mcp.json +4 -0
- package/.pi/model-router.json +93 -93
- package/.pi/prompts/graphify.md +23 -0
- package/.pi/prompts/harness-abort.md +41 -0
- package/.pi/prompts/harness-auto.md +83 -0
- package/.pi/prompts/harness-critic.md +52 -0
- package/.pi/prompts/harness-eval.md +51 -0
- package/.pi/prompts/harness-incident.md +51 -0
- package/.pi/prompts/harness-plan.md +64 -0
- package/.pi/prompts/harness-review.md +52 -0
- package/.pi/prompts/harness-router-tune.md +74 -0
- package/.pi/prompts/harness-run.md +59 -0
- package/.pi/prompts/harness-setup.md +316 -216
- package/.pi/prompts/harness-trace.md +51 -0
- package/.pi/prompts/wiki-autoresearch.md +9 -7
- package/.pi/prompts/wiki-save.md +20 -0
- package/.pi/skills/agent-router/SKILL.md +2 -4
- package/.pi/skills/ast-grep/SKILL.md +354 -0
- package/.pi/sounds/project-sounds.json +18 -24
- package/AGENTS.md +30 -0
- package/CHANGELOG.md +89 -0
- package/CONTRIBUTING.md +51 -1
- package/README.md +264 -20
- package/biome.json +8 -2
- package/lefthook.yml +3 -2
- package/node_modules/@sting8k/pi-vcc/README.md +200 -0
- package/node_modules/@sting8k/pi-vcc/index.ts +14 -0
- package/node_modules/@sting8k/pi-vcc/package.json +26 -0
- package/node_modules/@sting8k/pi-vcc/scripts/audit-sessions.ts +88 -0
- package/node_modules/@sting8k/pi-vcc/scripts/benchmark-real-sessions.ts +25 -0
- package/node_modules/@sting8k/pi-vcc/scripts/compare-before-after.ts +36 -0
- package/node_modules/@sting8k/pi-vcc/scripts/dump-branch-output.ts +20 -0
- package/node_modules/@sting8k/pi-vcc/src/commands/pi-vcc.ts +36 -0
- package/node_modules/@sting8k/pi-vcc/src/commands/vcc-recall.ts +65 -0
- package/node_modules/@sting8k/pi-vcc/src/core/brief.ts +381 -0
- package/node_modules/@sting8k/pi-vcc/src/core/build-sections.ts +79 -0
- package/node_modules/@sting8k/pi-vcc/src/core/content.ts +60 -0
- package/node_modules/@sting8k/pi-vcc/src/core/filter-noise.ts +42 -0
- package/node_modules/@sting8k/pi-vcc/src/core/format-recall.ts +27 -0
- package/node_modules/@sting8k/pi-vcc/src/core/format.ts +49 -0
- package/node_modules/@sting8k/pi-vcc/src/core/lineage.ts +26 -0
- package/node_modules/@sting8k/pi-vcc/src/core/load-messages.ts +41 -0
- package/node_modules/@sting8k/pi-vcc/src/core/normalize.ts +66 -0
- package/node_modules/@sting8k/pi-vcc/src/core/recall-scope.ts +14 -0
- package/node_modules/@sting8k/pi-vcc/src/core/render-entries.ts +55 -0
- package/node_modules/@sting8k/pi-vcc/src/core/report.ts +237 -0
- package/node_modules/@sting8k/pi-vcc/src/core/sanitize.ts +5 -0
- package/node_modules/@sting8k/pi-vcc/src/core/search-entries.ts +221 -0
- package/node_modules/@sting8k/pi-vcc/src/core/settings.ts +77 -0
- package/node_modules/@sting8k/pi-vcc/src/core/skill-collapse.ts +35 -0
- package/node_modules/@sting8k/pi-vcc/src/core/summarize.ts +157 -0
- package/node_modules/@sting8k/pi-vcc/src/core/tool-args.ts +14 -0
- package/node_modules/@sting8k/pi-vcc/src/details.ts +7 -0
- package/node_modules/@sting8k/pi-vcc/src/extract/commits.ts +69 -0
- package/node_modules/@sting8k/pi-vcc/src/extract/files.ts +80 -0
- package/node_modules/@sting8k/pi-vcc/src/extract/goals.ts +79 -0
- package/node_modules/@sting8k/pi-vcc/src/extract/preferences.ts +55 -0
- package/node_modules/@sting8k/pi-vcc/src/hooks/before-compact.ts +322 -0
- package/node_modules/@sting8k/pi-vcc/src/sections.ts +12 -0
- package/node_modules/@sting8k/pi-vcc/src/tools/recall.ts +109 -0
- package/node_modules/@sting8k/pi-vcc/src/types.ts +14 -0
- package/node_modules/@sting8k/pi-vcc/tests/before-compact-hook.test.ts +181 -0
- package/node_modules/@sting8k/pi-vcc/tests/before-compact.test.ts +140 -0
- package/node_modules/@sting8k/pi-vcc/tests/brief.test.ts +206 -0
- package/node_modules/@sting8k/pi-vcc/tests/build-sections.test.ts +59 -0
- package/node_modules/@sting8k/pi-vcc/tests/compile.test.ts +80 -0
- package/node_modules/@sting8k/pi-vcc/tests/content.test.ts +31 -0
- package/node_modules/@sting8k/pi-vcc/tests/extract-goals.test.ts +86 -0
- package/node_modules/@sting8k/pi-vcc/tests/extract-preferences.test.ts +30 -0
- package/node_modules/@sting8k/pi-vcc/tests/filter-noise.test.ts +61 -0
- package/node_modules/@sting8k/pi-vcc/tests/fixtures.ts +61 -0
- package/node_modules/@sting8k/pi-vcc/tests/format-recall.test.ts +30 -0
- package/node_modules/@sting8k/pi-vcc/tests/format.test.ts +62 -0
- package/node_modules/@sting8k/pi-vcc/tests/lineage.test.ts +33 -0
- package/node_modules/@sting8k/pi-vcc/tests/load-messages.test.ts +51 -0
- package/node_modules/@sting8k/pi-vcc/tests/normalize.test.ts +97 -0
- package/node_modules/@sting8k/pi-vcc/tests/real-sessions.test.ts +38 -0
- package/node_modules/@sting8k/pi-vcc/tests/recall-expand.test.ts +15 -0
- package/node_modules/@sting8k/pi-vcc/tests/recall-scope.test.ts +32 -0
- package/node_modules/@sting8k/pi-vcc/tests/recall-tool-scope.test.ts +67 -0
- package/node_modules/@sting8k/pi-vcc/tests/render-entries.test.ts +62 -0
- package/node_modules/@sting8k/pi-vcc/tests/report.test.ts +44 -0
- package/node_modules/@sting8k/pi-vcc/tests/sanitize.test.ts +24 -0
- package/node_modules/@sting8k/pi-vcc/tests/search-entries.test.ts +144 -0
- package/node_modules/@sting8k/pi-vcc/tests/support/load-session.ts +23 -0
- package/node_modules/@sting8k/pi-vcc/tests/support/real-sessions.ts +51 -0
- package/package.json +15 -4
- package/scripts/__pycache__/merge_graphify_corpora.cpython-314.pyc +0 -0
- package/scripts/index_youtube_urls.py +376 -0
- package/scripts/merge_graphify_corpora.py +398 -0
- package/scripts/regen_graphify_html.py +46 -0
- package/.agents/skills/defuddle/SKILL.md +0 -90
- package/.agents/skills/wiki/SKILL.md +0 -215
- package/.agents/skills/wiki/references/css-snippets.md +0 -122
- package/.agents/skills/wiki/references/frontmatter.md +0 -107
- package/.agents/skills/wiki/references/git-setup.md +0 -58
- package/.agents/skills/wiki/references/mcp-setup.md +0 -149
- package/.agents/skills/wiki/references/modes.md +0 -259
- package/.agents/skills/wiki/references/plugins.md +0 -96
- package/.agents/skills/wiki/references/rest-api.md +0 -124
- package/.agents/skills/wiki-fold/SKILL.md +0 -204
- package/.agents/skills/wiki-fold/references/fold-template.md +0 -133
- package/.agents/skills/wiki-ingest/SKILL.md +0 -288
- package/.agents/skills/wiki-lint/SKILL.md +0 -183
- package/.agents/skills/wiki-query/SKILL.md +0 -176
- package/.pi/agents/rethink.md +0 -140
- package/.pi/agents/wiki-ingest.md +0 -67
- package/.pi/agents/wiki-lint.md +0 -75
- package/.pi/internal/cursor-sdk-transcript-parser.ts +0 -59
- package/.pi/prompts/save.md +0 -16
- package/.pi/prompts/wiki.md +0 -23
- package/.pi/providers/cursor-sdk-provider.test.mjs +0 -476
- package/.pi/providers/cursor-sdk-provider.ts +0 -1085
- package/vault/AGENTS.md +0 -37
- package/vault/wiki/_templates/comparison.md +0 -39
- package/vault/wiki/_templates/concept.md +0 -40
- package/vault/wiki/_templates/decision.md +0 -21
- package/vault/wiki/_templates/entity.md +0 -32
- package/vault/wiki/_templates/flow.md +0 -14
- package/vault/wiki/_templates/module.md +0 -18
- package/vault/wiki/_templates/question.md +0 -31
- package/vault/wiki/_templates/source.md +0 -39
- package/vault/wiki/concepts/AST-Aware Code Chunking.md +0 -44
- package/vault/wiki/concepts/Build-Time Prompt Compilation.md +0 -107
- package/vault/wiki/concepts/Context Engine (AI Coding).md +0 -47
- package/vault/wiki/concepts/Context-Aware System Reminders.md +0 -61
- package/vault/wiki/concepts/Contextualized Text Embedding.md +0 -42
- package/vault/wiki/concepts/Contractor vs Employee AI Model.md +0 -55
- package/vault/wiki/concepts/Dual-Model Agent Architecture.md +0 -65
- package/vault/wiki/concepts/Late Chunking vs Early Chunking.md +0 -43
- package/vault/wiki/concepts/Majority Vote Ensembling.md +0 -68
- package/vault/wiki/concepts/Meta-Harness.md +0 -16
- package/vault/wiki/concepts/Multi-Agent AI Coding Architecture.md +0 -75
- package/vault/wiki/concepts/Prompt Enhancement.md +0 -90
- package/vault/wiki/concepts/Prompt Renderer.md +0 -89
- package/vault/wiki/concepts/Semantic Codebase Indexing.md +0 -67
- package/vault/wiki/concepts/additive-config-hierarchy.md +0 -16
- package/vault/wiki/concepts/agent-artifacts-verifiable-deliverables.md +0 -71
- package/vault/wiki/concepts/agent-browser-browser-automation.md +0 -99
- package/vault/wiki/concepts/agent-codebase-interface.md +0 -43
- package/vault/wiki/concepts/agent-harness-architecture.md +0 -67
- package/vault/wiki/concepts/agent-loop-detection-patterns.md +0 -133
- package/vault/wiki/concepts/agent-search-enforcement.md +0 -126
- package/vault/wiki/concepts/agent-skills-ecosystem.md +0 -74
- package/vault/wiki/concepts/agent-skills-pattern.md +0 -68
- package/vault/wiki/concepts/agentic-harness-context-enforcement.md +0 -91
- package/vault/wiki/concepts/agentic-harness.md +0 -34
- package/vault/wiki/concepts/agentic-orchestration-pipeline.md +0 -56
- package/vault/wiki/concepts/agentic-search-no-embeddings.md +0 -18
- package/vault/wiki/concepts/anthropic-context-engineering.md +0 -13
- package/vault/wiki/concepts/antigravity-agent-first-architecture.md +0 -61
- package/vault/wiki/concepts/ast-compression.md +0 -19
- package/vault/wiki/concepts/ast-truncation.md +0 -66
- package/vault/wiki/concepts/barrel-files.md +0 -37
- package/vault/wiki/concepts/browser-harness-agent.md +0 -41
- package/vault/wiki/concepts/browser-subagent-visual-verification.md +0 -82
- package/vault/wiki/concepts/codebase-intelligence-ecosystem-comparison.md +0 -192
- package/vault/wiki/concepts/codebase-intelligence-harness-integration.md +0 -161
- package/vault/wiki/concepts/codebase-to-context-ingestion.md +0 -46
- package/vault/wiki/concepts/codex-harness-innovations.md +0 -147
- package/vault/wiki/concepts/consensus-debate-flow.md +0 -17
- package/vault/wiki/concepts/consensus-debate.md +0 -206
- package/vault/wiki/concepts/content-addressed-spec-identity.md +0 -166
- package/vault/wiki/concepts/context-anxiety.md +0 -57
- package/vault/wiki/concepts/context-compression-techniques.md +0 -19
- package/vault/wiki/concepts/context-continuity.md +0 -22
- package/vault/wiki/concepts/context-drift-in-agents.md +0 -106
- package/vault/wiki/concepts/context-engineering.md +0 -62
- package/vault/wiki/concepts/context-folding.md +0 -67
- package/vault/wiki/concepts/context-mode.md +0 -38
- package/vault/wiki/concepts/cursor-harness-innovations.md +0 -107
- package/vault/wiki/concepts/deterministic-session-compaction.md +0 -79
- package/vault/wiki/concepts/drift-detection-unified.md +0 -296
- package/vault/wiki/concepts/execution-feedback-loop.md +0 -46
- package/vault/wiki/concepts/feedforward-feedback-harness.md +0 -60
- package/vault/wiki/concepts/five-root-cause-metrics-sentrux.md +0 -40
- package/vault/wiki/concepts/fork-safe-spec-storage.md +0 -89
- package/vault/wiki/concepts/fts5-sandbox.md +0 -19
- package/vault/wiki/concepts/fuzzy-edit-matching.md +0 -71
- package/vault/wiki/concepts/gemini-cli-architecture.md +0 -104
- package/vault/wiki/concepts/generator-evaluator-architecture.md +0 -64
- package/vault/wiki/concepts/guardian-agent-pattern.md +0 -67
- package/vault/wiki/concepts/harness-configuration-layers.md +0 -89
- package/vault/wiki/concepts/harness-control-frameworks.md +0 -155
- package/vault/wiki/concepts/harness-engineering-first-principles.md +0 -90
- package/vault/wiki/concepts/harness-h-formalism.md +0 -53
- package/vault/wiki/concepts/hybrid-code-search.md +0 -61
- package/vault/wiki/concepts/inline-post-edit-validation.md +0 -112
- package/vault/wiki/concepts/legendary-engineering-patterns-harness.md +0 -110
- package/vault/wiki/concepts/lifecycle-hooks.md +0 -94
- package/vault/wiki/concepts/mcp-tool-routing.md +0 -102
- package/vault/wiki/concepts/memory-system-of-record-vs-ephemeral-cache.md +0 -47
- package/vault/wiki/concepts/meta-agent-context-pruning.md +0 -151
- package/vault/wiki/concepts/model-adaptive-harness.md +0 -122
- package/vault/wiki/concepts/model-routing-agents.md +0 -101
- package/vault/wiki/concepts/monorepo-architecture.md +0 -45
- package/vault/wiki/concepts/multi-agent-specialization.md +0 -61
- package/vault/wiki/concepts/permission-subsystem.md +0 -16
- package/vault/wiki/concepts/pi-messenger-analysis.md +0 -243
- package/vault/wiki/concepts/pi-vscode-extension-landscape.md +0 -37
- package/vault/wiki/concepts/policy-engine-pattern.md +0 -78
- package/vault/wiki/concepts/progressive-disclosure-agents.md +0 -53
- package/vault/wiki/concepts/progressive-skill-disclosure.md +0 -17
- package/vault/wiki/concepts/provider-native-prompting.md +0 -203
- package/vault/wiki/concepts/quality-signal-sentrux.md +0 -37
- package/vault/wiki/concepts/repo-map-ranking.md +0 -42
- package/vault/wiki/concepts/result-monad-error-handling.md +0 -47
- package/vault/wiki/concepts/safety-defense-in-depth.md +0 -83
- package/vault/wiki/concepts/sandbox-os-enforcement.md +0 -18
- package/vault/wiki/concepts/selective-debate-routing.md +0 -70
- package/vault/wiki/concepts/self-evolving-harness.md +0 -60
- package/vault/wiki/concepts/sentrux-mcp-integration.md +0 -36
- package/vault/wiki/concepts/sentrux-rules-engine.md +0 -49
- package/vault/wiki/concepts/shell-pattern-compression.md +0 -24
- package/vault/wiki/concepts/skill-first-architecture.md +0 -166
- package/vault/wiki/concepts/structured-compaction.md +0 -78
- package/vault/wiki/concepts/subagent-orchestration.md +0 -17
- package/vault/wiki/concepts/subagent-worktree-isolation.md +0 -68
- package/vault/wiki/concepts/superpowers-methodology.md +0 -78
- package/vault/wiki/concepts/think-in-code.md +0 -73
- package/vault/wiki/concepts/ts-execution-layer.md +0 -100
- package/vault/wiki/concepts/typescript-strict-mode.md +0 -37
- package/vault/wiki/concepts/vcc-conversation-compaction-for-pi.md +0 -53
- package/vault/wiki/concepts/verification-drift-detection.md +0 -19
- package/vault/wiki/consensus/consensus-records.md +0 -58
- package/vault/wiki/decisions/2026-04-30-pi-lean-ctx-native.md +0 -122
- package/vault/wiki/decisions/2026-05-07-replace-lean-ctx-with-context-mode.md +0 -59
- package/vault/wiki/decisions/adr-008.md +0 -40
- package/vault/wiki/decisions/adr-009.md +0 -46
- package/vault/wiki/decisions/adr-010.md +0 -55
- package/vault/wiki/decisions/adr-011.md +0 -165
- package/vault/wiki/decisions/adr-012.md +0 -102
- package/vault/wiki/decisions/adr-013.md +0 -59
- package/vault/wiki/decisions/adr-014.md +0 -73
- package/vault/wiki/decisions/adr-015.md +0 -81
- package/vault/wiki/decisions/adr-016.md +0 -91
- package/vault/wiki/decisions/adr-017.md +0 -79
- package/vault/wiki/decisions/adr-018.md +0 -100
- package/vault/wiki/decisions/adr-019.md +0 -75
- package/vault/wiki/decisions/adr-020.md +0 -106
- package/vault/wiki/decisions/adr-021.md +0 -86
- package/vault/wiki/decisions/adr-022.md +0 -113
- package/vault/wiki/decisions/adr-023.md +0 -113
- package/vault/wiki/decisions/adr-024.md +0 -73
- package/vault/wiki/decisions/adr-025.md +0 -130
- package/vault/wiki/decisions/adr-026.md +0 -56
- package/vault/wiki/decisions/adr-027.md +0 -94
- package/vault/wiki/decisions/colocate-wiki.md +0 -34
- package/vault/wiki/entities/Anders Hejlsberg.md +0 -29
- package/vault/wiki/entities/Anthropic.md +0 -17
- package/vault/wiki/entities/Augment Code.md +0 -49
- package/vault/wiki/entities/Bjarne Stroustrup.md +0 -26
- package/vault/wiki/entities/Bolt.new (StackBlitz).md +0 -39
- package/vault/wiki/entities/Boris Cherny.md +0 -11
- package/vault/wiki/entities/Claude Code.md +0 -19
- package/vault/wiki/entities/Dennis Ritchie.md +0 -26
- package/vault/wiki/entities/Emergent Labs.md +0 -32
- package/vault/wiki/entities/Google Cloud.md +0 -16
- package/vault/wiki/entities/Guido van Rossum.md +0 -28
- package/vault/wiki/entities/Ken Thompson.md +0 -28
- package/vault/wiki/entities/Lee et al.md +0 -16
- package/vault/wiki/entities/Linus Torvalds.md +0 -28
- package/vault/wiki/entities/Lovable (company).md +0 -40
- package/vault/wiki/entities/Martin Fowler.md +0 -16
- package/vault/wiki/entities/Meng et al.md +0 -16
- package/vault/wiki/entities/OpenAI.md +0 -16
- package/vault/wiki/entities/Rocket.new.md +0 -38
- package/vault/wiki/entities/VILA-Lab.md +0 -15
- package/vault/wiki/entities/autodev-codebase.md +0 -18
- package/vault/wiki/entities/ck-tool.md +0 -59
- package/vault/wiki/entities/codesearch.md +0 -18
- package/vault/wiki/entities/disler-indydevdan.md +0 -33
- package/vault/wiki/entities/gsd-get-shit-done.md +0 -56
- package/vault/wiki/entities/javascript-runtimes.md +0 -48
- package/vault/wiki/entities/jesse-vincent.md +0 -38
- package/vault/wiki/entities/lean-ctx.md +0 -32
- package/vault/wiki/entities/opendev.md +0 -41
- package/vault/wiki/entities/ops-codegraph-tool.md +0 -18
- package/vault/wiki/entities/pi-coding-agent.md +0 -53
- package/vault/wiki/entities/sentrux.md +0 -54
- package/vault/wiki/entities/vgrep-tool.md +0 -57
- package/vault/wiki/entities/vitest.md +0 -41
- package/vault/wiki/flows/harness-wiki-pipeline.md +0 -204
- package/vault/wiki/hot.md +0 -932
- package/vault/wiki/index.md +0 -437
- package/vault/wiki/log.md +0 -422
- package/vault/wiki/meta/dashboard.md +0 -30
- package/vault/wiki/meta/lint-report-2026-04-30.md +0 -86
- package/vault/wiki/meta/lint-report-2026-05-02.md +0 -251
- package/vault/wiki/meta/overview.canvas +0 -43
- package/vault/wiki/modules/adversarial-verification.md +0 -57
- package/vault/wiki/modules/automated-observability.md +0 -54
- package/vault/wiki/modules/bench.md +0 -20
- package/vault/wiki/modules/extensions.md +0 -23
- package/vault/wiki/modules/grounding-checkpoints.md +0 -62
- package/vault/wiki/modules/harness-implementation-plan.md +0 -345
- package/vault/wiki/modules/harness-wiki-skill-mapping.md +0 -135
- package/vault/wiki/modules/harness.md +0 -86
- package/vault/wiki/modules/persistent-memory.md +0 -85
- package/vault/wiki/modules/schema-orchestration.md +0 -68
- package/vault/wiki/modules/skills.md +0 -27
- package/vault/wiki/modules/spec-hardening.md +0 -58
- package/vault/wiki/modules/structured-planning.md +0 -53
- package/vault/wiki/modules/think-in-code-enforcement.md +0 -153
- package/vault/wiki/modules/wiki-query-interface.md +0 -64
- package/vault/wiki/overview.md +0 -51
- package/vault/wiki/questions/Research-pi-vs-claude-code-agentic-orchestration-pipeline.md +0 -87
- package/vault/wiki/questions/Research-sentrux-dev.md +0 -123
- package/vault/wiki/questions/Research-superpowers-skill-for-agentic-coding-agents.md +0 -164
- package/vault/wiki/questions/Research: Augment Code Context Engine.md +0 -244
- package/vault/wiki/questions/Research: Automating Software Engineering - Lovable, Bolt, Emergent, Rocket.md +0 -112
- package/vault/wiki/questions/Research: Claude Code State-of-the-Art Harness Improvements.md +0 -209
- package/vault/wiki/questions/Research: Codex State-of-the-Art Harness Improvements.md +0 -99
- package/vault/wiki/questions/Research: Engineering Workflows of Legendary Programmers and AI Harness Mapping.md +0 -107
- package/vault/wiki/questions/Research: Fallow Codebase Intelligence Harness Integration.md +0 -72
- package/vault/wiki/questions/Research: Gemini CLI SOTA Harness Integration.md +0 -166
- package/vault/wiki/questions/Research: GitHub Issues as Harness Spec Storage.md +0 -188
- package/vault/wiki/questions/Research: Google Antigravity Harness Integration.md +0 -120
- package/vault/wiki/questions/Research: Meta-Agent Context Drift Detection.md +0 -236
- package/vault/wiki/questions/Research: Model-Adaptive Agent Harness Design.md +0 -95
- package/vault/wiki/questions/Research: Model-Specific Prompting Guides.md +0 -165
- package/vault/wiki/questions/Research: Prompt Renderer for Multi-Model Agent Harness.md +0 -216
- package/vault/wiki/questions/Research: Skill-First Harness Architecture.md +0 -91
- package/vault/wiki/questions/Research: TypeScript Best Practices and Codebase Structure.md +0 -88
- package/vault/wiki/questions/Research: TypeScript Execution Layer for Agent Tool Calling.md +0 -81
- package/vault/wiki/questions/Research: claude-mem over Obsidian for Harness Layer.md +0 -71
- package/vault/wiki/questions/Research: claude-mem over obsidian wiki as the knowledge base for our agentic harness pipeline. think from first principles. does this replace or complement our current setup? no hard feelings about previous decisions. gimme accurate points.md +0 -80
- package/vault/wiki/questions/Research: context-mode vs lean-ctx.md +0 -72
- package/vault/wiki/questions/Research: cursor.sh Harness Innovations.md +0 -92
- package/vault/wiki/questions/Research: executor.sh Harness Integration.md +0 -170
- package/vault/wiki/questions/Research: how GSD fits into our coding harness setup.md +0 -97
- package/vault/wiki/questions/Research: how claude-mem fits into our workflow. and whether it should replace obsidian in the codebase. no hard feelings about previous actions, rethink from first principles always.md +0 -80
- package/vault/wiki/questions/Research: pi-vcc.md +0 -113
- package/vault/wiki/questions/Research: semantic code search tools.md +0 -69
- package/vault/wiki/questions/Research: vcc extension for pi coding agent.md +0 -73
- package/vault/wiki/questions/how-to-enable-semantic-code-search-now.md +0 -111
- package/vault/wiki/questions/mvp-implementation-blueprint.md +0 -552
- package/vault/wiki/questions/research-agent-first-codebase-exploration.md +0 -199
- package/vault/wiki/questions/research-agentic-coding-harness-latest-papers.md +0 -142
- package/vault/wiki/questions/research-gitingest-gitreverse-integration.md +0 -100
- package/vault/wiki/questions/research-wozcode-token-reduction.md +0 -67
- package/vault/wiki/questions/resolved-context-pruning-inplace-vs-restart.md +0 -95
- package/vault/wiki/questions/resolved-context-window-economics.md +0 -167
- package/vault/wiki/questions/resolved-imad-debate-gating-transfer.md +0 -126
- package/vault/wiki/questions/resolved-mcp-tool-preference.md +0 -112
- package/vault/wiki/questions/resolved-small-model-meta-agents.md +0 -107
- package/vault/wiki/questions/resolved-treesitter-dynamic-languages.md +0 -95
- package/vault/wiki/sources/Auggie Context MCP Server.md +0 -63
- package/vault/wiki/sources/Augment Code Codacy AI Giants.md +0 -61
- package/vault/wiki/sources/Augment Code MCP SiliconAngle.md +0 -49
- package/vault/wiki/sources/Augment Code WorkOS ERC 2025.md +0 -55
- package/vault/wiki/sources/Augment Context Engine Official.md +0 -71
- package/vault/wiki/sources/Augment SWE-bench Agent GitHub.md +0 -74
- package/vault/wiki/sources/Augment SWE-bench Pro Blog.md +0 -58
- package/vault/wiki/sources/Source: AgentBus Jinja2 Prompt Pipelines.md +0 -75
- package/vault/wiki/sources/Source: Arxiv /342/200/224 Don't Break the Cache.md" +0 -85
- package/vault/wiki/sources/Source: Augment - Harness Engineering for AI Coding Agents.md +0 -58
- package/vault/wiki/sources/Source: Blake Crosley Agent Architecture Guide.md +0 -100
- package/vault/wiki/sources/Source: Bolt.new Architecture & Case Study.md +0 -75
- package/vault/wiki/sources/Source: Build-Time Prompt Compilation Architecture.md +0 -107
- package/vault/wiki/sources/Source: Claude API Agent Skills Overview.md +0 -70
- package/vault/wiki/sources/Source: Gemini CLI Changelogs.md +0 -88
- package/vault/wiki/sources/Source: Google Blog - Gemini CLI Announcement.md +0 -57
- package/vault/wiki/sources/Source: Google Gemini CLI Architecture Docs.md +0 -53
- package/vault/wiki/sources/Source: LangChain - Anatomy of Agent Harness.md +0 -65
- package/vault/wiki/sources/Source: Lovable Architecture & Clone Analysis.md +0 -83
- package/vault/wiki/sources/Source: Martin Fowler - Harness Engineering.md +0 -70
- package/vault/wiki/sources/Source: OpenAI Harness Engineering Five Principles.md +0 -58
- package/vault/wiki/sources/Source: OpenAI Harness Engineering /342/200/224 0 Lines of Human Code.md" +0 -101
- package/vault/wiki/sources/Source: OpenDev /342/200/224 Building AI Coding Agents for the Terminal.md" +0 -100
- package/vault/wiki/sources/Source: Render AI Coding Agents Benchmark 2025.md +0 -53
- package/vault/wiki/sources/Source: Rocket.new /342/200/224 Vibe Solutioning Platform.md" +0 -70
- package/vault/wiki/sources/Source: SwirlAI Agent Skills Progressive Disclosure.md +0 -71
- package/vault/wiki/sources/Source: TianPan Prompt Caching Architecture.md +0 -89
- package/vault/wiki/sources/Source: Vercel Labs agent-browser.md +0 -155
- package/vault/wiki/sources/Source: browser-harness CDP Harness.md +0 -126
- package/vault/wiki/sources/agent-drift-academic-paper.md +0 -79
- package/vault/wiki/sources/aider-repomap-tree-sitter.md +0 -42
- package/vault/wiki/sources/anthropic-compaction-api.md +0 -58
- package/vault/wiki/sources/anthropic-effective-harnesses.md +0 -42
- package/vault/wiki/sources/anthropic-prompt-best-practices.md +0 -100
- package/vault/wiki/sources/anthropic2026-harness-design.md +0 -63
- package/vault/wiki/sources/barrel-files-tkdodo.md +0 -38
- package/vault/wiki/sources/birth-of-unix-kernighan-interview.md +0 -57
- package/vault/wiki/sources/bockeler2026-harness-engineering.md +0 -69
- package/vault/wiki/sources/cast-code-chunking-paper.md +0 -50
- package/vault/wiki/sources/ck-semantic-search.md +0 -78
- package/vault/wiki/sources/claude-code-architecture-karaxai-2026.md +0 -71
- package/vault/wiki/sources/claude-code-architecture-qubytes-2026.md +0 -50
- package/vault/wiki/sources/claude-code-architecture-vila-lab-2026.md +0 -64
- package/vault/wiki/sources/claude-code-security-architecture-penligent-2026.md +0 -70
- package/vault/wiki/sources/claude-context-editing-docs.md +0 -13
- package/vault/wiki/sources/cloudflare-codemode.md +0 -63
- package/vault/wiki/sources/code-chunk-library-supermemory.md +0 -63
- package/vault/wiki/sources/codeact-apple-2024.md +0 -62
- package/vault/wiki/sources/codex-dsc-rfc-8573.md +0 -41
- package/vault/wiki/sources/codex-open-source-agent-2026.md +0 -110
- package/vault/wiki/sources/coir-code-retrieval-benchmark.md +0 -51
- package/vault/wiki/sources/colinmcnamara-context-optimization-codemode.md +0 -48
- package/vault/wiki/sources/context-folding-paper.md +0 -61
- package/vault/wiki/sources/context-mode-website.md +0 -63
- package/vault/wiki/sources/cursor-agent-best-practices-2026.md +0 -62
- package/vault/wiki/sources/cursor-fork-29b-2025.md +0 -50
- package/vault/wiki/sources/cursor-harness-april-2026.md +0 -76
- package/vault/wiki/sources/cursor-instant-apply-2024.md +0 -45
- package/vault/wiki/sources/cursor-shadow-workspace-2024.md +0 -52
- package/vault/wiki/sources/cursor-shipped-coding-agent-2026.md +0 -53
- package/vault/wiki/sources/cursor-vs-antigravity-2026.md +0 -51
- package/vault/wiki/sources/disler-pi-vs-claude-code.md +0 -69
- package/vault/wiki/sources/distill-deterministic-context-compression.md +0 -53
- package/vault/wiki/sources/embedding-models-benchmark-supermemory-2025.md +0 -48
- package/vault/wiki/sources/executor-rhyssullivan.md +0 -122
- package/vault/wiki/sources/fallow-rs-codebase-intelligence.md +0 -125
- package/vault/wiki/sources/fan2025-imad.md +0 -60
- package/vault/wiki/sources/forgecode-gpt5-agent-improvements.md +0 -63
- package/vault/wiki/sources/gemini-3-prompting-guide.md +0 -78
- package/vault/wiki/sources/gh-cli-sub-issue-rfc.md +0 -50
- package/vault/wiki/sources/gh-sub-issue-extension.md +0 -72
- package/vault/wiki/sources/github-fork-issues-discussion.md +0 -44
- package/vault/wiki/sources/github-issue-dependencies-docs.md +0 -49
- package/vault/wiki/sources/github-sub-issues-docs.md +0 -51
- package/vault/wiki/sources/gitingest.md +0 -91
- package/vault/wiki/sources/gitreverse.md +0 -63
- package/vault/wiki/sources/google-antigravity-official-blog.md +0 -47
- package/vault/wiki/sources/google-antigravity-wikipedia.md +0 -53
- package/vault/wiki/sources/gsd-codecentric-deep-dive.md +0 -57
- package/vault/wiki/sources/gsd-github-repo.md +0 -51
- package/vault/wiki/sources/gsd-hn-discussion.md +0 -59
- package/vault/wiki/sources/guido-python-design-philosophy.md +0 -56
- package/vault/wiki/sources/hejlsberg-7-learnings.md +0 -48
- package/vault/wiki/sources/ironclaw-drift-monitor.md +0 -80
- package/vault/wiki/sources/langsight-loop-detection.md +0 -80
- package/vault/wiki/sources/leanctx-website.md +0 -69
- package/vault/wiki/sources/lee2026-meta-harness.md +0 -59
- package/vault/wiki/sources/linux-kernel-coding-workflow.md +0 -50
- package/vault/wiki/sources/lou2026-autoharness.md +0 -53
- package/vault/wiki/sources/martin-fowler-harness-engineering.md +0 -73
- package/vault/wiki/sources/mcp-architecture-docs.md +0 -13
- package/vault/wiki/sources/meng2026-agent-harness-survey.md +0 -79
- package/vault/wiki/sources/mindstudio-four-agent-types.md +0 -68
- package/vault/wiki/sources/ms-chat-history-management.md +0 -13
- package/vault/wiki/sources/openai-prompt-guidance.md +0 -104
- package/vault/wiki/sources/openclaw-session-pruning.md +0 -13
- package/vault/wiki/sources/opencode-dcp.md +0 -13
- package/vault/wiki/sources/opendev-arxiv-2603.05344v1.md +0 -79
- package/vault/wiki/sources/openhands-platform.md +0 -39
- package/vault/wiki/sources/oss-guide-codebase-exploration.md +0 -53
- package/vault/wiki/sources/pi-compaction-extensions-ecosystem.md +0 -102
- package/vault/wiki/sources/pi-context-prune-github-repo.md +0 -38
- package/vault/wiki/sources/pi-mono-compaction-docs.md +0 -38
- package/vault/wiki/sources/pi-omni-compact-github-repo.md +0 -50
- package/vault/wiki/sources/pi-rtk-optimizer-github-repo.md +0 -45
- package/vault/wiki/sources/pi-vcc-github-repo.md +0 -69
- package/vault/wiki/sources/pi-vscode-marketplace.md +0 -41
- package/vault/wiki/sources/pi-vscode-model-provider-marketplace.md +0 -39
- package/vault/wiki/sources/py-tree-sitter.md +0 -13
- package/vault/wiki/sources/sentrux-dev-landing.md +0 -40
- package/vault/wiki/sources/sentrux-docs-pro-architecture.md +0 -75
- package/vault/wiki/sources/sentrux-docs-quality-signal.md +0 -46
- package/vault/wiki/sources/sentrux-docs-root-cause-metrics.md +0 -57
- package/vault/wiki/sources/sentrux-docs-rules-engine.md +0 -58
- package/vault/wiki/sources/sentrux-github-repo.md +0 -56
- package/vault/wiki/sources/superpowers-github-repo.md +0 -56
- package/vault/wiki/sources/superpowers-release-blog.md +0 -54
- package/vault/wiki/sources/superpowers-termdock-analysis.md +0 -45
- package/vault/wiki/sources/swe-agent-aci.md +0 -42
- package/vault/wiki/sources/swe-bench.md +0 -45
- package/vault/wiki/sources/swe-pruner-context-pruning.md +0 -13
- package/vault/wiki/sources/think-in-code-blog.md +0 -48
- package/vault/wiki/sources/tree-sitter-docs.md +0 -13
- package/vault/wiki/sources/ts-best-practices-2025-devto.md +0 -42
- package/vault/wiki/sources/ts-folder-structure-mingyang.md +0 -58
- package/vault/wiki/sources/ts-monorepo-koerselman.md +0 -44
- package/vault/wiki/sources/ts-result-error-handling-kkalamarski.md +0 -52
- package/vault/wiki/sources/ts-runtimes-comparison-betterstack.md +0 -42
- package/vault/wiki/sources/ts-strict-mode-rishikc.md +0 -43
- package/vault/wiki/sources/unix-philosophy.md +0 -48
- package/vault/wiki/sources/vectara-chunking-vs-embedding-naacl2025.md +0 -39
- package/vault/wiki/sources/vectara-guardian-agents.md +0 -79
- package/vault/wiki/sources/vgrep-semantic-search.md +0 -76
- package/vault/wiki/sources/vitest-official.md +0 -41
- package/vault/wiki/sources/vscode-pi-community-extension.md +0 -40
- package/vault/wiki/sources/wozcode.md +0 -79
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { describe, test, expect } from "bun:test";
|
|
2
|
+
import { buildOwnCut } from "../src/hooks/before-compact";
|
|
3
|
+
|
|
4
|
+
const msg = (id: string, role: "user" | "assistant" | "toolResult", content = "x") => ({
|
|
5
|
+
id,
|
|
6
|
+
type: "message",
|
|
7
|
+
message: { role, content },
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
const comp = (id: string, firstKeptEntryId?: string) => ({
|
|
11
|
+
id,
|
|
12
|
+
type: "compaction",
|
|
13
|
+
firstKeptEntryId,
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
describe("buildOwnCut", () => {
|
|
17
|
+
test("no prior compaction: cuts at last user message", () => {
|
|
18
|
+
const r = buildOwnCut([
|
|
19
|
+
msg("m1", "user", "a"),
|
|
20
|
+
msg("m2", "assistant", "b"),
|
|
21
|
+
msg("m3", "user", "c"),
|
|
22
|
+
msg("m4", "assistant", "d"),
|
|
23
|
+
]);
|
|
24
|
+
expect(r.ok).toBe(true);
|
|
25
|
+
if (!r.ok) return;
|
|
26
|
+
expect(r.firstKeptEntryId).toBe("m3");
|
|
27
|
+
expect(r.messages).toHaveLength(2);
|
|
28
|
+
expect(r.compactAll).toBe(false);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
test("cancels with too_few_live_messages when liveMessages <= 2", () => {
|
|
32
|
+
const r = buildOwnCut([
|
|
33
|
+
comp("c1", "m1"),
|
|
34
|
+
msg("m1", "user", "x"),
|
|
35
|
+
msg("m2", "assistant", "y"),
|
|
36
|
+
]);
|
|
37
|
+
expect(r.ok).toBe(false);
|
|
38
|
+
if (r.ok) return;
|
|
39
|
+
expect(r.reason).toBe("too_few_live_messages");
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
test("orphan firstKeptEntryId triggers recovery (collect after compaction)", () => {
|
|
43
|
+
// Prev compaction set firstKeptEntryId to a non-existent id (e.g. "" sentinel
|
|
44
|
+
// from a previous compact-all). Recovery should collect msgs after compaction.
|
|
45
|
+
const r = buildOwnCut([
|
|
46
|
+
msg("old1", "user", "old"),
|
|
47
|
+
msg("old2", "assistant", "old"),
|
|
48
|
+
comp("c1", "ORPHAN_ID"),
|
|
49
|
+
msg("m1", "user", "a"),
|
|
50
|
+
msg("m2", "assistant", "b"),
|
|
51
|
+
msg("m3", "user", "c"),
|
|
52
|
+
msg("m4", "assistant", "d"),
|
|
53
|
+
]);
|
|
54
|
+
expect(r.ok).toBe(true);
|
|
55
|
+
if (!r.ok) return;
|
|
56
|
+
expect(r.firstKeptEntryId).toBe("m3");
|
|
57
|
+
expect(r.messages).toHaveLength(2);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
test("resumes from firstKeptEntryId after prior compaction", () => {
|
|
61
|
+
const r = buildOwnCut([
|
|
62
|
+
msg("old1", "user", "old"),
|
|
63
|
+
msg("old2", "assistant", "old"),
|
|
64
|
+
comp("c1", "m1"),
|
|
65
|
+
msg("m1", "user", "a"),
|
|
66
|
+
msg("m2", "assistant", "b"),
|
|
67
|
+
msg("m3", "user", "c"),
|
|
68
|
+
msg("m4", "assistant", "d"),
|
|
69
|
+
]);
|
|
70
|
+
expect(r.ok).toBe(true);
|
|
71
|
+
if (!r.ok) return;
|
|
72
|
+
expect(r.firstKeptEntryId).toBe("m3");
|
|
73
|
+
expect(r.messages).toHaveLength(2);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
test("single user prompt + autonomous tail: compact all", () => {
|
|
77
|
+
// The Discord scenario: user types 1 prompt, agent runs autonomously
|
|
78
|
+
// (assistant + toolResult interleaved). No user > idx 0.
|
|
79
|
+
const r = buildOwnCut([
|
|
80
|
+
msg("m1", "user", "go"),
|
|
81
|
+
msg("m2", "assistant", "calling tool"),
|
|
82
|
+
msg("m3", "toolResult", "result"),
|
|
83
|
+
msg("m4", "assistant", "more"),
|
|
84
|
+
msg("m5", "toolResult", "result2"),
|
|
85
|
+
msg("m6", "assistant", "done"),
|
|
86
|
+
]);
|
|
87
|
+
expect(r.ok).toBe(true);
|
|
88
|
+
if (!r.ok) return;
|
|
89
|
+
expect(r.compactAll).toBe(true);
|
|
90
|
+
expect(r.firstKeptEntryId).toBe("");
|
|
91
|
+
expect(r.messages).toHaveLength(6);
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
test("no_user_message when no user role at all", () => {
|
|
95
|
+
const r = buildOwnCut([
|
|
96
|
+
msg("m1", "assistant", "a"),
|
|
97
|
+
msg("m2", "assistant", "b"),
|
|
98
|
+
msg("m3", "assistant", "c"),
|
|
99
|
+
]);
|
|
100
|
+
expect(r.ok).toBe(false);
|
|
101
|
+
if (r.ok) return;
|
|
102
|
+
expect(r.reason).toBe("no_user_message");
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
test("compact-all then more chat: orphan recovery + normal cut", () => {
|
|
106
|
+
// After a compact-all (firstKeptEntryId=""), user chats more turns,
|
|
107
|
+
// next compaction should orphan-recover and find multiple users.
|
|
108
|
+
const r = buildOwnCut([
|
|
109
|
+
msg("o1", "user", "old"),
|
|
110
|
+
msg("o2", "assistant", "old"),
|
|
111
|
+
comp("c1", ""), // sentinel from prior compact-all
|
|
112
|
+
msg("u1", "user", "new1"),
|
|
113
|
+
msg("a1", "assistant", "reply1"),
|
|
114
|
+
msg("u2", "user", "new2"),
|
|
115
|
+
msg("a2", "assistant", "reply2"),
|
|
116
|
+
msg("u3", "user", "new3"),
|
|
117
|
+
msg("a3", "assistant", "reply3"),
|
|
118
|
+
]);
|
|
119
|
+
expect(r.ok).toBe(true);
|
|
120
|
+
if (!r.ok) return;
|
|
121
|
+
expect(r.compactAll).toBe(false);
|
|
122
|
+
expect(r.firstKeptEntryId).toBe("u3");
|
|
123
|
+
expect(r.messages).toHaveLength(4); // u1, a1, u2, a2
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
test("compact-all then single user msg + autonomous: compact all again", () => {
|
|
127
|
+
const r = buildOwnCut([
|
|
128
|
+
msg("o1", "user", "old"),
|
|
129
|
+
comp("c1", ""),
|
|
130
|
+
msg("u1", "user", "okay"),
|
|
131
|
+
msg("a1", "assistant", "x"),
|
|
132
|
+
msg("t1", "toolResult", "y"),
|
|
133
|
+
msg("a2", "assistant", "z"),
|
|
134
|
+
]);
|
|
135
|
+
expect(r.ok).toBe(true);
|
|
136
|
+
if (!r.ok) return;
|
|
137
|
+
expect(r.compactAll).toBe(true);
|
|
138
|
+
expect(r.firstKeptEntryId).toBe("");
|
|
139
|
+
});
|
|
140
|
+
});
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
import { describe, it, expect } from "bun:test";
|
|
2
|
+
import { compileBrief } from "../src/core/brief";
|
|
3
|
+
import type { NormalizedBlock } from "../src/types";
|
|
4
|
+
|
|
5
|
+
describe("compileBrief", () => {
|
|
6
|
+
it("returns empty string for no blocks", () => {
|
|
7
|
+
expect(compileBrief([])).toBe("");
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
it("renders user and assistant text", () => {
|
|
11
|
+
const blocks: NormalizedBlock[] = [
|
|
12
|
+
{ kind: "user", text: "fix auth bug" },
|
|
13
|
+
{ kind: "assistant", text: "Let me look at the auth module." },
|
|
14
|
+
];
|
|
15
|
+
const r = compileBrief(blocks);
|
|
16
|
+
expect(r).toContain("[user]");
|
|
17
|
+
expect(r).toContain("fix auth bug");
|
|
18
|
+
expect(r).toContain("[assistant]");
|
|
19
|
+
expect(r).toContain("Let me look at the auth module.");
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it("strips filler prefixes but preserves meaningful lead-ins", () => {
|
|
23
|
+
const blocks: NormalizedBlock[] = [
|
|
24
|
+
{ kind: "assistant", text: "Okay, I found the root cause." },
|
|
25
|
+
{ kind: "assistant", text: "Actually, the issue is in middleware." },
|
|
26
|
+
{ kind: "assistant", text: "Let me check the logs." },
|
|
27
|
+
];
|
|
28
|
+
const r = compileBrief(blocks);
|
|
29
|
+
expect(r).toContain("I found the root cause.");
|
|
30
|
+
expect(r).toContain("the issue is in middleware.");
|
|
31
|
+
expect(r).toContain("Let me check the logs.");
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it("collapses tool calls to one-liners under [assistant]", () => {
|
|
35
|
+
const blocks: NormalizedBlock[] = [
|
|
36
|
+
{ kind: "assistant", text: "Let me check." },
|
|
37
|
+
{ kind: "tool_call", name: "Read", args: { file_path: "auth.ts" } },
|
|
38
|
+
{ kind: "tool_call", name: "Edit", args: { file_path: "auth.ts" } },
|
|
39
|
+
];
|
|
40
|
+
const r = compileBrief(blocks);
|
|
41
|
+
expect(r).toContain('* Read "auth.ts"');
|
|
42
|
+
expect(r).toContain('* Edit "auth.ts"');
|
|
43
|
+
// Should merge into single [assistant] section
|
|
44
|
+
const matches = r.match(/\[assistant\]/g);
|
|
45
|
+
expect(matches?.length).toBe(1);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it("hides non-error tool results", () => {
|
|
49
|
+
const blocks: NormalizedBlock[] = [
|
|
50
|
+
{ kind: "tool_result", name: "Read", text: "const x = 1;\nconst y = 2;\n// lots of code", isError: false },
|
|
51
|
+
];
|
|
52
|
+
const r = compileBrief(blocks);
|
|
53
|
+
expect(r).toBe("");
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it("shows tool errors with first line", () => {
|
|
57
|
+
const blocks: NormalizedBlock[] = [
|
|
58
|
+
{ kind: "tool_result", name: "bash", text: "FAIL auth.test.ts\nexpected 200 got 401", isError: true },
|
|
59
|
+
];
|
|
60
|
+
const r = compileBrief(blocks);
|
|
61
|
+
expect(r).toContain("[tool_error] bash");
|
|
62
|
+
expect(r).toContain("FAIL auth.test.ts");
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
it("hides thinking blocks", () => {
|
|
66
|
+
const blocks: NormalizedBlock[] = [
|
|
67
|
+
{ kind: "thinking", text: "Let me think about this...", redacted: false },
|
|
68
|
+
{ kind: "assistant", text: "Here's what I found." },
|
|
69
|
+
];
|
|
70
|
+
const r = compileBrief(blocks);
|
|
71
|
+
expect(r).not.toContain("think");
|
|
72
|
+
expect(r).toContain("Here's what I found.");
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
it("merges adjacent assistant sections", () => {
|
|
76
|
+
const blocks: NormalizedBlock[] = [
|
|
77
|
+
{ kind: "assistant", text: "First part." },
|
|
78
|
+
{ kind: "tool_call", name: "Read", args: { file_path: "a.ts" } },
|
|
79
|
+
// No user/tool_result between these — should merge
|
|
80
|
+
{ kind: "assistant", text: "Second part." },
|
|
81
|
+
{ kind: "tool_call", name: "Read", args: { file_path: "b.ts" } },
|
|
82
|
+
];
|
|
83
|
+
const r = compileBrief(blocks);
|
|
84
|
+
const matches = r.match(/\[assistant\]/g);
|
|
85
|
+
expect(matches?.length).toBe(1);
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
it("does NOT merge assistant after user", () => {
|
|
89
|
+
const blocks: NormalizedBlock[] = [
|
|
90
|
+
{ kind: "assistant", text: "First." },
|
|
91
|
+
{ kind: "user", text: "Next task." },
|
|
92
|
+
{ kind: "assistant", text: "Second." },
|
|
93
|
+
];
|
|
94
|
+
const r = compileBrief(blocks);
|
|
95
|
+
const matches = r.match(/\[assistant\]/g);
|
|
96
|
+
expect(matches?.length).toBe(2);
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it("truncates long user text", () => {
|
|
100
|
+
const longText = Array.from({ length: 300 }, (_, i) => `word${i}`).join(" ");
|
|
101
|
+
const blocks: NormalizedBlock[] = [
|
|
102
|
+
{ kind: "user", text: longText },
|
|
103
|
+
];
|
|
104
|
+
const r = compileBrief(blocks);
|
|
105
|
+
expect(r).toContain("(truncated)");
|
|
106
|
+
expect(r).not.toContain("word299");
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
it("truncates long assistant text", () => {
|
|
110
|
+
const longText = Array.from({ length: 300 }, (_, i) => `word${i}`).join(" ");
|
|
111
|
+
const blocks: NormalizedBlock[] = [
|
|
112
|
+
{ kind: "assistant", text: longText },
|
|
113
|
+
];
|
|
114
|
+
const r = compileBrief(blocks);
|
|
115
|
+
expect(r).toContain("(truncated)");
|
|
116
|
+
expect(r).not.toContain("word299");
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
it("renders a realistic conversation flow", () => {
|
|
120
|
+
const blocks: NormalizedBlock[] = [
|
|
121
|
+
{ kind: "user", text: "fix the login bug" },
|
|
122
|
+
{ kind: "thinking", text: "I need to check...", redacted: false },
|
|
123
|
+
{ kind: "assistant", text: "Let me investigate." },
|
|
124
|
+
{ kind: "tool_call", name: "Read", args: { file_path: "login.ts" } },
|
|
125
|
+
{ kind: "tool_result", name: "Read", text: "export function login() { ... }", isError: false },
|
|
126
|
+
{ kind: "tool_call", name: "bash", args: { command: "npm test" } },
|
|
127
|
+
{ kind: "tool_result", name: "bash", text: "FAIL: login test\nExpected true, got false", isError: true },
|
|
128
|
+
{ kind: "assistant", text: "The test is failing because..." },
|
|
129
|
+
{ kind: "tool_call", name: "Edit", args: { file_path: "login.ts" } },
|
|
130
|
+
{ kind: "tool_result", name: "Edit", text: "File edited successfully", isError: false },
|
|
131
|
+
{ kind: "user", text: "test lại đi" },
|
|
132
|
+
{ kind: "assistant", text: "Running tests again." },
|
|
133
|
+
{ kind: "tool_call", name: "bash", args: { command: "npm test" } },
|
|
134
|
+
{ kind: "tool_result", name: "bash", text: "All tests passed", isError: false },
|
|
135
|
+
];
|
|
136
|
+
const r = compileBrief(blocks);
|
|
137
|
+
|
|
138
|
+
// Check structure
|
|
139
|
+
expect(r).toContain("[user]\nfix the login bug");
|
|
140
|
+
expect(r).toContain('[assistant]\nLet me investigate.\n* Read "login.ts"');
|
|
141
|
+
expect(r).toContain("[tool_error] bash\nFAIL: login test");
|
|
142
|
+
expect(r).toContain('[assistant]\nThe test is failing because...\n* Edit "login.ts"');
|
|
143
|
+
expect(r).toContain("[user]\ntest lại đi");
|
|
144
|
+
expect(r).toContain('[assistant]\nRunning tests again.\n* bash "npm test"');
|
|
145
|
+
|
|
146
|
+
// Hidden content
|
|
147
|
+
expect(r).not.toContain("think");
|
|
148
|
+
expect(r).not.toContain("export function login");
|
|
149
|
+
expect(r).not.toContain("File edited successfully");
|
|
150
|
+
expect(r).not.toContain("All tests passed");
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
// ── noise filtering tests (aligned with VCC) ──
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
it("suppresses blank lines between consecutive tool-only sections", () => {
|
|
164
|
+
const blocks: NormalizedBlock[] = [
|
|
165
|
+
{ kind: "assistant", text: "Checking files." },
|
|
166
|
+
{ kind: "tool_call", name: "Read", args: { file_path: "a.ts" } },
|
|
167
|
+
{ kind: "tool_result", name: "Read", text: "...", isError: false },
|
|
168
|
+
// tool_result hidden → next tool_call starts new assistant section
|
|
169
|
+
// but since both are tool-only, no blank line between
|
|
170
|
+
{ kind: "tool_call", name: "Read", args: { file_path: "b.ts" } },
|
|
171
|
+
{ kind: "tool_result", name: "Read", text: "...", isError: false },
|
|
172
|
+
];
|
|
173
|
+
const r = compileBrief(blocks);
|
|
174
|
+
// The first assistant section has text + tool, so it's NOT tool-only
|
|
175
|
+
// The second would be tool-only but merges into the first (adjacent assistant)
|
|
176
|
+
// So all under one [assistant]
|
|
177
|
+
expect(r.match(/\[assistant\]/g)?.length).toBe(1);
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
it("caps tool calls per [assistant] turn at 8 (keep tail)", () => {
|
|
181
|
+
const blocks: NormalizedBlock[] = [
|
|
182
|
+
{ kind: "assistant", text: "Working." },
|
|
183
|
+
];
|
|
184
|
+
for (let i = 1; i <= 12; i++) {
|
|
185
|
+
blocks.push({ kind: "tool_call", name: "bash", args: { command: `echo ${i}` } });
|
|
186
|
+
}
|
|
187
|
+
const r = compileBrief(blocks);
|
|
188
|
+
expect(r).toContain("(4 earlier tool-call entries omitted)");
|
|
189
|
+
// Last 8 (5..12) kept; first 4 dropped
|
|
190
|
+
expect(r).not.toContain("echo 1\"");
|
|
191
|
+
expect(r).not.toContain("echo 4\"");
|
|
192
|
+
expect(r).toContain("echo 5");
|
|
193
|
+
expect(r).toContain("echo 12");
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
it("does not cap when tool calls per turn <= 8", () => {
|
|
197
|
+
const blocks: NormalizedBlock[] = [{ kind: "assistant", text: "ok" }];
|
|
198
|
+
for (let i = 1; i <= 8; i++) {
|
|
199
|
+
blocks.push({ kind: "tool_call", name: "bash", args: { command: `c${i}` } });
|
|
200
|
+
}
|
|
201
|
+
const r = compileBrief(blocks);
|
|
202
|
+
expect(r).not.toContain("entries omitted");
|
|
203
|
+
expect(r).toContain("c1");
|
|
204
|
+
expect(r).toContain("c8");
|
|
205
|
+
});
|
|
206
|
+
});
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { describe, it, expect } from "bun:test";
|
|
2
|
+
import { buildSections } from "../src/core/build-sections";
|
|
3
|
+
import type { NormalizedBlock } from "../src/types";
|
|
4
|
+
|
|
5
|
+
describe("buildSections", () => {
|
|
6
|
+
it("returns all-empty for no blocks", () => {
|
|
7
|
+
const r = buildSections({ blocks: [] });
|
|
8
|
+
expect(r.sessionGoal).toEqual([]);
|
|
9
|
+
expect(r.outstandingContext).toEqual([]);
|
|
10
|
+
expect(r.briefTranscript).toBe("");
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
it("populates sections from realistic blocks", () => {
|
|
14
|
+
const blocks: NormalizedBlock[] = [
|
|
15
|
+
{ kind: "user", text: "Fix the auth bug" },
|
|
16
|
+
{ kind: "tool_call", name: "Read", args: { file_path: "auth.ts" } },
|
|
17
|
+
{ kind: "tool_result", name: "Read", text: "const x = 1;", isError: false },
|
|
18
|
+
{ kind: "tool_call", name: "Edit", args: { file_path: "auth.ts" } },
|
|
19
|
+
{ kind: "tool_result", name: "Edit", text: "ok", isError: false },
|
|
20
|
+
{ kind: "assistant", text: "- run tests next" },
|
|
21
|
+
];
|
|
22
|
+
const r = buildSections({ blocks });
|
|
23
|
+
expect(r.sessionGoal).toContain("Fix the auth bug");
|
|
24
|
+
expect(r.briefTranscript).toContain('[user]');
|
|
25
|
+
expect(r.briefTranscript).toContain('* Read "auth.ts"');
|
|
26
|
+
expect(r.briefTranscript).toContain('* Edit "auth.ts"');
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it("captures outstanding context from errors", () => {
|
|
30
|
+
const blocks: NormalizedBlock[] = [
|
|
31
|
+
{ kind: "tool_result", name: "bash", text: "FAIL: test broken\ndetails here", isError: true },
|
|
32
|
+
];
|
|
33
|
+
const r = buildSections({ blocks });
|
|
34
|
+
expect(r.outstandingContext.length).toBeGreaterThan(0);
|
|
35
|
+
expect(r.outstandingContext[0]).toContain("FAIL");
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it("brief transcript hides tool results but shows errors", () => {
|
|
39
|
+
const blocks: NormalizedBlock[] = [
|
|
40
|
+
{ kind: "tool_result", name: "Read", text: "lots of code here ...", isError: false },
|
|
41
|
+
{ kind: "tool_result", name: "bash", text: "Command not found", isError: true },
|
|
42
|
+
];
|
|
43
|
+
const r = buildSections({ blocks });
|
|
44
|
+
expect(r.briefTranscript).not.toContain("lots of code");
|
|
45
|
+
expect(r.briefTranscript).toContain("[tool_error] bash");
|
|
46
|
+
expect(r.briefTranscript).toContain("Command not found");
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it("brief transcript merges adjacent assistant sections", () => {
|
|
50
|
+
const blocks: NormalizedBlock[] = [
|
|
51
|
+
{ kind: "assistant", text: "Part one." },
|
|
52
|
+
{ kind: "tool_call", name: "Read", args: { file_path: "a.ts" } },
|
|
53
|
+
{ kind: "assistant", text: "Part two." },
|
|
54
|
+
];
|
|
55
|
+
const r = buildSections({ blocks });
|
|
56
|
+
const matches = r.briefTranscript.match(/\[assistant\]/g);
|
|
57
|
+
expect(matches?.length).toBe(1);
|
|
58
|
+
});
|
|
59
|
+
});
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { describe, it, expect } from "bun:test";
|
|
2
|
+
import { compile } from "../src/core/summarize";
|
|
3
|
+
import {
|
|
4
|
+
userMsg,
|
|
5
|
+
assistantText,
|
|
6
|
+
assistantWithToolCall,
|
|
7
|
+
toolResult,
|
|
8
|
+
} from "./fixtures";
|
|
9
|
+
|
|
10
|
+
describe("compile", () => {
|
|
11
|
+
it("returns empty string for no messages", () => {
|
|
12
|
+
expect(compile({ messages: [] })).toBe("");
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it("produces hybrid output with header + brief transcript", () => {
|
|
16
|
+
const r = compile({
|
|
17
|
+
messages: [
|
|
18
|
+
userMsg("Fix login bug"),
|
|
19
|
+
assistantWithToolCall("Read", { path: "auth.ts" }),
|
|
20
|
+
assistantText("Found the issue.\n1. Fix validation"),
|
|
21
|
+
],
|
|
22
|
+
});
|
|
23
|
+
expect(r).toContain("[Session Goal]");
|
|
24
|
+
expect(r).toContain("Fix login bug");
|
|
25
|
+
expect(r).toContain("---");
|
|
26
|
+
expect(r).toContain("[user]\nFix login bug");
|
|
27
|
+
expect(r).toContain('* Read "auth.ts"');
|
|
28
|
+
expect(r).toContain("Found the issue.");
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it("merges previous summary goals", () => {
|
|
32
|
+
const r = compile({
|
|
33
|
+
messages: [userMsg("New task")],
|
|
34
|
+
previousSummary: "[Session Goal]\n- Original goal\n\n---\n\n[user]\nOriginal goal",
|
|
35
|
+
});
|
|
36
|
+
expect(r).toContain("- Original goal");
|
|
37
|
+
expect(r).toContain("- New task");
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it("appends brief transcript on merge", () => {
|
|
41
|
+
const previousSummary = [
|
|
42
|
+
"[Session Goal]\n- Original goal",
|
|
43
|
+
"---",
|
|
44
|
+
"[user]\nOriginal goal\n\n[assistant]\n* Read \"old.ts\"",
|
|
45
|
+
].join("\n\n");
|
|
46
|
+
const r = compile({
|
|
47
|
+
previousSummary,
|
|
48
|
+
messages: [
|
|
49
|
+
userMsg("Next step"),
|
|
50
|
+
assistantWithToolCall("Read", { path: "new.ts" }),
|
|
51
|
+
],
|
|
52
|
+
});
|
|
53
|
+
expect(r).toContain('* Read "old.ts"');
|
|
54
|
+
expect(r).toContain('* Read "new.ts"');
|
|
55
|
+
expect(r).toContain("Next step");
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it("outstanding context is volatile (fresh only)", () => {
|
|
59
|
+
const previousSummary = "[Outstanding Context]\n- old blocker\n\n---\n\n[user]\nhi";
|
|
60
|
+
const r = compile({
|
|
61
|
+
previousSummary,
|
|
62
|
+
messages: [userMsg("continue")],
|
|
63
|
+
});
|
|
64
|
+
expect(r).not.toContain("old blocker");
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it("caps long brief transcript with rolling window", () => {
|
|
68
|
+
// Build a very long previous transcript
|
|
69
|
+
const longTranscript = Array.from({ length: 200 }, (_, i) =>
|
|
70
|
+
`[user]\nmessage ${i}`
|
|
71
|
+
).join("\n\n");
|
|
72
|
+
const previousSummary = `[Session Goal]\n- goal\n\n---\n\n${longTranscript}`;
|
|
73
|
+
const r = compile({
|
|
74
|
+
previousSummary,
|
|
75
|
+
messages: [userMsg("latest")],
|
|
76
|
+
});
|
|
77
|
+
expect(r).toContain("earlier lines omitted");
|
|
78
|
+
expect(r).toContain("latest");
|
|
79
|
+
});
|
|
80
|
+
});
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { describe, it, expect } from "bun:test";
|
|
2
|
+
import { textParts, textOf, clip, firstLine } from "../src/core/content";
|
|
3
|
+
|
|
4
|
+
describe("textParts", () => {
|
|
5
|
+
it("returns [] for undefined content", () => {
|
|
6
|
+
expect(textParts(undefined as any)).toEqual([]);
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
it("returns [] for null content", () => {
|
|
10
|
+
expect(textParts(null as any)).toEqual([]);
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
it("wraps string content", () => {
|
|
14
|
+
expect(textParts("hello")).toEqual(["hello"]);
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
it("extracts text parts from array content", () => {
|
|
18
|
+
const content = [
|
|
19
|
+
{ type: "text" as const, text: "first" },
|
|
20
|
+
{ type: "toolCall" as const, name: "x", id: "1", arguments: {} },
|
|
21
|
+
{ type: "text" as const, text: "second" },
|
|
22
|
+
];
|
|
23
|
+
expect(textParts(content)).toEqual(["first", "second"]);
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
describe("textOf", () => {
|
|
28
|
+
it("returns empty string for undefined content", () => {
|
|
29
|
+
expect(textOf(undefined as any)).toBe("");
|
|
30
|
+
});
|
|
31
|
+
});
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { describe, it, expect } from "bun:test";
|
|
2
|
+
import { extractGoals } from "../src/extract/goals";
|
|
3
|
+
import type { NormalizedBlock } from "../src/types";
|
|
4
|
+
|
|
5
|
+
describe("extractGoals", () => {
|
|
6
|
+
it("returns empty for no blocks", () => {
|
|
7
|
+
expect(extractGoals([])).toEqual([]);
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
it("returns empty when no user blocks", () => {
|
|
11
|
+
const blocks: NormalizedBlock[] = [
|
|
12
|
+
{ kind: "assistant", text: "hello" },
|
|
13
|
+
];
|
|
14
|
+
expect(extractGoals(blocks)).toEqual([]);
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
it("extracts first user message lines as goals", () => {
|
|
18
|
+
const blocks: NormalizedBlock[] = [
|
|
19
|
+
{ kind: "user", text: "Fix login bug\nCheck auth flow" },
|
|
20
|
+
];
|
|
21
|
+
const goals = extractGoals(blocks);
|
|
22
|
+
expect(goals).toEqual(["Fix login bug", "Check auth flow"]);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it("takes up to 6 lines from first user block", () => {
|
|
26
|
+
const blocks: NormalizedBlock[] = [
|
|
27
|
+
{ kind: "user", text: "fix the login bug\ncheck auth flow\nupdate the tests\nrefactor utils\nclean up" },
|
|
28
|
+
];
|
|
29
|
+
expect(extractGoals(blocks)).toHaveLength(5);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it("ignores subsequent user blocks", () => {
|
|
33
|
+
const blocks: NormalizedBlock[] = [
|
|
34
|
+
{ kind: "user", text: "first goal" },
|
|
35
|
+
{ kind: "assistant", text: "ok" },
|
|
36
|
+
{ kind: "user", text: "second request" },
|
|
37
|
+
];
|
|
38
|
+
expect(extractGoals(blocks)).toEqual(["first goal"]);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it("detects scope change with explicit pivot keywords", () => {
|
|
42
|
+
const blocks: NormalizedBlock[] = [
|
|
43
|
+
{ kind: "user", text: "Fix login bug" },
|
|
44
|
+
{ kind: "assistant", text: "ok" },
|
|
45
|
+
{ kind: "user", text: "Actually, instead let's refactor the auth module" },
|
|
46
|
+
];
|
|
47
|
+
const goals = extractGoals(blocks);
|
|
48
|
+
expect(goals).toContain("Fix login bug");
|
|
49
|
+
expect(goals).toContain("[Scope change]");
|
|
50
|
+
expect(goals.some((g) => g.includes("refactor"))).toBe(true);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it("detects scope change from new task statements", () => {
|
|
54
|
+
const blocks: NormalizedBlock[] = [
|
|
55
|
+
{ kind: "user", text: "Fix login bug" },
|
|
56
|
+
{ kind: "assistant", text: "done" },
|
|
57
|
+
{ kind: "user", text: "Now implement the user registration flow" },
|
|
58
|
+
];
|
|
59
|
+
const goals = extractGoals(blocks);
|
|
60
|
+
expect(goals).toContain("[Scope change]");
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it("keeps latest scope change only", () => {
|
|
64
|
+
const blocks: NormalizedBlock[] = [
|
|
65
|
+
{ kind: "user", text: "Fix login bug" },
|
|
66
|
+
{ kind: "assistant", text: "done" },
|
|
67
|
+
{ kind: "user", text: "Actually, fix the signup page instead" },
|
|
68
|
+
{ kind: "assistant", text: "ok" },
|
|
69
|
+
{ kind: "user", text: "Change of plan, implement password reset" },
|
|
70
|
+
];
|
|
71
|
+
const goals = extractGoals(blocks);
|
|
72
|
+
const scopeIdx = goals.indexOf("[Scope change]");
|
|
73
|
+
expect(goals[scopeIdx + 1]).toContain("password reset");
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it("skips noise short user messages as goals", () => {
|
|
77
|
+
const blocks: NormalizedBlock[] = [
|
|
78
|
+
{ kind: "user", text: "ok" },
|
|
79
|
+
{ kind: "assistant", text: "hello" },
|
|
80
|
+
{ kind: "user", text: "Fix the authentication module" },
|
|
81
|
+
];
|
|
82
|
+
const goals = extractGoals(blocks);
|
|
83
|
+
expect(goals[0]).toContain("Fix the authentication");
|
|
84
|
+
expect(goals.some((g) => g === "ok")).toBe(false);
|
|
85
|
+
});
|
|
86
|
+
});
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { describe, it, expect } from "bun:test";
|
|
2
|
+
import { extractPreferences } from "../src/extract/preferences";
|
|
3
|
+
import type { NormalizedBlock } from "../src/types";
|
|
4
|
+
|
|
5
|
+
describe("extractPreferences", () => {
|
|
6
|
+
it("returns empty for no blocks", () => {
|
|
7
|
+
expect(extractPreferences([])).toEqual([]);
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
it("captures preference patterns from user", () => {
|
|
11
|
+
const blocks: NormalizedBlock[] = [
|
|
12
|
+
{ kind: "user", text: "I prefer TypeScript over JavaScript" },
|
|
13
|
+
];
|
|
14
|
+
expect(extractPreferences(blocks).length).toBe(1);
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
it("ignores assistant blocks", () => {
|
|
18
|
+
const blocks: NormalizedBlock[] = [
|
|
19
|
+
{ kind: "assistant", text: "I always use best practices" },
|
|
20
|
+
];
|
|
21
|
+
expect(extractPreferences(blocks)).toEqual([]);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it("captures please use pattern", () => {
|
|
25
|
+
const blocks: NormalizedBlock[] = [
|
|
26
|
+
{ kind: "user", text: "please use bun instead of node" },
|
|
27
|
+
];
|
|
28
|
+
expect(extractPreferences(blocks).length).toBe(1);
|
|
29
|
+
});
|
|
30
|
+
});
|