@orchestraworks/cli 0.5.0 → 0.5.1
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 +15 -11
- package/dist/cli/core/banner.d.ts +10 -0
- package/dist/cli/core/banner.js +63 -0
- package/dist/cli/core/package-root.d.ts +3 -2
- package/dist/cli/core/package-root.js +4 -4
- package/dist/cli/core/skill-pointer.d.ts +7 -2
- package/dist/cli/core/skill-pointer.js +13 -3
- package/dist/cli/main.js +5 -3
- package/dist/cli/skill-install-fs.d.ts +0 -2
- package/dist/cli/skill-install-fs.js +0 -2
- package/node_modules/@orchestraworks/client/package.json +1 -1
- package/package.json +2 -2
- package/skills/orchestra/SKILL.md +138 -123
- package/skills/orchestra-fdk/SKILL.md +269 -120
- package/skills/orchestra-fdk/references/authoring.md +12 -1
- package/skills/orchestra-fdk/references/environment.md +39 -24
package/README.md
CHANGED
|
@@ -2,6 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
The `orchestra` command line and the FDK library: write your software factory in TypeScript and apply it to the Orchestra platform.
|
|
4
4
|
|
|
5
|
+
## For coding agents
|
|
6
|
+
|
|
7
|
+
Do these steps in order.
|
|
8
|
+
|
|
9
|
+
1. Install the CLI: `npm install -g @orchestraworks/cli && orchestra --help`. Or run `npm install @orchestraworks/cli` in the factory folder. The help ends with the paths of the two skills on this machine.
|
|
10
|
+
2. Read both skills. Read [skills/orchestra/SKILL.md](https://unpkg.com/@orchestraworks/cli/skills/orchestra/SKILL.md) to learn how to use the orchestra CLI, and [skills/orchestra-fdk/SKILL.md](https://unpkg.com/@orchestraworks/cli/skills/orchestra-fdk/SKILL.md) to set up a factory.
|
|
11
|
+
3. To link both skills into your harness, run `orchestra skills install --harness claude --scope project` (or `--harness codex`) in the factory folder.
|
|
12
|
+
4. Follow the `orchestra-fdk` skill. It tells you what to ask the developer and which commands to run.
|
|
13
|
+
|
|
14
|
+
The full guide to every construct, secrets, connections and troubleshooting is [docs/REFERENCE.md](https://unpkg.com/@orchestraworks/cli/docs/REFERENCE.md). `orchestra <command> --help` gives the flags of one command.
|
|
15
|
+
|
|
5
16
|
## Install
|
|
6
17
|
|
|
7
18
|
- **Node ≥ 22** is required.
|
|
@@ -9,13 +20,15 @@ The `orchestra` command line and the FDK library: write your software factory in
|
|
|
9
20
|
```bash
|
|
10
21
|
npm install -g @orchestraworks/cli # the CLI, on your path as `orchestra`
|
|
11
22
|
npm install @orchestraworks/cli # the current release
|
|
12
|
-
npm install @orchestraworks/cli@0.5.
|
|
23
|
+
npm install @orchestraworks/cli@0.5.1 # this exact release
|
|
13
24
|
```
|
|
14
25
|
|
|
15
26
|
Then `import { Factory, Agent, … } from "@orchestraworks/cli"` normally — the package `exports` entry resolves
|
|
16
27
|
to the built `dist/` that ships inside this package, so there is nothing to build. Run the CLI
|
|
17
28
|
as `orchestra …` after the global install, or as `npx orchestra …` from a folder that installed the package.
|
|
18
29
|
|
|
30
|
+
`npm update -g @orchestraworks/cli` keeps a global install and both skills current. For a folder install, run `npm update @orchestraworks/cli` in that folder.
|
|
31
|
+
|
|
19
32
|
## Quick start
|
|
20
33
|
|
|
21
34
|
Make a new, empty folder and go into it. Run every command from the **factory directory**: this folder, which holds `fdk.json` after `fdk init`.
|
|
@@ -30,15 +43,6 @@ orchestra fdk apply # make the platform mat
|
|
|
30
43
|
|
|
31
44
|
Before `fdk apply`, read the `README.md` that `fdk init` writes. It names the values to set.
|
|
32
45
|
|
|
33
|
-
## For coding agents
|
|
34
|
-
|
|
35
|
-
- `skills/orchestra/SKILL.md`: the platform's ideas, how the CLI works, and what it cannot do yet.
|
|
36
|
-
- `skills/orchestra-fdk/SKILL.md`: how to build and apply a factory for an existing codebase.
|
|
37
|
-
- `orchestra --help` lists every command. `orchestra <command> --help` gives its flags.
|
|
38
|
-
- [docs/REFERENCE.md](docs/REFERENCE.md): the full guide to every construct, secrets, connections and troubleshooting.
|
|
39
|
-
|
|
40
|
-
`orchestra skills install` links both skills into your coding harness. Read the `SKILL.md` in each skill folder the command prints. The CLI may be installed globally or in your factory folder. `npm update -g @orchestraworks/cli` keeps a global install and both skills current; for a folder install, run `npm update @orchestraworks/cli` in that folder.
|
|
41
|
-
|
|
42
46
|
## License
|
|
43
47
|
|
|
44
|
-
Apache License 2.0. The full text is in [LICENSE](LICENSE).
|
|
48
|
+
Apache License 2.0. The full text is in [LICENSE](https://unpkg.com/@orchestraworks/cli/LICENSE).
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export interface BannerTerminal {
|
|
2
|
+
readonly isTTY?: boolean;
|
|
3
|
+
readonly columns?: number;
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* The banner and a blank line, or the empty string. `NO_COLOR` follows no-color.org: any non-empty value
|
|
7
|
+
* turns it off. `COLORTERM` of `truecolor` or `24bit` selects 24-bit color. A terminal narrower than the
|
|
8
|
+
* mark and the wordmark gets the mark with the plain word beside its centre.
|
|
9
|
+
*/
|
|
10
|
+
export declare function helpBanner(terminal: BannerTerminal, env: NodeJS.ProcessEnv): string;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
// The Orchestra mark at the top of bare `orchestra` and `orchestra --help`, for a person at a terminal.
|
|
2
|
+
// A coding agent usually reads piped output, so the banner prints only to a terminal with color allowed:
|
|
3
|
+
// piped output stays plain text with no escape codes.
|
|
4
|
+
/**
|
|
5
|
+
* The console's 48-dot mark (`console/src/components/BrandMark.tsx`), its circles rasterized onto a
|
|
6
|
+
* 42-by-40 dot grid and written as braille, eight dots to a character.
|
|
7
|
+
*/
|
|
8
|
+
const MARK = [
|
|
9
|
+
"⠀⠀⠀⠀⢀⣤⡀⠀⠀⣴⣶⡄⣼⣿⡆⠀⠀⠀⠀⠀⠀",
|
|
10
|
+
"⠀⠀⠀⠀⠹⠿⠧⣿⡆⠈⠉⣶⡌⢹⣷⡄⢀⣀⠀⠀⠀",
|
|
11
|
+
"⢠⣶⣄⣿⡷⢰⣶⠀⠀⠿⠀⢈⡀⢀⣭⠀⢿⡿⠂⠀⠀",
|
|
12
|
+
"⠘⠛⢋⣤⡀⢠⡄⠀⠶⠀⠀⠈⠁⠈⠉⠀⣿⠆⣾⣿⡇",
|
|
13
|
+
"⢰⣿⡯⠙⣁⠀⠀⣤⠀⠀⠉⠀⠙⠀⠰⠆⠀⢴⣿⡍⠀",
|
|
14
|
+
"⠀⠉⣤⣌⠛⠀⣤⠀⠀⠒⠀⣀⠀⢴⠄⠐⠿⠂⣩⣄⠀",
|
|
15
|
+
"⠀⣤⣿⠋⣤⡄⢀⡀⠀⠦⠀⢀⠀⢀⣤⠀⣶⣮⠿⠿⠀",
|
|
16
|
+
"⠀⠻⠟⢁⣭⡅⠈⡋⠀⣀⡀⠛⢀⣤⡁⣠⣍⠁⠀⠀⠀",
|
|
17
|
+
"⠀⠀⠀⠘⣻⣧⡸⠿⣂⡙⢣⣤⡄⣙⡁⠻⠟⠀⠀⠀⠀",
|
|
18
|
+
"⠀⠀⠀⠀⠻⠿⠇⠸⣿⠗⠈⠛⠹⣿⡿⠀⠀⠀⠀⠀⠀",
|
|
19
|
+
];
|
|
20
|
+
/** "ORCHESTRA" in the figlet ANSI Shadow face. */
|
|
21
|
+
const WORDMARK = [
|
|
22
|
+
" ██████╗ ██████╗ ██████╗██╗ ██╗███████╗███████╗████████╗██████╗ █████╗ ",
|
|
23
|
+
"██╔═══██╗██╔══██╗██╔════╝██║ ██║██╔════╝██╔════╝╚══██╔══╝██╔══██╗██╔══██╗",
|
|
24
|
+
"██║ ██║██████╔╝██║ ███████║█████╗ ███████╗ ██║ ██████╔╝███████║",
|
|
25
|
+
"██║ ██║██╔══██╗██║ ██╔══██║██╔══╝ ╚════██║ ██║ ██╔══██╗██╔══██║",
|
|
26
|
+
"╚██████╔╝██║ ██║╚██████╗██║ ██║███████╗███████║ ██║ ██║ ██║██║ ██║",
|
|
27
|
+
" ╚═════╝ ╚═╝ ╚═╝ ╚═════╝╚═╝ ╚═╝╚══════╝╚══════╝ ╚═╝ ╚═╝ ╚═╝╚═╝ ╚═╝",
|
|
28
|
+
];
|
|
29
|
+
const MARK_WIDTH = MARK[0].length;
|
|
30
|
+
const GAP = " ";
|
|
31
|
+
/** The mark and the wordmark side by side. */
|
|
32
|
+
const BANNER_WIDTH = MARK_WIDTH + GAP.length + WORDMARK[0].length;
|
|
33
|
+
/** The first mark row the wordmark sits on, which centres it on the mark. */
|
|
34
|
+
const WORDMARK_TOP = Math.floor((MARK.length - WORDMARK.length) / 2);
|
|
35
|
+
const WORD = "Orchestra";
|
|
36
|
+
/** The console's light-theme accent, `consolePalette.json` `light.accent`, as 24-bit RGB. */
|
|
37
|
+
const ACCENT_TRUE_COLOR = "\u001b[38;2;66;99;235m";
|
|
38
|
+
/** The nearest color in the 256-color table, for a terminal that does not announce 24-bit color. */
|
|
39
|
+
const ACCENT_256 = "\u001b[38;5;63m";
|
|
40
|
+
const BOLD = "\u001b[1m";
|
|
41
|
+
const RESET = "\u001b[0m";
|
|
42
|
+
/**
|
|
43
|
+
* The banner and a blank line, or the empty string. `NO_COLOR` follows no-color.org: any non-empty value
|
|
44
|
+
* turns it off. `COLORTERM` of `truecolor` or `24bit` selects 24-bit color. A terminal narrower than the
|
|
45
|
+
* mark and the wordmark gets the mark with the plain word beside its centre.
|
|
46
|
+
*/
|
|
47
|
+
export function helpBanner(terminal, env) {
|
|
48
|
+
if (terminal.isTTY !== true || (env.NO_COLOR ?? "") !== "") {
|
|
49
|
+
return "";
|
|
50
|
+
}
|
|
51
|
+
const accent = /^(truecolor|24bit)$/i.test(env.COLORTERM ?? "") ? ACCENT_TRUE_COLOR : ACCENT_256;
|
|
52
|
+
const wide = (terminal.columns ?? BANNER_WIDTH) >= BANNER_WIDTH;
|
|
53
|
+
const lines = MARK.map((row, index) => {
|
|
54
|
+
if (wide) {
|
|
55
|
+
const word = WORDMARK[index - WORDMARK_TOP];
|
|
56
|
+
return word === undefined ? `${accent}${row}${RESET}` : `${accent}${row}${GAP}${word.trimEnd()}${RESET}`;
|
|
57
|
+
}
|
|
58
|
+
return index === Math.floor(MARK.length / 2)
|
|
59
|
+
? `${accent}${row}${RESET}${GAP}${BOLD}${WORD}${RESET}`
|
|
60
|
+
: `${accent}${row}${RESET}`;
|
|
61
|
+
});
|
|
62
|
+
return `${lines.join("\n")}\n\n`;
|
|
63
|
+
}
|
|
@@ -1,11 +1,12 @@
|
|
|
1
|
+
import { type KitSkill } from "../skill-install-fs.js";
|
|
1
2
|
/**
|
|
2
3
|
* The package root this process runs from. Under `npx orchestra` outside an installed folder this is npm's
|
|
3
4
|
* disposable cache, which `skills install` refuses to link into.
|
|
4
5
|
*/
|
|
5
6
|
export declare function runningPackageRoot(): string;
|
|
6
7
|
/**
|
|
7
|
-
*
|
|
8
|
+
* A bundled skill's path, or `null` when this install does not carry it. The exists-guard is the
|
|
8
9
|
* contract: callers print this as a pointer to follow, and pointing a reader at a path with nothing behind
|
|
9
10
|
* it is a worse repair than printing none. `packageRoot` is the test seam.
|
|
10
11
|
*/
|
|
11
|
-
export declare function resolveBundledSkillPath(packageRoot?: string): string | null;
|
|
12
|
+
export declare function resolveBundledSkillPath(packageRoot?: string, skill?: KitSkill): string | null;
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
import { existsSync } from "node:fs";
|
|
7
7
|
import { join } from "node:path";
|
|
8
8
|
import { fileURLToPath } from "node:url";
|
|
9
|
-
import {
|
|
9
|
+
import { SKILL_FILE_NAME, skillPackageDir } from "../skill-install-fs.js";
|
|
10
10
|
/**
|
|
11
11
|
* The package root this process runs from. Under `npx orchestra` outside an installed folder this is npm's
|
|
12
12
|
* disposable cache, which `skills install` refuses to link into.
|
|
@@ -15,11 +15,11 @@ export function runningPackageRoot() {
|
|
|
15
15
|
return fileURLToPath(new URL("../../..", import.meta.url));
|
|
16
16
|
}
|
|
17
17
|
/**
|
|
18
|
-
*
|
|
18
|
+
* A bundled skill's path, or `null` when this install does not carry it. The exists-guard is the
|
|
19
19
|
* contract: callers print this as a pointer to follow, and pointing a reader at a path with nothing behind
|
|
20
20
|
* it is a worse repair than printing none. `packageRoot` is the test seam.
|
|
21
21
|
*/
|
|
22
|
-
export function resolveBundledSkillPath(packageRoot = runningPackageRoot()) {
|
|
23
|
-
const skillPath = join(packageRoot,
|
|
22
|
+
export function resolveBundledSkillPath(packageRoot = runningPackageRoot(), skill = "orchestra") {
|
|
23
|
+
const skillPath = join(packageRoot, skillPackageDir(skill), SKILL_FILE_NAME);
|
|
24
24
|
return existsSync(skillPath) ? skillPath : null;
|
|
25
25
|
}
|
|
@@ -5,10 +5,15 @@ export interface SkillPointer {
|
|
|
5
5
|
readonly fields: {
|
|
6
6
|
readonly skillPath: string;
|
|
7
7
|
};
|
|
8
|
+
/**
|
|
9
|
+
* The lines `orchestra` and `orchestra --help` end with. A coding agent often runs the help right after the
|
|
10
|
+
* install, and npm hides install-script output, so this tail is where the agent learns which skill to read.
|
|
11
|
+
*/
|
|
12
|
+
readonly helpEpilogue: readonly string[];
|
|
8
13
|
}
|
|
9
14
|
/**
|
|
10
15
|
* `null` when this install carries no bundled manual, in which case every surface prints nothing at all.
|
|
11
|
-
* Omission is the contract, not a degraded mode. `skillPath`
|
|
16
|
+
* Omission is the contract, not a degraded mode. `skillPath` and `setupSkillPath` are the test seams.
|
|
12
17
|
*/
|
|
13
|
-
export declare function bundledSkillPointer(skillPath?: string | null): SkillPointer | null;
|
|
18
|
+
export declare function bundledSkillPointer(skillPath?: string | null, setupSkillPath?: string | null): SkillPointer | null;
|
|
14
19
|
export declare function emitSkillPointer(io: CliIo, pointer?: SkillPointer | null): void;
|
|
@@ -1,13 +1,23 @@
|
|
|
1
1
|
import { resolveBundledSkillPath } from "./package-root.js";
|
|
2
2
|
/**
|
|
3
3
|
* `null` when this install carries no bundled manual, in which case every surface prints nothing at all.
|
|
4
|
-
* Omission is the contract, not a degraded mode. `skillPath`
|
|
4
|
+
* Omission is the contract, not a degraded mode. `skillPath` and `setupSkillPath` are the test seams.
|
|
5
5
|
*/
|
|
6
|
-
export function bundledSkillPointer(skillPath = resolveBundledSkillPath()) {
|
|
6
|
+
export function bundledSkillPointer(skillPath = resolveBundledSkillPath(), setupSkillPath = resolveBundledSkillPath(undefined, "orchestra-fdk")) {
|
|
7
7
|
if (skillPath === null) {
|
|
8
8
|
return null;
|
|
9
9
|
}
|
|
10
|
-
return {
|
|
10
|
+
return {
|
|
11
|
+
line: `Learn orchestra: read ${skillPath}`,
|
|
12
|
+
fields: { skillPath },
|
|
13
|
+
helpEpilogue: [
|
|
14
|
+
"Coding agents: read both skills before you start.",
|
|
15
|
+
` To learn how to use the orchestra CLI, read ${skillPath}`,
|
|
16
|
+
...(setupSkillPath === null ? [] : [` To set up a factory, read ${setupSkillPath}`]),
|
|
17
|
+
" To link both skills into your harness, run:",
|
|
18
|
+
" orchestra skills install --harness claude|codex --scope project",
|
|
19
|
+
],
|
|
20
|
+
};
|
|
11
21
|
}
|
|
12
22
|
export function emitSkillPointer(io, pointer = bundledSkillPointer()) {
|
|
13
23
|
if (pointer !== null) {
|
package/dist/cli/main.js
CHANGED
|
@@ -37,6 +37,7 @@ import { DEFAULT_TEMPLATE, initCommand, MODEL_KEY_CHOICES, OFFERED_TEMPLATES } f
|
|
|
37
37
|
import { grantCommand } from "./api/grant.js";
|
|
38
38
|
import { addAuthOptions } from "./core/invocation.js";
|
|
39
39
|
import { errorDocument, reportError, settleExitCode } from "./core/errors.js";
|
|
40
|
+
import { helpBanner } from "./core/banner.js";
|
|
40
41
|
import { bundledSkillPointer, emitSkillPointer } from "./core/skill-pointer.js";
|
|
41
42
|
import { outputModeFromArgv } from "./core/output-mode.js";
|
|
42
43
|
import { defaultIo, writeLines } from "./core/output.js";
|
|
@@ -170,7 +171,7 @@ LEARN MORE
|
|
|
170
171
|
* entirely. `pointer` is the test seam.
|
|
171
172
|
*/
|
|
172
173
|
export function topLevelHelpText(pointer = bundledSkillPointer()) {
|
|
173
|
-
return pointer === null ? TOP_LEVEL_HELP : `${TOP_LEVEL_HELP}\n${pointer.
|
|
174
|
+
return pointer === null ? TOP_LEVEL_HELP : `${TOP_LEVEL_HELP}\n${pointer.helpEpilogue.join("\n")}\n`;
|
|
174
175
|
}
|
|
175
176
|
const REQUIRE_APPROVAL_HELP = requireApprovalHelp(IMPERATIVE_APPROVAL_DEFAULT);
|
|
176
177
|
/**
|
|
@@ -294,9 +295,10 @@ export function buildProgram(handlers = defaultHandlers, pointer = bundledSkillP
|
|
|
294
295
|
// Deliberately an own-property assignment and NOT `configureHelp`: commander copies `_helpConfiguration`
|
|
295
296
|
// into every subcommand created afterwards, so configuring the formatter here would make every
|
|
296
297
|
// `--help` print the top-level text too. The text is computed once and the closure returns that same
|
|
297
|
-
// string every time, so `--help` printed twice in one process cannot disagree with itself.
|
|
298
|
+
// string every time, so `--help` printed twice in one process cannot disagree with itself. The banner
|
|
299
|
+
// above it depends on the stream the help goes to: stderr for a bare `orchestra`, stdout for `--help`.
|
|
298
300
|
const helpText = topLevelHelpText(pointer);
|
|
299
|
-
program.helpInformation = () => helpText
|
|
301
|
+
program.helpInformation = (context) => `${helpBanner(context?.error === true ? process.stderr : process.stdout, process.env)}${helpText}`;
|
|
300
302
|
// Registered on the program, which is where commander looks: it walks a command's ancestors when an action
|
|
301
303
|
// fires, so one hook here covers the whole tree. It runs after parsing, so `--help` and a usage error —
|
|
302
304
|
// both of which end during the parse — never reach it.
|
|
@@ -10,8 +10,6 @@ export declare const KIT_INSTALL_SPEC = "@orchestraworks/cli";
|
|
|
10
10
|
export declare const KIT_SKILLS: readonly ["orchestra", "orchestra-fdk"];
|
|
11
11
|
export type KitSkill = (typeof KIT_SKILLS)[number];
|
|
12
12
|
export declare function skillPackageDir(skill: KitSkill): string;
|
|
13
|
-
/** The reference skill's directory, which the CLI's own pointer names. */
|
|
14
|
-
export declare const SKILL_DIR_IN_PACKAGE: string;
|
|
15
13
|
export declare const SKILL_FILE_NAME = "SKILL.md";
|
|
16
14
|
/** "other" is a printed-path branch, never a link target. */
|
|
17
15
|
export type LinkableHarness = "claude" | "codex";
|
|
@@ -16,8 +16,6 @@ export const KIT_SKILLS = ["orchestra", "orchestra-fdk"];
|
|
|
16
16
|
export function skillPackageDir(skill) {
|
|
17
17
|
return join("skills", skill);
|
|
18
18
|
}
|
|
19
|
-
/** The reference skill's directory, which the CLI's own pointer names. */
|
|
20
|
-
export const SKILL_DIR_IN_PACKAGE = skillPackageDir("orchestra");
|
|
21
19
|
export const SKILL_FILE_NAME = "SKILL.md";
|
|
22
20
|
/**
|
|
23
21
|
* Identical under a project root and under `$HOME`. The ONE home for these strings: the link math, the menu
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@orchestraworks/cli",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "The Orchestra command line.",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -109,7 +109,7 @@
|
|
|
109
109
|
},
|
|
110
110
|
"dependencies": {
|
|
111
111
|
"@agentclientprotocol/sdk": "1.3.0",
|
|
112
|
-
"@orchestraworks/client": "0.5.
|
|
112
|
+
"@orchestraworks/client": "0.5.1",
|
|
113
113
|
"@orchestraworks/worker": "0.0.136",
|
|
114
114
|
"commander": "^14.0.0",
|
|
115
115
|
"liquidjs": "^10.28.0"
|