@orchestraworks/cli 0.3.0 → 0.5.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 (38) hide show
  1. package/README.md +20 -1257
  2. package/dist/cli/core/invocation.js +1 -1
  3. package/dist/cli/factory/init.d.ts +1 -1
  4. package/dist/cli/factory/init.js +41 -13
  5. package/dist/cli/main.js +0 -0
  6. package/dist/cli/skill.js +20 -7
  7. package/docs/REFERENCE.md +1278 -0
  8. package/node_modules/@orchestraworks/client/package.json +1 -1
  9. package/package.json +7 -8
  10. package/skills/orchestra/SKILL.md +29 -3
  11. package/skills/orchestra-fdk/SKILL.md +68 -10
  12. package/skills/orchestra-fdk/references/authoring.md +14 -14
  13. package/templates/bug-fix/tsconfig.json +12 -0
  14. package/templates/engineering-team/lib/setup.sh +16 -0
  15. package/templates/engineering-team/package.json +1 -1
  16. package/templates/todo-factory/package.json +1 -1
  17. package/node_modules/@orchestraworks/workflow-render/LICENSE +0 -202
  18. package/node_modules/@orchestraworks/workflow-render/dist/constants.d.ts +0 -98
  19. package/node_modules/@orchestraworks/workflow-render/dist/context.d.ts +0 -37
  20. package/node_modules/@orchestraworks/workflow-render/dist/geometry-core.d.ts +0 -40
  21. package/node_modules/@orchestraworks/workflow-render/dist/graph-digest.d.ts +0 -4
  22. package/node_modules/@orchestraworks/workflow-render/dist/grid.d.ts +0 -33
  23. package/node_modules/@orchestraworks/workflow-render/dist/heuristic.d.ts +0 -7
  24. package/node_modules/@orchestraworks/workflow-render/dist/identity.d.ts +0 -9
  25. package/node_modules/@orchestraworks/workflow-render/dist/index.d.ts +0 -24
  26. package/node_modules/@orchestraworks/workflow-render/dist/index.js +0 -1
  27. package/node_modules/@orchestraworks/workflow-render/dist/layout.d.ts +0 -6
  28. package/node_modules/@orchestraworks/workflow-render/dist/normalize.d.ts +0 -33
  29. package/node_modules/@orchestraworks/workflow-render/dist/place.d.ts +0 -81
  30. package/node_modules/@orchestraworks/workflow-render/dist/ports.d.ts +0 -15
  31. package/node_modules/@orchestraworks/workflow-render/dist/presence.d.ts +0 -6
  32. package/node_modules/@orchestraworks/workflow-render/dist/route-cells.d.ts +0 -15
  33. package/node_modules/@orchestraworks/workflow-render/dist/sha256.d.ts +0 -3
  34. package/node_modules/@orchestraworks/workflow-render/dist/svg.d.ts +0 -7
  35. package/node_modules/@orchestraworks/workflow-render/dist/text.d.ts +0 -14
  36. package/node_modules/@orchestraworks/workflow-render/dist/types.d.ts +0 -310
  37. package/node_modules/@orchestraworks/workflow-render/dist/verify.d.ts +0 -26
  38. package/node_modules/@orchestraworks/workflow-render/package.json +0 -42
@@ -14,7 +14,7 @@ import { errorCode } from "./errors.js";
14
14
  export function addAuthOptions(command) {
15
15
  return command
16
16
  .option("--profile <name>", "named auth profile to read (default profile if omitted)")
17
- .option("--base-url <url>", "platform base URL (overrides PLATFORM_BASE_URL and the stored profile)")
17
+ .option("--base-url <url>", "platform base URL (overrides ORCHESTRA_BASE_URL, PLATFORM_BASE_URL and the stored profile)")
18
18
  .option("--org <id>", "target organization id (overrides ORCHESTRA_ORGANIZATION_ID and the stored profile)");
19
19
  }
