@ulpi/cli 0.1.3 → 0.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/dist/{auth-KQCJ43U2.js → auth-BFFBUJUC.js} +1 -1
  2. package/dist/{chunk-YM2HV4IA.js → chunk-26LLDX2T.js} +50 -2
  3. package/dist/{chunk-QJ5GSMEC.js → chunk-5SCG7UYM.js} +2 -1
  4. package/dist/{chunk-5J6NLQUN.js → chunk-6OURRFP7.js} +8 -8
  5. package/dist/chunk-AV5RB3N2.js +173 -0
  6. package/dist/{chunk-7LXY5UVC.js → chunk-DDRLI6JU.js} +2 -1
  7. package/dist/{chunk-ZLYRPD7I.js → chunk-DOIKS6C5.js} +1 -1
  8. package/dist/{chunk-SPOI23SB.js → chunk-EIWYSP3A.js} +1 -1
  9. package/dist/{chunk-7AL4DOEJ.js → chunk-ELTGWMDE.js} +3 -3
  10. package/dist/{chunk-6OCEY7JY.js → chunk-IFATANHR.js} +34 -3
  11. package/dist/{chunk-2HEE5OKX.js → chunk-K4OVPFY2.js} +1 -1
  12. package/dist/{chunk-JGBXM5NC.js → chunk-L3PWNHSA.js} +2 -2
  13. package/dist/{chunk-2VYFVYJL.js → chunk-LD52XG3X.js} +24 -24
  14. package/dist/{chunk-F7OXF7Z3.js → chunk-P2RESJRN.js} +2 -2
  15. package/dist/{chunk-3SBPZRB5.js → chunk-RJIRWQJD.js} +1 -1
  16. package/dist/{chunk-2CLNOKPA.js → chunk-RSFJ6QSR.js} +18 -0
  17. package/dist/{chunk-PDR55ZNW.js → chunk-UCMT5OKP.js} +4 -4
  18. package/dist/{chunk-2MZER6ND.js → chunk-YYZOFYS6.js} +2 -2
  19. package/dist/ci-JQ56YIKC.js +756 -0
  20. package/dist/{codemap-RKSD4MIE.js → codemap-HMYBXJL2.js} +36 -36
  21. package/dist/{config-EGAXXCGL.js → config-YYWEN7U2.js} +1 -1
  22. package/dist/dist-2K7IEVTA.js +43 -0
  23. package/dist/{dist-UKMCJBB2.js → dist-4XTJ6HLM.js} +7 -7
  24. package/dist/{dist-QAU3LGJN.js → dist-5R4RYNQO.js} +3 -3
  25. package/dist/{dist-CB5D5LMO.js → dist-6MFVWIFF.js} +8 -8
  26. package/dist/{dist-GJYT2OQV.js → dist-7WLLPWWB.js} +8 -8
  27. package/dist/{dist-RKOGLK7R.js → dist-GWGTAHNM.js} +1 -1
  28. package/dist/{dist-CS2VKNYS.js → dist-U7ZIJMZD.js} +8 -8
  29. package/dist/{dist-YA2BWZB2.js → dist-WAMAQVPK.js} +2 -2
  30. package/dist/dist-XD4YI27T.js +26 -0
  31. package/dist/dist-XG2GG5SD.js +36 -0
  32. package/dist/{history-NFNA4HE5.js → history-RNUWO4JZ.js} +7 -7
  33. package/dist/hooks-installer-K2JXEBNN.js +19 -0
  34. package/dist/index.js +42 -42
  35. package/dist/{init-6CH4HV5T.js → init-NQWFZPKO.js} +11 -11
  36. package/dist/{launchd-LF2QMSKZ.js → launchd-OYXUAVW6.js} +2 -2
  37. package/dist/{mcp-installer-NQCGKQ23.js → mcp-installer-TOYDP77X.js} +1 -1
  38. package/dist/{memory-Y6OZTXJ2.js → memory-D6ZFFCI2.js} +17 -17
  39. package/dist/{openai-E7G2YAHU-UYY4ZWON.js → openai-E7G2YAHU-IG33BFYF.js} +2 -2
  40. package/dist/{projects-ATHDD3D6.js → projects-COUJP4ZC.js} +3 -3
  41. package/dist/{review-ADUPV3PN.js → review-KMGP2S25.js} +2 -2
  42. package/dist/{rules-E427DKYJ.js → rules-3OFGWHP4.js} +1 -1
  43. package/dist/server-USLHY6GH-F4JSXCWA.js +18 -0
  44. package/dist/server-X5P6WH2M-ULZF5WHZ.js +11 -0
  45. package/dist/{skills-CX73O3IV.js → skills-GY2CTPWN.js} +2 -2
  46. package/dist/{status-4DFHDJMN.js → status-SE43TIFJ.js} +2 -2
  47. package/dist/{templates-U7T6MARD.js → templates-O2XDKB5R.js} +5 -5
  48. package/dist/{ui-OWXZ3YSR.js → ui-4SM2SUI6.js} +13 -13
  49. package/dist/{ulpi-RMMCUAGP-JCJ273T6.js → ulpi-RMMCUAGP-EWYUE7RU.js} +1 -1
  50. package/dist/{uninstall-6SW35IK4.js → uninstall-KWGSGZTI.js} +3 -3
  51. package/dist/{update-WUITQX4Z.js → update-QYZA4D23.js} +3 -3
  52. package/dist/{version-checker-SMAYSN7Y.js → version-checker-MVB74DEX.js} +2 -2
  53. package/package.json +1 -1
  54. package/dist/chunk-G6SVZ4Q5.js +0 -122
  55. package/dist/ci-QM57ZCBW.js +0 -367
  56. package/dist/server-USLHY6GH-AEOJC5ST.js +0 -18
  57. package/dist/server-X5P6WH2M-7K2RY34N.js +0 -11
