@whxway/loom 1.0.1 → 1.0.2

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 (2) hide show
  1. package/bin/loom.mjs +80 -21
  2. package/package.json +1 -1
package/bin/loom.mjs CHANGED
@@ -121,12 +121,69 @@ var init_paths = __esm({
121
121
  }
122
122
  });
123
123
 
124
+ // lib/cli/external-aliases.ts
125
+ import { existsSync as existsSync2, lstatSync, mkdirSync, readFileSync as readFileSync2, readlinkSync, rmSync, symlinkSync } from "node:fs";
126
+ import { createRequire } from "node:module";
127
+ import { dirname, relative, resolve as resolve2 } from "node:path";
128
+ function ensureExternalAliases() {
129
+ if (!existsSync2(MANIFEST)) return;
130
+ let aliases;
131
+ try {
132
+ aliases = JSON.parse(readFileSync2(MANIFEST, "utf8"));
133
+ } catch (err) {
134
+ console.warn(`[loom] failed to parse ${MANIFEST}:`, err.message);
135
+ return;
136
+ }
137
+ if (!aliases || typeof aliases !== "object" || Object.keys(aliases).length === 0) return;
138
+ mkdirSync(MODULES_DIR, { recursive: true });
139
+ const requireFromPkg = createRequire(resolve2(PACKAGE_ROOT, "package.json"));
140
+ let created = 0;
141
+ for (const [hashed, real] of Object.entries(aliases)) {
142
+ const linkPath = resolve2(MODULES_DIR, hashed);
143
+ try {
144
+ const stat = lstatSync(linkPath);
145
+ if (stat.isSymbolicLink()) {
146
+ const target2 = resolve2(MODULES_DIR, readlinkSync(linkPath));
147
+ if (existsSync2(target2)) continue;
148
+ }
149
+ rmSync(linkPath, { recursive: true, force: true });
150
+ } catch {
151
+ }
152
+ let realPkgDir;
153
+ try {
154
+ realPkgDir = dirname(requireFromPkg.resolve(`${real}/package.json`));
155
+ } catch (err) {
156
+ console.warn(`[loom] couldn't resolve "${real}" for alias "${hashed}": ${err.message}`);
157
+ continue;
158
+ }
159
+ const target = relative(MODULES_DIR, realPkgDir);
160
+ try {
161
+ symlinkSync(target, linkPath, "junction");
162
+ created++;
163
+ } catch (err) {
164
+ console.warn(`[loom] failed to symlink "${hashed}" -> "${target}": ${err.message}`);
165
+ }
166
+ }
167
+ if (created > 0) {
168
+ console.log(`[loom] linked ${created} external package alias${created === 1 ? "" : "es"}`);
169
+ }
170
+ }
171
+ var MANIFEST, MODULES_DIR;
172
+ var init_external_aliases = __esm({
173
+ "lib/cli/external-aliases.ts"() {
174
+ "use strict";
175
+ init_paths();
176
+ MANIFEST = resolve2(PACKAGE_ROOT, ".next/external-aliases.json");
177
+ MODULES_DIR = resolve2(PACKAGE_ROOT, ".next/node_modules");
178
+ }
179
+ });
180
+
124
181
  // lib/cli/next-runtime.ts
125
182
  import { spawn } from "node:child_process";
