@zenera/cli 1.1.14 → 1.1.16

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 (32) hide show
  1. package/README.md +563 -206
  2. package/dist/banner.d.ts +5 -1
  3. package/dist/banner.js +2 -2
  4. package/dist/command.d.ts +5 -0
  5. package/dist/commands/init.js +46 -2
  6. package/dist/main.js +10 -6
  7. package/dist/validate.js +1 -1
  8. package/package.json +2 -2
  9. package/templates/editor/.github/copilot-instructions.md +253 -218
  10. package/templates/editor/.github/prompts/new-agent.prompt.md +6 -6
  11. package/templates/editor/.github/prompts/new-skill.prompt.md +7 -7
  12. package/templates/editor/.github/prompts/review-project.prompt.md +1 -1
  13. package/templates/editor/.github/prompts/sync-with-spec.prompt.md +26 -26
  14. package/templates/editor/.github/skills/zen-cli/SKILL.md +62 -6
  15. package/templates/editor/.github/skills/zen-cli/references/check.md +3 -3
  16. package/templates/editor/.github/skills/zen-cli/references/faker.md +14 -14
  17. package/templates/editor/.github/skills/zen-cli/references/frame.md +6 -6
  18. package/templates/editor/.github/skills/zen-cli/references/inspect.md +3 -3
  19. package/templates/editor/.github/skills/zen-cli/references/keys.md +9 -9
  20. package/templates/editor/.github/skills/zen-cli/references/memory.md +11 -11
  21. package/templates/editor/.github/skills/zen-cli/references/models.md +8 -8
  22. package/templates/editor/.github/skills/zen-cli/references/projects.md +3 -3
  23. package/templates/editor/.github/skills/zen-cli/references/rag.md +191 -56
  24. package/templates/editor/.github/skills/zen-cli/references/run.md +3 -3
  25. package/templates/editor/.github/skills/zen-cli/references/sandbox.md +8 -8
  26. package/templates/editor/.github/skills/zen-memory/SKILL.md +50 -50
  27. package/templates/editor/.github/skills/zen-rag-docs/SKILL.md +71 -48
  28. package/templates/editor/.github/skills/zen-rag-schema/SKILL.md +67 -67
  29. package/templates/editor/.vscode/settings.json +5 -2
  30. package/templates/project/INSTRUCTIONS.md +1 -1
  31. package/templates/project/assets/README.md +1 -1
  32. package/templates/project/sandbox/Dockerfile.tmpl +3 -0
package/dist/banner.d.ts CHANGED
@@ -6,8 +6,12 @@ export interface BannerText {
6
6
  /** the line underneath, dim */
7
7
  subtitle: string;
8
8
  }
9
+ export interface PrintBannerOptions {
10
+ /** Render the block face even when the terminal is narrower than it. */
11
+ readonly full?: boolean;
12
+ }
9
13
  export declare const NEO_BANNER: BannerText;
10
14
  export declare function bannerLines(text: BannerText, columns?: number): string[];
11
15
  /** Narration, and only for someone watching. */
12
- export declare function printBanner(text: BannerText): void;
16
+ export declare function printBanner(text: BannerText, options?: PrintBannerOptions): void;
13
17
  //# sourceMappingURL=banner.d.ts.map
package/dist/banner.js CHANGED
@@ -112,12 +112,12 @@ export function bannerLines(text, columns = process.stderr.columns || 80) {
112
112
  return lines;
113
113
  }
114
114
  /** Narration, and only for someone watching. */