@@ -2,7 +2,7 @@ import {
2
2
  extractCredentials,
3
3
  getCredentialExpiry,
4
4
  validateCredentials
5
- } from "./chunk-G6SVZ4Q5.js";
5
+ } from "./chunk-AV5RB3N2.js";
6
6
  import "./chunk-4VNS5WPM.js";
7
7
 
8
8
  // src/commands/auth.ts
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  SESSIONS_DIR
3
- } from "./chunk-7LXY5UVC.js";
3
+ } from "./chunk-DDRLI6JU.js";
4
4
 
5
5
  // ../../packages/session-engine/dist/index.js
6
6
  import * as fs from "fs";
@@ -8,6 +8,7 @@ import * as path from "path";
8
8
  import * as path2 from "path";
9
9
  import * as fs2 from "fs";
10
10
  import * as path3 from "path";
11
+ import { execFileSync } from "child_process";
11
12
  function projectDirToSlug(dir) {
12
13
  const slug = dir.replace(/^\//, "").replace(/\//g, "-").replace(/\./g, "_").replace(/-{2,}/g, "-").replace(/^-|-$/g, "").toLowerCase();
13
14
  return slug || "unknown-project";
@@ -494,12 +495,59 @@ function readEvents(sessionId, projectDir, baseDir) {
494
495
  }
495
496
  return events;
496
497
  }
498
+ function nextPhase(current, hookEvent, context) {
499
+ switch (current) {
500
+ case "idle":
501
+ if (hookEvent === "SessionStart") {
502
+ return { phase: "active" };
503
+ }
504
+ break;
505
+ case "active":
506
+ if (hookEvent === "PostToolUse" && context?.hasNewCommit) {
507
+ return { phase: "active_committed", sideEffect: "capture" };
508
+ }
509
+ if (hookEvent === "SessionEnd") {
510
+ return { phase: "ended" };
511
+ }
512
+ break;
513
+ case "active_committed":
514
+ if (hookEvent === "PostToolUse" && context?.hasNewCommit) {
515
+ return { phase: "active_committed", sideEffect: "capture" };
516
+ }
517
+ if (hookEvent === "SessionEnd") {
518
+ return { phase: "ended" };
519
+ }
520
+ break;
521
+ case "ended":
522
+ break;
523
+ }
524
+ return { phase: current };
525
+ }
526
+ function detectNewCommit(projectDir, lastKnownHead) {
527
+ try {
528
+ const currentHead = execFileSync("git", ["rev-parse", "HEAD"], {
529
+ cwd: projectDir,
530
+ encoding: "utf-8",
531
+ timeout: 3e3
532
+ }).toString().trim();
533
+ if (currentHead && currentHead !== lastKnownHead) {
534
+ return { hasNewCommit: true, newHead: currentHead };
535
+ }
536
+ return { hasNewCommit: false, newHead: null };
537
+ } catch {
538
+ return { hasNewCommit: false, newHead: null };
539
+ }
540
+ }
497
541
 
498
542
  export {
499
543
  projectDirToSlug,
544
+ validateSessionId,
500
545
  JsonSessionStore,
546
+ createEmptyState,
501
547
  createInitialState,
502
548
  updateStateFromInput,
503
549
  appendEvent,
504
- readEvents
550
+ readEvents,
551
+ nextPhase,
552
+ detectNewCommit
505
553
  };
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  CLI_BIN_NAME,
3
3
  getBinaryPath
4
- } from "./chunk-7LXY5UVC.js";
4
+ } from "./chunk-DDRLI6JU.js";
5
5
 
