@sleepy-hollow/framework 0.3.2 → 0.3.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -1,23 +1,23 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  resolveConfiguration
4
- } from "./chunk-BJONRVDG.js";
4
+ } from "./chunk-2GNHTFCZ.js";
5
5
  import {
6
6
  createTraceabilityReport,
7
7
  selectAffectedTests
8
- } from "./chunk-D4U3ZY4O.js";
8
+ } from "./chunk-RYKRRAPD.js";
9
9
  import "./chunk-BAKXP7IR.js";
10
10
  import {
11
11
  composeProjectSecurity
12
- } from "./chunk-DGTHFZPZ.js";
12
+ } from "./chunk-AADQFGT4.js";
13
13
  import {
14
14
  normalizeRoutes
15
- } from "./chunk-CAPFDC25.js";
15
+ } from "./chunk-QY3TSXM6.js";
16
16
  import {
17
17
  discoverRoutes,
18
18
  platform
19
- } from "./chunk-53TZY5YP.js";
20
- import "./chunk-LNJDFJGT.js";
19
+ } from "./chunk-LPPASMRR.js";
20
+ import "./chunk-EHBEUJIZ.js";
21
21
  import "./chunk-5WRI5ZAA.js";
22
22
 
23
23
  // cli/main.ts
@@ -1006,7 +1006,7 @@ var CreationError = class extends Error {
1006
1006
  };
1007
1007
 
1008
1008
  // cli/create/create.ts
1009
- var VERSION = "0.3.2";
1009
+ var VERSION = "0.3.4";
1010
1010
  var NAME = /^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/;
