portweave 0.1.0
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/LICENSE +21 -0
- package/README.md +535 -0
- package/dist/allocator/allocate.concurrent.d.ts +3 -0
- package/dist/allocator/allocate.concurrent.d.ts.map +1 -0
- package/dist/allocator/allocate.concurrent.js +10 -0
- package/dist/allocator/allocate.concurrent.js.map +1 -0
- package/dist/allocator/allocate.d.ts +20 -0
- package/dist/allocator/allocate.d.ts.map +1 -0
- package/dist/allocator/allocate.js +106 -0
- package/dist/allocator/allocate.js.map +1 -0
- package/dist/allocator/cross-project.d.ts +2 -0
- package/dist/allocator/cross-project.d.ts.map +1 -0
- package/dist/allocator/cross-project.js +9 -0
- package/dist/allocator/cross-project.js.map +1 -0
- package/dist/allocator/order.d.ts +2 -0
- package/dist/allocator/order.d.ts.map +1 -0
- package/dist/allocator/order.js +8 -0
- package/dist/allocator/order.js.map +1 -0
- package/dist/allocator/pool.d.ts +35 -0
- package/dist/allocator/pool.d.ts.map +1 -0
- package/dist/allocator/pool.js +74 -0
- package/dist/allocator/pool.js.map +1 -0
- package/dist/allocator/probe.d.ts +22 -0
- package/dist/allocator/probe.d.ts.map +1 -0
- package/dist/allocator/probe.js +40 -0
- package/dist/allocator/probe.js.map +1 -0
- package/dist/cli/banner.d.ts +25 -0
- package/dist/cli/banner.d.ts.map +1 -0
- package/dist/cli/banner.js +61 -0
- package/dist/cli/banner.js.map +1 -0
- package/dist/cli/run.d.ts +15 -0
- package/dist/cli/run.d.ts.map +1 -0
- package/dist/cli/run.js +156 -0
- package/dist/cli/run.js.map +1 -0
- package/dist/cli/show.d.ts +21 -0
- package/dist/cli/show.d.ts.map +1 -0
- package/dist/cli/show.js +141 -0
- package/dist/cli/show.js.map +1 -0
- package/dist/cli/spawn.d.ts +30 -0
- package/dist/cli/spawn.d.ts.map +1 -0
- package/dist/cli/spawn.js +85 -0
- package/dist/cli/spawn.js.map +1 -0
- package/dist/cli.d.ts +5 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +52 -0
- package/dist/cli.js.map +1 -0
- package/dist/config/anonymous.d.ts +5 -0
- package/dist/config/anonymous.d.ts.map +1 -0
- package/dist/config/anonymous.js +21 -0
- package/dist/config/anonymous.js.map +1 -0
- package/dist/config/index.d.ts +4 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +4 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/loader.d.ts +8 -0
- package/dist/config/loader.d.ts.map +1 -0
- package/dist/config/loader.js +59 -0
- package/dist/config/loader.js.map +1 -0
- package/dist/config/schema.d.ts +21 -0
- package/dist/config/schema.d.ts.map +1 -0
- package/dist/config/schema.js +125 -0
- package/dist/config/schema.js.map +1 -0
- package/dist/env/build.d.ts +4 -0
- package/dist/env/build.d.ts.map +1 -0
- package/dist/env/build.js +17 -0
- package/dist/env/build.js.map +1 -0
- package/dist/env/dotenv-merge.d.ts +5 -0
- package/dist/env/dotenv-merge.d.ts.map +1 -0
- package/dist/env/dotenv-merge.js +73 -0
- package/dist/env/dotenv-merge.js.map +1 -0
- package/dist/env/index.d.ts +4 -0
- package/dist/env/index.d.ts.map +1 -0
- package/dist/env/index.js +4 -0
- package/dist/env/index.js.map +1 -0
- package/dist/env/resolve.d.ts +11 -0
- package/dist/env/resolve.d.ts.map +1 -0
- package/dist/env/resolve.js +29 -0
- package/dist/env/resolve.js.map +1 -0
- package/dist/env/templates.d.ts +2 -0
- package/dist/env/templates.d.ts.map +1 -0
- package/dist/env/templates.js +11 -0
- package/dist/env/templates.js.map +1 -0
- package/dist/env/writer.d.ts +6 -0
- package/dist/env/writer.d.ts.map +1 -0
- package/dist/env/writer.js +68 -0
- package/dist/env/writer.js.map +1 -0
- package/dist/errors.d.ts +22 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +32 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/dist/registry/atomic-write.d.ts +3 -0
- package/dist/registry/atomic-write.d.ts.map +1 -0
- package/dist/registry/atomic-write.js +43 -0
- package/dist/registry/atomic-write.js.map +1 -0
- package/dist/registry/lock.d.ts +4 -0
- package/dist/registry/lock.d.ts.map +1 -0
- package/dist/registry/lock.js +86 -0
- package/dist/registry/lock.js.map +1 -0
- package/dist/registry/paths.d.ts +7 -0
- package/dist/registry/paths.d.ts.map +1 -0
- package/dist/registry/paths.js +13 -0
- package/dist/registry/paths.js.map +1 -0
- package/dist/registry/prune.d.ts +3 -0
- package/dist/registry/prune.d.ts.map +1 -0
- package/dist/registry/prune.js +24 -0
- package/dist/registry/prune.js.map +1 -0
- package/dist/registry/serialize.d.ts +6 -0
- package/dist/registry/serialize.d.ts.map +1 -0
- package/dist/registry/serialize.js +134 -0
- package/dist/registry/serialize.js.map +1 -0
- package/dist/registry/storage.concurrent.d.ts +3 -0
- package/dist/registry/storage.concurrent.d.ts.map +1 -0
- package/dist/registry/storage.concurrent.js +10 -0
- package/dist/registry/storage.concurrent.js.map +1 -0
- package/dist/registry/storage.d.ts +11 -0
- package/dist/registry/storage.d.ts.map +1 -0
- package/dist/registry/storage.js +101 -0
- package/dist/registry/storage.js.map +1 -0
- package/dist/registry/types.d.ts +14 -0
- package/dist/registry/types.d.ts.map +1 -0
- package/dist/registry/types.js +2 -0
- package/dist/registry/types.js.map +1 -0
- package/dist/result.d.ts +11 -0
- package/dist/result.d.ts.map +1 -0
- package/dist/result.js +6 -0
- package/dist/result.js.map +1 -0
- package/dist/runtime/error-passthrough.d.ts +20 -0
- package/dist/runtime/error-passthrough.d.ts.map +1 -0
- package/dist/runtime/error-passthrough.js +20 -0
- package/dist/runtime/error-passthrough.js.map +1 -0
- package/dist/runtime/exports-smoke.d.ts +4 -0
- package/dist/runtime/exports-smoke.d.ts.map +1 -0
- package/dist/runtime/exports-smoke.js +36 -0
- package/dist/runtime/exports-smoke.js.map +1 -0
- package/dist/runtime/index.d.ts +15 -0
- package/dist/runtime/index.d.ts.map +1 -0
- package/dist/runtime/index.js +99 -0
- package/dist/runtime/index.js.map +1 -0
- package/dist/runtime/upward-walk.d.ts +14 -0
- package/dist/runtime/upward-walk.d.ts.map +1 -0
- package/dist/runtime/upward-walk.js +39 -0
- package/dist/runtime/upward-walk.js.map +1 -0
- package/dist/worktree/git.d.ts +13 -0
- package/dist/worktree/git.d.ts.map +1 -0
- package/dist/worktree/git.js +66 -0
- package/dist/worktree/git.js.map +1 -0
- package/dist/worktree/key.d.ts +10 -0
- package/dist/worktree/key.d.ts.map +1 -0
- package/dist/worktree/key.js +38 -0
- package/dist/worktree/key.js.map +1 -0
- package/dist/worktree/namespace.d.ts +8 -0
- package/dist/worktree/namespace.d.ts.map +1 -0
- package/dist/worktree/namespace.js +58 -0
- package/dist/worktree/namespace.js.map +1 -0
- package/package.json +109 -0
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type Allocation } from '../allocator/allocate.ts';
|
|
2
|
+
import { PortweaveError } from '../errors.ts';
|
|
3
|
+
import { type Result } from '../result.ts';
|
|
4
|
+
export interface PortsOptions {
|
|
5
|
+
/** Explicit config path; bypasses upward-walk discovery. Resolved against `cwd` if relative. */
|
|
6
|
+
readonly configPath?: string;
|
|
7
|
+
/** Anonymous-mode fallback. If no `portweave.config.json` is found AND `count` is provided, synthesize a config with N services (`port-1`..`port-N` / `PORT_1`..`PORT_N`). */
|
|
8
|
+
readonly count?: number;
|
|
9
|
+
/** Working directory used for worktree-key resolution and config discovery. Defaults to `process.cwd()`. */
|
|
10
|
+
readonly cwd?: string;
|
|
11
|
+
}
|
|
12
|
+
export declare function allocation(opts?: PortsOptions): Promise<Result<Allocation, PortweaveError>>;
|
|
13
|
+
export declare function env(opts?: PortsOptions): Promise<Result<Record<string, string>, PortweaveError>>;
|
|
14
|
+
export declare function ports(opts?: PortsOptions): Promise<Result<Record<string, number>, PortweaveError>>;
|
|
15
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/runtime/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAY,KAAK,UAAU,EAAE,MAAM,0BAA0B,CAAA;AAOpE,OAAO,EAAE,cAAc,EAAkB,MAAM,cAAc,CAAA;AAC7D,OAAO,EAAW,KAAK,MAAM,EAAE,MAAM,cAAc,CAAA;AAInD,MAAM,WAAW,YAAY;IAC3B,gGAAgG;IAChG,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAA;IAC5B,8KAA8K;IAC9K,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAA;IACvB,4GAA4G;IAC5G,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CACtB;AAuGD,wBAAsB,UAAU,CAC9B,IAAI,CAAC,EAAE,YAAY,GAClB,OAAO,CAAC,MAAM,CAAC,UAAU,EAAE,cAAc,CAAC,CAAC,CAM7C;AAED,wBAAsB,GAAG,CACvB,IAAI,CAAC,EAAE,YAAY,GAClB,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,cAAc,CAAC,CAAC,CAMzD;AAED,wBAAsB,KAAK,CACzB,IAAI,CAAC,EAAE,YAAY,GAClB,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,cAAc,CAAC,CAAC,CAMzD"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { dirname, resolve as resolvePath } from 'node:path';
|
|
2
|
+
import { allocate } from "../allocator/allocate.js";
|
|
3
|
+
import { loadConfig, synthesizeAnonymousConfig, } from "../config/index.js";
|
|
4
|
+
import { resolveEnv } from "../env/index.js";
|
|
5
|
+
import { PortweaveError, PW_ERROR_CODES } from "../errors.js";
|
|
6
|
+
import { err, ok } from "../result.js";
|
|
7
|
+
import { resolveAllocationKey } from "../worktree/key.js";
|
|
8
|
+
import { CONFIG_FILENAME, findConfigUpward } from "./upward-walk.js";
|
|
9
|
+
async function resolveConfigForRuntime(cwd, opts) {
|
|
10
|
+
// Explicit configPath wins — no upward walk.
|
|
11
|
+
if (opts?.configPath !== undefined) {
|
|
12
|
+
const absConfigPath = resolvePath(cwd, opts.configPath);
|
|
13
|
+
const loaded = await loadConfig(dirname(absConfigPath), {
|
|
14
|
+
configPath: absConfigPath,
|
|
15
|
+
});
|
|
16
|
+
if (!loaded.ok) {
|
|
17
|
+
return loaded;
|
|
18
|
+
}
|
|
19
|
+
return ok({ config: loaded.value, projectRoot: dirname(absConfigPath) });
|
|
20
|
+
}
|
|
21
|
+
// Upward walk: cwd → parent → ... → filesystem root.
|
|
22
|
+
const found = await findConfigUpward(cwd);
|
|
23
|
+
if (found !== null) {
|
|
24
|
+
const loaded = await loadConfig(found.dir, {
|
|
25
|
+
configPath: CONFIG_FILENAME,
|
|
26
|
+
});
|
|
27
|
+
if (!loaded.ok) {
|
|
28
|
+
return loaded;
|
|
29
|
+
}
|
|
30
|
+
return ok({ config: loaded.value, projectRoot: found.dir });
|
|
31
|
+
}
|
|
32
|
+
// No config file found. Anonymous fallback if `count` is provided.
|
|
33
|
+
if (opts?.count !== undefined) {
|
|
34
|
+
const anon = synthesizeAnonymousConfig(opts.count);
|
|
35
|
+
if (!anon.ok) {
|
|
36
|
+
return anon;
|
|
37
|
+
}
|
|
38
|
+
return ok({ config: anon.value, projectRoot: cwd });
|
|
39
|
+
}
|
|
40
|
+
// Neither config file nor `count` provided — typed error.
|
|
41
|
+
return err(new PortweaveError(PW_ERROR_CODES.RUNTIME_CONFIG_NOT_FOUND, `no ${CONFIG_FILENAME} found by walking up from ${cwd}, and no { count } option was provided`));
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Run the full allocate → resolveEnv pipeline once and return its outcome.
|
|
45
|
+
*
|
|
46
|
+
* Async because `allocate()` and `resolveEnv()` are async — they go through
|
|
47
|
+
* the registry lock and the `.portweave/current.env` write. The early
|
|
48
|
+
* `resolveAllocationKey()` call is sync (it returns a `Result`), so the
|
|
49
|
+
* early-return-on-`!keyResult.ok` path is plain `Result` propagation, not
|
|
50
|
+
* a Promise boundary.
|
|
51
|
+
*/
|
|
52
|
+
async function resolveRuntime(opts) {
|
|
53
|
+
const cwd = resolvePath(opts?.cwd ?? process.cwd());
|
|
54
|
+
const keyResult = resolveAllocationKey(cwd);
|
|
55
|
+
if (!keyResult.ok) {
|
|
56
|
+
return keyResult;
|
|
57
|
+
}
|
|
58
|
+
const key = keyResult.value;
|
|
59
|
+
const configResult = await resolveConfigForRuntime(cwd, opts);
|
|
60
|
+
if (!configResult.ok) {
|
|
61
|
+
return configResult;
|
|
62
|
+
}
|
|
63
|
+
const { config, projectRoot } = configResult.value;
|
|
64
|
+
const allocResult = await allocate(key, config);
|
|
65
|
+
if (!allocResult.ok) {
|
|
66
|
+
return allocResult;
|
|
67
|
+
}
|
|
68
|
+
const envResult = await resolveEnv(allocResult.value.allocation, config, projectRoot);
|
|
69
|
+
if (!envResult.ok) {
|
|
70
|
+
return envResult;
|
|
71
|
+
}
|
|
72
|
+
return ok({
|
|
73
|
+
allocation: allocResult.value.allocation,
|
|
74
|
+
env: envResult.value.env,
|
|
75
|
+
ports: allocResult.value.allocation.ports,
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
export async function allocation(opts) {
|
|
79
|
+
const result = await resolveRuntime(opts);
|
|
80
|
+
if (!result.ok) {
|
|
81
|
+
return result;
|
|
82
|
+
}
|
|
83
|
+
return ok(result.value.allocation);
|
|
84
|
+
}
|
|
85
|
+
export async function env(opts) {
|
|
86
|
+
const result = await resolveRuntime(opts);
|
|
87
|
+
if (!result.ok) {
|
|
88
|
+
return result;
|
|
89
|
+
}
|
|
90
|
+
return ok({ ...result.value.env });
|
|
91
|
+
}
|
|
92
|
+
export async function ports(opts) {
|
|
93
|
+
const result = await resolveRuntime(opts);
|
|
94
|
+
if (!result.ok) {
|
|
95
|
+
return result;
|
|
96
|
+
}
|
|
97
|
+
return ok({ ...result.value.ports });
|
|
98
|
+
}
|
|
99
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/runtime/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical filename of the project's portweave configuration. The runtime
|
|
3
|
+
* (and the CLI via `loadConfig`) discover this name at the project root.
|
|
4
|
+
*/
|
|
5
|
+
export declare const CONFIG_FILENAME = "portweave.config.json";
|
|
6
|
+
/**
|
|
7
|
+
* Walk upward from `start` toward the filesystem root, checking for
|
|
8
|
+
* `portweave.config.json` at each level. Returns the directory containing the
|
|
9
|
+
* first matching file, or `null` if none is found.
|
|
10
|
+
*/
|
|
11
|
+
export declare function findConfigUpward(start: string): Promise<null | {
|
|
12
|
+
dir: string;
|
|
13
|
+
}>;
|
|
14
|
+
//# sourceMappingURL=upward-walk.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"upward-walk.d.ts","sourceRoot":"","sources":["../../src/runtime/upward-walk.ts"],"names":[],"mappings":"AAGA;;;GAGG;AACH,eAAO,MAAM,eAAe,0BAA0B,CAAA;AAEtD;;;;GAIG;AACH,wBAAsB,gBAAgB,CACpC,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,IAAI,GAAG;IAAE,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC,CA4BjC"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { access } from 'node:fs/promises';
|
|
2
|
+
import { dirname, resolve as resolvePath } from 'node:path';
|
|
3
|
+
/**
|
|
4
|
+
* Canonical filename of the project's portweave configuration. The runtime
|
|
5
|
+
* (and the CLI via `loadConfig`) discover this name at the project root.
|
|
6
|
+
*/
|
|
7
|
+
export const CONFIG_FILENAME = 'portweave.config.json';
|
|
8
|
+
/**
|
|
9
|
+
* Walk upward from `start` toward the filesystem root, checking for
|
|
10
|
+
* `portweave.config.json` at each level. Returns the directory containing the
|
|
11
|
+
* first matching file, or `null` if none is found.
|
|
12
|
+
*/
|
|
13
|
+
export async function findConfigUpward(start) {
|
|
14
|
+
let dir = resolvePath(start);
|
|
15
|
+
for (;;) {
|
|
16
|
+
const candidate = resolvePath(dir, CONFIG_FILENAME);
|
|
17
|
+
try {
|
|
18
|
+
await access(candidate);
|
|
19
|
+
return { dir };
|
|
20
|
+
}
|
|
21
|
+
catch (caught) {
|
|
22
|
+
// Only swallow ENOENT — the file doesn't exist at this level; keep walking.
|
|
23
|
+
// All other errors (EACCES, EPERM, etc.) propagate so callers can diagnose
|
|
24
|
+
// permission issues rather than getting a misleading RUNTIME_CONFIG_NOT_FOUND.
|
|
25
|
+
if (!(caught instanceof Error &&
|
|
26
|
+
'code' in caught &&
|
|
27
|
+
caught.code === 'ENOENT')) {
|
|
28
|
+
throw caught;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
const parent = dirname(dir);
|
|
32
|
+
if (parent === dir) {
|
|
33
|
+
// Reached filesystem root without finding a config file.
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
dir = parent;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=upward-walk.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"upward-walk.js","sourceRoot":"","sources":["../../src/runtime/upward-walk.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAA;AACzC,OAAO,EAAE,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,WAAW,CAAA;AAE3D;;;GAGG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,uBAAuB,CAAA;AAEtD;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,KAAa;IAEb,IAAI,GAAG,GAAG,WAAW,CAAC,KAAK,CAAC,CAAA;IAC5B,SAAS,CAAC;QACR,MAAM,SAAS,GAAG,WAAW,CAAC,GAAG,EAAE,eAAe,CAAC,CAAA;QACnD,IAAI,CAAC;YACH,MAAM,MAAM,CAAC,SAAS,CAAC,CAAA;YACvB,OAAO,EAAE,GAAG,EAAE,CAAA;QAChB,CAAC;QAAC,OAAO,MAAe,EAAE,CAAC;YACzB,4EAA4E;YAC5E,2EAA2E;YAC3E,+EAA+E;YAC/E,IACE,CAAC,CACC,MAAM,YAAY,KAAK;gBACvB,MAAM,IAAI,MAAM;gBACf,MAA4B,CAAC,IAAI,KAAK,QAAQ,CAChD,EACD,CAAC;gBACD,MAAM,MAAM,CAAA;YACd,CAAC;QACH,CAAC;QACD,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,CAAA;QAC3B,IAAI,MAAM,KAAK,GAAG,EAAE,CAAC;YACnB,yDAAyD;YACzD,OAAO,IAAI,CAAA;QACb,CAAC;QACD,GAAG,GAAG,MAAM,CAAA;IACd,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { PortweaveError } from '../errors.ts';
|
|
2
|
+
import { type Result } from '../result.ts';
|
|
3
|
+
export interface GitWorktreeContext {
|
|
4
|
+
currentRoot: string;
|
|
5
|
+
gitCommonDir: string;
|
|
6
|
+
mainRoot: string;
|
|
7
|
+
worktreeRoots: string[];
|
|
8
|
+
}
|
|
9
|
+
export declare function gitEnvForCwd(): NodeJS.ProcessEnv;
|
|
10
|
+
export declare function normalizePath(path: string): string;
|
|
11
|
+
export declare function parseWorktreeRoots(output: string): string[];
|
|
12
|
+
export declare function detectGitWorktreeContext(cwd: string): Result<GitWorktreeContext, PortweaveError>;
|
|
13
|
+
//# sourceMappingURL=git.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git.d.ts","sourceRoot":"","sources":["../../src/worktree/git.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,cAAc,EAAkB,MAAM,cAAc,CAAA;AAC7D,OAAO,EAAW,KAAK,MAAM,EAAE,MAAM,cAAc,CAAA;AAEnD,MAAM,WAAW,kBAAkB;IACjC,WAAW,EAAE,MAAM,CAAA;IACnB,YAAY,EAAE,MAAM,CAAA;IACpB,QAAQ,EAAE,MAAM,CAAA;IAChB,aAAa,EAAE,MAAM,EAAE,CAAA;CACxB;AAgBD,wBAAgB,YAAY,IAAI,MAAM,CAAC,UAAU,CAMhD;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAElD;AAED,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAK3D;AAED,wBAAgB,wBAAwB,CACtC,GAAG,EAAE,MAAM,GACV,MAAM,CAAC,kBAAkB,EAAE,cAAc,CAAC,CA2B5C"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { spawnSync } from 'node:child_process';
|
|
2
|
+
import { isAbsolute, resolve } from 'node:path';
|
|
3
|
+
import { PortweaveError, PW_ERROR_CODES } from "../errors.js";
|
|
4
|
+
import { err, ok } from "../result.js";
|
|
5
|
+
// Strip git-passthrough vars that could alter git's behavior; we assume a
|
|
6
|
+
// trusted developer machine but defend against accidental envrc pollution.
|
|
7
|
+
const GIT_PASSTHROUGH_KEYS_TO_STRIP = [
|
|
8
|
+
'GIT_CONFIG_GLOBAL',
|
|
9
|
+
'GIT_DIR',
|
|
10
|
+
'GIT_EXEC_PATH',
|
|
11
|
+
'GIT_INDEX_FILE',
|
|
12
|
+
'GIT_PREFIX',
|
|
13
|
+
'GIT_SSH_COMMAND',
|
|
14
|
+
'GIT_WORK_TREE',
|
|
15
|
+
];
|
|
16
|
+
const WORKTREE_LINE_PREFIX = 'worktree ';
|
|
17
|
+
export function gitEnvForCwd() {
|
|
18
|
+
const env = { ...process.env };
|
|
19
|
+
for (const key of GIT_PASSTHROUGH_KEYS_TO_STRIP) {
|
|
20
|
+
Reflect.deleteProperty(env, key);
|
|
21
|
+
}
|
|
22
|
+
return env;
|
|
23
|
+
}
|
|
24
|
+
export function normalizePath(path) {
|
|
25
|
+
return resolve(path);
|
|
26
|
+
}
|
|
27
|
+
export function parseWorktreeRoots(output) {
|
|
28
|
+
return output
|
|
29
|
+
.split('\n')
|
|
30
|
+
.filter((line) => line.startsWith(WORKTREE_LINE_PREFIX))
|
|
31
|
+
.map((line) => normalizePath(line.slice(WORKTREE_LINE_PREFIX.length)));
|
|
32
|
+
}
|
|
33
|
+
export function detectGitWorktreeContext(cwd) {
|
|
34
|
+
const currentRoot = runGit(['rev-parse', '--show-toplevel'], cwd);
|
|
35
|
+
const gitCommonDir = runGit(['rev-parse', '--git-common-dir'], cwd);
|
|
36
|
+
const worktreeOutput = runGit(['worktree', 'list', '--porcelain'], cwd);
|
|
37
|
+
if (currentRoot === null ||
|
|
38
|
+
gitCommonDir === null ||
|
|
39
|
+
worktreeOutput === null) {
|
|
40
|
+
return err(new PortweaveError(PW_ERROR_CODES.NOT_A_GIT_REPO, `not a git repository (cwd=${cwd})`));
|
|
41
|
+
}
|
|
42
|
+
const worktreeRoots = parseWorktreeRoots(worktreeOutput);
|
|
43
|
+
const mainRoot = worktreeRoots[0] ?? currentRoot;
|
|
44
|
+
return ok({
|
|
45
|
+
currentRoot: normalizePath(currentRoot),
|
|
46
|
+
gitCommonDir: resolveGitPath(currentRoot, gitCommonDir),
|
|
47
|
+
mainRoot: normalizePath(mainRoot),
|
|
48
|
+
worktreeRoots,
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
function resolveGitPath(currentRoot, path) {
|
|
52
|
+
return isAbsolute(path) ? path : resolve(currentRoot, path);
|
|
53
|
+
}
|
|
54
|
+
function runGit(args, cwd) {
|
|
55
|
+
const result = spawnSync('git', args, {
|
|
56
|
+
cwd,
|
|
57
|
+
encoding: 'utf-8',
|
|
58
|
+
env: gitEnvForCwd(),
|
|
59
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
60
|
+
});
|
|
61
|
+
if (result.status !== 0 || result.stdout.length === 0) {
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
return result.stdout.trim();
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=git.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git.js","sourceRoot":"","sources":["../../src/worktree/git.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAA;AAC9C,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAC/C,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA;AAC7D,OAAO,EAAE,GAAG,EAAE,EAAE,EAAe,MAAM,cAAc,CAAA;AASnD,0EAA0E;AAC1E,2EAA2E;AAC3E,MAAM,6BAA6B,GAAG;IACpC,mBAAmB;IACnB,SAAS;IACT,eAAe;IACf,gBAAgB;IAChB,YAAY;IACZ,iBAAiB;IACjB,eAAe;CACP,CAAA;AAEV,MAAM,oBAAoB,GAAG,WAAW,CAAA;AAExC,MAAM,UAAU,YAAY;IAC1B,MAAM,GAAG,GAAsB,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE,CAAA;IACjD,KAAK,MAAM,GAAG,IAAI,6BAA6B,EAAE,CAAC;QAChD,OAAO,CAAC,cAAc,CAAC,GAAG,EAAE,GAAG,CAAC,CAAA;IAClC,CAAC;IACD,OAAO,GAAG,CAAA;AACZ,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,IAAY;IACxC,OAAO,OAAO,CAAC,IAAI,CAAC,CAAA;AACtB,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,MAAc;IAC/C,OAAO,MAAM;SACV,KAAK,CAAC,IAAI,CAAC;SACX,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,oBAAoB,CAAC,CAAC;SACvD,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,oBAAoB,CAAC,MAAM,CAAC,CAAC,CAAC,CAAA;AAC1E,CAAC;AAED,MAAM,UAAU,wBAAwB,CACtC,GAAW;IAEX,MAAM,WAAW,GAAG,MAAM,CAAC,CAAC,WAAW,EAAE,iBAAiB,CAAC,EAAE,GAAG,CAAC,CAAA;IACjE,MAAM,YAAY,GAAG,MAAM,CAAC,CAAC,WAAW,EAAE,kBAAkB,CAAC,EAAE,GAAG,CAAC,CAAA;IACnE,MAAM,cAAc,GAAG,MAAM,CAAC,CAAC,UAAU,EAAE,MAAM,EAAE,aAAa,CAAC,EAAE,GAAG,CAAC,CAAA;IAEvE,IACE,WAAW,KAAK,IAAI;QACpB,YAAY,KAAK,IAAI;QACrB,cAAc,KAAK,IAAI,EACvB,CAAC;QACD,OAAO,GAAG,CACR,IAAI,cAAc,CAChB,cAAc,CAAC,cAAc,EAC7B,6BAA6B,GAAG,GAAG,CACpC,CACF,CAAA;IACH,CAAC;IAED,MAAM,aAAa,GAAG,kBAAkB,CAAC,cAAc,CAAC,CAAA;IACxD,MAAM,QAAQ,GAAG,aAAa,CAAC,CAAC,CAAC,IAAI,WAAW,CAAA;IAEhD,OAAO,EAAE,CAAC;QACR,WAAW,EAAE,aAAa,CAAC,WAAW,CAAC;QACvC,YAAY,EAAE,cAAc,CAAC,WAAW,EAAE,YAAY,CAAC;QACvD,QAAQ,EAAE,aAAa,CAAC,QAAQ,CAAC;QACjC,aAAa;KACd,CAAC,CAAA;AACJ,CAAC;AAED,SAAS,cAAc,CAAC,WAAmB,EAAE,IAAY;IACvD,OAAO,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,WAAW,EAAE,IAAI,CAAC,CAAA;AAC7D,CAAC;AAED,SAAS,MAAM,CAAC,IAAc,EAAE,GAAW;IACzC,MAAM,MAAM,GAAG,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE;QACpC,GAAG;QACH,QAAQ,EAAE,OAAO;QACjB,GAAG,EAAE,YAAY,EAAE;QACnB,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;KAChC,CAAC,CAAA;IAEF,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACtD,OAAO,IAAI,CAAA;IACb,CAAC;IAED,OAAO,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,CAAA;AAC7B,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { PortweaveError } from '../errors.ts';
|
|
2
|
+
import { type Result } from '../result.ts';
|
|
3
|
+
export interface AllocationKey {
|
|
4
|
+
gitCommonDir: null | string;
|
|
5
|
+
namespace: string;
|
|
6
|
+
offsetOverride: null | number;
|
|
7
|
+
worktreeRoot: string;
|
|
8
|
+
}
|
|
9
|
+
export declare function resolveAllocationKey(cwd: string): Result<AllocationKey, PortweaveError>;
|
|
10
|
+
//# sourceMappingURL=key.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"key.d.ts","sourceRoot":"","sources":["../../src/worktree/key.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAkB,MAAM,cAAc,CAAA;AAC7D,OAAO,EAAW,KAAK,MAAM,EAAE,MAAM,cAAc,CAAA;AAQnD,MAAM,WAAW,aAAa;IAC5B,YAAY,EAAE,IAAI,GAAG,MAAM,CAAA;IAC3B,SAAS,EAAE,MAAM,CAAA;IACjB,cAAc,EAAE,IAAI,GAAG,MAAM,CAAA;IAC7B,YAAY,EAAE,MAAM,CAAA;CACrB;AAED,wBAAgB,oBAAoB,CAClC,GAAG,EAAE,MAAM,GACV,MAAM,CAAC,aAAa,EAAE,cAAc,CAAC,CAqCvC"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { resolve } from 'node:path';
|
|
2
|
+
import { PortweaveError, PW_ERROR_CODES } from "../errors.js";
|
|
3
|
+
import { err, ok } from "../result.js";
|
|
4
|
+
import { detectGitWorktreeContext } from "./git.js";
|
|
5
|
+
import { deriveNamespace, namespaceOverride, parseExplicitOffset, } from "./namespace.js";
|
|
6
|
+
export function resolveAllocationKey(cwd) {
|
|
7
|
+
const absoluteCwd = resolve(cwd);
|
|
8
|
+
const gitResult = detectGitWorktreeContext(absoluteCwd);
|
|
9
|
+
let worktreeRoot;
|
|
10
|
+
let gitCommonDir;
|
|
11
|
+
let derived;
|
|
12
|
+
if (gitResult.ok) {
|
|
13
|
+
worktreeRoot = gitResult.value.currentRoot;
|
|
14
|
+
gitCommonDir = gitResult.value.gitCommonDir;
|
|
15
|
+
derived = deriveNamespace(gitResult.value.currentRoot, gitResult.value.mainRoot);
|
|
16
|
+
}
|
|
17
|
+
else if (gitResult.error.code === PW_ERROR_CODES.NOT_A_GIT_REPO) {
|
|
18
|
+
worktreeRoot = absoluteCwd;
|
|
19
|
+
gitCommonDir = null;
|
|
20
|
+
derived = deriveNamespace(absoluteCwd, absoluteCwd);
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
return err(gitResult.error);
|
|
24
|
+
}
|
|
25
|
+
const override = namespaceOverride();
|
|
26
|
+
const namespace = override ?? derived;
|
|
27
|
+
const offsetResult = parseExplicitOffset();
|
|
28
|
+
if (!offsetResult.ok) {
|
|
29
|
+
return err(offsetResult.error);
|
|
30
|
+
}
|
|
31
|
+
return ok({
|
|
32
|
+
gitCommonDir,
|
|
33
|
+
namespace,
|
|
34
|
+
offsetOverride: offsetResult.value,
|
|
35
|
+
worktreeRoot,
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=key.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"key.js","sourceRoot":"","sources":["../../src/worktree/key.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACnC,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA;AAC7D,OAAO,EAAE,GAAG,EAAE,EAAE,EAAe,MAAM,cAAc,CAAA;AACnD,OAAO,EAAE,wBAAwB,EAAE,MAAM,UAAU,CAAA;AACnD,OAAO,EACL,eAAe,EACf,iBAAiB,EACjB,mBAAmB,GACpB,MAAM,gBAAgB,CAAA;AASvB,MAAM,UAAU,oBAAoB,CAClC,GAAW;IAEX,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,CAAA;IAChC,MAAM,SAAS,GAAG,wBAAwB,CAAC,WAAW,CAAC,CAAA;IAEvD,IAAI,YAAoB,CAAA;IACxB,IAAI,YAA2B,CAAA;IAC/B,IAAI,OAAe,CAAA;IAEnB,IAAI,SAAS,CAAC,EAAE,EAAE,CAAC;QACjB,YAAY,GAAG,SAAS,CAAC,KAAK,CAAC,WAAW,CAAA;QAC1C,YAAY,GAAG,SAAS,CAAC,KAAK,CAAC,YAAY,CAAA;QAC3C,OAAO,GAAG,eAAe,CACvB,SAAS,CAAC,KAAK,CAAC,WAAW,EAC3B,SAAS,CAAC,KAAK,CAAC,QAAQ,CACzB,CAAA;IACH,CAAC;SAAM,IAAI,SAAS,CAAC,KAAK,CAAC,IAAI,KAAK,cAAc,CAAC,cAAc,EAAE,CAAC;QAClE,YAAY,GAAG,WAAW,CAAA;QAC1B,YAAY,GAAG,IAAI,CAAA;QACnB,OAAO,GAAG,eAAe,CAAC,WAAW,EAAE,WAAW,CAAC,CAAA;IACrD,CAAC;SAAM,CAAC;QACN,OAAO,GAAG,CAAC,SAAS,CAAC,KAAK,CAAC,CAAA;IAC7B,CAAC;IAED,MAAM,QAAQ,GAAG,iBAAiB,EAAE,CAAA;IACpC,MAAM,SAAS,GAAG,QAAQ,IAAI,OAAO,CAAA;IAErC,MAAM,YAAY,GAAG,mBAAmB,EAAE,CAAA;IAC1C,IAAI,CAAC,YAAY,CAAC,EAAE,EAAE,CAAC;QACrB,OAAO,GAAG,CAAC,YAAY,CAAC,KAAK,CAAC,CAAA;IAChC,CAAC;IAED,OAAO,EAAE,CAAC;QACR,YAAY;QACZ,SAAS;QACT,cAAc,EAAE,YAAY,CAAC,KAAK;QAClC,YAAY;KACb,CAAC,CAAA;AACJ,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { PortweaveError } from '../errors.ts';
|
|
2
|
+
import { type Result } from '../result.ts';
|
|
3
|
+
export declare const MAIN_NAMESPACE = "main";
|
|
4
|
+
export declare function deriveNamespace(currentRoot: string, mainRoot: string): string;
|
|
5
|
+
export declare function namespaceOverride(): null | string;
|
|
6
|
+
export declare function parseExplicitOffset(): Result<null | number, PortweaveError>;
|
|
7
|
+
export declare function sanitizeNamespace(value: string): string;
|
|
8
|
+
//# sourceMappingURL=namespace.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"namespace.d.ts","sourceRoot":"","sources":["../../src/worktree/namespace.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,cAAc,EAAkB,MAAM,cAAc,CAAA;AAC7D,OAAO,EAAW,KAAK,MAAM,EAAE,MAAM,cAAc,CAAA;AAGnD,eAAO,MAAM,cAAc,SAAS,CAAA;AAYpC,wBAAgB,eAAe,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAQ7E;AAED,wBAAgB,iBAAiB,IAAI,IAAI,GAAG,MAAM,CAMjD;AAED,wBAAgB,mBAAmB,IAAI,MAAM,CAAC,IAAI,GAAG,MAAM,EAAE,cAAc,CAAC,CA2B3E;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAWvD"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { basename } from 'node:path';
|
|
3
|
+
import { PortweaveError, PW_ERROR_CODES } from "../errors.js";
|
|
4
|
+
import { err, ok } from "../result.js";
|
|
5
|
+
import { normalizePath } from "./git.js";
|
|
6
|
+
export const MAIN_NAMESPACE = 'main';
|
|
7
|
+
const DECIMAL_RADIX = 10;
|
|
8
|
+
const HASH_LENGTH = 8;
|
|
9
|
+
const MAX_SLUG_LENGTH = 40;
|
|
10
|
+
const NAMESPACE_ENV = 'PORTWEAVE_NAMESPACE';
|
|
11
|
+
const OFFSET_ENV = 'PORTWEAVE_OFFSET';
|
|
12
|
+
const NON_SLUG_CHARS = /[^a-z0-9]+/g;
|
|
13
|
+
const SURROUNDING_DASHES = /^-+|-+$/g;
|
|
14
|
+
const OFFSET_LITERAL = /^\d+$/;
|
|
15
|
+
export function deriveNamespace(currentRoot, mainRoot) {
|
|
16
|
+
const normalized = normalizePath(currentRoot);
|
|
17
|
+
if (normalized === normalizePath(mainRoot)) {
|
|
18
|
+
return MAIN_NAMESPACE;
|
|
19
|
+
}
|
|
20
|
+
const slug = sanitizeNamespace(basename(normalized));
|
|
21
|
+
return `${slug}-${hashPath(normalized)}`;
|
|
22
|
+
}
|
|
23
|
+
export function namespaceOverride() {
|
|
24
|
+
const raw = process.env[NAMESPACE_ENV];
|
|
25
|
+
if (raw === undefined || raw.trim().length === 0) {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
return sanitizeNamespace(raw);
|
|
29
|
+
}
|
|
30
|
+
export function parseExplicitOffset() {
|
|
31
|
+
const raw = process.env[OFFSET_ENV];
|
|
32
|
+
if (raw === undefined || raw.trim().length === 0) {
|
|
33
|
+
return ok(null);
|
|
34
|
+
}
|
|
35
|
+
if (!OFFSET_LITERAL.test(raw.trim())) {
|
|
36
|
+
return err(new PortweaveError(PW_ERROR_CODES.WORKTREE_OFFSET_INVALID, `${OFFSET_ENV} must be a non-negative integer (got "${raw}")`));
|
|
37
|
+
}
|
|
38
|
+
const offset = Number.parseInt(raw.trim(), DECIMAL_RADIX);
|
|
39
|
+
// guard against digit strings exceeding Number.MAX_SAFE_INTEGER
|
|
40
|
+
if (!Number.isSafeInteger(offset)) {
|
|
41
|
+
return err(new PortweaveError(PW_ERROR_CODES.WORKTREE_OFFSET_INVALID, `${OFFSET_ENV} must be a non-negative integer within Number.MAX_SAFE_INTEGER (got "${raw}")`));
|
|
42
|
+
}
|
|
43
|
+
return ok(offset);
|
|
44
|
+
}
|
|
45
|
+
export function sanitizeNamespace(value) {
|
|
46
|
+
const slug = value
|
|
47
|
+
.toLowerCase()
|
|
48
|
+
.replace(NON_SLUG_CHARS, '-')
|
|
49
|
+
.replace(SURROUNDING_DASHES, '');
|
|
50
|
+
if (slug.length === 0) {
|
|
51
|
+
return MAIN_NAMESPACE;
|
|
52
|
+
}
|
|
53
|
+
return slug.slice(0, MAX_SLUG_LENGTH);
|
|
54
|
+
}
|
|
55
|
+
function hashPath(path) {
|
|
56
|
+
return createHash('sha1').update(path).digest('hex').slice(0, HASH_LENGTH);
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=namespace.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"namespace.js","sourceRoot":"","sources":["../../src/worktree/namespace.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "portweave",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Zero-thought, conflict-free local-dev port allocation across projects and git worktrees.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "Gameweave",
|
|
7
|
+
"homepage": "https://github.com/gameweave/portweave#readme",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/gameweave/portweave.git"
|
|
11
|
+
},
|
|
12
|
+
"bugs": "https://github.com/gameweave/portweave/issues",
|
|
13
|
+
"keywords": [
|
|
14
|
+
"port",
|
|
15
|
+
"ports",
|
|
16
|
+
"port-allocation",
|
|
17
|
+
"worktree",
|
|
18
|
+
"git-worktree",
|
|
19
|
+
"local-dev",
|
|
20
|
+
"dev-server",
|
|
21
|
+
"cli",
|
|
22
|
+
"conflict-free",
|
|
23
|
+
"monorepo",
|
|
24
|
+
"dev-tools"
|
|
25
|
+
],
|
|
26
|
+
"type": "module",
|
|
27
|
+
"exports": {
|
|
28
|
+
".": {
|
|
29
|
+
"import": "./dist/index.js",
|
|
30
|
+
"types": "./dist/index.d.ts"
|
|
31
|
+
},
|
|
32
|
+
"./runtime": {
|
|
33
|
+
"import": "./dist/runtime/index.js",
|
|
34
|
+
"types": "./dist/runtime/index.d.ts"
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
"bin": {
|
|
38
|
+
"portweave": "dist/cli.js"
|
|
39
|
+
},
|
|
40
|
+
"files": [
|
|
41
|
+
"dist/",
|
|
42
|
+
"README.md",
|
|
43
|
+
"LICENSE"
|
|
44
|
+
],
|
|
45
|
+
"scripts": {
|
|
46
|
+
"build": "tsc --project tsconfig.build.json && chmod +x dist/cli.js",
|
|
47
|
+
"typecheck": "tsx scripts/bin/typecheck.ts",
|
|
48
|
+
"lint": "tsx scripts/bin/lint.ts",
|
|
49
|
+
"lint:fix": "tsx scripts/bin/lint.ts --fix",
|
|
50
|
+
"format": "tsx scripts/bin/format.ts",
|
|
51
|
+
"format:check": "tsx scripts/bin/format.ts --check",
|
|
52
|
+
"pretest": "npm run build",
|
|
53
|
+
"test": "vitest run --passWithNoTests",
|
|
54
|
+
"test:coverage": "vitest run --coverage --passWithNoTests",
|
|
55
|
+
"test:watch": "vitest",
|
|
56
|
+
"dupcheck": "tsx scripts/bin/dupcheck.ts",
|
|
57
|
+
"similarity:check": "tsx scripts/bin/similarity-check.ts",
|
|
58
|
+
"deadcode:check": "tsx scripts/bin/deadcode-check.ts",
|
|
59
|
+
"structure:check": "tsx scripts/bin/structure-check.ts",
|
|
60
|
+
"complexity:check": "tsx scripts/bin/complexity-check.ts",
|
|
61
|
+
"constants:check": "tsx scripts/bin/constants-check.ts --check",
|
|
62
|
+
"docs:freshness:check": "tsx scripts/bin/docs-freshness-check.ts",
|
|
63
|
+
"upgrade:check": "tsx scripts/bin/upgrade-check.ts",
|
|
64
|
+
"ci-workflow:check": "tsx scripts/bin/ci-workflow-check.ts",
|
|
65
|
+
"dev-workflow": "tsx scripts/bin/dev-workflow.ts",
|
|
66
|
+
"task:init": "tsx scripts/bin/task-init.ts",
|
|
67
|
+
"task:add": "tsx scripts/bin/task-add.ts",
|
|
68
|
+
"task:add-batch": "tsx scripts/bin/task-add-batch.ts",
|
|
69
|
+
"task:add-group": "tsx scripts/bin/task-add-group.ts",
|
|
70
|
+
"task:status": "tsx scripts/bin/task-status.ts",
|
|
71
|
+
"task:get": "tsx scripts/bin/task-get.ts",
|
|
72
|
+
"task:next": "tsx scripts/bin/task-next.ts",
|
|
73
|
+
"task:set-status": "tsx scripts/bin/task-set-status.ts",
|
|
74
|
+
"task:check-complete": "tsx scripts/bin/task-check-complete.ts",
|
|
75
|
+
"prepare": "husky",
|
|
76
|
+
"prepublishOnly": "npm run build"
|
|
77
|
+
},
|
|
78
|
+
"dependencies": {
|
|
79
|
+
"commander": "^14.0.3",
|
|
80
|
+
"zod": "^4.4.3"
|
|
81
|
+
},
|
|
82
|
+
"devDependencies": {
|
|
83
|
+
"@eslint/js": "^10.0.1",
|
|
84
|
+
"@stylistic/eslint-plugin": "^5.10.0",
|
|
85
|
+
"@types/node": "^25.9.0",
|
|
86
|
+
"@vitest/coverage-v8": "^4.1.7",
|
|
87
|
+
"constants-check": "^0.2.0",
|
|
88
|
+
"eslint": "^10.4.0",
|
|
89
|
+
"eslint-import-resolver-typescript": "^4.4.4",
|
|
90
|
+
"eslint-plugin-canonical": "^5.1.3",
|
|
91
|
+
"eslint-plugin-import-x": "^4.16.2",
|
|
92
|
+
"eslint-plugin-perfectionist": "^5.9.0",
|
|
93
|
+
"eslint-plugin-sonarjs": "^4.0.3",
|
|
94
|
+
"husky": "^9.1.7",
|
|
95
|
+
"jscpd": "^4.2.4",
|
|
96
|
+
"knip": "^6.14.2",
|
|
97
|
+
"loglevel": "^1.9.2",
|
|
98
|
+
"prettier": "~3.8.3",
|
|
99
|
+
"tsx": "^4.22.3",
|
|
100
|
+
"typescript": "~6.0.3",
|
|
101
|
+
"typescript-eslint": "^8.60.0",
|
|
102
|
+
"vitest": "^4.1.7",
|
|
103
|
+
"yaml": "^2.9.0"
|
|
104
|
+
},
|
|
105
|
+
"engines": {
|
|
106
|
+
"node": "^24.13.0",
|
|
107
|
+
"npm": ">=11.0.0"
|
|
108
|
+
}
|
|
109
|
+
}
|