nawabari 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.
Files changed (54) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +120 -0
  3. package/dist/cli.d.ts +9 -0
  4. package/dist/cli.js +298 -0
  5. package/dist/cli.js.map +1 -0
  6. package/dist/domain/doctor.d.ts +20 -0
  7. package/dist/domain/doctor.js +167 -0
  8. package/dist/domain/doctor.js.map +1 -0
  9. package/dist/domain/errors.d.ts +29 -0
  10. package/dist/domain/errors.js +42 -0
  11. package/dist/domain/errors.js.map +1 -0
  12. package/dist/domain/session-backend.d.ts +24 -0
  13. package/dist/domain/session-backend.js +206 -0
  14. package/dist/domain/session-backend.js.map +1 -0
  15. package/dist/domain/session.d.ts +89 -0
  16. package/dist/domain/session.js +47 -0
  17. package/dist/domain/session.js.map +1 -0
  18. package/dist/errors.d.ts +8 -0
  19. package/dist/errors.js +14 -0
  20. package/dist/errors.js.map +1 -0
  21. package/dist/git.d.ts +33 -0
  22. package/dist/git.js +157 -0
  23. package/dist/git.js.map +1 -0
  24. package/dist/index.d.ts +2 -0
  25. package/dist/index.js +6 -0
  26. package/dist/index.js.map +1 -0
  27. package/dist/presentation.d.ts +9 -0
  28. package/dist/presentation.js +61 -0
  29. package/dist/presentation.js.map +1 -0
  30. package/dist/registry/atomic.d.ts +20 -0
  31. package/dist/registry/atomic.js +128 -0
  32. package/dist/registry/atomic.js.map +1 -0
  33. package/dist/registry/errors.d.ts +8 -0
  34. package/dist/registry/errors.js +30 -0
  35. package/dist/registry/errors.js.map +1 -0
  36. package/dist/registry/lock.d.ts +60 -0
  37. package/dist/registry/lock.js +727 -0
  38. package/dist/registry/lock.js.map +1 -0
  39. package/dist/registry/store.d.ts +38 -0
  40. package/dist/registry/store.js +156 -0
  41. package/dist/registry/store.js.map +1 -0
  42. package/dist/registry/types.d.ts +18 -0
  43. package/dist/registry/types.js +3 -0
  44. package/dist/registry/types.js.map +1 -0
  45. package/dist/registry.d.ts +5 -0
  46. package/dist/registry.js +6 -0
  47. package/dist/registry.js.map +1 -0
  48. package/dist/session-id.d.ts +7 -0
  49. package/dist/session-id.js +32 -0
  50. package/dist/session-id.js.map +1 -0
  51. package/dist/session-registry.d.ts +169 -0
  52. package/dist/session-registry.js +1190 -0
  53. package/dist/session-registry.js.map +1 -0
  54. package/package.json +57 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 yohn-jp
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,120 @@
1
+ # Nawabari
2
+
3
+ Nawabari is a standalone local Git/session ownership layer for parallel coding
4
+ agents. It gives each active session one exclusively owned worktree and one
5
+ mutable branch. It works without GitHub, `gh`, a network connection, Mottainai,
6
+ or a particular agent runtime.
7
+
8
+ Nawabari governs operations routed through Nawabari. It is an authorization and
9
+ ownership boundary, not an operating-system or filesystem sandbox: a process
10
+ that already has filesystem permissions can still edit another worktree
11
+ directly.
12
+
13
+ ## Install
14
+
15
+ ```bash
16
+ npm install -g nawabari
17
+ ```
18
+
19
+ The package installs `nawabari` for direct use and `git-nawabari` for Git's
20
+ `git nawabari` external subcommand. Both names use the same entry point.
21
+
22
+ ```bash
23
+ git nawabari --help
24
+ nawabari --version
25
+ ```
26
+
27
+ ## Session lifecycle
28
+
29
+ Session IDs are generated automatically as UUIDv7 values. They are immutable
30
+ machine identities; labels and branch names are separate display metadata.
31
+
32
+ ```bash
33
+ git nawabari session create --branch feature/example --worktree ../example-worktree --json
34
+ git nawabari session id --json
35
+ git nawabari session show --json
36
+ git nawabari session list --json
37
+ git nawabari status --json
38
+ git nawabari guard --json
39
+ git nawabari session close --json
40
+ git nawabari gc --dry-run --json
41
+ git nawabari doctor --json
42
+ ```
43
+
44
+ `session create` provisions a dedicated worktree and mutable branch atomically
45
+ under the repository-scoped mutation lock. The default/integration worktree
46
+ and its protected branch cannot be session resources. `session id` and the
47
+ other current-session commands resolve ownership from the current worktree;
48
+ callers do not need to repeat the session ID.
49
+
50
+ Close is conservative. Dirty worktrees, ambiguous ownership, mismatched Git
51
+ state, and commits not proven reachable from the integration branch block
52
+ destructive cleanup. A clean close releases only the owned worktree and
53
+ branch, and repeating close is idempotent. `gc` detects stale or interrupted
54
+ sessions; `--apply` uses the same close safety checks and reports blocked
55
+ sessions instead of guessing.
56
+
57
+ ## Ownership guard
58
+
59
+ `git nawabari guard` is a cheap, side-effect-free authorization decision for a
60
+ Nawabari-governed mutation. It reads the current repository/worktree/branch and
61
+ the same authoritative session registry used by provisioning and lifecycle
62
+ operations. An optional `--session` asserts the caller's session identity.
63
+
64
+ ```bash
65
+ decision=$(git nawabari guard --session "$NAWABARI_SESSION_ID" --json) || {
66
+ printf '%s\n' "$decision" >&2
67
+ exit 1
68
+ }
69
+ ```
70
+
71
+ An allowed decision has `allowed: true` and `code: "ALLOWED"`. A denied
72
+ decision has `allowed: false`, a stable code such as
73
+ `WORKTREE_OWNED_BY_OTHER_SESSION`, `PROTECTED_WORKTREE`, or
74
+ `OWNERSHIP_MISMATCH`, and a non-zero exit status. Detached, corrupt, missing,
75
+ or conflicting state fails closed. The guard does not install hooks and does
76
+ not prevent direct filesystem writes outside Nawabari.
77
+
78
+ ## Orchestrator integration
79
+
80
+ An external orchestrator can create a session, capture the returned
81
+ `session_id`, launch its worker with the returned `worktree` as `cwd`, and
82
+ check the guard before each Nawabari-governed mutation:
83
+
84
+ ```bash
85
+ created=$(git nawabari session create --branch feature/task --json)
86
+ session_id=$(printf '%s' "$created" | jq -r .session_id)
87
+ worktree=$(printf '%s' "$created" | jq -r .worktree)
88
+
89
+ (cd "$worktree" && git nawabari guard --session "$session_id" --json)
90
+ # run the worker in "$worktree"
91
+ git nawabari session close --session "$session_id" --json
92
+ ```
93
+
94
+ The orchestrator owns scheduling, prompts, and worker lifetime; Nawabari owns
95
+ only local session identity, worktree/branch ownership, and safe cleanup. No
96
+ Mottainai, GitHub, `gh`, network, or agent-runtime dependency is required.
97
+
98
+ ## Repository state and concurrency
99
+
100
+ The authoritative registry is stored in the repository-common Git directory at
101
+ `.git/nawabari/session-registry.json`; linked worktrees therefore share one
102
+ registry. It records the schema version, repository identity, immutable session
103
+ ID, canonical worktree and branch identities, lifecycle state, and timestamps.
104
+
105
+ Ownership-changing writes use an exclusive repository-local lock and a synced
106
+ temporary file followed by atomic replacement. Concurrent creation cannot
107
+ silently duplicate an active worktree or branch. Lock recovery is conservative:
108
+ the lock records a random token, PID, host, and process-start identity; an
109
+ owner is reclaimed only when the same host proves that exact process identity
110
+ is dead. Invalid, remote, or otherwise unverifiable lock metadata is never
111
+ stolen and fails closed so an operator can inspect or remove it deliberately.
112
+
113
+ ## Development
114
+
115
+ ```bash
116
+ pnpm install --frozen-lockfile
117
+ pnpm run verify
118
+ ```
119
+
120
+ See [CONTRIBUTING.md](CONTRIBUTING.md) and [LICENSE](LICENSE).
package/dist/cli.d.ts ADDED
@@ -0,0 +1,9 @@
1
+ import { type SessionBackend } from "./domain/session.js";
2
+ import { type CliIO } from "./presentation.js";
3
+ export type CliDependencies = {
4
+ backend?: SessionBackend;
5
+ cwd?: string;
6
+ io?: CliIO;
7
+ version?: string;
8
+ };
9
+ export declare function runCli(argv: string[], dependencies?: CliDependencies): Promise<number>;
package/dist/cli.js ADDED
@@ -0,0 +1,298 @@
1
+ import { createRequire } from "node:module";
2
+ import { runDoctor } from "./domain/doctor.js";
3
+ import { DomainError, EXIT_CODES, failure } from "./domain/errors.js";
4
+ import { createLocalSessionBackend } from "./domain/session-backend.js";
5
+ import { defaultCliIO, renderFailure, renderSuccess } from "./presentation.js";
6
+ const CLI_NAME = "nawabari";
7
+ const packageMetadata = createRequire(import.meta.url)("../package.json");
8
+ const VERSION = packageMetadata.version;
9
+ const HELP_TEXT = [
10
+ `Usage: ${CLI_NAME} <command> [options]`,
11
+ "",
12
+ "Commands:",
13
+ " session create Request a new Nawabari session",
14
+ " session id Resolve the current session identity",
15
+ " session show Show the current or selected session",
16
+ " session list List repository sessions",
17
+ " session close Close the current or selected session",
18
+ " status Show Nawabari session status",
19
+ " guard [--session id] Authorize the current worktree for mutation",
20
+ " gc Detect or clean eligible stale sessions",
21
+ " doctor Check local Nawabari prerequisites",
22
+ " --help Show this help",
23
+ " --version Print the installed version",
24
+ "",
25
+ "Global options:",
26
+ " --json Emit one stable JSON document on stdout",
27
+ " -h, --help Show this help",
28
+ "",
29
+ "Session options:",
30
+ " session create --branch <name> --worktree <path> --base <ref> --label <text>",
31
+ " session show|close --session <id>",
32
+ " gc [--dry-run|--apply]",
33
+ ].join("\n");
34
+ const HELP_DATA = {
35
+ usage: `Usage: ${CLI_NAME} <command> [options]`,
36
+ commands: [
37
+ "session create",
38
+ "session id",
39
+ "session show",
40
+ "session list",
41
+ "session close",
42
+ "status",
43
+ "guard",
44
+ "gc",
45
+ "doctor",
46
+ ],
47
+ options: ["--json", "--help", "--version"],
48
+ session_options: ["--branch", "--worktree", "--base", "--label", "--session"],
49
+ gc_options: ["--apply", "--dry-run"],
50
+ };
51
+ function usageError(code, message, details = null) {
52
+ return new DomainError(code, message, details);
53
+ }
54
+ function parseGlobalArguments(argv) {
55
+ let json = false;
56
+ let help = false;
57
+ let version = false;
58
+ const commandArguments = [];
59
+ for (const argument of argv) {
60
+ if (argument === "--json") {
61
+ json = true;
62
+ }
63
+ else if (argument === "-h" || argument === "--help") {
64
+ help = true;
65
+ }
66
+ else if (argument === "--version") {
67
+ version = true;
68
+ }
69
+ else {
70
+ commandArguments.push(argument);
71
+ }
72
+ }
73
+ if (help && version) {
74
+ return failure(usageError("INVALID_ARGUMENT", "--help and --version cannot be used together."));
75
+ }
76
+ if (version && commandArguments.length > 0) {
77
+ return failure(usageError("INVALID_ARGUMENT", "--version cannot be combined with a command."));
78
+ }
79
+ return { ok: true, value: { json, help, version, commandArguments } };
80
+ }
81
+ function optionParts(argument) {
82
+ const separator = argument.indexOf("=");
83
+ if (separator === -1)
84
+ return { name: argument, inlineValue: null };
85
+ return { name: argument.slice(0, separator), inlineValue: argument.slice(separator + 1) };
86
+ }
87
+ function parseOptions(arguments_, allowed) {
88
+ const options = {
89
+ session_id: null,
90
+ branch: null,
91
+ worktree: null,
92
+ base: null,
93
+ label: null,
94
+ apply: false,
95
+ };
96
+ let dryRun = false;
97
+ for (let index = 0; index < arguments_.length; index += 1) {
98
+ const { name, inlineValue } = optionParts(arguments_[index]);
99
+ if (!allowed.has(name)) {
100
+ return failure(usageError("INVALID_ARGUMENT", `Unknown option: ${name}.`, { option: name }));
101
+ }
102
+ if (name === "--apply" || name === "--dry-run") {
103
+ if (inlineValue !== null) {
104
+ return failure(usageError("INVALID_ARGUMENT", `${name} does not accept a value.`, { option: name }));
105
+ }
106
+ if (name === "--apply")
107
+ options.apply = true;
108
+ else
109
+ dryRun = true;
110
+ continue;
111
+ }
112
+ const value = inlineValue ?? arguments_[index + 1];
113
+ if (value === undefined || value === "" || (inlineValue === null && value.startsWith("-"))) {
114
+ return failure(usageError("MISSING_ARGUMENT", `${name} requires a value.`, { option: name }));
115
+ }
116
+ if (inlineValue === null)
117
+ index += 1;
118
+ if (name === "--session")
119
+ options.session_id = value;
120
+ else if (name === "--branch")
121
+ options.branch = value;
122
+ else if (name === "--worktree")
123
+ options.worktree = value;
124
+ else if (name === "--base")
125
+ options.base = value;
126
+ else if (name === "--label")
127
+ options.label = value;
128
+ }
129
+ if (options.apply && dryRun) {
130
+ return failure(usageError("INVALID_ARGUMENT", "--apply and --dry-run cannot be used together."));
131
+ }
132
+ return { ok: true, value: options };
133
+ }
134
+ function noOptions(arguments_) {
135
+ return parseOptions(arguments_, new Set());
136
+ }
137
+ function sessionContext(cwd) {
138
+ return { cwd };
139
+ }
140
+ async function resolveSelectedSession(backend, context, sessionId) {
141
+ return sessionId === null ? backend.resolveCurrentSession(context) : backend.getSession(context, sessionId);
142
+ }
143
+ async function executeCommand(commandArguments, dependencies) {
144
+ const [command, subcommand, ...rest] = commandArguments;
145
+ const context = sessionContext(dependencies.cwd);
146
+ if (command === "session") {
147
+ if (subcommand === undefined) {
148
+ return failure(usageError("MISSING_ARGUMENT", "session requires a subcommand."));
149
+ }
150
+ if (subcommand === "create") {
151
+ const parsed = parseOptions(rest, new Set(["--branch", "--worktree", "--base", "--label"]));
152
+ if (!parsed.ok)
153
+ return parsed;
154
+ const options = {
155
+ branch: parsed.value.branch,
156
+ worktree: parsed.value.worktree,
157
+ base: parsed.value.base,
158
+ label: parsed.value.label,
159
+ };
160
+ const result = await dependencies.backend.createSession(context, options);
161
+ return result.ok ? { ok: true, value: result.value } : result;
162
+ }
163
+ if (subcommand === "id" || subcommand === "show" || subcommand === "close") {
164
+ if (subcommand === "id") {
165
+ const parsed = noOptions(rest);
166
+ if (!parsed.ok)
167
+ return parsed;
168
+ const selected = await dependencies.backend.resolveCurrentSession(context);
169
+ if (!selected.ok)
170
+ return selected;
171
+ return { ok: true, value: { session_id: selected.value.session_id } };
172
+ }
173
+ const parsed = parseOptions(rest, new Set(["--session"]));
174
+ if (!parsed.ok)
175
+ return parsed;
176
+ if (subcommand === "close") {
177
+ const closeOptions = { session_id: parsed.value.session_id };
178
+ const selected = await dependencies.backend.closeSession(context, closeOptions);
179
+ return selected.ok ? { ok: true, value: selected.value } : selected;
180
+ }
181
+ const selected = await resolveSelectedSession(dependencies.backend, context, parsed.value.session_id);
182
+ return selected.ok ? { ok: true, value: selected.value } : selected;
183
+ }
184
+ if (subcommand === "list") {
185
+ const parsed = noOptions(rest);
186
+ if (!parsed.ok)
187
+ return parsed;
188
+ const result = await dependencies.backend.listSessions(context);
189
+ return result.ok ? { ok: true, value: result.value } : result;
190
+ }
191
+ return failure(new DomainError("UNKNOWN_COMMAND", `Unknown session subcommand: ${subcommand}.`, { subcommand }));
192
+ }
193
+ if (command === "status") {
194
+ const parsed = noOptions([subcommand, ...rest].filter((argument) => argument !== undefined));
195
+ if (!parsed.ok)
196
+ return parsed;
197
+ const result = await dependencies.backend.status(context);
198
+ return result.ok ? { ok: true, value: result.value } : result;
199
+ }
200
+ if (command === "guard") {
201
+ const parsed = parseOptions([subcommand, ...rest].filter((argument) => argument !== undefined), new Set(["--session"]));
202
+ if (!parsed.ok)
203
+ return parsed;
204
+ const result = await dependencies.backend.guard(context, { session_id: parsed.value.session_id });
205
+ if (!result.ok)
206
+ return result;
207
+ if (result.value.allowed)
208
+ return { ok: true, value: result.value };
209
+ const code = result.value.code === "ALLOWED" ? "OPERATION_REJECTED" : result.value.code;
210
+ return failure(new DomainError(code, `Guard denied the current worktree: ${code}.`, {
211
+ allowed: false,
212
+ repository: result.value.repository,
213
+ worktree: result.value.worktree,
214
+ branch: result.value.branch,
215
+ session_id: result.value.session_id,
216
+ owner_session_id: result.value.owner_session_id,
217
+ requested_session_id: result.value.requested_session_id,
218
+ state: result.value.state,
219
+ details: result.value.details,
220
+ }));
221
+ }
222
+ if (command === "gc") {
223
+ const parsed = parseOptions([subcommand, ...rest].filter((argument) => argument !== undefined), new Set(["--apply", "--dry-run"]));
224
+ if (!parsed.ok)
225
+ return parsed;
226
+ const options = { apply: parsed.value.apply };
227
+ const result = await dependencies.backend.garbageCollect(context, options);
228
+ return result.ok ? { ok: true, value: result.value } : result;
229
+ }
230
+ if (command === "doctor") {
231
+ const parsed = noOptions([subcommand, ...rest].filter((argument) => argument !== undefined));
232
+ if (!parsed.ok)
233
+ return parsed;
234
+ const report = await runDoctor(dependencies.cwd);
235
+ if (!report.ok)
236
+ return report;
237
+ if (report.value.ok)
238
+ return { ok: true, value: report.value };
239
+ return failure(new DomainError("DOCTOR_FAILED", "One or more local Nawabari checks failed.", {
240
+ checks: report.value.checks,
241
+ repository: report.value.repository,
242
+ }));
243
+ }
244
+ if (command === undefined)
245
+ return failure(new DomainError("NO_COMMAND", "A command is required."));
246
+ return failure(new DomainError("UNKNOWN_COMMAND", `Unknown command: ${command}.`, { command }));
247
+ }
248
+ function commandName(commandArguments) {
249
+ if (commandArguments[0] === "session")
250
+ return commandArguments.slice(0, 2).join(" ");
251
+ return commandArguments[0] ?? "cli";
252
+ }
253
+ function emitFailure(mode, command, error, io) {
254
+ io[mode === "json" ? "stdout" : "stderr"](renderFailure(mode, command, error));
255
+ return error.exitCode;
256
+ }
257
+ export async function runCli(argv, dependencies = {}) {
258
+ const io = dependencies.io ?? defaultCliIO();
259
+ const mode = argv.includes("--json") ? "json" : "human";
260
+ const parsed = parseGlobalArguments(argv);
261
+ if (!parsed.ok)
262
+ return emitFailure(mode, "cli", parsed.error, io);
263
+ if (parsed.value.help) {
264
+ if (mode === "json")
265
+ io.stdout(renderSuccess(mode, "help", HELP_DATA));
266
+ else
267
+ io.stdout(HELP_TEXT);
268
+ return EXIT_CODES.success;
269
+ }
270
+ if (parsed.value.version) {
271
+ const payload = { version: dependencies.version ?? VERSION };
272
+ if (mode === "json")
273
+ io.stdout(renderSuccess(mode, "version", payload));
274
+ else
275
+ io.stdout(String(payload.version));
276
+ return EXIT_CODES.success;
277
+ }
278
+ if (parsed.value.commandArguments.length === 0) {
279
+ if (mode === "json")
280
+ return emitFailure(mode, "cli", new DomainError("NO_COMMAND", "A command is required."), io);
281
+ io.stdout(HELP_TEXT);
282
+ return EXIT_CODES.usage;
283
+ }
284
+ const command = commandName(parsed.value.commandArguments);
285
+ const cwd = dependencies.cwd ?? process.cwd();
286
+ try {
287
+ const backend = dependencies.backend ?? createLocalSessionBackend();
288
+ const result = await executeCommand(parsed.value.commandArguments, { backend, cwd });
289
+ if (!result.ok)
290
+ return emitFailure(mode, command, result.error, io);
291
+ io.stdout(renderSuccess(mode, command, result.value));
292
+ return EXIT_CODES.success;
293
+ }
294
+ catch {
295
+ return emitFailure(mode, command, new DomainError("INTERNAL_ERROR", "An unexpected internal error occurred."), io);
296
+ }
297
+ }
298
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ import { type DomainResult, type ErrorCode, type JsonObject } from "./errors.js";
2
+ export type DoctorCheckStatus = "ok" | "warning" | "error" | "not_configured" | "not_applicable";
3
+ export type DoctorCheck = {
4
+ name: "git" | "repository" | "registry" | "runtime";
5
+ status: DoctorCheckStatus;
6
+ code: ErrorCode | null;
7
+ message: string;
8
+ details: JsonObject;
9
+ };
10
+ export type RepositoryInfo = {
11
+ top_level: string;
12
+ common_dir: string;
13
+ registry_path: string;
14
+ };
15
+ export type DoctorReport = {
16
+ ok: boolean;
17
+ checks: DoctorCheck[];
18
+ repository: RepositoryInfo | null;
19
+ };
20
+ export declare function runDoctor(cwd?: string): Promise<DomainResult<DoctorReport>>;
@@ -0,0 +1,167 @@
1
+ import { spawn } from "node:child_process";
2
+ import { readFile } from "node:fs/promises";
3
+ import path from "node:path";
4
+ import process from "node:process";
5
+ import { SessionRegistry } from "../session-registry.js";
6
+ import { isSessionRegistryError } from "../errors.js";
7
+ import { success } from "./errors.js";
8
+ function runGit(args, cwd) {
9
+ return new Promise((resolve) => {
10
+ const child = spawn("git", args, {
11
+ cwd,
12
+ stdio: ["ignore", "pipe", "pipe"],
13
+ env: { ...process.env, GIT_TERMINAL_PROMPT: "0", GIT_OPTIONAL_LOCKS: "0" },
14
+ });
15
+ let stdout = "";
16
+ let stderr = "";
17
+ let settled = false;
18
+ const timer = setTimeout(() => {
19
+ if (settled)
20
+ return;
21
+ settled = true;
22
+ child.kill("SIGKILL");
23
+ resolve({ exit_code: null, stdout, stderr, error: "git command timed out" });
24
+ }, 10_000);
25
+ child.stdout.setEncoding("utf8");
26
+ child.stderr.setEncoding("utf8");
27
+ child.stdout.on("data", (chunk) => {
28
+ stdout += chunk;
29
+ });
30
+ child.stderr.on("data", (chunk) => {
31
+ stderr += chunk;
32
+ });
33
+ child.on("error", (error) => {
34
+ if (settled)
35
+ return;
36
+ settled = true;
37
+ clearTimeout(timer);
38
+ resolve({ exit_code: null, stdout, stderr, error: error.message });
39
+ });
40
+ child.on("close", (exitCode) => {
41
+ if (settled)
42
+ return;
43
+ settled = true;
44
+ clearTimeout(timer);
45
+ resolve({ exit_code: exitCode, stdout, stderr, error: null });
46
+ });
47
+ });
48
+ }
49
+ function supportsRuntime(version) {
50
+ const [majorText, minorText] = version.split(".");
51
+ const major = Number(majorText);
52
+ const minor = Number(minorText);
53
+ return Number.isFinite(major) && Number.isFinite(minor) && (major > 22 || (major === 22 && minor >= 13));
54
+ }
55
+ function check(name, status, code, message, details = {}) {
56
+ return { name, status, code, message, details };
57
+ }
58
+ function parseRepository(stdout, cwd) {
59
+ const lines = stdout
60
+ .trim()
61
+ .split(/\r?\n/u)
62
+ .map((line) => line.trim());
63
+ if (lines.length < 2 || lines[0] === "" || lines[1] === "")
64
+ return null;
65
+ const topLevel = path.resolve(cwd, lines[0]);
66
+ const commonDir = path.resolve(cwd, lines[1]);
67
+ return {
68
+ top_level: topLevel,
69
+ common_dir: commonDir,
70
+ registry_path: path.join(commonDir, "nawabari", "session-registry.json"),
71
+ };
72
+ }
73
+ async function inspectRegistry(repository) {
74
+ try {
75
+ const contents = await readFile(repository.registry_path, "utf8");
76
+ let parsed;
77
+ try {
78
+ parsed = JSON.parse(contents);
79
+ }
80
+ catch {
81
+ return check("registry", "error", "REGISTRY_CORRUPT", "The Nawabari registry is not valid JSON.", {
82
+ path: repository.registry_path,
83
+ });
84
+ }
85
+ if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
86
+ return check("registry", "error", "INVALID_REGISTRY", "The Nawabari registry must contain a JSON object.", {
87
+ path: repository.registry_path,
88
+ });
89
+ }
90
+ try {
91
+ const registry = new SessionRegistry({ cwd: repository.top_level });
92
+ const sessions = registry.list();
93
+ return check("registry", "ok", null, "The Nawabari registry is readable and valid.", {
94
+ path: repository.registry_path,
95
+ bytes: contents.length,
96
+ sessions: sessions.length,
97
+ });
98
+ }
99
+ catch (error) {
100
+ const code = isSessionRegistryError(error) && error.code === "UNSUPPORTED_SCHEMA_VERSION"
101
+ ? "REGISTRY_CORRUPT"
102
+ : isSessionRegistryError(error) && error.code === "REGISTRY_REPOSITORY_MISMATCH"
103
+ ? "INVALID_REGISTRY"
104
+ : "REGISTRY_UNREADABLE";
105
+ return check("registry", "error", code, "The Nawabari registry failed authoritative validation.", {
106
+ path: repository.registry_path,
107
+ });
108
+ }
109
+ }
110
+ catch (error) {
111
+ if (isFileNotFound(error)) {
112
+ return check("registry", "not_configured", null, "The Nawabari session registry is not initialized.", {
113
+ path: repository.registry_path,
114
+ });
115
+ }
116
+ return check("registry", "error", "REGISTRY_UNREADABLE", "The Nawabari registry cannot be read.", {
117
+ path: repository.registry_path,
118
+ });
119
+ }
120
+ }
121
+ function isFileNotFound(error) {
122
+ return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
123
+ }
124
+ export async function runDoctor(cwd = process.cwd()) {
125
+ const checks = [];
126
+ const runtimeOk = supportsRuntime(process.versions.node);
127
+ checks.push(runtimeOk
128
+ ? check("runtime", "ok", null, "The Nawabari runtime meets the supported Node.js version.", {
129
+ node: process.versions.node,
130
+ })
131
+ : check("runtime", "error", "UNSUPPORTED_RUNTIME", "The Node.js runtime is below the supported version.", {
132
+ node: process.versions.node,
133
+ }));
134
+ const gitVersion = await runGit(["--version"], cwd);
135
+ if (gitVersion.exit_code !== 0) {
136
+ checks.push(check("git", "error", "GIT_UNAVAILABLE", "Git is not available to the local CLI.", {
137
+ command: "git --version",
138
+ reason: gitVersion.error ?? gitVersion.stderr.trim(),
139
+ }));
140
+ checks.push(check("repository", "not_applicable", null, "Repository resolution was skipped because Git is unavailable."));
141
+ checks.push(check("registry", "not_applicable", null, "Registry inspection was skipped because Git is unavailable."));
142
+ }
143
+ else {
144
+ checks.push(check("git", "ok", null, "Git is available.", { version: gitVersion.stdout.trim() }));
145
+ const repositoryResult = await runGit(["rev-parse", "--show-toplevel", "--git-common-dir"], cwd);
146
+ const repository = repositoryResult.exit_code === 0 ? parseRepository(repositoryResult.stdout, cwd) : null;
147
+ if (repository === null) {
148
+ checks.push(check("repository", "error", "NOT_GIT_REPOSITORY", "The current directory is not a Git repository.", {
149
+ command: "git rev-parse --show-toplevel --git-common-dir",
150
+ reason: repositoryResult.stderr.trim(),
151
+ }));
152
+ checks.push(check("registry", "not_applicable", null, "Registry inspection was skipped outside a Git repository."));
153
+ }
154
+ else {
155
+ checks.push(check("repository", "ok", null, "Repository and common Git directory resolved.", {
156
+ top_level: repository.top_level,
157
+ common_dir: repository.common_dir,
158
+ }));
159
+ checks.push(await inspectRegistry(repository));
160
+ }
161
+ const hasError = checks.some((item) => item.status === "error");
162
+ return success({ ok: !hasError, checks, repository });
163
+ }
164
+ const hasError = checks.some((item) => item.status === "error");
165
+ return success({ ok: !hasError, checks, repository: null });
166
+ }
167
+ //# sourceMappingURL=doctor.js.map