@fourier-labs/harbour 0.1.32 → 0.1.33

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.
@@ -1,4 +1,4 @@
1
- import { readFile, readdir, writeFile } from "node:fs/promises";
1
+ import { readFile, readdir, rm, writeFile } from "node:fs/promises";
2
2
  import { join } from "node:path";
3
3
  import { readAppSchema } from "./app-schema.js";
4
4
  import { describeRetainedChecks, syncRetainedChecks } from "./retained-checks.js";
@@ -128,8 +128,16 @@ export async function runKitGate(root, options) {
128
128
  const done = await request("/_gate/report");
129
129
  if (done?.status === 200) {
130
130
  const result = await done.json();
131
- if (result.report)
131
+ if (result.report) {
132
+ // The app is mounted read-only and the gate works on a mirror, so
133
+ // what it authored for the app to ship comes home here — today the
134
+ // governed-AI inventory (`.harbour/ai-inventory.json`), which the
135
+ // pipeline verifies against the source and which only the gate may
136
+ // write. Written before the caller pins the tree digest, like the
137
+ // regenerated retained checks.
138
+ await writeGateFiles(root, result.files ?? {}, output);
132
139
  return result.report;
140
+ }
133
141
  throw new CliError("LOCAL_RUNTIME_FAILED", `The kit gate could not run: ${result.error ?? "no report"}.`);
134
142
  }
135
143
  if (!(await runtime.gateRunning(container)))
@@ -288,3 +296,19 @@ export async function readReport(root) {
288
296
  function lastLines(text, count = 5) { return text.trim().split("\n").slice(-count).join(" | ").slice(0, 600); }
289
297
  /** A multi-line detail (one gate violation per line) keeps its lines, each under the check name. */
290
298
  function indentLines(detail) { return detail.split("\n").map((line, index) => index ? ` ${line}` : line).join("\n"); }
299
+ /** Files the gate authored for the app (path → content, or null to remove), confined to `.harbour/`. */
300
+ export async function writeGateFiles(root, files, output) {
301
+ for (const [path, content] of Object.entries(files)) {
302
+ if (!/^\.harbour\/[A-Za-z0-9._-]+$/.test(path))
303
+ throw new CliError("LOCAL_RUNTIME_FAILED", `The kit gate named a file outside .harbour/: ${path}.`);
304
+ const target = join(root, path);
305
+ if (content === null) {
306
+ await rm(target, { force: true });
307
+ output(`Removed ${path}: the app no longer needs it.`);
308
+ }
309
+ else {
310
+ await writeFile(target, content);
311
+ output(`Wrote ${path}.`);
312
+ }
313
+ }
314
+ }
@@ -1,6 +1,6 @@
1
1
  export const PUBLISHED_KIT_BUNDLE = {
2
2
  "schema": "harbour.kit-bundle/1.0",
3
- "kitVersion": "0.1.32",
3
+ "kitVersion": "0.1.33",
4
4
  "sdk": {
5
5
  "package": "@harbour/app-sdk",
6
6
  "version": "1.1.0",
@@ -8,8 +8,8 @@ export const PUBLISHED_KIT_BUNDLE = {
8
8
  "url": "https://public.ecr.aws/v2/y6t4p3i8/harbour-kit-bundle/blobs/sha256:3f7ee9d3f7161e8fdb1f7eb89e045c6288a919a72902dbc5bf68ec73e6e578ce"
9
9
  },
10
10
  "images": {
11
- "appGateway": "public.ecr.aws/y6t4p3i8/harbour-app-gateway@sha256:516f56cf83d9b270bd1163914781a216dac6f0dfe1e794150fafaefdd76feaf6",
12
- "sessionFixture": "public.ecr.aws/y6t4p3i8/harbour-session-fixture@sha256:ac894b7490fd97ade2e646d2255bbc5ae8d386e800042ee25f8fc2049e51f5c8"
11
+ "appGateway": "public.ecr.aws/y6t4p3i8/harbour-app-gateway@sha256:7f96a6d1c4f78164d4c4b22fe49e784e87674600bbdae31d8098b2ea6833de11",
12
+ "sessionFixture": "public.ecr.aws/y6t4p3i8/harbour-session-fixture@sha256:573fb296161d57303bddf5e8134de0384ab4e9ae768d81ff09e84d6ef31c58a6"
13
13
  },
14
14
  "brief": {
15
15
  "fingerprint": "4b3c61acdce47995c15e5ce8c38d5e636a624cd79ef7bebb9401b6228d129d11"
@@ -1 +1 @@
1
- export const CLI_VERSION = "0.1.32";
1
+ export const CLI_VERSION = "0.1.33";
@@ -12,8 +12,8 @@ const MAX_FILE_BYTES = 256_000;
12
12
  // application files. Keeping them out also makes reruns idempotent after a
13
13
  // previous save has written a receipt into the selected workspace.
14
14
  const IGNORED_DIRS = new Set([".git", ".harbour", ".next", ".nuxt", ".svelte-kit", ".turbo", "coverage", "dist", "build", "node_modules", "vendor"]);
15
- /** The development kit commits its declaration, lock and journey checks under `.harbour` (see `isKitCommittedPath`); everything else there (local state, checks evidence, generated control files) stays out of the package. */
16
- const KIT_CONTROL_FILES = [".harbour/integrations.json", ".harbour/kit.lock.json"];
15
+ /** The development kit commits its declaration, lock, governed-AI inventory and journey checks under `.harbour` (see `isKitCommittedPath`); everything else there (local state, checks evidence, generated control files) stays out of the package. The inventory is what the pipeline plans a kit app's AI over (data plane 0.78.2.0): the gate writes it under `harbour check`, the lane refuses an app whose source calls governed AI without it. */
16
+ const KIT_CONTROL_FILES = [".harbour/integrations.json", ".harbour/kit.lock.json", ".harbour/ai-inventory.json"];
17
17
  const KIT_CHECKS_DIR = ".harbour/checks";
18
18
  const SECRET_FILE_NAMES = new Set([".env", ".env.local", ".env.production", ".env.development", ".npmrc"]);
19
19
  const TEXT_EXTENSIONS = new Set([".js", ".jsx", ".ts", ".tsx", ".mjs", ".cjs", ".json", ".html", ".css", ".py", ".rb", ".go", ".rs", ".java", ".cs", ".php", ".md", ".toml", ".yaml", ".yml", ".sh"]);
@@ -25,7 +25,7 @@ export function isSourceIntakeExcludedPath(path) {
25
25
  * Everything else there (local state, generated control files) stays local.
26
26
  */
27
27
  export function isKitCommittedPath(path) {
28
- return /(^|\/)\.harbour\/(?:integrations\.json|kit\.lock\.json|checks\/[^/]+\.(?:mjs|js|cjs))$/.test(path);
28
+ return /(^|\/)\.harbour\/(?:integrations\.json|kit\.lock\.json|ai-inventory\.json|checks\/[^/]+\.(?:mjs|js|cjs))$/.test(path);
29
29
  }
30
30
  /** Dependency and internal directories the intake never stages — `.harbour` except its committed kit files. */
31
31
  export function isInternalSourcePath(path) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fourier-labs/harbour",
3
- "version": "0.1.32",
3
+ "version": "0.1.33",
4
4
  "description": "Harbour productionisation helper",
5
5
  "type": "module",
6
6
  "bin": {
@@ -34,7 +34,7 @@
34
34
  "harbour": {
35
35
  "kitBundle": {
36
36
  "repository": "public.ecr.aws/y6t4p3i8/harbour-kit-bundle",
37
- "version": "0.1.32"
37
+ "version": "0.1.33"
38
38
  }
39
39
  }
40
40
  }