20
20
  /**
@@ -13,7 +13,7 @@ type ModelKeyChoice = Exclude<TemplateChoice, "credits">;
13
13
  /** What `--model-key` takes. */
14
14
  export declare const MODEL_KEY_CHOICES: readonly ModelKeyChoice[];
15
15
  /** Every file the starter writes besides package.json, in the order it prints them. */
16
- export declare const STARTER_FILES: readonly ["fdk.json", "main.ts", "image/Dockerfile", "image/setup.sh", "agents/bugfix.md", "skills/codebase/SKILL.md"];
16
+ export declare const STARTER_FILES: readonly ["fdk.json", "tsconfig.json", "main.ts", "image/Dockerfile", "image/setup.sh", "agents/bugfix.md", "skills/codebase/SKILL.md"];
17
17
  /** The starter plain `orchestra fdk init` writes, and the only one `--repository` and `--model-key` fill in. */
18
18
  export declare const DEFAULT_TEMPLATE = "bug-fix";
19
19
  /** The starters `--template` offers by name. Each is a folder under templates/ that brings its own package.json. */
@@ -13,6 +13,7 @@ export const MODEL_KEY_CHOICES = TEMPLATE_CHOICES.filter((choice) => choice !==
13
13
  /** Every file the starter writes besides package.json, in the order it prints them. */
14
14
  export const STARTER_FILES = [
15
15
  "fdk.json",
16
+ "tsconfig.json",
16
17
  "main.ts",
17
18
  "image/Dockerfile",
18
19
  "image/setup.sh",
@@ -27,8 +28,12 @@ const TEMPLATES_DIR = "templates";
27
28
  const TEMPLATE_DIR = join(TEMPLATES_DIR, DEFAULT_TEMPLATE);
28
29
  /** The one template file `init` fills in; every other file is copied as it is. */
29
30
  const FILLED_FILE = "main.ts";
31
+ /** What runs main.ts and checks its types; each is added at the range the kit itself is built with. */
32
+ const STARTER_DEV_PACKAGES = ["tsx", "typescript", "@types/node"];
33
+ /** The script the starter adds when package.json has none of that name. */
34
+ const TYPECHECK_SCRIPT = { name: "typecheck", command: "tsc -p tsconfig.json" };
30
35
  /** Any other package in package.json means the folder is a codebase rather than a new folder beside one. */
31
- const PACKAGES_ALLOWED = new Set([KIT_PACKAGE_NAME, "tsx"]);
36
+ const PACKAGES_ALLOWED = new Set([KIT_PACKAGE_NAME, ...STARTER_DEV_PACKAGES]);
32
37
  const DEPENDENCY_FIELDS = ["dependencies", "devDependencies", "optionalDependencies", "peerDependencies"];
33
38
  /** Leaves room for the longest construct path the template declares, so every derived slug stays within 60. */
34
39
  const FACTORY_NAME_MAX = 30;
@@ -90,15 +95,24 @@ export async function initCommand(options, io = defaultIo) {
90
95
  };
91
96
  });
92
97
  const record = manifest.kind === "object" ? manifest.record : {};
93
- const addsTsx = !listsPackage(record, "tsx");
94
- const devDependencies = { ...dependencyMap(record, "devDependencies"), tsx: kitTsxRange(packageRoot) };
95
- const merged = { ...record, type: "module", ...(addsTsx ? { devDependencies } : {}) };
98
+ const added = STARTER_DEV_PACKAGES.filter((name) => !listsPackage(record, name));
99
+ const ranges = kitDevRanges(packageRoot, added);
100
+ const devDependencies = { ...dependencyMap(record, "devDependencies"), ...ranges };
101
+ // A `scripts` that is not an object is left as it is rather than replaced.
102
+ const addsTypecheck = record.scripts === undefined || (isRecord(record.scripts) && record.scripts[TYPECHECK_SCRIPT.name] === undefined);
103
+ const scripts = dependencyMap(record, "scripts");
104
+ const merged = {
105
+ ...record,
106
+ type: "module",
107
+ ...(addsTypecheck ? { scripts: { ...scripts, [TYPECHECK_SCRIPT.name]: TYPECHECK_SCRIPT.command } } : {}),
108
+ ...(added.length > 0 ? { devDependencies } : {}),
109
+ };
96
110
  writeFileSync(manifestPath, `${JSON.stringify(merged, null, 2)}\n`);
