@zenera/cli 1.1.21 → 1.1.22
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 +3 -3
- package/dist/banner.d.ts +33 -24
- package/dist/banner.js +25 -6
- package/dist/commands/check.js +1 -0
- package/dist/commands/init.js +1 -0
- package/dist/commands/inspect.js +1 -0
- package/dist/commands/key.js +1 -0
- package/dist/commands/list.js +1 -0
- package/dist/commands/memory.js +1 -0
- package/dist/commands/open.js +1 -0
- package/dist/commands/run.js +3 -0
- package/dist/commands/sandbox.js +1 -0
- package/dist/commands/version.js +1 -0
- package/dist/lib.d.ts +2 -1
- package/dist/lib.js +2 -1
- package/dist/meta.d.ts +1 -1
- package/dist/meta.js +5 -28
- package/dist/resolve.js +19 -12
- package/dist/sandbox.js +1 -0
- package/dist/scaffold.js +3 -1
- package/dist/term.d.ts +2 -0
- package/dist/term.js +2 -0
- package/dist/tui/markdown.d.ts +16 -0
- package/dist/tui/markdown.js +259 -0
- package/dist/tui/theme.js +1 -1
- package/dist/tui/wrap.d.ts +1 -1
- package/dist/validate.js +82 -3
- package/package.json +2 -2
- package/templates/editor/.github/copilot-instructions.md +62 -33
- package/templates/editor/.github/prompts/spec-sync-project.prompt.md +31 -1
- package/templates/editor/.github/skills/zen-cli/SKILL.md +15 -15
- package/templates/editor/.github/skills/zen-cli/references/projects.md +1 -0
- package/templates/editor/.github/skills/zen-cli/references/rag.md +37 -3
- package/templates/editor/.github/skills/zen-cli/references/sandbox.md +30 -2
- package/templates/editor/.github/skills/zen-instructions/SKILL.md +232 -0
- package/templates/editor/.github/skills/zen-memory-warmup/SKILL.md +554 -0
- package/templates/editor/.github/skills/zen-rag-docs/SKILL.md +56 -23
- package/templates/editor/.github/skills/zen-rag-schema/SKILL.md +55 -28
- package/templates/editor/.github/skills/zen-review/SKILL.md +17 -1
- package/templates/editor/.github/skills/zen-sandbox/SKILL.md +257 -0
- package/templates/editor/.github/skills/zen-spec-sync/SKILL.md +15 -3
- package/templates/editor/.vscode/agents.schema.json +8 -3
- package/templates/project/SPECIFICATION.md.tmpl +2 -1
- package/templates/project/agents/files-instructions.md +86 -0
- package/templates/project/agents/fork-instructions.md +17 -0
- package/templates/project/agents/memory-instructions.md +37 -0
- package/templates/project/agents.yaml.tmpl +3 -3
- package/templates/project/gitignore +12 -1
- package/templates/project/scripts/_setup.sh +19 -4
package/README.md
CHANGED
|
@@ -310,13 +310,13 @@ agents:
|
|
|
310
310
|
- name: reader
|
|
311
311
|
description: Reads the workspace and summarises what is in it.
|
|
312
312
|
system: agents/prompts/reader.md
|
|
313
|
-
tools: [
|
|
313
|
+
tools: [files:read_file, files:list_dir, files:find_files]
|
|
314
314
|
handoffs: [writer]
|
|
315
315
|
|
|
316
316
|
- name: writer
|
|
317
317
|
description: Turns a summary into a file on disk.
|
|
318
318
|
system: agents/prompts/writer.md
|
|
319
|
-
tools: [
|
|
319
|
+
tools: [files:*]
|
|
320
320
|
handoffs: [reader] # a hand-off does not return by itself; give it a way back
|
|
321
321
|
```
|
|
322
322
|
|
|
@@ -351,7 +351,7 @@ lines. Then say where you put it and stop.
|
|
|
351
351
|
| `description` | what it is for - read by the _other_ agents when deciding to hand off |
|
|
352
352
|
| `system` | its own brief, in prose, at `agents/prompts/<name>.md` |
|
|
353
353
|
| `model` | this agent's model; the top-level one otherwise |
|
|
354
|
-
| `tools` | what it may reach for - `workspace
|
|
354
|
+
| `tools` | what it may reach for - `files:*` (or `workspace:*`), `sandbox:*` |
|
|
355
355
|
| `handoffs` | who it may pass the work to |
|
|
356
356
|
| `skills` | knowledge pulled in mid-run instead of carried in every prompt |
|
|
357
357
|
|
package/dist/banner.d.ts
CHANGED
|
@@ -1,29 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A stroke and the bevel that shades it, one step darker in the same hue.
|
|
3
|
+
*
|
|
4
|
+
* The head word is the terminal's own ink, so it has one per background: near
|
|
5
|
+
* white raised off grey, or near black embossed into it. The accent does not
|
|
6
|
+
* — it is the brand, it is the same orange on both, and it is the only word
|
|
7
|
+
* here that is allowed not to care what it is printed on.
|
|
8
|
+
*/
|
|
9
|
+
interface Tone {
|
|
10
|
+
face: string;
|
|
11
|
+
shade: string;
|
|
12
|
+
}
|
|
1
13
|
/** One per sub-brand, so two of them are told apart before the word is read. */
|
|
2
14
|
declare const ACCENTS: {
|
|
3
|
-
readonly orange:
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
readonly green:
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
readonly cyan:
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
readonly
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
readonly
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
readonly dusk:
|
|
24
|
-
readonly face: "\u001B[1;38;5;141m";
|
|
25
|
-
readonly shade: "\u001B[0;38;5;97m";
|
|
26
|
-
};
|
|
15
|
+
readonly orange: Tone;
|
|
16
|
+
readonly amber: Tone;
|
|
17
|
+
readonly gold: Tone;
|
|
18
|
+
readonly lime: Tone;
|
|
19
|
+
readonly green: Tone;
|
|
20
|
+
readonly emerald: Tone;
|
|
21
|
+
readonly mint: Tone;
|
|
22
|
+
readonly teal: Tone;
|
|
23
|
+
readonly cyan: Tone;
|
|
24
|
+
readonly sky: Tone;
|
|
25
|
+
readonly azure: Tone;
|
|
26
|
+
readonly steel: Tone;
|
|
27
|
+
readonly indigo: Tone;
|
|
28
|
+
readonly violet: Tone;
|
|
29
|
+
readonly purple: Tone;
|
|
30
|
+
readonly magenta: Tone;
|
|
31
|
+
readonly pink: Tone;
|
|
32
|
+
readonly rose: Tone;
|
|
33
|
+
readonly crimson: Tone;
|
|
34
|
+
readonly red: Tone;
|
|
35
|
+
readonly dusk: Tone;
|
|
27
36
|
};
|
|
28
37
|
export type Hue = keyof typeof ACCENTS;
|
|
29
38
|
export interface BannerText {
|
package/dist/banner.js
CHANGED
|
@@ -69,14 +69,33 @@ const HEADS = {
|
|
|
69
69
|
dark: { face: '\u001b[1;38;5;231m', shade: '\u001b[0;38;5;244m' },
|
|
70
70
|
light: { face: '\u001b[1;38;5;235m', shade: '\u001b[0;38;5;245m' },
|
|
71
71
|
};
|
|
72
|
+
const tone = (face, shade) => ({
|
|
73
|
+
face: `\u001b[1;38;5;${face}m`,
|
|
74
|
+
shade: `\u001b[0;38;5;${shade}m`,
|
|
75
|
+
});
|
|
72
76
|
/** One per sub-brand, so two of them are told apart before the word is read. */
|
|
73
77
|
const ACCENTS = {
|
|
74
|
-
orange:
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
78
|
+
orange: tone(208, 130),
|
|
79
|
+
amber: tone(214, 172),
|
|
80
|
+
gold: tone(220, 178),
|
|
81
|
+
lime: tone(154, 106),
|
|
82
|
+
green: tone(41, 29),
|
|
83
|
+
emerald: tone(48, 29),
|
|
84
|
+
mint: tone(121, 78),
|
|
85
|
+
teal: tone(44, 30),
|
|
86
|
+
cyan: tone(51, 37),
|
|
87
|
+
sky: tone(39, 26),
|
|
88
|
+
azure: tone(33, 25),
|
|
89
|
+
steel: tone(110, 67),
|
|
90
|
+
indigo: tone(105, 61),
|
|
91
|
+
violet: tone(141, 97),
|
|
92
|
+
purple: tone(171, 90),
|
|
93
|
+
magenta: tone(201, 127),
|
|
94
|
+
pink: tone(212, 169),
|
|
95
|
+
rose: tone(204, 125),
|
|
96
|
+
crimson: tone(197, 124),
|
|
97
|
+
red: tone(196, 88),
|
|
98
|
+
dusk: tone(141, 97),
|
|
80
99
|
};
|
|
81
100
|
/** Runs of stroke and runs of bevel, alternating; spaces stay unstyled. */
|
|
82
101
|
const RUNS = /[█▀▄]+|[^█▀▄ ]+/g;
|
package/dist/commands/check.js
CHANGED
|
@@ -34,6 +34,7 @@ const USAGE = 'zen check [name|dir] [--project <name|dir>] [--fix] [--no-sandbox
|
|
|
34
34
|
export const check = {
|
|
35
35
|
summary: 'Validate agents.yaml and every file it names, and ask its models.',
|
|
36
36
|
usage: USAGE,
|
|
37
|
+
banner: { head: 'Zenera', accent: 'Check', subtitle: 'Project Health', hue: 'lime' },
|
|
37
38
|
details: [
|
|
38
39
|
'Checks the whole project: the configuration parses and satisfies the',
|
|
39
40
|
'schema, every prompt, skill and catalog it names is on disk, hand-offs',
|
package/dist/commands/init.js
CHANGED
|
@@ -126,6 +126,7 @@ function hasExa(store) {
|
|
|
126
126
|
export const init = {
|
|
127
127
|
summary: 'Create a project here, or in <dir>, and register it.',
|
|
128
128
|
usage: USAGE,
|
|
129
|
+
banner: { head: 'Zenera', accent: 'Init', subtitle: 'Project Scaffolding', hue: 'rose' },
|
|
129
130
|
details: [
|
|
130
131
|
'Writes SPECIFICATION.md, agents.yaml, agents/ (house rules, the memory',
|
|
131
132
|
'rules and one role prompt) and scripts/, then records the directory so',
|
package/dist/commands/inspect.js
CHANGED
|
@@ -13,6 +13,7 @@ const USAGE = 'zen inspect [run] [--session <id>] [--open] [--rebuild] [--serve
|
|
|
13
13
|
export const inspect = {
|
|
14
14
|
summary: "Open or rebuild a run's report.html.",
|
|
15
15
|
usage: USAGE,
|
|
16
|
+
banner: { head: 'Zenera', accent: 'Inspect', subtitle: 'Run Trajectory', hue: 'indigo' },
|
|
16
17
|
details: [
|
|
17
18
|
'With no arguments: asks which session and run, or takes the newest of',
|
|
18
19
|
'each when there is nothing to ask on.',
|
package/dist/commands/key.js
CHANGED
|
@@ -508,6 +508,7 @@ const SUBS = {
|
|
|
508
508
|
export const key = {
|
|
509
509
|
summary: 'The credential store: add, choose, verify and export API keys.',
|
|
510
510
|
usage: USAGE,
|
|
511
|
+
banner: { head: 'Zenera', accent: 'Keys', subtitle: 'Credential Keyring', hue: 'amber' },
|
|
511
512
|
details: [
|
|
512
513
|
'Keys live in ~/.zenera/neo/keys.json (0600) and are materialised into',
|
|
513
514
|
'the environment before a run. A real environment variable always wins,',
|
package/dist/commands/list.js
CHANGED
|
@@ -9,6 +9,7 @@ const USAGE = 'zen list [--sessions] [--prune]';
|
|
|
9
9
|
export const list = {
|
|
10
10
|
summary: 'Every known project: sessions, last run, whether one is live.',
|
|
11
11
|
usage: USAGE,
|
|
12
|
+
banner: { head: 'Zenera', accent: 'Projects', subtitle: 'Project Registry', hue: 'sky' },
|
|
12
13
|
details: [
|
|
13
14
|
'The registry is an index, not the truth. An entry whose directory has',
|
|
14
15
|
'gone away is shown dimmed rather than hidden; --prune forgets them.',
|
package/dist/commands/memory.js
CHANGED
|
@@ -31,6 +31,7 @@ const LISTED = 30;
|
|
|
31
31
|
export const memory = {
|
|
32
32
|
summary: 'What the agents remember, and getting rid of it.',
|
|
33
33
|
usage: USAGE,
|
|
34
|
+
banner: { head: 'Zenera', accent: 'Memory', subtitle: 'Knowledge Graph', hue: 'purple' },
|
|
34
35
|
details: [
|
|
35
36
|
' stats Size, vocabulary, and whether it is embedded.',
|
|
36
37
|
' ls Nodes, newest first. Changes nothing.',
|
package/dist/commands/open.js
CHANGED
|
@@ -16,6 +16,7 @@ const USAGE = 'zen open [project] [--editor <cmd>] [--wait]';
|
|
|
16
16
|
export const open = {
|
|
17
17
|
summary: 'Open a project in your editor.',
|
|
18
18
|
usage: USAGE,
|
|
19
|
+
banner: { head: 'Zenera', accent: 'Open', subtitle: 'Workspace Studio', hue: 'teal' },
|
|
19
20
|
details: [
|
|
20
21
|
'Editor: --editor, then $ZENERA_EDITOR, then the editor this terminal',
|
|
21
22
|
'belongs to, then $VISUAL or $EDITOR, then a known editor on PATH or',
|
package/dist/commands/run.js
CHANGED
|
@@ -12,6 +12,7 @@ const USAGE = 'zen run [project] [prompt] [options]';
|
|
|
12
12
|
export const run = {
|
|
13
13
|
summary: 'Run the project — the TUI on a terminal, one shot otherwise.',
|
|
14
14
|
usage: USAGE,
|
|
15
|
+
banner: { head: 'Zenera', accent: 'Neo', subtitle: 'Agentic Runtime', hue: 'orange' },
|
|
15
16
|
details: [
|
|
16
17
|
'Arguments:',
|
|
17
18
|
' [project] Name of a project. Default: the one you are in.',
|
|
@@ -31,6 +32,7 @@ export const run = {
|
|
|
31
32
|
' --theme <dark|light> Colours for the TUI. Default: auto.',
|
|
32
33
|
' --out <file> Put the answer in this file instead of on screen.',
|
|
33
34
|
' --yes Answer yes to every question.',
|
|
35
|
+
' --json Print machine-readable JSON (session, run, mounts, output, etc...).',
|
|
34
36
|
'',
|
|
35
37
|
'The first word is the project when it names one, otherwise the prompt.',
|
|
36
38
|
'The answer goes to stdout and the progress to stderr, so `> out.md` keeps',
|
|
@@ -46,6 +48,7 @@ export const run = {
|
|
|
46
48
|
' git diff | zen run take the prompt from stdin',
|
|
47
49
|
' zen run "what changed?" > out.md redirect the answer into a file',
|
|
48
50
|
' zen run --out out.md "what changed?" write the answer to out.md only',
|
|
51
|
+
' zen run --json "what changed?" output JSON with workspace, run paths, state, etc...',
|
|
49
52
|
' zen run --read-only "what changed?" let it read but not write',
|
|
50
53
|
' zen run --memory ./mem remember into ./mem, not the project',
|
|
51
54
|
' zen run --new open the TUI in a new session',
|
package/dist/commands/sandbox.js
CHANGED
|
@@ -21,6 +21,7 @@ const INDENT = ' '.repeat(11);
|
|
|
21
21
|
export const sandbox = {
|
|
22
22
|
summary: 'Check and prepare the container command-line tools run in.',
|
|
23
23
|
usage: USAGE,
|
|
24
|
+
banner: { head: 'Zenera', accent: 'Sandbox', subtitle: 'Container Isolation', hue: 'azure' },
|
|
24
25
|
details: [
|
|
25
26
|
' status What is installed, running and pulled. Changes nothing.',
|
|
26
27
|
' up Install if asked, start the machine, pull or build the image.',
|
package/dist/commands/version.js
CHANGED
|
@@ -20,6 +20,7 @@ function libraryManifest() {
|
|
|
20
20
|
export const version = {
|
|
21
21
|
summary: 'Print the CLI, library and Node versions.',
|
|
22
22
|
usage: 'zen version',
|
|
23
|
+
banner: { head: 'Zenera', accent: 'Version', subtitle: 'Runtime & Build', hue: 'steel' },
|
|
23
24
|
run: async (ctx) => {
|
|
24
25
|
const versions = {
|
|
25
26
|
cli: await versionOf(cliManifest),
|
package/dist/lib.d.ts
CHANGED
|
@@ -7,5 +7,6 @@ export { assertPrivate, ensureDir, ensureHome, home, paths, readJson, writeJson
|
|
|
7
7
|
export { assertNotEmpty, assertOwner, assertUsable, describe, envNames, envOf, form, isOwner, isProvider, keyId, KeyStore, mask, OWNERS, parseRef, PROVIDERS, SERVICES, SHAPES, type CredentialForm, type KeyCheck, type KeyEntry, type KeyOwner, type Liveness, type Provider, type Service, } from './keys.ts';
|
|
8
8
|
export { probe, probeAll } from './liveness.ts';
|
|
9
9
|
export { engineDisk, ensurePodmanReady, ownedContainers, podmanStatus, removeContainers, type DiskLine, type EngineDisk, type OwnedContainer, type PodmanOptions, type PodmanStatus, } from './podman.ts';
|
|
10
|
-
export { ago, bold, CliError, count, credentialError, cyan, dim, EXIT, fail, green, invalidError, isInteractive, json, note, pad, red, table, usageError, warn, write, writeAll, yellow, type ExitCode, } from './term.ts';
|
|
10
|
+
export { ago, bold, CliError, count, credentialError, cyan, dim, EXIT, fail, green, invalidError, isInteractive, italic, json, note, pad, red, table, underline, usageError, warn, write, writeAll, yellow, type ExitCode, } from './term.ts';
|
|
11
|
+
export { formatBlocks, formatInline, formatMarkdown, wrapSpans } from './tui/markdown.ts';
|
|
11
12
|
//# sourceMappingURL=lib.d.ts.map
|
package/dist/lib.js
CHANGED
|
@@ -29,5 +29,6 @@ export { assertPrivate, ensureDir, ensureHome, home, paths, readJson, writeJson
|
|
|
29
29
|
export { assertNotEmpty, assertOwner, assertUsable, describe, envNames, envOf, form, isOwner, isProvider, keyId, KeyStore, mask, OWNERS, parseRef, PROVIDERS, SERVICES, SHAPES, } from "./keys.js";
|
|
30
30
|
export { probe, probeAll } from "./liveness.js";
|
|
31
31
|
export { engineDisk, ensurePodmanReady, ownedContainers, podmanStatus, removeContainers, } from "./podman.js";
|
|
32
|
-
export { ago, bold, CliError, count, credentialError, cyan, dim, EXIT, fail, green, invalidError, isInteractive, json, note, pad, red, table, usageError, warn, write, writeAll, yellow, } from "./term.js";
|
|
32
|
+
export { ago, bold, CliError, count, credentialError, cyan, dim, EXIT, fail, green, invalidError, isInteractive, italic, json, note, pad, red, table, underline, usageError, warn, write, writeAll, yellow, } from "./term.js";
|
|
33
|
+
export { formatBlocks, formatInline, formatMarkdown, wrapSpans } from "./tui/markdown.js";
|
|
33
34
|
//# sourceMappingURL=lib.js.map
|
package/dist/meta.d.ts
CHANGED
|
@@ -179,7 +179,7 @@ export declare function footerCells(label: string, width: number): string[];
|
|
|
179
179
|
export declare function windowSink(rows?: number): Sink;
|
|
180
180
|
/**
|
|
181
181
|
* The answer in the same box `zen run` draws it in: bounded width, rounded
|
|
182
|
-
* rule,
|
|
182
|
+
* rule, formatted with full markdown styling (bold, italics, code, lists, quotes, tables).
|
|
183
183
|
*
|
|
184
184
|
* Redirected output gets the text and nothing else — `zen meta run ... > out.md`
|
|
185
185
|
* is meant to produce a file you can read, not one with a border down its side.
|
package/dist/meta.js
CHANGED
|
@@ -6,7 +6,8 @@ import { invokedAs } from "./args.js";
|
|
|
6
6
|
import { paths, readJson, writeJson } from "./home.js";
|
|
7
7
|
import { envOf } from "./keys.js";
|
|
8
8
|
import { credentialError, cut, cyan, dim, note, pad, plain, red, styled, usageError, write, yellow, } from "./term.js";
|
|
9
|
-
import {
|
|
9
|
+
import { formatInline, formatMarkdown } from "./tui/markdown.js";
|
|
10
|
+
import { boxWidth } from "./tui/wrap.js";
|
|
10
11
|
export const PROMPT_DIR = '.github/prompts';
|
|
11
12
|
const PROMPT_SUFFIX = '.prompt.md';
|
|
12
13
|
// ---------------------------------------------------------------------------
|
|
@@ -483,7 +484,7 @@ export function windowSink(rows = WINDOW_ROWS) {
|
|
|
483
484
|
}
|
|
484
485
|
/**
|
|
485
486
|
* The answer in the same box `zen run` draws it in: bounded width, rounded
|
|
486
|
-
* rule,
|
|
487
|
+
* rule, formatted with full markdown styling (bold, italics, code, lists, quotes, tables).
|
|
487
488
|
*
|
|
488
489
|
* Redirected output gets the text and nothing else — `zen meta run ... > out.md`
|
|
489
490
|
* is meant to produce a file you can read, not one with a border down its side.
|
|
@@ -494,31 +495,7 @@ export function answerBox(text, columns = process.stdout.columns ?? 80) {
|
|
|
494
495
|
}
|
|
495
496
|
const outer = boxWidth(text, columns);
|
|
496
497
|
const inner = outer - 4;
|
|
497
|
-
const body =
|
|
498
|
-
let previous;
|
|
499
|
-
for (const block of blocksOf(text)) {
|
|
500
|
-
if (previous && !(block.kind === 'item' && previous.kind === 'item')) {
|
|
501
|
-
body.push('');
|
|
502
|
-
}
|
|
503
|
-
previous = block;
|
|
504
|
-
if (block.kind === 'code') {
|
|
505
|
-
// Indentation is the meaning of a fenced block, so it is cut rather
|
|
506
|
-
// than reflowed.
|
|
507
|
-
body.push(dim(`\u250c\u2500${block.title ? ` ${block.title}` : ''}`));
|
|
508
|
-
body.push(...(block.lines ?? []).map((l) => `${dim('\u2502')} ${cut(l, inner - 2)}`));
|
|
509
|
-
body.push(dim('\u2514\u2500'));
|
|
510
|
-
}
|
|
511
|
-
else if (block.lines || block.kind === 'table') {
|
|
512
|
-
body.push(...textOf(block)
|
|
513
|
-
.split('\n')
|
|
514
|
-
.map((l) => cut(l, inner)));
|
|
515
|
-
}
|
|
516
|
-
else {
|
|
517
|
-
// Plain, not styled: `wrap` counts characters, and a bold run
|
|
518
|
-
// measured with its escape codes in it folds the line early.
|
|
519
|
-
body.push(...wrap(textOf(block, inner), inner));
|
|
520
|
-
}
|
|
521
|
-
}
|
|
498
|
+
const body = formatMarkdown(text, inner);
|
|
522
499
|
const rule = BOX.h.repeat(outer - 2);
|
|
523
500
|
return [
|
|
524
501
|
'',
|
|
@@ -586,7 +563,7 @@ export function absorb(event, out, sink, width) {
|
|
|
586
563
|
out.answer = content;
|
|
587
564
|
}
|
|
588
565
|
else if (content) {
|
|
589
|
-
sink.narrate(cut(content.replace(/\s+/g, ' '), width));
|
|
566
|
+
sink.narrate(cut(formatInline(content.replace(/\s+/g, ' ')), width));
|
|
590
567
|
}
|
|
591
568
|
break;
|
|
592
569
|
}
|
package/dist/resolve.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { existsSync } from 'node:fs';
|
|
2
|
-
import { relative, resolve, sep } from 'node:path';
|
|
2
|
+
import { isAbsolute, relative, resolve, sep } from 'node:path';
|
|
3
3
|
import { stamp } from "./ids.js";
|
|
4
4
|
import * as Projects from "./projects.js";
|
|
5
5
|
import { createSession, listSessions, readSessionMeta, requireSession, sessionPaths, } from "./session.js";
|
|
6
|
-
import
|
|
6
|
+
import * as term from "./term.js";
|
|
7
|
+
import { ago, bold, cyan, dim, usageError, yellow } from "./term.js";
|
|
7
8
|
// ---------------------------------------------------------------------------
|
|
8
9
|
// Project
|
|
9
10
|
// ---------------------------------------------------------------------------
|
|
@@ -20,7 +21,7 @@ export async function project(want) {
|
|
|
20
21
|
if (known.length === 0) {
|
|
21
22
|
throw usageError('not inside a project, and none are registered', 'create one: zen init');
|
|
22
23
|
}
|
|
23
|
-
if (!isInteractive()) {
|
|
24
|
+
if (!term.isInteractive()) {
|
|
24
25
|
throw usageError('not inside a project', 'name one with --project');
|
|
25
26
|
}
|
|
26
27
|
// Most recently worked in first: the answer to "which project" is nearly
|
|
@@ -29,7 +30,7 @@ export async function project(want) {
|
|
|
29
30
|
const ranked = known
|
|
30
31
|
.map((entry) => ({ entry, used: Projects.lastUsedAt(entry.path) ?? '' }))
|
|
31
32
|
.sort((a, b) => b.used.localeCompare(a.used) || a.entry.name.localeCompare(b.entry.name));
|
|
32
|
-
const chosen = await choose('Which project?', ranked.map(({ entry }) => ({ label: entry.name, detail: entry.path, value: entry })));
|
|
33
|
+
const chosen = await term.choose('Which project?', ranked.map(({ entry }) => ({ label: entry.name, detail: entry.path, value: entry })));
|
|
33
34
|
return Projects.openDir(chosen.path);
|
|
34
35
|
}
|
|
35
36
|
// ---------------------------------------------------------------------------
|
|
@@ -89,11 +90,11 @@ async function pickExisting(projectDir) {
|
|
|
89
90
|
if (all.length === 0) {
|
|
90
91
|
return undefined;
|
|
91
92
|
}
|
|
92
|
-
if (!isInteractive()) {
|
|
93
|
+
if (!term.isInteractive()) {
|
|
93
94
|
return sessionPaths(projectDir, all[0].id);
|
|
94
95
|
}
|
|
95
96
|
const sessions = all.slice(0, MAX_SESSIONS);
|
|
96
|
-
const choice = await choose('Session', [
|
|
97
|
+
const choice = await term.choose('Session', [
|
|
97
98
|
{
|
|
98
99
|
key: '0',
|
|
99
100
|
label: bold(cyan('New session…')),
|
|
@@ -137,10 +138,10 @@ export async function chooseWorkspace(session, want) {
|
|
|
137
138
|
await approve(at, session, want);
|
|
138
139
|
return at;
|
|
139
140
|
}
|
|
140
|
-
if (!isInteractive()) {
|
|
141
|
+
if (!term.isInteractive()) {
|
|
141
142
|
return own;
|
|
142
143
|
}
|
|
143
|
-
const chosen = await choose('Workspace — what the agent can read and write', [
|
|
144
|
+
const chosen = await term.choose('Workspace — what the agent can read and write', [
|
|
144
145
|
{ label: 'A fresh, empty directory', detail: own, value: own },
|
|
145
146
|
{ label: 'The directory you started in', detail: want.cwd, value: want.cwd },
|
|
146
147
|
]);
|
|
@@ -151,20 +152,26 @@ async function approve(at, session, want) {
|
|
|
151
152
|
if (contains(session.dir, at)) {
|
|
152
153
|
return;
|
|
153
154
|
}
|
|
154
|
-
|
|
155
|
+
if (!want.workspace) {
|
|
156
|
+
term.warn(`the agent will be able to read and write ${at}`);
|
|
157
|
+
}
|
|
155
158
|
if (want.yes) {
|
|
156
159
|
return;
|
|
157
160
|
}
|
|
158
|
-
if (!isInteractive()) {
|
|
161
|
+
if (!term.isInteractive()) {
|
|
159
162
|
throw usageError('refusing a workspace outside the session without confirmation', 'pass --yes if that is what you meant');
|
|
160
163
|
}
|
|
161
|
-
if (!(await confirm('Continue?'))) {
|
|
164
|
+
if (!(await term.confirm('Continue?'))) {
|
|
162
165
|
throw usageError('cancelled');
|
|
163
166
|
}
|
|
164
167
|
}
|
|
165
168
|
function contains(parent, child) {
|
|
166
169
|
const from = resolve(parent);
|
|
167
170
|
const to = resolve(child);
|
|
168
|
-
|
|
171
|
+
if (from === to) {
|
|
172
|
+
return true;
|
|
173
|
+
}
|
|
174
|
+
const rel = relative(from, to);
|
|
175
|
+
return !rel.startsWith(`..${sep}`) && rel !== '..' && !isAbsolute(rel);
|
|
169
176
|
}
|
|
170
177
|
//# sourceMappingURL=resolve.js.map
|
package/dist/sandbox.js
CHANGED
package/dist/scaffold.js
CHANGED
|
@@ -33,6 +33,8 @@ import { fileURLToPath } from 'node:url';
|
|
|
33
33
|
const TEMPLATES = fileURLToPath(new URL('../templates', import.meta.url));
|
|
34
34
|
/** The suffix on a file with `{{...}}` in it, dropped when the file lands. */
|
|
35
35
|
const TEMPLATE = '.tmpl';
|
|
36
|
+
/** How to use file tools: a house rules file, landing under `agents/`. */
|
|
37
|
+
const FILE_RULES = join('agents', 'files-instructions.md');
|
|
36
38
|
/** How to use the memory graph: a house rules file, landing under `agents/`. */
|
|
37
39
|
const MEMORY_RULES = join('agents', 'memory-instructions.md');
|
|
38
40
|
/** How tools are called: the same, and equally not the project's to maintain. */
|
|
@@ -51,7 +53,7 @@ const FORK_RULES = join('agents', 'fork-instructions.md');
|
|
|
51
53
|
* place: project policy on any of those subjects goes in a topic file of its
|
|
52
54
|
* own beside them.
|
|
53
55
|
*/
|
|
54
|
-
export const SHARED_RULES = [FORK_RULES, MEMORY_RULES, TOOL_RULES];
|
|
56
|
+
export const SHARED_RULES = [FILE_RULES, FORK_RULES, MEMORY_RULES, TOOL_RULES];
|
|
55
57
|
/** The same bytes, kept in the `zen-memory` skill to restore or diff against. */
|
|
56
58
|
const MEMORY_REFERENCE = join('.github', 'skills', 'zen-memory', 'references', 'memory-instructions.md');
|
|
57
59
|
/**
|
package/dist/term.d.ts
CHANGED
|
@@ -26,6 +26,8 @@ export declare const CHROME: Record<Appearance, number>;
|
|
|
26
26
|
/** What the terminal looks like, as far as can be known without asking it. */
|
|
27
27
|
export declare function appearance(): Appearance;
|
|
28
28
|
export declare const bold: (s: string) => string;
|
|
29
|
+
export declare const italic: (s: string) => string;
|
|
30
|
+
export declare const underline: (s: string) => string;
|
|
29
31
|
/**
|
|
30
32
|
* One step quieter, which is half of everything this tool prints: paths,
|
|
31
33
|
* counts, hints, the second column of every table.
|
package/dist/term.js
CHANGED
|
@@ -88,6 +88,8 @@ function fromAppleTerminal() {
|
|
|
88
88
|
// Styling
|
|
89
89
|
// ---------------------------------------------------------------------------
|
|
90
90
|
export const bold = (s) => styleText('bold', s);
|
|
91
|
+
export const italic = (s) => styleText('italic', s);
|
|
92
|
+
export const underline = (s) => styleText('underline', s);
|
|
91
93
|
/**
|
|
92
94
|
* One step quieter, which is half of everything this tool prints: paths,
|
|
93
95
|
* counts, hints, the second column of every table.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type Block, type Span } from './wrap.ts';
|
|
2
|
+
export declare function wrapSpans(spans: readonly Span[], width: number, prefix?: string, subsequentPrefix?: string): string[];
|
|
3
|
+
/**
|
|
4
|
+
* Render a sequence of AST `Block`s into styled terminal lines wrapped to `width`.
|
|
5
|
+
*/
|
|
6
|
+
export declare function formatBlocks(blocks: readonly Block[], width?: number): string[];
|
|
7
|
+
/**
|
|
8
|
+
* Format markdown text into styled ANSI terminal lines wrapped to `width`.
|
|
9
|
+
*/
|
|
10
|
+
export declare function formatMarkdown(text: string, width?: number): string[];
|
|
11
|
+
/**
|
|
12
|
+
* Format inline markdown text (bold, italic, code, links) into a styled ANSI string.
|
|
13
|
+
* Markers like backticks and asterisks are resolved and removed.
|
|
14
|
+
*/
|
|
15
|
+
export declare function formatInline(text: string): string;
|
|
16
|
+
//# sourceMappingURL=markdown.d.ts.map
|