@zdreamer/forge 0.1.1 → 0.1.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 (62) hide show
  1. package/README.md +161 -8
  2. package/dist/server/src/app/collection.d.ts +10 -0
  3. package/dist/server/src/app/collection.js +29 -0
  4. package/dist/server/src/app/config.d.ts +12 -0
  5. package/dist/server/src/app/config.js +52 -0
  6. package/dist/server/src/app/http.d.ts +13 -0
  7. package/dist/server/src/app/http.js +19 -0
  8. package/dist/server/src/app/listener.d.ts +9 -0
  9. package/dist/server/src/app/listener.js +61 -0
  10. package/dist/server/src/app/startup.d.ts +16 -0
  11. package/dist/server/src/app/startup.js +60 -0
  12. package/dist/server/src/app/wire.d.ts +11 -0
  13. package/dist/server/src/app/wire.js +29 -0
  14. package/dist/server/src/app/workspace-routes.d.ts +11 -0
  15. package/dist/server/src/app/workspace-routes.js +15 -0
  16. package/dist/server/src/components/api-contract/index.d.ts +1 -0
  17. package/dist/server/src/components/api-contract/internal/types.d.ts +27 -0
  18. package/dist/server/src/components/diagnostic-ui/index.d.ts +1 -0
  19. package/dist/server/src/components/diagnostic-ui/index.js +1 -0
  20. package/dist/server/src/components/diagnostic-ui/internal/page.d.ts +1 -0
  21. package/dist/server/src/components/diagnostic-ui/internal/page.js +129 -0
  22. package/dist/server/src/components/diagnostic-ui/internal/routes.d.ts +2 -0
  23. package/dist/server/src/components/diagnostic-ui/internal/routes.js +11 -0
  24. package/dist/server/src/components/workspace-changes/index.d.ts +2 -0
  25. package/dist/server/src/components/workspace-changes/index.js +1 -0
  26. package/dist/server/src/components/workspace-changes/internal/boundaries.d.ts +3 -0
  27. package/dist/server/src/components/workspace-changes/internal/boundaries.js +56 -0
  28. package/dist/server/src/components/workspace-changes/internal/collect.d.ts +13 -0
  29. package/dist/server/src/components/workspace-changes/internal/collect.js +157 -0
  30. package/dist/server/src/components/workspace-changes/internal/comparison.d.ts +13 -0
  31. package/dist/server/src/components/workspace-changes/internal/comparison.js +229 -0
  32. package/dist/server/src/components/workspace-changes/internal/types.d.ts +10 -0
  33. package/dist/server/src/components/workspace-changes/internal/types.js +1 -0
  34. package/dist/server/src/components/workspace-policy/authoring/index.d.ts +1 -0
  35. package/dist/server/src/components/workspace-policy/authoring/index.js +1 -0
  36. package/dist/{components/workspace-policy → server/src/components/workspace-policy/authoring}/internal/types.d.ts +4 -2
  37. package/dist/server/src/components/workspace-policy/authoring/internal/types.js +1 -0
  38. package/dist/{components → server/src/components}/workspace-policy/index.d.ts +2 -1
  39. package/dist/{components → server/src/components}/workspace-policy/internal/load.d.ts +1 -1
  40. package/dist/{components → server/src/components}/workspace-policy/internal/load.js +3 -0
  41. package/dist/{components → server/src/components}/workspace-policy/internal/repositories.d.ts +3 -2
  42. package/dist/{components → server/src/components}/workspace-policy/internal/repositories.js +12 -6
  43. package/dist/server/src/lib/git/index.d.ts +2 -0
  44. package/dist/server/src/lib/git/index.js +1 -0
  45. package/dist/server/src/lib/git/internal/process.d.ts +16 -0
  46. package/dist/server/src/lib/git/internal/process.js +166 -0
  47. package/dist/server/src/lib/loopback-access/index.d.ts +1 -0
  48. package/dist/server/src/lib/loopback-access/index.js +1 -0
  49. package/dist/server/src/lib/loopback-access/internal/request-guard.d.ts +9 -0
  50. package/dist/server/src/lib/loopback-access/internal/request-guard.js +17 -0
  51. package/dist/server/src/main.js +33 -0
  52. package/dist/server/src/workspace.d.ts +1 -0
  53. package/dist/server/src/workspace.js +1 -0
  54. package/package.json +10 -5
  55. package/dist/main.js +0 -23
  56. package/dist/workspace.d.ts +0 -1
  57. /package/dist/{app → server/src/app}/inspect.d.ts +0 -0
  58. /package/dist/{app → server/src/app}/inspect.js +0 -0
  59. /package/dist/{components/workspace-policy/internal/types.js → server/src/components/api-contract/index.js} +0 -0
  60. /package/dist/{workspace.js → server/src/components/api-contract/internal/types.js} +0 -0
  61. /package/dist/{components → server/src/components}/workspace-policy/index.js +0 -0
  62. /package/dist/{main.d.ts → server/src/main.d.ts} +0 -0
