@delorenj/pjangler 1.5.45 → 1.5.46

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -11571,6 +11571,12 @@ function validateDeclaredAgent(ctx, declared) {
11571
11571
  }
11572
11572
  return { valid: details.length === 0, role: roleYaml.role, agentId: roleYaml.agentId, roleDir, details };
11573
11573
  }
11574
+ function repoPathNamesRoot(value, repoRoot, homeDir) {
11575
+ if (typeof value !== "string") return false;
11576
+ if (value === repoRoot) return true;
11577
+ if (!homeDir || value !== "~" && !value.startsWith("~/")) return false;
11578
+ return resolve7(homeDir, value.slice(2)) === resolve7(repoRoot);
11579
+ }
11574
11580
  function canonicalProjectJson(ctx) {
11575
11581
  const roles = discoverRoles(ctx.repoRoot);
11576
11582
  const existing = readProjectJson(ctx) ?? {};
@@ -11633,7 +11639,9 @@ function canonicalProjectJson(ctx) {
11633
11639
  project_name: String(existing.project_name ?? titleCaseSlug(slug)),
11634
11640
  project_description: String(existing.project_description ?? ""),
11635
11641
  project_id: slug,
11636
- repo_path: ctx.repoRoot,
11642
+ // A home-relative spelling that already names this repo is kept: rewriting
11643
+ // it to this host's absolute path would make the manifest wrong on its peers.
11644
+ repo_path: repoPathNamesRoot(existing.repo_path, ctx.repoRoot, ctx.homeDir) ? existing.repo_path : ctx.repoRoot,
11637
11645
  ticket_provider: ticketProvider,
11638
11646
  agents,
11639
11647
  ...Object.keys(automation).length ? { automation } : {},
@@ -11658,7 +11666,7 @@ function projectJsonFinding(ctx) {
11658
11666
  }
11659
11667
  if ("project_slug" in data) details.push("legacy project_slug should be migrated to project_id");
11660
11668
  if (typeof data.project_id === "string" && data.project_id !== data.project_id.toLowerCase()) details.push("project_id must be lowercase");
11661
- if (data.repo_path !== ctx.repoRoot) details.push(`repo_path should be ${ctx.repoRoot}`);
11669
+ if (!repoPathNamesRoot(data.repo_path, ctx.repoRoot, ctx.homeDir)) details.push(`repo_path should be ${ctx.repoRoot}`);
11662
11670
  const agents = data.agents ?? {};
11663
11671
  for (const role of roles) {
11664
11672
  const agent = agents[role.agentId];
@@ -10734,6 +10734,12 @@ function validateDeclaredAgent(ctx, declared) {
10734
10734
  }
10735
10735
  return { valid: details.length === 0, role: roleYaml.role, agentId: roleYaml.agentId, roleDir, details };
10736
10736
  }
10737
+ function repoPathNamesRoot(value, repoRoot, homeDir) {
10738
+ if (typeof value !== "string") return false;
10739
+ if (value === repoRoot) return true;
10740
+ if (!homeDir || value !== "~" && !value.startsWith("~/")) return false;
10741
+ return resolve6(homeDir, value.slice(2)) === resolve6(repoRoot);
10742
+ }
10737
10743
  function canonicalProjectJson(ctx) {
10738
10744
  const roles = discoverRoles(ctx.repoRoot);
10739
10745
  const existing = readProjectJson(ctx) ?? {};
@@ -10796,7 +10802,9 @@ function canonicalProjectJson(ctx) {
10796
10802
  project_name: String(existing.project_name ?? titleCaseSlug(slug)),
10797
10803
  project_description: String(existing.project_description ?? ""),
10798
10804
  project_id: slug,
10799
- repo_path: ctx.repoRoot,
10805
+ // A home-relative spelling that already names this repo is kept: rewriting
10806
+ // it to this host's absolute path would make the manifest wrong on its peers.
10807
+ repo_path: repoPathNamesRoot(existing.repo_path, ctx.repoRoot, ctx.homeDir) ? existing.repo_path : ctx.repoRoot,
10800
10808
  ticket_provider: ticketProvider,
10801
10809
  agents,
10802
10810
  ...Object.keys(automation).length ? { automation } : {},
@@ -10821,7 +10829,7 @@ function projectJsonFinding(ctx) {
10821
10829
  }
10822
10830
  if ("project_slug" in data) details.push("legacy project_slug should be migrated to project_id");
10823
10831
  if (typeof data.project_id === "string" && data.project_id !== data.project_id.toLowerCase()) details.push("project_id must be lowercase");
10824
- if (data.repo_path !== ctx.repoRoot) details.push(`repo_path should be ${ctx.repoRoot}`);
10832
+ if (!repoPathNamesRoot(data.repo_path, ctx.repoRoot, ctx.homeDir)) details.push(`repo_path should be ${ctx.repoRoot}`);
10825
10833
  const agents = data.agents ?? {};
10826
10834
  for (const role of roles) {
10827
10835
  const agent = agents[role.agentId];
@@ -635,7 +635,22 @@ async function body(request) {
635
635
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) throw new RegistryError("Expected JSON object", 400, "invalid_request");
636
636
  return parsed;
637
637
  }
638
+ var DEFAULT_REGISTRY_HOST = "127.0.0.1";
639
+ function registryBindHost(env = process.env) {
640
+ return env.PJ_REGISTRY_HOST?.trim() || DEFAULT_REGISTRY_HOST;
641
+ }
642
+ function isWildcardHost(host) {
643
+ return host === "0.0.0.0" || host === "::";
644
+ }
645
+ function registryLocalUrl(host, port) {
646
+ const name = isWildcardHost(host) ? "127.0.0.1" : host.includes(":") ? `[${host}]` : host;
647
+ return `http://${name}:${port}`;
648
+ }
649
+ function registryListeningMessage(service) {
650
+ return `PJangler project registry listening at ${service.url}${isWildcardHost(service.host) ? ` (bind ${service.host})` : ""}`;
651
+ }
638
652
  async function createRegistryService(options = {}) {
653
+ const host = options.host ?? registryBindHost();
639
654
  const pool = options.pool ?? new Pool({ database: process.env.PGDATABASE ?? "33god", connectionTimeoutMillis: 5e3, statement_timeout: 15e3 });
640
655
  const index = new ManifestIndex(pool);
641
656
  try {
@@ -710,7 +725,7 @@ async function createRegistryService(options = {}) {
710
725
  server.keepAliveTimeout = 1e3;
711
726
  await new Promise((resolve2, reject) => {
712
727
  server.once("error", reject);
713
- server.listen(options.port ?? Number(process.env.PJ_REGISTRY_PORT ?? 8764), options.host ?? "127.0.0.1", () => {
728
+ server.listen(options.port ?? Number(process.env.PJ_REGISTRY_PORT ?? 8764), host, () => {
714
729
  server.off("error", reject);
715
730
  resolve2();
716
731
  });
@@ -723,7 +738,8 @@ async function createRegistryService(options = {}) {
723
738
  server,
724
739
  pool,
725
740
  index,
726
- url: `http://127.0.0.1:${typeof address === "object" ? address?.port : options.port}`,
741
+ host,
742
+ url: registryLocalUrl(host, typeof address === "object" ? address?.port : options.port),
727
743
  async close() {
728
744
  await new Promise((resolve2, reject) => server.close((error) => error ? reject(error) : resolve2()));
729
745
  if (!options.pool) await pool.end();
@@ -732,7 +748,7 @@ async function createRegistryService(options = {}) {
732
748
  }
733
749
  async function startRegistryService() {
734
750
  const service = await createRegistryService();
735
- console.log(`PJangler project registry listening at ${service.url}`);
751
+ console.log(registryListeningMessage(service));
736
752
  const stop = () => {
737
753
  void service.close().then(() => process.exit(0), (error) => {
738
754
  console.error(error);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@delorenj/pjangler",
3
- "version": "1.5.45",
3
+ "version": "1.5.46",
4
4
  "description": "Project subsystem bootstrapper CLI",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",