6
6
  // src/hooks-installer.ts
7
7
  import * as fs from "fs";
@@ -140,6 +140,7 @@ function uninstallHooks(projectDir) {
140
140
 
141
141
  export {
142
142
  installHooks,
143
+ findSkillSource,
143
144
  installGlobalSkill,
144
145
  installLocalSkill,
145
146
  uninstallHooks
@@ -4,13 +4,13 @@ import {
4
4
  historyBranchExists,
5
5
  withWorktree,
6
6
  writeAndStage
7
- } from "./chunk-JGBXM5NC.js";
7
+ } from "./chunk-L3PWNHSA.js";
8
8
  import {
9
9
  CodemapConfigSchema
10
10
  } from "./chunk-74WVVWJ4.js";
11
11
  import {
12
12
  extractTagsFromTree
13
- } from "./chunk-ZLYRPD7I.js";
13
+ } from "./chunk-DOIKS6C5.js";
14
14
  import {
15
15
  LOGS_DIR,
16
16
  codemapBranchDir,
@@ -23,7 +23,7 @@ import {
23
23
  getCodemapBranch,
24
24
  getCurrentBranch,
25
25
  projectCodemapDir
26
- } from "./chunk-7LXY5UVC.js";
26
+ } from "./chunk-DDRLI6JU.js";
27
27
 
28
28
  // ../../packages/codemap-engine/dist/index.js
29
29
  import * as fs from "fs";
