@pugi/cli 0.1.0-beta.8 → 0.1.0-beta.87
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 +96 -0
- package/THIRD_PARTY_NOTICES.md +40 -0
- package/assets/pugi-prozr2-mascot.ansi +9 -0
- package/bin/run.js +33 -1
- package/dist/commands/deploy.js +40 -40
- package/dist/commands/flatten.js +191 -0
- package/dist/commands/jobs-watch.js +201 -0
- package/dist/commands/jobs.js +42 -27
- package/dist/commands/smoke.js +133 -0
- package/dist/core/agent-progress/cleanup.js +134 -0
- package/dist/core/agent-progress/schema.js +144 -0
- package/dist/core/agent-progress/writer.js +101 -0
- package/dist/core/agents/adaptive-router.js +330 -0
- package/dist/core/agents/query-decomposer.js +297 -0
- package/dist/core/agents/registry.js +2 -2
- package/dist/core/approvals/shortcut-resolver.js +98 -0
- package/dist/core/artifact-chain/dispatcher.js +148 -0
- package/dist/core/artifact-chain/exporter.js +164 -0
- package/dist/core/artifact-chain/state.js +243 -0
- package/dist/core/artifact-chain/steps.js +169 -0
- package/dist/core/ask-user/question.js +92 -0
- package/dist/core/audit/audit-trail.js +275 -0
- package/dist/core/auth/ensure-authenticated.js +129 -0
- package/dist/core/auth/env-provider.js +238 -0
- package/dist/core/auto-open-browser.js +4 -4
- package/dist/core/auto-update/channels.js +122 -0
- package/dist/core/auto-update/checker.js +241 -0
- package/dist/core/auto-update/state.js +235 -0
- package/dist/core/bare-mode/index.js +107 -0
- package/dist/core/bash/redirect.js +281 -0
- package/dist/core/bash-classifier.js +436 -40
- package/dist/core/checkpoint/resumer.js +149 -0
- package/dist/core/checkpoint/rewinder.js +291 -0
- package/dist/core/checkpoints/shadow-git.js +670 -0
- package/dist/core/citations/parser.js +109 -0
- package/dist/core/classifier/yolo-classifier.js +88 -0
- package/dist/core/codegraph/decision-store.js +248 -0
- package/dist/core/codegraph/detect-repo.js +459 -0
- package/dist/core/codegraph/install.js +134 -0
- package/dist/core/codegraph/offer-hook.js +220 -0
- package/dist/core/compact/auto-trigger.js +96 -0
- package/dist/core/compact/buffer-rewriter.js +115 -0
- package/dist/core/compact/summarizer.js +208 -0
- package/dist/core/compact/token-counter.js +108 -0
- package/dist/core/consensus/anvil-fanout.js +25 -25
- package/dist/core/consensus/diff-capture.js +121 -12
- package/dist/core/consensus/rubric.js +21 -21
- package/dist/core/context/builder.js +6 -6
- package/dist/core/context/compaction-events.js +8 -8
- package/dist/core/context/compaction.js +31 -31
- package/dist/core/context/index.js +15 -8
- package/dist/core/context/invariants.js +51 -51
- package/dist/core/context/markdown-loader.js +28 -10
- package/dist/core/context/markdown-traverse.js +255 -0
- package/dist/core/context/pugiignore.js +41 -41
- package/dist/core/context/repo-skeleton.js +37 -37
- package/dist/core/context/tool-eviction.js +55 -0
- package/dist/core/context/watcher.js +32 -32
- package/dist/core/context/working-set.js +23 -23
- package/dist/core/coordinator/agent-tools.js +77 -0
- package/dist/core/coordinator/agent-toolset.js +65 -0
- package/dist/core/coordinator/fsm.js +73 -0
- package/dist/core/coordinator/mode-fsm.js +70 -0
- package/dist/core/cost/rate-card.js +129 -0
- package/dist/core/cost/tracker.js +221 -0
- package/dist/core/credentials.js +12 -12
- package/dist/core/cron/scheduler.js +138 -0
- package/dist/core/denial-tracking/index.js +8 -0
- package/dist/core/denial-tracking/state.js +264 -0
- package/dist/core/diagnostics/probe-runner.js +93 -0
- package/dist/core/diagnostics/probes/api.js +46 -0
- package/dist/core/diagnostics/probes/auth.js +93 -0
- package/dist/core/diagnostics/probes/bare-mode.js +42 -0
- package/dist/core/diagnostics/probes/cli-version.js +127 -0
- package/dist/core/diagnostics/probes/config.js +72 -0
- package/dist/core/diagnostics/probes/denial-tracking.js +57 -0
- package/dist/core/diagnostics/probes/disk.js +81 -0
- package/dist/core/diagnostics/probes/engine-live.js +46 -0
- package/dist/core/diagnostics/probes/git.js +65 -0
- package/dist/core/diagnostics/probes/hooks.js +118 -0
- package/dist/core/diagnostics/probes/mcp.js +75 -0
- package/dist/core/diagnostics/probes/node.js +59 -0
- package/dist/core/diagnostics/probes/pnpm.js +36 -0
- package/dist/core/diagnostics/probes/pugi-md.js +89 -0
- package/dist/core/diagnostics/probes/sandbox.js +40 -0
- package/dist/core/diagnostics/probes/session.js +74 -0
- package/dist/core/diagnostics/probes/status-snapshot.js +488 -0
- package/dist/core/diagnostics/probes/workspace.js +63 -0
- package/dist/core/diagnostics/types.js +70 -0
- package/dist/core/dispatch/cache-cleanup.js +197 -0
- package/dist/core/dispatch/cache-handoff.js +295 -0
- package/dist/core/edits/apply-patch-layer-e.js +189 -0
- package/dist/core/edits/dispatch.js +293 -7
- package/dist/core/edits/format-matrix.js +26 -0
- package/dist/core/edits/fuzzy-ladder.js +650 -0
- package/dist/core/edits/index.js +3 -1
- package/dist/core/edits/journal.js +199 -0
- package/dist/core/edits/layer-a-apply.js +15 -15
- package/dist/core/edits/layer-a-fuzzy-apply.js +198 -0
- package/dist/core/edits/layer-b-apply.js +9 -9
- package/dist/core/edits/layer-c-apply.js +6 -6
- package/dist/core/edits/layer-d-ast.js +557 -14
- package/dist/core/edits/marker-parser.js +12 -12
- package/dist/core/edits/security-gate.js +27 -27
- package/dist/core/edits/verify-hook.js +273 -0
- package/dist/core/edits/worktree.js +322 -0
- package/dist/core/engine/anvil-client.js +140 -26
- package/dist/core/engine/auto-compact.js +179 -0
- package/dist/core/engine/budgets.js +186 -0
- package/dist/core/engine/context-prefix.js +155 -0
- package/dist/core/engine/index.js +1 -1
- package/dist/core/engine/intensity.js +158 -0
- package/dist/core/engine/intent.js +260 -0
- package/dist/core/engine/native-pugi.js +1295 -227
- package/dist/core/engine/prompts.js +134 -16
- package/dist/core/engine/strip-internal-fields.js +124 -0
- package/dist/core/engine/tool-bridge.js +1295 -59
- package/dist/core/evaluation/golden-dataset.js +293 -0
- package/dist/core/feedback/queue.js +177 -0
- package/dist/core/feedback/submitter.js +145 -0
- package/dist/core/file-cache.js +113 -1
- package/dist/core/flatten/flatten-repo.js +439 -0
- package/dist/core/format/osc8-link.js +28 -0
- package/dist/core/hook-chains.js +392 -0
- package/dist/core/hooks/citation-verify-hook.js +138 -0
- package/dist/core/hooks/citation-verify.js +112 -0
- package/dist/core/hooks/events.js +44 -0
- package/dist/core/hooks/index.js +15 -0
- package/dist/core/hooks/registry.js +213 -0
- package/dist/core/hooks/runner.js +236 -0
- package/dist/core/hooks/v2/event-emitter.js +115 -0
- package/dist/core/hooks/v2/executor.js +282 -0
- package/dist/core/hooks/v2/index.js +25 -0
- package/dist/core/hooks/v2/lifecycle.js +104 -0
- package/dist/core/hooks/v2/loader.js +216 -0
- package/dist/core/hooks/v2/matcher.js +125 -0
- package/dist/core/hooks/v2/trust.js +143 -0
- package/dist/core/hooks/v2/types.js +86 -0
- package/dist/core/image/renderer.js +71 -0
- package/dist/core/init/detector.js +582 -0
- package/dist/core/init/template-renderer.js +242 -0
- package/dist/core/jobs/registry.js +18 -18
- package/dist/core/ledger/results-tsv.js +142 -0
- package/dist/core/log-discipline/stdout-redirect.js +51 -0
- package/dist/core/lsp/cache.js +105 -0
- package/dist/core/lsp/client.js +776 -0
- package/dist/core/lsp/language-detect.js +66 -0
- package/dist/core/lsp/post-edit-diagnostics.js +171 -0
- package/dist/core/lsp/symbol-tools.js +372 -0
- package/dist/core/mcp/client.js +97 -28
- package/dist/core/mcp/http-server.js +553 -0
- package/dist/core/mcp/orchestrator-tools.js +662 -0
- package/dist/core/mcp/permission.js +190 -0
- package/dist/core/mcp/registry.js +39 -17
- package/dist/core/mcp/server-tools.js +219 -0
- package/dist/core/mcp/server.js +397 -0
- package/dist/core/mcp/trust.js +10 -10
- package/dist/core/memory/dual-write.js +416 -0
- package/dist/core/memory/passive-extract.js +130 -0
- package/dist/core/memory/phase1-kinds.js +20 -0
- package/dist/core/memory/secret-scanner.js +304 -0
- package/dist/core/memory-sync/queue.js +170 -0
- package/dist/core/metrics/extract.js +113 -0
- package/dist/core/modes/roo-modes.js +68 -0
- package/dist/core/onboarding/ensure-initialized.js +133 -0
- package/dist/core/onboarding/marker.js +111 -0
- package/dist/core/onboarding/telemetry-state.js +108 -0
- package/dist/core/output-style/presets.js +176 -0
- package/dist/core/output-style/state.js +185 -0
- package/dist/core/path-security.js +287 -5
- package/dist/core/permission.js +82 -22
- package/dist/core/permissions/auto-classifier.js +124 -0
- package/dist/core/permissions/bash-parser.js +371 -0
- package/dist/core/permissions/circuit-breaker.js +83 -0
- package/dist/core/permissions/constrained-edit.js +91 -0
- package/dist/core/permissions/gate.js +278 -0
- package/dist/core/permissions/index.js +20 -0
- package/dist/core/permissions/mode.js +174 -0
- package/dist/core/permissions/network-egress.js +137 -0
- package/dist/core/permissions/state.js +241 -0
- package/dist/core/permissions/tool-class.js +93 -0
- package/dist/core/plan-mode/ui-state.js +51 -0
- package/dist/core/plans/plan-artifact.js +721 -0
- package/dist/core/policy-limits/etag-store.js +122 -0
- package/dist/core/prd-check/parser.js +215 -0
- package/dist/core/prd-check/reporter.js +127 -0
- package/dist/core/prd-check/session-review.js +557 -0
- package/dist/core/prd-check/verifiers.js +223 -0
- package/dist/core/prompt-cache/client-cache.js +99 -0
- package/dist/core/prompts/assembly.js +29 -0
- package/dist/core/prompts/registry.js +364 -0
- package/dist/core/pugi-md/cc-compat-rules.js +735 -0
- package/dist/core/pugi-md/context-injector.js +76 -0
- package/dist/core/pugi-md/walk-up.js +207 -0
- package/dist/core/python/uv-installer.js +270 -0
- package/dist/core/python/uv-resolver.js +83 -0
- package/dist/core/rate-limit/narrator.js +146 -0
- package/dist/core/recipes/cli-types.js +20 -0
- package/dist/core/recipes/loader.js +103 -0
- package/dist/core/recipes/runner.js +345 -0
- package/dist/core/recipes/schema.js +587 -0
- package/dist/core/release-notes/parser.js +241 -0
- package/dist/core/release-notes/state.js +116 -0
- package/dist/core/repl/ask.js +37 -37
- package/dist/core/repl/cancellation.js +26 -26
- package/dist/core/repl/cap-warning.js +4 -4
- package/dist/core/repl/clipboard-read.js +11 -11
- package/dist/core/repl/dispatch-fsm.js +12 -12
- package/dist/core/repl/history-search.js +15 -15
- package/dist/core/repl/history.js +28 -18
- package/dist/core/repl/kill-ring.js +5 -5
- package/dist/core/repl/model-pricing.js +135 -0
- package/dist/core/repl/privacy-banner.js +22 -22
- package/dist/core/repl/session.js +2157 -214
- package/dist/core/repl/slash-commands.js +533 -40
- package/dist/core/repl/store/index.js +1 -1
- package/dist/core/repl/store/jsonl-log.js +22 -22
- package/dist/core/repl/store/lockfile.js +10 -10
- package/dist/core/repl/store/session-store.js +136 -107
- package/dist/core/repl/store/types.js +15 -15
- package/dist/core/repl/store/uuid-v7.js +12 -12
- package/dist/core/repl/workspace-context.js +43 -21
- package/dist/core/repo-map/build.js +125 -0
- package/dist/core/repo-map/cache.js +185 -0
- package/dist/core/repo-map/extractor.js +254 -0
- package/dist/core/repo-map/formatter.js +145 -0
- package/dist/core/repo-map/page-rank.js +105 -0
- package/dist/core/repo-map/scanner.js +211 -0
- package/dist/core/retry-budget/budget.js +284 -0
- package/dist/core/retry-budget/index.js +5 -0
- package/dist/core/retry-budget/retry-cap.js +74 -0
- package/dist/core/routing/lead-worker.js +43 -0
- package/dist/core/routing/pre-flight-estimator.js +108 -0
- package/dist/core/runs/run-tree.js +103 -0
- package/dist/core/security/injection-scanner.js +367 -0
- package/dist/core/security/output-filter.js +418 -0
- package/dist/core/session/env-file.js +105 -0
- package/dist/core/session/section-budgets.js +140 -0
- package/dist/core/session.js +92 -0
- package/dist/core/settings.js +286 -5
- package/dist/core/share/formatter.js +271 -0
- package/dist/core/share/redactor.js +221 -0
- package/dist/core/share/uploader.js +267 -0
- package/dist/core/skills/defaults.js +457 -0
- package/dist/core/skills/loader.js +22 -22
- package/dist/core/skills/sources.js +27 -27
- package/dist/core/smoke/headless-driver.js +174 -0
- package/dist/core/smoke/orchestrator.js +194 -0
- package/dist/core/smoke/runner.js +238 -0
- package/dist/core/smoke/scenario-parser.js +316 -0
- package/dist/core/statusline.js +99 -0
- package/dist/core/subagents/dispatcher-real.js +600 -0
- package/dist/core/subagents/dispatcher.js +132 -43
- package/dist/core/subagents/index.js +19 -6
- package/dist/core/subagents/isolation-matrix.js +213 -0
- package/dist/core/subagents/spawn.js +19 -4
- package/dist/core/telemetry/emitter.js +229 -0
- package/dist/core/telemetry/queue.js +251 -0
- package/dist/core/theme/context.js +91 -0
- package/dist/core/theme/presets.js +228 -0
- package/dist/core/theme/state.js +181 -0
- package/dist/core/todos/invariant.js +10 -0
- package/dist/core/todos/state.js +177 -0
- package/dist/core/tool-schema/compressor.js +89 -0
- package/dist/core/transport/version-interceptor.js +166 -0
- package/dist/core/trust.js +2 -2
- package/dist/core/tui/thinking-block.js +64 -0
- package/dist/core/vim/keymap.js +288 -0
- package/dist/core/vim/state.js +92 -0
- package/dist/core/watch-markers/marker-watcher.js +133 -0
- package/dist/core/worktree-manager/cleanup.js +123 -0
- package/dist/core/worktree-manager/manager.js +303 -0
- package/dist/index.js +28 -0
- package/dist/runtime/bootstrap.js +190 -0
- package/dist/runtime/cli.js +4151 -489
- package/dist/runtime/commands/agents.js +30 -30
- package/dist/runtime/commands/budget.js +5 -5
- package/dist/runtime/commands/cancel.js +231 -0
- package/dist/runtime/commands/chain.js +489 -0
- package/dist/runtime/commands/codegraph-status.js +227 -0
- package/dist/runtime/commands/compact.js +297 -0
- package/dist/runtime/commands/config.js +32 -32
- package/dist/runtime/commands/cost.js +199 -0
- package/dist/runtime/commands/delegate.js +244 -13
- package/dist/runtime/commands/dispatch.js +126 -0
- package/dist/runtime/commands/doctor.js +579 -0
- package/dist/runtime/commands/feedback.js +184 -0
- package/dist/runtime/commands/hooks.js +184 -0
- package/dist/runtime/commands/init.js +254 -0
- package/dist/runtime/commands/lsp.js +368 -0
- package/dist/runtime/commands/mcp.js +879 -0
- package/dist/runtime/commands/memory.js +582 -0
- package/dist/runtime/commands/model.js +237 -0
- package/dist/runtime/commands/onboarding.js +275 -0
- package/dist/runtime/commands/patch.js +128 -0
- package/dist/runtime/commands/permissions.js +112 -0
- package/dist/runtime/commands/plan.js +143 -0
- package/dist/runtime/commands/prd-check.js +285 -0
- package/dist/runtime/commands/privacy.js +17 -17
- package/dist/runtime/commands/recipe.js +325 -0
- package/dist/runtime/commands/redo-blob-store.js +92 -0
- package/dist/runtime/commands/redo.js +361 -0
- package/dist/runtime/commands/release-notes.js +229 -0
- package/dist/runtime/commands/repo-map.js +95 -0
- package/dist/runtime/commands/report.js +299 -0
- package/dist/runtime/commands/resume.js +118 -0
- package/dist/runtime/commands/review-consensus.js +68 -53
- package/dist/runtime/commands/rewind.js +333 -0
- package/dist/runtime/commands/roster.js +14 -14
- package/dist/runtime/commands/sessions.js +163 -0
- package/dist/runtime/commands/share.js +316 -0
- package/dist/runtime/commands/skills.js +31 -31
- package/dist/runtime/commands/status.js +186 -0
- package/dist/runtime/commands/stickers.js +82 -0
- package/dist/runtime/commands/style.js +194 -0
- package/dist/runtime/commands/theme.js +196 -0
- package/dist/runtime/commands/undo.js +54 -22
- package/dist/runtime/commands/update.js +289 -0
- package/dist/runtime/commands/vim.js +140 -0
- package/dist/runtime/commands/worktree.js +177 -0
- package/dist/runtime/commands/worktrees.js +155 -0
- package/dist/runtime/headless-repl.js +195 -0
- package/dist/runtime/headless.js +543 -0
- package/dist/runtime/load-hooks-or-exit.js +71 -0
- package/dist/runtime/plan-decompose.js +531 -0
- package/dist/runtime/update-check.js +28 -28
- package/dist/runtime/version.js +65 -0
- package/dist/skills/bundled/batch.js +617 -0
- package/dist/skills/bundled/index.js +45 -0
- package/dist/skills/bundled/loop.js +358 -0
- package/dist/skills/bundled/remember.js +383 -0
- package/dist/skills/bundled/simplify.js +289 -0
- package/dist/skills/bundled/skillify.js +373 -0
- package/dist/skills/bundled/stuck.js +558 -0
- package/dist/skills/bundled/verify.js +439 -0
- package/dist/testing/vcr.js +486 -0
- package/dist/tools/agent-tool.js +229 -0
- package/dist/tools/apply-patch.js +556 -0
- package/dist/tools/ask-user-question.js +222 -0
- package/dist/tools/ask-user.js +115 -0
- package/dist/tools/bash.js +623 -45
- package/dist/tools/brief.js +224 -0
- package/dist/tools/enter-worktree.js +250 -0
- package/dist/tools/exit-worktree.js +147 -0
- package/dist/tools/file-tools.js +161 -44
- package/dist/tools/lsp-tools.js +189 -0
- package/dist/tools/mcp-tool.js +260 -0
- package/dist/tools/multi-edit.js +361 -0
- package/dist/tools/powershell.js +268 -0
- package/dist/tools/registry.js +85 -0
- package/dist/tools/skill-tool.js +96 -0
- package/dist/tools/sleep.js +99 -0
- package/dist/tools/synthetic-output.js +133 -0
- package/dist/tools/tasks.js +208 -0
- package/dist/tools/todo-write.js +184 -0
- package/dist/tools/verify-plan-execution.js +295 -0
- package/dist/tools/web-fetch-injection-scanner.js +207 -0
- package/dist/tools/web-fetch.js +195 -10
- package/dist/tools/web-search.js +458 -0
- package/dist/tui/agent-progress-card.js +111 -0
- package/dist/tui/agent-tree.js +11 -1
- package/dist/tui/ask-modal.js +14 -14
- package/dist/tui/ask-user-question-prompt.js +203 -0
- package/dist/tui/compact-banner.js +81 -0
- package/dist/tui/conversation-pane.js +85 -11
- package/dist/tui/cost-table.js +111 -0
- package/dist/tui/device-flow.js +2 -2
- package/dist/tui/doctor-table.js +46 -0
- package/dist/tui/feedback-prompt.js +156 -0
- package/dist/tui/input-box.js +247 -32
- package/dist/tui/login-picker.js +3 -3
- package/dist/tui/markdown-render.js +6 -6
- package/dist/tui/onboarding-wizard.js +240 -0
- package/dist/tui/permissions-picker.js +86 -0
- package/dist/tui/render.js +35 -0
- package/dist/tui/repl-render.js +332 -54
- package/dist/tui/repl-splash-art.js +16 -16
- package/dist/tui/repl-splash-mascot.js +48 -24
- package/dist/tui/repl-splash.js +22 -22
- package/dist/tui/repl.js +124 -44
- package/dist/tui/slash-palette.js +6 -6
- package/dist/tui/splash.js +2 -2
- package/dist/tui/status-bar.js +109 -31
- package/dist/tui/status-table.js +7 -0
- package/dist/tui/stickers-art.js +136 -0
- package/dist/tui/style-table.js +28 -0
- package/dist/tui/theme-table.js +29 -0
- package/dist/tui/thinking-spinner.js +123 -0
- package/dist/tui/tool-stream-pane.js +53 -4
- package/dist/tui/update-banner.js +27 -2
- package/dist/tui/vim-input.js +267 -0
- package/dist/tui/welcome-banner.js +107 -0
- package/dist/tui/welcome-data.js +293 -0
- package/dist/tui/workspace-context.js +2 -2
- package/docs/examples/codegraph.mcp.json +10 -0
- package/package.json +23 -6
- package/test/scenarios/codegen-create-file.scenario.txt +13 -0
- package/test/scenarios/compact-force.scenario.txt +11 -0
- package/test/scenarios/identity.scenario.txt +11 -0
- package/test/scenarios/persona-handoff.scenario.txt +11 -0
- package/test/scenarios/walkback.scenario.txt +12 -0
- package/dist/core/engine/compaction-hook.js +0 -154
|
@@ -12,29 +12,29 @@ import { validateHostnameForFetch } from '../../tools/web-fetch.js';
|
|
|
12
12
|
*
|
|
13
13
|
* Supported source schemes:
|
|
14
14
|
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
15
|
+
* 1. `gh:owner/repo[/subdir][@ref]`
|
|
16
|
+
* → `gh:anthropics/skills/python-coding-standards@main`
|
|
17
|
+
* Fetches the GitHub tarball via the public codeload endpoint,
|
|
18
|
+
* extracts the requested subtree.
|
|
19
19
|
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
20
|
+
* 2. `https://github.com/<owner>/<repo>/tree/<ref>/<subdir>` (or `/blob/`)
|
|
21
|
+
* Normalised to the gh: form above.
|
|
22
22
|
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
23
|
+
* 3. `anthropic:<slug>` — convenience alias for
|
|
24
|
+
* `gh:anthropics/skills/<slug>@main`. Hard-coded base; the only
|
|
25
|
+
* reason this exists is so operators can copy a slug from the
|
|
26
|
+
* Anthropic docs without remembering the org name.
|
|
27
27
|
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
28
|
+
* 4. `npm:<package>` — fetches a tarball from the npm registry,
|
|
29
|
+
* extracts, looks for `SKILL.md` at the package root.
|
|
30
30
|
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
31
|
+
* 5. Local path — `./relative` or `/abs/path`. Copied to tmp so the
|
|
32
|
+
* caller can mutate the original without affecting install.
|
|
33
33
|
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
34
|
+
* 6. Catalog name — bare slug, queried against
|
|
35
|
+
* `https://catalog.pugi.dev/api/skills/<name>`. Returns a 404 →
|
|
36
|
+
* we surface a hint pointing at the `gh:anthropics/skills/<name>`
|
|
37
|
+
* form rather than crashing.
|
|
38
38
|
*
|
|
39
39
|
* Every resolver writes the payload into a fresh temp dir under
|
|
40
40
|
* `/tmp/pugi-skill-XXXXXX/` (caller cleans up after install completes).
|
|
@@ -58,7 +58,7 @@ export async function fetchSource(source) {
|
|
|
58
58
|
throw new Error(`SOURCE_PARSE: anthropic: source needs a bare slug (got "${source}"). Example: anthropic:algorithmic-art`);
|
|
59
59
|
}
|
|
60
60
|
// Real layout is `anthropics/skills` repo → `skills/<slug>/SKILL.md`.
|
|
61
|
-
// Verified
|
|
61
|
+
// Verified against the live repo tarball.
|
|
62
62
|
return fetchGitHub(`${ANTHROPIC_REPO}/skills/${slug}@main`.slice(3));
|
|
63
63
|
}
|
|
64
64
|
if (source.startsWith('npm:')) {
|
|
@@ -113,7 +113,7 @@ async function fetchGitHub(raw) {
|
|
|
113
113
|
const spec = parseGithubSpec(raw);
|
|
114
114
|
// Use codeload.github.com — the public tarball endpoint requires no
|
|
115
115
|
// auth for public repos and returns a single .tar.gz of the requested
|
|
116
|
-
// ref's tree. Private repos are out of scope for
|
|
116
|
+
// ref's tree. Private repos are out of scope for .
|
|
117
117
|
const tarUrl = `https://codeload.github.com/${spec.owner}/${spec.repo}/tar.gz/${spec.ref}`;
|
|
118
118
|
const tmpRoot = mkdtempSync(join(tmpdir(), 'pugi-skill-gh-'));
|
|
119
119
|
const tarPath = join(tmpRoot, 'payload.tar.gz');
|
|
@@ -268,9 +268,9 @@ async function requestFollow(url) {
|
|
|
268
268
|
// future: webhook delivery). Drift between two copies of that block
|
|
269
269
|
// list would be a real footgun — the SSRF cheat-sheet covers ~10
|
|
270
270
|
// ranges and missing one (e.g. SIIT/NAT64) is exactly the class of
|
|
271
|
-
// bug Codex caught in PR
|
|
271
|
+
// bug Codex caught in PR.
|
|
272
272
|
// Initial scheme — locked for entire redirect chain. Codex P2 review
|
|
273
|
-
// (PR
|
|
273
|
+
// (PR v2): an HTTPS source that 302s к public http:// URL would
|
|
274
274
|
// otherwise be fetched cleartext, MITM tampers payload. Stay TLS.
|
|
275
275
|
const initialScheme = new URL(currentUrl).protocol;
|
|
276
276
|
await guardOutboundUrl(currentUrl, 'initial request', initialScheme);
|
|
@@ -321,7 +321,7 @@ async function guardOutboundUrl(rawUrl, label, initialScheme) {
|
|
|
321
321
|
if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {
|
|
322
322
|
throw new Error(`SOURCE_SSRF: ${label} uses unsupported scheme ${parsed.protocol} (only http/https).`);
|
|
323
323
|
}
|
|
324
|
-
// Codex P2 PR
|
|
324
|
+
// Codex P2 PR v2: HTTPS source MUST NOT downgrade к HTTP across
|
|
325
325
|
// redirect chain — would let MITM tamper с payload after the initial
|
|
326
326
|
// TLS hop. Once we started TLS, stay TLS.
|
|
327
327
|
if (initialScheme === 'https:' && parsed.protocol === 'http:') {
|
|
@@ -405,20 +405,20 @@ async function extractTarball(tarPath, destDir) {
|
|
|
405
405
|
// violations and throw AFTER extraction completes (see below).
|
|
406
406
|
filter: (path, entry) => {
|
|
407
407
|
// 1. Block any symlink or hardlink — these are the tar-slip
|
|
408
|
-
//
|
|
409
|
-
//
|
|
408
|
+
// vectors. A symlink to ../../home/user/.ssh + a follow-up
|
|
409
|
+
// write to that symlink would exfil secrets.
|
|
410
410
|
if (entry.type === 'SymbolicLink' || entry.type === 'Link') {
|
|
411
411
|
violations.push(`SOURCE_TAR_SYMLINK: tarball contains ${entry.type} entry (${path} → ${entry.linkpath ?? '?'}). Refusing extraction.`);
|
|
412
412
|
return false;
|
|
413
413
|
}
|
|
414
414
|
// 2. Block absolute paths — `tar` strips the leading "/" in
|
|
415
|
-
//
|
|
415
|
+
// permissive mode and writes anyway. We refuse such entries.
|
|
416
416
|
if (path.startsWith('/')) {
|
|
417
417
|
violations.push(`SOURCE_TAR_ABSOLUTE: tarball entry has absolute path: ${path}`);
|
|
418
418
|
return false;
|
|
419
419
|
}
|
|
420
420
|
// 3. Block parent-traversal segments. `..` as a path segment
|
|
421
|
-
//
|
|
421
|
+
// cannot be present in any legitimate skill/agent payload.
|
|
422
422
|
const segments = path.split(/[\\/]+/);
|
|
423
423
|
if (segments.includes('..')) {
|
|
424
424
|
violations.push(`SOURCE_TAR_TRAVERSAL: tarball entry has parent-traversal segment: ${path}`);
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Headless subprocess driver for the smoke harness (Phase 1).
|
|
3
|
+
*
|
|
4
|
+
* Spawns `pugi --headless`, feeds the scenario's user-input lines one
|
|
5
|
+
* at a time, and collects every JSON envelope written to stdout. The
|
|
6
|
+
* driver is the bridge between the in-process scenario parser and the
|
|
7
|
+
* real CLI binary — running scenarios via subprocess is what lets
|
|
8
|
+
* `pugi smoke` validate the AS-PUBLISHED CLI, not just the in-process
|
|
9
|
+
* code path.
|
|
10
|
+
*
|
|
11
|
+
* Phase 1 invariants:
|
|
12
|
+
*
|
|
13
|
+
* - One scenario = one subprocess. We do NOT reuse processes across
|
|
14
|
+
* scenarios; each run starts in a fresh temp workspace so file
|
|
15
|
+
* assertions are deterministic.
|
|
16
|
+
*
|
|
17
|
+
* - Stdin is fed line-by-line on a timer (default 200ms gap). We
|
|
18
|
+
* could fire all lines at once, but spacing them out gives the
|
|
19
|
+
* engine a chance to emit `persona-turn` envelopes between user
|
|
20
|
+
* turns. Mirrors real-operator typing cadence — feeds a more
|
|
21
|
+
* realistic test signal than a burst write.
|
|
22
|
+
*
|
|
23
|
+
* - Hard timeout per scenario (default 30s). The driver kills the
|
|
24
|
+
* subprocess on timeout and surfaces a clean executor-error so the
|
|
25
|
+
* report still shows the row instead of hanging CI.
|
|
26
|
+
*
|
|
27
|
+
* - Stderr is captured but NOT parsed. We forward it to the optional
|
|
28
|
+
* `onStderr` sink so the operator can see what the headless CLI
|
|
29
|
+
* wrote to stderr (banners, MCP load notices) — handy for
|
|
30
|
+
* debugging a failing scenario locally.
|
|
31
|
+
*/
|
|
32
|
+
import { spawn } from 'node:child_process';
|
|
33
|
+
import { mkdtempSync, rmSync } from 'node:fs';
|
|
34
|
+
import { tmpdir } from 'node:os';
|
|
35
|
+
import { resolve } from 'node:path';
|
|
36
|
+
/**
|
|
37
|
+
* Run a parsed scenario through the headless CLI. Returns the captured
|
|
38
|
+
* envelope stream + the workspace root the process ran in so the
|
|
39
|
+
* runner can resolve `EXPECT_FILE` paths.
|
|
40
|
+
*/
|
|
41
|
+
export async function runHeadlessScenario(scenario, opts = {}) {
|
|
42
|
+
const pugiBin = opts.pugiBin ?? 'pugi';
|
|
43
|
+
const extraArgs = opts.extraArgs ?? [];
|
|
44
|
+
const timeoutMs = opts.timeoutMs ?? 30_000;
|
|
45
|
+
const lineGapMs = opts.lineGapMs ?? 200;
|
|
46
|
+
const onStderr = opts.onStderr ?? noopChunk;
|
|
47
|
+
const spawner = opts.spawner ?? defaultSpawner;
|
|
48
|
+
const workspaceRoot = mkdtempSync(resolve(tmpdir(), 'pugi-smoke-'));
|
|
49
|
+
let cleanedUp = false;
|
|
50
|
+
const args = ['--headless', ...extraArgs];
|
|
51
|
+
const child = spawner(pugiBin, args, {
|
|
52
|
+
cwd: workspaceRoot,
|
|
53
|
+
env: { ...process.env, PUGI_HEADLESS: '1' },
|
|
54
|
+
});
|
|
55
|
+
const envelopes = [];
|
|
56
|
+
let stdoutBuffer = '';
|
|
57
|
+
child.stdout.setEncoding('utf8');
|
|
58
|
+
child.stdout.on('data', (chunk) => {
|
|
59
|
+
stdoutBuffer += chunk;
|
|
60
|
+
let newlineIndex = stdoutBuffer.indexOf('\n');
|
|
61
|
+
while (newlineIndex !== -1) {
|
|
62
|
+
const line = stdoutBuffer.slice(0, newlineIndex);
|
|
63
|
+
stdoutBuffer = stdoutBuffer.slice(newlineIndex + 1);
|
|
64
|
+
const parsed = parseEnvelopeLine(line);
|
|
65
|
+
if (parsed)
|
|
66
|
+
envelopes.push(parsed);
|
|
67
|
+
newlineIndex = stdoutBuffer.indexOf('\n');
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
child.stderr.setEncoding('utf8');
|
|
71
|
+
child.stderr.on('data', (chunk) => onStderr(chunk));
|
|
72
|
+
const userInputs = scenario.steps
|
|
73
|
+
.filter((s) => s.kind === 'user-input')
|
|
74
|
+
.map((s) => s.body);
|
|
75
|
+
// Feed inputs serially with a small gap. We don't await the engine's
|
|
76
|
+
// response — Phase 1 evaluates the WHOLE envelope stream after the
|
|
77
|
+
// process closes, so the gap is purely to give the engine room to
|
|
78
|
+
// emit between turns. A future phase can swap this for a barrier
|
|
79
|
+
// ("wait for `persona-turn` before sending the next `user-turn`")
|
|
80
|
+
// once envelope ordering is sealed.
|
|
81
|
+
const feedPromise = (async () => {
|
|
82
|
+
for (const line of userInputs) {
|
|
83
|
+
child.stdin.write(`${line}\n`);
|
|
84
|
+
await delay(lineGapMs);
|
|
85
|
+
}
|
|
86
|
+
child.stdin.end();
|
|
87
|
+
})();
|
|
88
|
+
const timeoutHandle = setTimeout(() => {
|
|
89
|
+
child.kill('SIGTERM');
|
|
90
|
+
}, timeoutMs);
|
|
91
|
+
// Don't keep node alive purely for the timeout — the spawned child
|
|
92
|
+
// already holds the loop via its IPC pipe.
|
|
93
|
+
timeoutHandle.unref?.();
|
|
94
|
+
await new Promise((resolvePromise) => {
|
|
95
|
+
child.on('close', () => resolvePromise());
|
|
96
|
+
});
|
|
97
|
+
clearTimeout(timeoutHandle);
|
|
98
|
+
// Flush any tail bytes that did not end with a newline.
|
|
99
|
+
if (stdoutBuffer.length > 0) {
|
|
100
|
+
const parsed = parseEnvelopeLine(stdoutBuffer);
|
|
101
|
+
if (parsed)
|
|
102
|
+
envelopes.push(parsed);
|
|
103
|
+
stdoutBuffer = '';
|
|
104
|
+
}
|
|
105
|
+
await feedPromise.catch(() => {
|
|
106
|
+
/* feed promise rejects when the child closes early — ignore */
|
|
107
|
+
});
|
|
108
|
+
// Cleanup the temp workspace lazily — the orchestrator may want to
|
|
109
|
+
// inspect it after the run. Callers that need a fresh dir per scenario
|
|
110
|
+
// should pass a custom workspaceRoot in a future phase; for now the
|
|
111
|
+
// runner resolves EXPECT_FILE paths against this directory and the
|
|
112
|
+
// OS reaps the tmp tree on reboot.
|
|
113
|
+
// (Explicit cleanup helper exposed for tests that want determinism.)
|
|
114
|
+
void cleanedUp;
|
|
115
|
+
return { envelopes, workspaceRoot };
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Tear down a workspace created by `runHeadlessScenario`. Exposed
|
|
119
|
+
* separately because the orchestrator wants the directory to survive
|
|
120
|
+
* the run for EXPECT_FILE evaluation.
|
|
121
|
+
*/
|
|
122
|
+
export function cleanupWorkspace(workspaceRoot) {
|
|
123
|
+
try {
|
|
124
|
+
rmSync(workspaceRoot, { recursive: true, force: true });
|
|
125
|
+
}
|
|
126
|
+
catch {
|
|
127
|
+
/* best-effort */
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Parse one line of headless stdout into an envelope. Returns null
|
|
132
|
+
* when the line is empty or unparseable — non-fatal so the runner can
|
|
133
|
+
* tolerate stray banner output.
|
|
134
|
+
*/
|
|
135
|
+
export function parseEnvelopeLine(raw) {
|
|
136
|
+
const line = raw.trim();
|
|
137
|
+
if (line.length === 0)
|
|
138
|
+
return null;
|
|
139
|
+
if (!line.startsWith('{'))
|
|
140
|
+
return null;
|
|
141
|
+
try {
|
|
142
|
+
const parsed = JSON.parse(line);
|
|
143
|
+
if (typeof parsed['kind'] !== 'string')
|
|
144
|
+
return null;
|
|
145
|
+
if (typeof parsed['body'] !== 'string')
|
|
146
|
+
return null;
|
|
147
|
+
const ts = typeof parsed['ts'] === 'number'
|
|
148
|
+
? parsed['ts']
|
|
149
|
+
: Number(parsed['ts'] ?? Date.now());
|
|
150
|
+
return {
|
|
151
|
+
kind: parsed['kind'],
|
|
152
|
+
body: parsed['body'],
|
|
153
|
+
ts: Number.isFinite(ts) ? ts : Date.now(),
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
catch {
|
|
157
|
+
return null;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
function defaultSpawner(bin, args, options) {
|
|
161
|
+
return spawn(bin, args, {
|
|
162
|
+
cwd: options.cwd,
|
|
163
|
+
env: options.env,
|
|
164
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
function delay(ms) {
|
|
168
|
+
return new Promise((resolve) => {
|
|
169
|
+
const handle = setTimeout(resolve, ms);
|
|
170
|
+
handle.unref?.();
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
function noopChunk(_chunk) { }
|
|
174
|
+
//# sourceMappingURL=headless-driver.js.map
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Smoke orchestrator — glues the scenario parser, the headless
|
|
3
|
+
* subprocess driver, and the runner into a single "load → run → report"
|
|
4
|
+
* pipeline. The CLI surface (`pugi smoke`) and the standalone script
|
|
5
|
+
* (`scripts/run-scenarios.ts`) both call into this module so the two
|
|
6
|
+
* entry points share one code path.
|
|
7
|
+
*
|
|
8
|
+
* Phase 1 boundary — `runSmoke` is responsible for:
|
|
9
|
+
*
|
|
10
|
+
* 1. Discovering scenario files under `scenariosDir` (glob match on
|
|
11
|
+
* `*.scenario.txt`).
|
|
12
|
+
* 2. Parsing each file via `parseScenario`. Parse errors are surfaced
|
|
13
|
+
* via the report but do not stop the run — every scenario gets a
|
|
14
|
+
* chance to fail with a clean diagnostic.
|
|
15
|
+
* 3. Driving each scenario through the headless executor (the
|
|
16
|
+
* executor is injected so tests can swap it for a deterministic
|
|
17
|
+
* stub; production wires `runHeadlessScenario` from
|
|
18
|
+
* `headless-driver.ts`).
|
|
19
|
+
* 4. Filtering by `--filter <pattern>` (compiles to fnmatch-lite).
|
|
20
|
+
* 5. Computing pass/fail/summary numbers.
|
|
21
|
+
*
|
|
22
|
+
* The orchestrator is intentionally synchronous (apart from the
|
|
23
|
+
* per-scenario `await`) — running scenarios in parallel is a Phase 2
|
|
24
|
+
* concern. The corpus is small and sequential output is easier to read.
|
|
25
|
+
*/
|
|
26
|
+
import { readdirSync, readFileSync, statSync } from 'node:fs';
|
|
27
|
+
import { resolve } from 'node:path';
|
|
28
|
+
import { parseScenario, } from './scenario-parser.js';
|
|
29
|
+
import { runScenario, } from './runner.js';
|
|
30
|
+
/**
|
|
31
|
+
* Top-level smoke entry. Returns the report so the CLI can pretty-print
|
|
32
|
+
* it AND set `process.exitCode` deterministically.
|
|
33
|
+
*/
|
|
34
|
+
export async function runSmoke(opts) {
|
|
35
|
+
const log = opts.log ?? noopLog;
|
|
36
|
+
const now = opts.now ?? Date.now;
|
|
37
|
+
const allScenarios = loadScenariosFromDir(opts.scenariosDir);
|
|
38
|
+
const visible = opts.filter && opts.filter.length > 0
|
|
39
|
+
? filterByPattern(allScenarios, opts.filter)
|
|
40
|
+
: allScenarios;
|
|
41
|
+
const results = [];
|
|
42
|
+
let passed = 0;
|
|
43
|
+
let failed = 0;
|
|
44
|
+
for (const item of visible) {
|
|
45
|
+
log(`pugi smoke: running ${item.scenario.id}`);
|
|
46
|
+
if (item.parseErrors.length > 0) {
|
|
47
|
+
results.push({
|
|
48
|
+
id: item.scenario.id,
|
|
49
|
+
filePath: item.scenario.filePath,
|
|
50
|
+
status: 'parse-error',
|
|
51
|
+
durationMs: 0,
|
|
52
|
+
assertionCount: 0,
|
|
53
|
+
failures: [],
|
|
54
|
+
parseErrors: item.parseErrors,
|
|
55
|
+
});
|
|
56
|
+
failed += 1;
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
let envelopes = [];
|
|
60
|
+
let workspaceRoot = '.';
|
|
61
|
+
try {
|
|
62
|
+
const out = await opts.executor(item.scenario);
|
|
63
|
+
envelopes = out.envelopes;
|
|
64
|
+
workspaceRoot = out.workspaceRoot;
|
|
65
|
+
}
|
|
66
|
+
catch (error) {
|
|
67
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
68
|
+
results.push({
|
|
69
|
+
id: item.scenario.id,
|
|
70
|
+
filePath: item.scenario.filePath,
|
|
71
|
+
status: 'executor-error',
|
|
72
|
+
durationMs: 0,
|
|
73
|
+
assertionCount: 0,
|
|
74
|
+
failures: [],
|
|
75
|
+
executorError: message,
|
|
76
|
+
});
|
|
77
|
+
failed += 1;
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
const result = runScenario({
|
|
81
|
+
scenario: item.scenario,
|
|
82
|
+
envelopes,
|
|
83
|
+
workspaceRoot,
|
|
84
|
+
now,
|
|
85
|
+
});
|
|
86
|
+
results.push({
|
|
87
|
+
id: result.id,
|
|
88
|
+
filePath: item.scenario.filePath,
|
|
89
|
+
status: result.passed ? 'passed' : 'failed',
|
|
90
|
+
durationMs: result.durationMs,
|
|
91
|
+
assertionCount: result.assertionCount,
|
|
92
|
+
failures: result.failures,
|
|
93
|
+
});
|
|
94
|
+
if (result.passed)
|
|
95
|
+
passed += 1;
|
|
96
|
+
else
|
|
97
|
+
failed += 1;
|
|
98
|
+
}
|
|
99
|
+
const total = visible.length;
|
|
100
|
+
const skipped = allScenarios.length - visible.length;
|
|
101
|
+
const exitCode = failed === 0 ? 0 : 1;
|
|
102
|
+
return { total, passed, failed, skipped, results, exitCode };
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Walk `dir` for `*.scenario.txt` files (non-recursive). Returns each
|
|
106
|
+
* file's parsed scenario + collected parse errors so the orchestrator
|
|
107
|
+
* can surface malformed files as failed runs rather than skipping them.
|
|
108
|
+
*/
|
|
109
|
+
export function loadScenariosFromDir(dir) {
|
|
110
|
+
let names = [];
|
|
111
|
+
try {
|
|
112
|
+
names = readdirSync(dir);
|
|
113
|
+
}
|
|
114
|
+
catch {
|
|
115
|
+
return [];
|
|
116
|
+
}
|
|
117
|
+
const out = [];
|
|
118
|
+
for (const name of names) {
|
|
119
|
+
if (!name.endsWith('.scenario.txt'))
|
|
120
|
+
continue;
|
|
121
|
+
const filePath = resolve(dir, name);
|
|
122
|
+
let stat;
|
|
123
|
+
try {
|
|
124
|
+
stat = statSync(filePath);
|
|
125
|
+
}
|
|
126
|
+
catch {
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
if (!stat.isFile())
|
|
130
|
+
continue;
|
|
131
|
+
const body = readFileSync(filePath, 'utf8');
|
|
132
|
+
const parsed = parseScenario(filePath, body);
|
|
133
|
+
if (parsed.scenario) {
|
|
134
|
+
out.push({ scenario: parsed.scenario, parseErrors: parsed.errors });
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
// Stable sort by id so report output is deterministic across
|
|
138
|
+
// filesystems with different readdir order.
|
|
139
|
+
out.sort((a, b) => a.scenario.id.localeCompare(b.scenario.id));
|
|
140
|
+
return out;
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Render a SmokeReport into a multi-line human-readable string. Kept
|
|
144
|
+
* separate from `runSmoke` so the CLI can pick its own format (text vs
|
|
145
|
+
* JSON). The default text format mirrors `node:test`'s tap-lite output:
|
|
146
|
+
*
|
|
147
|
+
* ok 1 - identity (12ms)
|
|
148
|
+
* not ok 2 - codegen-create-file (8ms)
|
|
149
|
+
* line 5: EXPECT failed — no envelope matched ...
|
|
150
|
+
*
|
|
151
|
+
* pugi smoke: 1 passed, 1 failed
|
|
152
|
+
*/
|
|
153
|
+
export function renderReportText(report) {
|
|
154
|
+
const lines = [];
|
|
155
|
+
for (let i = 0; i < report.results.length; i += 1) {
|
|
156
|
+
const r = report.results[i];
|
|
157
|
+
if (!r)
|
|
158
|
+
continue;
|
|
159
|
+
const ordinal = i + 1;
|
|
160
|
+
if (r.status === 'passed') {
|
|
161
|
+
lines.push(`ok ${ordinal} - ${r.id} (${r.durationMs}ms)`);
|
|
162
|
+
}
|
|
163
|
+
else if (r.status === 'failed') {
|
|
164
|
+
lines.push(`not ok ${ordinal} - ${r.id} (${r.durationMs}ms)`);
|
|
165
|
+
for (const f of r.failures) {
|
|
166
|
+
lines.push(` line ${f.line}: ${f.message}`);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
else if (r.status === 'parse-error') {
|
|
170
|
+
lines.push(`not ok ${ordinal} - ${r.id} (parse error)`);
|
|
171
|
+
for (const e of r.parseErrors ?? []) {
|
|
172
|
+
lines.push(` line ${e.line}: ${e.message}`);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
else if (r.status === 'executor-error') {
|
|
176
|
+
lines.push(`not ok ${ordinal} - ${r.id} (executor error)`);
|
|
177
|
+
lines.push(` ${r.executorError ?? 'unknown executor failure'}`);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
lines.push('');
|
|
181
|
+
const skippedSuffix = report.skipped > 0 ? `, ${report.skipped} skipped` : '';
|
|
182
|
+
lines.push(`pugi smoke: ${report.passed} passed, ${report.failed} failed${skippedSuffix}`);
|
|
183
|
+
return lines.join('\n');
|
|
184
|
+
}
|
|
185
|
+
function filterByPattern(scenarios, pattern) {
|
|
186
|
+
if (!pattern.includes('*')) {
|
|
187
|
+
return scenarios.filter((s) => s.scenario.id.includes(pattern));
|
|
188
|
+
}
|
|
189
|
+
const escaped = pattern.replace(/[.+^${}()|[\]\\]/g, '\\$&');
|
|
190
|
+
const re = new RegExp(`^${escaped.replace(/\*/g, '.*')}$`);
|
|
191
|
+
return scenarios.filter((s) => re.test(s.scenario.id));
|
|
192
|
+
}
|
|
193
|
+
function noopLog(_line) { }
|
|
194
|
+
//# sourceMappingURL=orchestrator.js.map
|