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.
- package/agents/skills/README.md +308 -0
- package/agents/skills/canary:generate.md +49 -0
- package/agents/skills/canary:init.md +37 -0
- package/agents/skills/canary:migrate.md +66 -0
- package/agents/skills/claude-code/canary-add-framework/SKILL.md +248 -0
- package/agents/skills/claude-code/canary-blackhawk/SKILL.md +170 -0
- package/agents/skills/claude-code/canary-blackhawk/scripts/cli.mjs +188 -0
- package/agents/skills/claude-code/canary-blackhawk/scripts/rules.mjs +120 -0
- package/agents/skills/claude-code/canary-blackhawk/scripts/scanner.mjs +244 -0
- package/agents/skills/claude-code/canary-blackhawk/scripts/string-literals.mjs +116 -0
- package/agents/skills/claude-code/canary-cassandra/SKILL.md +180 -0
- package/agents/skills/claude-code/canary-cassandra/scripts/cli.mjs +268 -0
- package/agents/skills/claude-code/canary-cassandra/scripts/engine.mjs +95 -0
- package/agents/skills/claude-code/canary-ci-ready/SKILL.md +161 -0
- package/agents/skills/claude-code/canary-ci-ready/skill.yaml +14 -0
- package/agents/skills/claude-code/canary-company-knowledge/SKILL.md +196 -0
- package/agents/skills/claude-code/canary-critical-areas/SKILL.md +142 -0
- package/agents/skills/claude-code/canary-critical-areas/skill.yaml +16 -0
- package/agents/skills/claude-code/canary-edge-case-discovery/SKILL.md +160 -0
- package/agents/skills/claude-code/canary-edge-case-discovery/skill.yaml +16 -0
- package/agents/skills/claude-code/canary-fail-fast/SKILL.md +75 -0
- package/agents/skills/claude-code/canary-fail-fast/scripts/cli.mjs +118 -0
- package/agents/skills/claude-code/canary-fail-fast/scripts/digest.mjs +69 -0
- package/agents/skills/claude-code/canary-fail-fast/scripts/failures.mjs +60 -0
- package/agents/skills/claude-code/canary-fail-fast/scripts/fastfail_check.mjs +43 -0
- package/agents/skills/claude-code/canary-fail-fast/scripts/parse.mjs +149 -0
- package/agents/skills/claude-code/canary-failure-impact/SKILL.md +153 -0
- package/agents/skills/claude-code/canary-failure-impact/skill.yaml +15 -0
- package/agents/skills/claude-code/canary-fleet-health/SKILL.md +196 -0
- package/agents/skills/claude-code/canary-generate-test/SKILL.md +185 -0
- package/agents/skills/claude-code/canary-instrument/SKILL.md +157 -0
- package/agents/skills/claude-code/canary-instrument/scripts/cli.mjs +178 -0
- package/agents/skills/claude-code/canary-instrument/scripts/otel_bootstrap/instrument.mjs +96 -0
- package/agents/skills/claude-code/canary-instrument/scripts/otel_bootstrap/playwright-fixture.ts +44 -0
- package/agents/skills/claude-code/canary-instrument/scripts/run_types.mjs +81 -0
- package/agents/skills/claude-code/canary-instrument/scripts/span_reader.mjs +187 -0
- package/agents/skills/claude-code/canary-katana/SKILL.md +243 -0
- package/agents/skills/claude-code/canary-katana/scripts/alarm.mjs +296 -0
- package/agents/skills/claude-code/canary-katana/scripts/cli.mjs +247 -0
- package/agents/skills/claude-code/canary-katana/scripts/diffscan.mjs +0 -0
- package/agents/skills/claude-code/canary-katana/scripts/ledger.mjs +183 -0
- package/agents/skills/claude-code/canary-pr-guardian/SKILL.md +129 -0
- package/agents/skills/claude-code/canary-pr-guardian/skill.yaml +17 -0
- package/agents/skills/claude-code/canary-promote-test/SKILL.md +228 -0
- package/agents/skills/claude-code/canary-savant/SKILL.md +233 -0
- package/agents/skills/claude-code/canary-savant/scripts/cli.mjs +274 -0
- package/agents/skills/claude-code/canary-savant/scripts/restoration.mjs +274 -0
- package/agents/skills/claude-code/canary-savant/scripts/rules.mjs +168 -0
- package/agents/skills/claude-code/canary-savant/scripts/runner.mjs +572 -0
- package/agents/skills/claude-code/canary-savant/scripts/scanner.mjs +374 -0
- package/agents/skills/claude-code/canary-savant/scripts/string-literals.mjs +116 -0
- package/agents/skills/claude-code/canary-setup-harness/SKILL.md +263 -0
- package/agents/skills/claude-code/canary-shadow/SKILL.md +131 -0
- package/agents/skills/claude-code/canary-shadow/scripts/cases.example.json +32 -0
- package/agents/skills/claude-code/canary-shadow/scripts/cli.mjs +195 -0
- package/agents/skills/claude-code/canary-ship/SKILL.md +177 -0
- package/agents/skills/claude-code/canary-ship/skill.yaml +16 -0
- package/agents/skills/claude-code/canary-strix/SKILL.md +130 -0
- package/agents/skills/claude-code/canary-strix/scripts/cli.mjs +255 -0
- package/agents/skills/claude-code/canary-strix/scripts/scanner.mjs +252 -0
- package/agents/skills/claude-code/canary-strix/scripts/terms.mjs +132 -0
- package/agents/skills/claude-code/canary-test-pipeline/SKILL.md +159 -0
- package/agents/skills/claude-code/canary-test-pipeline/skill.yaml +19 -0
- package/agents/skills/claude-code/canary-test-reporter/SKILL.md +138 -0
- package/agents/skills/claude-code/canary-test-reporter/scripts/cli.mjs +98 -0
- package/agents/skills/claude-code/canary-test-reporter/scripts/json_report.mjs +58 -0
- package/agents/skills/claude-code/canary-test-reporter/scripts/parse.mjs +216 -0
- package/agents/skills/claude-code/canary-test-reporter/scripts/render.mjs +114 -0
- package/agents/skills/lib/parse-args.mjs +214 -0
- package/dist/engine/analysis/cli.js +116 -54
- package/dist/engine/analysis/engine.js +34 -16
- package/dist/engine/analysis/reports.js +5 -4
- package/dist/engine/cli-commands.js +252 -106
- package/dist/engine/cli-common.js +15 -24
- package/dist/engine/cli.core.js +37 -11
- package/dist/engine/cli.js +2 -2
- package/dist/engine/company-knowledge-cli.js +2 -2
- package/dist/engine/core/adoption.js +408 -0
- package/dist/engine/core/framework-probes.js +7 -7
- package/dist/engine/core/fs-glob.js +2 -2
- package/dist/engine/core/gate-result.js +17 -0
- package/dist/engine/core/migrator.js +9 -17
- package/dist/engine/core/pattern-matcher.js +23 -5
- package/dist/engine/core/persona.js +421 -0
- package/dist/engine/core/promotion-verdict.js +261 -0
- package/dist/engine/core/quality-scorer.js +15 -2
- package/dist/engine/core/reporter.js +1 -9
- package/dist/engine/core/skill-dispatch.js +115 -0
- package/dist/engine/core/skill-examples.js +392 -0
- package/dist/engine/core/skill-registry.js +59 -4
- package/dist/engine/core/skill-surfaces.js +307 -0
- package/dist/engine/core/static-linter.js +310 -38
- package/dist/engine/core/test-files.js +77 -0
- package/dist/engine/core/ticket-updater.js +1 -7
- package/dist/engine/core/vacuity-scanner.js +726 -0
- package/dist/engine/core/workflow-discovery.js +2 -8
- package/dist/engine/core/workspace-detect.js +7 -6
- package/dist/engine/data/personas/registry.json +36 -0
- package/dist/engine/guardian/adjudication.js +5 -5
- package/dist/engine/guardian/analysis-emit.js +19 -28
- package/dist/engine/guardian/cli.js +150 -51
- package/dist/engine/guardian/coverage.js +1 -1
- package/dist/engine/guardian/diff-coverage/heuristic-tier.js +1 -1
- package/dist/engine/guardian/diff-coverage/orchestrator.js +2 -2
- package/dist/engine/guardian/pr-check.js +322 -33
- package/dist/engine/guardian/pr-comment.js +4 -3
- package/dist/engine/history/cli.js +210 -6
- package/dist/engine/history/ndjson-store.js +9 -5
- package/dist/engine/history/record.js +34 -5
- package/dist/engine/history/run-recorder.js +165 -0
- package/dist/engine/history/schema.js +25 -7
- package/dist/engine/history/store.js +9 -0
- package/dist/engine/mcp-server.js +35 -13
- package/dist/engine/skills-cli.js +249 -23
- package/dist/engine/util/ensure-ascii.js +37 -0
- package/dist/engine/workflow-cli.js +6 -6
- package/dist/gate-result.d.ts +11 -0
- package/dist/gate-result.js +18 -0
- package/dist/reporters/testtracker.d.ts +1 -1
- package/dist/reporters/testtracker.js +1 -1
- package/dist/uninstall.js +12 -5
- 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
|
+
}
|