@entelligentsia/forgecli 1.0.2 → 1.0.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +67 -0
- package/README.md +2 -1
- package/dist/CHANGELOG-forge-plugin.md +124 -0
- package/dist/CHANGELOG-pi.md +94 -0
- package/dist/extensions/forgecli/audience-gate.js +1 -1
- package/dist/extensions/forgecli/audience-gate.js.map +1 -1
- package/dist/extensions/forgecli/fix-bug.d.ts +1 -2
- package/dist/extensions/forgecli/fix-bug.js +678 -609
- package/dist/extensions/forgecli/fix-bug.js.map +1 -1
- package/dist/extensions/forgecli/forge-artifact-tool.js +42 -7
- package/dist/extensions/forgecli/forge-artifact-tool.js.map +1 -1
- package/dist/extensions/forgecli/forge-subagent.d.ts +17 -0
- package/dist/extensions/forgecli/forge-subagent.js +31 -12
- package/dist/extensions/forgecli/forge-subagent.js.map +1 -1
- package/dist/extensions/forgecli/forge-tools.d.ts +6 -0
- package/dist/extensions/forgecli/forge-tools.js +71 -8
- package/dist/extensions/forgecli/forge-tools.js.map +1 -1
- package/dist/extensions/forgecli/run-task.js +461 -391
- package/dist/extensions/forgecli/run-task.js.map +1 -1
- package/dist/extensions/forgecli/session-registry.d.ts +12 -0
- package/dist/extensions/forgecli/session-registry.js +23 -0
- package/dist/extensions/forgecli/session-registry.js.map +1 -1
- package/dist/extensions/forgecli/subagent/caller-context.d.ts +35 -11
- package/dist/extensions/forgecli/subagent/caller-context.js +49 -21
- package/dist/extensions/forgecli/subagent/caller-context.js.map +1 -1
- package/dist/extensions/forgecli/subagent/orchestrator-transcript.d.ts +66 -0
- package/dist/extensions/forgecli/subagent/orchestrator-transcript.js +66 -0
- package/dist/extensions/forgecli/subagent/orchestrator-transcript.js.map +1 -0
- package/dist/extensions/forgecli/subagent/phase-guard.d.ts +34 -0
- package/dist/extensions/forgecli/subagent/phase-guard.js +149 -0
- package/dist/extensions/forgecli/subagent/phase-guard.js.map +1 -0
- package/dist/extensions/forgecli/subagent/phase-summary-map.d.ts +2 -0
- package/dist/extensions/forgecli/subagent/phase-summary-map.js +39 -0
- package/dist/extensions/forgecli/subagent/phase-summary-map.js.map +1 -0
- package/dist/extensions/forgecli/thread-switcher.js +2 -2
- package/dist/extensions/forgecli/thread-switcher.js.map +1 -1
- package/dist/extensions/forgecli/viewport-events.d.ts +4 -0
- package/dist/extensions/forgecli/viewport-events.js +18 -1
- package/dist/extensions/forgecli/viewport-events.js.map +1 -1
- package/dist/extensions/forgecli/viewport-renderer.d.ts +12 -2
- package/dist/extensions/forgecli/viewport-renderer.js +8 -6
- package/dist/extensions/forgecli/viewport-renderer.js.map +1 -1
- package/dist/forge-payload/.base-pack/workflows/_fragments/store-cli-verbs.md +18 -3
- package/dist/forge-payload/.base-pack/workflows/architect_approve.md +4 -5
- package/dist/forge-payload/.base-pack/workflows/collator_agent.md +1 -1
- package/dist/forge-payload/.base-pack/workflows/commit_task.md +2 -3
- package/dist/forge-payload/.base-pack/workflows/fix_bug.md +10 -28
- package/dist/forge-payload/.base-pack/workflows/implement_plan.md +3 -2
- package/dist/forge-payload/.base-pack/workflows/orchestrate_task.md +41 -47
- package/dist/forge-payload/.base-pack/workflows/triage.md +190 -0
- package/dist/forge-payload/.base-pack/workflows/validate_task.md +2 -3
- package/dist/forge-payload/.claude-plugin/plugin.json +1 -1
- package/dist/forge-payload/.schemas/_defs/locator.schema.json +13 -0
- package/dist/forge-payload/.schemas/bug.schema.json +1 -0
- package/dist/forge-payload/.schemas/enum-catalog.json +2 -2
- package/dist/forge-payload/.schemas/migrations.json +72 -0
- package/dist/forge-payload/.schemas/sprint.schema.json +1 -0
- package/dist/forge-payload/.schemas/task.schema.json +1 -0
- package/dist/forge-payload/integrity.json +3 -3
- package/dist/forge-payload/meta/fragments/tool-discipline.md +21 -2
- package/dist/forge-payload/meta/workflows/_fragments/store-cli-verbs.md +18 -3
- package/dist/forge-payload/meta/workflows/meta-approve.md +4 -5
- package/dist/forge-payload/meta/workflows/meta-bug-triage.md +210 -0
- package/dist/forge-payload/meta/workflows/meta-collate.md +1 -1
- package/dist/forge-payload/meta/workflows/meta-commit.md +2 -3
- package/dist/forge-payload/meta/workflows/meta-fix-bug.md +10 -28
- package/dist/forge-payload/meta/workflows/meta-implement.md +3 -2
- package/dist/forge-payload/meta/workflows/meta-orchestrate.md +41 -47
- package/dist/forge-payload/meta/workflows/meta-validate.md +2 -3
- package/dist/forge-payload/schemas/_defs/locator.schema.json +13 -0
- package/dist/forge-payload/schemas/bug.schema.json +1 -0
- package/dist/forge-payload/schemas/enum-catalog.json +2 -2
- package/dist/forge-payload/schemas/sprint.schema.json +1 -0
- package/dist/forge-payload/schemas/structure-manifest.json +22 -2
- package/dist/forge-payload/schemas/task.schema.json +1 -0
- package/dist/forge-payload/tools/artifact-store.cjs +242 -0
- package/dist/forge-payload/tools/artifact.cjs +69 -100
- package/dist/forge-payload/tools/lib/artifact-kinds.cjs +95 -0
- package/dist/forge-payload/tools/lib/store-nlp.cjs +6 -0
- package/dist/forge-payload/tools/lib/store-query-exec.cjs +39 -5
- package/dist/forge-payload/tools/lib/suggest.cjs +2 -1
- package/dist/forge-payload/tools/preflight-gate.cjs +55 -5
- package/dist/forge-payload/tools/store-cli.cjs +50 -15
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/agent-harness.d.ts +5 -2
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/agent-harness.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/agent-harness.js +81 -18
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/agent-harness.js.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/compaction/branch-summarization.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/compaction/branch-summarization.js +1 -0
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/compaction/branch-summarization.js.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/compaction/compaction.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/compaction/compaction.js +19 -24
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/compaction/compaction.js.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/session.d.ts +1 -0
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/session.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/session.js +14 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/session.js.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/types.d.ts +22 -8
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/types.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/types.js.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/package.json +3 -3
- package/node_modules/@earendil-works/pi-ai/README.md +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/models.generated.d.ts +374 -122
- package/node_modules/@earendil-works/pi-ai/dist/models.generated.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/models.generated.js +424 -232
- package/node_modules/@earendil-works/pi-ai/dist/models.generated.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/amazon-bedrock.d.ts +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/amazon-bedrock.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/amazon-bedrock.js +38 -2
- package/node_modules/@earendil-works/pi-ai/dist/providers/amazon-bedrock.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/anthropic.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/anthropic.js +21 -12
- package/node_modules/@earendil-works/pi-ai/dist/providers/anthropic.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/azure-openai-responses.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/azure-openai-responses.js +6 -10
- package/node_modules/@earendil-works/pi-ai/dist/providers/azure-openai-responses.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/google-vertex.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/google-vertex.js +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/google-vertex.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/google.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/google.js +5 -3
- package/node_modules/@earendil-works/pi-ai/dist/providers/google.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/images/openrouter.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/images/openrouter.js +3 -4
- package/node_modules/@earendil-works/pi-ai/dist/providers/images/openrouter.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/mistral.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/mistral.js +2 -3
- package/node_modules/@earendil-works/pi-ai/dist/providers/mistral.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/openai-codex-responses.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/openai-codex-responses.js +159 -78
- package/node_modules/@earendil-works/pi-ai/dist/providers/openai-codex-responses.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/openai-completions.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/openai-completions.js +16 -11
- package/node_modules/@earendil-works/pi-ai/dist/providers/openai-completions.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/openai-responses-shared.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/openai-responses-shared.js +4 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/openai-responses-shared.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/openai-responses.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/openai-responses.js +6 -10
- package/node_modules/@earendil-works/pi-ai/dist/providers/openai-responses.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/simple-options.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/simple-options.js +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/providers/simple-options.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/stream.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/stream.js +14 -2
- package/node_modules/@earendil-works/pi-ai/dist/stream.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/types.d.ts +14 -4
- package/node_modules/@earendil-works/pi-ai/dist/types.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/types.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/utils/abort-signals.d.ts +6 -0
- package/node_modules/@earendil-works/pi-ai/dist/utils/abort-signals.d.ts.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/utils/abort-signals.js +34 -0
- package/node_modules/@earendil-works/pi-ai/dist/utils/abort-signals.js.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/device-code.d.ts +9 -7
- package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/device-code.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/device-code.js +8 -7
- package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/device-code.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/github-copilot.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/github-copilot.js +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/github-copilot.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/index.d.ts +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/index.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/index.js +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/index.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/openai-codex.d.ts +10 -1
- package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/openai-codex.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/openai-codex.js +179 -79
- package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/openai-codex.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/package.json +2 -2
- package/node_modules/@earendil-works/pi-coding-agent/CHANGELOG.md +94 -0
- package/node_modules/@earendil-works/pi-coding-agent/README.md +9 -0
- package/node_modules/@earendil-works/pi-coding-agent/dist/cli/args.d.ts +3 -0
- package/node_modules/@earendil-works/pi-coding-agent/dist/cli/args.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/cli/args.js +27 -0
- package/node_modules/@earendil-works/pi-coding-agent/dist/cli/args.js.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/config.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/config.js +15 -2
- package/node_modules/@earendil-works/pi-coding-agent/dist/config.js.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session-services.d.ts +1 -0
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session-services.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session-services.js +1 -0
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session-services.js.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session.d.ts +5 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session.js +28 -4
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session.js.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/compaction/compaction.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/compaction/compaction.js +18 -24
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/compaction/compaction.js.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/extensions/runner.d.ts +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/extensions/runner.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/extensions/runner.js +8 -2
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/extensions/runner.js.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/extensions/types.d.ts +7 -5
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/extensions/types.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/extensions/types.js.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/model-registry.js +65 -13
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/model-registry.js.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/model-resolver.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/model-resolver.js +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/model-resolver.js.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/resolve-config-value.d.ts +9 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/resolve-config-value.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/resolve-config-value.js +134 -11
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/resolve-config-value.js.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/sdk.d.ts +2 -0
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/sdk.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/sdk.js +10 -6
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/sdk.js.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/session-manager.d.ts +6 -7
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/session-manager.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/session-manager.js +75 -28
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/session-manager.js.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/settings-manager.d.ts +2 -0
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/settings-manager.js +14 -9
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/system-prompt.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/system-prompt.js +0 -3
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/system-prompt.js.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/edit.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/edit.js +7 -10
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/edit.js.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/find.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/find.js.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/grep.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/grep.js.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/ls.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/ls.js +5 -7
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/ls.js.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/read.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/read.js +6 -7
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/read.js.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/render-utils.d.ts +5 -2
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/render-utils.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/render-utils.js +17 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/render-utils.js.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/write.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/write.js +5 -6
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/write.js.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/index.d.ts +2 -0
- package/node_modules/@earendil-works/pi-coding-agent/dist/index.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/index.js +2 -0
- package/node_modules/@earendil-works/pi-coding-agent/dist/index.js.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/main.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/main.js +69 -16
- package/node_modules/@earendil-works/pi-coding-agent/dist/main.js.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/migrations.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/migrations.js +118 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/migrations.js.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/login-dialog.d.ts +1 -3
- package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/login-dialog.js +2 -4
- package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/login-dialog.js.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/user-message.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/user-message.js +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/user-message.js.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +3 -0
- package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/interactive-mode.js +59 -6
- package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/theme/theme.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/theme/theme.js +10 -0
- package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/theme/theme.js.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/modes/rpc/rpc-mode.js +3 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/modes/rpc/rpc-types.d.ts +1 -0
- package/node_modules/@earendil-works/pi-coding-agent/dist/modes/rpc/rpc-types.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/modes/rpc/rpc-types.js.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/utils/deprecation.d.ts +4 -0
- package/node_modules/@earendil-works/pi-coding-agent/dist/utils/deprecation.d.ts.map +1 -0
- package/node_modules/@earendil-works/pi-coding-agent/dist/utils/deprecation.js +13 -0
- package/node_modules/@earendil-works/pi-coding-agent/dist/utils/deprecation.js.map +1 -0
- package/node_modules/@earendil-works/pi-coding-agent/dist/utils/json.d.ts +3 -0
- package/node_modules/@earendil-works/pi-coding-agent/dist/utils/json.d.ts.map +1 -0
- package/node_modules/@earendil-works/pi-coding-agent/dist/utils/json.js +7 -0
- package/node_modules/@earendil-works/pi-coding-agent/dist/utils/json.js.map +1 -0
- package/node_modules/@earendil-works/pi-coding-agent/docs/custom-provider.md +13 -10
- package/node_modules/@earendil-works/pi-coding-agent/docs/development.md +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/docs/extensions.md +12 -6
- package/node_modules/@earendil-works/pi-coding-agent/docs/models.md +25 -12
- package/node_modules/@earendil-works/pi-coding-agent/docs/providers.md +13 -5
- package/node_modules/@earendil-works/pi-coding-agent/docs/quickstart.md +1 -0
- package/node_modules/@earendil-works/pi-coding-agent/docs/rpc.md +2 -1
- package/node_modules/@earendil-works/pi-coding-agent/docs/sdk.md +6 -0
- package/node_modules/@earendil-works/pi-coding-agent/docs/session-format.md +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/docs/sessions.md +8 -0
- package/node_modules/@earendil-works/pi-coding-agent/docs/settings.md +7 -3
- package/node_modules/@earendil-works/pi-coding-agent/docs/terminal-setup.md +2 -0
- package/node_modules/@earendil-works/pi-coding-agent/docs/tui.md +2 -2
- package/node_modules/@earendil-works/pi-coding-agent/docs/usage.md +9 -0
- package/node_modules/@earendil-works/pi-coding-agent/examples/extensions/README.md +1 -0
- package/node_modules/@earendil-works/pi-coding-agent/examples/extensions/custom-provider-anthropic/index.ts +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/examples/extensions/custom-provider-gitlab-duo/index.ts +54 -3
- package/node_modules/@earendil-works/pi-coding-agent/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/examples/extensions/git-merge-and-resolve.ts +115 -0
- package/node_modules/@earendil-works/pi-coding-agent/examples/extensions/input-transform-streaming.ts +39 -0
- package/node_modules/@earendil-works/pi-coding-agent/examples/extensions/sandbox/package.json +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/examples/extensions/with-deps/package.json +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/npm-shrinkwrap.json +443 -61
- package/node_modules/@earendil-works/pi-coding-agent/package.json +6 -6
- package/node_modules/@earendil-works/pi-tui/README.md +2 -2
- package/node_modules/@earendil-works/pi-tui/dist/components/editor.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/components/editor.js +24 -83
- package/node_modules/@earendil-works/pi-tui/dist/components/editor.js.map +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/components/input.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/components/input.js +7 -55
- package/node_modules/@earendil-works/pi-tui/dist/components/input.js.map +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/components/markdown.d.ts +7 -1
- package/node_modules/@earendil-works/pi-tui/dist/components/markdown.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/components/markdown.js +12 -2
- package/node_modules/@earendil-works/pi-tui/dist/components/markdown.js.map +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/index.d.ts +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/index.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/index.js.map +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/terminal-image.d.ts +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/terminal-image.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/terminal-image.js +34 -7
- package/node_modules/@earendil-works/pi-tui/dist/terminal-image.js.map +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/terminal.d.ts +33 -10
- package/node_modules/@earendil-works/pi-tui/dist/terminal.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/terminal.js +172 -37
- package/node_modules/@earendil-works/pi-tui/dist/terminal.js.map +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/utils.d.ts +6 -1
- package/node_modules/@earendil-works/pi-tui/dist/utils.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/utils.js +27 -15
- package/node_modules/@earendil-works/pi-tui/dist/utils.js.map +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/word-navigation.d.ts +25 -0
- package/node_modules/@earendil-works/pi-tui/dist/word-navigation.d.ts.map +1 -0
- package/node_modules/@earendil-works/pi-tui/dist/word-navigation.js +96 -0
- package/node_modules/@earendil-works/pi-tui/dist/word-navigation.js.map +1 -0
- package/node_modules/@earendil-works/pi-tui/package.json +2 -2
- package/node_modules/@entelligentsia/forge-compress/LICENSE +21 -0
- package/node_modules/@entelligentsia/forge-compress/README.md +85 -0
- package/node_modules/@entelligentsia/forge-compress/dist/compressor.d.ts +6 -0
- package/node_modules/@entelligentsia/forge-compress/dist/compressor.js +137 -0
- package/node_modules/@entelligentsia/forge-compress/dist/entropy.d.ts +3 -0
- package/node_modules/@entelligentsia/forge-compress/dist/entropy.js +99 -0
- package/node_modules/@entelligentsia/forge-compress/dist/forge/entity.d.ts +8 -0
- package/node_modules/@entelligentsia/forge-compress/dist/forge/entity.js +149 -0
- package/node_modules/@entelligentsia/forge-compress/dist/forge/index.d.ts +7 -0
- package/node_modules/@entelligentsia/forge-compress/dist/forge/index.js +4 -0
- package/node_modules/@entelligentsia/forge-compress/dist/forge/markdown.d.ts +5 -0
- package/node_modules/@entelligentsia/forge-compress/dist/forge/markdown.js +92 -0
- package/node_modules/@entelligentsia/forge-compress/dist/forge/query.d.ts +7 -0
- package/node_modules/@entelligentsia/forge-compress/dist/forge/query.js +60 -0
- package/node_modules/@entelligentsia/forge-compress/dist/forge/validate.d.ts +1 -0
- package/node_modules/@entelligentsia/forge-compress/dist/forge/validate.js +82 -0
- package/node_modules/@entelligentsia/forge-compress/dist/index.d.ts +6 -0
- package/node_modules/@entelligentsia/forge-compress/dist/index.js +5 -0
- package/node_modules/@entelligentsia/forge-compress/dist/progressive.d.ts +1 -0
- package/node_modules/@entelligentsia/forge-compress/dist/progressive.js +108 -0
- package/node_modules/@entelligentsia/forge-compress/dist/strip.d.ts +4 -0
- package/node_modules/@entelligentsia/forge-compress/dist/strip.js +55 -0
- package/node_modules/@entelligentsia/forge-compress/dist/tokens.d.ts +2 -0
- package/node_modules/@entelligentsia/forge-compress/dist/tokens.js +17 -0
- package/node_modules/@entelligentsia/forge-compress/package.json +45 -0
- package/node_modules/@entelligentsia/forge-compress/src/__tests__/compress.test.ts +409 -0
- package/node_modules/@entelligentsia/forge-compress/src/compressor.ts +147 -0
- package/node_modules/@entelligentsia/forge-compress/src/entropy.ts +105 -0
- package/node_modules/@entelligentsia/forge-compress/src/forge/entity.ts +184 -0
- package/node_modules/@entelligentsia/forge-compress/src/forge/index.ts +10 -0
- package/node_modules/@entelligentsia/forge-compress/src/forge/markdown.ts +122 -0
- package/node_modules/@entelligentsia/forge-compress/src/forge/query.ts +105 -0
- package/node_modules/@entelligentsia/forge-compress/src/forge/validate.ts +86 -0
- package/node_modules/@entelligentsia/forge-compress/src/index.ts +22 -0
- package/node_modules/@entelligentsia/forge-compress/src/progressive.ts +123 -0
- package/node_modules/@entelligentsia/forge-compress/src/strip.ts +58 -0
- package/node_modules/@entelligentsia/forge-compress/src/tokens.ts +19 -0
- package/node_modules/@mariozechner/clipboard/Cargo.toml +3 -3
- package/node_modules/@mariozechner/clipboard/index.d.ts +34 -20
- package/node_modules/@mariozechner/clipboard/index.js +546 -257
- package/node_modules/@mariozechner/clipboard/package.json +5 -6
- package/node_modules/@mariozechner/clipboard/package.json.prepack-backup +14 -14
- package/node_modules/@mariozechner/clipboard/src/lib.rs +4 -9
- package/node_modules/@mariozechner/clipboard-linux-x64-gnu/clipboard.linux-x64-gnu.node +0 -0
- package/node_modules/@mariozechner/clipboard-linux-x64-gnu/package.json +2 -2
- package/package.json +11 -16
- package/dist/forge-payload/.base-pack/commands/quiz-agent.md +0 -6
- package/dist/forge-payload/.base-pack/commands/retrospective.md +0 -6
- package/dist/forge-payload/.base-pack/commands/sprint-intake.md +0 -6
- package/dist/forge-payload/.base-pack/commands/sprint-plan.md +0 -6
- package/dist/forge-payload/commands/calibrate.md +0 -10
- package/dist/forge-payload/commands/materialize.md +0 -119
- package/dist/forge-payload/commands/migrate.md +0 -12
- package/dist/forge-payload/commands/quiz-agent.md +0 -6
- package/dist/forge-payload/commands/regenerate.md +0 -6
- package/dist/forge-payload/commands/store-query.md +0 -6
- package/dist/forge-payload/commands/store-repair.md +0 -6
- package/dist/forge-payload/commands/update-tools.md +0 -10
- package/dist/forge-payload/meta/templates/meta-retrospective.md +0 -28
- package/dist/forge-payload/tools/prompts/sprint-plan-prompt.md +0 -70
- package/dist/forge-payload/tools/schemas/task-list.schema.json +0 -53
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/execution-env.d.ts +0 -4
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/execution-env.d.ts.map +0 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/execution-env.js +0 -3
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/execution-env.js.map +0 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/repo/jsonl.d.ts +0 -20
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/repo/jsonl.d.ts.map +0 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/repo/jsonl.js +0 -92
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/repo/jsonl.js.map +0 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/repo/memory.d.ts +0 -18
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/repo/memory.d.ts.map +0 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/repo/memory.js +0 -42
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/repo/memory.js.map +0 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/repo/shared.d.ts +0 -10
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/repo/shared.d.ts.map +0 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/repo/shared.js +0 -31
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/repo/shared.js.map +0 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/storage/jsonl.d.ts +0 -30
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/storage/jsonl.d.ts.map +0 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/storage/jsonl.js +0 -170
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/storage/jsonl.js.map +0 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/storage/memory.d.ts +0 -26
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/storage/memory.d.ts.map +0 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/storage/memory.js +0 -90
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/storage/memory.js.map +0 -1
- package/node_modules/@mariozechner/clipboard-linux-x64-musl/README.md +0 -3
- package/node_modules/@mariozechner/clipboard-linux-x64-musl/clipboard.linux-x64-musl.node +0 -0
- package/node_modules/@mariozechner/clipboard-linux-x64-musl/package.json +0 -25
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { truncateToTokenBudget } from "./tokens.js";
|
|
2
|
+
const LAMBDA = 1.35;
|
|
3
|
+
function expWeights(n) {
|
|
4
|
+
return Array.from({ length: n }, (_, i) => Math.exp(LAMBDA * i));
|
|
5
|
+
}
|
|
6
|
+
function allocateBudget(budgetTokens, weights) {
|
|
7
|
+
const n = weights.length;
|
|
8
|
+
if (n === 0 || budgetTokens === 0)
|
|
9
|
+
return new Array(n).fill(0);
|
|
10
|
+
const sumW = Math.max(weights.reduce((a, b) => a + b, 0), Number.EPSILON);
|
|
11
|
+
const base = new Array(n).fill(0);
|
|
12
|
+
const frac = new Array(n).fill(0);
|
|
13
|
+
for (let i = 0; i < n; i++) {
|
|
14
|
+
const exact = (budgetTokens * weights[i]) / sumW;
|
|
15
|
+
base[i] = Math.floor(exact);
|
|
16
|
+
frac[i] = exact - base[i];
|
|
17
|
+
}
|
|
18
|
+
const given = base.reduce((a, b) => a + b, 0);
|
|
19
|
+
const order = Array.from({ length: n }, (_, i) => i).sort((a, b) => frac[b] - frac[a]);
|
|
20
|
+
let extra = budgetTokens - given;
|
|
21
|
+
for (const i of order) {
|
|
22
|
+
if (extra <= 0)
|
|
23
|
+
break;
|
|
24
|
+
base[i]++;
|
|
25
|
+
extra--;
|
|
26
|
+
}
|
|
27
|
+
return base;
|
|
28
|
+
}
|
|
29
|
+
function tierForIndex(i, n) {
|
|
30
|
+
if (n <= 1)
|
|
31
|
+
return 2;
|
|
32
|
+
const r = i / (n - 1);
|
|
33
|
+
if (r < 1 / 3)
|
|
34
|
+
return 0;
|
|
35
|
+
if (r < 2 / 3)
|
|
36
|
+
return 1;
|
|
37
|
+
return 2;
|
|
38
|
+
}
|
|
39
|
+
const STRUCTURE_KEYWORDS = [
|
|
40
|
+
"fn ",
|
|
41
|
+
"pub ",
|
|
42
|
+
"struct ",
|
|
43
|
+
"enum ",
|
|
44
|
+
"trait ",
|
|
45
|
+
"impl ",
|
|
46
|
+
"mod ",
|
|
47
|
+
"use ",
|
|
48
|
+
"def ",
|
|
49
|
+
"class ",
|
|
50
|
+
"function ",
|
|
51
|
+
"export ",
|
|
52
|
+
"import ",
|
|
53
|
+
"const ",
|
|
54
|
+
"interface ",
|
|
55
|
+
];
|
|
56
|
+
function mapLike(s, maxTokens) {
|
|
57
|
+
const picked = [];
|
|
58
|
+
const lines = s.split("\n");
|
|
59
|
+
for (let i = 0; i < lines.length; i++) {
|
|
60
|
+
if (i === 0 || STRUCTURE_KEYWORDS.some((k) => lines[i].includes(k))) {
|
|
61
|
+
picked.push(lines[i]);
|
|
62
|
+
}
|
|
63
|
+
if (picked.length >= 48)
|
|
64
|
+
break;
|
|
65
|
+
}
|
|
66
|
+
if (picked.length === 0 && lines.length > 0) {
|
|
67
|
+
picked.push(lines[0]);
|
|
68
|
+
}
|
|
69
|
+
return truncateToTokenBudget(picked.join("\n"), Math.max(4, maxTokens));
|
|
70
|
+
}
|
|
71
|
+
function oneLineSummary(segIdx, s, maxTokens) {
|
|
72
|
+
const preview = s.split("\n")[0]?.slice(0, 120) ?? "";
|
|
73
|
+
const lineCount = s.split("\n").length;
|
|
74
|
+
const draft = `// seg[${segIdx}] ${lineCount} lines, ${s.length} chars | ${preview}`;
|
|
75
|
+
return truncateToTokenBudget(draft, Math.max(8, maxTokens));
|
|
76
|
+
}
|
|
77
|
+
export function compressProgressive(segments, budgetTokens) {
|
|
78
|
+
const n = segments.length;
|
|
79
|
+
if (n === 0)
|
|
80
|
+
return [];
|
|
81
|
+
if (budgetTokens === 0)
|
|
82
|
+
return segments.map(() => "");
|
|
83
|
+
const weights = expWeights(n);
|
|
84
|
+
const allocs = allocateBudget(budgetTokens, weights);
|
|
85
|
+
const out = [];
|
|
86
|
+
for (let i = 0; i < n; i++) {
|
|
87
|
+
const alloc = allocs[i];
|
|
88
|
+
const tier = tierForIndex(i, n);
|
|
89
|
+
if (alloc === 0) {
|
|
90
|
+
out.push("");
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
let compressed;
|
|
94
|
+
switch (tier) {
|
|
95
|
+
case 2:
|
|
96
|
+
compressed = truncateToTokenBudget(segments[i], alloc);
|
|
97
|
+
break;
|
|
98
|
+
case 1:
|
|
99
|
+
compressed = mapLike(segments[i], alloc);
|
|
100
|
+
break;
|
|
101
|
+
default:
|
|
102
|
+
compressed = oneLineSummary(i, segments[i], alloc);
|
|
103
|
+
break;
|
|
104
|
+
}
|
|
105
|
+
out.push(truncateToTokenBudget(compressed, alloc));
|
|
106
|
+
}
|
|
107
|
+
return out;
|
|
108
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
const ANSI_RE = /\x1b\[[0-9;]*[a-zA-Z]/g;
|
|
2
|
+
export function stripAnsi(s) {
|
|
3
|
+
if (!s.includes("\x1b"))
|
|
4
|
+
return s;
|
|
5
|
+
return s.replace(ANSI_RE, "");
|
|
6
|
+
}
|
|
7
|
+
const TS_RE = /\d{4}-\d{2}-\d{2}[T ]\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:?\d{2})?/g;
|
|
8
|
+
const HASH_RE = /\b[0-9a-f]{32,64}\b/g;
|
|
9
|
+
export function stripTimestampsAndHashes(line) {
|
|
10
|
+
return line.replace(TS_RE, "[TS]").replace(HASH_RE, "[HASH]");
|
|
11
|
+
}
|
|
12
|
+
export function normalizeWhitespace(line) {
|
|
13
|
+
let result = "";
|
|
14
|
+
let prevSpace = false;
|
|
15
|
+
for (const ch of line) {
|
|
16
|
+
if (ch === " " || ch === "\t") {
|
|
17
|
+
if (!prevSpace) {
|
|
18
|
+
result += " ";
|
|
19
|
+
prevSpace = true;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
result += ch;
|
|
24
|
+
prevSpace = false;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return result;
|
|
28
|
+
}
|
|
29
|
+
const BOILERPLATE_PREFIXES = [
|
|
30
|
+
"copyright",
|
|
31
|
+
"licensed under",
|
|
32
|
+
"license:",
|
|
33
|
+
"all rights reserved",
|
|
34
|
+
"generated by",
|
|
35
|
+
"auto-generated",
|
|
36
|
+
];
|
|
37
|
+
const SEPARATOR_CHARS = new Set(["=", "-", "*", "─", "━"]);
|
|
38
|
+
export function isBoilerplate(line) {
|
|
39
|
+
const lower = line.toLowerCase();
|
|
40
|
+
if (BOILERPLATE_PREFIXES.some((p) => lower.startsWith(p)))
|
|
41
|
+
return true;
|
|
42
|
+
if (line.length >= 4) {
|
|
43
|
+
const first = line[0];
|
|
44
|
+
if (SEPARATOR_CHARS.has(first)) {
|
|
45
|
+
let same = 0;
|
|
46
|
+
for (const c of line) {
|
|
47
|
+
if (c === first)
|
|
48
|
+
same++;
|
|
49
|
+
}
|
|
50
|
+
if (same / line.length > 0.8)
|
|
51
|
+
return true;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
const CHARS_PER_TOKEN = 3.7;
|
|
2
|
+
export function countTokens(text) {
|
|
3
|
+
if (!text)
|
|
4
|
+
return 0;
|
|
5
|
+
return Math.ceil(text.length / CHARS_PER_TOKEN);
|
|
6
|
+
}
|
|
7
|
+
export function truncateToTokenBudget(text, maxTokens) {
|
|
8
|
+
if (maxTokens <= 0)
|
|
9
|
+
return "";
|
|
10
|
+
if (countTokens(text) <= maxTokens)
|
|
11
|
+
return text;
|
|
12
|
+
const charBudget = Math.floor(maxTokens * CHARS_PER_TOKEN);
|
|
13
|
+
const truncated = text.slice(0, charBudget);
|
|
14
|
+
const lastNewline = truncated.lastIndexOf("\n");
|
|
15
|
+
const clean = lastNewline > 0 ? truncated.slice(0, lastNewline) : truncated;
|
|
16
|
+
return `${clean} …`;
|
|
17
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@entelligentsia/forge-compress",
|
|
3
|
+
"repository": {
|
|
4
|
+
"type": "git",
|
|
5
|
+
"url": "https://github.com/Entelligentsia/forge-compress.git"
|
|
6
|
+
},
|
|
7
|
+
"version": "0.1.0",
|
|
8
|
+
"description": "Token-efficient compression for Forge SDLC tool outputs — store queries, entities, artifacts",
|
|
9
|
+
"type": "module",
|
|
10
|
+
"main": "dist/index.js",
|
|
11
|
+
"types": "dist/index.d.ts",
|
|
12
|
+
"exports": {
|
|
13
|
+
".": {
|
|
14
|
+
"types": "./dist/index.d.ts",
|
|
15
|
+
"import": "./dist/index.js"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"files": [
|
|
19
|
+
"dist",
|
|
20
|
+
"src"
|
|
21
|
+
],
|
|
22
|
+
"scripts": {
|
|
23
|
+
"build": "tsc",
|
|
24
|
+
"test": "vitest run",
|
|
25
|
+
"test:watch": "vitest",
|
|
26
|
+
"lint": "biome check src/",
|
|
27
|
+
"prepublishOnly": "npm run build"
|
|
28
|
+
},
|
|
29
|
+
"keywords": [
|
|
30
|
+
"compression",
|
|
31
|
+
"forge",
|
|
32
|
+
"sdlc",
|
|
33
|
+
"ai-agent",
|
|
34
|
+
"token-reduction"
|
|
35
|
+
],
|
|
36
|
+
"license": "MIT",
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"typescript": "^5.7.0",
|
|
39
|
+
"vitest": "^3.0.0",
|
|
40
|
+
"@biomejs/biome": "^1.9.0"
|
|
41
|
+
},
|
|
42
|
+
"engines": {
|
|
43
|
+
"node": ">=18"
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -0,0 +1,409 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import {
|
|
3
|
+
compressStoreQuery,
|
|
4
|
+
compressEntity,
|
|
5
|
+
compressEntityList,
|
|
6
|
+
compressMarkdown,
|
|
7
|
+
compressValidateStore,
|
|
8
|
+
countTokens,
|
|
9
|
+
compressIb,
|
|
10
|
+
compressProgressive,
|
|
11
|
+
truncateToTokenBudget,
|
|
12
|
+
lightweightCleanup,
|
|
13
|
+
verbatimCompact,
|
|
14
|
+
stripAnsi,
|
|
15
|
+
} from "../index.js";
|
|
16
|
+
|
|
17
|
+
// ── store-query compressor ──────────────────────────────────
|
|
18
|
+
|
|
19
|
+
const SAMPLE_QUERY = JSON.stringify(
|
|
20
|
+
{
|
|
21
|
+
query: "open tasks in S12",
|
|
22
|
+
path: "intent-nlp",
|
|
23
|
+
traversalTrace: [
|
|
24
|
+
"parsed intent: entity=task, status=open, sprint=S12",
|
|
25
|
+
"resolved S12 → PROJ-S12",
|
|
26
|
+
"loaded 8 task records",
|
|
27
|
+
"filtered by status: 5 matched",
|
|
28
|
+
],
|
|
29
|
+
results: [
|
|
30
|
+
{
|
|
31
|
+
id: "PROJ-S12-T01",
|
|
32
|
+
title: "Add auth middleware",
|
|
33
|
+
status: "implementing",
|
|
34
|
+
type: "task",
|
|
35
|
+
relationships: { sprintId: "PROJ-S12", featureId: "F-AUTH", blockedBy: null },
|
|
36
|
+
fileRefs: { json: ".forge/store/tasks/PROJ-S12-T01.json", md: ".forge/sprints/S12/tasks/T01/INDEX.md" },
|
|
37
|
+
storeRef: ".forge/store/tasks/PROJ-S12-T01.json",
|
|
38
|
+
indexRef: ".forge/sprints/S12/tasks/T01/INDEX.md",
|
|
39
|
+
excerpt: "# T01: Add auth middleware\n\n## Status: implementing\n\n## Plan\nImplement JWT-based auth middleware...\n\n## Key Changes\n- Added middleware handler\n- Updated route config\n- Added token validation\n\n## Notes\nBlocked by upstream API changes.\nNeed to coordinate with team B.\nAlso requires DB migration.\nSee PR #42 for details.\nReviewed by @alice.",
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
id: "PROJ-S12-T02",
|
|
43
|
+
title: "Fix rate limiter",
|
|
44
|
+
status: "planned",
|
|
45
|
+
type: "task",
|
|
46
|
+
relationships: { sprintId: "PROJ-S12" },
|
|
47
|
+
fileRefs: { json: ".forge/store/tasks/PROJ-S12-T02.json", md: ".forge/sprints/S12/tasks/T02/INDEX.md" },
|
|
48
|
+
storeRef: ".forge/store/tasks/PROJ-S12-T02.json",
|
|
49
|
+
indexRef: ".forge/sprints/S12/tasks/T02/INDEX.md",
|
|
50
|
+
excerpt: "# T02: Fix rate limiter\n\n## Status: planned\n\nRate limiter is dropping legitimate requests under load.",
|
|
51
|
+
},
|
|
52
|
+
],
|
|
53
|
+
relatedFileRefs: [".forge/sprints/S12/INDEX.md", ".forge/features/F-AUTH.md"],
|
|
54
|
+
config: { store: ".forge/store", engineering: ".forge/engineering" },
|
|
55
|
+
meta: { mode: "intent-nlp", engineVersion: "1.2.0", totalTimeMs: 42 },
|
|
56
|
+
},
|
|
57
|
+
null,
|
|
58
|
+
2,
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
describe("compressStoreQuery", () => {
|
|
62
|
+
it("strips envelope fields", () => {
|
|
63
|
+
const result = compressStoreQuery(SAMPLE_QUERY);
|
|
64
|
+
const parsed = JSON.parse(result);
|
|
65
|
+
expect(parsed.traversalTrace).toBeUndefined();
|
|
66
|
+
expect(parsed.config).toBeUndefined();
|
|
67
|
+
expect(parsed.meta).toBeUndefined();
|
|
68
|
+
expect(parsed.relatedFileRefs).toBeUndefined();
|
|
69
|
+
expect(parsed.results).toHaveLength(2);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it("strips fileRefs and storeRef from results", () => {
|
|
73
|
+
const result = compressStoreQuery(SAMPLE_QUERY);
|
|
74
|
+
const parsed = JSON.parse(result);
|
|
75
|
+
expect(parsed.results[0].fileRefs).toBeUndefined();
|
|
76
|
+
expect(parsed.results[0].storeRef).toBeUndefined();
|
|
77
|
+
expect(parsed.results[0].indexRef).toBeUndefined();
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it("strips excerpts by default", () => {
|
|
81
|
+
const result = compressStoreQuery(SAMPLE_QUERY);
|
|
82
|
+
const parsed = JSON.parse(result);
|
|
83
|
+
expect(parsed.results[0].excerpt).toBeUndefined();
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it("keeps truncated excerpts when requested", () => {
|
|
87
|
+
const result = compressStoreQuery(SAMPLE_QUERY, {
|
|
88
|
+
keepExcerpts: true,
|
|
89
|
+
maxExcerptLines: 3,
|
|
90
|
+
});
|
|
91
|
+
const parsed = JSON.parse(result);
|
|
92
|
+
expect(parsed.results[0].excerpt).toContain("Add auth middleware");
|
|
93
|
+
expect(parsed.results[0].excerpt).toContain("more lines");
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
it("preserves query and path", () => {
|
|
97
|
+
const result = compressStoreQuery(SAMPLE_QUERY);
|
|
98
|
+
const parsed = JSON.parse(result);
|
|
99
|
+
expect(parsed.query).toBe("open tasks in S12");
|
|
100
|
+
expect(parsed.path).toBe("intent-nlp");
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
it("limits results count", () => {
|
|
104
|
+
const result = compressStoreQuery(SAMPLE_QUERY, { maxResults: 1 });
|
|
105
|
+
const parsed = JSON.parse(result);
|
|
106
|
+
expect(parsed.results).toHaveLength(1);
|
|
107
|
+
expect(parsed.truncated).toBe(1);
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
it("strips null relationships", () => {
|
|
111
|
+
const result = compressStoreQuery(SAMPLE_QUERY);
|
|
112
|
+
const parsed = JSON.parse(result);
|
|
113
|
+
expect(parsed.results[0].relationships.blockedBy).toBeUndefined();
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
it("is significantly smaller than input", () => {
|
|
117
|
+
const result = compressStoreQuery(SAMPLE_QUERY);
|
|
118
|
+
expect(countTokens(result)).toBeLessThan(countTokens(SAMPLE_QUERY) * 0.5);
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
it("passes through non-JSON input", () => {
|
|
122
|
+
expect(compressStoreQuery("not json")).toBe("not json");
|
|
123
|
+
});
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
// ── entity compressor ───────────────────────────────────────
|
|
127
|
+
|
|
128
|
+
const SAMPLE_TASK = JSON.stringify(
|
|
129
|
+
{
|
|
130
|
+
taskId: "PROJ-S12-T01",
|
|
131
|
+
sprintId: "PROJ-S12",
|
|
132
|
+
title: "Add auth middleware",
|
|
133
|
+
status: "implementing",
|
|
134
|
+
path: "sprints/S12/tasks/T01",
|
|
135
|
+
feature_id: "F-AUTH",
|
|
136
|
+
description: "Implement JWT-based authentication middleware for all API routes.",
|
|
137
|
+
estimate: "M",
|
|
138
|
+
dependencies: ["PROJ-S12-T03"],
|
|
139
|
+
knowledgeUpdates: [{ file: "auth.md", delta: "Added JWT flow" }],
|
|
140
|
+
planIterations: 2,
|
|
141
|
+
codeReviewIterations: 1,
|
|
142
|
+
assignedModel: "claude-opus-4-7",
|
|
143
|
+
pipeline: "standard",
|
|
144
|
+
summaries: {
|
|
145
|
+
plan: {
|
|
146
|
+
objective: "Design JWT middleware architecture",
|
|
147
|
+
written_at: "2026-05-20T10:00:00Z",
|
|
148
|
+
key_changes: ["Created middleware handler", "Updated route config", "Added token validation", "Set up refresh flow"],
|
|
149
|
+
findings: ["Need to handle expired tokens gracefully"],
|
|
150
|
+
verdict: "approved",
|
|
151
|
+
artifact_ref: "PLAN.md",
|
|
152
|
+
},
|
|
153
|
+
review_plan: {
|
|
154
|
+
objective: "Review plan for auth middleware",
|
|
155
|
+
written_at: "2026-05-20T14:00:00Z",
|
|
156
|
+
key_changes: ["Approved with minor suggestions"],
|
|
157
|
+
verdict: "approved",
|
|
158
|
+
},
|
|
159
|
+
implementation: {
|
|
160
|
+
objective: "Implement auth middleware per plan",
|
|
161
|
+
written_at: "2026-05-21T09:00:00Z",
|
|
162
|
+
key_changes: ["Implemented JWT parsing", "Added route guards", "Unit tests passing", "Integration tests added", "Error handling complete"],
|
|
163
|
+
verdict: "approved",
|
|
164
|
+
artifact_ref: "PROGRESS.md",
|
|
165
|
+
},
|
|
166
|
+
},
|
|
167
|
+
},
|
|
168
|
+
null,
|
|
169
|
+
2,
|
|
170
|
+
);
|
|
171
|
+
|
|
172
|
+
describe("compressEntity", () => {
|
|
173
|
+
it("keeps essential fields", () => {
|
|
174
|
+
const result = compressEntity(SAMPLE_TASK);
|
|
175
|
+
const parsed = JSON.parse(result);
|
|
176
|
+
expect(parsed.taskId).toBe("PROJ-S12-T01");
|
|
177
|
+
expect(parsed.title).toBe("Add auth middleware");
|
|
178
|
+
expect(parsed.status).toBe("implementing");
|
|
179
|
+
expect(parsed.sprintId).toBe("PROJ-S12");
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
it("drops verbose fields by default", () => {
|
|
183
|
+
const result = compressEntity(SAMPLE_TASK);
|
|
184
|
+
const parsed = JSON.parse(result);
|
|
185
|
+
expect(parsed.description).toBeUndefined();
|
|
186
|
+
expect(parsed.knowledgeUpdates).toBeUndefined();
|
|
187
|
+
expect(parsed.assignedModel).toBeUndefined();
|
|
188
|
+
expect(parsed.path).toBeUndefined();
|
|
189
|
+
expect(parsed.planIterations).toBeUndefined();
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
it("keeps only latest summary by default", () => {
|
|
193
|
+
const result = compressEntity(SAMPLE_TASK);
|
|
194
|
+
const parsed = JSON.parse(result);
|
|
195
|
+
expect(parsed.summaries).toBeUndefined();
|
|
196
|
+
expect(parsed.latestPhase).toBe("implementation");
|
|
197
|
+
expect(parsed.latestSummary.objective).toBe("Implement auth middleware per plan");
|
|
198
|
+
expect(parsed.latestSummary.verdict).toBe("approved");
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
it("truncates key_changes in summary", () => {
|
|
202
|
+
const result = compressEntity(SAMPLE_TASK, { maxKeyChanges: 2 });
|
|
203
|
+
const parsed = JSON.parse(result);
|
|
204
|
+
expect(parsed.latestSummary.key_changes).toHaveLength(3);
|
|
205
|
+
expect(parsed.latestSummary.key_changes[2]).toContain("+3 more");
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
it("keeps all summaries when requested", () => {
|
|
209
|
+
const result = compressEntity(SAMPLE_TASK, { keepSummaries: "all" });
|
|
210
|
+
const parsed = JSON.parse(result);
|
|
211
|
+
expect(parsed.summaries).toBeDefined();
|
|
212
|
+
expect(parsed.summaries.plan).toBeDefined();
|
|
213
|
+
expect(parsed.summaries.implementation).toBeDefined();
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
it("produces flat format", () => {
|
|
217
|
+
const result = compressEntity(SAMPLE_TASK, { flatFormat: true });
|
|
218
|
+
expect(result).toContain("taskId: PROJ-S12-T01");
|
|
219
|
+
expect(result).toContain("status: implementing");
|
|
220
|
+
expect(result).not.toContain("{");
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
it("is smaller than input", () => {
|
|
224
|
+
const result = compressEntity(SAMPLE_TASK);
|
|
225
|
+
expect(countTokens(result)).toBeLessThan(countTokens(SAMPLE_TASK) * 0.5);
|
|
226
|
+
});
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
describe("compressEntityList", () => {
|
|
230
|
+
it("compresses array of entities", () => {
|
|
231
|
+
const list = JSON.stringify([JSON.parse(SAMPLE_TASK), JSON.parse(SAMPLE_TASK)], null, 2);
|
|
232
|
+
const result = compressEntityList(list);
|
|
233
|
+
const parsed = JSON.parse(result);
|
|
234
|
+
expect(parsed).toHaveLength(2);
|
|
235
|
+
expect(parsed[0].taskId).toBe("PROJ-S12-T01");
|
|
236
|
+
expect(parsed[0].description).toBeUndefined();
|
|
237
|
+
});
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
// ── markdown compressor ─────────────────────────────────────
|
|
241
|
+
|
|
242
|
+
const SAMPLE_MD = `---
|
|
243
|
+
title: Sprint S12 Progress
|
|
244
|
+
date: 2026-05-25
|
|
245
|
+
---
|
|
246
|
+
|
|
247
|
+
# Sprint S12: Auth & Rate Limiting
|
|
248
|
+
|
|
249
|
+
## Overview
|
|
250
|
+
This sprint covers the implementation of JWT authentication
|
|
251
|
+
middleware and fixing the rate limiter under high load.
|
|
252
|
+
There are multiple sub-tasks involved.
|
|
253
|
+
|
|
254
|
+
## Tasks
|
|
255
|
+
|
|
256
|
+
### T01: Add auth middleware
|
|
257
|
+
- **Status**: implementing
|
|
258
|
+
- **Estimate**: M
|
|
259
|
+
- Started implementation on May 20th
|
|
260
|
+
- Plan was approved after 2 iterations
|
|
261
|
+
- Currently blocked on upstream API
|
|
262
|
+
|
|
263
|
+
### T02: Fix rate limiter
|
|
264
|
+
- **Status**: planned
|
|
265
|
+
- **Estimate**: S
|
|
266
|
+
- Root cause identified as connection pool exhaustion
|
|
267
|
+
|
|
268
|
+
## Risks
|
|
269
|
+
- Upstream API team may not deliver on time
|
|
270
|
+
- Rate limiter fix requires load testing infrastructure
|
|
271
|
+
- JWT library has a known CVE that needs patching
|
|
272
|
+
|
|
273
|
+
## Timeline
|
|
274
|
+
| Milestone | Date | Status |
|
|
275
|
+
|-----------|------|--------|
|
|
276
|
+
| Plan approval | May 20 | Done |
|
|
277
|
+
| Auth impl | May 25 | In progress |
|
|
278
|
+
| Rate limiter | May 28 | Not started |
|
|
279
|
+
`;
|
|
280
|
+
|
|
281
|
+
describe("compressMarkdown", () => {
|
|
282
|
+
it("map mode keeps headings and key lines", () => {
|
|
283
|
+
const result = compressMarkdown(SAMPLE_MD, { mode: "map" });
|
|
284
|
+
expect(result).toContain("# Sprint S12");
|
|
285
|
+
expect(result).toContain("### T01");
|
|
286
|
+
expect(result).toContain("### T02");
|
|
287
|
+
expect(result).toContain("**Status**");
|
|
288
|
+
expect(result).toContain("body lines omitted");
|
|
289
|
+
expect(countTokens(result)).toBeLessThan(countTokens(SAMPLE_MD) * 0.7);
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
it("headings mode extracts structure only", () => {
|
|
293
|
+
const result = compressMarkdown(SAMPLE_MD, { mode: "headings" });
|
|
294
|
+
expect(result).toContain("Sprint S12");
|
|
295
|
+
expect(result).toContain("T01: Add auth middleware");
|
|
296
|
+
expect(result).toContain("sections");
|
|
297
|
+
expect(result).not.toContain("implementing");
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
it("truncate mode respects token budget", () => {
|
|
301
|
+
const result = compressMarkdown(SAMPLE_MD, { mode: "truncate", maxTokens: 50 });
|
|
302
|
+
expect(countTokens(result)).toBeLessThanOrEqual(60);
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
it("skips frontmatter", () => {
|
|
306
|
+
const result = compressMarkdown(SAMPLE_MD, { mode: "map" });
|
|
307
|
+
expect(result).not.toContain("title: Sprint S12 Progress");
|
|
308
|
+
expect(result).not.toContain("date: 2026");
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
it("handles empty input", () => {
|
|
312
|
+
expect(compressMarkdown("")).toBe("");
|
|
313
|
+
expect(compressMarkdown(" ")).toBe("");
|
|
314
|
+
});
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
// ── validate-store compressor ───────────────────────────────
|
|
318
|
+
|
|
319
|
+
describe("compressValidateStore", () => {
|
|
320
|
+
it("compresses JSON report", () => {
|
|
321
|
+
const report = JSON.stringify({
|
|
322
|
+
ok: false,
|
|
323
|
+
errors: [
|
|
324
|
+
{ entity: "task", id: "PROJ-S12-T01", category: "missing-required", field: "title", message: "title is required" },
|
|
325
|
+
{ entity: "task", id: "PROJ-S12-T02", category: "missing-required", field: "status", message: "status is required" },
|
|
326
|
+
{ entity: "bug", id: "PROJ-B01", category: "orphaned-fk", field: "sprintId", message: "references non-existent sprint" },
|
|
327
|
+
],
|
|
328
|
+
warnings: [
|
|
329
|
+
{ entity: "task", id: "PROJ-S12-T03", category: "stale-path", message: "path does not match filesystem" },
|
|
330
|
+
],
|
|
331
|
+
fixes: [
|
|
332
|
+
{ entity: "task", id: "PROJ-S12-T01", category: "backfill", message: "backfilled path", applied: true },
|
|
333
|
+
],
|
|
334
|
+
summary: { sprints: 2, tasks: 5, bugs: 1, features: 0, errors: 3, warnings: 1, fixes: 1 },
|
|
335
|
+
});
|
|
336
|
+
const result = compressValidateStore(report);
|
|
337
|
+
expect(result).toContain("missing-required (2)");
|
|
338
|
+
expect(result).toContain("orphaned-fk (1)");
|
|
339
|
+
expect(result).toContain("1 warnings");
|
|
340
|
+
expect(result).toContain("1 fixes (1 applied)");
|
|
341
|
+
expect(countTokens(result)).toBeLessThan(countTokens(report) * 0.6);
|
|
342
|
+
});
|
|
343
|
+
|
|
344
|
+
it("returns ok for valid store", () => {
|
|
345
|
+
const report = JSON.stringify({
|
|
346
|
+
ok: true,
|
|
347
|
+
errors: [],
|
|
348
|
+
warnings: [],
|
|
349
|
+
fixes: [],
|
|
350
|
+
summary: { sprints: 3, tasks: 12, bugs: 2, features: 1, errors: 0, warnings: 0, fixes: 0 },
|
|
351
|
+
});
|
|
352
|
+
const result = compressValidateStore(report);
|
|
353
|
+
expect(result).toContain("3 sprints");
|
|
354
|
+
expect(result).toContain("12 tasks");
|
|
355
|
+
});
|
|
356
|
+
|
|
357
|
+
it("compresses plain text validation output", () => {
|
|
358
|
+
const lines = Array.from({ length: 20 }, (_, i) =>
|
|
359
|
+
`ERROR PROJ-S12-T${String(i).padStart(2, "0")}: missing required field`
|
|
360
|
+
).join("\n");
|
|
361
|
+
const result = compressValidateStore(lines);
|
|
362
|
+
expect(result).toContain("20 errors");
|
|
363
|
+
expect(result).toContain("... +15 more");
|
|
364
|
+
});
|
|
365
|
+
});
|
|
366
|
+
|
|
367
|
+
// ── core utilities ──────────────────────────────────────────
|
|
368
|
+
|
|
369
|
+
describe("core utilities", () => {
|
|
370
|
+
it("countTokens", () => {
|
|
371
|
+
expect(countTokens("")).toBe(0);
|
|
372
|
+
expect(countTokens("hello world")).toBeGreaterThan(0);
|
|
373
|
+
});
|
|
374
|
+
|
|
375
|
+
it("stripAnsi", () => {
|
|
376
|
+
expect(stripAnsi("\x1b[31mERROR\x1b[0m")).toBe("ERROR");
|
|
377
|
+
expect(stripAnsi("clean")).toBe("clean");
|
|
378
|
+
});
|
|
379
|
+
|
|
380
|
+
it("truncateToTokenBudget", () => {
|
|
381
|
+
const long = "word ".repeat(1000);
|
|
382
|
+
const result = truncateToTokenBudget(long, 50);
|
|
383
|
+
expect(countTokens(result)).toBeLessThanOrEqual(60);
|
|
384
|
+
});
|
|
385
|
+
|
|
386
|
+
it("compressIb preserves high-entropy lines", () => {
|
|
387
|
+
let boring = "aaa bbb aaa bbb\n".repeat(30);
|
|
388
|
+
boring += "unique_identifier_xyz_quartz\n";
|
|
389
|
+
const result = compressIb(boring, 0.15);
|
|
390
|
+
expect(result).toContain("unique_identifier_xyz_quartz");
|
|
391
|
+
});
|
|
392
|
+
|
|
393
|
+
it("compressProgressive respects budget", () => {
|
|
394
|
+
const segs = Array.from({ length: 4 }, (_, i) => `segment ${i} content\n`);
|
|
395
|
+
const out = compressProgressive(segs, 80);
|
|
396
|
+
const total = out.reduce((acc, s) => acc + countTokens(s), 0);
|
|
397
|
+
expect(total).toBeLessThanOrEqual(80);
|
|
398
|
+
});
|
|
399
|
+
|
|
400
|
+
it("lightweightCleanup collapses blanks", () => {
|
|
401
|
+
const result = lightweightCleanup("a\n\n\n\n\nb");
|
|
402
|
+
expect(result.match(/\n/g)?.length ?? 0).toBeLessThanOrEqual(3);
|
|
403
|
+
});
|
|
404
|
+
|
|
405
|
+
it("verbatimCompact deduplicates", () => {
|
|
406
|
+
const result = verbatimCompact("same\n".repeat(20));
|
|
407
|
+
expect(result).toContain("[20x]");
|
|
408
|
+
});
|
|
409
|
+
});
|