trellis 3.1.13 → 3.1.19
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/CHANGELOG.md +8 -0
- package/LICENSE +2 -0
- package/README.md +12 -9
- package/bin/trellis.mjs +10 -2
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +405 -336
- package/dist/cli/repo-path.d.ts +12 -0
- package/dist/cli/repo-path.d.ts.map +1 -0
- package/package.json +3 -3
package/dist/cli/index.js
CHANGED
|
@@ -2401,8 +2401,8 @@ var exports_server = {};
|
|
|
2401
2401
|
__export(exports_server, {
|
|
2402
2402
|
startUIServer: () => startUIServer
|
|
2403
2403
|
});
|
|
2404
|
-
import { readFileSync as
|
|
2405
|
-
import { join as join5, dirname as
|
|
2404
|
+
import { readFileSync as readFileSync4, existsSync as existsSync5 } from "fs";
|
|
2405
|
+
import { join as join5, dirname as dirname5 } from "path";
|
|
2406
2406
|
function buildGraph(engine) {
|
|
2407
2407
|
const nodes = [];
|
|
2408
2408
|
const edges = [];
|
|
@@ -2506,7 +2506,7 @@ function buildGraph(engine) {
|
|
|
2506
2506
|
if (existsSync5(absPath)) {
|
|
2507
2507
|
mdFiles.push({
|
|
2508
2508
|
path: f.path,
|
|
2509
|
-
content:
|
|
2509
|
+
content: readFileSync4(absPath, "utf-8")
|
|
2510
2510
|
});
|
|
2511
2511
|
}
|
|
2512
2512
|
}
|
|
@@ -2732,26 +2732,26 @@ async function startUIServer(opts) {
|
|
|
2732
2732
|
const engine = new TrellisVcsEngine({ rootPath: opts.rootPath });
|
|
2733
2733
|
engine.open();
|
|
2734
2734
|
function findClientHtml() {
|
|
2735
|
-
const
|
|
2735
|
+
const here2 = dirname5(process.argv[1]);
|
|
2736
2736
|
const candidates = [
|
|
2737
|
-
join5(
|
|
2738
|
-
join5(
|
|
2739
|
-
join5(
|
|
2737
|
+
join5(here2, "client.html"),
|
|
2738
|
+
join5(here2, "..", "ui", "client.html"),
|
|
2739
|
+
join5(here2, "ui", "client.html")
|
|
2740
2740
|
];
|
|
2741
|
-
let dir =
|
|
2741
|
+
let dir = here2;
|
|
2742
2742
|
for (let i = 0;i < 5; i++) {
|
|
2743
2743
|
candidates.push(join5(dir, "dist", "ui", "client.html"));
|
|
2744
2744
|
candidates.push(join5(dir, "ui", "client.html"));
|
|
2745
|
-
dir =
|
|
2745
|
+
dir = dirname5(dir);
|
|
2746
2746
|
}
|
|
2747
2747
|
for (const p of candidates) {
|
|
2748
2748
|
if (existsSync5(p))
|
|
2749
2749
|
return p;
|
|
2750
2750
|
}
|
|
2751
|
-
throw new Error(`Could not find client.html. Searched from: ${
|
|
2751
|
+
throw new Error(`Could not find client.html. Searched from: ${here2}
|
|
2752
2752
|
Try reinstalling the package or running \`bun run build\`.`);
|
|
2753
2753
|
}
|
|
2754
|
-
const clientHtml =
|
|
2754
|
+
const clientHtml = readFileSync4(findClientHtml(), "utf-8");
|
|
2755
2755
|
let embeddingManager = null;
|
|
2756
2756
|
function getEmbeddingManager() {
|
|
2757
2757
|
if (!embeddingManager) {
|
|
@@ -3375,7 +3375,7 @@ var chalkStderr = createChalk({ level: stderrColor ? stderrColor.level : 0 });
|
|
|
3375
3375
|
var source_default = chalk;
|
|
3376
3376
|
|
|
3377
3377
|
// src/cli/index.ts
|
|
3378
|
-
import { resolve, join as join6 } from "path";
|
|
3378
|
+
import { resolve as resolve2, join as join6 } from "path";
|
|
3379
3379
|
|
|
3380
3380
|
// node_modules/@inquirer/core/dist/lib/key.js
|
|
3381
3381
|
var isUpKey = (key, keybindings = []) => key.name === "up" || keybindings.includes("vim") && key.name === "k" || keybindings.includes("emacs") && key.ctrl && key.name === "p";
|
|
@@ -5706,15 +5706,54 @@ function base58btcEncode(buf) {
|
|
|
5706
5706
|
}
|
|
5707
5707
|
return encoded || "1";
|
|
5708
5708
|
}
|
|
5709
|
-
// src/cli/
|
|
5710
|
-
|
|
5711
|
-
|
|
5712
|
-
|
|
5713
|
-
|
|
5714
|
-
|
|
5715
|
-
|
|
5709
|
+
// src/cli/repo-path.ts
|
|
5710
|
+
import { readFileSync as readFileSync3 } from "fs";
|
|
5711
|
+
import { dirname as dirname4, resolve } from "path";
|
|
5712
|
+
import { fileURLToPath } from "url";
|
|
5713
|
+
init_engine();
|
|
5714
|
+
var here = dirname4(fileURLToPath(import.meta.url));
|
|
5715
|
+
function cliVersion() {
|
|
5716
|
+
const path = resolve(here, "../../package.json");
|
|
5717
|
+
try {
|
|
5718
|
+
const pkg = JSON.parse(readFileSync3(path, "utf8"));
|
|
5719
|
+
if (typeof pkg.version === "string")
|
|
5720
|
+
return pkg.version;
|
|
5721
|
+
} catch {}
|
|
5722
|
+
return "0.0.0";
|
|
5723
|
+
}
|
|
5724
|
+
function findRepoRoot(pathOpt) {
|
|
5725
|
+
const start = resolve(pathOpt ?? process.cwd());
|
|
5726
|
+
let dir = start;
|
|
5727
|
+
while (true) {
|
|
5728
|
+
if (TrellisVcsEngine.isRepo(dir))
|
|
5729
|
+
return dir;
|
|
5730
|
+
const parent = dirname4(dir);
|
|
5731
|
+
if (parent === dir)
|
|
5732
|
+
return;
|
|
5733
|
+
dir = parent;
|
|
5716
5734
|
}
|
|
5717
5735
|
}
|
|
5736
|
+
function resolveRepoRoot(pathOpt) {
|
|
5737
|
+
const start = resolve(pathOpt ?? process.cwd());
|
|
5738
|
+
const found = findRepoRoot(pathOpt);
|
|
5739
|
+
if (found)
|
|
5740
|
+
return found;
|
|
5741
|
+
failNotRepo(start, pathOpt);
|
|
5742
|
+
}
|
|
5743
|
+
function failNotRepo(start, pathOpt) {
|
|
5744
|
+
console.error(source_default.red("Not a TrellisVCS repository."));
|
|
5745
|
+
console.error(source_default.dim(` looked from: ${start}`));
|
|
5746
|
+
if (pathOpt && resolve(pathOpt) !== process.cwd()) {
|
|
5747
|
+
console.error(source_default.dim(` -p: ${resolve(pathOpt)}`));
|
|
5748
|
+
}
|
|
5749
|
+
console.error(source_default.dim(` cwd: ${process.cwd()}`));
|
|
5750
|
+
console.error(source_default.dim(" Hint: run from the repo root, pass -p <path>, or run `trellis init`."));
|
|
5751
|
+
process.exit(1);
|
|
5752
|
+
}
|
|
5753
|
+
|
|
5754
|
+
// src/cli/index.ts
|
|
5755
|
+
var program2 = new Command;
|
|
5756
|
+
program2.name("trellis").description("TrellisVCS \u2014 graph-native, code-first version control").version(cliVersion());
|
|
5718
5757
|
async function runInit(rootPath, opts = {}) {
|
|
5719
5758
|
const isInteractive = opts.interactive !== false && process.stdout.isTTY && !process.argv.includes("--no-interactive");
|
|
5720
5759
|
if (TrellisVcsEngine.isRepo(rootPath)) {
|
|
@@ -5750,115 +5789,147 @@ async function runInit(rootPath, opts = {}) {
|
|
|
5750
5789
|
if (isInteractive) {
|
|
5751
5790
|
console.log(source_default.cyan(`
|
|
5752
5791
|
Configuring workspace...`));
|
|
5753
|
-
const
|
|
5754
|
-
|
|
5755
|
-
{ name: "Vue", value: "vue" },
|
|
5756
|
-
{ name: "Svelte", value: "svelte" },
|
|
5757
|
-
{ name: "Next.js", value: "next" },
|
|
5758
|
-
{ name: "Nuxt", value: "nuxt" },
|
|
5759
|
-
{ name: "Remotion", value: "remotion" },
|
|
5760
|
-
{ name: "Expo / React Native", value: "expo" },
|
|
5761
|
-
{ name: "Bun runtime", value: "bun" },
|
|
5762
|
-
{ name: "Node.js server", value: "node" },
|
|
5763
|
-
{ name: "CLI tool", value: "cli" },
|
|
5764
|
-
{ name: "Library / Package", value: "library" },
|
|
5765
|
-
{ name: "Animation studio", value: "animation" },
|
|
5766
|
-
{ name: "Games", value: "games" },
|
|
5767
|
-
{ name: "None / Vanilla", value: "none" }
|
|
5768
|
-
];
|
|
5769
|
-
framework = await dist_default5({
|
|
5770
|
-
message: detectedFramework ? `What type of project are you building? (detected: ${detectedFramework})` : "What type of project are you building?",
|
|
5771
|
-
choices: frameworkChoices,
|
|
5772
|
-
default: opts.framework || detectedFramework || "none"
|
|
5773
|
-
});
|
|
5774
|
-
const ideChoices = [
|
|
5775
|
-
{
|
|
5776
|
-
name: "Cursor",
|
|
5777
|
-
value: "cursor",
|
|
5778
|
-
checked: selectedIdes.includes("cursor") || selectedIdes.length === 0
|
|
5779
|
-
},
|
|
5780
|
-
{
|
|
5781
|
-
name: "Windsurf",
|
|
5782
|
-
value: "windsurf",
|
|
5783
|
-
checked: selectedIdes.includes("windsurf")
|
|
5784
|
-
},
|
|
5785
|
-
{
|
|
5786
|
-
name: "Claude Desktop",
|
|
5787
|
-
value: "claude",
|
|
5788
|
-
checked: selectedIdes.includes("claude")
|
|
5789
|
-
},
|
|
5790
|
-
{
|
|
5791
|
-
name: "VS Code Copilot",
|
|
5792
|
-
value: "copilot",
|
|
5793
|
-
checked: selectedIdes.includes("copilot")
|
|
5794
|
-
},
|
|
5795
|
-
{
|
|
5796
|
-
name: "Google Gemini (Code Assist)",
|
|
5797
|
-
value: "gemini",
|
|
5798
|
-
checked: selectedIdes.includes("gemini")
|
|
5799
|
-
},
|
|
5800
|
-
{
|
|
5801
|
-
name: "OpenAI Codex",
|
|
5802
|
-
value: "codex",
|
|
5803
|
-
checked: selectedIdes.includes("codex")
|
|
5804
|
-
}
|
|
5805
|
-
];
|
|
5806
|
-
selectedIdes = await dist_default4({
|
|
5807
|
-
message: "Which IDEs/agents do you want to scaffold for?",
|
|
5808
|
-
choices: ideChoices
|
|
5809
|
-
});
|
|
5810
|
-
footprint = await dist_default5({
|
|
5811
|
-
message: "How minimal do you want your workspace?",
|
|
5812
|
-
choices: [
|
|
5813
|
-
{ name: "Minimal (just agent rules)", value: "minimal" },
|
|
5814
|
-
{ name: "Standard (includes skills + workflows)", value: "standard" },
|
|
5815
|
-
{ name: "Full (kitchen sink)", value: "full" }
|
|
5816
|
-
],
|
|
5817
|
-
default: footprint
|
|
5818
|
-
});
|
|
5819
|
-
plugins = await dist_default4({
|
|
5820
|
-
message: "Select features:",
|
|
5792
|
+
const setupType = await dist_default5({
|
|
5793
|
+
message: "Choose your setup mode:",
|
|
5821
5794
|
choices: [
|
|
5822
5795
|
{
|
|
5823
|
-
name: "
|
|
5824
|
-
value: "
|
|
5825
|
-
checked: plugins.includes("sub-projects")
|
|
5796
|
+
name: "\u26A1 Minimal Setup (One-shot setup with detected defaults)",
|
|
5797
|
+
value: "minimal"
|
|
5826
5798
|
},
|
|
5827
|
-
{ name: "P2P Sync", value: "p2p", checked: plugins.includes("p2p") },
|
|
5828
5799
|
{
|
|
5829
|
-
name: "
|
|
5830
|
-
value: "
|
|
5831
|
-
|
|
5800
|
+
name: "\uD83D\uDD27 Custom Guided Setup (Customize framework, IDEs, footprint, features)",
|
|
5801
|
+
value: "custom"
|
|
5802
|
+
}
|
|
5803
|
+
],
|
|
5804
|
+
default: "minimal"
|
|
5805
|
+
});
|
|
5806
|
+
if (setupType === "minimal") {
|
|
5807
|
+
footprint = "minimal";
|
|
5808
|
+
framework = detectedFramework || "none";
|
|
5809
|
+
const ides = [];
|
|
5810
|
+
const envKeys = Object.keys(process.env).join(",").toLowerCase();
|
|
5811
|
+
if (process.env.TERM_PROGRAM === "Windsurf" || envKeys.includes("windsurf")) {
|
|
5812
|
+
ides.push("windsurf");
|
|
5813
|
+
} else if (process.env.TERM_PROGRAM === "vscode" || envKeys.includes("cursor")) {
|
|
5814
|
+
ides.push("cursor");
|
|
5815
|
+
} else {
|
|
5816
|
+
ides.push("cursor", "windsurf");
|
|
5817
|
+
}
|
|
5818
|
+
selectedIdes = ides;
|
|
5819
|
+
plugins = [];
|
|
5820
|
+
console.log(source_default.green(` \u2713 Detected project type: ${source_default.bold(framework)}`));
|
|
5821
|
+
console.log(source_default.green(` \u2713 Scaffolding rules for: ${source_default.bold(selectedIdes.join(", "))}`));
|
|
5822
|
+
} else {
|
|
5823
|
+
const frameworkChoices = [
|
|
5824
|
+
{ name: "React", value: "react" },
|
|
5825
|
+
{ name: "Vue", value: "vue" },
|
|
5826
|
+
{ name: "Svelte", value: "svelte" },
|
|
5827
|
+
{ name: "Next.js", value: "next" },
|
|
5828
|
+
{ name: "Nuxt", value: "nuxt" },
|
|
5829
|
+
{ name: "Remotion", value: "remotion" },
|
|
5830
|
+
{ name: "Expo / React Native", value: "expo" },
|
|
5831
|
+
{ name: "Bun runtime", value: "bun" },
|
|
5832
|
+
{ name: "Node.js server", value: "node" },
|
|
5833
|
+
{ name: "CLI tool", value: "cli" },
|
|
5834
|
+
{ name: "Library / Package", value: "library" },
|
|
5835
|
+
{ name: "Animation studio", value: "animation" },
|
|
5836
|
+
{ name: "Games", value: "games" },
|
|
5837
|
+
{ name: "None / Vanilla", value: "none" }
|
|
5838
|
+
];
|
|
5839
|
+
framework = await dist_default5({
|
|
5840
|
+
message: detectedFramework ? `What type of project are you building? (detected: ${detectedFramework})` : "What type of project are you building?",
|
|
5841
|
+
choices: frameworkChoices,
|
|
5842
|
+
default: opts.framework || detectedFramework || "none"
|
|
5843
|
+
});
|
|
5844
|
+
const ideChoices = [
|
|
5845
|
+
{
|
|
5846
|
+
name: "Cursor",
|
|
5847
|
+
value: "cursor",
|
|
5848
|
+
checked: selectedIdes.includes("cursor") || selectedIdes.length === 0
|
|
5832
5849
|
},
|
|
5833
5850
|
{
|
|
5834
|
-
name: "
|
|
5835
|
-
value: "
|
|
5836
|
-
checked:
|
|
5851
|
+
name: "Windsurf",
|
|
5852
|
+
value: "windsurf",
|
|
5853
|
+
checked: selectedIdes.includes("windsurf")
|
|
5837
5854
|
},
|
|
5838
5855
|
{
|
|
5839
|
-
name: "
|
|
5840
|
-
value: "
|
|
5841
|
-
checked:
|
|
5856
|
+
name: "Claude Desktop",
|
|
5857
|
+
value: "claude",
|
|
5858
|
+
checked: selectedIdes.includes("claude")
|
|
5842
5859
|
},
|
|
5843
5860
|
{
|
|
5844
|
-
name: "
|
|
5845
|
-
value: "
|
|
5846
|
-
checked:
|
|
5861
|
+
name: "VS Code Copilot",
|
|
5862
|
+
value: "copilot",
|
|
5863
|
+
checked: selectedIdes.includes("copilot")
|
|
5847
5864
|
},
|
|
5848
5865
|
{
|
|
5849
|
-
name: "
|
|
5850
|
-
value: "
|
|
5851
|
-
checked:
|
|
5866
|
+
name: "Google Gemini (Code Assist)",
|
|
5867
|
+
value: "gemini",
|
|
5868
|
+
checked: selectedIdes.includes("gemini")
|
|
5852
5869
|
},
|
|
5853
5870
|
{
|
|
5854
|
-
name: "
|
|
5855
|
-
value: "
|
|
5856
|
-
checked:
|
|
5871
|
+
name: "OpenAI Codex",
|
|
5872
|
+
value: "codex",
|
|
5873
|
+
checked: selectedIdes.includes("codex")
|
|
5857
5874
|
}
|
|
5858
|
-
]
|
|
5859
|
-
|
|
5860
|
-
|
|
5861
|
-
|
|
5875
|
+
];
|
|
5876
|
+
selectedIdes = await dist_default4({
|
|
5877
|
+
message: "Which IDEs/agents do you want to scaffold for?",
|
|
5878
|
+
choices: ideChoices
|
|
5879
|
+
});
|
|
5880
|
+
footprint = await dist_default5({
|
|
5881
|
+
message: "How minimal do you want your workspace?",
|
|
5882
|
+
choices: [
|
|
5883
|
+
{ name: "Minimal (just agent rules)", value: "minimal" },
|
|
5884
|
+
{ name: "Standard (includes skills + workflows)", value: "standard" },
|
|
5885
|
+
{ name: "Full (kitchen sink)", value: "full" }
|
|
5886
|
+
],
|
|
5887
|
+
default: footprint
|
|
5888
|
+
});
|
|
5889
|
+
plugins = await dist_default4({
|
|
5890
|
+
message: "Select features:",
|
|
5891
|
+
choices: [
|
|
5892
|
+
{
|
|
5893
|
+
name: "Sub-projects (monorepo, workspaces)",
|
|
5894
|
+
value: "sub-projects",
|
|
5895
|
+
checked: plugins.includes("sub-projects")
|
|
5896
|
+
},
|
|
5897
|
+
{ name: "P2P Sync", value: "p2p", checked: plugins.includes("p2p") },
|
|
5898
|
+
{
|
|
5899
|
+
name: "MCP Server",
|
|
5900
|
+
value: "mcp",
|
|
5901
|
+
checked: plugins.includes("mcp")
|
|
5902
|
+
},
|
|
5903
|
+
{
|
|
5904
|
+
name: "UI Components",
|
|
5905
|
+
value: "ui-components",
|
|
5906
|
+
checked: plugins.includes("ui-components")
|
|
5907
|
+
},
|
|
5908
|
+
{
|
|
5909
|
+
name: "Media Pipelines",
|
|
5910
|
+
value: "media-pipelines",
|
|
5911
|
+
checked: plugins.includes("media-pipelines")
|
|
5912
|
+
},
|
|
5913
|
+
{
|
|
5914
|
+
name: "Brand System",
|
|
5915
|
+
value: "brand-system",
|
|
5916
|
+
checked: plugins.includes("brand-system")
|
|
5917
|
+
},
|
|
5918
|
+
{
|
|
5919
|
+
name: "Agent Memory",
|
|
5920
|
+
value: "agent-memory",
|
|
5921
|
+
checked: plugins.includes("agent-memory")
|
|
5922
|
+
},
|
|
5923
|
+
{
|
|
5924
|
+
name: "Workflows",
|
|
5925
|
+
value: "workflows",
|
|
5926
|
+
checked: plugins.includes("workflows") || footprint !== "minimal"
|
|
5927
|
+
}
|
|
5928
|
+
]
|
|
5929
|
+
});
|
|
5930
|
+
if (plugins.includes("sub-projects") && !plugins.includes("workflows")) {
|
|
5931
|
+
plugins.push("workflows");
|
|
5932
|
+
}
|
|
5862
5933
|
}
|
|
5863
5934
|
}
|
|
5864
5935
|
const engine = new TrellisVcsEngine({ rootPath });
|
|
@@ -5893,7 +5964,7 @@ async function runInit(rootPath, opts = {}) {
|
|
|
5893
5964
|
}
|
|
5894
5965
|
}
|
|
5895
5966
|
program2.command("init").description("Initialize a new TrellisVCS repository in the current directory").option("-p, --path <path>", "Path to initialize", ".").option("--ides <ides...>", "IDEs to scaffold for (cursor, windsurf, claude, copilot, codex, gemini)").option("--framework <framework>", "Project framework (react, vue, svelte, next, nuxt, remotion, expo, bun, node, cli, library, animation, games, none)", "none").option("--footprint <footprint>", "Workspace footprint (minimal, standard, full)", "standard").option("--no-interactive", "Skip interactive prompts").action(async (opts) => {
|
|
5896
|
-
const rootPath =
|
|
5967
|
+
const rootPath = resolve2(opts.path);
|
|
5897
5968
|
if (TrellisVcsEngine.isRepo(rootPath)) {
|
|
5898
5969
|
console.log(source_default.yellow("Already a Trellis workspace."));
|
|
5899
5970
|
return;
|
|
@@ -5911,7 +5982,6 @@ program2.command("init").description("Initialize a new TrellisVCS repository in
|
|
|
5911
5982
|
console.log(` ${source_default.dim("Ops:")} ${opsCount} initial operations scanned`);
|
|
5912
5983
|
console.log(` ${source_default.dim("Config:")} .trellis/config.json`);
|
|
5913
5984
|
console.log(` ${source_default.dim("Op log:")} .trellis/ops.json`);
|
|
5914
|
-
console.log(` ${source_default.dim("Graph DB:")} .trellis/graph.db`);
|
|
5915
5985
|
console.log(` ${source_default.dim("Agent context:")} .trellis/agents/AGENTS.md`);
|
|
5916
5986
|
const preInfer = await inferProjectContext(rootPath);
|
|
5917
5987
|
if (preInfer.domain) {
|
|
@@ -5936,8 +6006,7 @@ program2.command("init").description("Initialize a new TrellisVCS repository in
|
|
|
5936
6006
|
console.log(source_default.dim("The causal stream is now active. Every file change will be tracked."));
|
|
5937
6007
|
});
|
|
5938
6008
|
program2.command("seed").description("Refresh agent context files with current project state").option("-p, --path <path>", "Repository path", ".").option("--ide <ide>", "IDE to update (cursor, windsurf, claude, copilot)", "none").option("-f, --force", "Force rewrite even if files do not exist", false).action(async (opts) => {
|
|
5939
|
-
const rootPath =
|
|
5940
|
-
requireRepo(rootPath);
|
|
6009
|
+
const rootPath = resolveRepoRoot(opts.path);
|
|
5941
6010
|
const ide = opts.ide || "none";
|
|
5942
6011
|
const force = opts.force || false;
|
|
5943
6012
|
console.log(source_default.dim("Seeding agent context..."));
|
|
@@ -5954,8 +6023,7 @@ program2.command("seed").description("Refresh agent context files with current p
|
|
|
5954
6023
|
}
|
|
5955
6024
|
});
|
|
5956
6025
|
program2.command("repair").description("Attempt to repair a corrupted .trellis/ops.json file").option("-p, --path <path>", "Repository path", ".").action((opts) => {
|
|
5957
|
-
const rootPath =
|
|
5958
|
-
requireRepo(rootPath);
|
|
6026
|
+
const rootPath = resolveRepoRoot(opts.path);
|
|
5959
6027
|
console.log(source_default.yellow("Attempting to repair ops.json..."));
|
|
5960
6028
|
const result = TrellisVcsEngine.repair(rootPath);
|
|
5961
6029
|
if (result.lost === -1) {
|
|
@@ -5967,11 +6035,7 @@ program2.command("repair").description("Attempt to repair a corrupted .trellis/o
|
|
|
5967
6035
|
}
|
|
5968
6036
|
});
|
|
5969
6037
|
program2.command("status").description("Show current repository status").option("-p, --path <path>", "Repository path", ".").action(async (opts) => {
|
|
5970
|
-
const rootPath =
|
|
5971
|
-
if (!TrellisVcsEngine.isRepo(rootPath)) {
|
|
5972
|
-
console.log(source_default.red("Not a TrellisVCS repository. Run `trellis init` first."));
|
|
5973
|
-
process.exit(1);
|
|
5974
|
-
}
|
|
6038
|
+
const rootPath = resolveRepoRoot(opts.path);
|
|
5975
6039
|
const engine = new TrellisVcsEngine({ rootPath });
|
|
5976
6040
|
engine.open();
|
|
5977
6041
|
const st = engine.status();
|
|
@@ -6001,11 +6065,7 @@ program2.command("status").description("Show current repository status").option(
|
|
|
6001
6065
|
}
|
|
6002
6066
|
});
|
|
6003
6067
|
program2.command("log").description("Show operation history").option("-p, --path <path>", "Repository path", ".").option("-n, --limit <n>", "Number of ops to show", "20").option("-f, --file <file>", "Filter by file path").action(async (opts) => {
|
|
6004
|
-
const rootPath =
|
|
6005
|
-
if (!TrellisVcsEngine.isRepo(rootPath)) {
|
|
6006
|
-
console.log(source_default.red("Not a TrellisVCS repository. Run `trellis init` first."));
|
|
6007
|
-
process.exit(1);
|
|
6008
|
-
}
|
|
6068
|
+
const rootPath = resolveRepoRoot(opts.path);
|
|
6009
6069
|
const engine = new TrellisVcsEngine({ rootPath });
|
|
6010
6070
|
engine.open();
|
|
6011
6071
|
const ops = engine.log({
|
|
@@ -6028,11 +6088,7 @@ program2.command("log").description("Show operation history").option("-p, --path
|
|
|
6028
6088
|
}
|
|
6029
6089
|
});
|
|
6030
6090
|
program2.command("files").description("List all tracked files").option("-p, --path <path>", "Repository path", ".").action(async (opts) => {
|
|
6031
|
-
const rootPath =
|
|
6032
|
-
if (!TrellisVcsEngine.isRepo(rootPath)) {
|
|
6033
|
-
console.log(source_default.red("Not a TrellisVCS repository. Run `trellis init` first."));
|
|
6034
|
-
process.exit(1);
|
|
6035
|
-
}
|
|
6091
|
+
const rootPath = resolveRepoRoot(opts.path);
|
|
6036
6092
|
const engine = new TrellisVcsEngine({ rootPath });
|
|
6037
6093
|
engine.open();
|
|
6038
6094
|
const files = engine.trackedFiles();
|
|
@@ -6048,11 +6104,7 @@ program2.command("files").description("List all tracked files").option("-p, --pa
|
|
|
6048
6104
|
}
|
|
6049
6105
|
});
|
|
6050
6106
|
program2.command("watch").description("Start file watcher (foreground, Ctrl+C to stop)").option("-p, --path <path>", "Repository path", ".").action(async (opts) => {
|
|
6051
|
-
const rootPath =
|
|
6052
|
-
if (!TrellisVcsEngine.isRepo(rootPath)) {
|
|
6053
|
-
console.log(source_default.red("Not a TrellisVCS repository. Run `trellis init` first."));
|
|
6054
|
-
process.exit(1);
|
|
6055
|
-
}
|
|
6107
|
+
const rootPath = resolveRepoRoot(opts.path);
|
|
6056
6108
|
const engine = new TrellisVcsEngine({ rootPath });
|
|
6057
6109
|
engine.open();
|
|
6058
6110
|
console.log(source_default.green("\u2713 Watching for changes\u2026") + source_default.dim(" (Ctrl+C to stop)"));
|
|
@@ -6067,8 +6119,8 @@ program2.command("watch").description("Start file watcher (foreground, Ctrl+C to
|
|
|
6067
6119
|
});
|
|
6068
6120
|
});
|
|
6069
6121
|
program2.command("import").description("Import from an existing Git repository").requiredOption("--from <path>", "Path to the Git repository to import from").option("-p, --path <path>", "Target TrellisVCS repository path", ".").action(async (opts) => {
|
|
6070
|
-
const from =
|
|
6071
|
-
const to =
|
|
6122
|
+
const from = resolve2(opts.from);
|
|
6123
|
+
const to = resolve2(opts.path);
|
|
6072
6124
|
console.log(source_default.dim(`Importing from Git: ${from}`));
|
|
6073
6125
|
console.log(source_default.dim(`Target: ${to}`));
|
|
6074
6126
|
console.log();
|
|
@@ -6103,12 +6155,8 @@ Import failed: ${err.message}`));
|
|
|
6103
6155
|
}
|
|
6104
6156
|
});
|
|
6105
6157
|
program2.command("export").description("Export milestones to a Git repository").requiredOption("--to <path>", "Path to the target Git repository").option("-p, --path <path>", "Source TrellisVCS repository path", ".").option("--author-name <name>", "Author name for Git commits").option("--author-email <email>", "Author email for Git commits").action(async (opts) => {
|
|
6106
|
-
const from =
|
|
6107
|
-
const to =
|
|
6108
|
-
if (!TrellisVcsEngine.isRepo(from)) {
|
|
6109
|
-
console.error(source_default.red("Not a TrellisVCS repository. Run `trellis init` first."));
|
|
6110
|
-
process.exit(1);
|
|
6111
|
-
}
|
|
6158
|
+
const from = resolveRepoRoot(opts.path);
|
|
6159
|
+
const to = resolve2(opts.to);
|
|
6112
6160
|
console.log(source_default.dim(`Exporting from: ${from}`));
|
|
6113
6161
|
console.log(source_default.dim(`Target Git repo: ${to}`));
|
|
6114
6162
|
console.log();
|
|
@@ -6141,11 +6189,7 @@ Export failed: ${err.message}`));
|
|
|
6141
6189
|
}
|
|
6142
6190
|
});
|
|
6143
6191
|
program2.command("branch").description("Manage branches").argument("[name]", "Branch name to create or switch to").option("-d, --delete <name>", "Delete a branch").option("-l, --list", "List all branches").option("-p, --path <path>", "Repository path", ".").action(async (name, opts) => {
|
|
6144
|
-
const rootPath =
|
|
6145
|
-
if (!TrellisVcsEngine.isRepo(rootPath)) {
|
|
6146
|
-
console.error(source_default.red("Not a TrellisVCS repository. Run `trellis init` first."));
|
|
6147
|
-
process.exit(1);
|
|
6148
|
-
}
|
|
6192
|
+
const rootPath = resolveRepoRoot(opts.path);
|
|
6149
6193
|
const engine = new TrellisVcsEngine({ rootPath });
|
|
6150
6194
|
engine.open();
|
|
6151
6195
|
if (opts.delete) {
|
|
@@ -6196,11 +6240,7 @@ program2.command("branch").description("Manage branches").argument("[name]", "Br
|
|
|
6196
6240
|
}
|
|
6197
6241
|
});
|
|
6198
6242
|
program2.command("milestone").description("Create or list milestones").argument("[action]", '"create" or "list" (default: list)').option("-m, --message <message>", "Milestone message").option("--from <hash>", "Start op hash for the milestone range").option("--to <hash>", "End op hash for the milestone range").option("-p, --path <path>", "Repository path", ".").action(async (action, opts) => {
|
|
6199
|
-
const rootPath =
|
|
6200
|
-
if (!TrellisVcsEngine.isRepo(rootPath)) {
|
|
6201
|
-
console.error(source_default.red("Not a TrellisVCS repository. Run `trellis init` first."));
|
|
6202
|
-
process.exit(1);
|
|
6203
|
-
}
|
|
6243
|
+
const rootPath = resolveRepoRoot(opts.path);
|
|
6204
6244
|
const engine = new TrellisVcsEngine({ rootPath });
|
|
6205
6245
|
engine.open();
|
|
6206
6246
|
if (action === "create") {
|
|
@@ -6241,11 +6281,7 @@ program2.command("milestone").description("Create or list milestones").argument(
|
|
|
6241
6281
|
}
|
|
6242
6282
|
});
|
|
6243
6283
|
program2.command("checkpoint").description("Create or list checkpoints").argument("[action]", '"create" or "list" (default: list)').option("-p, --path <path>", "Repository path", ".").action(async (action, opts) => {
|
|
6244
|
-
const rootPath =
|
|
6245
|
-
if (!TrellisVcsEngine.isRepo(rootPath)) {
|
|
6246
|
-
console.error(source_default.red("Not a TrellisVCS repository. Run `trellis init` first."));
|
|
6247
|
-
process.exit(1);
|
|
6248
|
-
}
|
|
6284
|
+
const rootPath = resolveRepoRoot(opts.path);
|
|
6249
6285
|
const engine = new TrellisVcsEngine({ rootPath });
|
|
6250
6286
|
engine.open();
|
|
6251
6287
|
if (action === "create") {
|
|
@@ -6273,11 +6309,7 @@ program2.command("checkpoint").description("Create or list checkpoints").argumen
|
|
|
6273
6309
|
}
|
|
6274
6310
|
});
|
|
6275
6311
|
program2.command("diff").description("Show file-level diff between two points in history").argument("[from]", "Starting op hash or milestone ID").argument("[to]", "Ending op hash (default: current head)").option("-p, --path <path>", "Repository path", ".").option("--stat", "Show only summary stats").action((from, to, opts) => {
|
|
6276
|
-
const rootPath =
|
|
6277
|
-
if (!TrellisVcsEngine.isRepo(rootPath)) {
|
|
6278
|
-
console.error(source_default.red("Not a TrellisVCS repository. Run `trellis init` first."));
|
|
6279
|
-
process.exit(1);
|
|
6280
|
-
}
|
|
6312
|
+
const rootPath = resolveRepoRoot(opts.path);
|
|
6281
6313
|
const engine = new TrellisVcsEngine({ rootPath });
|
|
6282
6314
|
engine.open();
|
|
6283
6315
|
let result;
|
|
@@ -6335,11 +6367,7 @@ program2.command("diff").description("Show file-level diff between two points in
|
|
|
6335
6367
|
}
|
|
6336
6368
|
});
|
|
6337
6369
|
program2.command("merge").description("Merge a branch into the current branch").argument("<branch>", "Source branch to merge").option("-p, --path <path>", "Repository path", ".").option("--dry-run", "Preview merge without applying changes").action((branch, opts) => {
|
|
6338
|
-
const rootPath =
|
|
6339
|
-
if (!TrellisVcsEngine.isRepo(rootPath)) {
|
|
6340
|
-
console.error(source_default.red("Not a TrellisVCS repository. Run `trellis init` first."));
|
|
6341
|
-
process.exit(1);
|
|
6342
|
-
}
|
|
6370
|
+
const rootPath = resolveRepoRoot(opts.path);
|
|
6343
6371
|
const engine = new TrellisVcsEngine({ rootPath });
|
|
6344
6372
|
engine.open();
|
|
6345
6373
|
const result = engine.mergeBranch(branch);
|
|
@@ -6365,13 +6393,12 @@ program2.command("merge").description("Merge a branch into the current branch").
|
|
|
6365
6393
|
}
|
|
6366
6394
|
});
|
|
6367
6395
|
program2.command("parse").description("Parse a file into AST-level semantic entities").argument("<file>", "File to parse").option("-p, --path <path>", "Repository path", ".").action((file, opts) => {
|
|
6368
|
-
const rootPath =
|
|
6396
|
+
const rootPath = resolveRepoRoot(opts.path);
|
|
6369
6397
|
const engine = new TrellisVcsEngine({ rootPath });
|
|
6370
|
-
|
|
6371
|
-
|
|
6372
|
-
const
|
|
6373
|
-
const
|
|
6374
|
-
const content = readFileSync4(filePath, "utf-8");
|
|
6398
|
+
engine.open();
|
|
6399
|
+
const { readFileSync: readFileSync5 } = __require("fs");
|
|
6400
|
+
const filePath = resolve2(file);
|
|
6401
|
+
const content = readFileSync5(filePath, "utf-8");
|
|
6375
6402
|
const result = engine.parseFile(content, file);
|
|
6376
6403
|
if (!result) {
|
|
6377
6404
|
console.log(source_default.dim(`No parser available for: ${file}`));
|
|
@@ -6403,13 +6430,12 @@ program2.command("parse").description("Parse a file into AST-level semantic enti
|
|
|
6403
6430
|
}
|
|
6404
6431
|
});
|
|
6405
6432
|
program2.command("sdiff").description("Show semantic diff between two versions of a file").argument("<fileA>", "Old version of the file").argument("<fileB>", "New version of the file").option("-p, --path <path>", "Repository path", ".").action((fileA, fileB, opts) => {
|
|
6406
|
-
const rootPath =
|
|
6433
|
+
const rootPath = resolveRepoRoot(opts.path);
|
|
6407
6434
|
const engine = new TrellisVcsEngine({ rootPath });
|
|
6408
|
-
|
|
6409
|
-
|
|
6410
|
-
const
|
|
6411
|
-
const
|
|
6412
|
-
const newContent = readFileSync4(resolve(fileB), "utf-8");
|
|
6435
|
+
engine.open();
|
|
6436
|
+
const { readFileSync: readFileSync5 } = __require("fs");
|
|
6437
|
+
const oldContent = readFileSync5(resolve2(fileA), "utf-8");
|
|
6438
|
+
const newContent = readFileSync5(resolve2(fileB), "utf-8");
|
|
6413
6439
|
const patches = engine.semanticDiff(oldContent, newContent, fileA);
|
|
6414
6440
|
if (patches.length === 0) {
|
|
6415
6441
|
console.log(source_default.dim("No semantic differences."));
|
|
@@ -6455,11 +6481,7 @@ program2.command("sdiff").description("Show semantic diff between two versions o
|
|
|
6455
6481
|
}
|
|
6456
6482
|
});
|
|
6457
6483
|
program2.command("sync").description("Sync operations with another TrellisVCS repository").argument("[action]", '"push", "pull", "status", or "reconcile" (default: status)').option("-p, --path <path>", "Local repository path", ".").option("--remote <remote>", "Remote repository path").action((action, opts) => {
|
|
6458
|
-
const rootPath =
|
|
6459
|
-
if (!TrellisVcsEngine.isRepo(rootPath)) {
|
|
6460
|
-
console.error(source_default.red("Not a TrellisVCS repository. Run `trellis init` first."));
|
|
6461
|
-
process.exit(1);
|
|
6462
|
-
}
|
|
6484
|
+
const rootPath = resolveRepoRoot(opts.path);
|
|
6463
6485
|
const engine = new TrellisVcsEngine({ rootPath });
|
|
6464
6486
|
engine.open();
|
|
6465
6487
|
const ops = engine.getOps();
|
|
@@ -6472,7 +6494,7 @@ program2.command("sync").description("Sync operations with another TrellisVCS re
|
|
|
6472
6494
|
return;
|
|
6473
6495
|
}
|
|
6474
6496
|
if (action === "reconcile" && opts.remote) {
|
|
6475
|
-
const remotePath =
|
|
6497
|
+
const remotePath = resolve2(opts.remote);
|
|
6476
6498
|
if (!TrellisVcsEngine.isRepo(remotePath)) {
|
|
6477
6499
|
console.error(source_default.red(`Not a TrellisVCS repository: ${remotePath}`));
|
|
6478
6500
|
process.exit(1);
|
|
@@ -6502,11 +6524,7 @@ program2.command("sync").description("Sync operations with another TrellisVCS re
|
|
|
6502
6524
|
console.log(source_default.dim("Full peer sync requires a transport layer (coming soon)."));
|
|
6503
6525
|
});
|
|
6504
6526
|
program2.command("garden").description("Explore the Idea Garden \u2014 abandoned work clusters").argument("[action]", '"list", "show <id>", "search", "revive <id>", or "stats" (default: list)').argument("[id]", "Cluster ID (for show/revive)").option("-p, --path <path>", "Repository path", ".").option("-f, --file <file>", "Filter by file path").option("-k, --keyword <keyword>", "Filter by keyword").option("-s, --status <status>", "Filter by status (abandoned|draft|revived)").option("-n, --limit <n>", "Max results", parseInt).action((action, id, opts) => {
|
|
6505
|
-
const rootPath =
|
|
6506
|
-
if (!TrellisVcsEngine.isRepo(rootPath)) {
|
|
6507
|
-
console.error(source_default.red("Not a TrellisVCS repository. Run `trellis init` first."));
|
|
6508
|
-
process.exit(1);
|
|
6509
|
-
}
|
|
6527
|
+
const rootPath = resolveRepoRoot(opts.path);
|
|
6510
6528
|
const engine = new TrellisVcsEngine({ rootPath });
|
|
6511
6529
|
engine.open();
|
|
6512
6530
|
const garden = engine.garden();
|
|
@@ -6663,9 +6681,8 @@ function formatCriterionStatus(status) {
|
|
|
6663
6681
|
}
|
|
6664
6682
|
}
|
|
6665
6683
|
var issueCmd = program2.command("issue").description("Manage issues (task tracking)");
|
|
6666
|
-
issueCmd.command("create").description("Create a new issue").requiredOption("-t, --title <title>", "Issue title").option("-P, --priority <priority>", "Priority: critical, high, medium, low", "medium").option("-l, --labels <labels>", "Comma-separated labels").option("--assignee <agentId>", "Agent to assign").option("--parent <id>", "Parent issue ID (for sub-tasks)").option("-d, --desc <description>", "Short description").option("-S, --status <status>", "Initial status: backlog (default) or queue", "backlog").option("--ac <criteria...>", 'Acceptance criteria. Prefix with "test:" for test commands').option("-p, --path <path>", "Repository path", ".").action(async (opts) => {
|
|
6667
|
-
const rootPath =
|
|
6668
|
-
requireRepo(rootPath);
|
|
6684
|
+
issueCmd.command("create").description("Create a new issue").requiredOption("-t, --title <title>", "Issue title").option("-P, --priority <priority>", "Priority: critical, high, medium, low", "medium").option("-l, --labels <labels>", "Comma-separated labels").option("--assignee <agentId>", "Agent to assign").option("--parent <id>", "Parent issue ID (for sub-tasks)").option("-d, --desc <description>", "Short description").option("--description <description>", "Alias for --desc").option("-S, --status <status>", "Initial status: backlog (default) or queue", "backlog").option("--ac <criteria...>", 'Acceptance criteria. Prefix with "test:" for test commands').option("-p, --path <path>", "Repository path", ".").action(async (opts) => {
|
|
6685
|
+
const rootPath = resolveRepoRoot(opts.path);
|
|
6669
6686
|
const engine = new TrellisVcsEngine({ rootPath });
|
|
6670
6687
|
engine.open();
|
|
6671
6688
|
const labels = opts.labels ? opts.labels.split(",").map((l) => l.trim()) : undefined;
|
|
@@ -6680,7 +6697,7 @@ issueCmd.command("create").description("Create a new issue").requiredOption("-t,
|
|
|
6680
6697
|
labels,
|
|
6681
6698
|
assignee: opts.assignee,
|
|
6682
6699
|
parentId: opts.parent,
|
|
6683
|
-
description: opts.desc,
|
|
6700
|
+
description: opts.desc ?? opts.description,
|
|
6684
6701
|
status: opts.status,
|
|
6685
6702
|
criteria
|
|
6686
6703
|
});
|
|
@@ -6699,8 +6716,7 @@ issueCmd.command("create").description("Create a new issue").requiredOption("-t,
|
|
|
6699
6716
|
}
|
|
6700
6717
|
});
|
|
6701
6718
|
issueCmd.command("list").description("List issues").option("--status <status>", "Filter by status: backlog, queue, in_progress, paused, closed").option("--label <label>", "Filter by label").option("--assignee <agentId>", "Filter by assignee").option("--parent <id>", "Filter by parent issue").option("-p, --path <path>", "Repository path", ".").action((opts) => {
|
|
6702
|
-
const rootPath =
|
|
6703
|
-
requireRepo(rootPath);
|
|
6719
|
+
const rootPath = resolveRepoRoot(opts.path);
|
|
6704
6720
|
const engine = new TrellisVcsEngine({ rootPath });
|
|
6705
6721
|
engine.open();
|
|
6706
6722
|
const issues = engine.listIssues({
|
|
@@ -6725,8 +6741,7 @@ issueCmd.command("list").description("List issues").option("--status <status>",
|
|
|
6725
6741
|
}
|
|
6726
6742
|
});
|
|
6727
6743
|
issueCmd.command("show").description("Show issue details").argument("<id>", "Issue ID (e.g. TRL-1)").option("-p, --path <path>", "Repository path", ".").action((id, opts) => {
|
|
6728
|
-
const rootPath =
|
|
6729
|
-
requireRepo(rootPath);
|
|
6744
|
+
const rootPath = resolveRepoRoot(opts.path);
|
|
6730
6745
|
const engine = new TrellisVcsEngine({ rootPath });
|
|
6731
6746
|
engine.open();
|
|
6732
6747
|
const issue = engine.getIssue(id);
|
|
@@ -6780,8 +6795,7 @@ issueCmd.command("show").description("Show issue details").argument("<id>", "Iss
|
|
|
6780
6795
|
}
|
|
6781
6796
|
});
|
|
6782
6797
|
issueCmd.command("start").description("Start working on an issue (creates branch, auto-assigns)").argument("<id>", "Issue ID").option("-p, --path <path>", "Repository path", ".").action(async (id, opts) => {
|
|
6783
|
-
const rootPath =
|
|
6784
|
-
requireRepo(rootPath);
|
|
6798
|
+
const rootPath = resolveRepoRoot(opts.path);
|
|
6785
6799
|
const engine = new TrellisVcsEngine({ rootPath });
|
|
6786
6800
|
engine.open();
|
|
6787
6801
|
const op = await engine.startIssue(id);
|
|
@@ -6795,8 +6809,7 @@ issueCmd.command("start").description("Start working on an issue (creates branch
|
|
|
6795
6809
|
}
|
|
6796
6810
|
});
|
|
6797
6811
|
issueCmd.command("pause").description("Pause an in-progress issue (switches to default branch)").argument("<id>", "Issue ID").requiredOption("-n, --note <note>", "Why paused and what must happen before resuming").option("-p, --path <path>", "Repository path", ".").action(async (id, opts) => {
|
|
6798
|
-
const rootPath =
|
|
6799
|
-
requireRepo(rootPath);
|
|
6812
|
+
const rootPath = resolveRepoRoot(opts.path);
|
|
6800
6813
|
const engine = new TrellisVcsEngine({ rootPath });
|
|
6801
6814
|
engine.open();
|
|
6802
6815
|
await engine.pauseIssue(id, opts.note);
|
|
@@ -6805,8 +6818,7 @@ issueCmd.command("pause").description("Pause an in-progress issue (switches to d
|
|
|
6805
6818
|
console.log(` ${source_default.dim("Switched to:")} ${engine.getCurrentBranch()}`);
|
|
6806
6819
|
});
|
|
6807
6820
|
issueCmd.command("resume").description("Resume a paused issue (switches to issue branch)").argument("<id>", "Issue ID").option("-p, --path <path>", "Repository path", ".").action(async (id, opts) => {
|
|
6808
|
-
const rootPath =
|
|
6809
|
-
requireRepo(rootPath);
|
|
6821
|
+
const rootPath = resolveRepoRoot(opts.path);
|
|
6810
6822
|
const engine = new TrellisVcsEngine({ rootPath });
|
|
6811
6823
|
engine.open();
|
|
6812
6824
|
await engine.resumeIssue(id);
|
|
@@ -6817,23 +6829,22 @@ issueCmd.command("resume").description("Resume a paused issue (switches to issue
|
|
|
6817
6829
|
}
|
|
6818
6830
|
});
|
|
6819
6831
|
issueCmd.command("triage").description("Move a backlog issue to queue (ready to start)").argument("<id>", "Issue ID").option("-p, --path <path>", "Repository path", ".").action(async (id, opts) => {
|
|
6820
|
-
const rootPath =
|
|
6821
|
-
requireRepo(rootPath);
|
|
6832
|
+
const rootPath = resolveRepoRoot(opts.path);
|
|
6822
6833
|
const engine = new TrellisVcsEngine({ rootPath });
|
|
6823
6834
|
engine.open();
|
|
6824
6835
|
await engine.triageIssue(id);
|
|
6825
6836
|
console.log(source_default.green(`\u2713 Triaged ${source_default.bold(id)} \u2192 queue`));
|
|
6826
6837
|
});
|
|
6827
|
-
issueCmd.command("update").description("Update issue metadata").argument("<id>", "Issue ID").option("--title <title>", "New title").option("-d, --desc <description>", "Short description").option("--status <status>", "New status: backlog, queue, in_progress, paused, closed").option("-P, --priority <priority>", "Priority: critical, high, medium, low").option("-l, --labels <labels>", "Comma-separated labels").option("--assignee <agentId>", "Agent to assign").option("-p, --path <path>", "Repository path", ".").action(async (id, opts) => {
|
|
6828
|
-
const rootPath =
|
|
6829
|
-
requireRepo(rootPath);
|
|
6838
|
+
issueCmd.command("update").description("Update issue metadata").argument("<id>", "Issue ID").option("--title <title>", "New title").option("-d, --desc <description>", "Short description").option("--description <description>", "Alias for --desc").option("--status <status>", "New status: backlog, queue, in_progress, paused, closed").option("-P, --priority <priority>", "Priority: critical, high, medium, low").option("-l, --labels <labels>", "Comma-separated labels").option("--assignee <agentId>", "Agent to assign").option("-p, --path <path>", "Repository path", ".").action(async (id, opts) => {
|
|
6839
|
+
const rootPath = resolveRepoRoot(opts.path);
|
|
6830
6840
|
const engine = new TrellisVcsEngine({ rootPath });
|
|
6831
6841
|
engine.open();
|
|
6832
6842
|
const updates = {};
|
|
6833
6843
|
if (opts.title !== undefined)
|
|
6834
6844
|
updates.title = opts.title;
|
|
6835
|
-
|
|
6836
|
-
|
|
6845
|
+
const desc = opts.desc ?? opts.description;
|
|
6846
|
+
if (desc !== undefined)
|
|
6847
|
+
updates.description = desc;
|
|
6837
6848
|
if (opts.status !== undefined)
|
|
6838
6849
|
updates.status = opts.status;
|
|
6839
6850
|
if (opts.priority !== undefined)
|
|
@@ -6847,24 +6858,21 @@ issueCmd.command("update").description("Update issue metadata").argument("<id>",
|
|
|
6847
6858
|
console.log(source_default.green(`\u2713 Updated ${source_default.bold(id)}`));
|
|
6848
6859
|
});
|
|
6849
6860
|
issueCmd.command("describe").description("Set an issue description").argument("<id>", "Issue ID").argument("<description>", "Short description text").option("-p, --path <path>", "Repository path", ".").action(async (id, description, opts) => {
|
|
6850
|
-
const rootPath =
|
|
6851
|
-
requireRepo(rootPath);
|
|
6861
|
+
const rootPath = resolveRepoRoot(opts.path);
|
|
6852
6862
|
const engine = new TrellisVcsEngine({ rootPath });
|
|
6853
6863
|
engine.open();
|
|
6854
6864
|
await engine.updateIssue(id, { description });
|
|
6855
6865
|
console.log(source_default.green(`\u2713 Description set for ${source_default.bold(id)}`));
|
|
6856
6866
|
});
|
|
6857
6867
|
issueCmd.command("assign").description("Assign an issue to an agent").argument("<id>", "Issue ID").requiredOption("--to <agentId>", "Agent ID to assign").option("-p, --path <path>", "Repository path", ".").action(async (id, opts) => {
|
|
6858
|
-
const rootPath =
|
|
6859
|
-
requireRepo(rootPath);
|
|
6868
|
+
const rootPath = resolveRepoRoot(opts.path);
|
|
6860
6869
|
const engine = new TrellisVcsEngine({ rootPath });
|
|
6861
6870
|
engine.open();
|
|
6862
6871
|
await engine.assignIssue(id, opts.to);
|
|
6863
6872
|
console.log(source_default.green(`\u2713 Assigned ${source_default.bold(id)} \u2192 ${opts.to}`));
|
|
6864
6873
|
});
|
|
6865
6874
|
issueCmd.command("ac").description("Add acceptance criterion to an issue").argument("<id>", "Issue ID").argument("<description>", "Criterion description").option("--test <command>", "Shell command to validate (exit 0 = pass)").option("-p, --path <path>", "Repository path", ".").action(async (id, description, opts) => {
|
|
6866
|
-
const rootPath =
|
|
6867
|
-
requireRepo(rootPath);
|
|
6875
|
+
const rootPath = resolveRepoRoot(opts.path);
|
|
6868
6876
|
const engine = new TrellisVcsEngine({ rootPath });
|
|
6869
6877
|
engine.open();
|
|
6870
6878
|
await engine.addCriterion(id, description, opts.test);
|
|
@@ -6872,24 +6880,21 @@ issueCmd.command("ac").description("Add acceptance criterion to an issue").argum
|
|
|
6872
6880
|
console.log(source_default.green(`\u2713 Added criterion to ${source_default.bold(id)}: ${description}${cmdNote}`));
|
|
6873
6881
|
});
|
|
6874
6882
|
issueCmd.command("ac-pass").description("Manually mark an acceptance criterion as passed").argument("<id>", "Issue ID").argument("<index>", "Criterion number (1-based)").option("-p, --path <path>", "Repository path", ".").action(async (id, index, opts) => {
|
|
6875
|
-
const rootPath =
|
|
6876
|
-
requireRepo(rootPath);
|
|
6883
|
+
const rootPath = resolveRepoRoot(opts.path);
|
|
6877
6884
|
const engine = new TrellisVcsEngine({ rootPath });
|
|
6878
6885
|
engine.open();
|
|
6879
6886
|
await engine.setCriterionStatus(id, parseInt(index, 10), "passed");
|
|
6880
6887
|
console.log(source_default.green(`\u2713 Criterion #${index} on ${source_default.bold(id)} marked as passed`));
|
|
6881
6888
|
});
|
|
6882
6889
|
issueCmd.command("ac-fail").description("Manually mark an acceptance criterion as failed").argument("<id>", "Issue ID").argument("<index>", "Criterion number (1-based)").option("-p, --path <path>", "Repository path", ".").action(async (id, index, opts) => {
|
|
6883
|
-
const rootPath =
|
|
6884
|
-
requireRepo(rootPath);
|
|
6890
|
+
const rootPath = resolveRepoRoot(opts.path);
|
|
6885
6891
|
const engine = new TrellisVcsEngine({ rootPath });
|
|
6886
6892
|
engine.open();
|
|
6887
6893
|
await engine.setCriterionStatus(id, parseInt(index, 10), "failed");
|
|
6888
6894
|
console.log(source_default.red(`\u2717 Criterion #${index} on ${source_default.bold(id)} marked as failed`));
|
|
6889
6895
|
});
|
|
6890
6896
|
issueCmd.command("check").description("Run acceptance criteria for an issue").argument("<id>", "Issue ID").option("-p, --path <path>", "Repository path", ".").action(async (id, opts) => {
|
|
6891
|
-
const rootPath =
|
|
6892
|
-
requireRepo(rootPath);
|
|
6897
|
+
const rootPath = resolveRepoRoot(opts.path);
|
|
6893
6898
|
const engine = new TrellisVcsEngine({ rootPath });
|
|
6894
6899
|
engine.open();
|
|
6895
6900
|
console.log(source_default.bold(`Running criteria for ${id}...
|
|
@@ -6924,8 +6929,7 @@ issueCmd.command("check").description("Run acceptance criteria for an issue").ar
|
|
|
6924
6929
|
}
|
|
6925
6930
|
});
|
|
6926
6931
|
issueCmd.command("close").description("Close an issue (requires all criteria pass + --confirm)").argument("<id>", "Issue ID").option("--confirm", "Confirm closure after criteria pass").option("-p, --path <path>", "Repository path", ".").action(async (id, opts) => {
|
|
6927
|
-
const rootPath =
|
|
6928
|
-
requireRepo(rootPath);
|
|
6932
|
+
const rootPath = resolveRepoRoot(opts.path);
|
|
6929
6933
|
const engine = new TrellisVcsEngine({ rootPath });
|
|
6930
6934
|
engine.open();
|
|
6931
6935
|
try {
|
|
@@ -6947,32 +6951,28 @@ issueCmd.command("close").description("Close an issue (requires all criteria pas
|
|
|
6947
6951
|
}
|
|
6948
6952
|
});
|
|
6949
6953
|
issueCmd.command("reopen").description("Reopen a closed issue").argument("<id>", "Issue ID").option("-p, --path <path>", "Repository path", ".").action(async (id, opts) => {
|
|
6950
|
-
const rootPath =
|
|
6951
|
-
requireRepo(rootPath);
|
|
6954
|
+
const rootPath = resolveRepoRoot(opts.path);
|
|
6952
6955
|
const engine = new TrellisVcsEngine({ rootPath });
|
|
6953
6956
|
engine.open();
|
|
6954
6957
|
await engine.reopenIssue(id);
|
|
6955
6958
|
console.log(source_default.green(`\u2713 Issue ${source_default.bold(id)} reopened`));
|
|
6956
6959
|
});
|
|
6957
6960
|
issueCmd.command("block").description("Mark an issue as blocked by another issue").argument("<id>", "Issue ID to block").argument("<blockedBy>", "Issue ID that blocks it").option("-p, --path <path>", "Repository path", ".").action(async (id, blockedBy, opts) => {
|
|
6958
|
-
const rootPath =
|
|
6959
|
-
requireRepo(rootPath);
|
|
6961
|
+
const rootPath = resolveRepoRoot(opts.path);
|
|
6960
6962
|
const engine = new TrellisVcsEngine({ rootPath });
|
|
6961
6963
|
engine.open();
|
|
6962
6964
|
await engine.blockIssue(id, blockedBy);
|
|
6963
6965
|
console.log(source_default.yellow(`\uD83D\uDD12 ${source_default.bold(id)} is now blocked by ${source_default.bold(blockedBy)}`));
|
|
6964
6966
|
});
|
|
6965
6967
|
issueCmd.command("unblock").description("Remove a blocking relationship").argument("<id>", "Blocked issue ID").argument("<blockedBy>", "Blocking issue ID to remove").option("-p, --path <path>", "Repository path", ".").action(async (id, blockedBy, opts) => {
|
|
6966
|
-
const rootPath =
|
|
6967
|
-
requireRepo(rootPath);
|
|
6968
|
+
const rootPath = resolveRepoRoot(opts.path);
|
|
6968
6969
|
const engine = new TrellisVcsEngine({ rootPath });
|
|
6969
6970
|
engine.open();
|
|
6970
6971
|
await engine.unblockIssue(id, blockedBy);
|
|
6971
6972
|
console.log(source_default.green(`\uD83D\uDD13 ${source_default.bold(id)} is no longer blocked by ${source_default.bold(blockedBy)}`));
|
|
6972
6973
|
});
|
|
6973
6974
|
issueCmd.command("active").description("Show all active (in-progress) issues").option("-p, --path <path>", "Repository path", ".").action((opts) => {
|
|
6974
|
-
const rootPath =
|
|
6975
|
-
requireRepo(rootPath);
|
|
6975
|
+
const rootPath = resolveRepoRoot(opts.path);
|
|
6976
6976
|
const engine = new TrellisVcsEngine({ rootPath });
|
|
6977
6977
|
engine.open();
|
|
6978
6978
|
const active = engine.getActiveIssues();
|
|
@@ -6989,8 +6989,7 @@ issueCmd.command("active").description("Show all active (in-progress) issues").o
|
|
|
6989
6989
|
}
|
|
6990
6990
|
});
|
|
6991
6991
|
issueCmd.command("readiness").description("Check if all issues are complete (no queue, paused, or in-progress)").option("-p, --path <path>", "Repository path", ".").action((opts) => {
|
|
6992
|
-
const rootPath =
|
|
6993
|
-
requireRepo(rootPath);
|
|
6992
|
+
const rootPath = resolveRepoRoot(opts.path);
|
|
6994
6993
|
const engine = new TrellisVcsEngine({ rootPath });
|
|
6995
6994
|
engine.open();
|
|
6996
6995
|
const result = engine.checkCompletionReadiness();
|
|
@@ -7001,8 +7000,7 @@ issueCmd.command("readiness").description("Check if all issues are complete (no
|
|
|
7001
7000
|
});
|
|
7002
7001
|
var decisionCmd = program2.command("decision").description("Manage decision traces");
|
|
7003
7002
|
decisionCmd.command("list").description("List decision traces").option("-p, --path <path>", "Repository path", ".").option("-t, --tool <pattern>", 'Filter by tool name pattern (e.g. "trellis_issue_*")').option("-e, --entity <id>", "Filter by related entity ID").option("-n, --limit <n>", "Max results", "20").action((opts) => {
|
|
7004
|
-
const rootPath =
|
|
7005
|
-
requireRepo(rootPath);
|
|
7003
|
+
const rootPath = resolveRepoRoot(opts.path);
|
|
7006
7004
|
const engine = new TrellisVcsEngine({ rootPath });
|
|
7007
7005
|
engine.open();
|
|
7008
7006
|
const decisions = engine.queryDecisions({
|
|
@@ -7023,8 +7021,7 @@ decisionCmd.command("list").description("List decision traces").option("-p, --pa
|
|
|
7023
7021
|
}
|
|
7024
7022
|
});
|
|
7025
7023
|
decisionCmd.command("show").description("Show full details of a decision trace").argument("<id>", "Decision ID (e.g. DEC-1)").option("-p, --path <path>", "Repository path", ".").action((id, opts) => {
|
|
7026
|
-
const rootPath =
|
|
7027
|
-
requireRepo(rootPath);
|
|
7024
|
+
const rootPath = resolveRepoRoot(opts.path);
|
|
7028
7025
|
const engine = new TrellisVcsEngine({ rootPath });
|
|
7029
7026
|
engine.open();
|
|
7030
7027
|
const d = engine.getDecision(id);
|
|
@@ -7051,8 +7048,7 @@ decisionCmd.command("show").description("Show full details of a decision trace")
|
|
|
7051
7048
|
}
|
|
7052
7049
|
});
|
|
7053
7050
|
decisionCmd.command("chain").description("Trace all decisions that affected a given entity").argument("<entityId>", 'Entity ID (e.g. "issue:TRL-5", "file:src/engine.ts")').option("-p, --path <path>", "Repository path", ".").action((entityId, opts) => {
|
|
7054
|
-
const rootPath =
|
|
7055
|
-
requireRepo(rootPath);
|
|
7051
|
+
const rootPath = resolveRepoRoot(opts.path);
|
|
7056
7052
|
const engine = new TrellisVcsEngine({ rootPath });
|
|
7057
7053
|
engine.open();
|
|
7058
7054
|
const chain = engine.getDecisionChain(entityId);
|
|
@@ -7070,7 +7066,7 @@ decisionCmd.command("chain").description("Trace all decisions that affected a gi
|
|
|
7070
7066
|
}
|
|
7071
7067
|
});
|
|
7072
7068
|
program2.command("identity").description("Manage local identity (Ed25519 key pair)").argument("[action]", '"init" or "show" (default: show)').option("-p, --path <path>", "Repository path", ".").option("--name <name>", "Display name for new identity").option("--email <email>", "Email for new identity").action((action, opts) => {
|
|
7073
|
-
const rootPath =
|
|
7069
|
+
const rootPath = resolve2(opts.path);
|
|
7074
7070
|
const trellisDir = join6(rootPath, ".trellis");
|
|
7075
7071
|
if (action === "init") {
|
|
7076
7072
|
if (hasIdentity(trellisDir)) {
|
|
@@ -7108,14 +7104,10 @@ program2.command("identity").description("Manage local identity (Ed25519 key pai
|
|
|
7108
7104
|
console.log(` ${source_default.dim("Created:")} ${pub.createdAt}`);
|
|
7109
7105
|
});
|
|
7110
7106
|
program2.command("refs").description("List wiki-link references in files or find backlinks").argument("[file]", "File to list outgoing refs for").option("-p, --path <path>", "Repository path", ".").option("--backlinks <entity>", "Show all files referencing an entity (e.g. TRL-5)").option("--broken", "List all broken and stale references").option("--stats", "Show reference index statistics").action((file, opts) => {
|
|
7111
|
-
const rootPath =
|
|
7112
|
-
if (!TrellisVcsEngine.isRepo(rootPath)) {
|
|
7113
|
-
console.error(source_default.red("Not a TrellisVCS repository. Run `trellis init` first."));
|
|
7114
|
-
process.exit(1);
|
|
7115
|
-
}
|
|
7107
|
+
const rootPath = resolveRepoRoot(opts.path);
|
|
7116
7108
|
const engine = new TrellisVcsEngine({ rootPath });
|
|
7117
7109
|
engine.open();
|
|
7118
|
-
const { readFileSync:
|
|
7110
|
+
const { readFileSync: readFileSync5 } = __require("fs");
|
|
7119
7111
|
const {
|
|
7120
7112
|
parseFileRefs,
|
|
7121
7113
|
buildRefIndex: buildRefIndex2,
|
|
@@ -7135,7 +7127,7 @@ program2.command("refs").description("List wiki-link references in files or find
|
|
|
7135
7127
|
for (const f of trackedFiles) {
|
|
7136
7128
|
try {
|
|
7137
7129
|
const absPath = join6(rootPath, f.path);
|
|
7138
|
-
const content =
|
|
7130
|
+
const content = readFileSync5(absPath, "utf-8");
|
|
7139
7131
|
fileContents.push({ path: f.path, content });
|
|
7140
7132
|
} catch {}
|
|
7141
7133
|
}
|
|
@@ -7247,11 +7239,7 @@ program2.command("refs").description("List wiki-link references in files or find
|
|
|
7247
7239
|
}
|
|
7248
7240
|
});
|
|
7249
7241
|
program2.command("search").description("Semantic search across all embedded content").argument("<query>", "Natural language search query").option("-p, --path <path>", "Repository path", ".").option("-l, --limit <n>", "Max results", "10").option("-t, --type <types>", "Filter by chunk type(s), comma-separated (issue_title,issue_desc,milestone_msg,markdown,code_entity,doc_comment,summary_md)").action(async (query, opts) => {
|
|
7250
|
-
const rootPath =
|
|
7251
|
-
if (!TrellisVcsEngine.isRepo(rootPath)) {
|
|
7252
|
-
console.error(source_default.red("Not a TrellisVCS repository. Run `trellis init` first."));
|
|
7253
|
-
process.exit(1);
|
|
7254
|
-
}
|
|
7242
|
+
const rootPath = resolveRepoRoot(opts.path);
|
|
7255
7243
|
const engine = new TrellisVcsEngine({ rootPath });
|
|
7256
7244
|
engine.open();
|
|
7257
7245
|
const { EmbeddingManager } = (init_embeddings(), __toCommonJS(exports_embeddings));
|
|
@@ -7285,11 +7273,7 @@ program2.command("search").description("Semantic search across all embedded cont
|
|
|
7285
7273
|
}
|
|
7286
7274
|
});
|
|
7287
7275
|
program2.command("reindex").description("Rebuild the semantic embedding index").option("-p, --path <path>", "Repository path", ".").action(async (opts) => {
|
|
7288
|
-
const rootPath =
|
|
7289
|
-
if (!TrellisVcsEngine.isRepo(rootPath)) {
|
|
7290
|
-
console.error(source_default.red("Not a TrellisVCS repository. Run `trellis init` first."));
|
|
7291
|
-
process.exit(1);
|
|
7292
|
-
}
|
|
7276
|
+
const rootPath = resolveRepoRoot(opts.path);
|
|
7293
7277
|
const engine = new TrellisVcsEngine({ rootPath });
|
|
7294
7278
|
engine.open();
|
|
7295
7279
|
const { EmbeddingManager } = (init_embeddings(), __toCommonJS(exports_embeddings));
|
|
@@ -7306,11 +7290,7 @@ program2.command("reindex").description("Rebuild the semantic embedding index").
|
|
|
7306
7290
|
}
|
|
7307
7291
|
});
|
|
7308
7292
|
program2.command("ui").description("Launch the interactive graph explorer in your browser").option("-p, --path <path>", "Repository path", ".").option("--port <port>", "Server port", "3333").option("--no-open", "Do not auto-open browser").action(async (opts) => {
|
|
7309
|
-
const rootPath =
|
|
7310
|
-
if (!TrellisVcsEngine.isRepo(rootPath)) {
|
|
7311
|
-
console.error(source_default.red("Not a TrellisVCS repository. Run `trellis init` first."));
|
|
7312
|
-
process.exit(1);
|
|
7313
|
-
}
|
|
7293
|
+
const rootPath = resolveRepoRoot(opts.path);
|
|
7314
7294
|
const { startUIServer: startUIServer2 } = (init_server(), __toCommonJS(exports_server));
|
|
7315
7295
|
const port = parseInt(opts.port, 10) || 3000;
|
|
7316
7296
|
try {
|
|
@@ -7348,8 +7328,7 @@ async function bootKernel(rootPath) {
|
|
|
7348
7328
|
}
|
|
7349
7329
|
var entityCmd = program2.command("entity").description("Manage graph entities (generic CRUD)");
|
|
7350
7330
|
entityCmd.command("create").description("Create a new entity in the graph").requiredOption("-i, --id <id>", 'Entity ID (e.g. "project:my-app")').requiredOption("-t, --type <type>", 'Entity type (e.g. "Project", "User")').option("-a, --attr <attrs...>", "Attributes as key=value pairs").option("-p, --path <path>", "Repository path", ".").action(async (opts) => {
|
|
7351
|
-
const rootPath =
|
|
7352
|
-
requireRepo(rootPath);
|
|
7331
|
+
const rootPath = resolveRepoRoot(opts.path);
|
|
7353
7332
|
const kernel = await bootKernel(rootPath);
|
|
7354
7333
|
try {
|
|
7355
7334
|
const attrs = {};
|
|
@@ -7379,8 +7358,7 @@ entityCmd.command("create").description("Create a new entity in the graph").requ
|
|
|
7379
7358
|
}
|
|
7380
7359
|
});
|
|
7381
7360
|
entityCmd.command("get").description("Get an entity by ID").argument("<id>", "Entity ID").option("-p, --path <path>", "Repository path", ".").option("--json", "Output as JSON").action(async (id, opts) => {
|
|
7382
|
-
const rootPath =
|
|
7383
|
-
requireRepo(rootPath);
|
|
7361
|
+
const rootPath = resolveRepoRoot(opts.path);
|
|
7384
7362
|
const kernel = await bootKernel(rootPath);
|
|
7385
7363
|
try {
|
|
7386
7364
|
const entity = kernel.getEntity(id);
|
|
@@ -7421,8 +7399,7 @@ entityCmd.command("get").description("Get an entity by ID").argument("<id>", "En
|
|
|
7421
7399
|
}
|
|
7422
7400
|
});
|
|
7423
7401
|
entityCmd.command("update").description("Update attributes on an existing entity").argument("<id>", "Entity ID").requiredOption("-a, --attr <attrs...>", "Attributes as key=value pairs").option("-p, --path <path>", "Repository path", ".").action(async (id, opts) => {
|
|
7424
|
-
const rootPath =
|
|
7425
|
-
requireRepo(rootPath);
|
|
7402
|
+
const rootPath = resolveRepoRoot(opts.path);
|
|
7426
7403
|
const kernel = await bootKernel(rootPath);
|
|
7427
7404
|
try {
|
|
7428
7405
|
const updates = {};
|
|
@@ -7450,8 +7427,7 @@ entityCmd.command("update").description("Update attributes on an existing entity
|
|
|
7450
7427
|
}
|
|
7451
7428
|
});
|
|
7452
7429
|
entityCmd.command("delete").description("Delete an entity and all its facts/links").argument("<id>", "Entity ID").option("-p, --path <path>", "Repository path", ".").action(async (id, opts) => {
|
|
7453
|
-
const rootPath =
|
|
7454
|
-
requireRepo(rootPath);
|
|
7430
|
+
const rootPath = resolveRepoRoot(opts.path);
|
|
7455
7431
|
const kernel = await bootKernel(rootPath);
|
|
7456
7432
|
try {
|
|
7457
7433
|
const entity = kernel.getEntity(id);
|
|
@@ -7466,8 +7442,7 @@ entityCmd.command("delete").description("Delete an entity and all its facts/link
|
|
|
7466
7442
|
}
|
|
7467
7443
|
});
|
|
7468
7444
|
entityCmd.command("list").description("List entities, optionally filtered by type").option("-t, --type <type>", "Filter by entity type").option("-f, --filter <filters...>", "Attribute filters as key=value").option("--json", "Output as JSON").option("-p, --path <path>", "Repository path", ".").action(async (opts) => {
|
|
7469
|
-
const rootPath =
|
|
7470
|
-
requireRepo(rootPath);
|
|
7445
|
+
const rootPath = resolveRepoRoot(opts.path);
|
|
7471
7446
|
const kernel = await bootKernel(rootPath);
|
|
7472
7447
|
try {
|
|
7473
7448
|
let filters;
|
|
@@ -7519,8 +7494,7 @@ entityCmd.command("list").description("List entities, optionally filtered by typ
|
|
|
7519
7494
|
});
|
|
7520
7495
|
var factCmd = program2.command("fact").description("Add or remove individual facts on entities");
|
|
7521
7496
|
factCmd.command("add").description("Add a fact to an entity").argument("<entity>", "Entity ID").argument("<attribute>", "Attribute name").argument("<value>", "Value").option("-p, --path <path>", "Repository path", ".").action(async (entity, attribute, value, opts) => {
|
|
7522
|
-
const rootPath =
|
|
7523
|
-
requireRepo(rootPath);
|
|
7497
|
+
const rootPath = resolveRepoRoot(opts.path);
|
|
7524
7498
|
const kernel = await bootKernel(rootPath);
|
|
7525
7499
|
try {
|
|
7526
7500
|
let val = value;
|
|
@@ -7537,8 +7511,7 @@ factCmd.command("add").description("Add a fact to an entity").argument("<entity>
|
|
|
7537
7511
|
}
|
|
7538
7512
|
});
|
|
7539
7513
|
factCmd.command("remove").description("Remove a fact from an entity").argument("<entity>", "Entity ID").argument("<attribute>", "Attribute name").argument("<value>", "Value to remove").option("-p, --path <path>", "Repository path", ".").action(async (entity, attribute, value, opts) => {
|
|
7540
|
-
const rootPath =
|
|
7541
|
-
requireRepo(rootPath);
|
|
7514
|
+
const rootPath = resolveRepoRoot(opts.path);
|
|
7542
7515
|
const kernel = await bootKernel(rootPath);
|
|
7543
7516
|
try {
|
|
7544
7517
|
let val = value;
|
|
@@ -7555,8 +7528,7 @@ factCmd.command("remove").description("Remove a fact from an entity").argument("
|
|
|
7555
7528
|
}
|
|
7556
7529
|
});
|
|
7557
7530
|
factCmd.command("query").description("Query facts by entity or attribute").option("-e, --entity <id>", "Filter by entity ID").option("-a, --attribute <attr>", "Filter by attribute").option("--json", "Output as JSON").option("-p, --path <path>", "Repository path", ".").action(async (opts) => {
|
|
7558
|
-
const rootPath =
|
|
7559
|
-
requireRepo(rootPath);
|
|
7531
|
+
const rootPath = resolveRepoRoot(opts.path);
|
|
7560
7532
|
const kernel = await bootKernel(rootPath);
|
|
7561
7533
|
try {
|
|
7562
7534
|
const store = kernel.getStore();
|
|
@@ -7590,8 +7562,7 @@ factCmd.command("query").description("Query facts by entity or attribute").optio
|
|
|
7590
7562
|
});
|
|
7591
7563
|
var linkCmd = program2.command("link").description("Add or remove links between entities");
|
|
7592
7564
|
linkCmd.command("add").description("Add a link between two entities").argument("<source>", "Source entity ID").argument("<attribute>", "Relationship attribute").argument("<target>", "Target entity ID").option("-p, --path <path>", "Repository path", ".").action(async (source, attribute, target, opts) => {
|
|
7593
|
-
const rootPath =
|
|
7594
|
-
requireRepo(rootPath);
|
|
7565
|
+
const rootPath = resolveRepoRoot(opts.path);
|
|
7595
7566
|
const kernel = await bootKernel(rootPath);
|
|
7596
7567
|
try {
|
|
7597
7568
|
await kernel.addLink(source, attribute, target);
|
|
@@ -7601,8 +7572,7 @@ linkCmd.command("add").description("Add a link between two entities").argument("
|
|
|
7601
7572
|
}
|
|
7602
7573
|
});
|
|
7603
7574
|
linkCmd.command("remove").description("Remove a link between two entities").argument("<source>", "Source entity ID").argument("<attribute>", "Relationship attribute").argument("<target>", "Target entity ID").option("-p, --path <path>", "Repository path", ".").action(async (source, attribute, target, opts) => {
|
|
7604
|
-
const rootPath =
|
|
7605
|
-
requireRepo(rootPath);
|
|
7575
|
+
const rootPath = resolveRepoRoot(opts.path);
|
|
7606
7576
|
const kernel = await bootKernel(rootPath);
|
|
7607
7577
|
try {
|
|
7608
7578
|
await kernel.removeLink(source, attribute, target);
|
|
@@ -7612,8 +7582,7 @@ linkCmd.command("remove").description("Remove a link between two entities").argu
|
|
|
7612
7582
|
}
|
|
7613
7583
|
});
|
|
7614
7584
|
linkCmd.command("query").description("Query links for an entity").option("-e, --entity <id>", "Entity ID").option("-a, --attribute <attr>", "Relationship attribute").option("--json", "Output as JSON").option("-p, --path <path>", "Repository path", ".").action(async (opts) => {
|
|
7615
|
-
const rootPath =
|
|
7616
|
-
requireRepo(rootPath);
|
|
7585
|
+
const rootPath = resolveRepoRoot(opts.path);
|
|
7617
7586
|
const kernel = await bootKernel(rootPath);
|
|
7618
7587
|
try {
|
|
7619
7588
|
const store = kernel.getStore();
|
|
@@ -7648,8 +7617,7 @@ linkCmd.command("query").description("Query links for an entity").option("-e, --
|
|
|
7648
7617
|
}
|
|
7649
7618
|
});
|
|
7650
7619
|
program2.command("query").description("Execute an EQL-S query against the graph").argument("<query>", 'EQL-S query string (or "find ?e where attr = value" shorthand)').option("-p, --path <path>", "Repository path", ".").option("--json", "Output as JSON").action(async (queryStr, opts) => {
|
|
7651
|
-
const rootPath =
|
|
7652
|
-
requireRepo(rootPath);
|
|
7620
|
+
const rootPath = resolveRepoRoot(opts.path);
|
|
7653
7621
|
const kernel = await bootKernel(rootPath);
|
|
7654
7622
|
try {
|
|
7655
7623
|
const store = kernel.getStore();
|
|
@@ -7688,8 +7656,7 @@ ${result.count} result(s) in ${result.executionTime.toFixed(1)}ms`));
|
|
|
7688
7656
|
}
|
|
7689
7657
|
});
|
|
7690
7658
|
program2.command("repl").description("Interactive EQL-S query shell").option("-p, --path <path>", "Repository path", ".").action(async (opts) => {
|
|
7691
|
-
const rootPath =
|
|
7692
|
-
requireRepo(rootPath);
|
|
7659
|
+
const rootPath = resolveRepoRoot(opts.path);
|
|
7693
7660
|
const kernel = await bootKernel(rootPath);
|
|
7694
7661
|
const store = kernel.getStore();
|
|
7695
7662
|
const engine = new QueryEngine(store);
|
|
@@ -7867,8 +7834,7 @@ Relations:`));
|
|
|
7867
7834
|
console.log(source_default.dim("Available types: " + registry.listEntityTypes().join(", ")));
|
|
7868
7835
|
});
|
|
7869
7836
|
ontologyCmd.command("validate").description("Validate all entities in the graph against registered ontologies").option("-p, --path <path>", "Repository path", ".").option("--strict", "Treat unknown types as errors").action(async (opts) => {
|
|
7870
|
-
const rootPath =
|
|
7871
|
-
requireRepo(rootPath);
|
|
7837
|
+
const rootPath = resolveRepoRoot(opts.path);
|
|
7872
7838
|
const kernel = await bootKernel(rootPath);
|
|
7873
7839
|
try {
|
|
7874
7840
|
const registry = new OntologyRegistry;
|
|
@@ -7905,8 +7871,7 @@ ontologyCmd.command("validate").description("Validate all entities in the graph
|
|
|
7905
7871
|
}
|
|
7906
7872
|
});
|
|
7907
7873
|
program2.command("ask").description("Natural language search over the graph (semantic search)").argument("<question>", "Natural language query").option("-p, --path <path>", "Repository path", ".").option("-n, --limit <n>", "Max results", "5").option("--json", "Output as JSON").option("--rag", "Output as RAG context (for LLM consumption)").action(async (question, opts) => {
|
|
7908
|
-
const rootPath =
|
|
7909
|
-
requireRepo(rootPath);
|
|
7874
|
+
const rootPath = resolveRepoRoot(opts.path);
|
|
7910
7875
|
const dbPath = join6(rootPath, ".trellis", "embeddings.db");
|
|
7911
7876
|
const vectorStore = new VectorStore(dbPath);
|
|
7912
7877
|
try {
|
|
@@ -7995,12 +7960,12 @@ function formatRelativeTime(iso) {
|
|
|
7995
7960
|
var db = program2.command("db").description("Trellis DB \u2014 use Trellis as an application database");
|
|
7996
7961
|
db.command("init").description("Initialize a new Trellis DB in the current directory").option("-p, --path <path>", "Database directory", ".trellis-db").option("--port <port>", "Server port", "3000").option("--key <key>", "API key (auto-generated if omitted)").option("--jwt-secret <secret>", "JWT secret (auto-generated if omitted)").option("--multi-tenant", "Enable multi-tenancy (separate SQLite per tenant)").action(async (opts) => {
|
|
7997
7962
|
const { writeConfig, defaultLocalConfig, hasConfig, configPath } = await import("../config-8hczw0rs.js");
|
|
7998
|
-
const { resolve:
|
|
7963
|
+
const { resolve: resolve3 } = await import("path");
|
|
7999
7964
|
if (hasConfig(".")) {
|
|
8000
7965
|
console.log(source_default.yellow(`Already initialized (${configPath(".")}). Use \`trellis db serve\` to start.`));
|
|
8001
7966
|
return;
|
|
8002
7967
|
}
|
|
8003
|
-
const dbPath =
|
|
7968
|
+
const dbPath = resolve3(opts.path);
|
|
8004
7969
|
const apiKey = opts.key ?? `spk_${crypto.randomUUID().replace(/-/g, "")}`;
|
|
8005
7970
|
const jwtSecret = opts.jwtSecret ?? `jws_${crypto.randomUUID().replace(/-/g, "")}`;
|
|
8006
7971
|
writeConfig(defaultLocalConfig(dbPath, {
|
|
@@ -8048,8 +8013,8 @@ db.command("create <type> [json]").description("Create an entity (json can be a
|
|
|
8048
8013
|
const db2 = TrellisDb.fromConfig(opts.configDir);
|
|
8049
8014
|
let attributes = {};
|
|
8050
8015
|
if (jsonArg) {
|
|
8051
|
-
const { readFileSync:
|
|
8052
|
-
const raw = jsonArg.startsWith("@") ?
|
|
8016
|
+
const { readFileSync: readFileSync5 } = await import("fs");
|
|
8017
|
+
const raw = jsonArg.startsWith("@") ? readFileSync5(jsonArg.slice(1), "utf8") : jsonArg;
|
|
8053
8018
|
attributes = JSON.parse(raw);
|
|
8054
8019
|
}
|
|
8055
8020
|
const id = await db2.create(type, attributes);
|
|
@@ -8070,8 +8035,8 @@ db.command("read <id>").description("Read an entity by ID").option("--config-dir
|
|
|
8070
8035
|
db.command("update <id> <json>").description("Update entity attributes (JSON string or @file.json)").option("--config-dir <dir>", "Config directory", ".").action(async (id, jsonArg, opts) => {
|
|
8071
8036
|
const { TrellisDb } = await import("../sdk-bepky0xs.js");
|
|
8072
8037
|
const db2 = TrellisDb.fromConfig(opts.configDir);
|
|
8073
|
-
const { readFileSync:
|
|
8074
|
-
const raw = jsonArg.startsWith("@") ?
|
|
8038
|
+
const { readFileSync: readFileSync5 } = await import("fs");
|
|
8039
|
+
const raw = jsonArg.startsWith("@") ? readFileSync5(jsonArg.slice(1), "utf8") : jsonArg;
|
|
8075
8040
|
await db2.update(id, JSON.parse(raw));
|
|
8076
8041
|
console.log(source_default.green(`\u2713 Updated: ${source_default.bold(id)}`));
|
|
8077
8042
|
db2.close();
|
|
@@ -8102,7 +8067,7 @@ db.command("query <eql>").description("Run an EQL-S query").option("--config-dir
|
|
|
8102
8067
|
db2.close();
|
|
8103
8068
|
});
|
|
8104
8069
|
db.command("upload <file>").description("Upload a file to the blob store").option("--config-dir <dir>", "Config directory", ".").option("--type <mime>", "MIME type (auto-detected if omitted)").action(async (filePath, opts) => {
|
|
8105
|
-
const { readFileSync:
|
|
8070
|
+
const { readFileSync: readFileSync5 } = await import("fs");
|
|
8106
8071
|
const { extname } = await import("path");
|
|
8107
8072
|
const { TrellisDb } = await import("../sdk-bepky0xs.js");
|
|
8108
8073
|
const mimeMap = {
|
|
@@ -8115,7 +8080,7 @@ db.command("upload <file>").description("Upload a file to the blob store").optio
|
|
|
8115
8080
|
".txt": "text/plain"
|
|
8116
8081
|
};
|
|
8117
8082
|
const contentType = opts.type ?? mimeMap[extname(filePath).toLowerCase()] ?? "application/octet-stream";
|
|
8118
|
-
const buffer =
|
|
8083
|
+
const buffer = readFileSync5(filePath);
|
|
8119
8084
|
const db2 = TrellisDb.fromConfig(opts.configDir);
|
|
8120
8085
|
const result = await db2.upload(new Uint8Array(buffer), contentType);
|
|
8121
8086
|
console.log(source_default.green(`\u2713 Uploaded`));
|
|
@@ -8266,10 +8231,10 @@ vmProgram.command("destroy <name>").description("Destroy a Sprite").action(async
|
|
|
8266
8231
|
input: process.stdin,
|
|
8267
8232
|
output: process.stdout
|
|
8268
8233
|
});
|
|
8269
|
-
const answer = await new Promise((
|
|
8234
|
+
const answer = await new Promise((resolve3) => {
|
|
8270
8235
|
rl.question(`Destroy Sprite "${name}"? Cannot be undone. (y/N) `, (a) => {
|
|
8271
8236
|
rl.close();
|
|
8272
|
-
|
|
8237
|
+
resolve3(a.trim().toLowerCase());
|
|
8273
8238
|
});
|
|
8274
8239
|
});
|
|
8275
8240
|
if (answer !== "y" && answer !== "yes") {
|
|
@@ -8532,8 +8497,7 @@ vmProgram.command("code [name]").description("Create Sprite, deploy Trellis, ope
|
|
|
8532
8497
|
});
|
|
8533
8498
|
program2.addCommand(vmProgram);
|
|
8534
8499
|
program2.command("season").description("Enrich project context for agents \u2014 interactive Q&A").option("-p, --path <path>", "Repository path", ".").option("--reset", "Re-run even if previously configured").action(async (opts) => {
|
|
8535
|
-
const rootPath =
|
|
8536
|
-
requireRepo(rootPath);
|
|
8500
|
+
const rootPath = resolveRepoRoot(opts.path);
|
|
8537
8501
|
const { createInterface: createInterface2 } = await import("readline");
|
|
8538
8502
|
const rl = createInterface2({
|
|
8539
8503
|
input: process.stdin,
|
|
@@ -8561,8 +8525,8 @@ program2.command("season").description("Enrich project context for agents \u2014
|
|
|
8561
8525
|
writeAgentScaffold(rootPath, { profile, context: updatedContext });
|
|
8562
8526
|
const agentContextPath = join6(rootPath, ".trellis", "agents", "agent-context.json");
|
|
8563
8527
|
try {
|
|
8564
|
-
const { readFileSync:
|
|
8565
|
-
const existing = JSON.parse(
|
|
8528
|
+
const { readFileSync: readFileSync5, writeFileSync: writeFileSync3 } = await import("fs");
|
|
8529
|
+
const existing = JSON.parse(readFileSync5(agentContextPath, "utf-8"));
|
|
8566
8530
|
existing.domain = updatedContext.domain;
|
|
8567
8531
|
if (toolsRaw) {
|
|
8568
8532
|
existing.tools = toolsRaw.split(",").map((s) => s.trim()).filter(Boolean);
|
|
@@ -8584,12 +8548,12 @@ program2.command("season").description("Enrich project context for agents \u2014
|
|
|
8584
8548
|
console.log();
|
|
8585
8549
|
});
|
|
8586
8550
|
program2.command("code").alias("ide").description('Launch OpenCode in "Harness" mode, bridged to this Trellis repository').option("-p, --path <path>", "Repository path", ".").option("-m, --model <model>", "OpenCode model to use").option("-w, --web", "Launch MCP server in HTTP mode for web client access").option("--mcp-port <port>", "MCP HTTP server port (default: 3333)", "3333").option("--no-init", "Skip initialization even if not a Trellis workspace").action(async (opts) => {
|
|
8587
|
-
const { resolve:
|
|
8551
|
+
const { resolve: resolve3, dirname: dirname7, join: join7 } = await import("path");
|
|
8588
8552
|
const { existsSync: existsSync6 } = await import("fs");
|
|
8589
8553
|
const { spawn } = await import("child_process");
|
|
8590
|
-
const { readFileSync:
|
|
8554
|
+
const { readFileSync: readFileSync5 } = await import("fs");
|
|
8591
8555
|
const { createServer: createHttpServer } = await import("http");
|
|
8592
|
-
const rootPath =
|
|
8556
|
+
const rootPath = findRepoRoot(opts.path) ?? resolve3(opts.path);
|
|
8593
8557
|
if (!opts.noInit) {
|
|
8594
8558
|
if (!TrellisVcsEngine.isRepo(rootPath)) {
|
|
8595
8559
|
console.log(source_default.dim("Not a Trellis workspace \u2014 initializing\u2026"));
|
|
@@ -8600,17 +8564,17 @@ program2.command("code").alias("ide").description('Launch OpenCode in "Harness"
|
|
|
8600
8564
|
}
|
|
8601
8565
|
}
|
|
8602
8566
|
function findOpencode() {
|
|
8603
|
-
const
|
|
8567
|
+
const here2 = dirname7(process.argv[1]);
|
|
8604
8568
|
const candidates = [
|
|
8605
|
-
join7(
|
|
8606
|
-
join7(
|
|
8569
|
+
join7(here2, "..", "node_modules", ".bin", "opencode"),
|
|
8570
|
+
join7(here2, "..", "..", "node_modules", ".bin", "opencode")
|
|
8607
8571
|
];
|
|
8608
|
-
let dir =
|
|
8572
|
+
let dir = here2;
|
|
8609
8573
|
for (let i = 0;i < 5; i++) {
|
|
8610
8574
|
const p = join7(dir, "node_modules", ".bin", "opencode");
|
|
8611
8575
|
if (existsSync6(p))
|
|
8612
8576
|
return p;
|
|
8613
|
-
dir =
|
|
8577
|
+
dir = dirname7(dir);
|
|
8614
8578
|
}
|
|
8615
8579
|
for (const p of candidates) {
|
|
8616
8580
|
if (existsSync6(p))
|
|
@@ -8619,14 +8583,14 @@ program2.command("code").alias("ide").description('Launch OpenCode in "Harness"
|
|
|
8619
8583
|
return null;
|
|
8620
8584
|
}
|
|
8621
8585
|
function findMcpServer() {
|
|
8622
|
-
const
|
|
8586
|
+
const here2 = dirname7(process.argv[1]);
|
|
8623
8587
|
const candidates = [
|
|
8624
|
-
join7(
|
|
8625
|
-
join7(
|
|
8626
|
-
join7(
|
|
8627
|
-
join7(
|
|
8628
|
-
join7(
|
|
8629
|
-
join7(
|
|
8588
|
+
join7(here2, "..", "..", "src", "mcp", "index.ts"),
|
|
8589
|
+
join7(here2, "..", "src", "mcp", "index.ts"),
|
|
8590
|
+
join7(here2, "..", "..", "..", "src", "mcp", "index.ts"),
|
|
8591
|
+
join7(here2, "..", "mcp", "index.js"),
|
|
8592
|
+
join7(here2, "..", "mcp", "index.ts"),
|
|
8593
|
+
join7(here2, "mcp", "index.ts")
|
|
8630
8594
|
];
|
|
8631
8595
|
for (const p of candidates) {
|
|
8632
8596
|
if (existsSync6(p))
|
|
@@ -8657,7 +8621,16 @@ program2.command("code").alias("ide").description('Launch OpenCode in "Harness"
|
|
|
8657
8621
|
let mcpProcess = null;
|
|
8658
8622
|
if (opts.web) {
|
|
8659
8623
|
console.log(source_default.dim(` Starting MCP server on port ${mcpPort}\u2026`));
|
|
8660
|
-
mcpProcess = spawn("bun", [
|
|
8624
|
+
mcpProcess = spawn("bun", [
|
|
8625
|
+
"run",
|
|
8626
|
+
mcp,
|
|
8627
|
+
"--quiet",
|
|
8628
|
+
"--path",
|
|
8629
|
+
rootPath,
|
|
8630
|
+
"--http",
|
|
8631
|
+
"--port",
|
|
8632
|
+
String(mcpPort)
|
|
8633
|
+
], {
|
|
8661
8634
|
stdio: ["pipe", "pipe", "pipe"],
|
|
8662
8635
|
detached: false
|
|
8663
8636
|
});
|
|
@@ -8723,12 +8696,12 @@ program2.command("code").alias("ide").description('Launch OpenCode in "Harness"
|
|
|
8723
8696
|
});
|
|
8724
8697
|
});
|
|
8725
8698
|
program2.command("studio").alias("web").description("Launch Trellis Studio in your browser, bridged to this repo").option("-p, --path <path>", "Repository path", ".").option("--port <port>", "Studio HTTP port (defaults to turtlecode default)").option("--new", "Open the new-project prompt instead of the current directory").option("--no-open", "Do not auto-open the browser").option("--no-init", "Skip initialization even if not a Trellis workspace").option("--quiet-backend", "Suppress backend stdout/stderr").allowUnknownOption(true).action(async (opts, command) => {
|
|
8726
|
-
const { resolve:
|
|
8727
|
-
const { existsSync: existsSync6, readFileSync:
|
|
8699
|
+
const { resolve: resolve3 } = await import("path");
|
|
8700
|
+
const { existsSync: existsSync6, readFileSync: readFileSync5 } = await import("fs");
|
|
8728
8701
|
const { spawn } = await import("child_process");
|
|
8729
8702
|
const { createRequire } = await import("module");
|
|
8730
8703
|
const path = await import("path");
|
|
8731
|
-
const rootPath =
|
|
8704
|
+
const rootPath = findRepoRoot(opts.path) ?? resolve3(opts.path);
|
|
8732
8705
|
if (!opts.noInit) {
|
|
8733
8706
|
if (!TrellisVcsEngine.isRepo(rootPath)) {
|
|
8734
8707
|
console.log(source_default.dim("Not a Trellis workspace \u2014 initializing\u2026"));
|
|
@@ -8740,7 +8713,7 @@ program2.command("studio").alias("web").description("Launch Trellis Studio in yo
|
|
|
8740
8713
|
let turtlecodeBin = null;
|
|
8741
8714
|
try {
|
|
8742
8715
|
const pkgPath = requireFn.resolve("turtlecode/package.json");
|
|
8743
|
-
const pkg = JSON.parse(
|
|
8716
|
+
const pkg = JSON.parse(readFileSync5(pkgPath, "utf-8"));
|
|
8744
8717
|
const binRel = typeof pkg.bin === "string" ? pkg.bin : pkg.bin?.turtlecode;
|
|
8745
8718
|
if (binRel) {
|
|
8746
8719
|
const candidate = path.join(path.dirname(pkgPath), binRel);
|
|
@@ -8792,10 +8765,10 @@ async function waitForMcpReady(url, timeoutMs) {
|
|
|
8792
8765
|
const { get } = await import("http");
|
|
8793
8766
|
const start = Date.now();
|
|
8794
8767
|
while (Date.now() - start < timeoutMs) {
|
|
8795
|
-
await new Promise((
|
|
8768
|
+
await new Promise((resolve3) => setTimeout(resolve3, 500));
|
|
8796
8769
|
try {
|
|
8797
|
-
const res = await new Promise((
|
|
8798
|
-
const req = get(`${url}/health`,
|
|
8770
|
+
const res = await new Promise((resolve3, reject) => {
|
|
8771
|
+
const req = get(`${url}/health`, resolve3);
|
|
8799
8772
|
req.on("error", reject);
|
|
8800
8773
|
req.setTimeout(2000);
|
|
8801
8774
|
});
|
|
@@ -8806,4 +8779,100 @@ async function waitForMcpReady(url, timeoutMs) {
|
|
|
8806
8779
|
}
|
|
8807
8780
|
return false;
|
|
8808
8781
|
}
|
|
8782
|
+
var cmsCmd = program2.command("cms").description("Manage CMS entities (collections, libraries, schemas)");
|
|
8783
|
+
cmsCmd.command("register-library <pkg>").description("Register a Svelte 5 component library as DesignComponent entities. The package must ship dist/components.json (see @turtle.tech/ui for the format).").option("-p, --path <path>", "Repository path", ".").option("--url <url>", "Trellis server URL", "http://localhost:4096").option("--dry-run", "Print the facts that would be asserted without contacting the server").action(async (pkg, opts) => {
|
|
8784
|
+
const rootPath = resolveRepoRoot(opts.path);
|
|
8785
|
+
const { readFileSync: readFileSync5, existsSync: existsSync6 } = await import("fs");
|
|
8786
|
+
const manifestPath = join6(rootPath, "node_modules", pkg, "dist", "components.json");
|
|
8787
|
+
if (!existsSync6(manifestPath)) {
|
|
8788
|
+
console.error(source_default.red(`\u2717 No manifest at ${manifestPath}`));
|
|
8789
|
+
console.error(source_default.dim(` Install ${pkg} in this repo and ensure it ships dist/components.json.`));
|
|
8790
|
+
process.exit(1);
|
|
8791
|
+
}
|
|
8792
|
+
let manifest;
|
|
8793
|
+
try {
|
|
8794
|
+
manifest = JSON.parse(readFileSync5(manifestPath, "utf8"));
|
|
8795
|
+
} catch (err) {
|
|
8796
|
+
console.error(source_default.red(`\u2717 Manifest is not valid JSON: ${manifestPath}`));
|
|
8797
|
+
console.error(source_default.dim(` ${err?.message ?? String(err)}`));
|
|
8798
|
+
process.exit(1);
|
|
8799
|
+
}
|
|
8800
|
+
const { package: pkgName, version, components } = manifest;
|
|
8801
|
+
if (!Array.isArray(components) || components.length === 0) {
|
|
8802
|
+
console.error(source_default.yellow(`\u26A0 Manifest is empty: ${manifestPath}`));
|
|
8803
|
+
process.exit(1);
|
|
8804
|
+
}
|
|
8805
|
+
const pkgSlug = pkgName.replace(/^@/, "").replace(/\//g, "__");
|
|
8806
|
+
const now = new Date().toISOString();
|
|
8807
|
+
const facts = [];
|
|
8808
|
+
for (const comp of components) {
|
|
8809
|
+
const id = `design:component:${pkgSlug}:${comp.slug}`;
|
|
8810
|
+
facts.push({ e: id, a: "type", v: "DesignComponent" }, { e: id, a: "label", v: comp.component }, { e: id, a: "package", v: pkgName }, { e: id, a: "packageVersion", v: version }, { e: id, a: "slug", v: comp.slug }, { e: id, a: "source", v: comp.source ?? "" }, { e: id, a: "editable", v: JSON.stringify(comp.editable ?? []) }, { e: id, a: "createdAt", v: now });
|
|
8811
|
+
}
|
|
8812
|
+
if (opts.dryRun) {
|
|
8813
|
+
console.log(source_default.dim("\u2500\u2500 Dry run: would assert these facts \u2500\u2500"));
|
|
8814
|
+
console.log(JSON.stringify(facts, null, 2));
|
|
8815
|
+
console.log(source_default.dim(`\u2500\u2500 ${facts.length} facts across ${components.length} components \u2500\u2500`));
|
|
8816
|
+
return;
|
|
8817
|
+
}
|
|
8818
|
+
const url = new URL("/trellis/store/assert", opts.url);
|
|
8819
|
+
url.searchParams.set("directory", rootPath);
|
|
8820
|
+
const meta = {
|
|
8821
|
+
actor: "cli:trellis",
|
|
8822
|
+
actorKind: "user",
|
|
8823
|
+
source: "trellis-cms-register-library",
|
|
8824
|
+
relatedEntities: [...new Set(facts.map((f) => f.e))]
|
|
8825
|
+
};
|
|
8826
|
+
try {
|
|
8827
|
+
const res = await fetch(url.toString(), {
|
|
8828
|
+
method: "POST",
|
|
8829
|
+
headers: { "Content-Type": "application/json" },
|
|
8830
|
+
body: JSON.stringify({ facts, meta })
|
|
8831
|
+
});
|
|
8832
|
+
if (!res.ok) {
|
|
8833
|
+
const body2 = await res.text().catch(() => "");
|
|
8834
|
+
console.error(source_default.red(`\u2717 Assert failed: HTTP ${res.status}`));
|
|
8835
|
+
if (body2)
|
|
8836
|
+
console.error(source_default.dim(` ${body2.slice(0, 400)}`));
|
|
8837
|
+
process.exit(1);
|
|
8838
|
+
}
|
|
8839
|
+
const body = await res.json().catch(() => ({ added: 0 }));
|
|
8840
|
+
console.log(source_default.green(`\u2713 Registered ${source_default.bold(String(components.length))} components from ${source_default.bold(pkgName)}@${version}`));
|
|
8841
|
+
console.log(` ${source_default.dim("Facts added:")} ${body.added ?? "?"}`);
|
|
8842
|
+
console.log(` ${source_default.dim("Workspace:")} ${rootPath}`);
|
|
8843
|
+
for (const comp of components) {
|
|
8844
|
+
console.log(` ${source_default.dim("\u2022")} ${comp.component} ${source_default.dim(`(design:component:${pkgSlug}:${comp.slug})`)}`);
|
|
8845
|
+
}
|
|
8846
|
+
} catch (err) {
|
|
8847
|
+
const msg = err?.message ?? String(err);
|
|
8848
|
+
console.error(source_default.red(`\u2717 Could not reach Trellis server at ${opts.url}`));
|
|
8849
|
+
console.error(source_default.dim(` ${msg}`));
|
|
8850
|
+
console.error(source_default.dim(` Hint: start the Trellis backend (e.g. open the turtlecode IDE) and retry.`));
|
|
8851
|
+
process.exit(1);
|
|
8852
|
+
}
|
|
8853
|
+
});
|
|
8854
|
+
program2.command("skills").description("Install Trellis agent skills using the skills CLI (npx skills)").argument("[args...]", "Additional arguments to pass to the skills CLI").allowUnknownOption().action(async () => {
|
|
8855
|
+
const skillsIndex = process.argv.indexOf("skills");
|
|
8856
|
+
const extraArgs = skillsIndex !== -1 ? process.argv.slice(skillsIndex + 1) : [];
|
|
8857
|
+
const { spawnSync } = await import("child_process");
|
|
8858
|
+
const skillsArgs = ["skills", "add", "trentbrew/trellis", ...extraArgs];
|
|
8859
|
+
console.log(source_default.cyan(" Installing Trellis agent skills..."));
|
|
8860
|
+
console.log(source_default.dim(` Running: npx ${skillsArgs.join(" ")}
|
|
8861
|
+
`));
|
|
8862
|
+
if (process.env.TRELLIS_CLI_DRY_RUN === "1") {
|
|
8863
|
+
return;
|
|
8864
|
+
}
|
|
8865
|
+
const result = spawnSync("npx", skillsArgs, {
|
|
8866
|
+
stdio: "inherit",
|
|
8867
|
+
shell: true
|
|
8868
|
+
});
|
|
8869
|
+
if (result.error) {
|
|
8870
|
+
console.error(source_default.red(`
|
|
8871
|
+
\u2717 Failed to run skills CLI: ${result.error.message}`));
|
|
8872
|
+
process.exit(1);
|
|
8873
|
+
}
|
|
8874
|
+
if (result.status !== 0) {
|
|
8875
|
+
process.exit(result.status ?? 1);
|
|
8876
|
+
}
|
|
8877
|
+
});
|
|
8809
8878
|
program2.parse();
|