canary-test-cli 7.0.0 → 7.2.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.
Files changed (122) hide show
  1. package/agents/skills/README.md +308 -0
  2. package/agents/skills/canary:generate.md +49 -0
  3. package/agents/skills/canary:init.md +37 -0
  4. package/agents/skills/canary:migrate.md +66 -0
  5. package/agents/skills/claude-code/canary-add-framework/SKILL.md +248 -0
  6. package/agents/skills/claude-code/canary-blackhawk/SKILL.md +170 -0
  7. package/agents/skills/claude-code/canary-blackhawk/scripts/cli.mjs +188 -0
  8. package/agents/skills/claude-code/canary-blackhawk/scripts/rules.mjs +120 -0
  9. package/agents/skills/claude-code/canary-blackhawk/scripts/scanner.mjs +244 -0
  10. package/agents/skills/claude-code/canary-blackhawk/scripts/string-literals.mjs +116 -0
  11. package/agents/skills/claude-code/canary-cassandra/SKILL.md +180 -0
  12. package/agents/skills/claude-code/canary-cassandra/scripts/cli.mjs +268 -0
  13. package/agents/skills/claude-code/canary-cassandra/scripts/engine.mjs +95 -0
  14. package/agents/skills/claude-code/canary-ci-ready/SKILL.md +161 -0
  15. package/agents/skills/claude-code/canary-ci-ready/skill.yaml +14 -0
  16. package/agents/skills/claude-code/canary-company-knowledge/SKILL.md +196 -0
  17. package/agents/skills/claude-code/canary-critical-areas/SKILL.md +142 -0
  18. package/agents/skills/claude-code/canary-critical-areas/skill.yaml +16 -0
  19. package/agents/skills/claude-code/canary-edge-case-discovery/SKILL.md +160 -0
  20. package/agents/skills/claude-code/canary-edge-case-discovery/skill.yaml +16 -0
  21. package/agents/skills/claude-code/canary-fail-fast/SKILL.md +75 -0
  22. package/agents/skills/claude-code/canary-fail-fast/scripts/cli.mjs +118 -0
  23. package/agents/skills/claude-code/canary-fail-fast/scripts/digest.mjs +69 -0
  24. package/agents/skills/claude-code/canary-fail-fast/scripts/failures.mjs +60 -0
  25. package/agents/skills/claude-code/canary-fail-fast/scripts/fastfail_check.mjs +43 -0
  26. package/agents/skills/claude-code/canary-fail-fast/scripts/parse.mjs +149 -0
  27. package/agents/skills/claude-code/canary-failure-impact/SKILL.md +153 -0
  28. package/agents/skills/claude-code/canary-failure-impact/skill.yaml +15 -0
  29. package/agents/skills/claude-code/canary-fleet-health/SKILL.md +196 -0
  30. package/agents/skills/claude-code/canary-generate-test/SKILL.md +185 -0
  31. package/agents/skills/claude-code/canary-instrument/SKILL.md +157 -0
  32. package/agents/skills/claude-code/canary-instrument/scripts/cli.mjs +178 -0
  33. package/agents/skills/claude-code/canary-instrument/scripts/otel_bootstrap/instrument.mjs +96 -0
  34. package/agents/skills/claude-code/canary-instrument/scripts/otel_bootstrap/playwright-fixture.ts +44 -0
  35. package/agents/skills/claude-code/canary-instrument/scripts/run_types.mjs +81 -0
  36. package/agents/skills/claude-code/canary-instrument/scripts/span_reader.mjs +187 -0
  37. package/agents/skills/claude-code/canary-katana/SKILL.md +243 -0
  38. package/agents/skills/claude-code/canary-katana/scripts/alarm.mjs +296 -0
  39. package/agents/skills/claude-code/canary-katana/scripts/cli.mjs +247 -0
  40. package/agents/skills/claude-code/canary-katana/scripts/diffscan.mjs +0 -0
  41. package/agents/skills/claude-code/canary-katana/scripts/ledger.mjs +183 -0
  42. package/agents/skills/claude-code/canary-pr-guardian/SKILL.md +129 -0
  43. package/agents/skills/claude-code/canary-pr-guardian/skill.yaml +17 -0
  44. package/agents/skills/claude-code/canary-promote-test/SKILL.md +228 -0
  45. package/agents/skills/claude-code/canary-savant/SKILL.md +233 -0
  46. package/agents/skills/claude-code/canary-savant/scripts/cli.mjs +274 -0
  47. package/agents/skills/claude-code/canary-savant/scripts/restoration.mjs +274 -0
  48. package/agents/skills/claude-code/canary-savant/scripts/rules.mjs +168 -0
  49. package/agents/skills/claude-code/canary-savant/scripts/runner.mjs +572 -0
  50. package/agents/skills/claude-code/canary-savant/scripts/scanner.mjs +374 -0
  51. package/agents/skills/claude-code/canary-savant/scripts/string-literals.mjs +116 -0
  52. package/agents/skills/claude-code/canary-setup-harness/SKILL.md +263 -0
  53. package/agents/skills/claude-code/canary-shadow/SKILL.md +131 -0
  54. package/agents/skills/claude-code/canary-shadow/scripts/cases.example.json +32 -0
  55. package/agents/skills/claude-code/canary-shadow/scripts/cli.mjs +195 -0
  56. package/agents/skills/claude-code/canary-ship/SKILL.md +177 -0
  57. package/agents/skills/claude-code/canary-ship/skill.yaml +16 -0
  58. package/agents/skills/claude-code/canary-strix/SKILL.md +130 -0
  59. package/agents/skills/claude-code/canary-strix/scripts/cli.mjs +255 -0
  60. package/agents/skills/claude-code/canary-strix/scripts/scanner.mjs +252 -0
  61. package/agents/skills/claude-code/canary-strix/scripts/terms.mjs +132 -0
  62. package/agents/skills/claude-code/canary-test-pipeline/SKILL.md +159 -0
  63. package/agents/skills/claude-code/canary-test-pipeline/skill.yaml +19 -0
  64. package/agents/skills/claude-code/canary-test-reporter/SKILL.md +138 -0
  65. package/agents/skills/claude-code/canary-test-reporter/scripts/cli.mjs +98 -0
  66. package/agents/skills/claude-code/canary-test-reporter/scripts/json_report.mjs +58 -0
  67. package/agents/skills/claude-code/canary-test-reporter/scripts/parse.mjs +216 -0
  68. package/agents/skills/claude-code/canary-test-reporter/scripts/render.mjs +114 -0
  69. package/agents/skills/lib/parse-args.mjs +214 -0
  70. package/dist/engine/analysis/cli.js +116 -54
  71. package/dist/engine/analysis/engine.js +34 -16
  72. package/dist/engine/analysis/reports.js +5 -4
  73. package/dist/engine/cli-commands.js +252 -106
  74. package/dist/engine/cli-common.js +15 -24
  75. package/dist/engine/cli.core.js +37 -11
  76. package/dist/engine/cli.js +2 -2
  77. package/dist/engine/company-knowledge-cli.js +2 -2
  78. package/dist/engine/core/adoption.js +408 -0
  79. package/dist/engine/core/framework-probes.js +7 -7
  80. package/dist/engine/core/fs-glob.js +2 -2
  81. package/dist/engine/core/gate-result.js +17 -0
  82. package/dist/engine/core/migrator.js +9 -17
  83. package/dist/engine/core/pattern-matcher.js +23 -5
  84. package/dist/engine/core/persona.js +421 -0
  85. package/dist/engine/core/promotion-verdict.js +261 -0
  86. package/dist/engine/core/quality-scorer.js +15 -2
  87. package/dist/engine/core/reporter.js +1 -9
  88. package/dist/engine/core/skill-dispatch.js +115 -0
  89. package/dist/engine/core/skill-examples.js +392 -0
  90. package/dist/engine/core/skill-registry.js +59 -4
  91. package/dist/engine/core/skill-surfaces.js +307 -0
  92. package/dist/engine/core/static-linter.js +310 -38
  93. package/dist/engine/core/test-files.js +77 -0
  94. package/dist/engine/core/ticket-updater.js +1 -7
  95. package/dist/engine/core/vacuity-scanner.js +726 -0
  96. package/dist/engine/core/workflow-discovery.js +2 -8
  97. package/dist/engine/core/workspace-detect.js +7 -6
  98. package/dist/engine/data/personas/registry.json +36 -0
  99. package/dist/engine/guardian/adjudication.js +5 -5
  100. package/dist/engine/guardian/analysis-emit.js +19 -28
  101. package/dist/engine/guardian/cli.js +150 -51
  102. package/dist/engine/guardian/coverage.js +1 -1
  103. package/dist/engine/guardian/diff-coverage/heuristic-tier.js +1 -1
  104. package/dist/engine/guardian/diff-coverage/orchestrator.js +2 -2
  105. package/dist/engine/guardian/pr-check.js +322 -33
  106. package/dist/engine/guardian/pr-comment.js +4 -3
  107. package/dist/engine/history/cli.js +210 -6
  108. package/dist/engine/history/ndjson-store.js +9 -5
  109. package/dist/engine/history/record.js +34 -5
  110. package/dist/engine/history/run-recorder.js +165 -0
  111. package/dist/engine/history/schema.js +25 -7
  112. package/dist/engine/history/store.js +9 -0
  113. package/dist/engine/mcp-server.js +35 -13
  114. package/dist/engine/skills-cli.js +249 -23
  115. package/dist/engine/util/ensure-ascii.js +37 -0
  116. package/dist/engine/workflow-cli.js +6 -6
  117. package/dist/gate-result.d.ts +11 -0
  118. package/dist/gate-result.js +18 -0
  119. package/dist/reporters/testtracker.d.ts +1 -1
  120. package/dist/reporters/testtracker.js +1 -1
  121. package/dist/uninstall.js +12 -5
  122. package/package.json +3 -2
