@entelligentsia/forgecli 0.21.0 → 1.0.3
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 +44 -0
- package/README.md +31 -33
- package/dist/CHANGELOG-forge-plugin.md +142 -0
- package/dist/CHANGELOG-pi.md +24 -1
- package/dist/bin/forgecli.d.ts +2 -0
- package/dist/bin/forgecli.js +6 -0
- package/dist/bin/forgecli.js.map +1 -0
- package/dist/extensions/forgecli/add-pipeline.js +1 -1
- package/dist/extensions/forgecli/add-pipeline.js.map +1 -1
- package/dist/extensions/forgecli/add-task.js +1 -1
- package/dist/extensions/forgecli/add-task.js.map +1 -1
- package/dist/extensions/forgecli/approve.js +17 -2
- package/dist/extensions/forgecli/approve.js.map +1 -1
- package/dist/extensions/forgecli/audience-gate.js +1 -1
- package/dist/extensions/forgecli/audience-gate.js.map +1 -1
- package/dist/extensions/forgecli/calibrate.js +11 -8
- package/dist/extensions/forgecli/calibrate.js.map +1 -1
- package/dist/extensions/forgecli/collate.js +1 -1
- package/dist/extensions/forgecli/collate.js.map +1 -1
- package/dist/extensions/forgecli/commit.js +17 -2
- package/dist/extensions/forgecli/commit.js.map +1 -1
- package/dist/extensions/forgecli/enhance.js +1 -1
- package/dist/extensions/forgecli/enhance.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.d.ts +6 -8
- package/dist/extensions/forgecli/forge-artifact-tool.js +94 -197
- package/dist/extensions/forgecli/forge-artifact-tool.js.map +1 -1
- package/dist/extensions/forgecli/forge-commands.js +57 -18
- package/dist/extensions/forgecli/forge-commands.js.map +1 -1
- package/dist/extensions/forgecli/forge-init/phase4-register.js +6 -7
- package/dist/extensions/forgecli/forge-init/phase4-register.js.map +1 -1
- package/dist/extensions/forgecli/forge-init/run-phases.d.ts +4 -0
- package/dist/extensions/forgecli/forge-init/run-phases.js +304 -0
- package/dist/extensions/forgecli/forge-init/run-phases.js.map +1 -0
- package/dist/extensions/forgecli/forge-init/verifiers.d.ts +14 -5
- package/dist/extensions/forgecli/forge-init/verifiers.js +79 -62
- package/dist/extensions/forgecli/forge-init/verifiers.js.map +1 -1
- package/dist/extensions/forgecli/forge-init.js +131 -76
- package/dist/extensions/forgecli/forge-init.js.map +1 -1
- package/dist/extensions/forgecli/forge-subagent.d.ts +26 -0
- package/dist/extensions/forgecli/forge-subagent.js +42 -18
- package/dist/extensions/forgecli/forge-subagent.js.map +1 -1
- package/dist/extensions/forgecli/forge-tools.d.ts +34 -4
- package/dist/extensions/forgecli/forge-tools.js +191 -79
- package/dist/extensions/forgecli/forge-tools.js.map +1 -1
- package/dist/extensions/forgecli/health-check.js +3 -3
- package/dist/extensions/forgecli/health-check.js.map +1 -1
- package/dist/extensions/forgecli/hook-dispatcher.d.ts +1 -1
- package/dist/extensions/forgecli/hooks/check-update.d.ts +8 -0
- package/dist/extensions/forgecli/hooks/check-update.js +29 -1
- package/dist/extensions/forgecli/hooks/check-update.js.map +1 -1
- package/dist/extensions/forgecli/hooks/post-init-hook.js +6 -6
- package/dist/extensions/forgecli/hooks/post-init-hook.js.map +1 -1
- package/dist/extensions/forgecli/hooks/post-sprint-hook.js +6 -6
- package/dist/extensions/forgecli/hooks/post-sprint-hook.js.map +1 -1
- package/dist/extensions/forgecli/hooks/triage-error.js +1 -0
- package/dist/extensions/forgecli/hooks/triage-error.js.map +1 -1
- package/dist/extensions/forgecli/implement.js +20 -2
- package/dist/extensions/forgecli/implement.js.map +1 -1
- package/dist/extensions/forgecli/index.js +39 -32
- package/dist/extensions/forgecli/index.js.map +1 -1
- package/dist/extensions/forgecli/lib/pipeline-guard.d.ts +41 -0
- package/dist/extensions/forgecli/lib/pipeline-guard.js +100 -0
- package/dist/extensions/forgecli/lib/pipeline-guard.js.map +1 -0
- package/dist/extensions/forgecli/loaders/persona-skill-loader.js +2 -2
- package/dist/extensions/forgecli/loaders/persona-skill-loader.js.map +1 -1
- package/dist/extensions/forgecli/migrate.d.ts +3 -0
- package/dist/extensions/forgecli/migrate.js +4 -2
- package/dist/extensions/forgecli/migrate.js.map +1 -1
- package/dist/extensions/forgecli/plan.js +21 -2
- package/dist/extensions/forgecli/plan.js.map +1 -1
- package/dist/extensions/forgecli/quiz-agent.js +7 -7
- package/dist/extensions/forgecli/quiz-agent.js.map +1 -1
- package/dist/extensions/forgecli/regenerate.js +49 -18
- package/dist/extensions/forgecli/regenerate.js.map +1 -1
- package/dist/extensions/forgecli/remove-command.js +1 -1
- package/dist/extensions/forgecli/remove-command.js.map +1 -1
- package/dist/extensions/forgecli/report-bug.js +1 -1
- package/dist/extensions/forgecli/report-bug.js.map +1 -1
- package/dist/extensions/forgecli/retrospective.js +9 -9
- package/dist/extensions/forgecli/retrospective.js.map +1 -1
- package/dist/extensions/forgecli/review-code.d.ts +13 -0
- package/dist/extensions/forgecli/review-code.js +62 -3
- package/dist/extensions/forgecli/review-code.js.map +1 -1
- package/dist/extensions/forgecli/review-plan.d.ts +13 -0
- package/dist/extensions/forgecli/review-plan.js +65 -3
- package/dist/extensions/forgecli/review-plan.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/skill-curator-subagent.d.ts +2 -1
- package/dist/extensions/forgecli/skill-curator-subagent.js +2 -1
- package/dist/extensions/forgecli/skill-curator-subagent.js.map +1 -1
- package/dist/extensions/forgecli/sprint-intake.js +6 -6
- package/dist/extensions/forgecli/sprint-intake.js.map +1 -1
- package/dist/extensions/forgecli/sprint-plan.js +9 -9
- package/dist/extensions/forgecli/sprint-plan.js.map +1 -1
- package/dist/extensions/forgecli/status-command.js +1 -1
- package/dist/extensions/forgecli/status-command.js.map +1 -1
- package/dist/extensions/forgecli/store-query.js +11 -11
- package/dist/extensions/forgecli/store-query.js.map +1 -1
- package/dist/extensions/forgecli/store-repair.js +7 -7
- package/dist/extensions/forgecli/store-repair.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 +139 -0
- package/dist/extensions/forgecli/subagent/phase-guard.js.map +1 -0
- package/dist/extensions/forgecli/subagent/phase-summary-map.d.ts +1 -0
- package/dist/extensions/forgecli/subagent/phase-summary-map.js +22 -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/validate.js +17 -2
- package/dist/extensions/forgecli/validate.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/commands/check-agent.md +22 -0
- package/dist/forge-payload/.base-pack/commands/new-sprint.md +22 -0
- package/dist/forge-payload/.base-pack/commands/plan-sprint.md +22 -0
- package/dist/forge-payload/.base-pack/commands/quiz-agent.md +2 -18
- package/dist/forge-payload/.base-pack/commands/retro.md +22 -0
- package/dist/forge-payload/.base-pack/commands/retrospective.md +2 -18
- package/dist/forge-payload/.base-pack/commands/sprint-intake.md +2 -18
- package/dist/forge-payload/.base-pack/commands/sprint-plan.md +2 -18
- package/dist/forge-payload/.base-pack/workflows/_fragments/friction-emit.md +2 -2
- package/dist/forge-payload/.base-pack/workflows/_fragments/generation-instructions.md +4 -4
- package/dist/forge-payload/.base-pack/workflows/_fragments/iron-laws.md +1 -1
- package/dist/forge-payload/.base-pack/workflows/architect_approve.md +13 -1
- package/dist/forge-payload/.base-pack/workflows/commit_task.md +12 -1
- package/dist/forge-payload/.base-pack/workflows/enhance.md +6 -6
- package/dist/forge-payload/.base-pack/workflows/fix_bug.md +11 -29
- package/dist/forge-payload/.base-pack/workflows/implement_plan.md +14 -2
- package/dist/forge-payload/.base-pack/workflows/migrate_structural.md +2 -2
- package/dist/forge-payload/.base-pack/workflows/orchestrate_task.md +20 -4
- package/dist/forge-payload/.base-pack/workflows/plan_task.md +14 -2
- package/dist/forge-payload/.base-pack/workflows/review_code.md +37 -7
- package/dist/forge-payload/.base-pack/workflows/review_plan.md +36 -6
- package/dist/forge-payload/.base-pack/workflows/run_sprint.md +2 -2
- package/dist/forge-payload/.base-pack/workflows/triage.md +190 -0
- package/dist/forge-payload/.base-pack/workflows/validate_task.md +37 -7
- package/dist/forge-payload/.claude-plugin/plugin.json +1 -1
- package/dist/forge-payload/.schemas/config.schema.json +0 -5
- package/dist/forge-payload/.schemas/enum-catalog.json +9 -13
- package/dist/forge-payload/.schemas/migrations.json +63 -0
- package/dist/forge-payload/agents/tomoshibi.md +150 -6
- package/dist/forge-payload/commands/add-pipeline.md +1 -1
- package/dist/forge-payload/commands/add-task.md +1 -1
- package/dist/forge-payload/commands/calibrate.md +4 -350
- package/dist/forge-payload/commands/check-agent.md +38 -0
- package/dist/forge-payload/commands/config.md +3 -113
- package/dist/forge-payload/commands/enhance.md +5 -32
- package/dist/forge-payload/commands/health.md +155 -13
- package/dist/forge-payload/commands/init.md +25 -31
- package/dist/forge-payload/commands/migrate.md +6 -154
- package/dist/forge-payload/commands/quiz-agent.md +2 -34
- package/dist/forge-payload/commands/rebuild.md +664 -0
- package/dist/forge-payload/commands/regenerate.md +2 -774
- package/dist/forge-payload/commands/remove.md +10 -13
- package/dist/forge-payload/commands/repair.md +187 -0
- package/dist/forge-payload/commands/search.md +73 -0
- package/dist/forge-payload/commands/status.md +105 -0
- package/dist/forge-payload/commands/store-query.md +2 -69
- package/dist/forge-payload/commands/store-repair.md +2 -183
- package/dist/forge-payload/commands/update-tools.md +4 -50
- package/dist/forge-payload/commands/update.md +64 -58
- package/dist/forge-payload/hooks/check-update.cjs +1 -1
- package/dist/forge-payload/hooks/post-init.cjs +2 -2
- package/dist/forge-payload/hooks/post-sprint.cjs +2 -2
- package/dist/forge-payload/hooks/triage-error.cjs +11 -10
- package/dist/forge-payload/init/phases/phase-1-collect.md +138 -0
- package/dist/forge-payload/init/phases/phase-2-discover.md +127 -0
- package/dist/forge-payload/init/phases/phase-3-materialize.md +113 -0
- package/dist/forge-payload/init/phases/phase-4-register.md +159 -0
- package/dist/forge-payload/integrity.json +21 -24
- package/dist/forge-payload/meta/fragments/tool-discipline.md +41 -0
- package/dist/forge-payload/meta/templates/meta-retro.md +28 -0
- package/dist/forge-payload/meta/workflows/_fragments/friction-emit.md +2 -2
- package/dist/forge-payload/meta/workflows/_fragments/generation-instructions.md +4 -4
- package/dist/forge-payload/meta/workflows/_fragments/iron-laws.md +1 -1
- package/dist/forge-payload/meta/workflows/meta-approve.md +13 -1
- package/dist/forge-payload/meta/workflows/meta-bug-triage.md +210 -0
- package/dist/forge-payload/meta/workflows/meta-check-agent.md +138 -0
- package/dist/forge-payload/meta/workflows/meta-commit.md +12 -1
- package/dist/forge-payload/meta/workflows/meta-enhance.md +5 -5
- package/dist/forge-payload/meta/workflows/meta-fix-bug.md +11 -29
- package/dist/forge-payload/meta/workflows/meta-implement.md +13 -1
- package/dist/forge-payload/meta/workflows/meta-migrate.md +3 -3
- package/dist/forge-payload/meta/workflows/meta-new-sprint.md +84 -0
- package/dist/forge-payload/meta/workflows/meta-orchestrate.md +20 -4
- package/dist/forge-payload/meta/workflows/meta-plan-sprint.md +152 -0
- package/dist/forge-payload/meta/workflows/meta-plan-task.md +13 -1
- package/dist/forge-payload/meta/workflows/meta-retro.md +73 -0
- package/dist/forge-payload/meta/workflows/meta-review-implementation.md +37 -7
- package/dist/forge-payload/meta/workflows/meta-review-plan.md +36 -6
- package/dist/forge-payload/meta/workflows/meta-validate.md +37 -7
- package/dist/forge-payload/schemas/config.schema.json +0 -5
- package/dist/forge-payload/schemas/enum-catalog.json +9 -13
- package/dist/forge-payload/schemas/structure-manifest.json +25 -8
- package/dist/forge-payload/tools/artifact.cjs +324 -0
- package/dist/forge-payload/tools/banners.cjs +3 -4
- package/dist/forge-payload/tools/build-context-pack.cjs +1 -1
- package/dist/forge-payload/tools/check-structure.cjs +8 -3
- package/dist/forge-payload/tools/store-cli.cjs +67 -7
- package/dist/forge-payload/tools/substitute-placeholders.cjs +1 -1
- package/dist/forge-payload/tools/verify-apply.cjs +75 -0
- package/dist/forge-payload/tools/verify-phase.cjs +259 -0
- package/node_modules/@earendil-works/pi-agent-core/package.json +2 -2
- package/node_modules/@earendil-works/pi-ai/dist/models.generated.d.ts +0 -17
- 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 +21 -38
- package/node_modules/@earendil-works/pi-ai/dist/models.generated.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 +5 -4
- package/node_modules/@earendil-works/pi-ai/dist/providers/openai-codex-responses.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/utils/overflow.d.ts +2 -1
- package/node_modules/@earendil-works/pi-ai/dist/utils/overflow.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/utils/overflow.js +5 -2
- package/node_modules/@earendil-works/pi-ai/dist/utils/overflow.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/package.json +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/CHANGELOG.md +24 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/cli/file-processor.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/cli/file-processor.js +2 -3
- package/node_modules/@earendil-works/pi-coding-agent/dist/cli/file-processor.js.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/output-guard.d.ts +1 -0
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/output-guard.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/output-guard.js +52 -22
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/output-guard.js.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/package-manager.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/package-manager.js +16 -4
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/package-manager.js.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/bash.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/bash.js +45 -50
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/bash.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 +43 -81
- 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/file-mutation-queue.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/file-mutation-queue.js +27 -12
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/file-mutation-queue.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 +2 -3
- 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 +3 -3
- 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 -5
- 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/path-utils.d.ts +2 -0
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/path-utils.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/path-utils.js +37 -0
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/path-utils.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 +9 -8
- 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/write.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/write.js +20 -35
- 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/modes/rpc/rpc-client.d.ts +3 -0
- package/node_modules/@earendil-works/pi-coding-agent/dist/modes/rpc/rpc-client.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/modes/rpc/rpc-client.js +64 -7
- package/node_modules/@earendil-works/pi-coding-agent/dist/modes/rpc/rpc-client.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 +15 -3
- 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/utils/clipboard-native.d.ts +3 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/utils/clipboard-native.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/utils/clipboard-native.js +14 -8
- package/node_modules/@earendil-works/pi-coding-agent/dist/utils/clipboard-native.js.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/utils/image-resize-core.d.ts +30 -0
- package/node_modules/@earendil-works/pi-coding-agent/dist/utils/image-resize-core.d.ts.map +1 -0
- package/node_modules/@earendil-works/pi-coding-agent/dist/utils/image-resize-core.js +124 -0
- package/node_modules/@earendil-works/pi-coding-agent/dist/utils/image-resize-core.js.map +1 -0
- package/node_modules/@earendil-works/pi-coding-agent/dist/utils/image-resize-worker.d.ts +2 -0
- package/node_modules/@earendil-works/pi-coding-agent/dist/utils/image-resize-worker.d.ts.map +1 -0
- package/node_modules/@earendil-works/pi-coding-agent/dist/utils/image-resize-worker.js +31 -0
- package/node_modules/@earendil-works/pi-coding-agent/dist/utils/image-resize-worker.js.map +1 -0
- package/node_modules/@earendil-works/pi-coding-agent/dist/utils/image-resize.d.ts +7 -27
- package/node_modules/@earendil-works/pi-coding-agent/dist/utils/image-resize.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/utils/image-resize.js +75 -115
- package/node_modules/@earendil-works/pi-coding-agent/dist/utils/image-resize.js.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/docs/terminal-setup.md +6 -0
- 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/package.json +1 -1
- 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 +12 -14
- package/node_modules/@earendil-works/pi-coding-agent/package.json +5 -5
- package/node_modules/@earendil-works/pi-tui/dist/native-modifiers.d.ts +3 -0
- package/node_modules/@earendil-works/pi-tui/dist/native-modifiers.d.ts.map +1 -0
- package/node_modules/@earendil-works/pi-tui/dist/native-modifiers.js +53 -0
- package/node_modules/@earendil-works/pi-tui/dist/native-modifiers.js.map +1 -0
- 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 +4 -1
- 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 +2 -0
- package/node_modules/@earendil-works/pi-tui/dist/terminal.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/terminal.js +13 -1
- package/node_modules/@earendil-works/pi-tui/dist/terminal.js.map +1 -1
- package/node_modules/@earendil-works/pi-tui/native/darwin/prebuilds/darwin-arm64/darwin-modifiers.node +0 -0
- package/node_modules/@earendil-works/pi-tui/native/darwin/prebuilds/darwin-x64/darwin-modifiers.node +0 -0
- package/node_modules/@earendil-works/pi-tui/package.json +2 -2
- 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/package.json +10 -15
- package/dist/extensions/forgecli/forge-init/phase-descriptors.d.ts +0 -72
- package/dist/extensions/forgecli/forge-init/phase-descriptors.js +0 -359
- package/dist/extensions/forgecli/forge-init/phase-descriptors.js.map +0 -1
- package/dist/extensions/forgecli/forge-init/prompts.d.ts +0 -10
- package/dist/extensions/forgecli/forge-init/prompts.js +0 -91
- package/dist/extensions/forgecli/forge-init/prompts.js.map +0 -1
- package/dist/extensions/forgecli/lib/store-error-remediation.d.ts +0 -65
- package/dist/extensions/forgecli/lib/store-error-remediation.js +0 -298
- package/dist/extensions/forgecli/lib/store-error-remediation.js.map +0 -1
- package/dist/forge-payload/hooks/check-update.js +0 -378
- package/dist/forge-payload/hooks/forge-permissions.js +0 -164
- package/dist/forge-payload/hooks/triage-error.js +0 -77
- package/dist/forge-payload/hooks/validate-write.js +0 -250
|
@@ -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
|
+
});
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { countTokens } from "./tokens.js";
|
|
2
|
+
import {
|
|
3
|
+
stripAnsi,
|
|
4
|
+
stripTimestampsAndHashes,
|
|
5
|
+
normalizeWhitespace,
|
|
6
|
+
isBoilerplate,
|
|
7
|
+
} from "./strip.js";
|
|
8
|
+
|
|
9
|
+
export function lightweightCleanup(content: string): string {
|
|
10
|
+
const lines = content.split("\n");
|
|
11
|
+
const total = lines.length;
|
|
12
|
+
const result: string[] = [];
|
|
13
|
+
let blankCount = 0;
|
|
14
|
+
let braceRun: string[] = [];
|
|
15
|
+
|
|
16
|
+
const flushBraceRun = () => {
|
|
17
|
+
if (total <= 200 || braceRun.length <= 5) {
|
|
18
|
+
result.push(...braceRun);
|
|
19
|
+
} else {
|
|
20
|
+
result.push(braceRun[0], braceRun[1]);
|
|
21
|
+
result.push(`[${braceRun.length - 2} brace-only lines collapsed]`);
|
|
22
|
+
}
|
|
23
|
+
braceRun = [];
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
for (const line of lines) {
|
|
27
|
+
const trimmed = line.trim();
|
|
28
|
+
if (!trimmed) {
|
|
29
|
+
flushBraceRun();
|
|
30
|
+
blankCount++;
|
|
31
|
+
if (blankCount <= 1) result.push("");
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
blankCount = 0;
|
|
35
|
+
if (/^[}\]);]+$/.test(trimmed)) {
|
|
36
|
+
braceRun.push(trimmed);
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
flushBraceRun();
|
|
40
|
+
result.push(line);
|
|
41
|
+
}
|
|
42
|
+
flushBraceRun();
|
|
43
|
+
return result.join("\n");
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function verbatimCompact(text: string): string {
|
|
47
|
+
const lines: string[] = [];
|
|
48
|
+
let blankCount = 0;
|
|
49
|
+
let prevLine: string | null = null;
|
|
50
|
+
let repeatCount = 0;
|
|
51
|
+
|
|
52
|
+
const flushRepeats = () => {
|
|
53
|
+
if (repeatCount > 1 && prevLine !== null) {
|
|
54
|
+
const lastIdx = lines.length - 1;
|
|
55
|
+
if (lastIdx >= 0) {
|
|
56
|
+
lines[lastIdx] = `[${repeatCount}x] ${prevLine}`;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
repeatCount = 0;
|
|
60
|
+
prevLine = null;
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
for (const line of text.split("\n")) {
|
|
64
|
+
const trimmed = line.trim();
|
|
65
|
+
if (!trimmed) {
|
|
66
|
+
blankCount++;
|
|
67
|
+
if (blankCount <= 1) {
|
|
68
|
+
flushRepeats();
|
|
69
|
+
lines.push("");
|
|
70
|
+
}
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
blankCount = 0;
|
|
74
|
+
if (isBoilerplate(trimmed)) continue;
|
|
75
|
+
|
|
76
|
+
const normalized = normalizeWhitespace(trimmed);
|
|
77
|
+
const stripped = stripTimestampsAndHashes(normalized);
|
|
78
|
+
|
|
79
|
+
if (prevLine !== null && prevLine === stripped) {
|
|
80
|
+
repeatCount++;
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
flushRepeats();
|
|
84
|
+
prevLine = stripped;
|
|
85
|
+
repeatCount = 1;
|
|
86
|
+
lines.push(stripped);
|
|
87
|
+
}
|
|
88
|
+
flushRepeats();
|
|
89
|
+
return lines.join("\n");
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export function aggressiveCompress(
|
|
93
|
+
content: string,
|
|
94
|
+
ext?: string,
|
|
95
|
+
): string {
|
|
96
|
+
const result: string[] = [];
|
|
97
|
+
const isPython = ext === "py";
|
|
98
|
+
const isHtml = ext === "html" || ext === "htm" || ext === "xml" || ext === "svg";
|
|
99
|
+
const isSql = ext === "sql";
|
|
100
|
+
const isShell = ext === "sh" || ext === "bash" || ext === "zsh" || ext === "fish";
|
|
101
|
+
let inBlockComment = false;
|
|
102
|
+
|
|
103
|
+
for (const line of content.split("\n")) {
|
|
104
|
+
const trimmed = line.trim();
|
|
105
|
+
if (!trimmed) continue;
|
|
106
|
+
|
|
107
|
+
if (inBlockComment) {
|
|
108
|
+
if (trimmed.includes("*/") || (isHtml && trimmed.includes("-->"))) {
|
|
109
|
+
inBlockComment = false;
|
|
110
|
+
}
|
|
111
|
+
continue;
|
|
112
|
+
}
|
|
113
|
+
if (trimmed.startsWith("/*") || (isHtml && trimmed.startsWith("<!--"))) {
|
|
114
|
+
if (!(trimmed.includes("*/") || trimmed.includes("-->"))) {
|
|
115
|
+
inBlockComment = true;
|
|
116
|
+
}
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
119
|
+
if (trimmed.startsWith("//") && !trimmed.startsWith("///")) continue;
|
|
120
|
+
if (trimmed.startsWith("*") || trimmed.startsWith("*/")) continue;
|
|
121
|
+
if (isPython && trimmed.startsWith("#")) continue;
|
|
122
|
+
if (isSql && trimmed.startsWith("--")) continue;
|
|
123
|
+
if (isShell && trimmed.startsWith("#") && !trimmed.startsWith("#!")) continue;
|
|
124
|
+
|
|
125
|
+
if (/^[}\]);]+$/.test(trimmed)) {
|
|
126
|
+
const last = result[result.length - 1];
|
|
127
|
+
if (last && /^[}\]);]+$/.test(last.trim())) {
|
|
128
|
+
result[result.length - 1] = last + trimmed;
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
result.push(trimmed);
|
|
133
|
+
}
|
|
134
|
+
return result.join("\n");
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export function safeguardRatio(original: string, compressed: string): string {
|
|
138
|
+
const origTokens = countTokens(original);
|
|
139
|
+
const compTokens = countTokens(compressed);
|
|
140
|
+
if (origTokens === 0) return compressed;
|
|
141
|
+
if (compTokens > origTokens) return original;
|
|
142
|
+
const ratio = compTokens / origTokens;
|
|
143
|
+
if (ratio < 0.05 && origTokens < 2000) return original;
|
|
144
|
+
return compressed;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
export { stripAnsi };
|