@opengsd/gsd-core 1.18.0 → 1.19.0
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/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +2 -1
- package/.opencode/plugins/gsd-core.js +2 -3
- package/agents/gsd-code-fixer.compact.md +2 -2
- package/agents/gsd-code-fixer.md +4 -3
- package/agents/gsd-verifier.md +1 -1
- package/bin/install.js +422 -103
- package/gsd-core/bin/gsd-tools.cjs +106 -7
- package/gsd-core/bin/lib/agent-install-check.cjs +29 -3
- package/gsd-core/bin/lib/args-terminator.cjs +114 -0
- package/gsd-core/bin/lib/broken-windows.cjs +59 -1
- package/gsd-core/bin/lib/capability-lock.cjs +13 -2
- package/gsd-core/bin/lib/capability-registry.cjs +156 -74
- package/gsd-core/bin/lib/capability-state.cjs +14 -8
- package/gsd-core/bin/lib/capability-validator.cjs +17 -0
- package/gsd-core/bin/lib/config-loader.cjs +10 -0
- package/gsd-core/bin/lib/config.cjs +256 -58
- package/gsd-core/bin/lib/core-utils.cjs +34 -0
- package/gsd-core/bin/lib/decision-coverage-support.cjs +74 -0
- package/gsd-core/bin/lib/gate-context-drift.cjs +8 -3
- package/gsd-core/bin/lib/gate-decision-coverage-plan.cjs +6 -1
- package/gsd-core/bin/lib/gate-decision-coverage-verify.cjs +6 -1
- package/gsd-core/bin/lib/gate-evaluation-scope.cjs +134 -13
- package/gsd-core/bin/lib/gate-tdd-review-checkpoint.cjs +63 -22
- package/gsd-core/bin/lib/gate-ui-safety.cjs +23 -5
- package/gsd-core/bin/lib/git-info-exclude.cjs +57 -0
- package/gsd-core/bin/lib/health-diagnostic-rules/phase-structure.cjs +18 -3
- package/gsd-core/bin/lib/health-diagnostic-types.cjs +4 -0
- package/gsd-core/bin/lib/health-diagnostic.cjs +52 -1
- package/gsd-core/bin/lib/host-integration.cjs +13 -6
- package/gsd-core/bin/lib/init.cjs +65 -1
- package/gsd-core/bin/lib/install-engine.cjs +246 -32
- package/gsd-core/bin/lib/install-profiles.cjs +9 -4
- package/gsd-core/bin/lib/installer-migration-report.cjs +2 -0
- package/gsd-core/bin/lib/markdown-line-diff.cjs +147 -0
- package/gsd-core/bin/lib/markdown-sectionizer.cjs +113 -0
- package/gsd-core/bin/lib/milestone-lock.cjs +8 -1
- package/gsd-core/bin/lib/milestone-release-map.cjs +244 -0
- package/gsd-core/bin/lib/milestone-release-tags.cjs +440 -0
- package/gsd-core/bin/lib/milestone.cjs +43 -1
- package/gsd-core/bin/lib/model-catalog.cjs +8 -0
- package/gsd-core/bin/lib/normalize-test-command.cjs +67 -0
- package/gsd-core/bin/lib/phase-id.cjs +21 -4
- package/gsd-core/bin/lib/phase-lifecycle.cjs +37 -4
- package/gsd-core/bin/lib/phase.cjs +115 -26
- package/gsd-core/bin/lib/planning-snapshot.cjs +3 -1
- package/gsd-core/bin/lib/planning-workspace.cjs +18 -0
- package/gsd-core/bin/lib/pristine-baseline.cjs +11 -3
- package/gsd-core/bin/lib/read-only-git-env.cjs +58 -0
- package/gsd-core/bin/lib/review-lane-descriptor.cjs +35 -2
- package/gsd-core/bin/lib/review-lane-runner.cjs +33 -4
- package/gsd-core/bin/lib/roadmap-parser.cjs +12 -0
- package/gsd-core/bin/lib/roadmap-upgrade.cjs +39 -2
- package/gsd-core/bin/lib/roadmap.cjs +33 -25
- package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +381 -14
- package/gsd-core/bin/lib/runtime-artifact-layout.cjs +8 -4
- package/gsd-core/bin/lib/runtime-hooks-surface.cjs +60 -16
- package/gsd-core/bin/lib/shell-command-projection.cjs +121 -16
- package/gsd-core/bin/lib/smart-entry.cjs +13 -0
- package/gsd-core/bin/lib/state-contract.cjs +29 -9
- package/gsd-core/bin/lib/state-document.cjs +12 -4
- package/gsd-core/bin/lib/state-transition.cjs +119 -24
- package/gsd-core/bin/lib/state.cjs +50 -28
- package/gsd-core/bin/lib/surface.cjs +9 -0
- package/gsd-core/bin/lib/task-command-router.cjs +5 -25
- package/gsd-core/bin/lib/task-content-resolution.cjs +46 -1
- package/gsd-core/bin/lib/verification.cjs +96 -9
- package/gsd-core/bin/lib/verify.cjs +2 -0
- package/gsd-core/bin/lib/worktree-safety.cjs +22 -1
- package/gsd-core/bin/shared/config-defaults.manifest.json +1 -0
- package/gsd-core/bin/shared/config-schema.manifest.json +1 -0
- package/gsd-core/references/git-integration.md +11 -0
- package/gsd-core/references/loop-hook-dispatch.md +13 -6
- package/gsd-core/references/planning-config.md +2 -0
- package/gsd-core/references/tdd.md +2 -2
- package/gsd-core/templates/DEBUG.md +16 -0
- package/gsd-core/templates/config.json +2 -1
- package/gsd-core/templates/verification-report.md +1 -1
- package/gsd-core/workflows/audit-fix.md +2 -1
- package/gsd-core/workflows/code-review/steps/structural-pre-pass.md +10 -1
- package/gsd-core/workflows/code-review.md +61 -7
- package/gsd-core/workflows/complete-milestone/steps/project-md-evolution-review.md +145 -0
- package/gsd-core/workflows/complete-milestone/steps/release-map.md +80 -0
- package/gsd-core/workflows/complete-milestone.md +37 -150
- package/gsd-core/workflows/diagnose-issues.md +29 -5
- package/gsd-core/workflows/discuss-phase/modes/power.md +1 -1
- package/gsd-core/workflows/discuss-phase-assumptions.md +33 -2
- package/gsd-core/workflows/discuss-phase-power.md +19 -2
- package/gsd-core/workflows/discuss-phase.md +6 -10
- package/gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md +13 -7
- package/gsd-core/workflows/execute-phase/steps/post-merge-gate.md +7 -2
- package/gsd-core/workflows/execute-phase/steps/regression-gate-run.md +2 -1
- package/gsd-core/workflows/execute-phase/steps/verify-phase-goal.md +2 -2
- package/gsd-core/workflows/execute-phase/steps/wave-post-gate-hooks.md +11 -2
- package/gsd-core/workflows/execute-phase.md +9 -5
- package/gsd-core/workflows/health.md +2 -1
- package/gsd-core/workflows/import.md +1 -1
- package/gsd-core/workflows/plan-phase/steps/chunked-planning-mode.md +2 -2
- package/gsd-core/workflows/plan-phase.md +13 -13
- package/gsd-core/workflows/quick/steps/plan-checker-loop.md +1 -1
- package/gsd-core/workflows/quick/steps/worktree-pre-dispatch-commit.md +8 -1
- package/gsd-core/workflows/quick-batch/steps/plan-checker-loop.md +2 -1
- package/gsd-core/workflows/quick.md +1 -1
- package/gsd-core/workflows/review.md +16 -13
- package/gsd-core/workflows/section-manifest.json +5 -0
- package/gsd-core/workflows/settings.md +1 -0
- package/gsd-core/workflows/ship.md +3 -4
- package/gsd-core/workflows/spec-phase.md +3 -6
- package/gsd-core/workflows/verify-work.md +4 -3
- package/hooks/dist/gsd-agent-isolation-guard.js +11 -1
- package/hooks/dist/gsd-cursor-subagent-start.js +6 -2
- package/hooks/dist/gsd-path-export.js +95 -0
- package/hooks/dist/gsd-secret-read-guard.js +172 -39
- package/hooks/dist/gsd-statusline.js +35 -2
- package/hooks/dist/gsd-windsurf-pre-write.js +28 -1
- package/hooks/dist/gsd-workflow-guard.js +1 -1
- package/hooks/dist/gsd-worktree-path-guard.js +28 -1
- package/hooks/dist/lib/isolation-sentinel.js +44 -0
- package/hooks/dist/managed-hooks-registry.cjs +1 -0
- package/hooks/gsd-agent-isolation-guard.js +11 -1
- package/hooks/gsd-cursor-subagent-start.js +6 -2
- package/hooks/gsd-path-export.js +95 -0
- package/hooks/gsd-secret-read-guard.js +172 -39
- package/hooks/gsd-statusline.js +35 -2
- package/hooks/gsd-windsurf-pre-write.js +28 -1
- package/hooks/gsd-workflow-guard.js +1 -1
- package/hooks/gsd-worktree-path-guard.js +28 -1
- package/hooks/hooks.json +1 -0
- package/hooks/lib/isolation-sentinel.js +44 -0
- package/hooks/managed-hooks-registry.cjs +1 -0
- package/package.json +13 -6
- package/pi/gsd.cjs +1047 -10
- package/pi/package-agents/gsd-advisor-researcher.md +113 -0
- package/pi/package-agents/gsd-ai-researcher.md +111 -0
- package/pi/package-agents/gsd-assumptions-analyzer.md +110 -0
- package/pi/package-agents/gsd-code-fixer.md +769 -0
- package/pi/package-agents/gsd-code-reviewer.md +402 -0
- package/pi/package-agents/gsd-codebase-mapper.md +850 -0
- package/pi/package-agents/gsd-debug-session-manager.md +416 -0
- package/pi/package-agents/gsd-debugger.md +1274 -0
- package/pi/package-agents/gsd-doc-classifier.md +269 -0
- package/pi/package-agents/gsd-doc-synthesizer.md +259 -0
- package/pi/package-agents/gsd-doc-verifier.md +212 -0
- package/pi/package-agents/gsd-doc-writer.md +626 -0
- package/pi/package-agents/gsd-dom-verifier.md +164 -0
- package/pi/package-agents/gsd-domain-researcher.md +144 -0
- package/pi/package-agents/gsd-eval-auditor.md +185 -0
- package/pi/package-agents/gsd-eval-planner.md +149 -0
- package/pi/package-agents/gsd-executor.md +894 -0
- package/pi/package-agents/gsd-framework-selector.md +159 -0
- package/pi/package-agents/gsd-integration-checker.md +476 -0
- package/pi/package-agents/gsd-intel-updater.md +338 -0
- package/pi/package-agents/gsd-mempalace-curator.md +49 -0
- package/pi/package-agents/gsd-nyquist-auditor.md +200 -0
- package/pi/package-agents/gsd-pattern-mapper.md +340 -0
- package/pi/package-agents/gsd-phase-researcher.md +897 -0
- package/pi/package-agents/gsd-plan-checker.md +1077 -0
- package/pi/package-agents/gsd-planner.md +1003 -0
- package/pi/package-agents/gsd-project-researcher.md +611 -0
- package/pi/package-agents/gsd-research-synthesizer.md +259 -0
- package/pi/package-agents/gsd-roadmapper.md +779 -0
- package/pi/package-agents/gsd-security-auditor.md +171 -0
- package/pi/package-agents/gsd-ui-auditor.md +581 -0
- package/pi/package-agents/gsd-ui-checker.md +417 -0
- package/pi/package-agents/gsd-ui-researcher.md +469 -0
- package/pi/package-agents/gsd-user-profiler.md +174 -0
- package/pi/package-agents/gsd-verifier.md +963 -0
- package/pi/package-agents/manifest.json +39 -0
- package/pi/package-skills/gsd-add-tests/SKILL.md +39 -0
- package/pi/package-skills/gsd-ai-integration-phase/SKILL.md +36 -0
- package/pi/package-skills/gsd-audit-fix/SKILL.md +34 -0
- package/pi/package-skills/gsd-audit-milestone/SKILL.md +40 -0
- package/pi/package-skills/gsd-audit-uat/SKILL.md +26 -0
- package/pi/package-skills/gsd-autonomous/SKILL.md +52 -0
- package/pi/package-skills/gsd-capture/SKILL.md +68 -0
- package/pi/package-skills/gsd-cleanup/SKILL.md +25 -0
- package/pi/package-skills/gsd-code-review/SKILL.md +71 -0
- package/pi/package-skills/gsd-complete-milestone/SKILL.md +147 -0
- package/pi/package-skills/gsd-config/SKILL.md +60 -0
- package/pi/package-skills/gsd-debug/SKILL.md +64 -0
- package/pi/package-skills/gsd-discuss-phase/SKILL.md +74 -0
- package/pi/package-skills/gsd-docs-update/SKILL.md +50 -0
- package/pi/package-skills/gsd-eval-review/SKILL.md +35 -0
- package/pi/package-skills/gsd-execute-phase/SKILL.md +62 -0
- package/pi/package-skills/gsd-explore/SKILL.md +26 -0
- package/pi/package-skills/gsd-extract-learnings/SKILL.md +25 -0
- package/pi/package-skills/gsd-fast/SKILL.md +33 -0
- package/pi/package-skills/gsd-forensics/SKILL.md +59 -0
- package/pi/package-skills/gsd-graphify/SKILL.md +210 -0
- package/pi/package-skills/gsd-health/SKILL.md +36 -0
- package/pi/package-skills/gsd-help/SKILL.md +37 -0
- package/pi/package-skills/gsd-import/SKILL.md +46 -0
- package/pi/package-skills/gsd-inbox/SKILL.md +42 -0
- package/pi/package-skills/gsd-ingest-docs/SKILL.md +43 -0
- package/pi/package-skills/gsd-manager/SKILL.md +46 -0
- package/pi/package-skills/gsd-map-codebase/SKILL.md +85 -0
- package/pi/package-skills/gsd-mempalace-capture/SKILL.md +111 -0
- package/pi/package-skills/gsd-mempalace-recall/SKILL.md +111 -0
- package/pi/package-skills/gsd-milestone-summary/SKILL.md +54 -0
- package/pi/package-skills/gsd-mvp-phase/SKILL.md +45 -0
- package/pi/package-skills/gsd-new-milestone/SKILL.md +49 -0
- package/pi/package-skills/gsd-new-project/SKILL.md +49 -0
- package/pi/package-skills/gsd-next/SKILL.md +34 -0
- package/pi/package-skills/gsd-ns-context/SKILL.md +31 -0
- package/pi/package-skills/gsd-ns-ideate/SKILL.md +30 -0
- package/pi/package-skills/gsd-ns-manage/SKILL.md +42 -0
- package/pi/package-skills/gsd-ns-project/SKILL.md +34 -0
- package/pi/package-skills/gsd-ns-review/SKILL.md +35 -0
- package/pi/package-skills/gsd-ns-workflow/SKILL.md +44 -0
- package/pi/package-skills/gsd-onboard/SKILL.md +46 -0
- package/pi/package-skills/gsd-pause-work/SKILL.md +48 -0
- package/pi/package-skills/gsd-phase/SKILL.md +61 -0
- package/pi/package-skills/gsd-plan-phase/SKILL.md +62 -0
- package/pi/package-skills/gsd-plan-review-convergence/SKILL.md +63 -0
- package/pi/package-skills/gsd-pr-branch/SKILL.md +31 -0
- package/pi/package-skills/gsd-profile-user/SKILL.md +48 -0
- package/pi/package-skills/gsd-progress/SKILL.md +51 -0
- package/pi/package-skills/gsd-quick/SKILL.md +179 -0
- package/pi/package-skills/gsd-quick-batch/SKILL.md +114 -0
- package/pi/package-skills/gsd-resume-work/SKILL.md +31 -0
- package/pi/package-skills/gsd-review/SKILL.md +50 -0
- package/pi/package-skills/gsd-review-backlog/SKILL.md +65 -0
- package/pi/package-skills/gsd-secure-phase/SKILL.md +37 -0
- package/pi/package-skills/gsd-settings/SKILL.md +30 -0
- package/pi/package-skills/gsd-ship/SKILL.md +27 -0
- package/pi/package-skills/gsd-sketch/SKILL.md +56 -0
- package/pi/package-skills/gsd-spec-phase/SKILL.md +63 -0
- package/pi/package-skills/gsd-spike/SKILL.md +53 -0
- package/pi/package-skills/gsd-stats/SKILL.md +22 -0
- package/pi/package-skills/gsd-surface/SKILL.md +177 -0
- package/pi/package-skills/gsd-thread/SKILL.md +29 -0
- package/pi/package-skills/gsd-ui-phase/SKILL.md +35 -0
- package/pi/package-skills/gsd-ui-review/SKILL.md +35 -0
- package/pi/package-skills/gsd-ultraplan-phase/SKILL.md +38 -0
- package/pi/package-skills/gsd-undo/SKILL.md +38 -0
- package/pi/package-skills/gsd-update/SKILL.md +51 -0
- package/pi/package-skills/gsd-validate-phase/SKILL.md +37 -0
- package/pi/package-skills/gsd-verify-work/SKILL.md +41 -0
- package/pi/package-skills/gsd-workspace/SKILL.md +57 -0
- package/pi/package-skills/gsd-workstreams/SKILL.md +73 -0
- package/scripts/build-hooks.js +4 -0
- package/scripts/command-contract-helpers.cjs +1 -1
- package/scripts/docs-guard-registry.cjs +20 -7
- package/scripts/gen-health-docs.cjs +13 -1
- package/scripts/gen-pi-package-skills.cjs +217 -0
- package/scripts/lib/macos-conformance-tier.generated.cjs +11 -1
- package/scripts/lib/platform-conformance-tier.generated.cjs +26 -1
- package/scripts/lint-docs-guard-registration.exempt-baseline.cjs +3 -3
- package/scripts/lint-retired-runtime-name.cjs +5 -0
- package/scripts/npm-audit-baseline.cjs +41 -7
- package/scripts/reviewed-or-maintainer-policy.cjs +181 -0
- package/scripts/select-docs-guards.cjs +1 -1
- package/scripts/self-test-report-policy.cjs +350 -0
- package/vscode/package.json +1 -1
- package/scripts/diagnose-validate-commit-in-tier.cjs +0 -270
- package/scripts/diagnose-validate-commit-phases.cjs +0 -348
- package/scripts/xtrace-phase-timing.cjs +0 -205
|
@@ -1,205 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Per-line cost attribution for a `bash -x` trace whose PS4 stamps every
|
|
5
|
-
* traced command with a millisecond timestamp, its line number and enclosing
|
|
6
|
-
* function (#5473).
|
|
7
|
-
*
|
|
8
|
-
* The stamp is `<depth marks>@@<nonce>@@<epoch-ms>@@<lineno>@@<function>@@ `, so
|
|
9
|
-
* one trace line looks like `++@@k3f9@@1760615775123@@271@@@@ MSG_SUFFIX=...`.
|
|
10
|
-
* The nonce is a per-run random token: a traced value that merely LOOKS like a
|
|
11
|
-
* stamp (hostile or accidental) cannot forge one without knowing it.
|
|
12
|
-
*
|
|
13
|
-
* WHAT A GAP MEANS. bash prints a trace line (and so evaluates PS4) AFTER it
|
|
14
|
-
* has expanded the command's words and BEFORE it runs the command. The gap
|
|
15
|
-
* between stamp i and stamp i+1 is therefore
|
|
16
|
-
*
|
|
17
|
-
* execution of command i + expansion of command i+1
|
|
18
|
-
*
|
|
19
|
-
* which cannot be split from the trace alone. Both attributions are reported:
|
|
20
|
-
* `afterMs` (the gap that FOLLOWS the line) is large for a line that EXECUTES
|
|
21
|
-
* slowly (an external command, a `$(...)` already expanded); `beforeMs` (the
|
|
22
|
-
* gap that PRECEDES it) is large for a line whose EXPANSION is slow (a
|
|
23
|
-
* `${var//pat/x}` or `${var:off}` over a 112KB value, whose result is only
|
|
24
|
-
* printed once it is computed). Neither alone is "the cost of the line".
|
|
25
|
-
*
|
|
26
|
-
* Every traced command also pays one stamp (a subshell and a perl); measure it
|
|
27
|
-
* with a run of no-ops (see the CLI) and read gaps below it as zero.
|
|
28
|
-
*
|
|
29
|
-
* No I/O and no clock: every function returns a value computed from its
|
|
30
|
-
* arguments. The CLI that runs bash is scripts/diagnose-validate-commit-phases.cjs.
|
|
31
|
-
*/
|
|
32
|
-
|
|
33
|
-
/** PS4 to hand to `bash -x`; `timestampCommand` prints the epoch milliseconds. */
|
|
34
|
-
function stampPs4(timestampCommand, nonce) {
|
|
35
|
-
return `+@@${nonce}@@$(${timestampCommand})@@\${LINENO}@@\${FUNCNAME:-}@@ `;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* How the stamp reaches bash. Every other route failed somewhere:
|
|
40
|
-
* - an exported PS4: bash 5.x does not run the command substitution in a PS4
|
|
41
|
-
* it imported from the environment, so it silently degrades to `+ `;
|
|
42
|
-
* - BASH_ENV: bash reads the system bashrc INSTEAD of it in some
|
|
43
|
-
* environments (it did in the gsd-test tester container);
|
|
44
|
-
* - `bash -c '... . "$0"'`: puts an uncontrolled path inside a shell command.
|
|
45
|
-
* So the script under test is run as an ordinary script that has ONE line
|
|
46
|
-
* inserted after its shebang, which assigns PS4 (read from a sibling file, so
|
|
47
|
-
* the stamp text is never quoted into shell code) and turns on xtrace. `$0`,
|
|
48
|
-
* `exit` and sibling files then behave exactly as in a direct run (the CLI's
|
|
49
|
-
* tests pin this against the real hook).
|
|
50
|
-
*/
|
|
51
|
-
const TRACE_PS4_FILE = 'xtrace-ps4.txt';
|
|
52
|
-
const INJECTED_LINES = 1;
|
|
53
|
-
const INJECTED_LINE = `PS4="$(cat "\${0%/*}/${TRACE_PS4_FILE}")"; set -x`;
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* `scriptText` with the tracing line inserted after its shebang (or at the top
|
|
57
|
-
* when it has none). The script must be run by a path containing a `/`, with
|
|
58
|
-
* the PS4 text in TRACE_PS4_FILE beside it. Adds exactly INJECTED_LINES lines.
|
|
59
|
-
*/
|
|
60
|
-
function injectTracing(scriptText) {
|
|
61
|
-
const text = String(scriptText);
|
|
62
|
-
if (!text.startsWith('#!')) return `${INJECTED_LINE}\n${text}`;
|
|
63
|
-
const eol = text.indexOf('\n');
|
|
64
|
-
if (eol === -1) return `${text}\n${INJECTED_LINE}\n`;
|
|
65
|
-
return `${text.slice(0, eol + 1)}${INJECTED_LINE}\n${text.slice(eol + 1)}`;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
// What follows the depth marks and the nonce: `<epoch-ms>@@<lineno>@@<function>@@ `.
|
|
69
|
-
const STAMP_TAIL = /^(\d+)@@(\d+)@@([^@]*)@@ ?/;
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* Parse a stamped trace. Lines with no stamp are continuations of the
|
|
73
|
-
* previous command (a traced value that itself contains newlines) and are
|
|
74
|
-
* folded into it; text before the first stamp is ignored.
|
|
75
|
-
*
|
|
76
|
-
* @param {string} text
|
|
77
|
-
* @param {string} nonce the nonce given to stampPs4
|
|
78
|
-
* @returns {{ t: number, line: number, depth: number, fn: string, cmd: string }[]}
|
|
79
|
-
*/
|
|
80
|
-
function parseTimedXtrace(text, nonce) {
|
|
81
|
-
// The nonce is matched as a literal prefix, never compiled into a pattern.
|
|
82
|
-
const head = `@@${nonce}@@`;
|
|
83
|
-
const entries = [];
|
|
84
|
-
const lines = String(text).split('\n');
|
|
85
|
-
// A stream ends with the newline of its last line; that is a terminator, not
|
|
86
|
-
// an empty continuation of the last command.
|
|
87
|
-
if (lines.length > 0 && lines[lines.length - 1] === '') lines.pop();
|
|
88
|
-
for (const raw of lines) {
|
|
89
|
-
let depth = 0;
|
|
90
|
-
while (raw[depth] === '+') depth++;
|
|
91
|
-
const tail = depth > 0 && raw.startsWith(head, depth)
|
|
92
|
-
? STAMP_TAIL.exec(raw.slice(depth + head.length))
|
|
93
|
-
: null;
|
|
94
|
-
if (tail) {
|
|
95
|
-
entries.push({
|
|
96
|
-
t: Number(tail[1]),
|
|
97
|
-
line: Number(tail[2]),
|
|
98
|
-
depth,
|
|
99
|
-
fn: tail[3],
|
|
100
|
-
cmd: raw.slice(depth + head.length + tail[0].length),
|
|
101
|
-
});
|
|
102
|
-
} else if (entries.length > 0) {
|
|
103
|
-
entries[entries.length - 1].cmd += `\n${raw}`;
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
return entries;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
/**
|
|
110
|
-
* Entries with their line numbers moved back by `injected` lines, so a stamp
|
|
111
|
-
* reports the line of the ORIGINAL script, not of the instrumented copy.
|
|
112
|
-
*/
|
|
113
|
-
function shiftLines(entries, injected) {
|
|
114
|
-
return entries.map((e) => ({ ...e, line: e.line - injected }));
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
/**
|
|
118
|
-
* Attribute the gaps around each entry to its (function, line): `afterMs` is
|
|
119
|
-
* the gap to the NEXT stamp, `beforeMs` the gap from the PREVIOUS one (see the
|
|
120
|
-
* header for what each means). A clock that steps backwards counts as zero.
|
|
121
|
-
*
|
|
122
|
-
* @param {{ t: number, line: number, fn?: string, cmd: string }[]} entries
|
|
123
|
-
* @returns {{ costs: { fn: string, line: number, afterMs: number, beforeMs: number, maxMs: number, count: number, sample: string }[], totalMs: number }}
|
|
124
|
-
*/
|
|
125
|
-
function phaseCosts(entries) {
|
|
126
|
-
const byKey = new Map();
|
|
127
|
-
const last = entries.length - 1;
|
|
128
|
-
for (let i = 0; i <= last; i++) {
|
|
129
|
-
const after = i < last ? Math.max(0, entries[i + 1].t - entries[i].t) : 0;
|
|
130
|
-
const before = i > 0 ? Math.max(0, entries[i].t - entries[i - 1].t) : 0;
|
|
131
|
-
const e = entries[i];
|
|
132
|
-
const fn = e.fn || '';
|
|
133
|
-
const key = `${fn}\u0000${e.line}`;
|
|
134
|
-
const acc = byKey.get(key) || { fn, line: e.line, afterMs: 0, beforeMs: 0, maxMs: 0, count: 0, sample: '' };
|
|
135
|
-
acc.afterMs += after;
|
|
136
|
-
acc.beforeMs += before;
|
|
137
|
-
acc.count += 1;
|
|
138
|
-
const peak = Math.max(after, before);
|
|
139
|
-
if (peak >= acc.maxMs) {
|
|
140
|
-
acc.maxMs = peak;
|
|
141
|
-
acc.sample = e.cmd;
|
|
142
|
-
}
|
|
143
|
-
byKey.set(key, acc);
|
|
144
|
-
}
|
|
145
|
-
const totalMs = entries.length > 1 ? Math.max(0, entries[last].t - entries[0].t) : 0;
|
|
146
|
-
return { costs: [...byKey.values()], totalMs };
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
/** A line's weight when ranking: the larger of its two attributions. */
|
|
150
|
-
const peakMs = (c) => Math.max(c.afterMs, c.beforeMs);
|
|
151
|
-
|
|
152
|
-
/**
|
|
153
|
-
* The `n` most expensive lines, costliest first; ties broken by function then
|
|
154
|
-
* line number so the order is deterministic.
|
|
155
|
-
*/
|
|
156
|
-
function slowestLines(costs, n) {
|
|
157
|
-
return [...costs]
|
|
158
|
-
.sort((a, b) => peakMs(b) - peakMs(a) || (a.fn < b.fn ? -1 : a.fn > b.fn ? 1 : 0) || a.line - b.line)
|
|
159
|
-
.slice(0, n);
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
/**
|
|
163
|
-
* Elapsed time per run of `size` source lines of the script's top level, in
|
|
164
|
-
* line order, plus one entry per function. `afterMs` summed over a region is
|
|
165
|
-
* the time from its first stamp to the next region's, so regions roughly
|
|
166
|
-
* partition the run: a coarse "which phase" view that needs no knowledge of
|
|
167
|
-
* the script.
|
|
168
|
-
*
|
|
169
|
-
* @returns {{ label: string, afterMs: number }[]}
|
|
170
|
-
*/
|
|
171
|
-
function rollupByRegion(costs, size) {
|
|
172
|
-
if (!Number.isInteger(size) || size < 1) throw new RangeError('region size must be a positive integer');
|
|
173
|
-
const regions = new Map();
|
|
174
|
-
for (const c of costs) {
|
|
175
|
-
const start = Math.floor((c.line - 1) / size) * size + 1;
|
|
176
|
-
const label = c.fn ? `in ${c.fn}()` : `lines ${start}-${start + size - 1}`;
|
|
177
|
-
const from = c.fn ? Number.MAX_SAFE_INTEGER : start; // functions sort after the top level
|
|
178
|
-
const acc = regions.get(label) || { label, from, afterMs: 0 };
|
|
179
|
-
acc.afterMs += c.afterMs;
|
|
180
|
-
regions.set(label, acc);
|
|
181
|
-
}
|
|
182
|
-
return [...regions.values()]
|
|
183
|
-
.sort((a, b) => a.from - b.from || (a.label < b.label ? -1 : a.label > b.label ? 1 : 0))
|
|
184
|
-
.map(({ label, afterMs }) => ({ label, afterMs }));
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
/** One-line, length-bounded rendering of a traced command for a report. */
|
|
188
|
-
function abbreviate(cmd, max = 100) {
|
|
189
|
-
const flat = String(cmd).replace(/\s+/g, ' ').trim();
|
|
190
|
-
return flat.length <= max ? flat : `${flat.slice(0, max)}… (${flat.length} chars)`;
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
module.exports = {
|
|
194
|
-
stampPs4,
|
|
195
|
-
TRACE_PS4_FILE,
|
|
196
|
-
INJECTED_LINES,
|
|
197
|
-
injectTracing,
|
|
198
|
-
parseTimedXtrace,
|
|
199
|
-
shiftLines,
|
|
200
|
-
phaseCosts,
|
|
201
|
-
peakMs,
|
|
202
|
-
slowestLines,
|
|
203
|
-
rollupByRegion,
|
|
204
|
-
abbreviate,
|
|
205
|
-
};
|