126
- import { createRequire } from "node:module";
127
- import { resolve as resolve2 } from "node:path";
183
+ import { createRequire as createRequire2 } from "node:module";
184
+ import { resolve as resolve3 } from "node:path";
128
185
  function resolveNextBin() {
129
- const requireFromPkg = createRequire(resolve2(PACKAGE_ROOT, "package.json"));
186
+ const requireFromPkg = createRequire2(resolve3(PACKAGE_ROOT, "package.json"));
130
187
  try {
131
188
  return requireFromPkg.resolve("next/dist/bin/next");
132
189
  } catch (err) {
@@ -141,6 +198,7 @@ function runNext(mode, opts) {
141
198
  const nextBin = resolveNextBin();
142
199
  process.env.LOOM_USER_CWD = USER_CWD;
143
200
  process.env.LOOM_PACKAGE_ROOT = PACKAGE_ROOT;
201
+ if (mode === "start") ensureExternalAliases();
144
202
  const { path: cfgPath, applied } = preflightFromConfig();
145
203
  if (cfgPath) {
146
204
  const note2 = applied.length > 0 ? ` (env: ${applied.join(", ")})` : "";
@@ -162,6 +220,7 @@ var init_next_runtime = __esm({
162
220
  "lib/cli/next-runtime.ts"() {
163
221
  "use strict";
164
222
  init_preflight();
223
+ init_external_aliases();
165
224
  init_paths();
166
225
  }
167
226
  });
@@ -402,9 +461,9 @@ var init_template = __esm({
402
461
  });
403
462
 
404
463
  // lib/cli/init/wizard.ts
405
- import { existsSync as existsSync2, mkdirSync, writeFileSync } from "node:fs";
464
+ import { existsSync as existsSync3, mkdirSync as mkdirSync2, writeFileSync } from "node:fs";
406
465
  import { homedir as homedir2 } from "node:os";
407
- import { dirname, resolve as resolve3 } from "node:path";
466
+ import { dirname as dirname2, resolve as resolve4 } from "node:path";
408
467
  import { confirm, group, intro, log, note, outro, password as password2, select as select2, text as text2 } from "@clack/prompts";
409
468
  async function runInteractiveInit(opts) {
410
469
  if (opts.print) {
@@ -413,7 +472,7 @@ async function runInteractiveInit(opts) {
413
472
  }
414
473
  if (opts.yes) {
415
474
  const outPath2 = resolveOutPath(opts);
416
- if (existsSync2(outPath2) && !opts.force) {
475
+ if (existsSync3(outPath2) && !opts.force) {
417
476
  console.error(`Refusing to overwrite existing file: ${outPath2}`);
418
477
  console.error("Pass --force to replace it.");
419
478
  process.exit(1);
@@ -497,22 +556,22 @@ async function promptOutPath() {
497
556
  initialValue: "project"
498
557
  })
499
558
  );
500
- if (target === "project") return resolve3(USER_CWD, "loom.config.yaml");
559
+ if (target === "project") return resolve4(USER_CWD, "loom.config.yaml");
501
560
  if (target === "user") {
502
- const xdg = process.env.XDG_CONFIG_HOME || resolve3(homedir2(), ".config");
503
- return resolve3(xdg, "loom.yaml");
561
+ const xdg = process.env.XDG_CONFIG_HOME || resolve4(homedir2(), ".config");
562
+ return resolve4(xdg, "loom.yaml");
504
563
  }
505
564
  const custom = await ask(
506
565
  text2({
507
566
  message: "Config path",
508
- placeholder: resolve3(USER_CWD, "loom.config.yaml"),
509
- initialValue: resolve3(USER_CWD, "loom.config.yaml")
567
+ placeholder: resolve4(USER_CWD, "loom.config.yaml"),
568
+ initialValue: resolve4(USER_CWD, "loom.config.yaml")
510
569
  })
511
570
  );
512
- return resolve3(USER_CWD, custom);
571
+ return resolve4(USER_CWD, custom);
513
572
  }
514
573
  async function promptOverwrite(outPath) {
515
- if (!existsSync2(outPath)) return;
574
+ if (!existsSync3(outPath)) return;
516
575
  const overwrite = await ask(
517
576
  confirm({
518
577
  message: `${outPath} already exists. Overwrite?`,
@@ -541,15 +600,15 @@ async function promptAdminPassword() {
541
600
  );
542
601
  }
543
602
  function resolveOutPath(opts) {
544
- if (opts.explicitOut) return resolve3(USER_CWD, opts.explicitOut);
603
+ if (opts.explicitOut) return resolve4(USER_CWD, opts.explicitOut);
545
604
  if (opts.user) {
546
- const xdg = process.env.XDG_CONFIG_HOME || resolve3(homedir2(), ".config");
547
- return resolve3(xdg, "loom.yaml");
605
+ const xdg = process.env.XDG_CONFIG_HOME || resolve4(homedir2(), ".config");
606
+ return resolve4(xdg, "loom.yaml");
548
607
  }
549
- return resolve3(USER_CWD, "loom.config.yaml");
608
+ return resolve4(USER_CWD, "loom.config.yaml");
550
609
  }
551
610
  function writeOut(outPath, yaml) {
552
- mkdirSync(dirname(outPath), { recursive: true });
611
+ mkdirSync2(dirname2(outPath), { recursive: true });
553
612
  writeFileSync(outPath, yaml, { mode: 384 });
554
613
  log.success(`Wrote ${outPath}`);
555
614
  }
@@ -649,7 +708,7 @@ var init_main = __esm({
649
708
  main = defineCommand4({
650
709
  meta: {
651
710
  name: "loom",
652
- version: "0.1.0",
711
+ version: "1.0.2",
653
712
  description: "Self-hosted AI testing platform \u2014 playground, MCP runtime, request logs, and an OpenAI-compatible gateway."
654
713
  },
655
714
  subCommands: {
@@ -667,9 +726,9 @@ var init_main = __esm({
667
726
  });
668
727
 
669
728
  // bin/loom.ts
670
- import { dirname as dirname2, resolve as resolve4 } from "node:path";
729
+ import { dirname as dirname3, resolve as resolve5 } from "node:path";
671
730
  import { fileURLToPath } from "node:url";
672
731
  import { runMain } from "citty";
673
- process.env.LOOM_PACKAGE_ROOT = resolve4(dirname2(fileURLToPath(import.meta.url)), "..");
732
+ process.env.LOOM_PACKAGE_ROOT = resolve5(dirname3(fileURLToPath(import.meta.url)), "..");
674
733
  var { main: main2 } = await Promise.resolve().then(() => (init_main(), main_exports));
675
734
  runMain(main2);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@whxway/loom",
3
- "version": "1.0.1",
3
+ "version": "1.0.2",
4
4
  "description": "Self-hosted AI testing platform — try models and MCP servers, log every request, and front your apps through an OpenAI-compatible gateway.",
5
5
  "keywords": [
6
6
  "ai",