@@ -934,7 +934,7 @@ function diffManifest(oldManifest, newFiles) {
934
934
  async function createEmbedder(config) {
935
935
  switch (config.provider) {
936
936
  case "openai": {
937
- const { OpenAIEmbedder: OpenAIEmbedder2 } = await import("./openai-E7G2YAHU-UYY4ZWON.js");
937
+ const { OpenAIEmbedder: OpenAIEmbedder2 } = await import("./openai-E7G2YAHU-IG33BFYF.js");
938
938
  return new OpenAIEmbedder2(config.model, config.dimensions);
939
939
  }
940
940
  case "ollama": {
@@ -942,7 +942,7 @@ async function createEmbedder(config) {
942
942
  return new OllamaEmbedder2(config.model, config.dimensions);
943
943
  }
944
944
  case "ulpi": {
945
- const { UlpiEmbedder } = await import("./ulpi-RMMCUAGP-JCJ273T6.js");
945
+ const { UlpiEmbedder } = await import("./ulpi-RMMCUAGP-EWYUE7RU.js");
946
946
  return new UlpiEmbedder(config.model, config.dimensions, config.baseUrl);
947
947
  }
948
948
  default:
@@ -1663,7 +1663,7 @@ async function runPipelineInner(projectDir, onProgress, branch) {
1663
1663
  let depgraphResult;
1664
1664
  if (allTags.size > 0) {
1665
1665
  try {
1666
- const { buildReferenceGraph, computePageRank, savePageRank, computeMetrics, saveMetrics, saveGraph } = await import("./dist-YA2BWZB2.js");
1666
+ const { buildReferenceGraph, computePageRank, savePageRank, computeMetrics, saveMetrics, saveGraph } = await import("./dist-WAMAQVPK.js");
1667
1667
  onProgress?.({
1668
1668
  phase: "graph",
1669
1669
  current: 0,
@@ -1819,7 +1819,7 @@ async function rebuildDepgraphInner(projectDir, onProgress, branch) {
1819
1819
  log("warn", "No tags extracted \u2014 cannot build depgraph");
1820
1820
  return { nodeCount: 0, edgeCount: 0, definitionCount: 0, referenceCount: 0, cycleCount: 0, durationMs: Date.now() - startTime, taggedFiles: 0, totalFiles: scannedFiles.length };
1821
1821
  }
1822
- const { buildReferenceGraph, computePageRank, savePageRank, computeMetrics, saveMetrics, saveGraph } = await import("./dist-YA2BWZB2.js");
1822
+ const { buildReferenceGraph, computePageRank, savePageRank, computeMetrics, saveMetrics, saveGraph } = await import("./dist-WAMAQVPK.js");
1823
1823
  onProgress?.({ phase: "graph", current: 0, total: 3, message: "Building dependency graph..." });
1824
1824
  const graph = buildReferenceGraph(allTags, filePaths);
1825
1825
  for (const sf of scannedFiles) {
@@ -2090,7 +2090,7 @@ async function searchCode(projectDir, query, options = {}) {
2090
2090
  let graphRanks;
2091
2091
  if (weights.graphRank && weights.graphRank > 0) {
2092
2092
  try {
2093
- const { loadPageRankMap } = await import("./dist-YA2BWZB2.js");
2093
+ const { loadPageRankMap } = await import("./dist-WAMAQVPK.js");
2094
2094
  graphRanks = loadPageRankMap(projectDir, resolvedBranch) ?? void 0;
2095
2095
  } catch {
2096
2096
  }
@@ -0,0 +1,173 @@
1
+ // ../../packages/ci-engine/dist/index.js
2
+ import * as fs4 from "fs";
3
+ import * as path3 from "path";
4
+ import { execFileSync as execFileSync2 } from "child_process";
5
+ function buildPrompt(config, context) {
6
+ const sections = [];
7
+ sections.push("# Task");
8
+ sections.push("");
9
+ sections.push(config.instruction);
10
+ sections.push("");
11
+ if (context.prTitle || context.prBody) {
12
+ sections.push("# Pull Request Context");
13
+ sections.push("");
14
+ if (context.prTitle) sections.push(`**Title:** ${context.prTitle}`);
15
+ if (context.prBody) {
16
+ sections.push("");
17
+ sections.push(context.prBody);
18
+ }
19
+ sections.push("");
20
+ }
21
+ sections.push("# Branch Info");
22
+ sections.push("");
23
+ sections.push(`- **Working branch:** ${config.ref}`);
24
+ sections.push(`- **Base branch:** ${config.baseBranch}`);
25
+ sections.push(`- **Repository:** ${config.repoFullName}`);
26
+ sections.push("");
27
+ if (config.jiraContext || context.jiraContext) {
28
+ sections.push("# Jira Context");
29
+ sections.push("");
30
+ sections.push(config.jiraContext ?? context.jiraContext ?? "");
31
+ sections.push("");
32
+ }
33
+ sections.push("# Workflow: Plan \u2192 Execute");
34
+ sections.push("");
35
+ sections.push("You MUST follow this two-phase workflow:");
36
+ sections.push("");
37
+ sections.push("## Phase 1: Plan");
38
+ sections.push("");
39
+ sections.push("1. **Discover skills**: Scan `.claude/skills/*/SKILL.md` for available skills. If a `start` skill exists, follow its protocol.");
40
+ sections.push("2. **Use `plan-enhanced`**: If the repo has a `.claude/skills/plan-enhanced/SKILL.md` skill, use it to create a structured plan. The plan must include:");
41
+ sections.push(" - Task breakdown with scope and estimated files");
42
+ sections.push(" - Dependency graph between tasks");
43
+ sections.push(" - Parallelizability score");
44
+ sections.push(" - Agent assignment for each task (match domain to `.claude/agents/` \u2014 e.g. `express-senior-engineer`, `react-vite-tailwind-engineer`, `nodejs-cli-senior-engineer`)");
45
+ sections.push(" - Agent briefs with scope, files, output, and success criteria");
46
+ sections.push("3. **Write plan to file**: Save the plan as `plan.md` in the repo root and commit it. Do NOT just output text.");
47
+ sections.push("");
48
+ sections.push("## Phase 2: Execute");
49
+ sections.push("");
50
+ sections.push("4. **Launch agents from the plan**: Read the plan file and spawn the assigned agents via the Task tool. Launch independent streams in parallel (multiple Task tool calls in one message). Sequential tasks run after their dependencies complete.");
51
+ sections.push("5. **Commit results**: After agents finish, use the `/commit` skill to commit all changes. This skill analyzes diffs and creates proper conventional commit messages.");
52
+ sections.push("6. **Run tests**: If a test runner is configured, run tests and fix failures.");
53
+ sections.push("");
54
+ sections.push("If the task is simple (1\u20132 files, single domain), skip `plan-enhanced` and execute directly with the matching agent.");
55
+ sections.push("");
56
+ if (context.stackContext) {
57
+ sections.push("# Project Stack");
58
+ sections.push("");
59
+ sections.push(context.stackContext);
60
+ sections.push("");
61
+ }
62
+ sections.push("# CI Constraints");
63
+ sections.push("");
64
+ sections.push("- You are running in CI mode inside a worker container.");
65
+ sections.push("- **Commit early and often.** After completing each logical unit of work (a feature, a module, a batch of related files), commit immediately with `git add` + `git commit`. Do NOT wait until the end to commit everything at once. Use conventional commit messages (e.g. `feat:`, `fix:`, `chore:`).");
66
+ sections.push("- Work on the existing branch \u2014 do NOT create new branches.");
67
+ sections.push("- Do NOT push to the remote \u2014 the orchestrator will handle pushing.");
68
+ sections.push("");
69
+ sections.push("# Prohibited Actions");
70
+ sections.push("");
71
+ sections.push("The following are STRICTLY FORBIDDEN in CI mode:");
72
+ sections.push("- **No `npm install`, `npm init`, `npx create-*`, `yarn add`, `pnpm add`, or any package installation commands.** Dependencies must be declared in package.json and committed \u2014 never installed at runtime.");
73
+ sections.push("- **No scaffolding tools** (`create-next-app`, `create-react-app`, `express-generator`, etc.). Write files directly.");
74
+ sections.push("- **No documentation directories** (`docs/`, `guides/`, `examples/`) unless explicitly requested in the task.");
75
+ sections.push("- **No infrastructure/DevOps files** (`Dockerfile`, `docker-compose.yml`, `nginx.conf`, `Makefile`, CI/CD pipelines, monitoring configs) unless explicitly requested.");
76
+ sections.push("- **No `.env` or `.env.example` files** unless explicitly requested.");
77
+ sections.push("- **Minimize TodoWrite** \u2014 use it at most once to set up your task list, not repeatedly during execution.");
78
+ sections.push("");
79
+ sections.push("# Code Quality");
80
+ sections.push("");
81
+ sections.push("- **Always use TypeScript (`.ts`/`.tsx`)** for all application code. Never write `.js` files except for config files that require it (e.g. `tailwind.config.js`, `postcss.config.js`).");
82
+ sections.push("- Write production code directly \u2014 no placeholder implementations, no TODO comments, no stub functions.");
83
+ sections.push("- Focus exclusively on what the task asks for. Do not add extras (monitoring, logging infrastructure, CI/CD, documentation) unless the task explicitly requires them.");
84
+ sections.push("- Keep solutions minimal and focused. Three files that work are better than twenty files of scaffolding.");
85
+ sections.push("");
86
+ return sections.join("\n");
87
+ }
88
+ var CREDENTIAL_FILES = [
89
+ "oauth_token",
90
+ ".credentials.json",
91
+ "credentials.json",
92
+ "auth.json"
93
+ ];
94
+ function extractCredentials(claudeConfigDir) {
95
+ const configDir = claudeConfigDir ?? path3.join(process.env.HOME ?? "", ".claude");
96
+ if (!fs4.existsSync(configDir)) {
97
+ throw new Error(
98
+ `Claude config directory not found: ${configDir}`
99
+ );
100
+ }
101
+ const existingFiles = CREDENTIAL_FILES.filter(
102
+ (f) => fs4.existsSync(path3.join(configDir, f))
103
+ );
104
+ if (existingFiles.length === 0) {
105
+ throw new Error(
106
+ `No credential files found in ${configDir}. Run 'claude login' first.`
107
+ );
108
+ }
109
+ const tarOutput = execFileSync2(
110
+ "tar",
111
+ ["-czf", "-", "-C", configDir, ...existingFiles],
112
+ {
113
+ encoding: "buffer",
114
+ timeout: 3e4,
115
+ maxBuffer: 10 * 1024 * 1024
116
+ // 10MB limit (credentials are tiny)
117
+ }
118
+ );
119
+ return tarOutput.toString("base64");
120
+ }
121
+ function writeCredentials(blob, targetDir) {
122
+ fs4.mkdirSync(targetDir, { recursive: true });
123
+ const tarBuffer = Buffer.from(blob, "base64");
124
+ execFileSync2("tar", ["-xzf", "-", "-C", targetDir], {
125
+ input: tarBuffer,
126
+ timeout: 3e4
127
+ });
128
+ }
129
+ function validateCredentials(blob) {
130
+ const tmpDir = fs4.mkdtempSync("/tmp/ulpi-claude-check-");
131
+ try {
132
+ writeCredentials(blob, tmpDir);
133
+ const files = fs4.readdirSync(tmpDir);
134
+ return files.length > 0;
135
+ } catch {
136
+ return false;
137
+ } finally {
138
+ try {
139
+ fs4.rmSync(tmpDir, { recursive: true, force: true });
140
+ } catch {
141
+ }
142
+ }
143
+ }
144
+ function getCredentialExpiry(blob) {
145
+ const tmpDir = fs4.mkdtempSync("/tmp/ulpi-claude-expiry-");
146
+ try {
147
+ writeCredentials(blob, tmpDir);
148
+ const authFile = path3.join(tmpDir, ".credentials.json");
149
+ if (fs4.existsSync(authFile)) {
150
+ try {
151
+ const data = JSON.parse(
152
+ fs4.readFileSync(authFile, "utf-8")
153
+ );
154
+ if (data.expiresAt) return data.expiresAt;
155
+ if (data.expires_at) return data.expires_at;
156
+ } catch {
157
+ }
158
+ }
159
+ return void 0;
160
+ } finally {
161
+ try {
162
+ fs4.rmSync(tmpDir, { recursive: true, force: true });
163
+ } catch {
164
+ }
165
+ }
166
+ }
167
+
168
+ export {
169
+ buildPrompt,
170
+ extractCredentials,
171
+ validateCredentials,
172
+ getCredentialExpiry
173
+ };
@@ -5,7 +5,7 @@ import { join, resolve } from "path";
5
5
  import { execFileSync } from "child_process";
6
6
  import { existsSync as existsSync2, readFileSync as readFileSync2, writeFileSync, mkdirSync } from "fs";
7
7
  import { dirname } from "path";
8
- var ULPI_GLOBAL_DIR = join(homedir(), ".ulpi");
8
+ var ULPI_GLOBAL_DIR = process.env.ULPI_GLOBAL_DIR || join(homedir(), ".ulpi");
9
9
  var ULPI_PROJECT_DIR = ".ulpi";
10
10
  var GUARDS_FILENAME = "guards.yml";
11
11
  var GUARDS_FILENAME_ALT = "guards.yaml";
@@ -150,6 +150,7 @@ function memoryPromptsDir(projectDir) {
150
150
  }
151
151
  var CLI_BIN_NAME = "ulpi";
152
152
  function getBinaryPath() {
153
+ if (process.env.ULPI_CI_MODE) return CLI_BIN_NAME;
153
154
  if (process.argv[1] && process.argv[1].includes("node_modules")) {
154
155
  return CLI_BIN_NAME;
155
156
  }
@@ -3,7 +3,7 @@ import {
3
3
  depgraphGraphFile,
4
4
  depgraphMetricsFile,
5
5
  depgraphPagerankFile
6
- } from "./chunk-7LXY5UVC.js";
6
+ } from "./chunk-DDRLI6JU.js";
7
7
 
8
8
  // ../../packages/depgraph-engine/dist/index.js
9
9
  import { mkdirSync, readFileSync, writeFileSync } from "fs";
@@ -2,7 +2,7 @@ import {
2
2
  ULPI_GLOBAL_DIR,
3
3
  projectGuardsFile,
4
4
  projectGuardsFileAlt
5
- } from "./chunk-7LXY5UVC.js";
5
+ } from "./chunk-DDRLI6JU.js";
6
6
 
7
7
  // ../../packages/projects-engine/dist/index.js
8
8
  import * as fs from "fs";
@@ -3,14 +3,14 @@ import {
3
3
  } from "./chunk-MIAQVCFW.js";
4
4
  import {
5
5
  getProject
6
- } from "./chunk-SPOI23SB.js";
6
+ } from "./chunk-EIWYSP3A.js";
7
7
  import {
8
8
  JsonSessionStore,
9
9
  readEvents
10
- } from "./chunk-YM2HV4IA.js";
10
+ } from "./chunk-26LLDX2T.js";
11
11
  import {
12
12
  getApiHost
13
- } from "./chunk-7LXY5UVC.js";
13
+ } from "./chunk-DDRLI6JU.js";
14
14
 
15
15
  // ../api/dist/chunk-F3LN44RE.js
16
16
  import { WebSocketServer } from "ws";
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  USER_SKILLS_DIR,
3
3
  USER_TEMPLATES_DIR
4
- } from "./chunk-7LXY5UVC.js";
4
+ } from "./chunk-DDRLI6JU.js";
5
5
 
6
6
  // ../../packages/templates-engine/dist/index.js
7
7
  import * as fs from "fs";
@@ -56,6 +56,9 @@ function loadBundledTemplates() {
56
56
  const dir = findTemplatesDir();
57
57
  return loadTemplatesFromDir(dir);
58
58
  }
59
+ function loadTemplates(dir) {
60
+ return loadTemplatesFromDir(dir);
61
+ }
59
62
  function loadTemplatesFromDir(dir) {
60
63
  if (!fs.existsSync(dir)) {
61
64
  return [];
@@ -70,6 +73,10 @@ function loadTemplatesFromDir(dir) {
70
73
  }
71
74
  return layers;
72
75
  }
76
+ function getBundledTemplate(id) {
77
+ const all = loadBundledTemplates();
78
+ return all.find((t) => t.id === id) ?? null;
79
+ }
73
80
  function deepClone(value) {
74
81
  if (typeof structuredClone === "function") {
75
82
  return structuredClone(value);
@@ -199,12 +206,13 @@ function resolveTemplate(composed, config) {
199
206
  permissions: resolveValue(composed.permissions, vars),
200
207
  pipelines: resolveValue(composed.pipelines, vars)
201
208
  };
209
+ const RUNTIME_PLACEHOLDERS = /* @__PURE__ */ new Set(["{file_path}", "{command}"]);
202
210
  const unresolved = [
203
211
  ...findUnresolvedPlaceholders(resolved.preconditions),
204
212
  ...findUnresolvedPlaceholders(resolved.postconditions),
205
213
  ...findUnresolvedPlaceholders(resolved.permissions),
206
214
  ...findUnresolvedPlaceholders(resolved.pipelines)
207
- ];
215
+ ].filter((p) => !RUNTIME_PLACEHOLDERS.has(p));
208
216
  if (unresolved.length > 0) {
209
217
  const unique = [...new Set(unresolved)];
210
218
  console.error(`[ulpi] Warning: unresolved template variables after resolution: ${unique.join(", ")}`);
@@ -241,6 +249,22 @@ function saveUserTemplate(template, baseDir = DEFAULT_BASE_DIR) {
241
249
  const yaml = stringifyYaml(template, { indent: 2, lineWidth: 0 });
242
250
  fs2.writeFileSync(filePath, yaml, "utf-8");
243
251
  }
252
+ function loadUserTemplate(name, baseDir = DEFAULT_BASE_DIR) {
253
+ const filePath = templatePath(name, baseDir);
254
+ if (!fs2.existsSync(filePath)) {
255
+ return null;
256
+ }
257
+ try {
258
+ const raw = fs2.readFileSync(filePath, "utf-8");
259
+ const parsed = parseYaml2(raw);
260
+ if (!parsed || typeof parsed !== "object" || !parsed.name) {
261
+ return null;
262
+ }
263
+ return parsed;
264
+ } catch {
265
+ return null;
266
+ }
267
+ }
244
268
  function listUserTemplates(baseDir = DEFAULT_BASE_DIR) {
245
269
  if (!fs2.existsSync(baseDir)) {
246
270
  return [];
@@ -406,17 +430,24 @@ var BUNDLED_SKILLS = [
406
430
  category: "quality"
407
431
  }
408
432
  ];
433
+ function getBundledSkillInfo(id) {
434
+ return BUNDLED_SKILLS.find((s) => s.id === id);
435
+ }
409
436
 
410
437
  export {
411
438
  loadBundledTemplates,
439
+ loadTemplates,
440
+ getBundledTemplate,
412
441
  composeTemplates,
413
442
  resolveTemplate,
414
443
  saveUserTemplate,
444
+ loadUserTemplate,
415
445
  listUserTemplates,
416
446
  deleteUserTemplate,
417
447
  exportUserTemplate,
418
448
  importUserTemplate,
419
449
  loadSkillSync,
420
450
  injectSkill,
421
- BUNDLED_SKILLS
451
+ BUNDLED_SKILLS,
452
+ getBundledSkillInfo
422
453
  };
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  resolveApiKey
3
- } from "./chunk-7LXY5UVC.js";
3
+ } from "./chunk-DDRLI6JU.js";
4
4
 
5
5
  // ../../packages/codemap-engine/dist/chunk-ZW4DV263.js
6
6
  var OPENAI_EMBEDDINGS_URL = "https://api.openai.com/v1/embeddings";
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  JsonSessionStore,
3
3
  readEvents
4
- } from "./chunk-YM2HV4IA.js";
4
+ } from "./chunk-26LLDX2T.js";
5
5
  import {
6
6
  DEFAULT_AI_MODEL,
7
7
  REVIEWS_DIR,
@@ -9,7 +9,7 @@ import {
9
9
  getHistoryBranch,
10
10
  projectGuardsFile,
11
11
  projectGuardsFileAlt
12
- } from "./chunk-7LXY5UVC.js";
12
+ } from "./chunk-DDRLI6JU.js";
13
13
 
14
14
  // ../../packages/history-engine/dist/index.js
15
15
  import { execFileSync } from "child_process";