openspecui 0.9.0 → 0.9.3
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/dist/cli.mjs +152 -76
- package/package.json +2 -1
package/dist/cli.mjs
CHANGED
|
@@ -2647,14 +2647,14 @@ function usage(yargs, shim$2) {
|
|
|
2647
2647
|
if (shim$2.process.stdColumns) return Math.min(maxWidth$1, shim$2.process.stdColumns);
|
|
2648
2648
|
else return maxWidth$1;
|
|
2649
2649
|
}
|
|
2650
|
-
let version = null;
|
|
2650
|
+
let version$1 = null;
|
|
2651
2651
|
self.version = (ver) => {
|
|
2652
|
-
version = ver;
|
|
2652
|
+
version$1 = ver;
|
|
2653
2653
|
};
|
|
2654
2654
|
self.showVersion = (level) => {
|
|
2655
2655
|
const logger = yargs.getInternalMethods().getLoggerInstance();
|
|
2656
2656
|
if (!level) level = "error";
|
|
2657
|
-
(typeof level === "function" ? level : logger[level])(version);
|
|
2657
|
+
(typeof level === "function" ? level : logger[level])(version$1);
|
|
2658
2658
|
};
|
|
2659
2659
|
self.reset = function reset(localLookup) {
|
|
2660
2660
|
failMessage = null;
|
|
@@ -4502,10 +4502,13 @@ function isYargsInstance(y) {
|
|
|
4502
4502
|
const Yargs = YargsFactory(esm_default);
|
|
4503
4503
|
var yargs_default = Yargs;
|
|
4504
4504
|
|
|
4505
|
+
//#endregion
|
|
4506
|
+
//#region package.json
|
|
4507
|
+
var version = "0.9.3";
|
|
4508
|
+
|
|
4505
4509
|
//#endregion
|
|
4506
4510
|
//#region src/export.ts
|
|
4507
4511
|
const __dirname$1 = dirname$1(fileURLToPath$1(import.meta.url));
|
|
4508
|
-
const WEB_PACKAGE_VERSION = "0.9.0";
|
|
4509
4512
|
/**
|
|
4510
4513
|
* Generate a complete data snapshot of the OpenSpec project
|
|
4511
4514
|
* (Kept for backwards compatibility and testing)
|
|
@@ -4585,7 +4588,7 @@ async function generateSnapshot(projectDir) {
|
|
|
4585
4588
|
return {
|
|
4586
4589
|
meta: {
|
|
4587
4590
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4588
|
-
version
|
|
4591
|
+
version,
|
|
4589
4592
|
projectDir
|
|
4590
4593
|
},
|
|
4591
4594
|
dashboard: {
|
|
@@ -4601,62 +4604,111 @@ async function generateSnapshot(projectDir) {
|
|
|
4601
4604
|
};
|
|
4602
4605
|
}
|
|
4603
4606
|
/**
|
|
4604
|
-
*
|
|
4607
|
+
* Check if running in local monorepo development mode
|
|
4608
|
+
* Returns the path to web package root if available, null otherwise
|
|
4609
|
+
*/
|
|
4610
|
+
function findLocalWebPackage() {
|
|
4611
|
+
if (existsSync(join$1(__dirname$1, "..", "..", "web", "package.json"))) return join$1(__dirname$1, "..", "..", "web");
|
|
4612
|
+
return null;
|
|
4613
|
+
}
|
|
4614
|
+
/**
|
|
4615
|
+
* Run a command and wait for it to complete
|
|
4616
|
+
*/
|
|
4617
|
+
function runCommand(cmd, args, cwd) {
|
|
4618
|
+
return new Promise((resolvePromise, reject) => {
|
|
4619
|
+
const child = spawn(cmd, args, {
|
|
4620
|
+
stdio: "inherit",
|
|
4621
|
+
cwd,
|
|
4622
|
+
shell: true
|
|
4623
|
+
});
|
|
4624
|
+
child.on("close", (code) => {
|
|
4625
|
+
if (code === 0) resolvePromise();
|
|
4626
|
+
else reject(/* @__PURE__ */ new Error(`Command failed with exit code ${code}`));
|
|
4627
|
+
});
|
|
4628
|
+
child.on("error", (err) => reject(err));
|
|
4629
|
+
});
|
|
4630
|
+
}
|
|
4631
|
+
/**
|
|
4632
|
+
* Detect the package manager used in the current project
|
|
4605
4633
|
*/
|
|
4606
4634
|
function detectPackageManager() {
|
|
4607
|
-
|
|
4608
|
-
|
|
4609
|
-
if (userAgent
|
|
4610
|
-
|
|
4635
|
+
if (process.env.DENO_VERSION) return "deno";
|
|
4636
|
+
const userAgent = process.env.npm_config_user_agent;
|
|
4637
|
+
if (userAgent) {
|
|
4638
|
+
if (userAgent.startsWith("bun")) return "bun";
|
|
4639
|
+
if (userAgent.startsWith("pnpm")) return "pnpm";
|
|
4640
|
+
if (userAgent.startsWith("yarn")) return "yarn";
|
|
4641
|
+
if (userAgent.startsWith("npm")) return "npm";
|
|
4642
|
+
if (userAgent.startsWith("deno")) return "deno";
|
|
4643
|
+
}
|
|
4644
|
+
if (existsSync("deno.lock")) return "deno";
|
|
4645
|
+
if (existsSync("bun.lockb") || existsSync("bun.lock")) return "bun";
|
|
4646
|
+
if (existsSync("pnpm-lock.yaml")) return "pnpm";
|
|
4647
|
+
if (existsSync("yarn.lock")) return "yarn";
|
|
4611
4648
|
return "npm";
|
|
4612
4649
|
}
|
|
4613
4650
|
/**
|
|
4614
|
-
* Get the command
|
|
4651
|
+
* Get the exec command for running a package binary
|
|
4652
|
+
* Uses appropriate flags to ensure the correct version of @openspecui/web is installed
|
|
4615
4653
|
*/
|
|
4616
4654
|
function getExecCommand(pm) {
|
|
4617
|
-
const
|
|
4655
|
+
const webPkgSpec = `@openspecui/web@${version}`;
|
|
4618
4656
|
switch (pm) {
|
|
4657
|
+
case "bun": return {
|
|
4658
|
+
cmd: "bunx",
|
|
4659
|
+
args: [
|
|
4660
|
+
"-p",
|
|
4661
|
+
webPkgSpec,
|
|
4662
|
+
"openspecui-ssg"
|
|
4663
|
+
]
|
|
4664
|
+
};
|
|
4619
4665
|
case "pnpm": return {
|
|
4620
4666
|
cmd: "pnpm",
|
|
4621
|
-
args: ["dlx",
|
|
4667
|
+
args: ["dlx", webPkgSpec]
|
|
4622
4668
|
};
|
|
4623
4669
|
case "yarn": return {
|
|
4624
4670
|
cmd: "yarn",
|
|
4625
|
-
args: ["dlx",
|
|
4671
|
+
args: ["dlx", webPkgSpec]
|
|
4626
4672
|
};
|
|
4627
|
-
case "
|
|
4628
|
-
cmd: "
|
|
4629
|
-
args: [
|
|
4673
|
+
case "deno": return {
|
|
4674
|
+
cmd: "deno",
|
|
4675
|
+
args: [
|
|
4676
|
+
"run",
|
|
4677
|
+
"-A",
|
|
4678
|
+
`npm:${webPkgSpec}/openspecui-ssg`
|
|
4679
|
+
]
|
|
4630
4680
|
};
|
|
4631
|
-
case "npm":
|
|
4632
4681
|
default: return {
|
|
4633
4682
|
cmd: "npx",
|
|
4634
|
-
args: [
|
|
4683
|
+
args: [
|
|
4684
|
+
"-p",
|
|
4685
|
+
webPkgSpec,
|
|
4686
|
+
"openspecui-ssg"
|
|
4687
|
+
]
|
|
4635
4688
|
};
|
|
4636
4689
|
}
|
|
4637
4690
|
}
|
|
4638
4691
|
/**
|
|
4639
|
-
*
|
|
4640
|
-
* Returns the path to local SSG CLI if available, null otherwise
|
|
4692
|
+
* Export as JSON only (data.json)
|
|
4641
4693
|
*/
|
|
4642
|
-
function
|
|
4643
|
-
const
|
|
4644
|
-
if (existsSync(
|
|
4645
|
-
|
|
4694
|
+
async function exportJson(options) {
|
|
4695
|
+
const { projectDir, outputDir, clean } = options;
|
|
4696
|
+
if (clean && existsSync(outputDir)) rmSync(outputDir, { recursive: true });
|
|
4697
|
+
mkdirSync(outputDir, { recursive: true });
|
|
4698
|
+
console.log("Generating data snapshot...");
|
|
4699
|
+
const snapshot = await generateSnapshot(projectDir);
|
|
4700
|
+
const dataJsonPath = join$1(outputDir, "data.json");
|
|
4701
|
+
writeFileSync(dataJsonPath, JSON.stringify(snapshot, null, 2));
|
|
4702
|
+
console.log(`\nExported to ${dataJsonPath}`);
|
|
4703
|
+
console.log(` Specs: ${snapshot.specs.length}`);
|
|
4704
|
+
console.log(` Changes: ${snapshot.changes.length}`);
|
|
4705
|
+
console.log(` Archives: ${snapshot.archives.length}`);
|
|
4646
4706
|
}
|
|
4647
4707
|
/**
|
|
4648
|
-
* Export
|
|
4649
|
-
*
|
|
4650
|
-
* This function:
|
|
4651
|
-
* 1. Generates a data snapshot from the openspec/ directory
|
|
4652
|
-
* 2. Writes data.json to the output directory
|
|
4653
|
-
* 3. Delegates to @openspecui/web's SSG CLI for rendering
|
|
4654
|
-
*
|
|
4655
|
-
* In development (monorepo), it uses the local web package.
|
|
4656
|
-
* In production, it uses npx/pnpm dlx to fetch the published package.
|
|
4708
|
+
* Export as static HTML site
|
|
4657
4709
|
*/
|
|
4658
|
-
async function
|
|
4659
|
-
const { projectDir, outputDir, basePath, clean, open, previewPort, previewHost } = options;
|
|
4710
|
+
async function exportHtml(options) {
|
|
4711
|
+
const { projectDir, outputDir, basePath = "/", clean, open, previewPort, previewHost } = options;
|
|
4660
4712
|
if (clean && existsSync(outputDir)) rmSync(outputDir, { recursive: true });
|
|
4661
4713
|
mkdirSync(outputDir, { recursive: true });
|
|
4662
4714
|
console.log("Generating data snapshot...");
|
|
@@ -4664,46 +4716,63 @@ async function exportStaticSite(options) {
|
|
|
4664
4716
|
const dataJsonPath = join$1(outputDir, "data.json");
|
|
4665
4717
|
writeFileSync(dataJsonPath, JSON.stringify(snapshot, null, 2));
|
|
4666
4718
|
console.log(`Data snapshot written to ${dataJsonPath}`);
|
|
4667
|
-
const
|
|
4668
|
-
|
|
4669
|
-
|
|
4670
|
-
"
|
|
4671
|
-
outputDir
|
|
4672
|
-
];
|
|
4673
|
-
if (basePath !== void 0) ssgOnlyArgs.push("--base-path", basePath);
|
|
4674
|
-
if (open) {
|
|
4675
|
-
ssgOnlyArgs.push("--open");
|
|
4676
|
-
if (previewPort !== void 0) ssgOnlyArgs.push("--preview-port", String(previewPort));
|
|
4677
|
-
if (previewHost !== void 0) ssgOnlyArgs.push("--host", previewHost);
|
|
4678
|
-
}
|
|
4679
|
-
const localCli = findLocalSSGCli();
|
|
4680
|
-
let cmd;
|
|
4681
|
-
let args;
|
|
4682
|
-
if (localCli) {
|
|
4683
|
-
cmd = "npx";
|
|
4684
|
-
args = [
|
|
4719
|
+
const localWebPkg = findLocalWebPackage();
|
|
4720
|
+
if (localWebPkg) {
|
|
4721
|
+
console.log("\n[Local dev mode] Running SSG from local web package...");
|
|
4722
|
+
await runCommand("pnpm", [
|
|
4685
4723
|
"tsx",
|
|
4686
|
-
|
|
4687
|
-
|
|
4688
|
-
|
|
4724
|
+
join$1(localWebPkg, "src", "ssg", "cli.ts"),
|
|
4725
|
+
"--data",
|
|
4726
|
+
dataJsonPath,
|
|
4727
|
+
"--output",
|
|
4728
|
+
outputDir,
|
|
4729
|
+
"--base-path",
|
|
4730
|
+
basePath
|
|
4731
|
+
], localWebPkg);
|
|
4689
4732
|
} else {
|
|
4690
|
-
|
|
4691
|
-
|
|
4692
|
-
|
|
4733
|
+
console.log("\n[Production mode] Running SSG via @openspecui/web...");
|
|
4734
|
+
const pm = detectPackageManager();
|
|
4735
|
+
const execCmd = getExecCommand(pm);
|
|
4736
|
+
try {
|
|
4737
|
+
await runCommand(execCmd.cmd, [
|
|
4738
|
+
...execCmd.args,
|
|
4739
|
+
"--data",
|
|
4740
|
+
dataJsonPath,
|
|
4741
|
+
"--output",
|
|
4742
|
+
outputDir,
|
|
4743
|
+
"--base-path",
|
|
4744
|
+
basePath
|
|
4745
|
+
], process.cwd());
|
|
4746
|
+
} catch (err) {
|
|
4747
|
+
console.error("\nSSG failed. Make sure @openspecui/web is installed:");
|
|
4748
|
+
console.error(` ${pm} add @openspecui/web`);
|
|
4749
|
+
throw err;
|
|
4750
|
+
}
|
|
4751
|
+
}
|
|
4752
|
+
console.log(`\nExport complete: ${outputDir}`);
|
|
4753
|
+
if (open) {
|
|
4754
|
+
console.log("\nStarting preview server...");
|
|
4755
|
+
const previewArgs = [
|
|
4756
|
+
"vite",
|
|
4757
|
+
"preview",
|
|
4758
|
+
"--outDir",
|
|
4759
|
+
resolve$1(outputDir)
|
|
4760
|
+
];
|
|
4761
|
+
if (previewPort) previewArgs.push("--port", String(previewPort));
|
|
4762
|
+
if (previewHost) previewArgs.push("--host", previewHost);
|
|
4763
|
+
previewArgs.push("--open");
|
|
4764
|
+
await runCommand(detectPackageManager(), previewArgs, outputDir);
|
|
4693
4765
|
}
|
|
4694
|
-
|
|
4695
|
-
|
|
4696
|
-
|
|
4697
|
-
|
|
4698
|
-
|
|
4699
|
-
|
|
4700
|
-
|
|
4701
|
-
|
|
4702
|
-
|
|
4703
|
-
|
|
4704
|
-
reject(/* @__PURE__ */ new Error(`Failed to start SSG CLI: ${err.message}`));
|
|
4705
|
-
});
|
|
4706
|
-
});
|
|
4766
|
+
}
|
|
4767
|
+
/**
|
|
4768
|
+
* Export the OpenSpec project
|
|
4769
|
+
*
|
|
4770
|
+
* @param options Export options
|
|
4771
|
+
* @param options.format 'html' (default) - full static site, 'json' - data only
|
|
4772
|
+
*/
|
|
4773
|
+
async function exportStaticSite(options) {
|
|
4774
|
+
if ((options.format || "html") === "json") await exportJson(options);
|
|
4775
|
+
else await exportHtml(options);
|
|
4707
4776
|
}
|
|
4708
4777
|
|
|
4709
4778
|
//#endregion
|
|
@@ -4778,12 +4847,18 @@ async function main() {
|
|
|
4778
4847
|
console.error("❌ Failed to start server:", error);
|
|
4779
4848
|
process.exit(1);
|
|
4780
4849
|
}
|
|
4781
|
-
}).command("export", "Export OpenSpec
|
|
4850
|
+
}).command("export", "Export OpenSpec project as static website or JSON data", (yargs) => {
|
|
4782
4851
|
return yargs.option("output", {
|
|
4783
4852
|
alias: "o",
|
|
4784
|
-
describe: "Output directory for
|
|
4853
|
+
describe: "Output directory for export",
|
|
4785
4854
|
type: "string",
|
|
4786
4855
|
demandOption: true
|
|
4856
|
+
}).option("format", {
|
|
4857
|
+
alias: "f",
|
|
4858
|
+
describe: "Export format",
|
|
4859
|
+
type: "string",
|
|
4860
|
+
choices: ["html", "json"],
|
|
4861
|
+
default: "html"
|
|
4787
4862
|
}).option("dir", {
|
|
4788
4863
|
alias: "d",
|
|
4789
4864
|
describe: "Project directory containing openspec/",
|
|
@@ -4813,6 +4888,7 @@ async function main() {
|
|
|
4813
4888
|
await exportStaticSite({
|
|
4814
4889
|
projectDir,
|
|
4815
4890
|
outputDir,
|
|
4891
|
+
format: argv.format,
|
|
4816
4892
|
basePath: argv["base-path"],
|
|
4817
4893
|
clean: argv.clean,
|
|
4818
4894
|
open: argv.open,
|
|
@@ -4824,7 +4900,7 @@ async function main() {
|
|
|
4824
4900
|
console.error("❌ Export failed:", error);
|
|
4825
4901
|
process.exit(1);
|
|
4826
4902
|
}
|
|
4827
|
-
}).example("$0", "Start server in current directory").example("$0 ./my-project", "Start server with specific project").example("$0 -p 8080", "Start server on custom port").example("$0 export -o ./dist", "Export to ./dist directory").example("$0 export
|
|
4903
|
+
}).example("$0", "Start server in current directory").example("$0 ./my-project", "Start server with specific project").example("$0 -p 8080", "Start server on custom port").example("$0 export -o ./dist", "Export HTML to ./dist directory").example("$0 export -o ./dist -f json", "Export JSON data only").example("$0 export -o ./dist --base-path=/docs/", "Export for subdirectory deployment").example("$0 export -o ./dist --clean", "Clean output directory before export").version(getVersion()).alias("v", "version").help().alias("h", "help").parse();
|
|
4828
4904
|
}
|
|
4829
4905
|
main();
|
|
4830
4906
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "openspecui",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.3",
|
|
4
4
|
"description": "OpenSpec UI - Visual interface for spec-driven development",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.mjs",
|
|
@@ -31,6 +31,7 @@
|
|
|
31
31
|
"typescript": "^5.7.2",
|
|
32
32
|
"vitest": "^2.1.8",
|
|
33
33
|
"yargs": "^18.0.0",
|
|
34
|
+
"@openspecui/web": "0.9.3",
|
|
34
35
|
"@openspecui/server": "0.9.0"
|
|
35
36
|
},
|
|
36
37
|
"scripts": {
|