@zenera/cli 1.1.15 → 1.1.17

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 (57) hide show
  1. package/README.md +201 -129
  2. package/dist/banner.d.ts +5 -1
  3. package/dist/banner.js +2 -2
  4. package/dist/catalog.js +19 -20
  5. package/dist/command.d.ts +5 -0
  6. package/dist/commands/check.js +5 -1
  7. package/dist/commands/init.js +41 -6
  8. package/dist/commands/run.js +4 -0
  9. package/dist/engine.js +6 -0
  10. package/dist/env.d.ts +20 -0
  11. package/dist/env.js +65 -0
  12. package/dist/keys.d.ts +2 -0
  13. package/dist/keys.js +2 -0
  14. package/dist/main.js +10 -6
  15. package/dist/sandbox.d.ts +9 -0
  16. package/dist/sandbox.js +23 -3
  17. package/dist/scaffold.d.ts +6 -0
  18. package/dist/scaffold.js +56 -15
  19. package/dist/validate.js +57 -15
  20. package/package.json +2 -2
  21. package/templates/editor/.github/copilot-instructions.md +501 -301
  22. package/templates/editor/.github/prompts/new-agent.prompt.md +6 -6
  23. package/templates/editor/.github/prompts/new-skill.prompt.md +7 -7
  24. package/templates/editor/.github/prompts/review-project.prompt.md +54 -15
  25. package/templates/editor/.github/prompts/sync-with-spec.prompt.md +229 -42
  26. package/templates/editor/.github/prompts/update-spec-from-feedback.prompt.md +142 -0
  27. package/templates/editor/.github/skills/zen-cli/SKILL.md +62 -6
  28. package/templates/editor/.github/skills/zen-cli/references/check.md +9 -6
  29. package/templates/editor/.github/skills/zen-cli/references/faker.md +14 -14
  30. package/templates/editor/.github/skills/zen-cli/references/frame.md +11 -9
  31. package/templates/editor/.github/skills/zen-cli/references/inspect.md +3 -3
  32. package/templates/editor/.github/skills/zen-cli/references/keys.md +9 -9
  33. package/templates/editor/.github/skills/zen-cli/references/memory.md +11 -11
  34. package/templates/editor/.github/skills/zen-cli/references/models.md +8 -8
  35. package/templates/editor/.github/skills/zen-cli/references/projects.md +23 -6
  36. package/templates/editor/.github/skills/zen-cli/references/rag.md +191 -56
  37. package/templates/editor/.github/skills/zen-cli/references/run.md +3 -3
  38. package/templates/editor/.github/skills/zen-cli/references/sandbox.md +14 -8
  39. package/templates/editor/.github/skills/zen-memory/SKILL.md +144 -72
  40. package/templates/editor/.github/skills/zen-memory/scripts/check-instructions.sh +115 -0
  41. package/templates/editor/.github/skills/zen-rag-docs/SKILL.md +71 -48
  42. package/templates/editor/.github/skills/zen-rag-schema/SKILL.md +67 -67
  43. package/templates/editor/.github/skills/zen-review/SKILL.md +123 -0
  44. package/templates/editor/.github/skills/zen-review/scripts/check-paths.sh +119 -0
  45. package/templates/editor/.github/skills/zen-review/scripts/review.sh +104 -0
  46. package/templates/editor/.github/skills/zen-spec-sync/SKILL.md +197 -0
  47. package/templates/editor/.github/skills/zen-spec-sync/scripts/snapshot.sh +200 -0
  48. package/templates/editor/.vscode/settings.json +46 -3
  49. package/templates/parts/memory-terms.yaml.tmpl +16 -0
  50. package/templates/parts/memory.yaml.tmpl +12 -0
  51. package/templates/project/SPECIFICATION.md.tmpl +7 -0
  52. package/templates/project/{INSTRUCTIONS.md → agents/instructions.md} +1 -1
  53. package/templates/project/agents/memory-instructions.md +278 -0
  54. package/templates/project/agents.yaml.tmpl +9 -0
  55. package/templates/project/assets/README.md +1 -1
  56. package/templates/project/env +22 -0
  57. package/templates/project/sandbox/Dockerfile.tmpl +3 -0
package/dist/validate.js CHANGED
@@ -11,13 +11,43 @@ import { BuildError, ensurePodmanReady } from "./podman.js";
11
11
  // Duplicated rather than exported, because a check that agreed with the loader
12
12
  // by construction could not report that the two had diverged.
13
13
  const CONFIG_NAMES = ['agents.yaml', 'agents.yml', 'agents/agents.yaml', 'agents/agents.yml'];
14
- const HOUSE_RULES = 'INSTRUCTIONS.md';
14
+ const AGENTS_DIR = 'agents';
15
+ const HOUSE_RULES = 'agents/instructions.md';
16
+ const INSTRUCTIONS_SUFFIX = '-instructions.md';
17
+ const LEGACY_HOUSE_RULES = 'INSTRUCTIONS.md';
15
18
  const PROMPTS_DIR = 'agents/prompts';
16
19
  const SKILLS_DIR = 'agents/skills';
17
20
  const SKILL_FILE = 'SKILL.md';
18
21
  const ASSETS_DIR = 'assets';
19
22
  /** What `allow:` and `preload:` accept, so a skill outside it cannot be named. */
20
23
  const REFERABLE = /^[a-z0-9]+(?:[-_][a-z0-9]+)*$/;
24
+ /**
25
+ * Mirrors `readHouseRules` in the loader, in the same order: the legacy file
26
+ * first, then `agents/instructions.md`, then every
27
+ * `agents/<topic>-instructions.md` by filename.
28
+ */
29
+ function houseRules(root) {
30
+ const found = [];
31
+ const take = (rel) => {
32
+ if (existsSync(join(root, rel))) {
33
+ found.push(rel);
34
+ }
35
+ };
36
+ take(LEGACY_HOUSE_RULES);
37
+ take(HOUSE_RULES);
38
+ const dir = join(root, AGENTS_DIR);
39
+ if (!existsSync(dir) || !statSync(dir).isDirectory()) {
40
+ return found;
41
+ }
42
+ const topics = readdirSync(dir, { withFileTypes: true })
43
+ .filter((entry) => entry.isFile() && entry.name.endsWith(INSTRUCTIONS_SUFFIX))
44
+ .map((entry) => entry.name)
45
+ .sort((a, b) => a.localeCompare(b));
46
+ for (const name of topics) {
47
+ take(`${AGENTS_DIR}/${name}`);
48
+ }
49
+ return found;
50
+ }
21
51
  export async function validateProject(opts) {
22
52
  const root = resolve(opts.dir);
23
53
  const findings = [];
@@ -140,23 +170,38 @@ export async function validateProject(opts) {
140
170
  // -----------------------------------------------------------------------
141
171
  // Files the config and the conventions name
142
172
  // -----------------------------------------------------------------------
143
- const hasHouseRules = record(HOUSE_RULES, 'house rules — prepended to every agent prompt', 'file', false);
144
- if (!hasHouseRules) {
173
+ const rules = houseRules(root);
174
+ for (const rel of rules) {
175
+ record(rel, 'house rules — prepended to every agent prompt', 'file', false);
176
+ if (empty(join(root, rel))) {
177
+ add({
178
+ severity: 'warning',
179
+ code: 'house-rules.empty',
180
+ where: rel,
181
+ message: `${rel} is empty, so it contributes nothing but a prompt section`,
182
+ fix: 'write the rules that hold whichever agent is answering, or delete it',
183
+ });
184
+ }
185
+ }
186
+ if (rules.length === 0) {
187
+ record(HOUSE_RULES, 'house rules — prepended to every agent prompt', 'file', false);
145
188
  add({
146
189
  severity: 'note',
147
190
  code: 'house-rules.missing',
148
191
  where: HOUSE_RULES,
149
- message: 'no INSTRUCTIONS.md, which is allowed: every agent then runs on its own role ' +
192
+ message: 'no house rules, which is allowed: every agent then runs on its own role ' +
150
193
  'prompt alone, with nothing shared between them',
151
194
  });
152
195
  }
153
- else if (empty(join(root, HOUSE_RULES))) {
196
+ if (rules.includes(LEGACY_HOUSE_RULES)) {
154
197
  add({
155
198
  severity: 'warning',
156
- code: 'house-rules.empty',
157
- where: HOUSE_RULES,
158
- message: 'INSTRUCTIONS.md is empty, so it contributes nothing but a prompt section',
159
- fix: 'write the rules that hold regardless of which agent is answering, or delete it',
199
+ code: 'house-rules.legacy',
200
+ where: LEGACY_HOUSE_RULES,
201
+ message: `${LEGACY_HOUSE_RULES} is where the house rules used to live. It is still ` +
202
+ `read, and still first, but the layout now keeps them under ${AGENTS_DIR}/ ` +
203
+ 'so a project can have more than one of them',
204
+ fix: `move it to ${HOUSE_RULES}, or fold it into the ${AGENTS_DIR}/*${INSTRUCTIONS_SUFFIX} files already there`,
160
205
  });
161
206
  }
162
207
  // -----------------------------------------------------------------------
@@ -400,14 +445,11 @@ export function availableTools(root, config) {
400
445
  }
401
446
  function checkAgent(root, config, spec, entry, available, record, add) {
402
447
  const where = `agents.${spec.name}`;
403
- const instructions = [];
404
- if (existsSync(join(root, HOUSE_RULES))) {
405
- instructions.push(HOUSE_RULES);
406
- }
448
+ const instructions = [...houseRules(root)];
407
449
  // The role prompt: named by `system:`, or found by convention. A named one
408
450
  // that is not there is an error — the loader says so too. An absent
409
451
  // conventional one is not, because a project may keep everything it has to
410
- // say in INSTRUCTIONS.md.
452
+ // say in its house rules.
411
453
  if (spec.system) {
412
454
  const rel = normalise(root, spec.system);
413
455
  const outside = rel === undefined;
@@ -457,7 +499,7 @@ function checkAgent(root, config, spec, entry, available, record, add) {
457
499
  severity: 'warning',
458
500
  code: 'agent.no-instructions',
459
501
  where,
460
- message: 'this agent has no prompt at all — no INSTRUCTIONS.md and no role file — so ' +
502
+ message: 'this agent has no prompt at all — no house rules and no role file — so ' +
461
503
  'it runs on the tool descriptions alone',
462
504
  fix: `write ${join(PROMPTS_DIR, `${spec.name}.md`)}, or name one with \`system:\``,
463
505
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zenera/cli",
3
- "version": "1.1.15",
3
+ "version": "1.1.17",
4
4
  "description": "Command-line front end for @zenera/neo: agentic projects you can run, share and commit.",
5
5
  "keywords": [
6
6
  "agents",
@@ -51,7 +51,7 @@
51
51
  "@inkjs/ui": "^2.0.0",
52
52
  "ink": "^7.1.1",
53
53
  "react": "^19.2.8",
54
- "@zenera/neo": "^1.1.15",
54
+ "@zenera/neo": "^1.1.17",
55
55
  "@anthropic-ai/sdk": "^0.120.0",
56
56
  "@google/genai": "^2.18.0",
57
57
  "@openrouter/sdk": "^1.2.80",