@@ -0,0 +1,168 @@
1
+ // Static suspect-rule catalog for canary-savant Tier-1 (pure data).
2
+ //
3
+ // Tier-1 flags the shared-state smells that *predict* order-dependent tests
4
+ // without executing anything: a module-level mutable that a test writes to, a
5
+ // setup with no matching teardown, a mutated process singleton, an
6
+ // order-coupled name. It is advisory: a smell is a suspect, not a proven leak.
7
+ // The dynamic confirmer (Tier-2, opt-in) is what turns a suspect into a named
8
+ // polluter.
9
+ //
10
+ // The detection logic lives in scanner.mjs; this module holds the metadata
11
+ // (id, severity, one-line rationale) each finding carries and the regexes the
12
+ // scanner tests against. JS has no verbose-regex flag, so patterns are compact
13
+ // literals documented by the comment above them.
14
+
15
+ export const SEVERITIES = ['high', 'medium', 'low'];
16
+
17
+ /** @typedef {{ruleId: string, severity: string, why: string}} Rule */
18
+
19
+ /** @type {Rule[]} */
20
+ export const RULES = [
21
+ {
22
+ ruleId: 'SV001-module-mutable-global',
23
+ severity: 'medium',
24
+ why:
25
+ 'a module-level mutable is written by a test, so state leaks into ' +
26
+ 'whatever test runs next',
27
+ },
28
+ {
29
+ ruleId: 'SV002-missing-teardown',
30
+ severity: 'medium',
31
+ why:
32
+ 'setup acquires state with no matching teardown, so the state outlives ' +
33
+ 'the test that created it',
34
+ },
35
+ {
36
+ ruleId: 'SV003-shared-singleton-mutation',
37
+ severity: 'low',
38
+ why:
39
+ 'a process-global singleton is mutated without restore, so the change ' +
40
+ 'persists across tests',
41
+ },
42
+ {
43
+ ruleId: 'SV004-order-coupled-name',
44
+ severity: 'low',
45
+ why:
46
+ 'the name or comment encodes an execution order, a self-reported ' +
47
+ 'dependence on another test running first',
48
+ },
49
+ ];
50
+
51
+ export const WHY = Object.fromEntries(RULES.map((r) => [r.ruleId, r.why]));
52
+ export const SEVERITY = Object.fromEntries(
53
+ RULES.map((r) => [r.ruleId, r.severity]),
54
+ );
55
+
56
+ // SV003: singleton / env mutation (assignment, never a read or comparison).
57
+ // A trailing negative lookahead on `=` keeps `==` comparisons out. One entry
58
+ // per process-global family (#493): `assign` detects the mutation (and, in a
59
+ // teardown region, the restore); `deletes` and `restoreAll` are restore-only
60
+ // idioms. Group 1/2 of `assign` and `deletes` capture the key (dot-property
61
+ // or bracket expression) so restoration.mjs can match restores per key.
62
+ // os.environ['X'] = ... | sys.modules['m'] = ... | process.env.X = ...
63
+ // | process.env['X'] = ...
64
+ export const SINGLETON_FAMILIES = [
65
+ {
66
+ id: 'process.env',
67
+ token: 'process\\.env',
68
+ assign: /\bprocess\.env\s*(?:\.(\w+)|\[([^\]]+)\])\s*=(?!=)/,
69
+ deletes: [/\bdelete\s+process\.env\s*(?:\.(\w+)|\[([^\]]+)\])/],
70
+ restoreAll: [/\bObject\.assign\s*\(\s*process\.env\s*,/],
71
+ },
72
+ {
73
+ id: 'os.environ',
74
+ token: 'os\\.environ',
75
+ assign: /\bos\.environ\s*\[([^\]]+)\]\s*=(?!=)/,
76
+ deletes: [
77
+ /\bdel\s+os\.environ\s*\[([^\]]+)\]/,
78
+ /\bos\.environ\.pop\s*\(\s*([^,)]+)/,
79
+ ],
80
+ restoreAll: [/\bos\.environ\.(?:update|clear)\s*\(/],
81
+ },
82
+ {
83
+ id: 'sys.modules',
84
+ token: 'sys\\.modules',
85
+ assign: /\bsys\.modules\s*\[([^\]]+)\]\s*=(?!=)/,
86
+ deletes: [
87
+ /\bdel\s+sys\.modules\s*\[([^\]]+)\]/,
88
+ /\bsys\.modules\.pop\s*\(\s*([^,)]+)/,
89
+ ],
90
+ restoreAll: [/\bsys\.modules\.update\s*\(/],
91
+ },
92
+ ];
93
+
94
+ // SV004: order-coupled name or comment (fires on code and comment lines).
95
+ // Split in two (#493) because the alternatives anchor differently:
96
+ //
97
+ // CODE-anchored: the token is source code in real usage, so a match starting
98
+ // inside a string literal is fixture data and is rejected.
99
+ // def test_1_... -> ordinal-indexed test
100
+ // def test_first / test_last(_more) -> ordinal test name (not test_firstname)
101
+ // it('... run first') -> ordering inside an it() title (anchor: `it(`)
102
+ export const SV004_CODE_PATTERN =
103
+ /\bdef\s+test_\d+_|\bdef\s+test_(?:first|second|third|fourth|fifth|sixth|seventh|last|initial|final)\s*[(:]|\bit\s*\(\s*['"][^'"]*\b(?:run|runs|running)\s+(?:first|last|before|after)\b/i;
104
+ //
105
+ // TEXT-anchored: the directive legitimately lives inside strings (test
106
+ // titles, docstrings) and comments, so it is NOT string-literal filtered.
107
+ // "must run before ..." -> self-reported ordering note
108
+ // "runs before ..."
109
+ export const SV004_TEXT_PATTERN =
110
+ /\bmust\s+run\s+(?:before|after|first|last)\b|\bruns?\s+(?:before|after)\b/i;
111
+
112
+ // SV002: framework-conditioned setup/teardown pairs. Only CLASS/ALL-scoped
113
+ // setup is included: it manages state shared across a class's tests, so a
114
+ // missing teardown genuinely leaks. Per-test setup (setUp / setup_method /
115
+ // beforeEach) rebuilds state for each test, so a missing teardown there is not a
116
+ // leak - and firing on it was the dominant false positive when dogfooding on
117
+ // canary's own suite (Phase 5). A setup present without its teardown fires.
118
+ export const PYTHON_SETUP_TEARDOWN = [
119
+ ['setup_class', 'teardown_class'],
120
+ ['setUpClass', 'tearDownClass'],
121
+ ];
122
+ export const JS_SETUP_TEARDOWN = [['beforeAll', 'afterAll']];
123
+
124
+ // SV001: mutable-literal declarations and the mutations that indict them.
125
+ // Python: NAME = {} | [] | set() | dict() | list() (optional trailing #comment)
126
+ export const PY_MODULE_MUTABLE =
127
+ /^(\w+)\s*=\s*(?:\{[^}]*\}|\[[^\]]*\]|set\(\)|dict\(\)|list\(\))\s*(?:#.*)?$/;
128
+ // JS: (let|var|const) NAME = {} | []
129
+ export const JS_MODULE_MUTABLE =
130
+ /^(?:let|var|const)\s+(\w+)\s*=\s*(?:\{[^}]*\}|\[[^\]]*\])/;
131
+
132
+ // Method calls that mutate a container in place (Python + JS array/object).
133
+ const MUTATING_METHODS = [
134
+ 'append',
135
+ 'add',
136
+ 'update',
137
+ 'extend',
138
+ 'insert',
139
+ 'pop',
140
+ 'clear',
141
+ 'setdefault',
142
+ 'remove',
143
+ 'discard',
144
+ 'push',
145
+ 'unshift',
146
+ 'splice',
147
+ ];
148
+
149
+ const RE_META = /[.*+?^${}()|[\]\\]/g;
150
+ const escapeRe = (s) => s.replace(RE_META, '\\$&');
151
+
152
+ /**
153
+ * A pattern matching an in-place mutation of `name`
154
+ * (index assign, mutating method, +=, or attribute/property set).
155
+ * @param {string} name
156
+ * @returns {RegExp}
157
+ */
158
+ export function mutationPattern(name) {
159
+ const n = escapeRe(name);
160
+ const methods = MUTATING_METHODS.join('|');
161
+ // \bNAME[...] = ... | \bNAME.method( | \bNAME += | \bNAME.attr = ...
162
+ return new RegExp(
163
+ `\\b${n}\\s*\\[[^\\]]*\\]\\s*=(?!=)` +
164
+ `|\\b${n}\\s*\\.\\s*(?:${methods})\\s*\\(` +
165
+ `|\\b${n}\\s*\\+=` +
166
+ `|\\b${n}\\s*\\.\\w+\\s*=(?!=)`,
167
+ );
168
+ }