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.
Files changed (43) hide show
  1. package/README.md +78 -0
  2. package/bin/cli.mjs +201 -1
  3. package/package.json +2 -2
  4. package/plugin/agents/kushi.agent.md +6 -2
  5. package/plugin/instructions/hooks.instructions.md +84 -0
  6. package/plugin/instructions/living-wiki.instructions.md +88 -0
  7. package/plugin/instructions/log-format.instructions.md +78 -0
  8. package/plugin/instructions/otel.instructions.md +75 -0
  9. package/plugin/instructions/parallel-execution.instructions.md +81 -0
  10. package/plugin/instructions/schema-evolve.instructions.md +73 -0
  11. package/plugin/instructions/wiki-lint.instructions.md +110 -0
  12. package/plugin/skills/_shared/Append-StateLog.ps1 +73 -0
  13. package/plugin/skills/_shared/Emit-OtelSpan.ps1 +111 -0
  14. package/plugin/skills/_shared/Invoke-Hooks.ps1 +177 -0
  15. package/plugin/skills/_shared/Update-StateIndex.ps1 +47 -0
  16. package/plugin/skills/_shared/hook-templates/console-debug.ps1 +15 -0
  17. package/plugin/skills/_shared/hook-templates/teams-notify.ps1 +47 -0
  18. package/plugin/skills/ask-project/SKILL.md +30 -0
  19. package/plugin/skills/build-state/SKILL.md +18 -2
  20. package/plugin/skills/lint-state/.created-by-skill-creator +0 -0
  21. package/plugin/skills/lint-state/SKILL.md +98 -0
  22. package/plugin/skills/lint-state/evals/evals.json +34 -0
  23. package/plugin/skills/lint-state/lint.ps1 +218 -0
  24. package/plugin/skills/refresh-project/SKILL.md +8 -4
  25. package/plugin/skills/schema-evolve/.created-by-skill-creator +0 -0
  26. package/plugin/skills/schema-evolve/SKILL.md +106 -0
  27. package/plugin/skills/schema-evolve/evals/evals.json +37 -0
  28. package/plugin/skills/self-check/SKILL.md +12 -55
  29. package/plugin/skills/self-check/references/algorithm.md +55 -0
  30. package/plugin/skills/self-check/run.ps1 +225 -3
  31. package/plugin/skills/skill-checker/check-skill.ps1 +1 -1
  32. package/plugin/skills/teach/.created-by-skill-creator +0 -0
  33. package/plugin/skills/teach/SKILL.md +77 -0
  34. package/plugin/skills/teach/evals/evals.json +37 -0
  35. package/plugin/templates/state/answers.README.md +7 -0
  36. package/plugin/templates/state/hot.template.md +12 -0
  37. package/plugin/templates/state/review-queue.template.md +10 -0
  38. package/src/eval-runner.test.mjs +1 -1
  39. package/src/hooks-dispatcher.test.mjs +135 -0
  40. package/src/otel-emit.test.mjs +73 -0
  41. package/src/parallel-refresh.test.mjs +50 -0
  42. package/src/schema-evolve.test.mjs +78 -0
  43. 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
+ });