@@ -5,7 +5,7 @@ export interface RepositoryDeclaration {
5
5
  export interface WorkspaceChange {
6
6
  readonly repo: string;
7
7
  readonly path: string;
8
- readonly kind: "added" | "modified" | "deleted" | "renamed" | "copied" | "type_changed";
8
+ readonly kind: "added" | "modified" | "deleted" | "renamed";
9
9
  readonly from?: string;
10
10
  }
11
11
  /** Identity is concrete; several codebases may share the same guidance folder. */
@@ -17,9 +17,11 @@ export interface CodebaseContext {
17
17
  * Trusted project code, called explicitly after loading. Forge probes only
18
18
  * declared repositories; missing locations are skipped, not configuration errors.
19
19
  * Routing is synchronous, side-effect-free and must handle absent
20
- * files lexically. Rename/copy membership includes both old and new paths.
20
+ * files lexically. Rename membership includes both old and new paths.
21
21
  */
22
22
  export interface WorkspacePolicy {
23
+ /** Literal display text; omission uses the canonical workspace root basename. */
24
+ readonly displayName?: string;
23
25
  readonly repositories: readonly RepositoryDeclaration[];
24
26
  codebasesForChange(change: WorkspaceChange): readonly CodebaseContext[];
25
27
  }
@@ -1,3 +1,4 @@
1
+ export type { CodebaseContext, RepositoryDeclaration, WorkspaceChange, WorkspacePolicy, } from "./authoring/index.ts";
1
2
  export { loadWorkspacePolicy } from "./internal/load.ts";
3
+ export type { RepositoryResolution } from "./internal/repositories.ts";
2
4
  export { resolveRepositories } from "./internal/repositories.ts";
3
- export type { CodebaseContext, RepositoryDeclaration, WorkspaceChange, WorkspacePolicy, } from "./internal/types.ts";
@@ -1,3 +1,3 @@
1
- import type { WorkspacePolicy } from "./types.ts";
1
+ import type { WorkspacePolicy } from "../authoring/index.ts";
2
2
  /** Imports execute trusted workspace code; this is not a sandbox or hot loader. */
3
3
  export declare function loadWorkspacePolicy(absolutePath: string): Promise<WorkspacePolicy>;
@@ -20,6 +20,9 @@ export async function loadWorkspacePolicy(absolutePath) {
20
20
  typeof policy.codebasesForChange !== "function") {
21
21
  throw new TypeError("Workspace module must default-export a WorkspacePolicy");
22
22
  }
23
+ if ("displayName" in policy && (typeof policy.displayName !== "string" || policy.displayName.length === 0)) {
24
+ throw new TypeError("Workspace displayName must be a nonempty string");
25
+ }
23
26
  const paths = new Set();
24
27
  for (const repository of policy.repositories) {
25
28
  if (typeof repository !== "object" ||
@@ -1,4 +1,5 @@
1
- import type { RepositoryDeclaration } from "./types.ts";
1
+ import { type GitProcess } from "../../../lib/git/index.ts";
2
+ import type { RepositoryDeclaration } from "../authoring/index.ts";
2
3
  export declare function validRepositoryPath(path: string): boolean;
3
4
  export type RepositoryResolution = {
4
5
  readonly path: string;
@@ -9,4 +10,4 @@ export type RepositoryResolution = {
9
10
  readonly status: "missing";
10
11
  };
11
12
  /** Explicit startup/reload probe, never a recursive scan or change-list poll. */
12
- export declare function resolveRepositories(workspaceRoot: string, declarations: readonly RepositoryDeclaration[]): Promise<readonly RepositoryResolution[]>;
13
+ export declare function resolveRepositories(workspaceRoot: string, declarations: readonly RepositoryDeclaration[], git: GitProcess): Promise<readonly RepositoryResolution[]>;
@@ -1,8 +1,6 @@
1
- import { execFile } from "node:child_process";
2
1
  import { realpath, stat } from "node:fs/promises";
3
2
  import { isAbsolute, relative, resolve, sep } from "node:path";
4
- import { promisify } from "node:util";
5
- const execute = promisify(execFile);
3
+ import { gitFailure } from "../../../lib/git/index.js";
6
4
  export function validRepositoryPath(path) {
7
5
  return (path === "." ||
8
6
  (path.length > 0 &&
@@ -12,7 +10,7 @@ export function validRepositoryPath(path) {
12
10
  path.split("/").every((part) => part !== "" && part !== "." && part !== "..")));
13
11
  }
14
12
  /** Explicit startup/reload probe, never a recursive scan or change-list poll. */
15
- export async function resolveRepositories(workspaceRoot, declarations) {
13
+ export async function resolveRepositories(workspaceRoot, declarations, git) {
16
14
  const root = await realpath(workspaceRoot);
17
15
  const results = [];
18
16
  const seen = new Set();
@@ -40,8 +38,16 @@ export async function resolveRepositories(workspaceRoot, declarations) {
40
38
  if (isAbsolute(within) || within === ".." || within.startsWith(`..${sep}`)) {
41
39
  throw new Error(`Declared repository escapes workspace root: ${path}`);
42
40
  }
43
- const { stdout } = await execute("git", ["-C", directory, "rev-parse", "--show-toplevel"]);
44
- const gitRoot = await realpath(stdout.trim());
41
+ const result = await git(directory, ["rev-parse", "--show-toplevel"]);
42
+ if (result.code !== 0)
43
+ throw gitFailure(`repository probe (${path})`, result);
44
+ if (result.stdout.at(-1) !== 10)
45
+ throw new Error("Git returned an invalid repository root");
46
+ const gitRoot = await realpath(new TextDecoder("utf-8", { fatal: true }).decode(result.stdout.subarray(0, -1)));
47
+ const fromGitRoot = relative(gitRoot, directory);
48
+ if (isAbsolute(fromGitRoot) || fromGitRoot === ".." || fromGitRoot.startsWith(`..${sep}`)) {
49
+ throw new Error(`Git root does not contain workspace: ${path}`);
50
+ }
45
51
  // '.' intentionally permits a Git root above the selected workspace.
46
52
  if (path !== "." && gitRoot !== directory) {
47
53
  throw new Error(`Declared nested repository resolves to another Git root: ${path}`);
@@ -0,0 +1,2 @@
1
+ export type { GitProcess, GitResult } from "./internal/process.ts";
2
+ export { createGitProcess, gitFailure, preflightRepository } from "./internal/process.ts";
@@ -0,0 +1 @@
1
+ export { createGitProcess, gitFailure, preflightRepository } from "./internal/process.js";
@@ -0,0 +1,16 @@
1
+ export type GitResult = {
2
+ code: number;
3
+ stdout: Buffer;
4
+ stderr: Buffer;
5
+ };
6
+ export type GitProcess = (cwd: string, args: readonly string[], options?: {
7
+ signal?: AbortSignal;
8
+ timeoutMs?: number;
9
+ maxOutputBytes?: number;
10
+ input?: Buffer;
11
+ }) => Promise<GitResult>;
12
+ /** Keep deliberate config isolation while ignoring ambient checkout/index redirection. */
13
+ export declare function createGitProcess(environment: Readonly<NodeJS.ProcessEnv>): GitProcess;
14
+ export declare function gitFailure(operation: string, result: GitResult): Error;
15
+ /** Refuse incomplete object stores before commands can request missing objects. Trusted filters remain enabled. */
16
+ export declare function preflightRepository(git: GitProcess, cwd: string, signal?: AbortSignal, objectPath?: string): Promise<void>;
@@ -0,0 +1,166 @@
1
+ import { spawn } from "node:child_process";
2
+ import { readdir } from "node:fs/promises";
3
+ import { isAbsolute, join, resolve } from "node:path";
4
+ /** Keep deliberate config isolation while ignoring ambient checkout/index redirection. */
5
+ export function createGitProcess(environment) {
6
+ const env = {};
7
+ const configIsolation = new Set([
8
+ "GIT_CONFIG_GLOBAL",
9
+ "GIT_CONFIG_SYSTEM",
10
+ "GIT_CONFIG_NOSYSTEM",
11
+ "GIT_ATTR_NOSYSTEM",
12
+ ]);
13
+ for (const [name, value] of Object.entries(environment)) {
14
+ if (!name.startsWith("GIT_") || configIsolation.has(name))
15
+ env[name] = value;
16
+ }
17
+ Object.assign(env, { GIT_OPTIONAL_LOCKS: "0", GIT_NO_LAZY_FETCH: "1", GIT_TERMINAL_PROMPT: "0", LC_ALL: "C" });
18
+ return (cwd, args, options = {}) => new Promise((resolve, reject) => {
19
+ if (options.signal?.aborted) {
20
+ reject(options.signal.reason ?? new Error("Git operation aborted"));
21
+ return;
22
+ }
23
+ if ((options.input?.length ?? 0) > 16 * 1024 * 1024) {
24
+ reject(new Error("Git input exceeded the collection limit"));
25
+ return;
26
+ }
27
+ const child = spawn("git", [
28
+ "--no-optional-locks",
29
+ "-c",
30
+ "core.fsmonitor=false",
31
+ "-c",
32
+ "core.hooksPath=/dev/null",
33
+ "-c",
34
+ "gc.auto=0",
35
+ "-c",
36
+ "maintenance.auto=false",
37
+ "-c",
38
+ "diff.autoRefreshIndex=false",
39
+ ...args,
40
+ ], { cwd, env, detached: true, stdio: ["pipe", "pipe", "pipe"] });
41
+ const stdout = [];
42
+ const stderr = [];
43
+ let size = 0;
44
+ let failure;
45
+ let killTimer;
46
+ let closed = false;
47
+ let exitCode = null;
48
+ const signalGroup = (signal) => {
49
+ if (!child.pid)
50
+ return false;
51
+ try {
52
+ process.kill(-child.pid, signal);
53
+ return true;
54
+ }
55
+ catch (error) {
56
+ if (error.code !== "ESRCH")
57
+ failure ??= error;
58
+ return false;
59
+ }
60
+ };
61
+ const settle = () => {
62
+ if (!closed || killTimer)
63
+ return;
64
+ clearTimeout(timer);
65
+ options.signal?.removeEventListener("abort", abort);
66
+ if (failure)
67
+ reject(failure);
68
+ else if (exitCode === null)
69
+ reject(new Error("Git process terminated"));
70
+ else
71
+ resolve({ code: exitCode, stdout: Buffer.concat(stdout), stderr: Buffer.concat(stderr) });
72
+ };
73
+ const terminate = () => {
74
+ if (killTimer || !signalGroup("SIGTERM"))
75
+ return;
76
+ // A filter may outlive Git or ignore TERM. Keep the group escalation even after Git closes.
77
+ killTimer = setTimeout(() => {
78
+ signalGroup("SIGKILL");
79
+ killTimer = undefined;
80
+ settle();
81
+ }, 250);
82
+ };
83
+ const stop = (error) => {
84
+ if (failure)
85
+ return;
86
+ failure = error;
87
+ terminate();
88
+ };
89
+ const abort = () => stop(new Error("Git operation aborted", { cause: options.signal?.reason }));
90
+ const timer = setTimeout(() => stop(new Error(`Git command timed out (${args[0] ?? "unknown"})`)), options.timeoutMs ?? 30_000);
91
+ options.signal?.addEventListener("abort", abort, { once: true });
92
+ if (options.signal?.aborted)
93
+ abort();
94
+ const consume = (chunks, chunk) => {
95
+ size += chunk.length;
96
+ if (size > Math.min(options.maxOutputBytes ?? 16 * 1024 * 1024, 16 * 1024 * 1024))
97
+ stop(new Error("Git output exceeded the collection limit"));
98
+ else if (!failure)
99
+ chunks.push(chunk);
100
+ };
101
+ child.stdout.on("data", (chunk) => consume(stdout, chunk));
102
+ child.stderr.on("data", (chunk) => consume(stderr, chunk));
103
+ child.stdin.on("error", (error) => {
104
+ // A command can reject its arguments and close stdin before consuming the supplied bytes.
105
+ if (error.code !== "EPIPE" && error.code !== "ERR_STREAM_DESTROYED")
106
+ stop(error);
107
+ });
108
+ child.stdin.end(options.input);
109
+ child.on("error", (error) => {
110
+ failure ??= error;
111
+ });
112
+ child.on("close", (code) => {
113
+ clearTimeout(timer);
114
+ closed = true;
115
+ exitCode = code;
116
+ terminate();
117
+ settle();
118
+ });
119
+ });
120
+ }
121
+ export function gitFailure(operation, result) {
122
+ const detail = result.stderr
123
+ .subarray(0, 1000)
124
+ .toString("utf8")
125
+ .replace(/\p{Cc}/gu, " ")
126
+ .trim();
127
+ return new Error(`Git ${operation} failed (${result.code})${detail ? `: ${detail}` : ""}`);
128
+ }
129
+ /** Refuse incomplete object stores before commands can request missing objects. Trusted filters remain enabled. */
130
+ export async function preflightRepository(git, cwd, signal, objectPath) {
131
+ const result = await git(cwd, ["config", "--null", "--list"], { signal });
132
+ if (result.code !== 0)
133
+ throw gitFailure("configuration inspection", result);
134
+ const text = new TextDecoder("utf-8", { fatal: true }).decode(result.stdout);
135
+ if (text && !text.endsWith("\0"))
136
+ throw new Error("Git returned truncated configuration");
137
+ for (const record of text.split("\0").slice(0, -1)) {
138
+ const separator = record.indexOf("\n");
139
+ const key = (separator < 0 ? record : record.slice(0, separator)).toLowerCase();
140
+ const value = separator < 0 ? "" : record.slice(separator + 1);
141
+ if (key === "extensions.partialclone" ||
142
+ (/^remote\..+\.promisor$/s.test(key) && !/^(false|no|off|0)$/i.test(value.trim()))) {
143
+ throw new Error("Partial/promisor repositories are unsupported for read-only collection");
144
+ }
145
+ }
146
+ let path = objectPath;
147
+ if (path === undefined) {
148
+ const location = await git(cwd, ["rev-parse", "--path-format=absolute", "--git-path", "objects"], { signal });
149
+ if (location.code !== 0)
150
+ throw gitFailure("object-store location", location);
151
+ path = new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(location.stdout).replace(/\n$/, "");
152
+ }
153
+ if (!path || path.includes("\0"))
154
+ throw new Error("Git returned an invalid object-store location");
155
+ const objects = isAbsolute(path) ? path : resolve(cwd, path);
156
+ try {
157
+ const names = await readdir(join(objects, "pack"));
158
+ if (names.some((name) => name.endsWith(".promisor"))) {
159
+ throw new Error("Partial/promisor repositories are unsupported for read-only collection");
160
+ }
161
+ }
162
+ catch (error) {
163
+ if (error.code !== "ENOENT")
164
+ throw error;
165
+ }
166
+ }
@@ -0,0 +1 @@
1
+ export { AccessRejectedError, createRequestGuard } from "./internal/request-guard.ts";
@@ -0,0 +1 @@
1
+ export { AccessRejectedError, createRequestGuard } from "./internal/request-guard.js";
@@ -0,0 +1,9 @@
1
+ import type { MiddlewareHandler } from "hono";
2
+ export declare class AccessRejectedError extends Error {
3
+ constructor();
4
+ }
5
+ type Deps = {
6
+ port: number;
7
+ };
8
+ export declare function createRequestGuard({ port }: Deps): MiddlewareHandler;
9
+ export {};
@@ -0,0 +1,17 @@
1
+ export class AccessRejectedError extends Error {
2
+ constructor() {
3
+ super("Request forbidden");
4
+ this.name = "AccessRejectedError";
5
+ }
6
+ }
7
+ export function createRequestGuard({ port }) {
8
+ const host = `127.0.0.1:${port}`;
9
+ const origin = `http://${host}`;
10
+ return async (context, next) => {
11
+ const headers = context.req.raw.headers;
12
+ if (headers.get("host") !== host || (headers.has("origin") && headers.get("origin") !== origin)) {
13
+ throw new AccessRejectedError();
14
+ }
15
+ await next();
16
+ };
17
+ }
@@ -0,0 +1,33 @@
1
+ #!/usr/bin/env node
2
+ import { readFile } from "node:fs/promises";
3
+ import { findPackageJSON } from "node:module";
4
+ import { fileURLToPath } from "node:url";
5
+ import { inspect } from "./app/inspect.js";
6
+ import { start } from "./app/startup.js";
7
+ const usage = "forge serve --workspace <path>\nforge inspect-workspace <workspace.ts> <repository> <path> [previous-path]";
8
+ const [command, ...args] = process.argv.slice(2);
9
+ try {
10
+ if (command === "--help" || command === undefined) {
11
+ console.log(usage);
12
+ }
13
+ else if (command === "serve" && args.length === 2 && args[0] === "--workspace" && args[1] !== "") {
14
+ const manifestPath = findPackageJSON(import.meta.url);
15
+ if (manifestPath === undefined)
16
+ throw new Error("Forge package manifest was not found");
17
+ const manifest = JSON.parse(await readFile(manifestPath, "utf8"));
18
+ const server = await start({ workspace: args[1], cwd: process.cwd(), env: process.env });
19
+ console.log(`Forge @zdreamer/forge ${manifest.version}\nExecutable: ${JSON.stringify(fileURLToPath(import.meta.url))}\nWorkspace: ${JSON.stringify(server.snapshot.root)}\n${server.address}`);
20
+ }
21
+ else if (command === "inspect-workspace" && (args.length === 3 || args.length === 4)) {
22
+ const [modulePath, repo, path, from] = args;
23
+ console.log(JSON.stringify(await inspect(modulePath, repo, path, from)));
24
+ }
25
+ else {
26
+ console.error(`Usage: ${usage}`);
27
+ process.exitCode = 1;
28
+ }
29
+ }
30
+ catch (error) {
31
+ console.error(error instanceof Error ? error.message : String(error));
32
+ process.exitCode = 1;
33
+ }
@@ -0,0 +1 @@
1
+ export type { CodebaseContext, RepositoryDeclaration, WorkspaceChange, WorkspacePolicy, } from "./components/workspace-policy/authoring/index.ts";
@@ -0,0 +1 @@
1
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zdreamer/forge",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "Forge workspace application and typed workspace policy contract",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -17,12 +17,12 @@
17
17
  "dist/"
18
18
  ],
19
19
  "bin": {
20
- "forge": "./dist/main.js"
20
+ "forge": "./dist/server/src/main.js"
21
21
  },
22
22
  "exports": {
23
23
  "./workspace": {
24
- "types": "./dist/workspace.d.ts",
25
- "default": "./dist/workspace.js"
24
+ "types": "./dist/server/src/workspace.d.ts",
25
+ "default": "./dist/server/src/workspace.js"
26
26
  }
27
27
  },
28
28
  "engines": {
@@ -31,7 +31,8 @@
31
31
  "packageManager": "pnpm@11.15.1",
32
32
  "scripts": {
33
33
  "build": "node --input-type=module -e \"import { rmSync } from 'node:fs'; rmSync('dist', { recursive: true, force: true })\" && tsc -p tsconfig.build.json",
34
- "check": "tsc --noEmit && biome check . && depcruise --config .dependency-cruiser.mjs 'src/**/*.ts' && node --test",
34
+ "check": "tsc --noEmit && biome check . && corepack pnpm --config.verify-deps-before-run=error run check:server && depcruise --config .dependency-cruiser.mjs server/src ui/src && node --test tools/*.test.ts",
35
+ "check:server": "tsc -p server/tsconfig.json --noEmit && tsc -p server/tsconfig.contract.json --noEmit && biome check server && cd server && depcruise --config .dependency-cruiser.mjs 'src/**/*.ts' && node --test",
35
36
  "test:workspace": "node tools/workspace-consumer.ts"
36
37
  },
37
38
  "devDependencies": {
@@ -41,5 +42,9 @@
41
42
  "@zdreamer/forge-ts-service": "0.1.1",
42
43
  "dependency-cruiser": "18.2.0",
43
44
  "typescript": "7.0.2"
45
+ },
46
+ "dependencies": {
47
+ "@hono/node-server": "2.1.4",
48
+ "hono": "4.13.13"
44
49
  }
45
50
  }
package/dist/main.js DELETED
@@ -1,23 +0,0 @@
1
- #!/usr/bin/env node
2
- import { inspect } from "./app/inspect.js";
3
- const [command, modulePath, repo, path, from, ...extra] = process.argv.slice(2);
4
- if (command === "--help" || command === undefined) {
5
- console.log("forge inspect-workspace <workspace.ts> <repository> <path> [previous-path]");
6
- }
7
- else if (command !== "inspect-workspace" ||
8
- modulePath === undefined ||
9
- repo === undefined ||
10
- path === undefined ||
11
- extra.length > 0) {
12
- console.error("Usage: forge inspect-workspace <workspace.ts> <repository> <path> [previous-path]");
13
- process.exitCode = 1;
14
- }
15
- else {
16
- try {
17
- console.log(JSON.stringify(await inspect(modulePath, repo, path, from)));
18
- }
19
- catch (error) {
20
- console.error(error instanceof Error ? error.message : String(error));
21
- process.exitCode = 1;
22
- }
23
- }
@@ -1 +0,0 @@
1
- export type { CodebaseContext, RepositoryDeclaration, WorkspaceChange, WorkspacePolicy, } from "./components/workspace-policy/index.ts";
File without changes
File without changes
File without changes