115
- export function printBanner(text) {
115
+ export function printBanner(text, options = {}) {
116
116
  if (!process.stderr.isTTY) {
117
117
  return;
118
118
  }
119
119
  note('');
120
- for (const line of bannerLines(text)) {
120
+ for (const line of bannerLines(text, options.full ? Infinity : undefined)) {
121
121
  note(line);
122
122
  }
123
123
  note('');
package/dist/command.d.ts CHANGED
@@ -9,6 +9,11 @@ export interface Command {
9
9
  readonly usage: string;
10
10
  /** lines printed under the usage line by `zen help <command>` */
11
11
  readonly details?: readonly string[];
12
+ /**
13
+ * Answers `--help` itself, for a command whose arguments select a page the
14
+ * frame cannot see. Without it the frame prints this command's own page.
15
+ */
16
+ help?(ctx: Context): Promise<void> | void;
12
17
  run(ctx: Context): Promise<void>;
13
18
  }
14
19
  //# sourceMappingURL=command.d.ts.map
@@ -9,7 +9,7 @@ import { probeAll } from "../liveness.js";
9
9
  import { ensurePodmanReady } from "../podman.js";
10
10
  import { isProjectDir, Registry } from "../projects.js";
11
11
  import { scaffold } from "../scaffold.js";
12
- import { bold, cyan, dim, green, invalidError, json, note, progress, usageError, write, yellow, } from "../term.js";
12
+ import { bold, cyan, dim, green, json, note, progress, usageError, write, yellow, } from "../term.js";
13
13
  const USAGE = 'zen init [dir] [--name <name>] [--model <ref>] [--force]';
14
14
  /**
15
15
  * The model each provider gets scaffolded with, when it is the one chosen.
@@ -101,6 +101,11 @@ export const init = {
101
101
  'find it by name. Editor files (.vscode/settings.json and the .github/',
102
102
  'tree) are written alongside, replacing any already there.',
103
103
  '',
104
+ 'A directory that is already a project is adopted rather than rebuilt:',
105
+ 'it is registered under its own name, and nothing in it is touched.',
106
+ 'That is how a project someone else wrote becomes a name on this',
107
+ 'machine after a clone.',
108
+ '',
104
109
  'SPECIFICATION.md states what the project is for and what it may do,',
105
110
  'and describes the one that was just written. Say what you are building',
106
111
  'there, then run /sync-with-spec in your editor to make the rest match.',
@@ -122,7 +127,8 @@ export const init = {
122
127
  const dir = resolve(ctx.cwd, one(positionals, 'directory', USAGE) ?? '.');
123
128
  const name = values.name ?? basename(dir);
124
129
  if (isProjectDir(dir)) {
125
- throw invalidError(`${dir} is already a project`);
130
+ await adopt(dir, values, ctx.json);
131
+ return;
126
132
  }
127
133
  if (existsSync(dir) && readdirSync(dir).length > 0 && !values.force) {
128
134
  throw usageError(`${dir} is not empty`, 'pass --force to write into it anyway');
@@ -177,6 +183,44 @@ export const init = {
177
183
  write(dir);
178
184
  },
179
185
  };
186
+ /**
187
+ * Takes a directory that is already a project into the registry.
188
+ *
189
+ * The registry lives in `$HOME`, so a project that arrives by clone, copy or
190
+ * `mv` is a working project that no name resolves to — and the only thing
191
+ * missing is the entry. Scaffolding over it would be the wrong repair: the
192
+ * files are somebody's work, and this writes none of them.
193
+ *
194
+ * Idempotent, because the honest answer to `zen init` in a project that is
195
+ * already listed is "it is", not an error.
196
+ */
197
+ async function adopt(dir, values, quiet) {
198
+ ensureHome();
199
+ const registry = await Registry.open();
200
+ const listed = registry.findPath(dir);
201
+ const name = values.name ?? listed?.name ?? basename(dir);
202
+ const renamed = listed !== undefined && listed.name !== name;
203
+ registry.add(name, dir);
204
+ registry.save();
205
+ const sandbox = await prepareSandbox(dir, quiet);
206
+ if (quiet) {
207
+ json({ name, path: dir, adopted: true, listed: listed !== undefined, sandbox });
208
+ return;
209
+ }
210
+ const what = listed === undefined
211
+ ? green('registered')
212
+ : renamed
213
+ ? green('renamed')
214
+ : dim('already registered');
215
+ note(`${what} ${bold(name)} ${dim(dir)}`);
216
+ // Nothing here was scaffolded, so the flags that shape a scaffold did not apply.
217
+ if (values.model) {
218
+ note(`${yellow('--model ignored')} ${dim('— the model this project uses is in agents.yaml')}`);
219
+ }
220
+ note();
221
+ note(`Next: ${cyan(`cd ${dir}`)} then ${cyan('zen check')}`);
222
+ write(dir);
223
+ }
180
224
  /**
181
225
  * Builds the sandbox image the project was just given, here rather than on the
182
226
  * first run.
package/dist/main.js CHANGED
@@ -57,9 +57,11 @@ async function main(argv) {
57
57
  // Narration, so `--json` and every pipe are untouched by it. A command
58
58
  // living in another package brings its own brand, but only once it is
59
59
  // actually there — a banner over "not installed" is a claim about nothing.
60
- if (!json) {
60
+ const ragSearch = name === 'rag' && ['docs', 'schema'].includes(rest[0]) && rest[1] === 'search';
61
+ const interactive = rest.includes('--interactive');
62
+ if (!json && (!ragSearch || interactive)) {
61
63
  const brand = external && hasExternal(external) ? external.banner : undefined;
62
- printBanner(brand ?? NEO_BANNER);
64
+ printBanner(brand ?? NEO_BANNER, { full: ragSearch && interactive });
63
65
  }
64
66
  if (parts.name === 'help') {
65
67
  await usage(rest[0]);
@@ -73,15 +75,17 @@ async function main(argv) {
73
75
  fail(`unknown command "${parts.name}"`, `run ${bold(`${NAME} --help`)} for the list`);
74
76
  return EXIT.usage;
75
77
  }
76
- if (values.help) {
77
- await usage(name);
78
- return EXIT.ok;
79
- }
80
78
  // `-C` is consumed here so no command ever reads `process.cwd()` itself,
81
79
  // and every relative path in every command means the same thing.
82
80
  const cwd = resolve(values.directory ?? process.cwd());
83
81
  try {
84
82
  const one = command ?? (await loadExternal(name, external));
83
+ if (values.help) {
84
+ // A command that nests its own pages answers for them; the frame
85
+ // only knows the one page it printed the command's name on.
86
+ await (one.help ? one.help({ args: rest, json, cwd }) : usage(name));
87
+ return EXIT.ok;
88
+ }
85
89
  await one.run({ args: rest, json, cwd });
86
90
  return EXIT.ok;
87
91
  }
package/dist/validate.js CHANGED
@@ -88,7 +88,7 @@ export async function validateProject(opts) {
88
88
  where: root,
89
89
  message: 'this directory is not registered, so `zen open` and `zen list` will not ' +
90
90
  'find it by name (naming it by path, as now, works either way)',
91
- fix: `register it: zen init ${root} --force`,
91
+ fix: `register it: zen init ${root}`,
92
92
  });
93
93
  }
94
94
  // -----------------------------------------------------------------------
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zenera/cli",
3
- "version": "1.1.14",
3
+ "version": "1.1.16",
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.14",
54
+ "@zenera/neo": "^1.1.16",
55
55
  "@anthropic-ai/sdk": "^0.120.0",
56
56
  "@google/genai": "^2.18.0",
57
57
  "@openrouter/sdk": "^1.2.80",