97
111
  for (const { path, text } of contents) {
98
112
  mkdirSync(dirname(join(dir, path)), { recursive: true });
99
113
  writeFileSync(join(dir, path), text);
100
114
  }
101
- printNextSteps(io, { repository: repository.full, factoryName, choice, dir, addsTsx });
115
+ printNextSteps(io, { repository: repository.full, factoryName, choice, dir, added, addsTypecheck });
102
116
  }
103
117
  /** The starters this kit carries: one folder each under templates/. */
104
118
  export function availableTemplates(packageRoot = runningPackageRoot()) {
@@ -325,14 +339,19 @@ function dependencyMap(record, field) {
325
339
  const value = record[field];
326
340
  return isRecord(value) ? value : {};
327
341
  }
328
- /** The tsx range the kit itself is tested with, so the starter runs on the tsx the kit was proven on. */
329
- function kitTsxRange(packageRoot) {
342
+ /** The ranges the kit itself is built and tested with, so the starter runs and type-checks on what the kit was proven on. */
343
+ function kitDevRanges(packageRoot, names) {
330
344
  const manifest = JSON.parse(readFileSync(join(packageRoot, "package.json"), "utf8"));
331
- const range = isRecord(manifest) ? dependencyMap(manifest, "devDependencies").tsx : undefined;
332
- if (typeof range !== "string") {
333
- throw new Error("this orchestra install names no tsx version to add. Reinstall the kit, then run orchestra fdk init again.");
345
+ const kitDev = isRecord(manifest) ? dependencyMap(manifest, "devDependencies") : {};
346
+ const ranges = {};
347
+ for (const name of names) {
348
+ const range = kitDev[name];
349
+ if (typeof range !== "string") {
350
+ throw new Error(`this orchestra install names no ${name} version to add. Reinstall the kit, then run orchestra fdk init again.`);
351
+ }
352
+ ranges[name] = range;
334
353
  }
335
- return range;
354
+ return ranges;
336
355
  }
337
356
  function isRecord(value) {
338
357
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -341,12 +360,17 @@ function printNextSteps(io, written) {
341
360
  const inputs = [...SHELL_INPUTS, ...(written.choice === "credits" ? [] : [MODEL_KEY_INPUTS[written.choice]])];
342
361
  const width = Math.max(...inputs.map(([name]) => name.length)) + 2;
343
362
  io.out(`Wrote a bug-fix factory named '${written.factoryName}' for ${written.repository} into ${written.dir}:`);
344
- io.out(` package.json (set "type": "module"${written.addsTsx ? ", added tsx to devDependencies" : ""})`);
363
+ const changes = [
364
+ `set "type": "module"`,
365
+ ...(written.addsTypecheck ? [`added the ${TYPECHECK_SCRIPT.name} script`] : []),
366
+ ...(written.added.length > 0 ? [`added ${listed(written.added)} to devDependencies`] : []),
367
+ ];
368
+ io.out(` package.json (${changes.join(", ")})`);
345
369
  for (const path of STARTER_FILES)
346
370
  io.out(` ${path}`);
347
371
  io.out("");
348
372
  io.out("Next, in this folder:");
349
- io.out(" 1. npm install");
373
+ io.out(" 1. npm install, then npm run typecheck");
350
374
  io.out(" 2. In the shell that runs orchestra, set these values. The platform's team hands them over until image");
351
375
  io.out(" hosting exists:");
352
376
  for (const [name, what] of inputs)
@@ -356,3 +380,7 @@ function printNextSteps(io, written) {
356
380
  io.out(" 3. npx orchestra fdk diff");
357
381
  io.out(" 4. npx orchestra fdk apply, then open the GitHub App install link it prints. It waits for the install.");
358
382
  }
383
+ /** `a`, `a and b`, or `a, b and c`. */
384
+ function listed(names) {
385
+ return names.length === 1 ? names[0] : `${names.slice(0, -1).join(", ")} and ${names[names.length - 1]}`;
386
+ }
package/dist/cli/main.js CHANGED
File without changes
package/dist/cli/skill.js CHANGED
@@ -21,8 +21,17 @@ const LINKABLE_HARNESSES = ["claude", "codex"];
21
21
  const HARNESS_LABEL = { claude: "Claude Code", codex: "Codex" };
22
22
  const HARNESS_VALUES = ["claude", "codex", "both", "other"];
23
23
  const SCOPE_VALUES = ["user", "project"];
24
- /** How a person keeps the linked skills current: the global install is updated in place. */
25
- const UPDATE_COMMAND = `npm update -g ${KIT_INSTALL_SPEC}`;
24
+ /**
25
+ * How a person keeps the linked skills current: the install the links point into is updated in place, so the
26
+ * command matches where the running package sits. A checkout outside both reads as global, the common case.
27
+ */
28
+ function updateCommand(running) {
29
+ return running.kind === "project" ? `npm update ${KIT_INSTALL_SPEC}` : `npm update -g ${KIT_INSTALL_SPEC}`;
30
+ }
31
+ /** The folder whose `node_modules` holds a project install: `<folder>/node_modules/@orchestraworks/cli`. */
32
+ function installFolder(packageRoot) {
33
+ return dirname(dirname(dirname(packageRoot)));
34
+ }
26
35
  export async function skillInstallCommand(options, deps = {}) {
27
36
  const io = deps.io ?? defaultIo;
28
37
  const env = deps.env ?? process.env;
@@ -90,14 +99,18 @@ export async function skillInstallCommand(options, deps = {}) {
90
99
  return;
91
100
  }
92
101
  io.out("");
93
- printSkillFiles(io, running.packageRoot);
102
+ printSkillFiles(io, running);
94
103
  }
95
104
  /** The step after the links: a harness loads a new skill only at its next start, so read them now. */
96
- function printSkillFiles(io, packageRoot) {
105
+ function printSkillFiles(io, running) {
97
106
  io.out("Read each skill now; your harness loads new skills only at its next start:");
98
107
  for (const skill of KIT_SKILLS)
99
- io.out(` ${skillFileIn(packageRoot, skill)}`);
100
- io.out(`\`${UPDATE_COMMAND}\` keeps them current.`);
108
+ io.out(` ${skillFileIn(running.packageRoot, skill)}`);
109
+ io.out("The kit may be installed globally or in the factory folder.");
110
+ io.out(running.kind === "project"
111
+ ? `This one is installed in ${installFolder(running.packageRoot)}, so \`${updateCommand(running)}\`, run in ` +
112
+ `that folder, keeps them current.`
113
+ : `This one is installed globally, so \`${updateCommand(running)}\` keeps them current.`);
101
114
  }
102
115
  function parseChoice(raw, allowed, flag) {
103
116
  if (raw === undefined) {
@@ -194,7 +207,7 @@ function printPointingInstructions(io, running, anchors, fs) {
194
207
  for (const file of skillFiles)
195
208
  io.out(` ${file}`);
196
209
  io.out("");
197
- io.out(`Point your harness at each directory (a link keeps it current across '${UPDATE_COMMAND}'):`);
210
+ io.out(`Point your harness at each directory (a link keeps it current across '${updateCommand(running)}'):`);
198
211
  for (const harness of LINKABLE_HARNESSES) {
199
212
  // The project leg prints the RELATIVE target the command itself would write, so a hand-made link
200
213
  // travels with the repo exactly like an installed one. Nothing recomputes after this line — the