kushi-agents 5.0.4 → 5.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/README.md +78 -0
- package/bin/cli.mjs +201 -1
- package/package.json +2 -2
- package/plugin/agents/kushi.agent.md +6 -2
- package/plugin/instructions/hooks.instructions.md +84 -0
- package/plugin/instructions/living-wiki.instructions.md +88 -0
- package/plugin/instructions/log-format.instructions.md +78 -0
- package/plugin/instructions/otel.instructions.md +75 -0
- package/plugin/instructions/parallel-execution.instructions.md +81 -0
- package/plugin/instructions/schema-evolve.instructions.md +73 -0
- package/plugin/instructions/wiki-lint.instructions.md +110 -0
- package/plugin/skills/_shared/Append-StateLog.ps1 +73 -0
- package/plugin/skills/_shared/Emit-OtelSpan.ps1 +111 -0
- package/plugin/skills/_shared/Invoke-Hooks.ps1 +177 -0
- package/plugin/skills/_shared/Update-StateIndex.ps1 +47 -0
- package/plugin/skills/_shared/hook-templates/console-debug.ps1 +15 -0
- package/plugin/skills/_shared/hook-templates/teams-notify.ps1 +47 -0
- package/plugin/skills/ask-project/SKILL.md +30 -0
- package/plugin/skills/build-state/SKILL.md +18 -2
- package/plugin/skills/lint-state/.created-by-skill-creator +0 -0
- package/plugin/skills/lint-state/SKILL.md +98 -0
- package/plugin/skills/lint-state/evals/evals.json +34 -0
- package/plugin/skills/lint-state/lint.ps1 +218 -0
- package/plugin/skills/refresh-project/SKILL.md +8 -4
- package/plugin/skills/schema-evolve/.created-by-skill-creator +0 -0
- package/plugin/skills/schema-evolve/SKILL.md +106 -0
- package/plugin/skills/schema-evolve/evals/evals.json +37 -0
- package/plugin/skills/self-check/SKILL.md +12 -55
- package/plugin/skills/self-check/references/algorithm.md +55 -0
- package/plugin/skills/self-check/run.ps1 +225 -3
- package/plugin/skills/skill-checker/check-skill.ps1 +1 -1
- package/plugin/skills/teach/.created-by-skill-creator +0 -0
- package/plugin/skills/teach/SKILL.md +77 -0
- package/plugin/skills/teach/evals/evals.json +37 -0
- package/plugin/templates/state/answers.README.md +7 -0
- package/plugin/templates/state/hot.template.md +12 -0
- package/plugin/templates/state/review-queue.template.md +10 -0
- package/src/eval-runner.test.mjs +1 -1
- package/src/hooks-dispatcher.test.mjs +135 -0
- package/src/otel-emit.test.mjs +73 -0
- package/src/parallel-refresh.test.mjs +50 -0
- package/src/schema-evolve.test.mjs +78 -0
- package/src/teach.test.mjs +45 -0
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
// kushi v5.2.0 — parallel refresh tests.
|
|
2
|
+
// Validates worker pool mechanics, failure aggregation, and --sequential flag.
|
|
3
|
+
|
|
4
|
+
import test from 'node:test';
|
|
5
|
+
import assert from 'node:assert/strict';
|
|
6
|
+
import fs from 'node:fs';
|
|
7
|
+
import path from 'node:path';
|
|
8
|
+
import { fileURLToPath } from 'node:url';
|
|
9
|
+
|
|
10
|
+
const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
|
|
11
|
+
|
|
12
|
+
test('parallel: refresh-project SKILL.md documents parallel dispatch', () => {
|
|
13
|
+
const skillFile = path.join(repoRoot, 'plugin', 'skills', 'refresh-project', 'SKILL.md');
|
|
14
|
+
const content = fs.readFileSync(skillFile, 'utf8');
|
|
15
|
+
// Must reference parallel dispatch
|
|
16
|
+
assert.match(content, /parallel/i, 'refresh-project must mention parallel dispatch');
|
|
17
|
+
assert.match(content, /sequential/i, 'refresh-project must mention --sequential fallback');
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
test('parallel: parallel-execution doctrine exists and has key sections', () => {
|
|
21
|
+
const doctrine = path.join(repoRoot, 'plugin', 'instructions', 'parallel-execution.instructions.md');
|
|
22
|
+
assert.ok(fs.existsSync(doctrine), 'parallel-execution.instructions.md must exist');
|
|
23
|
+
const content = fs.readFileSync(doctrine, 'utf8');
|
|
24
|
+
assert.match(content, /max_workers/, 'must document max_workers config');
|
|
25
|
+
assert.match(content, /throttle/, 'must document throttling');
|
|
26
|
+
assert.match(content, /error aggregation/i, 'must document error aggregation');
|
|
27
|
+
assert.match(content, /deterministic/i, 'must document deterministic ordering');
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
test('parallel: config supports max_workers setting', () => {
|
|
31
|
+
const doctrine = path.join(repoRoot, 'plugin', 'instructions', 'parallel-execution.instructions.md');
|
|
32
|
+
const content = fs.readFileSync(doctrine, 'utf8');
|
|
33
|
+
// Verify default value documented
|
|
34
|
+
assert.match(content, /default.*4|4.*default/i, 'default max_workers should be 4');
|
|
35
|
+
// Verify sequential = max_workers 1
|
|
36
|
+
assert.match(content, /sequential.*1|1.*sequential/i, '--sequential means max_workers=1');
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
test('parallel: failures in one worker do not halt others', () => {
|
|
40
|
+
// Structural test: verify the doctrine explicitly states this
|
|
41
|
+
const doctrine = path.join(repoRoot, 'plugin', 'instructions', 'parallel-execution.instructions.md');
|
|
42
|
+
const content = fs.readFileSync(doctrine, 'utf8');
|
|
43
|
+
assert.match(content, /failure.*NOT.*halt|independent/i, 'must state workers are independent');
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
test('parallel: refresh-project references parallel-execution doctrine', () => {
|
|
47
|
+
const skillFile = path.join(repoRoot, 'plugin', 'skills', 'refresh-project', 'SKILL.md');
|
|
48
|
+
const content = fs.readFileSync(skillFile, 'utf8');
|
|
49
|
+
assert.match(content, /parallel-execution\.instructions\.md/, 'must cite parallel doctrine');
|
|
50
|
+
});
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
// kushi v5.2.0 — schema-evolve skill tests.
|
|
2
|
+
// Validates rule capture and persistence behavior.
|
|
3
|
+
|
|
4
|
+
import test from 'node:test';
|
|
5
|
+
import assert from 'node:assert/strict';
|
|
6
|
+
import fs from 'node:fs';
|
|
7
|
+
import path from 'node:path';
|
|
8
|
+
import { fileURLToPath } from 'node:url';
|
|
9
|
+
|
|
10
|
+
const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
|
|
11
|
+
|
|
12
|
+
test('schema-evolve: SKILL.md exists with correct structure', () => {
|
|
13
|
+
const skillFile = path.join(repoRoot, 'plugin', 'skills', 'schema-evolve', 'SKILL.md');
|
|
14
|
+
assert.ok(fs.existsSync(skillFile), 'schema-evolve/SKILL.md must exist');
|
|
15
|
+
const content = fs.readFileSync(skillFile, 'utf8');
|
|
16
|
+
assert.match(content, /name:\s*"schema-evolve"/, 'must declare name');
|
|
17
|
+
assert.match(content, /USE WHEN/, 'description must start with USE WHEN');
|
|
18
|
+
assert.match(content, /CLAUDE\.md/, 'must reference CLAUDE.md as storage');
|
|
19
|
+
assert.match(content, /Step checklist/, 'must have step checklist (orchestrator pattern)');
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
test('schema-evolve: doctrine exists and defines rule format', () => {
|
|
23
|
+
const doctrine = path.join(repoRoot, 'plugin', 'instructions', 'schema-evolve.instructions.md');
|
|
24
|
+
assert.ok(fs.existsSync(doctrine), 'schema-evolve.instructions.md must exist');
|
|
25
|
+
const content = fs.readFileSync(doctrine, 'utf8');
|
|
26
|
+
assert.match(content, /## Rule:/, 'must document rule heading format');
|
|
27
|
+
assert.match(content, /Added/, 'must document timestamp field');
|
|
28
|
+
assert.match(content, /Scope/, 'must document scope field');
|
|
29
|
+
assert.match(content, /CLAUDE\.md/, 'must specify CLAUDE.md as storage location');
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
test('schema-evolve: rules stored in CLAUDE.md with proper structure', () => {
|
|
33
|
+
// Create a fixture with a CLAUDE.md and verify format
|
|
34
|
+
const fixture = path.join(repoRoot, '.testtmp', `schema-evolve-${Date.now()}`);
|
|
35
|
+
const stateDir = path.join(fixture, 'Evidence', 'tester', 'State');
|
|
36
|
+
fs.mkdirSync(stateDir, { recursive: true });
|
|
37
|
+
|
|
38
|
+
try {
|
|
39
|
+
// Simulate what schema-evolve would write
|
|
40
|
+
const claudeContent = `---
|
|
41
|
+
kushi_state_page: true
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
# CLAUDE.md — Project Conventions
|
|
45
|
+
|
|
46
|
+
Rules captured via \`schema-evolve\` skill. Read by build-state, ask-project, refresh-project at run start.
|
|
47
|
+
|
|
48
|
+
## Rule: Use HCA abbreviation
|
|
49
|
+
|
|
50
|
+
- **Added**: 2026-05-29T14:30:00Z
|
|
51
|
+
- **Scope**: project
|
|
52
|
+
- **Source**: user (natural language)
|
|
53
|
+
|
|
54
|
+
Always use 'HCA' not 'Healthcare Accelerator' in summaries.
|
|
55
|
+
`;
|
|
56
|
+
const claudePath = path.join(stateDir, 'CLAUDE.md');
|
|
57
|
+
fs.writeFileSync(claudePath, claudeContent);
|
|
58
|
+
|
|
59
|
+
// Verify structure
|
|
60
|
+
const written = fs.readFileSync(claudePath, 'utf8');
|
|
61
|
+
assert.match(written, /kushi_state_page:\s*true/, 'must have frontmatter');
|
|
62
|
+
assert.match(written, /## Rule:/, 'must have rule heading');
|
|
63
|
+
assert.match(written, /\*\*Added\*\*:/, 'must have Added timestamp');
|
|
64
|
+
assert.match(written, /\*\*Scope\*\*:/, 'must have Scope field');
|
|
65
|
+
assert.match(written, /\*\*Source\*\*:/, 'must have Source field');
|
|
66
|
+
} finally {
|
|
67
|
+
fs.rmSync(fixture, { recursive: true, force: true });
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
test('schema-evolve: hard doctrine override detection documented', () => {
|
|
72
|
+
const skillFile = path.join(repoRoot, 'plugin', 'skills', 'schema-evolve', 'SKILL.md');
|
|
73
|
+
const content = fs.readFileSync(skillFile, 'utf8');
|
|
74
|
+
// Must document that WorkIQ-only, CSC, verbatim-by-default cannot be overridden
|
|
75
|
+
assert.match(content, /WorkIQ-only/, 'must mention WorkIQ-only as non-overridable');
|
|
76
|
+
assert.match(content, /verbatim-by-default/, 'must mention verbatim-by-default');
|
|
77
|
+
assert.match(content, /CSC/, 'must mention CSC format');
|
|
78
|
+
});
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
// kushi v5.2.0 — teach skill tests.
|
|
2
|
+
// Validates topic matching and unknown-topic handling.
|
|
3
|
+
|
|
4
|
+
import test from 'node:test';
|
|
5
|
+
import assert from 'node:assert/strict';
|
|
6
|
+
import fs from 'node:fs';
|
|
7
|
+
import path from 'node:path';
|
|
8
|
+
import { fileURLToPath } from 'node:url';
|
|
9
|
+
|
|
10
|
+
const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
|
|
11
|
+
|
|
12
|
+
test('teach: SKILL.md exists and has correct structure', () => {
|
|
13
|
+
const skillFile = path.join(repoRoot, 'plugin', 'skills', 'teach', 'SKILL.md');
|
|
14
|
+
assert.ok(fs.existsSync(skillFile), 'teach/SKILL.md must exist');
|
|
15
|
+
const content = fs.readFileSync(skillFile, 'utf8');
|
|
16
|
+
// Check frontmatter
|
|
17
|
+
assert.match(content, /name:\s*"teach"/, 'must declare name: teach');
|
|
18
|
+
assert.match(content, /USE WHEN/, 'description must start with USE WHEN');
|
|
19
|
+
// Check topic mapping table
|
|
20
|
+
assert.match(content, /contradictions.*living-wiki/i, 'contradictions topic must map to living-wiki');
|
|
21
|
+
assert.match(content, /parallel.*parallel-execution/i, 'parallel topic must map to doctrine');
|
|
22
|
+
assert.match(content, /otel.*otel\.instructions/i, 'otel topic must map to doctrine');
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
test('teach: topic mapping covers all v5.2.0 features', () => {
|
|
26
|
+
const skillFile = path.join(repoRoot, 'plugin', 'skills', 'teach', 'SKILL.md');
|
|
27
|
+
const content = fs.readFileSync(skillFile, 'utf8');
|
|
28
|
+
// Each new v5.2.0 feature should be teachable
|
|
29
|
+
const requiredTopics = ['hooks', 'parallel', 'otel', 'schema'];
|
|
30
|
+
for (const topic of requiredTopics) {
|
|
31
|
+
assert.match(content, new RegExp(topic, 'i'), `teach must cover topic: ${topic}`);
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
test('teach: references existing doctrine files', () => {
|
|
36
|
+
const skillFile = path.join(repoRoot, 'plugin', 'skills', 'teach', 'SKILL.md');
|
|
37
|
+
const content = fs.readFileSync(skillFile, 'utf8');
|
|
38
|
+
// Extract doctrine file references
|
|
39
|
+
const doctrineRefs = content.match(/[\w-]+\.instructions\.md/g) || [];
|
|
40
|
+
// Each referenced doctrine should exist
|
|
41
|
+
for (const ref of doctrineRefs) {
|
|
42
|
+
const docPath = path.join(repoRoot, 'plugin', 'instructions', ref);
|
|
43
|
+
assert.ok(fs.existsSync(docPath), `referenced doctrine must exist: ${ref}`);
|
|
44
|
+
}
|
|
45
|
+
});
|