mirror of
https://github.com/profullstack/logicsrc.git
synced 2026-10-03 05:07:10 +00:00
logicsrc CLI 0.2.0: every LogicSRC tool is a word after logicsrc (#157)
OpenContext, OpenCreds, OpenOntology and OpenPRD were already registered under the umbrella. Three were not: - `logicsrc openmcp …`: OpenMCP lives in its own repository, so it is a dependency (@logicsrc/openmcp ^0.3.1, which exports ./cli for this) and every argument goes untouched to the same main the standalone binary runs. Imported on first use, because the catalog is node:sqlite (Node 24) while the rest of the CLI runs on 18; below the floor that one word says so and offers the standalone installer, which brings its own Node. - `logicsrc openspec <anything else>`: import, export and change stay ours; any other word (init, list, validate, archive, show) runs OpenSpec.dev's own CLI (@fission-ai/openspec) as the group's default subcommand, flags intact. One command for a repo in compatibility mode, and the OpenSpec.dev half is upstream itself rather than a copy that would drift. - `logicsrc mcp`: the LogicSRC MCP server (@profullstack/logicsrc-mcp) over stdio, spawned as a child because it owns the process's stdio. build:cli now builds that workspace. README gets a table of every word and the standalone name it mirrors; the OpenMCP spec page and doc mention the umbrella form. Claude-Session: https://claude.ai/code/session_01Qh2dieNyPZ4Hx5g3XNJ1Eo Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
parent
0f6326e910
commit
8951e824d5
11 changed files with 1466 additions and 12 deletions
60
packages/cli/src/openspec-dev.ts
Normal file
60
packages/cli/src/openspec-dev.ts
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
import { spawn } from "node:child_process";
|
||||
import { createRequire } from "node:module";
|
||||
import { dirname, join } from "node:path";
|
||||
import type { Command } from "commander";
|
||||
|
||||
/**
|
||||
* `logicsrc openspec <anything OpenSpec.dev understands>`
|
||||
*
|
||||
* `logicsrc openspec` owns three words of its own (`import`, `export`,
|
||||
* `change`: the LogicSRC-shaped view of a repo's OpenSpec artifacts). Every
|
||||
* other word is OpenSpec.dev's, and goes to OpenSpec.dev's real CLI
|
||||
* (`@fission-ai/openspec`, the `openspec` binary) with the arguments exactly
|
||||
* as typed: `logicsrc openspec init`, `list`, `validate`, `archive`, `show`.
|
||||
* So a repo in compatibility mode needs one command installed, not two, and
|
||||
* the OpenSpec.dev half is the upstream tool itself rather than a
|
||||
* reimplementation of it that would drift.
|
||||
*
|
||||
* Spawned rather than imported: the package exports a library entry only, and
|
||||
* its bin does the argv parsing, colour and prompts. Its bin is not on the
|
||||
* exports map, so it is found from the package root instead of resolved by
|
||||
* name.
|
||||
*/
|
||||
export const OPENSPEC_PACKAGE = "@fission-ai/openspec";
|
||||
|
||||
/** Where OpenSpec.dev's bin lives, found from its package root. */
|
||||
export function openspecBin(resolveEntry: (id: string) => string = createRequire(import.meta.url).resolve): string {
|
||||
// The only export is dist/index.js; bin/openspec.js sits beside dist/.
|
||||
const entry = resolveEntry(OPENSPEC_PACKAGE);
|
||||
return join(dirname(dirname(entry)), "bin", "openspec.js");
|
||||
}
|
||||
|
||||
export function runOpenspec(args: string[], bin: string = openspecBin()): Promise<number> {
|
||||
return new Promise((resolve) => {
|
||||
const child = spawn(process.execPath, [bin, ...args], { stdio: "inherit" });
|
||||
child.on("error", (error) => {
|
||||
console.error(`Could not start OpenSpec.dev's CLI at ${bin}: ${error.message}`);
|
||||
resolve(1);
|
||||
});
|
||||
child.on("exit", (code, signal) => resolve(code ?? (signal ? 1 : 0)));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Attach the pass-through as the group's default subcommand, so any word
|
||||
* commander does not know (`init`, `list`, `validate`, ...) lands here with
|
||||
* its arguments intact, while `import`, `export` and `change` keep working.
|
||||
*/
|
||||
export function registerOpenSpecDevPassthrough(openspec: Command, run: (args: string[]) => Promise<number> = runOpenspec): void {
|
||||
openspec.passThroughOptions();
|
||||
openspec
|
||||
.command("dev", { isDefault: true, hidden: true })
|
||||
.argument("[args...]", "Arguments for OpenSpec.dev's openspec command, exactly as it takes them")
|
||||
.allowUnknownOption()
|
||||
.passThroughOptions()
|
||||
.helpOption(false)
|
||||
.description("Any other word: OpenSpec.dev's own CLI (init, list, validate, archive, show, ...).")
|
||||
.action(async (args: string[]) => {
|
||||
process.exitCode = await run(args.length ? args : ["--help"]);
|
||||
});
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue