@pugi/cli 0.1.0-beta.99 → 1.0.0-alpha.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/LICENSE +1 -1
- package/README.md +11 -191
- package/bin/pugi +8 -0
- package/package.json +15 -71
- package/postinstall.mjs +31 -0
- package/CHANGELOG.md +0 -132
- package/THIRD_PARTY_NOTICES.md +0 -40
- package/assets/pugi-mascot.ansi +0 -16
- package/assets/pugi-prozr2-mascot.ansi +0 -9
- package/bin/run.js +0 -34
- package/dist/commands/deploy.js +0 -439
- package/dist/commands/flatten.js +0 -191
- package/dist/commands/jobs-watch.js +0 -201
- package/dist/commands/jobs.js +0 -260
- package/dist/commands/retro.js +0 -210
- package/dist/commands/smoke.js +0 -133
- package/dist/core/agent-progress/cleanup.js +0 -134
- package/dist/core/agent-progress/schema.js +0 -144
- package/dist/core/agent-progress/writer.js +0 -101
- package/dist/core/agents/adaptive-router.js +0 -330
- package/dist/core/agents/loader.js +0 -104
- package/dist/core/agents/query-decomposer.js +0 -297
- package/dist/core/agents/registry.js +0 -69
- package/dist/core/approvals/shortcut-resolver.js +0 -98
- package/dist/core/artifact-chain/dispatcher.js +0 -148
- package/dist/core/artifact-chain/exporter.js +0 -164
- package/dist/core/artifact-chain/state.js +0 -243
- package/dist/core/artifact-chain/steps.js +0 -169
- package/dist/core/ask-user/question.js +0 -92
- package/dist/core/audit/audit-trail.js +0 -275
- package/dist/core/auth/ensure-authenticated.js +0 -129
- package/dist/core/auth/env-provider.js +0 -238
- package/dist/core/auto-open-browser.js +0 -128
- package/dist/core/auto-update/channels.js +0 -122
- package/dist/core/auto-update/checker.js +0 -241
- package/dist/core/auto-update/state.js +0 -235
- package/dist/core/bare-mode/index.js +0 -107
- package/dist/core/bash/redirect.js +0 -281
- package/dist/core/bash-classifier.js +0 -1397
- package/dist/core/checkpoint/resumer.js +0 -149
- package/dist/core/checkpoint/rewinder.js +0 -291
- package/dist/core/checkpoints/shadow-git.js +0 -670
- package/dist/core/citations/parser.js +0 -109
- package/dist/core/classifier/yolo-classifier.js +0 -88
- package/dist/core/clipboard.js +0 -70
- package/dist/core/codegraph/decision-store.js +0 -248
- package/dist/core/codegraph/detect-repo.js +0 -459
- package/dist/core/codegraph/install.js +0 -134
- package/dist/core/codegraph/offer-hook.js +0 -220
- package/dist/core/compact/auto-trigger.js +0 -96
- package/dist/core/compact/buffer-rewriter.js +0 -115
- package/dist/core/compact/summarizer.js +0 -208
- package/dist/core/compact/token-counter.js +0 -108
- package/dist/core/consensus/anvil-fanout.js +0 -276
- package/dist/core/consensus/diff-capture.js +0 -491
- package/dist/core/consensus/rubric.js +0 -233
- package/dist/core/context/builder.js +0 -114
- package/dist/core/context/compaction-events.js +0 -99
- package/dist/core/context/compaction.js +0 -602
- package/dist/core/context/index.js +0 -28
- package/dist/core/context/invariants.js +0 -250
- package/dist/core/context/markdown-loader.js +0 -288
- package/dist/core/context/markdown-traverse.js +0 -255
- package/dist/core/context/pugiignore.js +0 -316
- package/dist/core/context/repo-skeleton.js +0 -533
- package/dist/core/context/tool-eviction.js +0 -55
- package/dist/core/context/watcher.js +0 -342
- package/dist/core/context/working-set.js +0 -165
- package/dist/core/coordinator/agent-tools.js +0 -77
- package/dist/core/coordinator/agent-toolset.js +0 -65
- package/dist/core/coordinator/fsm.js +0 -73
- package/dist/core/coordinator/mode-fsm.js +0 -70
- package/dist/core/cost/rate-card.js +0 -129
- package/dist/core/cost/tracker.js +0 -221
- package/dist/core/credentials.js +0 -355
- package/dist/core/cron/scheduler.js +0 -138
- package/dist/core/denial-tracking/index.js +0 -8
- package/dist/core/denial-tracking/state.js +0 -264
- package/dist/core/diagnostics/probe-runner.js +0 -93
- package/dist/core/diagnostics/probes/api.js +0 -46
- package/dist/core/diagnostics/probes/auth.js +0 -93
- package/dist/core/diagnostics/probes/bare-mode.js +0 -42
- package/dist/core/diagnostics/probes/cli-version.js +0 -127
- package/dist/core/diagnostics/probes/config.js +0 -72
- package/dist/core/diagnostics/probes/denial-tracking.js +0 -57
- package/dist/core/diagnostics/probes/disk.js +0 -81
- package/dist/core/diagnostics/probes/engine-live.js +0 -46
- package/dist/core/diagnostics/probes/git.js +0 -65
- package/dist/core/diagnostics/probes/hooks.js +0 -118
- package/dist/core/diagnostics/probes/mcp.js +0 -75
- package/dist/core/diagnostics/probes/node.js +0 -59
- package/dist/core/diagnostics/probes/pnpm.js +0 -36
- package/dist/core/diagnostics/probes/pugi-md.js +0 -89
- package/dist/core/diagnostics/probes/sandbox.js +0 -72
- package/dist/core/diagnostics/probes/session.js +0 -74
- package/dist/core/diagnostics/probes/status-snapshot.js +0 -488
- package/dist/core/diagnostics/probes/workspace.js +0 -63
- package/dist/core/diagnostics/types.js +0 -70
- package/dist/core/dispatch/cache-cleanup.js +0 -197
- package/dist/core/dispatch/cache-handoff.js +0 -295
- package/dist/core/edits/apply-patch-layer-e.js +0 -189
- package/dist/core/edits/dispatch.js +0 -511
- package/dist/core/edits/format-detector.js +0 -260
- package/dist/core/edits/format-matrix.js +0 -26
- package/dist/core/edits/fuzzy-ladder.js +0 -650
- package/dist/core/edits/index.js +0 -19
- package/dist/core/edits/journal.js +0 -199
- package/dist/core/edits/layer-a-apply.js +0 -217
- package/dist/core/edits/layer-a-fuzzy-apply.js +0 -198
- package/dist/core/edits/layer-b-apply.js +0 -211
- package/dist/core/edits/layer-c-apply.js +0 -160
- package/dist/core/edits/layer-d-ast.js +0 -572
- package/dist/core/edits/marker-parser.js +0 -401
- package/dist/core/edits/security-gate.js +0 -223
- package/dist/core/edits/verify-hook.js +0 -273
- package/dist/core/edits/worktree.js +0 -322
- package/dist/core/engine/adapter-runner.js +0 -8
- package/dist/core/engine/anvil-client.js +0 -344
- package/dist/core/engine/auto-compact.js +0 -179
- package/dist/core/engine/budgets.js +0 -195
- package/dist/core/engine/context-prefix.js +0 -155
- package/dist/core/engine/index.js +0 -12
- package/dist/core/engine/intensity.js +0 -163
- package/dist/core/engine/intent.js +0 -260
- package/dist/core/engine/native-pugi.js +0 -1616
- package/dist/core/engine/noop.js +0 -27
- package/dist/core/engine/prompts.js +0 -236
- package/dist/core/engine/strip-internal-fields.js +0 -124
- package/dist/core/engine/tool-bridge.js +0 -2173
- package/dist/core/engine/verification-patterns.js +0 -195
- package/dist/core/evaluation/golden-dataset.js +0 -293
- package/dist/core/feedback/queue.js +0 -177
- package/dist/core/feedback/submitter.js +0 -145
- package/dist/core/file-cache.js +0 -141
- package/dist/core/flatten/flatten-repo.js +0 -439
- package/dist/core/format/osc8-link.js +0 -28
- package/dist/core/hook-chains.js +0 -392
- package/dist/core/hooks/citation-verify-hook.js +0 -138
- package/dist/core/hooks/citation-verify.js +0 -112
- package/dist/core/hooks/events.js +0 -46
- package/dist/core/hooks/index.js +0 -15
- package/dist/core/hooks/registry.js +0 -216
- package/dist/core/hooks/runner.js +0 -236
- package/dist/core/hooks/v2/event-emitter.js +0 -115
- package/dist/core/hooks/v2/executor.js +0 -282
- package/dist/core/hooks/v2/index.js +0 -25
- package/dist/core/hooks/v2/lifecycle.js +0 -104
- package/dist/core/hooks/v2/loader.js +0 -216
- package/dist/core/hooks/v2/matcher.js +0 -125
- package/dist/core/hooks/v2/trust.js +0 -143
- package/dist/core/hooks/v2/types.js +0 -86
- package/dist/core/hooks/worktree-events.js +0 -158
- package/dist/core/hooks.js +0 -415
- package/dist/core/image/renderer.js +0 -71
- package/dist/core/index-store.js +0 -260
- package/dist/core/init/detector.js +0 -582
- package/dist/core/init/template-renderer.js +0 -242
- package/dist/core/jobs/registry.js +0 -462
- package/dist/core/ledger/results-tsv.js +0 -142
- package/dist/core/log-discipline/stdout-redirect.js +0 -51
- package/dist/core/lsp/cache.js +0 -105
- package/dist/core/lsp/client.js +0 -1229
- package/dist/core/lsp/language-detect.js +0 -66
- package/dist/core/lsp/post-edit-diagnostics.js +0 -171
- package/dist/core/lsp/server-detect.js +0 -173
- package/dist/core/lsp/symbol-cache.js +0 -162
- package/dist/core/lsp/symbol-tools.js +0 -664
- package/dist/core/mcp/client.js +0 -385
- package/dist/core/mcp/http-server.js +0 -553
- package/dist/core/mcp/orchestrator-config.js +0 -192
- package/dist/core/mcp/orchestrator-tools.js +0 -806
- package/dist/core/mcp/permission.js +0 -190
- package/dist/core/mcp/registry.js +0 -193
- package/dist/core/mcp/server-tools.js +0 -219
- package/dist/core/mcp/server.js +0 -397
- package/dist/core/mcp/trust.js +0 -91
- package/dist/core/memory/dual-write.js +0 -416
- package/dist/core/memory/passive-extract.js +0 -130
- package/dist/core/memory/phase1-kinds.js +0 -20
- package/dist/core/memory/secret-scanner.js +0 -304
- package/dist/core/memory-sync/queue.js +0 -170
- package/dist/core/metrics/extract.js +0 -113
- package/dist/core/modes/roo-modes.js +0 -68
- package/dist/core/onboarding/ensure-initialized.js +0 -133
- package/dist/core/onboarding/marker.js +0 -111
- package/dist/core/onboarding/telemetry-state.js +0 -108
- package/dist/core/output-style/presets.js +0 -176
- package/dist/core/output-style/state.js +0 -185
- package/dist/core/path-security.js +0 -345
- package/dist/core/permission.js +0 -369
- package/dist/core/permissions/auto-classifier.js +0 -124
- package/dist/core/permissions/bash-parser.js +0 -371
- package/dist/core/permissions/circuit-breaker.js +0 -83
- package/dist/core/permissions/constrained-edit.js +0 -91
- package/dist/core/permissions/gate.js +0 -278
- package/dist/core/permissions/index.js +0 -20
- package/dist/core/permissions/mode.js +0 -174
- package/dist/core/permissions/network-egress.js +0 -137
- package/dist/core/permissions/state.js +0 -241
- package/dist/core/permissions/tool-class.js +0 -107
- package/dist/core/plan-mode/ui-state.js +0 -51
- package/dist/core/plans/plan-artifact.js +0 -721
- package/dist/core/policy-limits/etag-store.js +0 -122
- package/dist/core/prd-check/parser.js +0 -215
- package/dist/core/prd-check/reporter.js +0 -127
- package/dist/core/prd-check/session-review.js +0 -557
- package/dist/core/prd-check/verifiers.js +0 -223
- package/dist/core/prompt-cache/client-cache.js +0 -99
- package/dist/core/prompts/assembly.js +0 -29
- package/dist/core/prompts/registry.js +0 -364
- package/dist/core/pugi-gitignore.js +0 -52
- package/dist/core/pugi-md/cc-compat-rules.js +0 -735
- package/dist/core/pugi-md/context-injector.js +0 -76
- package/dist/core/pugi-md/walk-up.js +0 -207
- package/dist/core/python/uv-installer.js +0 -270
- package/dist/core/python/uv-resolver.js +0 -83
- package/dist/core/rate-limit/narrator.js +0 -146
- package/dist/core/recipes/cli-types.js +0 -20
- package/dist/core/recipes/loader.js +0 -103
- package/dist/core/recipes/runner.js +0 -345
- package/dist/core/recipes/schema.js +0 -587
- package/dist/core/release-notes/parser.js +0 -241
- package/dist/core/release-notes/state.js +0 -116
- package/dist/core/repl/ask.js +0 -512
- package/dist/core/repl/cancellation.js +0 -98
- package/dist/core/repl/cap-warning.js +0 -91
- package/dist/core/repl/clipboard-read.js +0 -174
- package/dist/core/repl/dispatch-fsm.js +0 -220
- package/dist/core/repl/engine-bridge.js +0 -303
- package/dist/core/repl/history-search.js +0 -175
- package/dist/core/repl/history.js +0 -182
- package/dist/core/repl/kill-ring.js +0 -138
- package/dist/core/repl/model-pricing.js +0 -135
- package/dist/core/repl/privacy-banner.js +0 -71
- package/dist/core/repl/session.js +0 -4962
- package/dist/core/repl/slash-commands.js +0 -747
- package/dist/core/repl/store/index.js +0 -12
- package/dist/core/repl/store/jsonl-log.js +0 -321
- package/dist/core/repl/store/lockfile.js +0 -155
- package/dist/core/repl/store/session-store.js +0 -821
- package/dist/core/repl/store/types.js +0 -44
- package/dist/core/repl/store/uuid-v7.js +0 -68
- package/dist/core/repl/tool-route.js +0 -382
- package/dist/core/repl/workspace-context.js +0 -206
- package/dist/core/repo-map/build.js +0 -125
- package/dist/core/repo-map/cache.js +0 -185
- package/dist/core/repo-map/extractor.js +0 -254
- package/dist/core/repo-map/formatter.js +0 -145
- package/dist/core/repo-map/page-rank.js +0 -105
- package/dist/core/repo-map/scanner.js +0 -211
- package/dist/core/retro/git-collector.js +0 -251
- package/dist/core/retro/health-card.js +0 -25
- package/dist/core/retro/metrics.js +0 -342
- package/dist/core/retro/narrative.js +0 -249
- package/dist/core/retro/plane-collector.js +0 -274
- package/dist/core/retro/pr-issue-link.js +0 -65
- package/dist/core/retro/types.js +0 -16
- package/dist/core/retry-budget/budget.js +0 -284
- package/dist/core/retry-budget/index.js +0 -5
- package/dist/core/retry-budget/retry-cap.js +0 -74
- package/dist/core/routing/lead-worker.js +0 -43
- package/dist/core/routing/pre-flight-estimator.js +0 -108
- package/dist/core/runs/run-tree.js +0 -103
- package/dist/core/sandboxing/adapter.js +0 -29
- package/dist/core/sandboxing/index.js +0 -49
- package/dist/core/sandboxing/none.js +0 -19
- package/dist/core/sandboxing/seatbelt.js +0 -183
- package/dist/core/security/injection-scanner.js +0 -367
- package/dist/core/security/output-filter.js +0 -418
- package/dist/core/session/env-file.js +0 -105
- package/dist/core/session/section-budgets.js +0 -140
- package/dist/core/session.js +0 -377
- package/dist/core/settings.js +0 -400
- package/dist/core/share/formatter.js +0 -271
- package/dist/core/share/redactor.js +0 -221
- package/dist/core/share/uploader.js +0 -267
- package/dist/core/skills/defaults.js +0 -457
- package/dist/core/skills/loader.js +0 -454
- package/dist/core/skills/sources.js +0 -480
- package/dist/core/skills/trust.js +0 -172
- package/dist/core/smoke/headless-driver.js +0 -174
- package/dist/core/smoke/orchestrator.js +0 -194
- package/dist/core/smoke/runner.js +0 -238
- package/dist/core/smoke/scenario-parser.js +0 -316
- package/dist/core/statusline.js +0 -99
- package/dist/core/subagents/dispatcher-real.js +0 -600
- package/dist/core/subagents/dispatcher.js +0 -352
- package/dist/core/subagents/index.js +0 -39
- package/dist/core/subagents/isolation-matrix.js +0 -213
- package/dist/core/subagents/spawn.js +0 -101
- package/dist/core/telemetry/emitter.js +0 -229
- package/dist/core/telemetry/queue.js +0 -251
- package/dist/core/theme/context.js +0 -91
- package/dist/core/theme/presets.js +0 -228
- package/dist/core/theme/state.js +0 -181
- package/dist/core/todos/invariant.js +0 -10
- package/dist/core/todos/state.js +0 -177
- package/dist/core/tool-schema/compressor.js +0 -89
- package/dist/core/transport/version-interceptor.js +0 -166
- package/dist/core/trust.js +0 -109
- package/dist/core/tui/thinking-block.js +0 -64
- package/dist/core/vim/keymap.js +0 -288
- package/dist/core/vim/state.js +0 -92
- package/dist/core/watch-markers/marker-watcher.js +0 -133
- package/dist/core/worktree/include-parser.js +0 -249
- package/dist/core/worktree-manager/cleanup.js +0 -123
- package/dist/core/worktree-manager/manager.js +0 -303
- package/dist/index.js +0 -44
- package/dist/runtime/bootstrap.js +0 -190
- package/dist/runtime/cli.js +0 -8121
- package/dist/runtime/commands/agents.js +0 -385
- package/dist/runtime/commands/budget.js +0 -192
- package/dist/runtime/commands/cancel.js +0 -231
- package/dist/runtime/commands/chain.js +0 -489
- package/dist/runtime/commands/codegraph-status.js +0 -227
- package/dist/runtime/commands/compact.js +0 -297
- package/dist/runtime/commands/config.js +0 -595
- package/dist/runtime/commands/cost.js +0 -199
- package/dist/runtime/commands/delegate.js +0 -312
- package/dist/runtime/commands/dispatch.js +0 -126
- package/dist/runtime/commands/doctor.js +0 -579
- package/dist/runtime/commands/feedback.js +0 -184
- package/dist/runtime/commands/hooks.js +0 -187
- package/dist/runtime/commands/init.js +0 -254
- package/dist/runtime/commands/lsp.js +0 -368
- package/dist/runtime/commands/mcp.js +0 -935
- package/dist/runtime/commands/memory.js +0 -582
- package/dist/runtime/commands/model.js +0 -237
- package/dist/runtime/commands/onboarding.js +0 -275
- package/dist/runtime/commands/patch.js +0 -128
- package/dist/runtime/commands/permissions.js +0 -112
- package/dist/runtime/commands/plan.js +0 -143
- package/dist/runtime/commands/prd-check.js +0 -285
- package/dist/runtime/commands/privacy.js +0 -107
- package/dist/runtime/commands/recipe.js +0 -325
- package/dist/runtime/commands/redo-blob-store.js +0 -92
- package/dist/runtime/commands/redo.js +0 -361
- package/dist/runtime/commands/release-notes.js +0 -229
- package/dist/runtime/commands/repo-map.js +0 -95
- package/dist/runtime/commands/report.js +0 -299
- package/dist/runtime/commands/resume.js +0 -118
- package/dist/runtime/commands/review-consensus.js +0 -414
- package/dist/runtime/commands/rewind.js +0 -333
- package/dist/runtime/commands/roster.js +0 -117
- package/dist/runtime/commands/sessions.js +0 -163
- package/dist/runtime/commands/share.js +0 -316
- package/dist/runtime/commands/skills.js +0 -401
- package/dist/runtime/commands/status.js +0 -186
- package/dist/runtime/commands/stickers.js +0 -82
- package/dist/runtime/commands/style.js +0 -194
- package/dist/runtime/commands/theme.js +0 -196
- package/dist/runtime/commands/undo.js +0 -361
- package/dist/runtime/commands/update.js +0 -289
- package/dist/runtime/commands/vim.js +0 -140
- package/dist/runtime/commands/worktree.js +0 -177
- package/dist/runtime/commands/worktrees.js +0 -155
- package/dist/runtime/deprecation-warning.js +0 -69
- package/dist/runtime/engine-exit-code.js +0 -50
- package/dist/runtime/headless-repl.js +0 -195
- package/dist/runtime/headless.js +0 -548
- package/dist/runtime/load-hooks-or-exit.js +0 -71
- package/dist/runtime/plan-decompose.js +0 -531
- package/dist/runtime/sigint-guard.js +0 -272
- package/dist/runtime/stream-renderer.js +0 -195
- package/dist/runtime/update-check.js +0 -294
- package/dist/runtime/version.js +0 -65
- package/dist/runtime/worktree-bootstrap.js +0 -579
- package/dist/skills/bundled/batch.js +0 -617
- package/dist/skills/bundled/index.js +0 -45
- package/dist/skills/bundled/loop.js +0 -358
- package/dist/skills/bundled/remember.js +0 -383
- package/dist/skills/bundled/simplify.js +0 -289
- package/dist/skills/bundled/skillify.js +0 -373
- package/dist/skills/bundled/stuck.js +0 -558
- package/dist/skills/bundled/verify.js +0 -439
- package/dist/testing/vcr.js +0 -486
- package/dist/tools/agent-tool.js +0 -229
- package/dist/tools/apply-patch.js +0 -556
- package/dist/tools/ask-user-question.js +0 -337
- package/dist/tools/ask-user.js +0 -115
- package/dist/tools/bash.js +0 -1238
- package/dist/tools/brief.js +0 -224
- package/dist/tools/cron.js +0 -433
- package/dist/tools/enter-worktree.js +0 -250
- package/dist/tools/exit-worktree.js +0 -147
- package/dist/tools/file-tools.js +0 -553
- package/dist/tools/http-request.js +0 -336
- package/dist/tools/lsp-tools.js +0 -565
- package/dist/tools/mcp-tool.js +0 -260
- package/dist/tools/multi-edit.js +0 -361
- package/dist/tools/powershell.js +0 -268
- package/dist/tools/registry.js +0 -166
- package/dist/tools/server-tools.js +0 -892
- package/dist/tools/skill-tool.js +0 -96
- package/dist/tools/sleep.js +0 -99
- package/dist/tools/synthetic-output.js +0 -133
- package/dist/tools/tasks.js +0 -208
- package/dist/tools/todo-write.js +0 -184
- package/dist/tools/verify-plan-execution.js +0 -295
- package/dist/tools/web-fetch-injection-scanner.js +0 -207
- package/dist/tools/web-fetch.js +0 -720
- package/dist/tools/web-search.js +0 -458
- package/dist/tui/agent-progress-card.js +0 -111
- package/dist/tui/agent-tree-pane.js +0 -9
- package/dist/tui/agent-tree.js +0 -87
- package/dist/tui/ask-cli.js +0 -52
- package/dist/tui/ask-modal.js +0 -211
- package/dist/tui/ask-user-question-chips.js +0 -315
- package/dist/tui/ask-user-question-prompt.js +0 -203
- package/dist/tui/compact-banner.js +0 -81
- package/dist/tui/conversation-pane.js +0 -164
- package/dist/tui/cost-table.js +0 -111
- package/dist/tui/device-flow.js +0 -142
- package/dist/tui/doctor-table.js +0 -46
- package/dist/tui/feedback-prompt.js +0 -156
- package/dist/tui/input-box.js +0 -732
- package/dist/tui/login-picker.js +0 -69
- package/dist/tui/markdown-render.js +0 -266
- package/dist/tui/multi-file-diff-approval.js +0 -375
- package/dist/tui/onboarding-wizard.js +0 -240
- package/dist/tui/permissions-picker.js +0 -86
- package/dist/tui/render.js +0 -160
- package/dist/tui/repl-render.js +0 -770
- package/dist/tui/repl-splash-art.js +0 -64
- package/dist/tui/repl-splash-mascot.js +0 -154
- package/dist/tui/repl-splash.js +0 -117
- package/dist/tui/repl.js +0 -378
- package/dist/tui/slash-palette.js +0 -106
- package/dist/tui/splash-data.js +0 -61
- package/dist/tui/splash.js +0 -31
- package/dist/tui/status-bar.js +0 -209
- package/dist/tui/status-table.js +0 -7
- package/dist/tui/stickers-art.js +0 -136
- package/dist/tui/style-table.js +0 -28
- package/dist/tui/theme-table.js +0 -29
- package/dist/tui/thinking-spinner.js +0 -123
- package/dist/tui/tool-stream-pane.js +0 -140
- package/dist/tui/update-banner.js +0 -33
- package/dist/tui/vim-input.js +0 -267
- package/dist/tui/welcome-banner.js +0 -107
- package/dist/tui/welcome-data.js +0 -293
- package/dist/tui/workspace-context.js +0 -105
- package/docs/examples/codegraph.mcp.json +0 -10
- package/test/scenarios/codegen-create-file.scenario.txt +0 -13
- package/test/scenarios/compact-force.scenario.txt +0 -12
- package/test/scenarios/identity.scenario.txt +0 -11
- package/test/scenarios/persona-handoff.scenario.txt +0 -12
- package/test/scenarios/walkback.scenario.txt +0 -12
package/dist/core/hooks/index.js
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Public surface of the MVP hooks module ().
|
|
3
|
-
*
|
|
4
|
-
* Re-exports the registry, runner, and event types so callers can do
|
|
5
|
-
*
|
|
6
|
-
* import { loadHooksConfig, fireHooks } from '../core/hooks/index.js';
|
|
7
|
-
*
|
|
8
|
-
* without reaching into individual files. See `events.ts` for the
|
|
9
|
-
* scope note explaining why this MVP module co-exists with the older
|
|
10
|
-
* `src/core/hooks.ts` surface.
|
|
11
|
-
*/
|
|
12
|
-
export { DEFAULT_HOOK_TIMEOUT_MS, HooksConfig, MAX_HOOK_TIMEOUT_MS, defaultHooksMvpPath, isToolEvent, loadHooksConfig, matchesTool, } from './registry.js';
|
|
13
|
-
export { fireHooks } from './runner.js';
|
|
14
|
-
export { ALL_HOOK_EVENTS_V2, MVP_HOOK_EVENTS, } from './events.js';
|
|
15
|
-
//# sourceMappingURL=index.js.map
|
|
@@ -1,216 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Pugi hooks MVP — registry (, first pass).
|
|
3
|
-
*
|
|
4
|
-
* Reads `<home>/hooks-mvp.json` and validates its shape with Zod. The
|
|
5
|
-
* file uses the the upstream tool-style nested config:
|
|
6
|
-
*
|
|
7
|
-
* {
|
|
8
|
-
* "hooks": {
|
|
9
|
-
* "SessionStart": [{ "command": "echo session-start" }],
|
|
10
|
-
* "PreToolUse": [{ "matcher": "bash", "command": "echo bash-pre", "blocking": true }]
|
|
11
|
-
* }
|
|
12
|
-
* }
|
|
13
|
-
*
|
|
14
|
-
* Schema constraints:
|
|
15
|
-
* - Each hook entry MUST have a `command` (non-empty string).
|
|
16
|
-
* - `matcher` is optional. Defaults to `*` (any tool / any payload).
|
|
17
|
-
* For tool events, `matcher` is compared against the tool name.
|
|
18
|
-
* For non-tool events (SessionStart), `matcher` is ignored.
|
|
19
|
-
* - `timeoutMs` is optional. Defaults to 30 000 ms (per task spec).
|
|
20
|
-
* Capped at 60 000 ms to prevent operator-defined deadlocks.
|
|
21
|
-
* - `blocking` is optional. When true AND the hook exits non-zero,
|
|
22
|
-
* the registry surfaces an `anyBlocked: true` outcome so the
|
|
23
|
-
* caller can refuse the originating action. Only honoured for
|
|
24
|
-
* `PreToolUse` in the MVP — other events log but do not block.
|
|
25
|
-
*
|
|
26
|
-
* Failure modes:
|
|
27
|
-
* - File missing -> the registry is `empty()`. `list()` returns []
|
|
28
|
-
* and `fire()` is a no-op. This matches the the upstream tool default
|
|
29
|
-
* (hooks are opt-in).
|
|
30
|
-
* - File present but invalid JSON / fails schema -> `load()` throws.
|
|
31
|
-
* The CLI surface (`pugi hooks doctor`) reports the error
|
|
32
|
-
* verbatim so the operator can fix the config.
|
|
33
|
-
*
|
|
34
|
-
* Brand voice: ASCII only, no emoji, no em-dashes.
|
|
35
|
-
*/
|
|
36
|
-
import { existsSync, readFileSync } from 'node:fs';
|
|
37
|
-
import { homedir } from 'node:os';
|
|
38
|
-
import { resolve } from 'node:path';
|
|
39
|
-
import { z } from 'zod';
|
|
40
|
-
import { ALL_HOOK_EVENTS_V2 } from './events.js';
|
|
41
|
-
/** Default per-hook timeout when the operator does not set `timeoutMs`. */
|
|
42
|
-
export const DEFAULT_HOOK_TIMEOUT_MS = 30_000;
|
|
43
|
-
/** Hard upper bound on `timeoutMs`. Prevents config-defined deadlocks. */
|
|
44
|
-
export const MAX_HOOK_TIMEOUT_MS = 60_000;
|
|
45
|
-
const hookEntrySchema = z
|
|
46
|
-
.object({
|
|
47
|
-
/**
|
|
48
|
-
* Tool-name matcher. `*` matches any tool. Plain strings match
|
|
49
|
-
* exactly (no glob in the MVP — fast-follow widens to glob). Ignored
|
|
50
|
-
* for non-tool events such as `SessionStart`.
|
|
51
|
-
*/
|
|
52
|
-
matcher: z.string().min(1).optional(),
|
|
53
|
-
/** Shell command. Spawned via `/bin/sh -c <command>`. */
|
|
54
|
-
command: z.string().min(1),
|
|
55
|
-
/** Per-hook timeout override. Defaults to 30 000 ms. */
|
|
56
|
-
timeoutMs: z.number().int().positive().max(MAX_HOOK_TIMEOUT_MS).optional(),
|
|
57
|
-
/**
|
|
58
|
-
* When true, a non-zero exit code from this hook blocks the
|
|
59
|
-
* originating action (currently `PreToolUse` only). Other events
|
|
60
|
-
* log the exit but do not block.
|
|
61
|
-
*/
|
|
62
|
-
blocking: z.boolean().optional(),
|
|
63
|
-
})
|
|
64
|
-
.strict();
|
|
65
|
-
const hookEventEnum = z.enum([
|
|
66
|
-
'SessionStart',
|
|
67
|
-
'PreToolUse',
|
|
68
|
-
'PostToolUse',
|
|
69
|
-
'UserPromptSubmit',
|
|
70
|
-
'Stop',
|
|
71
|
-
'SubagentStop',
|
|
72
|
-
'PreCompact',
|
|
73
|
-
'Notification',
|
|
74
|
-
// PUGI-487 - user-facing worktree lifecycle events.
|
|
75
|
-
'WorktreeCreate',
|
|
76
|
-
'WorktreeRemove',
|
|
77
|
-
]);
|
|
78
|
-
const hooksFileSchema = z
|
|
79
|
-
.object({
|
|
80
|
-
hooks: z.record(hookEventEnum, z.array(hookEntrySchema)).default({}),
|
|
81
|
-
})
|
|
82
|
-
.strict();
|
|
83
|
-
/** Default config file location — `~/.pugi/hooks-mvp.json`. */
|
|
84
|
-
export function defaultHooksMvpPath(home) {
|
|
85
|
-
const root = home ?? process.env.PUGI_HOME ?? resolve(homedir(), '.pugi');
|
|
86
|
-
return resolve(root, 'hooks-mvp.json');
|
|
87
|
-
}
|
|
88
|
-
/**
|
|
89
|
-
* In-memory snapshot of the operator's `hooks-mvp.json`. Construct
|
|
90
|
-
* via `loadHooksConfig(path)` — `new HooksConfig()` is intentionally
|
|
91
|
-
* not exported so all production code paths go through the loader.
|
|
92
|
-
*/
|
|
93
|
-
export class HooksConfig {
|
|
94
|
-
path;
|
|
95
|
-
entries;
|
|
96
|
-
constructor(path, entries) {
|
|
97
|
-
this.path = path;
|
|
98
|
-
this.entries = entries;
|
|
99
|
-
}
|
|
100
|
-
/** Absolute path of the config file this snapshot was loaded from. */
|
|
101
|
-
configPath() {
|
|
102
|
-
return this.path;
|
|
103
|
-
}
|
|
104
|
-
/** All hooks declared for a given event. Returns [] when none. */
|
|
105
|
-
list(event) {
|
|
106
|
-
return this.entries[event] ?? [];
|
|
107
|
-
}
|
|
108
|
-
/**
|
|
109
|
-
* Hooks that match the (event, toolName?) tuple. For tool events
|
|
110
|
-
* (`PreToolUse`), `matcher` is compared against the tool name with
|
|
111
|
-
* `*` matching any. For non-tool events, all entries are returned
|
|
112
|
-
* regardless of `matcher`.
|
|
113
|
-
*/
|
|
114
|
-
listMatching(event, toolName) {
|
|
115
|
-
const all = this.list(event);
|
|
116
|
-
if (!isToolEvent(event))
|
|
117
|
-
return all;
|
|
118
|
-
return all.filter((entry) => matchesTool(entry.matcher, toolName));
|
|
119
|
-
}
|
|
120
|
-
/** Flat list of (event, entry) pairs across every configured event. */
|
|
121
|
-
flatten() {
|
|
122
|
-
const out = [];
|
|
123
|
-
for (const event of ALL_HOOK_EVENTS_V2) {
|
|
124
|
-
for (const entry of this.list(event)) {
|
|
125
|
-
out.push({ event, entry });
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
return out;
|
|
129
|
-
}
|
|
130
|
-
/** True iff at least one hook is registered for any event. */
|
|
131
|
-
isEmpty() {
|
|
132
|
-
return this.flatten().length === 0;
|
|
133
|
-
}
|
|
134
|
-
/** A no-op snapshot used when the config file is absent. */
|
|
135
|
-
static empty(path) {
|
|
136
|
-
return new HooksConfig(path, {});
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
/**
|
|
140
|
-
* Load + validate `hooks-mvp.json`. Returns a no-op snapshot when the
|
|
141
|
-
* file is absent. Throws on invalid JSON or schema violations — the
|
|
142
|
-
* caller is expected to surface the error to the operator via
|
|
143
|
-
* `pugi hooks doctor`.
|
|
144
|
-
*
|
|
145
|
-
* Contract (non-null invariant): this function ALWAYS returns a
|
|
146
|
-
* `HooksConfig` instance. It never returns `null` / `undefined`. When
|
|
147
|
-
* the config file is missing, callers receive `HooksConfig.empty(path)`
|
|
148
|
-
* — a truthy snapshot for which `isEmpty()` returns `true` and `list()`
|
|
149
|
-
* returns `[]`. Callers may safely chain `.isEmpty()` without a null
|
|
150
|
-
* guard. Asserted by `registry-empty.spec.ts`.
|
|
151
|
-
*/
|
|
152
|
-
export function loadHooksConfig(pathOverride) {
|
|
153
|
-
const path = pathOverride ?? defaultHooksMvpPath();
|
|
154
|
-
if (!existsSync(path)) {
|
|
155
|
-
return HooksConfig.empty(path);
|
|
156
|
-
}
|
|
157
|
-
let raw;
|
|
158
|
-
try {
|
|
159
|
-
raw = readFileSync(path, 'utf8');
|
|
160
|
-
}
|
|
161
|
-
catch (error) {
|
|
162
|
-
throw new Error(`pugi hooks: cannot read ${path}: ${error.message}`);
|
|
163
|
-
}
|
|
164
|
-
let parsed;
|
|
165
|
-
try {
|
|
166
|
-
parsed = JSON.parse(raw);
|
|
167
|
-
}
|
|
168
|
-
catch (error) {
|
|
169
|
-
throw new Error(`pugi hooks: ${path} is not valid JSON: ${error.message}`);
|
|
170
|
-
}
|
|
171
|
-
const result = hooksFileSchema.safeParse(parsed);
|
|
172
|
-
if (!result.success) {
|
|
173
|
-
const issues = result.error.issues
|
|
174
|
-
.map((issue) => `${issue.path.join('.') || '<root>'} ${issue.message}`)
|
|
175
|
-
.join('; ');
|
|
176
|
-
throw new Error(`pugi hooks: ${path} failed schema validation: ${issues}`);
|
|
177
|
-
}
|
|
178
|
-
// Zod's `z.record(enum, value)` returns `Partial<Record<...>>` shape
|
|
179
|
-
// — keys that the operator did not include are `undefined`. Coerce
|
|
180
|
-
// explicitly into the same shape `HooksConfig` expects.
|
|
181
|
-
const entries = {};
|
|
182
|
-
for (const event of ALL_HOOK_EVENTS_V2) {
|
|
183
|
-
const list = result.data.hooks[event];
|
|
184
|
-
if (list && list.length > 0) {
|
|
185
|
-
entries[event] = list;
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
return new HooksConfig(path, entries);
|
|
189
|
-
}
|
|
190
|
-
/**
|
|
191
|
-
* `isToolEvent(event)` -> true for events where `matcher` is compared
|
|
192
|
-
* against the tool name. SessionStart / Stop / Notification / etc. do
|
|
193
|
-
* not have an associated tool so matcher is ignored.
|
|
194
|
-
*/
|
|
195
|
-
export function isToolEvent(event) {
|
|
196
|
-
return event === 'PreToolUse' || event === 'PostToolUse';
|
|
197
|
-
}
|
|
198
|
-
/**
|
|
199
|
-
* Tool-name match grammar for the MVP. Intentionally narrow:
|
|
200
|
-
* - matcher missing or `*` -> matches any tool name (and the
|
|
201
|
-
* `bash`/`read`/... shape).
|
|
202
|
-
* - matcher === toolName -> exact match.
|
|
203
|
-
*
|
|
204
|
-
* Fast-follow widens this to glob via `picomatch` so operators can
|
|
205
|
-
* write `mcp__*` patterns. Deliberately not pulling in a glob lib for
|
|
206
|
-
* the MVP — the narrow grammar is enough to land the surface and the
|
|
207
|
-
* test matrix stays small.
|
|
208
|
-
*/
|
|
209
|
-
export function matchesTool(matcher, toolName) {
|
|
210
|
-
if (!matcher || matcher === '*')
|
|
211
|
-
return true;
|
|
212
|
-
if (!toolName)
|
|
213
|
-
return false;
|
|
214
|
-
return matcher === toolName;
|
|
215
|
-
}
|
|
216
|
-
//# sourceMappingURL=registry.js.map
|
|
@@ -1,236 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Pugi hooks MVP — runner (, first pass).
|
|
3
|
-
*
|
|
4
|
-
* Spawns the shell command declared in `hooks-mvp.json`, applies the
|
|
5
|
-
* timeout watchdog, captures stdout / stderr, and surfaces a
|
|
6
|
-
* structured result. Two events are wired in the MVP (SessionStart,
|
|
7
|
-
* PreToolUse); the runner itself is event-agnostic so the fast-follow
|
|
8
|
-
* PR can attach the remaining 6 events without changing this file.
|
|
9
|
-
*
|
|
10
|
-
* Safety properties:
|
|
11
|
-
* - 30 s default timeout (per task spec); SIGTERM then SIGKILL with
|
|
12
|
-
* a 2 s grace window.
|
|
13
|
-
* - 1 MiB output cap per stream — a misbehaving hook (`yes`) cannot
|
|
14
|
-
* OOM the parent CLI by buffering unbounded data.
|
|
15
|
-
* - Spawn failures are caught + logged; the session never crashes
|
|
16
|
-
* because of a missing binary or a syntax error in the command.
|
|
17
|
-
* - Hook errors are atomic-appended to `<workspaceRoot>/.pugi/logs/
|
|
18
|
-
* hooks.log`. Multiple sessions can write concurrently without
|
|
19
|
-
* interleaving because `appendFileSync` opens with O_APPEND.
|
|
20
|
-
*
|
|
21
|
-
* Brand voice: ASCII only.
|
|
22
|
-
*/
|
|
23
|
-
import { spawn } from 'node:child_process';
|
|
24
|
-
import { appendFileSync, existsSync, mkdirSync } from 'node:fs';
|
|
25
|
-
import { resolve } from 'node:path';
|
|
26
|
-
import { DEFAULT_HOOK_TIMEOUT_MS, isToolEvent, } from './registry.js';
|
|
27
|
-
const HOOK_STREAM_CAP_BYTES = 1024 * 1024;
|
|
28
|
-
const SIGKILL_GRACE_MS = 2_000;
|
|
29
|
-
/**
|
|
30
|
-
* Fire every matching hook for `event` sequentially. Sequential (not
|
|
31
|
-
* parallel) is the intentional default — operators frequently chain
|
|
32
|
-
* `git add` -> `eslint --fix` style hooks that would race otherwise.
|
|
33
|
-
* Returns a `HookFireOutcome` with the per-invocation results.
|
|
34
|
-
*/
|
|
35
|
-
export async function fireHooks(opts) {
|
|
36
|
-
const { config, event, payload, toolName, workspaceRoot, env } = opts;
|
|
37
|
-
const matching = config.listMatching(event, toolName);
|
|
38
|
-
if (matching.length === 0) {
|
|
39
|
-
return { event, results: [], anyBlocked: false };
|
|
40
|
-
}
|
|
41
|
-
const logger = workspaceRoot ? new HookLogger(workspaceRoot) : undefined;
|
|
42
|
-
const results = [];
|
|
43
|
-
let anyBlocked = false;
|
|
44
|
-
for (const entry of matching) {
|
|
45
|
-
const timeoutMs = entry.timeoutMs ?? DEFAULT_HOOK_TIMEOUT_MS;
|
|
46
|
-
const result = await executeOne(entry.command, payload, timeoutMs, env);
|
|
47
|
-
// Blocking semantics only honored for PreToolUse in the MVP.
|
|
48
|
-
// Other events can declare `blocking: true` but the runner just
|
|
49
|
-
// logs that intent — it does NOT short-circuit. The fast-follow
|
|
50
|
-
// PR threads PostToolUse + UserPromptSubmit blocking through.
|
|
51
|
-
const blockable = entry.blocking === true && event === 'PreToolUse';
|
|
52
|
-
const blocked = blockable && !result.ok;
|
|
53
|
-
if (blocked) {
|
|
54
|
-
anyBlocked = true;
|
|
55
|
-
result.blocked = true;
|
|
56
|
-
result.blockSentinel = `HOOK_BLOCKED: ${truncate(entry.command, 80)} exited ${result.exitCode}`;
|
|
57
|
-
}
|
|
58
|
-
if (logger && !result.ok) {
|
|
59
|
-
logger.recordFailure(event, entry.command, result);
|
|
60
|
-
}
|
|
61
|
-
results.push(result);
|
|
62
|
-
}
|
|
63
|
-
return { event, results, anyBlocked };
|
|
64
|
-
}
|
|
65
|
-
async function executeOne(command, payload, timeoutMs, env) {
|
|
66
|
-
const startedAt = Date.now();
|
|
67
|
-
return new Promise((resolvePromise) => {
|
|
68
|
-
const payloadJson = JSON.stringify(payload);
|
|
69
|
-
const childEnv = {
|
|
70
|
-
...(env ?? process.env),
|
|
71
|
-
PUGI_HOOK_PAYLOAD: payloadJson,
|
|
72
|
-
PUGI_HOOK_EVENT: payload.event,
|
|
73
|
-
PUGI_HOOK_SESSION_ID: payload.sessionId,
|
|
74
|
-
};
|
|
75
|
-
const child = spawn('/bin/sh', ['-c', command], {
|
|
76
|
-
env: childEnv,
|
|
77
|
-
stdio: ['pipe', 'pipe', 'pipe'],
|
|
78
|
-
});
|
|
79
|
-
const state = {
|
|
80
|
-
stdout: '',
|
|
81
|
-
stderr: '',
|
|
82
|
-
killedForTimeout: false,
|
|
83
|
-
killedForStreamCap: false,
|
|
84
|
-
};
|
|
85
|
-
const escalateKill = () => {
|
|
86
|
-
if (state.sigKillTimer)
|
|
87
|
-
return;
|
|
88
|
-
state.sigKillTimer = setTimeout(() => {
|
|
89
|
-
if (!child.killed)
|
|
90
|
-
child.kill('SIGKILL');
|
|
91
|
-
}, SIGKILL_GRACE_MS);
|
|
92
|
-
if (state.sigKillTimer.unref)
|
|
93
|
-
state.sigKillTimer.unref();
|
|
94
|
-
};
|
|
95
|
-
const enforceStreamCap = () => {
|
|
96
|
-
if (state.killedForStreamCap)
|
|
97
|
-
return;
|
|
98
|
-
if (state.stdout.length + state.stderr.length <= HOOK_STREAM_CAP_BYTES)
|
|
99
|
-
return;
|
|
100
|
-
state.killedForStreamCap = true;
|
|
101
|
-
child.kill('SIGTERM');
|
|
102
|
-
escalateKill();
|
|
103
|
-
};
|
|
104
|
-
child.stdout?.on('data', (chunk) => {
|
|
105
|
-
if (state.killedForStreamCap)
|
|
106
|
-
return;
|
|
107
|
-
state.stdout += chunk.toString('utf8');
|
|
108
|
-
enforceStreamCap();
|
|
109
|
-
});
|
|
110
|
-
child.stderr?.on('data', (chunk) => {
|
|
111
|
-
if (state.killedForStreamCap)
|
|
112
|
-
return;
|
|
113
|
-
state.stderr += chunk.toString('utf8');
|
|
114
|
-
enforceStreamCap();
|
|
115
|
-
});
|
|
116
|
-
// Best-effort stdin payload — hook scripts that want to read it can
|
|
117
|
-
// (e.g. `jq .`); scripts that ignore stdin will EPIPE on our write
|
|
118
|
-
// which we swallow because the env var carries the same data.
|
|
119
|
-
if (child.stdin) {
|
|
120
|
-
child.stdin.on('error', () => {
|
|
121
|
-
// EPIPE is benign — see above.
|
|
122
|
-
});
|
|
123
|
-
child.stdin.end(payloadJson);
|
|
124
|
-
}
|
|
125
|
-
const timer = setTimeout(() => {
|
|
126
|
-
state.killedForTimeout = true;
|
|
127
|
-
child.kill('SIGTERM');
|
|
128
|
-
escalateKill();
|
|
129
|
-
}, timeoutMs);
|
|
130
|
-
if (timer.unref)
|
|
131
|
-
timer.unref();
|
|
132
|
-
child.on('error', (error) => {
|
|
133
|
-
clearTimeout(timer);
|
|
134
|
-
if (state.sigKillTimer)
|
|
135
|
-
clearTimeout(state.sigKillTimer);
|
|
136
|
-
resolvePromise({
|
|
137
|
-
command: truncate(command, 200),
|
|
138
|
-
exitCode: -1,
|
|
139
|
-
stdoutBytes: state.stdout.length,
|
|
140
|
-
stderrBytes: state.stderr.length,
|
|
141
|
-
elapsedMs: Date.now() - startedAt,
|
|
142
|
-
ok: false,
|
|
143
|
-
blocked: false,
|
|
144
|
-
timedOut: false,
|
|
145
|
-
// No blockSentinel here — spawn errors are not the same as
|
|
146
|
-
// blocking-failure semantics. The caller logs them generically.
|
|
147
|
-
});
|
|
148
|
-
});
|
|
149
|
-
child.on('close', (code, signal) => {
|
|
150
|
-
clearTimeout(timer);
|
|
151
|
-
if (state.sigKillTimer)
|
|
152
|
-
clearTimeout(state.sigKillTimer);
|
|
153
|
-
let exitCode;
|
|
154
|
-
if (code !== null) {
|
|
155
|
-
exitCode = code;
|
|
156
|
-
}
|
|
157
|
-
else if (signal === 'SIGTERM') {
|
|
158
|
-
exitCode = -15;
|
|
159
|
-
}
|
|
160
|
-
else if (signal === 'SIGKILL') {
|
|
161
|
-
exitCode = -9;
|
|
162
|
-
}
|
|
163
|
-
else {
|
|
164
|
-
exitCode = -1;
|
|
165
|
-
}
|
|
166
|
-
const ok = exitCode === 0 &&
|
|
167
|
-
!state.killedForTimeout &&
|
|
168
|
-
!state.killedForStreamCap;
|
|
169
|
-
resolvePromise({
|
|
170
|
-
command: truncate(command, 200),
|
|
171
|
-
exitCode,
|
|
172
|
-
stdoutBytes: state.stdout.length,
|
|
173
|
-
stderrBytes: state.stderr.length,
|
|
174
|
-
elapsedMs: Date.now() - startedAt,
|
|
175
|
-
ok,
|
|
176
|
-
blocked: false,
|
|
177
|
-
timedOut: state.killedForTimeout,
|
|
178
|
-
});
|
|
179
|
-
});
|
|
180
|
-
});
|
|
181
|
-
}
|
|
182
|
-
/**
|
|
183
|
-
* Append-only failure log at `<workspaceRoot>/.pugi/logs/hooks.log`.
|
|
184
|
-
* Each line is a JSON record so log scrapers can `jq` over it.
|
|
185
|
-
*/
|
|
186
|
-
class HookLogger {
|
|
187
|
-
path;
|
|
188
|
-
prepared = false;
|
|
189
|
-
constructor(workspaceRoot) {
|
|
190
|
-
this.path = resolve(workspaceRoot, '.pugi', 'logs', 'hooks.log');
|
|
191
|
-
}
|
|
192
|
-
recordFailure(event, command, result) {
|
|
193
|
-
this.prepareDir();
|
|
194
|
-
const line = JSON.stringify({
|
|
195
|
-
ts: new Date().toISOString(),
|
|
196
|
-
event,
|
|
197
|
-
command: truncate(command, 200),
|
|
198
|
-
exitCode: result.exitCode,
|
|
199
|
-
timedOut: result.timedOut,
|
|
200
|
-
elapsedMs: result.elapsedMs,
|
|
201
|
-
stdoutBytes: result.stdoutBytes,
|
|
202
|
-
stderrBytes: result.stderrBytes,
|
|
203
|
-
toolEvent: isToolEvent(event),
|
|
204
|
-
});
|
|
205
|
-
try {
|
|
206
|
-
appendFileSync(this.path, `${line}\n`, 'utf8');
|
|
207
|
-
}
|
|
208
|
-
catch {
|
|
209
|
-
// Logging is best-effort — the session must not crash when the
|
|
210
|
-
// disk is full or the directory is read-only. The runner has
|
|
211
|
-
// already returned the result; dropping the log line is the
|
|
212
|
-
// safe fallback.
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
prepareDir() {
|
|
216
|
-
if (this.prepared)
|
|
217
|
-
return;
|
|
218
|
-
const dir = resolve(this.path, '..');
|
|
219
|
-
if (!existsSync(dir)) {
|
|
220
|
-
try {
|
|
221
|
-
mkdirSync(dir, { recursive: true });
|
|
222
|
-
}
|
|
223
|
-
catch {
|
|
224
|
-
// ignored — appendFileSync will surface a fresh error on the
|
|
225
|
-
// write path, which we also swallow.
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
this.prepared = true;
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
function truncate(value, max) {
|
|
232
|
-
if (value.length <= max)
|
|
233
|
-
return value;
|
|
234
|
-
return `${value.slice(0, max - 3)}...`;
|
|
235
|
-
}
|
|
236
|
-
//# sourceMappingURL=runner.js.map
|
|
@@ -1,115 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Pugi hooks v2 — event emitter .
|
|
3
|
-
*
|
|
4
|
-
* High-level fire API. Resolves matching hooks for an event, optionally
|
|
5
|
-
* prompts for trust on first encounter, executes each in declaration
|
|
6
|
-
* order (global before project), aggregates results, and surfaces
|
|
7
|
-
* blocking decisions to the caller.
|
|
8
|
-
*
|
|
9
|
-
* Sequential (not parallel) execution is intentional: operators chain
|
|
10
|
-
* `git add` -> `eslint --fix` style hooks that would race otherwise.
|
|
11
|
-
* Parallel execution lands in Phase 2 as an opt-in field on the hook
|
|
12
|
-
* declaration.
|
|
13
|
-
*
|
|
14
|
-
* Brand voice: ASCII only.
|
|
15
|
-
*/
|
|
16
|
-
import { compileMatcher } from './matcher.js';
|
|
17
|
-
import { executeHook } from './executor.js';
|
|
18
|
-
import { ensureHookTrust } from './trust.js';
|
|
19
|
-
import { isToolEventV2 } from './executor.js';
|
|
20
|
-
/**
|
|
21
|
-
* Fire all hooks matching `event`. Returns aggregated outcome — caller
|
|
22
|
-
* inspects `anyBlocked` + `additionalContext` to short-circuit + inject
|
|
23
|
-
* into the next prompt.
|
|
24
|
-
*
|
|
25
|
-
* Untrusted hooks (state === 'denied') are skipped. Hooks pending
|
|
26
|
-
* trust + no prompt available are also skipped (safety default).
|
|
27
|
-
*/
|
|
28
|
-
export async function fireHookEventV2(opts) {
|
|
29
|
-
const { config, event } = opts;
|
|
30
|
-
if (config.isEmpty()) {
|
|
31
|
-
return { event, results: [], anyBlocked: false };
|
|
32
|
-
}
|
|
33
|
-
// Resolve matching hooks. For tool events, match against toolName;
|
|
34
|
-
// for non-tool events, match against ''. The matcher's `*` and
|
|
35
|
-
// alternation grammars compile to predicates.
|
|
36
|
-
const candidate = isToolEventV2(event) ? (opts.toolName ?? '') : '';
|
|
37
|
-
const matching = config.forEvent(event).filter((hook) => {
|
|
38
|
-
try {
|
|
39
|
-
return compileMatcher(hook.matcher)(candidate);
|
|
40
|
-
}
|
|
41
|
-
catch {
|
|
42
|
-
// A malformed matcher should NOT crash the fire. The loader
|
|
43
|
-
// already validates at config-load time; this branch covers
|
|
44
|
-
// hooks injected programmatically by buggy test code.
|
|
45
|
-
return false;
|
|
46
|
-
}
|
|
47
|
-
});
|
|
48
|
-
if (matching.length === 0) {
|
|
49
|
-
return { event, results: [], anyBlocked: false };
|
|
50
|
-
}
|
|
51
|
-
const payload = {
|
|
52
|
-
schema_version: 1,
|
|
53
|
-
session_id: opts.sessionId,
|
|
54
|
-
transcript_path: opts.transcriptPath,
|
|
55
|
-
cwd: opts.workspaceRoot,
|
|
56
|
-
hook_event_name: event,
|
|
57
|
-
permission_mode: opts.permissionMode,
|
|
58
|
-
...(opts.toolName !== undefined ? { tool_name: opts.toolName } : {}),
|
|
59
|
-
...(opts.toolInput !== undefined ? { tool_input: opts.toolInput } : {}),
|
|
60
|
-
...(opts.toolResult !== undefined ? { tool_result: opts.toolResult } : {}),
|
|
61
|
-
...(opts.toolError !== undefined ? { tool_error: opts.toolError } : {}),
|
|
62
|
-
...(opts.userPrompt !== undefined ? { user_prompt: opts.userPrompt } : {}),
|
|
63
|
-
agent_id: opts.agentId ?? null,
|
|
64
|
-
agent_type: opts.agentType ?? null,
|
|
65
|
-
};
|
|
66
|
-
const results = [];
|
|
67
|
-
let anyBlocked = false;
|
|
68
|
-
const contextParts = [];
|
|
69
|
-
for (const hook of matching) {
|
|
70
|
-
const command = hook.command ?? '';
|
|
71
|
-
const trustState = await ensureHookTrust({
|
|
72
|
-
workspaceRoot: opts.workspaceRoot,
|
|
73
|
-
command,
|
|
74
|
-
event,
|
|
75
|
-
...(hook.description !== undefined
|
|
76
|
-
? { description: hook.description }
|
|
77
|
-
: {}),
|
|
78
|
-
}, opts.promptFn, opts.trustHomeOverride);
|
|
79
|
-
if (trustState === 'denied') {
|
|
80
|
-
results.push({
|
|
81
|
-
hookCommand: command.slice(0, 200),
|
|
82
|
-
event,
|
|
83
|
-
exitCode: -1,
|
|
84
|
-
stdout: '',
|
|
85
|
-
stderr: 'pugi hooks v2: hook denied by trust ledger',
|
|
86
|
-
decision: { decision: 'allow' },
|
|
87
|
-
elapsedMs: 0,
|
|
88
|
-
timedOut: false,
|
|
89
|
-
blocked: false,
|
|
90
|
-
});
|
|
91
|
-
continue;
|
|
92
|
-
}
|
|
93
|
-
const result = await executeHook({
|
|
94
|
-
hook,
|
|
95
|
-
payload,
|
|
96
|
-
...(opts.env !== undefined ? { env: opts.env } : {}),
|
|
97
|
-
});
|
|
98
|
-
if (result.blocked) {
|
|
99
|
-
anyBlocked = true;
|
|
100
|
-
}
|
|
101
|
-
if (result.additionalContext) {
|
|
102
|
-
contextParts.push(result.additionalContext);
|
|
103
|
-
}
|
|
104
|
-
results.push(result);
|
|
105
|
-
}
|
|
106
|
-
return {
|
|
107
|
-
event,
|
|
108
|
-
results,
|
|
109
|
-
anyBlocked,
|
|
110
|
-
...(contextParts.length > 0
|
|
111
|
-
? { additionalContext: contextParts.join('\n\n') }
|
|
112
|
-
: {}),
|
|
113
|
-
};
|
|
114
|
-
}
|
|
115
|
-
//# sourceMappingURL=event-emitter.js.map
|