1011
1011
  function files(name) {
1012
1012
  return {
@@ -1090,7 +1090,33 @@ test("capture artifact is persisted", async () => { await persist(); });
1090
1090
  engines: { node: ">=24" },
1091
1091
  scripts: { check: "tsc --noEmit", test: "vitest run", verify: "npm run check && npm run test && node .sleepyhollow/verify.ts" },
1092
1092
  dependencies: { "@sleepy-hollow/framework": `^${FRAMEWORK_VERSION}` },
1093
- devDependencies: { typescript: "5.9.3", vitest: "4.1.11" }
1093
+ devDependencies: { "@types/node": "26.2.0", typescript: "5.9.3", vitest: "4.1.11" }
1094
+ },
1095
+ null,
1096
+ 2
1097
+ ) + "\n",
1098
+ "tsconfig.json": JSON.stringify(
1099
+ {
1100
+ compilerOptions: {
1101
+ target: "ES2024",
1102
+ module: "NodeNext",
1103
+ moduleResolution: "NodeNext",
1104
+ strict: true,
1105
+ noEmit: true,
1106
+ allowImportingTsExtensions: true,
1107
+ verbatimModuleSyntax: true,
1108
+ skipLibCheck: true,
1109
+ types: ["node", "vitest/globals"]
1110
+ },
1111
+ include: [
1112
+ ".sleepyhollow/**/*.ts",
1113
+ "api/**/*.ts",
1114
+ "models/**/*.ts",
1115
+ "tests/**/*.ts",
1116
+ "sleepyhollow.config.ts",
1117
+ "vitest.config.ts"
1118
+ ],
1119
+ exclude: ["generated", "node_modules"]
1094
1120
  },
1095
1121
  null,
1096
1122
  2
@@ -1102,15 +1128,20 @@ export default defineConfig({ test: { globals: true, include: ["**/*_test.ts", "
1102
1128
  "generated/.gitkeep": "",
1103
1129
  "models/.gitkeep": "",
1104
1130
  "requirements/application.req.md": `---
1105
- schema: sleepy-hollow-application/v0.1
1131
+ schema: sgad-application/v0.2
1132
+ id: ${name}-application
1106
1133
  title: ${name}
1107
1134
  status: draft
1135
+ risk: standard
1136
+ depends_on: []
1137
+ owners:
1138
+ - application owner
1108
1139
  ---
1109
1140
 
1110
1141
  # Application requirements
1111
1142
 
1112
- Use the official Sleepy Hollow skill to plan actors, behavior, data, security,
1113
- operations, and acceptance criteria before generating endpoints.
1143
+ Use the official Sleepy Hollow skill to replace this planning placeholder with
1144
+ the complete application requirements before generating endpoints.
1114
1145
  `,
1115
1146
  "sleepyhollow.config.ts": `import { defineProject } from "./.sleepyhollow/project.ts";
1116
1147
 
@@ -1142,7 +1173,7 @@ async function pathExists(path) {
1142
1173
  throw error;
1143
1174
  }
1144
1175
  }
1145
- var FRAMEWORK_VERSION = "0.3.2";
1176
+ var FRAMEWORK_VERSION = "0.3.4";
1146
1177
  async function createProject(options) {
1147
1178
  if (!NAME.test(options.name) || options.name.length > 64) {
1148
1179
  throw creationError(
@@ -1328,6 +1359,7 @@ async function startWorker(options, expectedRoutes) {
1328
1359
  const child = workerCommand(options, "serve").spawn();
1329
1360
  const stdout = readFirstLine(child.stdout);
1330
1361
  const stderr = readBounded(child.stderr);
1362
+ const status = child.status;
1331
1363
  let timeout;
1332
1364
  const timer = new Promise((_, reject) => {
1333
1365
  timeout = setTimeout(
@@ -1356,9 +1388,34 @@ async function startWorker(options, expectedRoutes) {
1356
1388
  );
1357
1389
  }
1358
1390
  let stopped = false;
1391
+ const failure3 = new Promise((_, reject) => {
1392
+ void status.then(async (result) => {
1393
+ if (stopped) return;
1394
+ if (result.success) {
1395
+ reject(new DevCommandError([{
1396
+ code: "SH_DEV_WORKER_EXITED",
1397
+ severity: "error",
1398
+ summary: "The development worker exited after becoming active",
1399
+ correction: "Inspect the worker diagnostics and retry."
1400
+ }]));
1401
+ return;
1402
+ }
1403
+ reject(await workerFailure(
1404
+ await stderr,
1405
+ "The development worker failed after becoming active"
1406
+ ));
1407
+ }, async () => {
1408
+ if (stopped) return;
1409
+ reject(await workerFailure(
1410
+ await stderr,
1411
+ "The development worker failed after becoming active"
1412
+ ));
1413
+ });
1414
+ });
1359
1415
  return {
1360
1416
  url: `http://${options.hostname}:${options.port}/`,
1361
1417
  routeCount: expectedRoutes,
1418
+ failure: failure3,
1362
1419
  async stop() {
1363
1420
  if (stopped) return;
1364
1421
  stopped = true;
@@ -1589,6 +1646,7 @@ function failure2(error, fallback) {
1589
1646
  }
1590
1647
  function changedPaths(projectRoot, paths) {
1591
1648
  const normalized = [];
1649
+ const runtimeDatabaseArtifact = /^\.sleepyhollow\/[^/]+\.(?:sqlite|db)(?:-(?:wal|shm))?$/;
1592
1650
  for (const path of paths) {
1593
1651
  const absolute = isAbsolute(path) ? resolve2(path) : resolve2(projectRoot, path);
1594
1652
  const local = relative(projectRoot, absolute).split(sep).join("/");
@@ -1599,7 +1657,7 @@ function changedPaths(projectRoot, paths) {
1599
1657
  "Watch only project-contained application inputs."
1600
1658
  );
1601
1659
  }
1602
- if (local === ".git" || local.startsWith(".git/") || local === "generated" || local.startsWith("generated/") || local.includes("/node_modules/") || /(?:^|\/)(?:\.DS_Store|.*(?:\.swp|~))$/.test(local)) continue;
1660
+ if (local === ".git" || local.startsWith(".git/") || local === "generated" || local.startsWith("generated/") || local.includes("/node_modules/") || runtimeDatabaseArtifact.test(local) || /(?:^|\/)(?:\.DS_Store|.*(?:\.swp|~))$/.test(local)) continue;
1603
1661
  normalized.push(local);
1604
1662
  }
1605
1663
  return Object.freeze([...new Set(normalized)].sort());
@@ -1614,6 +1672,21 @@ function abortReason(signal) {
1614
1672
  }
1615
1673
  return "cancelled";
1616
1674
  }
1675
+ async function nextChange(iterator, active) {
1676
+ const change = iterator.next();
1677
+ if (!active?.failure) return change;
1678
+ return Promise.race([
1679
+ change,
1680
+ active.failure.then(() => {
1681
+ throw new DevCommandError([{
1682
+ code: "SH_DEV_WORKER_EXITED",
1683
+ severity: "error",
1684
+ summary: "The active development worker exited unexpectedly",
1685
+ correction: "Inspect the worker diagnostics and retry."
1686
+ }]);
1687
+ })
1688
+ ]);
1689
+ }
1617
1690
  async function runDevCommand(args, io, suppliedDependencies) {
1618
1691
  const parsed = parse2(args);
1619
1692
  if ("code" in parsed) {
@@ -1735,7 +1808,11 @@ ${parsed.correction}`
1735
1808
  return 1;
1736
1809
  }
1737
1810
  if (signal.aborted) await closeWatcher();
1738
- for await (const paths of watcher) {
1811
+ const iterator = watcher[Symbol.asyncIterator]();
1812
+ while (true) {
1813
+ const next = await nextChange(iterator, active);
1814
+ if (next.done) break;
1815
+ const paths = next.value;
1739
1816
  if (signal.aborted) break;
1740
1817
  const changes = changedPaths(projectRoot, paths);
1741
1818
  if (!Array.isArray(changes)) {
@@ -1888,14 +1965,26 @@ function safeDiagnostic(error, intent) {
1888
1965
  ...typeof item.key === "string" ? { configuration: [item.key] } : {}
1889
1966
  }));
1890
1967
  }
1891
- if (intent === "serve" && (error instanceof platform.errors.AddrInUse || error instanceof platform.errors.PermissionDenied)) {
1968
+ const nodeError = error;
1969
+ const nodeCode = typeof nodeError?.code === "string" ? nodeError.code : void 0;
1970
+ const isListenFailure = error instanceof platform.errors.AddrInUse || error instanceof platform.errors.PermissionDenied || nodeError?.syscall === "listen" || nodeCode === "EADDRINUSE" || nodeCode === "EACCES" || nodeCode === "EPERM";
1971
+ if (intent === "serve" && isListenFailure) {
1892
1972
  return [{
1893
1973
  code: "SH_DEV_BIND_FAILED",
1894
1974
  severity: "error",
1895
- summary: "The loopback listener could not bind",
1975
+ summary: nodeCode ? `The loopback listener failed with ${nodeCode}` : "The loopback listener could not bind",
1896
1976
  correction: "Choose an available port and confirm local network access."
1897
1977
  }];
1898
1978
  }
1979
+ if (intent === "serve") {
1980
+ const cause = error instanceof Error ? `${error.name}: ${error.message}`.replace(/\x1b\[[0-?]*[ -/]*[@-~]/g, "").replace(/(?:Bearer|token|password|secret|authorization)[=: ]+\S+/gi, "$1=[redacted]").replace(/(?:[A-Za-z]:)?\/[^\s]+/g, "[path]").slice(0, 180) : void 0;
1981
+ return [{
1982
+ code: "SH_DEV_SERVE_FAILED",
1983
+ severity: "error",
1984
+ summary: cause ? `The development server failed: ${cause}` : "The development server failed",
1985
+ correction: "Inspect the bounded server diagnostic and retry after repairing the host boundary."
1986
+ }];
1987
+ }
1899
1988
  return [{
1900
1989
  code: "SH_DEV_PROJECT_INVALID",
1901
1990
  severity: "error",
@@ -1967,20 +2056,20 @@ async function runDevWorker(args) {
1967
2056
  const [intent, projectRoot, hostname, rawPort] = args;
1968
2057
  const port = Number(rawPort);
1969
2058
  if (hostname !== "127.0.0.1" || !Number.isInteger(port) || port < 1 || port > 65535) return 2;
2059
+ let server;
1970
2060
  try {
1971
2061
  const { runtime: runtime2, routeCount } = await loadRuntime(projectRoot);
1972
2062
  if (intent === "validate") {
1973
2063
  console.log(JSON.stringify({ ready: true, routeCount }));
1974
2064
  return 0;
1975
2065
  }
1976
- const server = platform.serve({ hostname, port }, (request) => runtime2.fetch(request));
2066
+ server = platform.serve({ hostname, port }, (request) => runtime2.fetch(request));
2067
+ await server.ready;
1977
2068
  console.log(JSON.stringify({ ready: true, routeCount }));
1978
- await new Promise((resolve5, reject) => {
1979
- server.once("close", resolve5);
1980
- server.once("error", reject);
1981
- });
2069
+ await server.finished;
1982
2070
  return 0;
1983
2071
  } catch (error) {
2072
+ await server?.shutdown().catch(() => void 0);
1984
2073
  console.error(
1985
2074
  JSON.stringify({
1986
2075
  ready: false,
@@ -2880,7 +2969,7 @@ function renderArtifacts(inventory2) {
2880
2969
  ];
2881
2970
  const manifestContent = canonicalJson({
2882
2971
  schema: "sleepy-hollow-generated-manifest/v1",
2883
- generatorVersion: "0.3.2",
2972
+ generatorVersion: "0.3.4",
2884
2973
  serviceId: normalized.serviceId,
2885
2974
  inputDigest: digest2(input),
2886
2975
  artifacts: Object.fromEntries(
@@ -3154,7 +3243,7 @@ function inventoryFromRoutes(routes2, options) {
3154
3243
  return {
3155
3244
  serviceId: options.serviceId,
3156
3245
  title: options.title ?? options.serviceId,
3157
- version: options.version ?? "0.3.2",
3246
+ version: options.version ?? "0.3.4",
3158
3247
  ...options.description ? { description: options.description } : {},
3159
3248
  operations,
3160
3249
  securitySchemes: options.securitySchemes ?? {}
@@ -4008,7 +4097,7 @@ var CLI_COMMANDS = [
4008
4097
  "generate",
4009
4098
  "deploy"
4010
4099
  ];
4011
- var CLI_VERSION = "0.3.2";
4100
+ var CLI_VERSION = "0.3.4";
4012
4101
  var commandMetadata = {
4013
4102
  create: {
4014
4103
  description: "Create one deterministic Sleepy Hollow project.",
@@ -5578,7 +5667,8 @@ function declaredStatuses(schemas) {
5578
5667
  function authenticationOf(security2) {
5579
5668
  if (typeof security2 !== "object" || security2 === null) return "none";
5580
5669
  const declared = security2.authentication;
5581
- return declared === "required" ? "required" : "none";
5670
+ if (typeof declared !== "object" || declared === null) return "none";
5671
+ return declared.mode === "required" ? "required" : "none";
5582
5672
  }
5583
5673
  async function routes(project, artifact2) {
5584
5674
  const roots = project.services.length > 0 ? project.services.map((service) => ({