@xulthekl/team-flow 0.31.0 → 0.32.2
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/always/phase-guard.md +1 -1
- package/.claude-plugin/marketplace.json +3 -3
- package/.claude-plugin/plugin.json +1 -1
- package/.codex-plugin/plugin.json +2 -2
- package/.cursor-plugin/marketplace.json +2 -2
- package/.cursor-plugin/plugin.json +2 -2
- package/.github/plugin/marketplace.json +2 -2
- package/AGENTS.md +3 -3
- package/CHANGELOG.md +69 -0
- package/GEMINI.md +1 -1
- package/HANDOFF.md +1 -1
- package/INSTALL.md +1 -1
- package/README.md +2 -2
- package/agents/contract-builder.md +6 -1
- package/docs/README_en.md +1 -1
- package/docs/solutions/INDEX.md +2 -0
- package/docs/solutions/cross-phase/2026-08-01-no-summary.md +17 -0
- package/docs/solutions/cross-phase/2026-08-03-no-summary.md +17 -0
- package/gemini-extension.json +2 -2
- package/hooks/pre-tool-use-guard +43 -2
- package/hooks/session-start +2 -2
- package/llms.txt +1 -1
- package/package.json +6 -2
- package/plugin.json +1 -1
- package/scripts/guard/checks/test-gate-exemptions.mjs +53 -0
- package/scripts/guard/checks/test-matrix-complete.mjs +54 -30
- package/scripts/guard/checks/test-matrix-ready.mjs +60 -0
- package/scripts/guard/checks/tests-passing.mjs +112 -24
- package/scripts/guard/guard.mjs +11 -2
- package/scripts/lib/cmd-doctor.mjs +43 -1
- package/scripts/lib/cmd-execution.mjs +24 -1
- package/scripts/lib/cmd-state.mjs +28 -5
- package/scripts/lib/cmd-validate.mjs +42 -0
- package/scripts/lib/cmd-version.mjs +26 -21
- package/scripts/lib/execution-plan.mjs +23 -0
- package/scripts/lib/state-loader.mjs +16 -2
- package/scripts/lib/test-record.mjs +212 -0
- package/scripts/team-flow.mjs +3 -0
- package/skills/contract-builder/SKILL.md +9 -10
- package/skills/release-archivist/SKILL.md +16 -9
- package/skills/session-handoff/SKILL.md +1 -0
- package/skills/workflow-start/SKILL.md +5 -3
- package/skills/workflow-start/references/routing-rules.md +10 -6
- package/tests/e2e.test.mjs +0 -266
- package/tests/lib/cmd-audit.test.mjs +0 -202
- package/tests/lib/cmd-checkpoint.test.mjs +0 -98
- package/tests/lib/cmd-config.test.mjs +0 -101
- package/tests/lib/cmd-doctor.test.mjs +0 -450
- package/tests/lib/cmd-execution.test.mjs +0 -647
- package/tests/lib/cmd-handoff.test.mjs +0 -137
- package/tests/lib/cmd-inject.test.mjs +0 -218
- package/tests/lib/cmd-install-workbuddy.test.mjs +0 -113
- package/tests/lib/cmd-install-zcode.test.mjs +0 -42
- package/tests/lib/cmd-isolate.test.mjs +0 -68
- package/tests/lib/cmd-list.test.mjs +0 -127
- package/tests/lib/cmd-runtime.test.mjs +0 -83
- package/tests/lib/cmd-state-missing.test.mjs +0 -65
- package/tests/lib/cmd-state.test.mjs +0 -365
- package/tests/lib/cmd-sync-paths.test.mjs +0 -84
- package/tests/lib/cmd-validate-paths.test.mjs +0 -90
- package/tests/lib/config-loader.test.mjs +0 -175
- package/tests/lib/ensure-branch.test.mjs +0 -110
- package/tests/lib/execution-control-plane.test.mjs +0 -168
- package/tests/lib/execution-plan.test.mjs +0 -474
- package/tests/lib/guard-compound-captured.test.mjs +0 -92
- package/tests/lib/guard-specs-merged.test.mjs +0 -110
- package/tests/lib/guard-tests-passing.test.mjs +0 -114
- package/tests/lib/guard-transitions.test.mjs +0 -262
- package/tests/lib/guard.test.mjs +0 -613
- package/tests/lib/hash.test.mjs +0 -138
- package/tests/lib/infer-workflow.test.mjs +0 -161
- package/tests/lib/install-git-hooks.test.mjs +0 -20
- package/tests/lib/marketplace-release-docs.test.mjs +0 -31
- package/tests/lib/minimality-discipline.test.mjs +0 -37
- package/tests/lib/model-profiles-docs.test.mjs +0 -33
- package/tests/lib/node20-compatibility.test.mjs +0 -73
- package/tests/lib/node20-test-entry.test.mjs +0 -17
- package/tests/lib/platform-runtime-distribution.test.mjs +0 -157
- package/tests/lib/raw-mode-smoke.test.mjs +0 -42
- package/tests/lib/sdd-overlay.test.mjs +0 -118
- package/tests/lib/solutions-capture.test.mjs +0 -108
- package/tests/lib/solutions-index-gen.test.mjs +0 -147
- package/tests/lib/solutions-inject.test.mjs +0 -115
- package/tests/lib/solutions-promote.test.mjs +0 -200
- package/tests/lib/spec-paths.test.mjs +0 -80
- package/tests/lib/state-loader.test.mjs +0 -251
- package/tests/lib/token-baseline.test.mjs +0 -72
- package/tests/lib/token-rules.test.mjs +0 -94
- package/tests/lib/verify-marketplace-release.test.mjs +0 -128
- package/tests/tsconfig.json +0 -12
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
// tests/lib/token-baseline.test.mjs
|
|
2
|
-
// Tests for scripts/token-baseline.mjs — measurement and comparison
|
|
3
|
-
|
|
4
|
-
import { describe, it } from 'node:test';
|
|
5
|
-
import assert from 'node:assert/strict';
|
|
6
|
-
import { execSync } from 'node:child_process';
|
|
7
|
-
import { writeFileSync, unlinkSync, readFileSync } from 'node:fs';
|
|
8
|
-
import { join } from 'node:path';
|
|
9
|
-
import { tmpdir } from 'node:os';
|
|
10
|
-
|
|
11
|
-
const BASELINE_PATH = join(process.cwd(), 'scripts/token-baseline.mjs');
|
|
12
|
-
const TMP = tmpdir();
|
|
13
|
-
|
|
14
|
-
describe('token-baseline: measurement', () => {
|
|
15
|
-
it('outputs valid JSON with components and totals', () => {
|
|
16
|
-
const out = execSync(`node "${BASELINE_PATH}" --files hooks/session-start`, { encoding: 'utf-8' });
|
|
17
|
-
const data = JSON.parse(out);
|
|
18
|
-
assert.ok(Array.isArray(data.components), 'components should be an array');
|
|
19
|
-
assert.ok(data.components.length > 0, 'should have at least one component');
|
|
20
|
-
const c = data.components[0];
|
|
21
|
-
assert.ok(typeof c.lines === 'number' && c.lines > 0, 'lines should be positive');
|
|
22
|
-
assert.ok(typeof c.chars === 'number' && c.chars > 0, 'chars should be positive');
|
|
23
|
-
assert.ok(typeof c.estimatedTokens === 'number' && c.estimatedTokens > 0, 'estimatedTokens should be positive');
|
|
24
|
-
assert.ok(typeof data.totals === 'object', 'totals should be an object');
|
|
25
|
-
assert.ok(data.totals.estimatedTokens > 0, 'total estimatedTokens should be positive');
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
it('--files filter limits output', () => {
|
|
29
|
-
const out = execSync(`node "${BASELINE_PATH}" --files hooks/session-start`, { encoding: 'utf-8' });
|
|
30
|
-
const data = JSON.parse(out);
|
|
31
|
-
assert.equal(data.components.length, 1, 'should only have one component');
|
|
32
|
-
assert.ok(data.components[0].path.includes('hooks/session-start'), 'should be the filtered file');
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
it('--output writes to file', () => {
|
|
36
|
-
const outPath = join(TMP, 'token-baseline-test.json');
|
|
37
|
-
execSync(`node "${BASELINE_PATH}" --files hooks/session-start --output "${outPath}"`, { encoding: 'utf-8' });
|
|
38
|
-
const data = JSON.parse(readFileSync(outPath, 'utf-8'));
|
|
39
|
-
assert.ok(data.totals.estimatedTokens > 0, 'file should contain valid data');
|
|
40
|
-
unlinkSync(outPath);
|
|
41
|
-
});
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
describe('token-baseline: comparison', () => {
|
|
45
|
-
it('--compare produces change deltas', () => {
|
|
46
|
-
const baselinePath = join(TMP, 'baseline-cmp-test.json');
|
|
47
|
-
// Create a baseline with slightly different values
|
|
48
|
-
const baseline = {
|
|
49
|
-
timestamp: '2026-01-01T00:00:00Z',
|
|
50
|
-
components: [
|
|
51
|
-
{ path: 'hooks/session-start', label: 'hooks/session-start', lines: 30, chars: 2000, estimatedTokens: 500 },
|
|
52
|
-
],
|
|
53
|
-
totals: { lines: 30, chars: 2000, estimatedTokens: 500 },
|
|
54
|
-
};
|
|
55
|
-
writeFileSync(baselinePath, JSON.stringify(baseline));
|
|
56
|
-
|
|
57
|
-
const out = execSync(`node "${BASELINE_PATH}" --files hooks/session-start --compare "${baselinePath}"`, { encoding: 'utf-8' });
|
|
58
|
-
const data = JSON.parse(out);
|
|
59
|
-
assert.ok(Array.isArray(data.changes), 'should have changes array');
|
|
60
|
-
assert.ok(data.changes.length > 0, 'should have at least one change');
|
|
61
|
-
assert.ok(typeof data.summary.totalDelta === 'number', 'should have totalDelta');
|
|
62
|
-
assert.ok(typeof data.summary.totalPct === 'string', 'should have totalPct');
|
|
63
|
-
|
|
64
|
-
unlinkSync(baselinePath);
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
it('missing file in baseline reports error', () => {
|
|
68
|
-
const out = execSync(`node "${BASELINE_PATH}" --files hooks/session-start --compare /nonexistent/baseline.json 2>&1 || true`, { encoding: 'utf-8' });
|
|
69
|
-
// Should fail gracefully — error message from file not found
|
|
70
|
-
assert.ok(out.length > 0, 'should produce output even on error');
|
|
71
|
-
});
|
|
72
|
-
});
|
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
// tests/lib/token-rules.test.mjs
|
|
2
|
-
// Tests for scripts/lint/rules/token-rules.mjs — lint rule functions
|
|
3
|
-
|
|
4
|
-
import { describe, it } from 'node:test';
|
|
5
|
-
import assert from 'node:assert/strict';
|
|
6
|
-
import { checkMaxLines, checkMaxChars, checkMaxEmphasisMarkers, checkMaxCodeBlockLength } from '../../scripts/lint/rules/token-rules.mjs';
|
|
7
|
-
|
|
8
|
-
const CTX = { skillDirs: ['test-skill'], skillsDir: '/fake/skills' };
|
|
9
|
-
|
|
10
|
-
describe('token-rules: checkMaxLines', () => {
|
|
11
|
-
it('passes when under limit', async () => {
|
|
12
|
-
const issues = await checkMaxLines('test', 'line1\nline2\nline3', CTX, 10);
|
|
13
|
-
assert.equal(issues.length, 0);
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
it('fails when over limit', async () => {
|
|
17
|
-
const content = Array(251).fill('line').join('\n');
|
|
18
|
-
const issues = await checkMaxLines('test', content, CTX, 250);
|
|
19
|
-
assert.equal(issues.length, 1);
|
|
20
|
-
assert.equal(issues[0].severity, 'error');
|
|
21
|
-
assert.ok(issues[0].message.includes('251'));
|
|
22
|
-
});
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
describe('token-rules: checkMaxChars', () => {
|
|
26
|
-
it('passes when under limit', async () => {
|
|
27
|
-
const issues = await checkMaxChars('test', 'short', CTX, 100);
|
|
28
|
-
assert.equal(issues.length, 0);
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
it('warns when over limit', async () => {
|
|
32
|
-
const content = 'x'.repeat(10001);
|
|
33
|
-
const issues = await checkMaxChars('test', content, CTX, 10000);
|
|
34
|
-
assert.equal(issues.length, 1);
|
|
35
|
-
assert.equal(issues[0].severity, 'warning');
|
|
36
|
-
});
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
describe('token-rules: checkMaxEmphasisMarkers', () => {
|
|
40
|
-
it('passes for content without banned markers', async () => {
|
|
41
|
-
const issues = await checkMaxEmphasisMarkers('test', 'normal text with **some** emphasis', CTX, 30);
|
|
42
|
-
assert.equal(issues.length, 0);
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
it('detects EXTREMELY_IMPORTANT', async () => {
|
|
46
|
-
const issues = await checkMaxEmphasisMarkers('test', 'This is EXTREMELY_IMPORTANT content', CTX, 30);
|
|
47
|
-
const eiIssue = issues.find(i => i.message.includes('EXTREMELY_IMPORTANT'));
|
|
48
|
-
assert.ok(eiIssue, 'should flag EXTREMELY_IMPORTANT');
|
|
49
|
-
assert.equal(eiIssue.severity, 'error');
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
it('detects CRITICAL', async () => {
|
|
53
|
-
const issues = await checkMaxEmphasisMarkers('test', 'CRITICAL: do not skip', CTX, 30);
|
|
54
|
-
const crIssue = issues.find(i => i.message.includes('CRITICAL'));
|
|
55
|
-
assert.ok(crIssue, 'should flag CRITICAL');
|
|
56
|
-
assert.equal(crIssue.severity, 'error');
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
it('warns on too many IMPORTANT occurrences', async () => {
|
|
60
|
-
const content = 'IMPORTANT\n'.repeat(5) + 'text';
|
|
61
|
-
const issues = await checkMaxEmphasisMarkers('test', content, CTX, 30);
|
|
62
|
-
const impIssue = issues.find(i => i.message.includes('IMPORTANT'));
|
|
63
|
-
assert.ok(impIssue, 'should flag excessive IMPORTANT');
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
it('warns on too many emphasis markers', async () => {
|
|
67
|
-
const content = '**a** **b** '.repeat(31);
|
|
68
|
-
const issues = await checkMaxEmphasisMarkers('test', content, CTX, 30);
|
|
69
|
-
const empIssue = issues.find(i => i.message.includes('emphasis markers'));
|
|
70
|
-
assert.ok(empIssue, 'should flag excessive emphasis');
|
|
71
|
-
assert.equal(empIssue.severity, 'warning');
|
|
72
|
-
});
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
describe('token-rules: checkMaxCodeBlockLength', () => {
|
|
76
|
-
it('passes for short code blocks', async () => {
|
|
77
|
-
const issues = await checkMaxCodeBlockLength('test', '```\nline1\nline2\n```', CTX, 5);
|
|
78
|
-
assert.equal(issues.length, 0);
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
it('warns for long code blocks', async () => {
|
|
82
|
-
const lines = Array(17).fill('code').join('\n');
|
|
83
|
-
const content = '```\n' + lines + '\n```';
|
|
84
|
-
const issues = await checkMaxCodeBlockLength('test', content, CTX, 15);
|
|
85
|
-
assert.equal(issues.length, 1);
|
|
86
|
-
assert.equal(issues[0].severity, 'warning');
|
|
87
|
-
assert.ok(issues[0].message.includes('19'), `expected message to include '19', got: ${issues[0].message}`);
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
it('handles content with no code blocks', async () => {
|
|
91
|
-
const issues = await checkMaxCodeBlockLength('test', 'just text, no code', CTX, 15);
|
|
92
|
-
assert.equal(issues.length, 0);
|
|
93
|
-
});
|
|
94
|
-
});
|
|
@@ -1,128 +0,0 @@
|
|
|
1
|
-
import { describe, it } from 'node:test';
|
|
2
|
-
import assert from 'node:assert/strict';
|
|
3
|
-
import { spawnSync } from 'node:child_process';
|
|
4
|
-
import {
|
|
5
|
-
main,
|
|
6
|
-
parseReleaseCheckArgs,
|
|
7
|
-
verifyMarketplaceRelease,
|
|
8
|
-
} from '../../scripts/verify-marketplace-release.mjs';
|
|
9
|
-
|
|
10
|
-
const response = ({ ok = true, status = 200, body = { version: '0.9.0' } } = {}) => ({
|
|
11
|
-
ok,
|
|
12
|
-
status,
|
|
13
|
-
async json() { return body; },
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
describe('verify marketplace release', () => {
|
|
17
|
-
it('accepts a matching HTTPS manifest version', async () => {
|
|
18
|
-
const result = await verifyMarketplaceRelease({
|
|
19
|
-
manifestUrl: 'https://example.test/plugin.json',
|
|
20
|
-
expectedVersion: '0.9.0',
|
|
21
|
-
fetchImpl: async () => response(),
|
|
22
|
-
});
|
|
23
|
-
assert.equal(result.actualVersion, '0.9.0');
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
it('rejects HTTP, malformed, network, and version-drift responses', async () => {
|
|
27
|
-
await assert.rejects(
|
|
28
|
-
() => verifyMarketplaceRelease({
|
|
29
|
-
manifestUrl: 'https://example.test/plugin.json',
|
|
30
|
-
expectedVersion: '0.9.0',
|
|
31
|
-
fetchImpl: async () => response({ ok: false, status: 404 }),
|
|
32
|
-
}),
|
|
33
|
-
/HTTP 404/,
|
|
34
|
-
);
|
|
35
|
-
await assert.rejects(
|
|
36
|
-
() => verifyMarketplaceRelease({
|
|
37
|
-
manifestUrl: 'https://example.test/plugin.json',
|
|
38
|
-
expectedVersion: '0.9.0',
|
|
39
|
-
fetchImpl: async () => response({ body: { name: 'team-flow' } }),
|
|
40
|
-
}),
|
|
41
|
-
/missing a string version/,
|
|
42
|
-
);
|
|
43
|
-
await assert.rejects(
|
|
44
|
-
() => verifyMarketplaceRelease({
|
|
45
|
-
manifestUrl: 'https://example.test/plugin.json',
|
|
46
|
-
expectedVersion: '0.9.0',
|
|
47
|
-
fetchImpl: async () => ({
|
|
48
|
-
ok: true,
|
|
49
|
-
status: 200,
|
|
50
|
-
async json() { throw new Error('unexpected token'); },
|
|
51
|
-
}),
|
|
52
|
-
}),
|
|
53
|
-
/marketplace manifest is not valid JSON: unexpected token/,
|
|
54
|
-
);
|
|
55
|
-
await assert.rejects(
|
|
56
|
-
() => verifyMarketplaceRelease({
|
|
57
|
-
manifestUrl: 'https://example.test/plugin.json',
|
|
58
|
-
expectedVersion: '0.9.0',
|
|
59
|
-
fetchImpl: async () => { throw new Error('socket closed'); },
|
|
60
|
-
}),
|
|
61
|
-
/network request failed: socket closed/,
|
|
62
|
-
);
|
|
63
|
-
await assert.rejects(
|
|
64
|
-
() => verifyMarketplaceRelease({
|
|
65
|
-
manifestUrl: 'https://example.test/plugin.json',
|
|
66
|
-
expectedVersion: '0.9.0',
|
|
67
|
-
fetchImpl: async () => response({ body: { version: '0.8.17' } }),
|
|
68
|
-
}),
|
|
69
|
-
/expected 0.9.0, found 0.8.17/,
|
|
70
|
-
);
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
it('requires one HTTPS URL and one complete semver argument', () => {
|
|
74
|
-
assert.throws(() => parseReleaseCheckArgs([]), /Usage:/);
|
|
75
|
-
assert.throws(
|
|
76
|
-
() => parseReleaseCheckArgs([
|
|
77
|
-
'--manifest-url', 'http://example.test/plugin.json',
|
|
78
|
-
'--expected-version', '0.9.0',
|
|
79
|
-
]),
|
|
80
|
-
/HTTPS/,
|
|
81
|
-
);
|
|
82
|
-
assert.throws(
|
|
83
|
-
() => parseReleaseCheckArgs([
|
|
84
|
-
'--manifest-url', 'https://example.test/plugin.json',
|
|
85
|
-
'--expected-version', '0.9',
|
|
86
|
-
]),
|
|
87
|
-
/x\.y\.z/,
|
|
88
|
-
);
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
it('writes exact success and error messages through injected streams', async () => {
|
|
92
|
-
const stdout = [];
|
|
93
|
-
const stderr = [];
|
|
94
|
-
const args = [
|
|
95
|
-
'--manifest-url', 'https://example.test/plugin.json',
|
|
96
|
-
'--expected-version', '0.9.0',
|
|
97
|
-
];
|
|
98
|
-
const streams = {
|
|
99
|
-
stdout: { write: (message) => stdout.push(message) },
|
|
100
|
-
stderr: { write: (message) => stderr.push(message) },
|
|
101
|
-
};
|
|
102
|
-
|
|
103
|
-
assert.equal(await main(args, {
|
|
104
|
-
...streams,
|
|
105
|
-
fetchImpl: async () => response(),
|
|
106
|
-
}), 0);
|
|
107
|
-
assert.deepEqual(stdout, ['Marketplace manifest verified: 0.9.0 (https://example.test/plugin.json)\n']);
|
|
108
|
-
assert.deepEqual(stderr, []);
|
|
109
|
-
|
|
110
|
-
assert.equal(await main(args, {
|
|
111
|
-
...streams,
|
|
112
|
-
fetchImpl: async () => response({ body: { version: '0.8.17' } }),
|
|
113
|
-
}), 1);
|
|
114
|
-
assert.deepEqual(stderr, ['Error: marketplace version mismatch: expected 0.9.0, found 0.8.17\n']);
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
it('does not set process.exitCode when imported', () => {
|
|
118
|
-
const scriptUrl = new URL('../../scripts/verify-marketplace-release.mjs', import.meta.url).href;
|
|
119
|
-
const result = spawnSync(process.execPath, [
|
|
120
|
-
'--input-type=module',
|
|
121
|
-
'--eval',
|
|
122
|
-
`await import(${JSON.stringify(scriptUrl)}); if (process.exitCode !== undefined) throw new Error('process.exitCode was set');`,
|
|
123
|
-
], { encoding: 'utf8' });
|
|
124
|
-
|
|
125
|
-
assert.equal(result.status, 0, result.stderr);
|
|
126
|
-
assert.equal(result.stderr, '');
|
|
127
|
-
});
|
|
128
|
-
});
|
package/tests/tsconfig.json
DELETED