openspecui 1.5.1 → 1.6.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.
- package/dist/cli.mjs +245 -13
- package/dist/index.mjs +1 -1
- package/dist/{src-16GA3our.mjs → src-Brh3druE.mjs} +101 -4
- package/package.json +3 -3
- package/web/assets/{BufferResource-Bn1UWy0D.js → BufferResource-LpIscPOh.js} +1 -1
- package/web/assets/{CanvasRenderer-D8NiU8la.js → CanvasRenderer-hdBAgk8Z.js} +1 -1
- package/web/assets/{Filter-CRwq487x.js → Filter-DJVBXWdE.js} +1 -1
- package/web/assets/{RenderTargetSystem-CtoB_qTm.js → RenderTargetSystem-CEuUrT8d.js} +1 -1
- package/web/assets/{WebGLRenderer-BgKO8R0a.js → WebGLRenderer-DUSFltAk.js} +1 -1
- package/web/assets/{WebGPURenderer-CQeL2efC.js → WebGPURenderer-DafJULoy.js} +1 -1
- package/web/assets/{browserAll-DP6sOYev.js → browserAll-DYvdsmhE.js} +1 -1
- package/web/assets/{ghostty-web-evxujSxm.js → ghostty-web-BitlvuYh.js} +1 -1
- package/web/assets/{index-BnT52DZ8.js → index-5zLYkWge.js} +1 -1
- package/web/assets/{index-B0IbsqHi.js → index-B8AH-4mO.js} +1 -1
- package/web/assets/{index-D2Tp4F9B.js → index-BXlwoClD.js} +1 -1
- package/web/assets/{index-dSf1u0YV.js → index-BhxOfd1V.js} +1 -1
- package/web/assets/{index-f0QdJSzm.js → index-BwqUcS4o.js} +1 -1
- package/web/assets/{index-DTeOcXKn.js → index-CGTRVPmS.js} +1 -1
- package/web/assets/{index-T8xoxmUb.js → index-CKfGQiMr.js} +236 -205
- package/web/assets/{index-BejnsZfY.js → index-CYTyn82I.js} +1 -1
- package/web/assets/{index-DJqmTRAR.js → index-CjHce-bH.js} +1 -1
- package/web/assets/{index-B147AOgf.js → index-CuiBRRWA.js} +1 -1
- package/web/assets/{index-BPZ3nG0r.js → index-DEgCfC-b.js} +1 -1
- package/web/assets/{index-DcXyAs0z.js → index-DbrGteUX.js} +1 -1
- package/web/assets/{index-BMashGQn.js → index-Dge9ymDE.js} +1 -1
- package/web/assets/{index-CBCPR3Qb.js → index-DtJ1xKq6.js} +1 -1
- package/web/assets/index-USotIqwU.css +1 -0
- package/web/assets/{index-D6ardy54.js → index-gPPYc26D.js} +1 -1
- package/web/assets/{index-4MAU81Qk.js → index-hXwe0Xwc.js} +1 -1
- package/web/assets/{webworkerAll-DA2HufNb.js → webworkerAll-CFbGR7bA.js} +1 -1
- package/web/index.html +2 -2
- package/web/assets/index-Ys2MTD3W.css +0 -1
package/dist/cli.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { a as SchemaInfoSchema, c as
|
|
2
|
+
import { a as SchemaInfoSchema, c as toOpsxDisplayPath, d as DEFAULT_CONFIG, f as OpenSpecAdapter, i as SchemaDetailSchema, l as CliExecutor, m as __toESM, o as SchemaResolutionSchema, p as __commonJS, r as require_dist, s as TemplatesSchema, t as startServer, u as ConfigManager } from "./src-Brh3druE.mjs";
|
|
3
3
|
import { createRequire } from "node:module";
|
|
4
4
|
import { basename, dirname, extname, join, normalize, relative, resolve } from "path";
|
|
5
5
|
import { readFile } from "node:fs/promises";
|
|
@@ -8,7 +8,8 @@ import { existsSync, mkdirSync, readFileSync, readdirSync, rmSync, writeFileSync
|
|
|
8
8
|
import { readFileSync as readFileSync$1, readdirSync as readdirSync$1, statSync as statSync$1, writeFile as writeFile$1 } from "fs";
|
|
9
9
|
import { format, inspect } from "util";
|
|
10
10
|
import { fileURLToPath } from "url";
|
|
11
|
-
import { spawn } from "node:child_process";
|
|
11
|
+
import { execFile, spawn } from "node:child_process";
|
|
12
|
+
import { promisify as promisify$1 } from "node:util";
|
|
12
13
|
import { fileURLToPath as fileURLToPath$1 } from "node:url";
|
|
13
14
|
import { notStrictEqual, strictEqual } from "assert";
|
|
14
15
|
|
|
@@ -4506,11 +4507,12 @@ var yargs_default = Yargs;
|
|
|
4506
4507
|
//#endregion
|
|
4507
4508
|
//#region package.json
|
|
4508
4509
|
var import_dist = require_dist();
|
|
4509
|
-
var version = "1.
|
|
4510
|
+
var version = "1.6.0";
|
|
4510
4511
|
|
|
4511
4512
|
//#endregion
|
|
4512
4513
|
//#region src/export.ts
|
|
4513
4514
|
const __dirname$1 = dirname$1(fileURLToPath$1(import.meta.url));
|
|
4515
|
+
const execFileAsync = promisify$1(execFile);
|
|
4514
4516
|
function parseCliJson(raw, schema, label) {
|
|
4515
4517
|
const trimmed = raw.trim();
|
|
4516
4518
|
if (!trimmed) throw new Error(`${label} returned empty output`);
|
|
@@ -4559,6 +4561,184 @@ function parseSchemaYaml(content) {
|
|
|
4559
4561
|
if (!validated.success) throw new Error(`Invalid schema.yaml detail: ${validated.error.message}`);
|
|
4560
4562
|
return validated.data;
|
|
4561
4563
|
}
|
|
4564
|
+
function isAbsoluteFsPath(path$1) {
|
|
4565
|
+
const normalized = path$1.replace(/\\/g, "/");
|
|
4566
|
+
return normalized.startsWith("/") || /^[A-Za-z]:\//.test(normalized);
|
|
4567
|
+
}
|
|
4568
|
+
function toAbsoluteProjectPath(projectDir, path$1) {
|
|
4569
|
+
return isAbsoluteFsPath(path$1) ? path$1 : resolve$1(projectDir, path$1);
|
|
4570
|
+
}
|
|
4571
|
+
function normalizeGitPath(path$1) {
|
|
4572
|
+
return path$1.replace(/\\/g, "/").replace(/^\.\//, "");
|
|
4573
|
+
}
|
|
4574
|
+
function parseRelatedChanges(paths) {
|
|
4575
|
+
const related = /* @__PURE__ */ new Set();
|
|
4576
|
+
for (const rawPath of paths) {
|
|
4577
|
+
const path$1 = normalizeGitPath(rawPath);
|
|
4578
|
+
const activeMatch = /^openspec\/changes\/([^/]+)\//.exec(path$1);
|
|
4579
|
+
if (activeMatch?.[1]) {
|
|
4580
|
+
related.add(activeMatch[1]);
|
|
4581
|
+
continue;
|
|
4582
|
+
}
|
|
4583
|
+
const archiveMatch = /^openspec\/changes\/archive\/([^/]+)\//.exec(path$1);
|
|
4584
|
+
if (archiveMatch?.[1]) related.add(archiveMatch[1].replace(/^\d{4}-\d{2}-\d{2}-/, ""));
|
|
4585
|
+
}
|
|
4586
|
+
return [...related].sort((a, b) => a.localeCompare(b));
|
|
4587
|
+
}
|
|
4588
|
+
function parseNumstat(numstatOutput) {
|
|
4589
|
+
let files = 0;
|
|
4590
|
+
let insertions = 0;
|
|
4591
|
+
let deletions = 0;
|
|
4592
|
+
for (const line of numstatOutput.split("\n")) {
|
|
4593
|
+
const trimmed = line.trim();
|
|
4594
|
+
if (!trimmed) continue;
|
|
4595
|
+
const [addRaw, delRaw] = trimmed.split(" ");
|
|
4596
|
+
if (!addRaw || !delRaw) continue;
|
|
4597
|
+
files += 1;
|
|
4598
|
+
if (addRaw !== "-") insertions += Number(addRaw) || 0;
|
|
4599
|
+
if (delRaw !== "-") deletions += Number(delRaw) || 0;
|
|
4600
|
+
}
|
|
4601
|
+
return {
|
|
4602
|
+
files,
|
|
4603
|
+
insertions,
|
|
4604
|
+
deletions
|
|
4605
|
+
};
|
|
4606
|
+
}
|
|
4607
|
+
async function readDefaultBranch(projectDir) {
|
|
4608
|
+
try {
|
|
4609
|
+
const { stdout } = await execFileAsync("git", [
|
|
4610
|
+
"symbolic-ref",
|
|
4611
|
+
"--quiet",
|
|
4612
|
+
"--short",
|
|
4613
|
+
"refs/remotes/origin/HEAD"
|
|
4614
|
+
], {
|
|
4615
|
+
cwd: projectDir,
|
|
4616
|
+
encoding: "utf8",
|
|
4617
|
+
maxBuffer: 1024 * 1024
|
|
4618
|
+
});
|
|
4619
|
+
const branch = stdout.trim();
|
|
4620
|
+
if (branch.length > 0) return branch;
|
|
4621
|
+
} catch {}
|
|
4622
|
+
try {
|
|
4623
|
+
const { stdout } = await execFileAsync("git", [
|
|
4624
|
+
"rev-parse",
|
|
4625
|
+
"--abbrev-ref",
|
|
4626
|
+
"HEAD"
|
|
4627
|
+
], {
|
|
4628
|
+
cwd: projectDir,
|
|
4629
|
+
encoding: "utf8",
|
|
4630
|
+
maxBuffer: 1024 * 1024
|
|
4631
|
+
});
|
|
4632
|
+
const branch = stdout.trim();
|
|
4633
|
+
if (branch.length > 0 && branch !== "HEAD") return branch;
|
|
4634
|
+
} catch {}
|
|
4635
|
+
return "main";
|
|
4636
|
+
}
|
|
4637
|
+
function parseRecentCommitLog(output) {
|
|
4638
|
+
const commits = [];
|
|
4639
|
+
let current = null;
|
|
4640
|
+
const pushCurrent = () => {
|
|
4641
|
+
if (!current) return;
|
|
4642
|
+
commits.push({
|
|
4643
|
+
hash: current.hash,
|
|
4644
|
+
title: current.title,
|
|
4645
|
+
committedAt: current.committedAt,
|
|
4646
|
+
relatedChanges: parseRelatedChanges(current.changedPaths),
|
|
4647
|
+
diff: parseNumstat(current.numstatLines.join("\n"))
|
|
4648
|
+
});
|
|
4649
|
+
current = null;
|
|
4650
|
+
};
|
|
4651
|
+
for (const line of output.split("\n")) {
|
|
4652
|
+
if (line.startsWith("__COMMIT__ ")) {
|
|
4653
|
+
pushCurrent();
|
|
4654
|
+
const [_, hash, tsRaw, ...titleParts] = line.split(" ");
|
|
4655
|
+
const committedAt = Number(tsRaw) * 1e3;
|
|
4656
|
+
current = {
|
|
4657
|
+
hash: hash ?? "",
|
|
4658
|
+
title: titleParts.join(" ").trim() || (hash ? hash.slice(0, 8) : "commit"),
|
|
4659
|
+
committedAt: Number.isFinite(committedAt) && committedAt > 0 ? committedAt : 0,
|
|
4660
|
+
numstatLines: [],
|
|
4661
|
+
changedPaths: []
|
|
4662
|
+
};
|
|
4663
|
+
continue;
|
|
4664
|
+
}
|
|
4665
|
+
if (!current) continue;
|
|
4666
|
+
const trimmed = line.trim();
|
|
4667
|
+
if (!trimmed) continue;
|
|
4668
|
+
const [addRaw, delRaw, ...pathParts] = trimmed.split(" ");
|
|
4669
|
+
if (!addRaw || !delRaw || pathParts.length === 0) continue;
|
|
4670
|
+
const path$1 = pathParts.join(" ");
|
|
4671
|
+
current.numstatLines.push(`${addRaw}\t${delRaw}\t${path$1}`);
|
|
4672
|
+
current.changedPaths.push(path$1);
|
|
4673
|
+
}
|
|
4674
|
+
pushCurrent();
|
|
4675
|
+
return commits.filter((commit) => commit.hash.length > 0);
|
|
4676
|
+
}
|
|
4677
|
+
function normalizeRepositoryUrl(raw) {
|
|
4678
|
+
const value = raw.trim();
|
|
4679
|
+
if (!value) return null;
|
|
4680
|
+
if (value.startsWith("http://") || value.startsWith("https://")) return value.replace(/\.git$/i, "");
|
|
4681
|
+
const gitAtMatch = /^git@([^:]+):(.+)$/.exec(value);
|
|
4682
|
+
if (gitAtMatch?.[1] && gitAtMatch[2]) return `https://${gitAtMatch[1]}/${gitAtMatch[2].replace(/\.git$/i, "")}`;
|
|
4683
|
+
if (value.startsWith("ssh://")) try {
|
|
4684
|
+
const parsed = new URL(value);
|
|
4685
|
+
const pathname = parsed.pathname.replace(/^\/+/, "").replace(/\.git$/i, "");
|
|
4686
|
+
if (!pathname) return null;
|
|
4687
|
+
return `https://${parsed.hostname}/${pathname}`;
|
|
4688
|
+
} catch {}
|
|
4689
|
+
return value.replace(/\.git$/i, "");
|
|
4690
|
+
}
|
|
4691
|
+
async function readSnapshotGit(projectDir) {
|
|
4692
|
+
try {
|
|
4693
|
+
const defaultBranch = await readDefaultBranch(projectDir);
|
|
4694
|
+
const { stdout: latestTsRaw } = await execFileAsync("git", [
|
|
4695
|
+
"log",
|
|
4696
|
+
"-1",
|
|
4697
|
+
"--format=%ct"
|
|
4698
|
+
], {
|
|
4699
|
+
cwd: projectDir,
|
|
4700
|
+
encoding: "utf8",
|
|
4701
|
+
maxBuffer: 1024 * 1024
|
|
4702
|
+
});
|
|
4703
|
+
const latestSeconds = Number(latestTsRaw.trim());
|
|
4704
|
+
const latestCommitTs = Number.isFinite(latestSeconds) && latestSeconds > 0 ? latestSeconds * 1e3 : null;
|
|
4705
|
+
let repositoryUrl = null;
|
|
4706
|
+
try {
|
|
4707
|
+
const { stdout: remoteRaw } = await execFileAsync("git", [
|
|
4708
|
+
"config",
|
|
4709
|
+
"--get",
|
|
4710
|
+
"remote.origin.url"
|
|
4711
|
+
], {
|
|
4712
|
+
cwd: projectDir,
|
|
4713
|
+
encoding: "utf8",
|
|
4714
|
+
maxBuffer: 1024 * 1024
|
|
4715
|
+
});
|
|
4716
|
+
repositoryUrl = normalizeRepositoryUrl(remoteRaw);
|
|
4717
|
+
} catch {
|
|
4718
|
+
repositoryUrl = null;
|
|
4719
|
+
}
|
|
4720
|
+
const { stdout: logOutput } = await execFileAsync("git", [
|
|
4721
|
+
"log",
|
|
4722
|
+
"-n",
|
|
4723
|
+
"5",
|
|
4724
|
+
"--format=__COMMIT__%x09%H%x09%ct%x09%s",
|
|
4725
|
+
"--numstat",
|
|
4726
|
+
"--"
|
|
4727
|
+
], {
|
|
4728
|
+
cwd: projectDir,
|
|
4729
|
+
encoding: "utf8",
|
|
4730
|
+
maxBuffer: 8 * 1024 * 1024
|
|
4731
|
+
});
|
|
4732
|
+
return {
|
|
4733
|
+
defaultBranch,
|
|
4734
|
+
repositoryUrl,
|
|
4735
|
+
latestCommitTs,
|
|
4736
|
+
recentCommits: parseRecentCommitLog(logOutput)
|
|
4737
|
+
};
|
|
4738
|
+
} catch {
|
|
4739
|
+
return;
|
|
4740
|
+
}
|
|
4741
|
+
}
|
|
4562
4742
|
/**
|
|
4563
4743
|
* Generate a complete data snapshot of the OpenSpec project
|
|
4564
4744
|
* (Kept for backwards compatibility and testing)
|
|
@@ -4641,8 +4821,10 @@ async function generateSnapshot(projectDir) {
|
|
|
4641
4821
|
let configYaml;
|
|
4642
4822
|
let schemas = [];
|
|
4643
4823
|
const schemaDetails = {};
|
|
4824
|
+
const schemaYamls = {};
|
|
4644
4825
|
const schemaResolutions = {};
|
|
4645
4826
|
const templates = {};
|
|
4827
|
+
const templateContents = {};
|
|
4646
4828
|
const changeMetadata = {};
|
|
4647
4829
|
try {
|
|
4648
4830
|
configYaml = await readFile(join$1(projectDir, "openspec", "config.yaml"), "utf-8");
|
|
@@ -4660,16 +4842,56 @@ async function generateSnapshot(projectDir) {
|
|
|
4660
4842
|
const resolutionResult = await cliExecutor.schemaWhich(schema.name);
|
|
4661
4843
|
if (resolutionResult.success) {
|
|
4662
4844
|
const resolution = parseCliJson(resolutionResult.stdout, SchemaResolutionSchema, "openspec schema which");
|
|
4663
|
-
schemaResolutions[schema.name] =
|
|
4845
|
+
schemaResolutions[schema.name] = {
|
|
4846
|
+
...resolution,
|
|
4847
|
+
displayPath: toOpsxDisplayPath(resolution.path, {
|
|
4848
|
+
source: resolution.source,
|
|
4849
|
+
projectDir
|
|
4850
|
+
}),
|
|
4851
|
+
shadows: resolution.shadows.map((shadow) => ({
|
|
4852
|
+
...shadow,
|
|
4853
|
+
displayPath: toOpsxDisplayPath(shadow.path, {
|
|
4854
|
+
source: shadow.source,
|
|
4855
|
+
projectDir
|
|
4856
|
+
})
|
|
4857
|
+
}))
|
|
4858
|
+
};
|
|
4664
4859
|
try {
|
|
4665
4860
|
const schemaContent = await readFile(join$1(resolution.path, "schema.yaml"), "utf-8");
|
|
4666
4861
|
schemaDetails[schema.name] = parseSchemaYaml(schemaContent);
|
|
4862
|
+
schemaYamls[schema.name] = schemaContent;
|
|
4667
4863
|
} catch {}
|
|
4668
4864
|
}
|
|
4669
4865
|
} catch {}
|
|
4670
4866
|
try {
|
|
4671
4867
|
const templatesResult = await cliExecutor.templates(schema.name);
|
|
4672
|
-
if (templatesResult.success)
|
|
4868
|
+
if (templatesResult.success) {
|
|
4869
|
+
const parsedTemplates = parseCliJson(templatesResult.stdout, TemplatesSchema, "openspec templates");
|
|
4870
|
+
const normalizedTemplates = Object.fromEntries(Object.entries(parsedTemplates).map(([artifactId, info]) => [artifactId, {
|
|
4871
|
+
...info,
|
|
4872
|
+
path: toAbsoluteProjectPath(projectDir, info.path),
|
|
4873
|
+
displayPath: toOpsxDisplayPath(info.path, {
|
|
4874
|
+
source: info.source,
|
|
4875
|
+
projectDir
|
|
4876
|
+
})
|
|
4877
|
+
}]));
|
|
4878
|
+
templates[schema.name] = normalizedTemplates;
|
|
4879
|
+
const contents = await Promise.all(Object.entries(normalizedTemplates).map(async ([artifactId, info]) => {
|
|
4880
|
+
let content = null;
|
|
4881
|
+
try {
|
|
4882
|
+
content = await readFile(info.path, "utf-8");
|
|
4883
|
+
} catch {
|
|
4884
|
+
content = null;
|
|
4885
|
+
}
|
|
4886
|
+
return [artifactId, {
|
|
4887
|
+
content,
|
|
4888
|
+
path: info.path,
|
|
4889
|
+
displayPath: info.displayPath,
|
|
4890
|
+
source: info.source
|
|
4891
|
+
}];
|
|
4892
|
+
}));
|
|
4893
|
+
templateContents[schema.name] = Object.fromEntries(contents);
|
|
4894
|
+
}
|
|
4673
4895
|
} catch {}
|
|
4674
4896
|
}
|
|
4675
4897
|
try {
|
|
@@ -4680,6 +4902,7 @@ async function generateSnapshot(projectDir) {
|
|
|
4680
4902
|
changeMetadata[changeId] = null;
|
|
4681
4903
|
}
|
|
4682
4904
|
} catch {}
|
|
4905
|
+
const git = await readSnapshotGit(projectDir);
|
|
4683
4906
|
return {
|
|
4684
4907
|
meta: {
|
|
4685
4908
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -4691,6 +4914,7 @@ async function generateSnapshot(projectDir) {
|
|
|
4691
4914
|
changesCount: changes.filter((c) => c !== null).length,
|
|
4692
4915
|
archivesCount: archives.length
|
|
4693
4916
|
},
|
|
4917
|
+
git,
|
|
4694
4918
|
config: uiConfig,
|
|
4695
4919
|
specs,
|
|
4696
4920
|
changes: changes.filter((c) => c !== null),
|
|
@@ -4701,8 +4925,10 @@ async function generateSnapshot(projectDir) {
|
|
|
4701
4925
|
configYaml,
|
|
4702
4926
|
schemas,
|
|
4703
4927
|
schemaDetails,
|
|
4928
|
+
schemaYamls,
|
|
4704
4929
|
schemaResolutions,
|
|
4705
4930
|
templates,
|
|
4931
|
+
templateContents,
|
|
4706
4932
|
changeMetadata
|
|
4707
4933
|
}
|
|
4708
4934
|
};
|
|
@@ -4723,7 +4949,7 @@ function runCommand(cmd, args, cwd) {
|
|
|
4723
4949
|
const child = spawn(cmd, args, {
|
|
4724
4950
|
stdio: "inherit",
|
|
4725
4951
|
cwd,
|
|
4726
|
-
shell:
|
|
4952
|
+
shell: false
|
|
4727
4953
|
});
|
|
4728
4954
|
child.on("close", (code) => {
|
|
4729
4955
|
if (code === 0) resolvePromise();
|
|
@@ -4757,7 +4983,7 @@ function detectPackageManager() {
|
|
|
4757
4983
|
return "npm";
|
|
4758
4984
|
}
|
|
4759
4985
|
/**
|
|
4760
|
-
* Get the command to run a
|
|
4986
|
+
* Get the command to run a binary in a package-manager agnostic way.
|
|
4761
4987
|
*/
|
|
4762
4988
|
function getRunCommand(pm, bin) {
|
|
4763
4989
|
switch (pm) {
|
|
@@ -4767,11 +4993,11 @@ function getRunCommand(pm, bin) {
|
|
|
4767
4993
|
};
|
|
4768
4994
|
case "pnpm": return {
|
|
4769
4995
|
cmd: "pnpm",
|
|
4770
|
-
args: ["
|
|
4996
|
+
args: ["dlx", bin]
|
|
4771
4997
|
};
|
|
4772
4998
|
case "yarn": return {
|
|
4773
4999
|
cmd: "yarn",
|
|
4774
|
-
args: [bin]
|
|
5000
|
+
args: ["dlx", bin]
|
|
4775
5001
|
};
|
|
4776
5002
|
case "deno": return {
|
|
4777
5003
|
cmd: "deno",
|
|
@@ -5043,6 +5269,10 @@ async function main() {
|
|
|
5043
5269
|
}).option("preview-port", {
|
|
5044
5270
|
describe: "Port for the preview server (used with --open)",
|
|
5045
5271
|
type: "number"
|
|
5272
|
+
}).option("port", {
|
|
5273
|
+
alias: "p",
|
|
5274
|
+
describe: "Alias of --open --preview-port <port>",
|
|
5275
|
+
type: "number"
|
|
5046
5276
|
}).option("preview-host", {
|
|
5047
5277
|
describe: "Host for the preview server (used with --open)",
|
|
5048
5278
|
type: "string"
|
|
@@ -5050,6 +5280,8 @@ async function main() {
|
|
|
5050
5280
|
}, async (argv) => {
|
|
5051
5281
|
const projectDir = resolve$1(originalCwd, argv.dir || ".");
|
|
5052
5282
|
const outputDir = resolve$1(originalCwd, argv.output);
|
|
5283
|
+
const previewPort = argv.port ?? argv["preview-port"];
|
|
5284
|
+
const shouldOpen = argv.open || argv.port !== void 0;
|
|
5053
5285
|
try {
|
|
5054
5286
|
await exportStaticSite({
|
|
5055
5287
|
projectDir,
|
|
@@ -5057,16 +5289,16 @@ async function main() {
|
|
|
5057
5289
|
format: argv.format,
|
|
5058
5290
|
basePath: argv["base-path"],
|
|
5059
5291
|
clean: argv.clean,
|
|
5060
|
-
open:
|
|
5061
|
-
previewPort
|
|
5292
|
+
open: shouldOpen,
|
|
5293
|
+
previewPort,
|
|
5062
5294
|
previewHost: argv["preview-host"]
|
|
5063
5295
|
});
|
|
5064
|
-
if (!
|
|
5296
|
+
if (!shouldOpen) process.exit(0);
|
|
5065
5297
|
} catch (error) {
|
|
5066
5298
|
console.error("❌ Export failed:", error);
|
|
5067
5299
|
process.exit(1);
|
|
5068
5300
|
}
|
|
5069
|
-
}).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();
|
|
5301
|
+
}).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 -p 8092", "Export and open preview on port 8092").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();
|
|
5070
5302
|
}
|
|
5071
5303
|
main();
|
|
5072
5304
|
|
package/dist/index.mjs
CHANGED
|
@@ -7094,6 +7094,68 @@ const DASHBOARD_METRIC_KEYS = [
|
|
|
7094
7094
|
"taskCompletionPercent"
|
|
7095
7095
|
];
|
|
7096
7096
|
|
|
7097
|
+
//#endregion
|
|
7098
|
+
//#region ../core/src/opsx-display-path.ts
|
|
7099
|
+
const VIRTUAL_PROJECT_DIRNAME = "project";
|
|
7100
|
+
const WINDOWS_DRIVE_PREFIX = /^[A-Za-z]:\//;
|
|
7101
|
+
function normalizeFsPath(path$1) {
|
|
7102
|
+
return path$1.replace(/\\/g, "/").replace(/\/+$/g, "");
|
|
7103
|
+
}
|
|
7104
|
+
function isAbsolutePath(path$1) {
|
|
7105
|
+
return path$1.startsWith("/") || WINDOWS_DRIVE_PREFIX.test(path$1);
|
|
7106
|
+
}
|
|
7107
|
+
function stripRelativePrefix(path$1) {
|
|
7108
|
+
return path$1.replace(/^\.?\//, "");
|
|
7109
|
+
}
|
|
7110
|
+
function splitSegments(path$1) {
|
|
7111
|
+
return normalizeFsPath(path$1).split("/").filter(Boolean);
|
|
7112
|
+
}
|
|
7113
|
+
function toNpmSpecifier(path$1) {
|
|
7114
|
+
const normalized = normalizeFsPath(path$1);
|
|
7115
|
+
const match$1 = /(?:^|\/)node_modules\/(?:\.pnpm\/[^/]+\/node_modules\/)?(@[^/]+\/[^/]+|[^/]+)(\/.*)?/.exec(normalized);
|
|
7116
|
+
const pkgName = match$1?.[1];
|
|
7117
|
+
if (!pkgName) return null;
|
|
7118
|
+
return `npm:${pkgName}${match$1[2] ?? ""}`;
|
|
7119
|
+
}
|
|
7120
|
+
function toVirtualProjectPath(path$1) {
|
|
7121
|
+
return `${VIRTUAL_PROJECT_DIRNAME}:${stripRelativePrefix(path$1)}`;
|
|
7122
|
+
}
|
|
7123
|
+
function isPathInside(root, target) {
|
|
7124
|
+
const normalizedRoot = normalizeFsPath(root);
|
|
7125
|
+
const normalizedTarget = normalizeFsPath(target);
|
|
7126
|
+
const rootLower = normalizedRoot.toLowerCase();
|
|
7127
|
+
const targetLower = normalizedTarget.toLowerCase();
|
|
7128
|
+
return targetLower === rootLower || targetLower.startsWith(`${rootLower}/`);
|
|
7129
|
+
}
|
|
7130
|
+
function toRelativeFromRoot(root, target) {
|
|
7131
|
+
const rootSegments = splitSegments(root);
|
|
7132
|
+
const targetSegments = splitSegments(target);
|
|
7133
|
+
let index = 0;
|
|
7134
|
+
while (index < rootSegments.length && index < targetSegments.length) {
|
|
7135
|
+
if (rootSegments[index]?.toLowerCase() !== targetSegments[index]?.toLowerCase()) break;
|
|
7136
|
+
index += 1;
|
|
7137
|
+
}
|
|
7138
|
+
return targetSegments.slice(index).join("/");
|
|
7139
|
+
}
|
|
7140
|
+
function findOpspecSlice(path$1) {
|
|
7141
|
+
const segments = splitSegments(path$1);
|
|
7142
|
+
const idx = segments.lastIndexOf("openspec");
|
|
7143
|
+
if (idx < 0) return null;
|
|
7144
|
+
return segments.slice(idx).join("/");
|
|
7145
|
+
}
|
|
7146
|
+
function toOpsxDisplayPath(absoluteOrRelativePath, options) {
|
|
7147
|
+
const normalized = normalizeFsPath(absoluteOrRelativePath);
|
|
7148
|
+
const npmSpecifier = toNpmSpecifier(normalized);
|
|
7149
|
+
if (options?.source === "package" || npmSpecifier) {
|
|
7150
|
+
if (npmSpecifier) return npmSpecifier;
|
|
7151
|
+
}
|
|
7152
|
+
if (!isAbsolutePath(normalized)) return toVirtualProjectPath(normalized);
|
|
7153
|
+
if (options?.projectDir && isPathInside(options.projectDir, normalized)) return toVirtualProjectPath(toRelativeFromRoot(options.projectDir, normalized));
|
|
7154
|
+
const openspecSlice = findOpspecSlice(normalized);
|
|
7155
|
+
if (openspecSlice) return toVirtualProjectPath(openspecSlice);
|
|
7156
|
+
return toVirtualProjectPath(splitSegments(normalized).slice(-4).join("/"));
|
|
7157
|
+
}
|
|
7158
|
+
|
|
7097
7159
|
//#endregion
|
|
7098
7160
|
//#region ../core/src/opsx-types.ts
|
|
7099
7161
|
const ArtifactStatusSchema = objectType({
|
|
@@ -7177,17 +7239,20 @@ const SchemaResolutionSchema = objectType({
|
|
|
7177
7239
|
"package"
|
|
7178
7240
|
]),
|
|
7179
7241
|
path: stringType(),
|
|
7242
|
+
displayPath: stringType().optional(),
|
|
7180
7243
|
shadows: arrayType(objectType({
|
|
7181
7244
|
source: enumType([
|
|
7182
7245
|
"project",
|
|
7183
7246
|
"user",
|
|
7184
7247
|
"package"
|
|
7185
7248
|
]),
|
|
7186
|
-
path: stringType()
|
|
7249
|
+
path: stringType(),
|
|
7250
|
+
displayPath: stringType().optional()
|
|
7187
7251
|
}))
|
|
7188
7252
|
});
|
|
7189
7253
|
const TemplatesSchema = recordType(objectType({
|
|
7190
7254
|
path: stringType(),
|
|
7255
|
+
displayPath: stringType().optional(),
|
|
7191
7256
|
source: enumType([
|
|
7192
7257
|
"project",
|
|
7193
7258
|
"user",
|
|
@@ -13884,6 +13949,12 @@ function parseCliJson(raw$1, schema$6, label) {
|
|
|
13884
13949
|
function toRelativePath(root, absolutePath) {
|
|
13885
13950
|
return relative$1(root, absolutePath).split(sep).join("/");
|
|
13886
13951
|
}
|
|
13952
|
+
function isAbsoluteFsPath(path$1) {
|
|
13953
|
+
return path$1.startsWith("/") || /^[A-Za-z]:\//.test(path$1);
|
|
13954
|
+
}
|
|
13955
|
+
function toAbsoluteProjectPath(projectDir, path$1) {
|
|
13956
|
+
return isAbsoluteFsPath(path$1.replace(/\\/g, "/")) ? path$1 : resolve$1(projectDir, path$1);
|
|
13957
|
+
}
|
|
13887
13958
|
async function readEntriesUnderRoot(root) {
|
|
13888
13959
|
if (!(await reactiveStat(root))?.isDirectory) return [];
|
|
13889
13960
|
const collectEntries = async (dir) => {
|
|
@@ -14322,7 +14393,21 @@ var OpsxKernel = class {
|
|
|
14322
14393
|
await touchOpsxProjectDeps(this.projectDir);
|
|
14323
14394
|
const result = await this.cliExecutor.schemaWhich(name);
|
|
14324
14395
|
if (!result.success) throw new Error(result.stderr || `openspec schema which failed (exit ${result.exitCode ?? "null"})`);
|
|
14325
|
-
|
|
14396
|
+
const parsed = parseCliJson(result.stdout, SchemaResolutionSchema, "openspec schema which");
|
|
14397
|
+
return {
|
|
14398
|
+
...parsed,
|
|
14399
|
+
displayPath: toOpsxDisplayPath(parsed.path, {
|
|
14400
|
+
source: parsed.source,
|
|
14401
|
+
projectDir: this.projectDir
|
|
14402
|
+
}),
|
|
14403
|
+
shadows: parsed.shadows.map((shadow) => ({
|
|
14404
|
+
...shadow,
|
|
14405
|
+
displayPath: toOpsxDisplayPath(shadow.path, {
|
|
14406
|
+
source: shadow.source,
|
|
14407
|
+
projectDir: this.projectDir
|
|
14408
|
+
})
|
|
14409
|
+
}))
|
|
14410
|
+
};
|
|
14326
14411
|
}
|
|
14327
14412
|
async fetchSchemaDetail(name) {
|
|
14328
14413
|
await touchOpsxProjectDeps(this.projectDir);
|
|
@@ -14346,7 +14431,15 @@ var OpsxKernel = class {
|
|
|
14346
14431
|
await touchOpsxProjectDeps(this.projectDir);
|
|
14347
14432
|
const result = await this.cliExecutor.templates(schema$6);
|
|
14348
14433
|
if (!result.success) throw new Error(result.stderr || `openspec templates failed (exit ${result.exitCode ?? "null"})`);
|
|
14349
|
-
|
|
14434
|
+
const templates = parseCliJson(result.stdout, TemplatesSchema, "openspec templates");
|
|
14435
|
+
return Object.fromEntries(Object.entries(templates).map(([artifactId, info]) => [artifactId, {
|
|
14436
|
+
...info,
|
|
14437
|
+
path: toAbsoluteProjectPath(this.projectDir, info.path),
|
|
14438
|
+
displayPath: toOpsxDisplayPath(info.path, {
|
|
14439
|
+
source: info.source,
|
|
14440
|
+
projectDir: this.projectDir
|
|
14441
|
+
})
|
|
14442
|
+
}]));
|
|
14350
14443
|
}
|
|
14351
14444
|
async fetchTemplateContents(schema$6) {
|
|
14352
14445
|
await this.ensureTemplates(schema$6);
|
|
@@ -14355,6 +14448,10 @@ var OpsxKernel = class {
|
|
|
14355
14448
|
return [artifactId, {
|
|
14356
14449
|
content: await reactiveReadFile(info.path),
|
|
14357
14450
|
path: info.path,
|
|
14451
|
+
displayPath: info.displayPath ?? toOpsxDisplayPath(info.path, {
|
|
14452
|
+
source: info.source,
|
|
14453
|
+
projectDir: this.projectDir
|
|
14454
|
+
}),
|
|
14358
14455
|
source: info.source
|
|
14359
14456
|
}];
|
|
14360
14457
|
}));
|
|
@@ -25370,4 +25467,4 @@ async function startServer$1(options = {}) {
|
|
|
25370
25467
|
}
|
|
25371
25468
|
|
|
25372
25469
|
//#endregion
|
|
25373
|
-
export { SchemaInfoSchema as a,
|
|
25470
|
+
export { SchemaInfoSchema as a, toOpsxDisplayPath as c, DEFAULT_CONFIG as d, OpenSpecAdapter as f, SchemaDetailSchema as i, CliExecutor as l, __toESM$1 as m, createServer$2 as n, SchemaResolutionSchema as o, __commonJS$1 as p, require_dist as r, TemplatesSchema as s, startServer$1 as t, ConfigManager as u };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "openspecui",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.6.0",
|
|
4
4
|
"description": "OpenSpec UI - Visual interface for spec-driven development",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.mjs",
|
|
@@ -33,8 +33,8 @@
|
|
|
33
33
|
"typescript": "^5.7.2",
|
|
34
34
|
"vitest": "^2.1.8",
|
|
35
35
|
"yargs": "^18.0.0",
|
|
36
|
-
"@openspecui/
|
|
37
|
-
"@openspecui/
|
|
36
|
+
"@openspecui/server": "1.6.0",
|
|
37
|
+
"@openspecui/web": "1.6.0"
|
|
38
38
|
},
|
|
39
39
|
"scripts": {
|
|
40
40
|
"build": "pnpm run build:web && pnpm run build:copy-web && tsdown",
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{y as U,z as g,A as c,B as S,D as _,F as m,H as I,J as p}from"./index-
|
|
1
|
+
import{y as U,z as g,A as c,B as S,D as _,F as m,H as I,J as p}from"./index-CKfGQiMr.js";const x={name:"local-uniform-bit",vertex:{header:`
|
|
2
2
|
|
|
3
3
|
struct LocalUniforms {
|
|
4
4
|
uTransformMatrix:mat3x3<f32>,
|