@astrosheep/keiyaku 4.6.8 → 4.6.9
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/README.md +40 -14
- package/build/plugins/claude/.claude-plugin/plugin.json +1 -1
- package/build/plugins/claude/skills/keiyaku/SKILL.md +5 -6
- package/build/plugins/claude/skills/keiyaku-akuma/SKILL.md +1 -1
- package/build/plugins/claude/skills/keiyaku-akuma/references/automation.md +8 -8
- package/build/plugins/claude/skills/keiyaku-babysit/SKILL.md +1 -1
- package/build/plugins/claude/skills/keiyaku-bind/SKILL.md +9 -9
- package/build/plugins/claude/skills/keiyaku-debt/SKILL.md +91 -0
- package/build/plugins/claude/skills/keiyaku-workflow/SKILL.md +2 -2
- package/build/plugins/codex/.codex-plugin/plugin.json +1 -1
- package/build/plugins/codex/skills/keiyaku/SKILL.md +5 -6
- package/build/plugins/codex/skills/keiyaku-akuma/SKILL.md +1 -1
- package/build/plugins/codex/skills/keiyaku-akuma/references/automation.md +8 -8
- package/build/plugins/codex/skills/keiyaku-babysit/SKILL.md +1 -1
- package/build/plugins/codex/skills/keiyaku-bind/SKILL.md +9 -9
- package/build/plugins/codex/skills/keiyaku-debt/SKILL.md +91 -0
- package/build/plugins/codex/skills/keiyaku-workflow/SKILL.md +2 -2
- package/build/plugins/opencode/index.js +1 -1
- package/build/plugins/opencode/skills/keiyaku/SKILL.md +5 -6
- package/build/plugins/opencode/skills/keiyaku-akuma/SKILL.md +1 -1
- package/build/plugins/opencode/skills/keiyaku-akuma/references/automation.md +8 -8
- package/build/plugins/opencode/skills/keiyaku-babysit/SKILL.md +1 -1
- package/build/plugins/opencode/skills/keiyaku-bind/SKILL.md +9 -9
- package/build/plugins/opencode/skills/keiyaku-debt/SKILL.md +91 -0
- package/build/plugins/opencode/skills/keiyaku-workflow/SKILL.md +2 -2
- package/build/skills/keiyaku/SKILL.md +5 -6
- package/build/skills/keiyaku-akuma/SKILL.md +1 -1
- package/build/skills/keiyaku-akuma/references/automation.md +8 -8
- package/build/skills/keiyaku-babysit/SKILL.md +1 -1
- package/build/skills/keiyaku-bind/SKILL.md +9 -9
- package/build/skills/keiyaku-debt/SKILL.md +91 -0
- package/build/skills/keiyaku-workflow/SKILL.md +2 -2
- package/build/src/akuma/akuma-instance.d.ts +2 -0
- package/build/src/akuma/akuma-instance.js +10 -0
- package/build/src/akuma/akuma-observe.d.ts +33 -8
- package/build/src/akuma/akuma-observe.js +88 -64
- package/build/src/akuma/akuma-owner.d.ts +11 -2
- package/build/src/akuma/akuma-owner.js +45 -35
- package/build/src/akuma/akuma-selection-execution.js +9 -1
- package/build/src/akuma/akuma-stream.d.ts +22 -0
- package/build/src/akuma/akuma-stream.js +116 -0
- package/build/src/akuma/akuma-wait.d.ts +1 -40
- package/build/src/akuma/akuma-wait.js +23 -84
- package/build/src/akuma/akuma.d.ts +17 -11
- package/build/src/akuma/akuma.js +2 -0
- package/build/src/akuma/allowed.d.ts +7 -12
- package/build/src/akuma/allowed.js +13 -4
- package/build/src/akuma/body-supervisor.d.ts +5 -5
- package/build/src/akuma/body-supervisor.js +22 -20
- package/build/src/akuma/body.js +28 -1
- package/build/src/akuma/call-request.d.ts +12 -22
- package/build/src/akuma/heart/activity-schema.d.ts +12 -0
- package/build/src/akuma/heart/activity-schema.js +6 -0
- package/build/src/akuma/heart/index.d.ts +59 -2
- package/build/src/akuma/heart/index.js +87 -8
- package/build/src/akuma/heart/rows.js +5 -3
- package/build/src/akuma/heart/soul.d.ts +9 -0
- package/build/src/akuma/heart/soul.js +29 -0
- package/build/src/akuma/heart/storage.d.ts +15 -0
- package/build/src/akuma/heart/storage.js +55 -0
- package/build/src/akuma/heart/timeline.d.ts +7 -0
- package/build/src/akuma/heart/timeline.js +10 -0
- package/build/src/akuma/index.d.ts +1 -0
- package/build/src/akuma/projection.d.ts +25 -0
- package/build/src/akuma/projection.js +24 -7
- package/build/src/akuma/provider-recipe.d.ts +11 -0
- package/build/src/akuma/provider-recipe.js +23 -0
- package/build/src/akuma/provider.d.ts +25 -0
- package/build/src/akuma/provider.js +99 -7
- package/build/src/akuma/providers/acp/events.js +25 -2
- package/build/src/akuma/providers/claude/events.js +76 -10
- package/build/src/akuma/providers/claude/index.js +2 -5
- package/build/src/akuma/providers/codex-app-server/events.js +17 -2
- package/build/src/akuma/providers/codex-app-server/index.js +15 -9
- package/build/src/akuma/providers/decode.d.ts +8 -0
- package/build/src/akuma/providers/decode.js +21 -0
- package/build/src/akuma/providers/grok-build/index.js +10 -26
- package/build/src/akuma/providers/opencode-sdk/event-stream.d.ts +3 -3
- package/build/src/akuma/providers/opencode-sdk/event-stream.js +2 -25
- package/build/src/akuma/providers/opencode-sdk/events.d.ts +7 -43
- package/build/src/akuma/providers/opencode-sdk/events.js +147 -284
- package/build/src/akuma/providers/opencode-sdk/index.js +267 -421
- package/build/src/akuma/providers/opencode-sdk/native-http.d.ts +9 -0
- package/build/src/akuma/providers/opencode-sdk/native-http.js +69 -0
- package/build/src/akuma/providers/opencode-sdk/session.d.ts +42 -36
- package/build/src/akuma/providers/opencode-sdk/session.js +75 -82
- package/build/src/akuma/providers/paseo/events.d.ts +8 -0
- package/build/src/akuma/providers/paseo/events.js +58 -11
- package/build/src/akuma/providers/paseo/index.js +11 -7
- package/build/src/akuma/providers/pi/events.d.ts +2 -0
- package/build/src/akuma/providers/pi/events.js +32 -24
- package/build/src/akuma/providers/pi/index.js +21 -35
- package/build/src/akuma/request-lifecycle.d.ts +1 -2
- package/build/src/akuma/request-lifecycle.js +2 -8
- package/build/src/akuma/request-rendezvous.js +38 -55
- package/build/src/akuma/request-serve.d.ts +1 -1
- package/build/src/akuma/request-serve.js +77 -113
- package/build/src/akuma/selection-observation.d.ts +57 -51
- package/build/src/akuma/selection-observation.js +3 -3
- package/build/src/akuma/turn-drive.d.ts +3 -0
- package/build/src/akuma/turn-drive.js +26 -5
- package/build/src/akuma-body.js +12 -22
- package/build/src/cli/akuma-caller.js +10 -0
- package/build/src/cli/commands/akuma-grammar.js +3 -4
- package/build/src/cli/commands/akuma.js +13 -51
- package/build/src/cli/commands/contract-grammar.d.ts +7 -6
- package/build/src/cli/commands/contract-grammar.js +27 -32
- package/build/src/cli/commands/contract-help.d.ts +16 -7
- package/build/src/cli/commands/contract-help.js +20 -11
- package/build/src/cli/commands/contract.js +11 -11
- package/build/src/cli/commands/debt-grammar.d.ts +19 -0
- package/build/src/cli/commands/debt-grammar.js +323 -0
- package/build/src/cli/commands/debt-query.d.ts +5 -0
- package/build/src/cli/commands/{task-query.js → debt-query.js} +9 -9
- package/build/src/cli/commands/{task.d.ts → debt.d.ts} +2 -2
- package/build/src/cli/commands/{task.js → debt.js} +83 -143
- package/build/src/cli/coordinates.d.ts +1 -1
- package/build/src/cli/coordinates.js +1 -1
- package/build/src/cli/parse.d.ts +4 -4
- package/build/src/cli/parse.js +17 -16
- package/build/src/cli/render/akuma-activity.d.ts +11 -83
- package/build/src/cli/render/akuma-activity.js +20 -382
- package/build/src/cli/render/catalog.d.ts +2 -2
- package/build/src/cli/render/catalog.js +5 -5
- package/build/src/cli/render/contract.js +2 -2
- package/build/src/cli/render/debt.d.ts +28 -0
- package/build/src/cli/render/{task.js → debt.js} +51 -112
- package/build/src/cli/render/kanshi.js +28 -28
- package/build/src/cli/render/marks.d.ts +5 -5
- package/build/src/cli/render/marks.js +4 -10
- package/build/src/cli/render/nuke.js +1 -1
- package/build/src/cli/runtime.js +3 -3
- package/build/src/cli/scan.d.ts +1 -1
- package/build/src/cli/usage.d.ts +1 -1
- package/build/src/cli/usage.js +4 -4
- package/build/src/contract-worktree.js +3 -3
- package/build/src/debt/board.d.ts +160 -0
- package/build/src/{task → debt}/board.js +89 -89
- package/build/src/debt/catalog.d.ts +11 -0
- package/build/src/debt/catalog.js +59 -0
- package/build/src/{task → debt}/context.d.ts +1 -1
- package/build/src/{task → debt}/context.js +1 -1
- package/build/src/{task → debt}/created-observation.d.ts +6 -10
- package/build/src/{task → debt}/created-observation.js +7 -7
- package/build/src/debt/document.d.ts +37 -0
- package/build/src/{task → debt}/document.js +37 -37
- package/build/src/debt/identity.d.ts +21 -0
- package/build/src/{task → debt}/identity.js +35 -35
- package/build/src/debt/index.d.ts +111 -0
- package/build/src/debt/index.js +203 -0
- package/build/src/{task → debt}/input.d.ts +8 -8
- package/build/src/{task → debt}/input.js +21 -21
- package/build/src/debt/lifecycle-operations.d.ts +6 -0
- package/build/src/{task → debt}/lifecycle-operations.js +27 -31
- package/build/src/debt/mutation-result.d.ts +981 -0
- package/build/src/debt/mutation-result.js +109 -0
- package/build/src/debt/mutation.d.ts +424 -0
- package/build/src/debt/mutation.js +223 -0
- package/build/src/debt/operation-types.d.ts +71 -0
- package/build/src/debt/operations.d.ts +28 -0
- package/build/src/{task → debt}/operations.js +59 -60
- package/build/src/debt/query.d.ts +76 -0
- package/build/src/{task → debt}/query.js +55 -55
- package/build/src/{task → debt}/store.d.ts +13 -13
- package/build/src/{task → debt}/store.js +58 -49
- package/build/src/debt/view.d.ts +4 -0
- package/build/src/debt/view.js +7 -0
- package/build/src/identity/coordinates.d.ts +1 -1
- package/build/src/index.d.ts +13 -13
- package/build/src/index.js +9 -9
- package/build/src/kanshi/index.d.ts +1 -1
- package/build/src/kanshi/read.js +33 -33
- package/build/src/kanshi/report.d.ts +7 -7
- package/build/src/kanshi/select.js +4 -4
- package/build/src/library/akumas.d.ts +2 -3
- package/build/src/library/bind.d.ts +3 -3
- package/build/src/library/bind.js +5 -5
- package/build/src/library/contract-creation.js +5 -5
- package/build/src/library/contract-execution.js +4 -4
- package/build/src/library/contract-types.d.ts +2 -2
- package/build/src/library/input.d.ts +2 -2
- package/build/src/library/input.js +5 -5
- package/build/src/library/invocation.js +2 -2
- package/build/src/library/nuke.js +3 -3
- package/build/src/library/outcome.d.ts +126 -126
- package/build/src/library/outcome.js +3 -3
- package/build/src/library/selection.d.ts +1 -4
- package/build/src/library/selection.js +11 -62
- package/build/src/plugin/public.d.ts +5 -0
- package/build/src/plugin/runtime.js +3 -1
- package/build/src/runtime/proc/windows-launch.exe +0 -0
- package/build/src/settlement/fence.d.ts +3 -3
- package/build/src/settlement/fence.js +4 -4
- package/build/src/settlement/holder.d.ts +16 -16
- package/build/src/settlement/holder.js +69 -63
- package/build/src/settlement/settle.d.ts +5 -5
- package/build/src/settlement/settle.js +53 -53
- package/package.json +12 -6
- package/plugins/paseo/plugin/index.server.ts +17 -0
- package/plugins/paseo/plugin/paseo-plugin.json +4 -0
- package/plugins/paseo/plugin/server/attach.ts +52 -0
- package/plugins/paseo/plugin/server/keiyaku.ts +44 -0
- package/plugins/paseo/plugin/server/message.ts +60 -0
- package/plugins/paseo/plugin/server/mirror.ts +193 -0
- package/plugins/paseo/plugin/server/model.ts +14 -0
- package/plugins/paseo/plugin/server/provider.ts +276 -0
- package/plugins/paseo/plugin/server/sdk-worker.ts +237 -0
- package/plugins/paseo/plugin/server/sdk.ts +289 -0
- package/plugins/paseo/plugin/server/stop.ts +26 -0
- package/plugins/paseo/plugin/server/transport.ts +35 -0
- package/plugins/paseo/plugin/shared/attach-rpc.ts +10 -0
- package/plugins/paseo/plugin/shared/refresh-rpc.ts +6 -0
- package/plugins/paseo/plugin/tsconfig.json +6 -0
- package/skills/keiyaku/SKILL.md +5 -6
- package/skills/keiyaku-akuma/SKILL.md +1 -1
- package/skills/keiyaku-akuma/references/automation.md +8 -8
- package/skills/keiyaku-babysit/SKILL.md +1 -1
- package/skills/keiyaku-bind/SKILL.md +9 -9
- package/skills/keiyaku-debt/SKILL.md +91 -0
- package/skills/keiyaku-workflow/SKILL.md +2 -2
- package/build/plugins/claude/skills/keiyaku-task/SKILL.md +0 -104
- package/build/plugins/codex/skills/keiyaku-task/SKILL.md +0 -104
- package/build/plugins/opencode/skills/keiyaku-task/SKILL.md +0 -104
- package/build/skills/keiyaku-task/SKILL.md +0 -104
- package/build/src/cli/commands/task-grammar.d.ts +0 -19
- package/build/src/cli/commands/task-grammar.js +0 -384
- package/build/src/cli/commands/task-query.d.ts +0 -5
- package/build/src/cli/render/task.d.ts +0 -39
- package/build/src/task/board.d.ts +0 -168
- package/build/src/task/catalog.d.ts +0 -11
- package/build/src/task/catalog.js +0 -59
- package/build/src/task/compose-language.d.ts +0 -57
- package/build/src/task/compose-language.js +0 -364
- package/build/src/task/compose-parser.d.ts +0 -32
- package/build/src/task/compose-parser.js +0 -180
- package/build/src/task/compose.d.ts +0 -16
- package/build/src/task/compose.js +0 -189
- package/build/src/task/document.d.ts +0 -39
- package/build/src/task/identity.d.ts +0 -21
- package/build/src/task/index.d.ts +0 -138
- package/build/src/task/index.js +0 -269
- package/build/src/task/lifecycle-operations.d.ts +0 -6
- package/build/src/task/mutation-result.d.ts +0 -1726
- package/build/src/task/mutation-result.js +0 -198
- package/build/src/task/mutation.d.ts +0 -590
- package/build/src/task/mutation.js +0 -262
- package/build/src/task/operation-types.d.ts +0 -71
- package/build/src/task/operations.d.ts +0 -28
- package/build/src/task/query.d.ts +0 -76
- package/build/src/task/view.d.ts +0 -4
- package/build/src/task/view.js +0 -7
- package/skills/keiyaku-task/SKILL.md +0 -104
- /package/build/src/{task → debt}/operation-types.js +0 -0
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import {
|
|
2
|
+
import { createDebtRelations, projectCreatedByRows, debtRowsSchema } from "./board.js";
|
|
3
3
|
import { readBoard } from "./store.js";
|
|
4
|
-
export const
|
|
5
|
-
z.object({ kind: z.literal("present"), rows:
|
|
4
|
+
export const createdDebtObservationSchema = z.union([
|
|
5
|
+
z.object({ kind: z.literal("present"), rows: debtRowsSchema }).strict(),
|
|
6
6
|
z.object({ kind: z.literal("failed"), diagnostic: z.string() }).strict(),
|
|
7
7
|
]);
|
|
8
|
-
export const
|
|
8
|
+
export const EMPTY_CREATED_DEBT_OBSERVATION = { kind: "present", rows: [] };
|
|
9
9
|
function observationDiagnostic(error) {
|
|
10
10
|
return error instanceof Error ? error.message : String(error);
|
|
11
11
|
}
|
|
12
12
|
/**
|
|
13
|
-
* Project
|
|
13
|
+
* Project Debt board rows created by each identity, preserving input order. One complete
|
|
14
14
|
* board and one relationship projection answer every requested identity, and only the
|
|
15
15
|
* documents those identities created reach row projection.
|
|
16
16
|
*/
|
|
17
|
-
export async function
|
|
17
|
+
export async function observeCreatedDebtObservations(world, createdByIds) {
|
|
18
18
|
if (createdByIds.length === 0)
|
|
19
19
|
return [];
|
|
20
20
|
let board;
|
|
@@ -25,6 +25,6 @@ export async function observeCreatedTaskObservations(world, createdByIds) {
|
|
|
25
25
|
const failed = { kind: "failed", diagnostic: observationDiagnostic(error) };
|
|
26
26
|
return createdByIds.map(() => failed);
|
|
27
27
|
}
|
|
28
|
-
const rows = projectCreatedByRows(board,
|
|
28
|
+
const rows = projectCreatedByRows(board, createDebtRelations(board), createdByIds);
|
|
29
29
|
return createdByIds.map((createdBy) => ({ kind: "present", rows: rows.get(createdBy) ?? [] }));
|
|
30
30
|
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { type DebtCoordinate, type DebtId } from "./identity.js";
|
|
3
|
+
export declare const debtNonblankTextSchema: z.ZodString;
|
|
4
|
+
export declare const debtStateSchema: z.ZodEnum<{
|
|
5
|
+
open: "open";
|
|
6
|
+
done: "done";
|
|
7
|
+
drop: "drop";
|
|
8
|
+
}>;
|
|
9
|
+
export declare const debtPrioritySchema: z.ZodUnion<readonly [z.ZodLiteral<0>, z.ZodLiteral<1>, z.ZodLiteral<2>, z.ZodLiteral<3>]>;
|
|
10
|
+
export type DebtState = z.infer<typeof debtStateSchema>;
|
|
11
|
+
export type DebtPriority = z.infer<typeof debtPrioritySchema>;
|
|
12
|
+
export type DebtDocument = Readonly<{
|
|
13
|
+
id: DebtId;
|
|
14
|
+
title: string;
|
|
15
|
+
state: DebtState;
|
|
16
|
+
priority: DebtPriority;
|
|
17
|
+
needs: readonly DebtId[];
|
|
18
|
+
parent: DebtId | null;
|
|
19
|
+
supersedes: readonly DebtId[];
|
|
20
|
+
relates: readonly DebtId[];
|
|
21
|
+
note: string;
|
|
22
|
+
createdBy?: string;
|
|
23
|
+
createdAt: string;
|
|
24
|
+
updatedAt: string;
|
|
25
|
+
body: string;
|
|
26
|
+
}>;
|
|
27
|
+
export type DebtCreationDocument = Omit<DebtDocument, "id" | "createdBy" | "createdAt" | "updatedAt">;
|
|
28
|
+
export declare class DebtAuthorityCorruptionError extends Error {
|
|
29
|
+
/** The Debt document whose bytes failed decode, when the reader knew its coordinate. */
|
|
30
|
+
readonly coordinate?: DebtId;
|
|
31
|
+
constructor(message: string, options?: ErrorOptions & {
|
|
32
|
+
coordinate?: DebtId;
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
export declare function parseDebtDocument(bytes: Uint8Array, expected: DebtCoordinate): DebtDocument;
|
|
36
|
+
export declare function parseDebtCreationDocument(markdown: string): DebtCreationDocument;
|
|
37
|
+
export declare function serializeDebtDocument(document: DebtDocument): Uint8Array;
|
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
import { isMap, parseDocument, stringify } from "yaml";
|
|
2
2
|
import { z } from "zod";
|
|
3
|
-
import {
|
|
4
|
-
export const
|
|
5
|
-
export const
|
|
6
|
-
export const
|
|
7
|
-
export class
|
|
8
|
-
/** The
|
|
3
|
+
import { formatDebtId, parseDebtId } from "./identity.js";
|
|
4
|
+
export const debtNonblankTextSchema = z.string().refine((value) => value.trim() !== "");
|
|
5
|
+
export const debtStateSchema = z.enum(["open", "done", "drop"]);
|
|
6
|
+
export const debtPrioritySchema = z.union([z.literal(0), z.literal(1), z.literal(2), z.literal(3)]);
|
|
7
|
+
export class DebtAuthorityCorruptionError extends Error {
|
|
8
|
+
/** The Debt document whose bytes failed decode, when the reader knew its coordinate. */
|
|
9
9
|
coordinate;
|
|
10
10
|
constructor(message, options) {
|
|
11
11
|
super(message, options);
|
|
12
|
-
this.name = "
|
|
12
|
+
this.name = "DebtAuthorityCorruptionError";
|
|
13
13
|
if (options?.coordinate !== undefined)
|
|
14
14
|
this.coordinate = options.coordinate;
|
|
15
15
|
}
|
|
16
16
|
}
|
|
17
|
-
const STATES = new Set(["open", "
|
|
17
|
+
const STATES = new Set(["open", "done", "drop"]);
|
|
18
18
|
const REQUIRED_STORED_KEYS = [
|
|
19
19
|
"id",
|
|
20
20
|
"title",
|
|
@@ -32,41 +32,41 @@ const STORED_KEYS = [...REQUIRED_STORED_KEYS, "createdBy"];
|
|
|
32
32
|
const CREATION_KEYS = ["title", "state", "priority", "needs", "parent", "supersedes", "relates", "note"];
|
|
33
33
|
function frontMatter(markdown, fail) {
|
|
34
34
|
if (!markdown.startsWith("---\n"))
|
|
35
|
-
fail("
|
|
35
|
+
fail("debt document must begin with YAML front matter");
|
|
36
36
|
const end = markdown.indexOf("\n---\n", 4);
|
|
37
37
|
if (end < 0)
|
|
38
|
-
fail("
|
|
38
|
+
fail("debt document front matter is not closed");
|
|
39
39
|
const source = markdown.slice(4, end);
|
|
40
40
|
const parsed = parseDocument(source, { merge: false, prettyErrors: false, strict: true, uniqueKeys: true });
|
|
41
41
|
if (parsed.errors.length > 0 || parsed.warnings.length > 0 || !isMap(parsed.contents)) {
|
|
42
|
-
fail("
|
|
42
|
+
fail("debt front matter must be one strict YAML mapping", parsed.errors[0]);
|
|
43
43
|
}
|
|
44
44
|
const value = parsed.toJS({ maxAliasCount: 0 });
|
|
45
45
|
if (typeof value !== "object" || value === null || Array.isArray(value))
|
|
46
|
-
fail("
|
|
46
|
+
fail("debt front matter must be a mapping");
|
|
47
47
|
return { value: value, body: markdown.slice(end + 5) };
|
|
48
48
|
}
|
|
49
49
|
function closed(value, allowed, required, fail) {
|
|
50
50
|
for (const key of Object.keys(value))
|
|
51
51
|
if (!allowed.includes(key))
|
|
52
|
-
fail(`unknown
|
|
52
|
+
fail(`unknown debt front matter key: ${key}`);
|
|
53
53
|
for (const key of required)
|
|
54
54
|
if (!Object.hasOwn(value, key))
|
|
55
|
-
fail(`
|
|
55
|
+
fail(`debt front matter is missing ${key}`);
|
|
56
56
|
}
|
|
57
57
|
function title(value, fail) {
|
|
58
58
|
if (typeof value !== "string" || value.trim().length === 0)
|
|
59
|
-
fail("
|
|
59
|
+
fail("debt title must be a nonblank string");
|
|
60
60
|
return value;
|
|
61
61
|
}
|
|
62
62
|
function priority(value, fail) {
|
|
63
63
|
if (!Number.isInteger(value) || typeof value !== "number" || value < 0 || value > 3)
|
|
64
|
-
fail("
|
|
64
|
+
fail("debt priority must be 0, 1, 2, or 3");
|
|
65
65
|
return value;
|
|
66
66
|
}
|
|
67
67
|
function state(value, fail) {
|
|
68
68
|
if (typeof value !== "string" || !STATES.has(value))
|
|
69
|
-
fail(
|
|
69
|
+
fail(`debt state is invalid: ${String(value)}`);
|
|
70
70
|
return value;
|
|
71
71
|
}
|
|
72
72
|
function timestamp(value, field, fail) {
|
|
@@ -75,27 +75,27 @@ function timestamp(value, field, fail) {
|
|
|
75
75
|
fail(`${field} must be a canonical UTC ISO timestamp`);
|
|
76
76
|
return value;
|
|
77
77
|
}
|
|
78
|
-
function
|
|
78
|
+
function debtId(value, field, fail) {
|
|
79
79
|
if (typeof value !== "string")
|
|
80
|
-
fail(`${field} must be a
|
|
80
|
+
fail(`${field} must be a DebtId`);
|
|
81
81
|
try {
|
|
82
|
-
|
|
82
|
+
parseDebtId(value);
|
|
83
83
|
return value;
|
|
84
84
|
}
|
|
85
85
|
catch {
|
|
86
|
-
return fail(`${field} must be a canonical
|
|
86
|
+
return fail(`${field} must be a canonical DebtId`);
|
|
87
87
|
}
|
|
88
88
|
}
|
|
89
|
-
function
|
|
89
|
+
function debtIds(value, field, fail) {
|
|
90
90
|
if (!Array.isArray(value))
|
|
91
91
|
fail(`${field} must be an array`);
|
|
92
|
-
const ids = value.map((item) =>
|
|
92
|
+
const ids = value.map((item) => debtId(item, field, fail));
|
|
93
93
|
if (new Set(ids).size !== ids.length)
|
|
94
94
|
fail(`${field} must not contain duplicates`);
|
|
95
95
|
return ids;
|
|
96
96
|
}
|
|
97
|
-
function
|
|
98
|
-
return value === null ? null :
|
|
97
|
+
function nullableDebtId(value, field, fail) {
|
|
98
|
+
return value === null ? null : debtId(value, field, fail);
|
|
99
99
|
}
|
|
100
100
|
function createdBy(value, fail) {
|
|
101
101
|
if (typeof value !== "string" || value.trim().length === 0)
|
|
@@ -106,24 +106,24 @@ function fields(value, body, fail) {
|
|
|
106
106
|
return {
|
|
107
107
|
title: title(value.title, fail),
|
|
108
108
|
priority: priority(value.priority, fail),
|
|
109
|
-
needs:
|
|
110
|
-
parent:
|
|
111
|
-
supersedes:
|
|
112
|
-
relates:
|
|
109
|
+
needs: debtIds(value.needs, "needs", fail),
|
|
110
|
+
parent: nullableDebtId(value.parent, "parent", fail),
|
|
111
|
+
supersedes: debtIds(value.supersedes, "supersedes", fail),
|
|
112
|
+
relates: debtIds(value.relates, "relates", fail),
|
|
113
113
|
note: typeof value.note === "string" ? value.note : fail("note must be a string"),
|
|
114
114
|
body,
|
|
115
115
|
};
|
|
116
116
|
}
|
|
117
|
-
export function
|
|
118
|
-
const coordinate =
|
|
117
|
+
export function parseDebtDocument(bytes, expected) {
|
|
118
|
+
const coordinate = formatDebtId(expected);
|
|
119
119
|
const fail = (message, cause) => {
|
|
120
|
-
throw new
|
|
120
|
+
throw new DebtAuthorityCorruptionError(message, { coordinate, ...(cause === undefined ? {} : { cause }) });
|
|
121
121
|
};
|
|
122
122
|
const { value, body } = frontMatter(Buffer.from(bytes).toString("utf8"), fail);
|
|
123
123
|
closed(value, STORED_KEYS, REQUIRED_STORED_KEYS, fail);
|
|
124
|
-
const id =
|
|
125
|
-
if (id !==
|
|
126
|
-
fail(`
|
|
124
|
+
const id = debtId(value.id, "id", fail);
|
|
125
|
+
if (id !== formatDebtId(expected))
|
|
126
|
+
fail(`debt document ID ${id} does not match its authority path`);
|
|
127
127
|
const createdAt = timestamp(value.createdAt, "createdAt", fail), updatedAt = timestamp(value.updatedAt, "updatedAt", fail);
|
|
128
128
|
if (Date.parse(updatedAt) < Date.parse(createdAt))
|
|
129
129
|
fail("updatedAt must not precede createdAt");
|
|
@@ -136,7 +136,7 @@ export function parseTaskDocument(bytes, expected) {
|
|
|
136
136
|
...(Object.hasOwn(value, "createdBy") ? { createdBy: createdBy(value.createdBy, fail) } : {}),
|
|
137
137
|
};
|
|
138
138
|
}
|
|
139
|
-
export function
|
|
139
|
+
export function parseDebtCreationDocument(markdown) {
|
|
140
140
|
const fail = (message) => {
|
|
141
141
|
throw new TypeError(message);
|
|
142
142
|
};
|
|
@@ -154,7 +154,7 @@ export function parseTaskCreationDocument(markdown) {
|
|
|
154
154
|
};
|
|
155
155
|
return { state: state(complete.state, fail), ...fields(complete, body, fail) };
|
|
156
156
|
}
|
|
157
|
-
export function
|
|
157
|
+
export function serializeDebtDocument(document) {
|
|
158
158
|
const value = {
|
|
159
159
|
id: document.id,
|
|
160
160
|
title: document.title,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { type ContractId } from "../core/facts/types.js";
|
|
3
|
+
export type DebtId = `debt/${string}`;
|
|
4
|
+
export type DebtCoordinate = Readonly<{
|
|
5
|
+
namespace: readonly string[];
|
|
6
|
+
localId: string;
|
|
7
|
+
}>;
|
|
8
|
+
export declare const DEBT_LOCAL_ID_BYTES: number;
|
|
9
|
+
export declare function isDebtSegment(value: string): boolean;
|
|
10
|
+
export declare function parseDebtId(value: string): DebtCoordinate;
|
|
11
|
+
export declare function formatDebtId(coordinate: DebtCoordinate): DebtId;
|
|
12
|
+
export declare function canonicalDebtId(value: string): DebtId;
|
|
13
|
+
export declare const debtIdSchema: z.ZodPipe<z.ZodString, z.ZodTransform<`debt/${string}`, string>>;
|
|
14
|
+
export declare const debtNamespaceSchema: z.ZodReadonly<z.ZodArray<z.ZodString>>;
|
|
15
|
+
export declare const debtIdsSchema: z.ZodReadonly<z.ZodArray<z.ZodPipe<z.ZodString, z.ZodTransform<`debt/${string}`, string>>>>;
|
|
16
|
+
export declare function contractNamespace(id: ContractId): readonly string[];
|
|
17
|
+
export declare function debtAuthorityPath(debtsDirectory: string, coordinate: DebtCoordinate): string;
|
|
18
|
+
export declare function deriveLocalStem(title: string): string;
|
|
19
|
+
export declare function allocateLocalId(stem: string, occupied: ReadonlySet<string>): string;
|
|
20
|
+
export declare function physicalDebtSegment(segment: string, maxBytes?: number): string;
|
|
21
|
+
export declare function sameNamespace(left: readonly string[], right: readonly string[]): boolean;
|
|
@@ -5,72 +5,72 @@ import { contractSegment } from "../core/facts/types.js";
|
|
|
5
5
|
import { identityCoordinate, identitySegments } from "../identity/coordinates.js";
|
|
6
6
|
import { fitIdentityStem, normalizeIdentityStem } from "../identity/normalize.js";
|
|
7
7
|
const STEM_CODE_POINTS = 32;
|
|
8
|
-
const
|
|
9
|
-
const
|
|
10
|
-
const
|
|
8
|
+
const DEBT_FILENAME_BYTES = 255;
|
|
9
|
+
const DEBT_EXTENSION_BYTES = Buffer.byteLength(".md");
|
|
10
|
+
const DEBT_LOCK_EXTENSION_BYTES = Buffer.byteLength(".sqlite");
|
|
11
11
|
const GENERATED_SUFFIX = "-0000";
|
|
12
|
-
export const
|
|
13
|
-
const GENERATED_STEM_BYTES =
|
|
12
|
+
export const DEBT_LOCAL_ID_BYTES = DEBT_FILENAME_BYTES - DEBT_EXTENSION_BYTES - DEBT_LOCK_EXTENSION_BYTES - Buffer.byteLength(GENERATED_SUFFIX);
|
|
13
|
+
const GENERATED_STEM_BYTES = DEBT_LOCAL_ID_BYTES - Buffer.byteLength(GENERATED_SUFFIX);
|
|
14
14
|
const WINDOWS_RESERVED = /^(?:con|prn|aux|nul|clock\$|com[1-9]|lpt[1-9])(?:\..*)?$/iu;
|
|
15
|
-
export function
|
|
15
|
+
export function isDebtSegment(value) {
|
|
16
16
|
return (value.length > 0 &&
|
|
17
17
|
value !== "." &&
|
|
18
18
|
value !== ".." &&
|
|
19
19
|
!value.includes("/") &&
|
|
20
20
|
normalizeIdentityStem({ source: value }) === value);
|
|
21
21
|
}
|
|
22
|
-
export function
|
|
22
|
+
export function parseDebtId(value) {
|
|
23
23
|
let segments;
|
|
24
24
|
try {
|
|
25
|
-
segments = identitySegments({ family: "
|
|
25
|
+
segments = identitySegments({ family: "debt", value });
|
|
26
26
|
}
|
|
27
27
|
catch {
|
|
28
|
-
throw new TypeError("
|
|
28
|
+
throw new TypeError("debt ID must be debt/<local-id> or debt/<namespace...>/<local-id>");
|
|
29
29
|
}
|
|
30
|
-
if (!segments.every(
|
|
31
|
-
throw new TypeError("
|
|
30
|
+
if (!segments.every(isDebtSegment))
|
|
31
|
+
throw new TypeError("debt ID contains a noncanonical segment");
|
|
32
32
|
return { namespace: segments.slice(0, -1), localId: segments.at(-1) };
|
|
33
33
|
}
|
|
34
|
-
export function
|
|
35
|
-
if (![...coordinate.namespace, coordinate.localId].every(
|
|
36
|
-
throw new TypeError("
|
|
37
|
-
return identityCoordinate({ family: "
|
|
34
|
+
export function formatDebtId(coordinate) {
|
|
35
|
+
if (![...coordinate.namespace, coordinate.localId].every(isDebtSegment))
|
|
36
|
+
throw new TypeError("debt coordinate contains a noncanonical segment");
|
|
37
|
+
return identityCoordinate({ family: "debt", segments: [...coordinate.namespace, coordinate.localId] });
|
|
38
38
|
}
|
|
39
|
-
export function
|
|
40
|
-
const id =
|
|
39
|
+
export function canonicalDebtId(value) {
|
|
40
|
+
const id = formatDebtId(parseDebtId(value));
|
|
41
41
|
if (id !== value)
|
|
42
|
-
throw new TypeError("
|
|
42
|
+
throw new TypeError("debt ID is not canonical");
|
|
43
43
|
return id;
|
|
44
44
|
}
|
|
45
|
-
export const
|
|
45
|
+
export const debtIdSchema = z.string().transform((value, context) => {
|
|
46
46
|
try {
|
|
47
|
-
return
|
|
47
|
+
return canonicalDebtId(value);
|
|
48
48
|
}
|
|
49
49
|
catch {
|
|
50
|
-
context.addIssue({ code: "custom", message: "expected canonical
|
|
50
|
+
context.addIssue({ code: "custom", message: "expected canonical DebtId" });
|
|
51
51
|
return z.NEVER;
|
|
52
52
|
}
|
|
53
53
|
});
|
|
54
|
-
export const
|
|
55
|
-
export const
|
|
56
|
-
.array(
|
|
54
|
+
export const debtNamespaceSchema = z.array(z.string().refine(isDebtSegment)).readonly();
|
|
55
|
+
export const debtIdsSchema = z
|
|
56
|
+
.array(debtIdSchema)
|
|
57
57
|
.superRefine((ids, context) => {
|
|
58
58
|
if (new Set(ids).size !== ids.length)
|
|
59
|
-
context.addIssue({ code: "custom", message: "
|
|
59
|
+
context.addIssue({ code: "custom", message: "DebtIds must be unique" });
|
|
60
60
|
})
|
|
61
61
|
.readonly();
|
|
62
62
|
export function contractNamespace(id) {
|
|
63
63
|
return ["kei", contractSegment(id)];
|
|
64
64
|
}
|
|
65
|
-
export function
|
|
66
|
-
if (![...coordinate.namespace, coordinate.localId].every(
|
|
67
|
-
throw new TypeError("
|
|
68
|
-
return join(
|
|
65
|
+
export function debtAuthorityPath(debtsDirectory, coordinate) {
|
|
66
|
+
if (![...coordinate.namespace, coordinate.localId].every(isDebtSegment))
|
|
67
|
+
throw new TypeError("debt coordinate contains a noncanonical segment");
|
|
68
|
+
return join(debtsDirectory, ...coordinate.namespace.map((segment) => physicalDebtSegment(segment)), `${physicalDebtSegment(coordinate.localId)}.md`);
|
|
69
69
|
}
|
|
70
70
|
export function deriveLocalStem(title) {
|
|
71
71
|
const stem = normalizeIdentityStem({ source: title });
|
|
72
72
|
if (stem.length === 0)
|
|
73
|
-
throw new TypeError("
|
|
73
|
+
throw new TypeError("debt title must contain a normalized identity segment");
|
|
74
74
|
const words = stem.split("-");
|
|
75
75
|
let fitted = words[0];
|
|
76
76
|
let count = [...fitted].length;
|
|
@@ -87,18 +87,18 @@ export function allocateLocalId(stem, occupied) {
|
|
|
87
87
|
const seed = randomBytes(2).readUInt16BE(0);
|
|
88
88
|
for (let offset = 0; offset <= 0xffff; offset += 1) {
|
|
89
89
|
const suffix = ((seed + offset) & 0xffff).toString(16).padStart(4, "0");
|
|
90
|
-
const candidate = fitIdentityStem({ stem, maxBytes:
|
|
90
|
+
const candidate = fitIdentityStem({ stem, maxBytes: DEBT_LOCAL_ID_BYTES, suffix });
|
|
91
91
|
if (!occupied.has(candidate))
|
|
92
92
|
return candidate;
|
|
93
93
|
}
|
|
94
|
-
throw new Error("
|
|
94
|
+
throw new Error("debt identity hexadecimal suffix space exhausted");
|
|
95
95
|
}
|
|
96
|
-
export function
|
|
96
|
+
export function physicalDebtSegment(segment, maxBytes = DEBT_LOCAL_ID_BYTES) {
|
|
97
97
|
if (Buffer.byteLength(segment) <= maxBytes && !WINDOWS_RESERVED.test(segment))
|
|
98
98
|
return segment;
|
|
99
99
|
if (Buffer.byteLength(segment) > maxBytes)
|
|
100
|
-
throw new TypeError("
|
|
101
|
-
throw new TypeError("
|
|
100
|
+
throw new TypeError("debt identity cannot fit the physical filename budget");
|
|
101
|
+
throw new TypeError("debt identity contains a Windows-reserved physical segment");
|
|
102
102
|
}
|
|
103
103
|
export function sameNamespace(left, right) {
|
|
104
104
|
return left.length === right.length && left.every((segment, index) => segment === right[index]);
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import type { WorldRoot } from "../world.js";
|
|
2
|
+
import type { NamespaceContextSource, ResolvedNamespaceContext } from "./context.js";
|
|
3
|
+
import { type ExecutionContext } from "../akuma/requests.js";
|
|
4
|
+
import { type DebtLifecycleVerb } from "./mutation.js";
|
|
5
|
+
export type { WorldRoot } from "../world.js";
|
|
6
|
+
import { type BlockedDebtRow, type DebtDetailFacts, type DebtDoctorIssue, type DebtRef, type DebtRow, type DebtTreeNode } from "./board.js";
|
|
7
|
+
import { DebtAuthorityCorruptionError, type DebtPriority, type DebtState } from "./document.js";
|
|
8
|
+
import type { DebtId } from "./identity.js";
|
|
9
|
+
import { type AddDebtDocumentInput, type AddDebtInput, type DebtBatchResult, type DebtCleanupFailure, type DebtMutationResult, type DebtOutcome, type DebtRefusal, type DebtRetry, type DebtUpdateResult, type DebtView, type UpdateDebtInput } from "./operations.js";
|
|
10
|
+
import { DEBT_RELATION_PREDICATE_FIELDS, type DebtPage, type DebtQueryExpression, type DebtQueryPredicate, type DebtQueryRow, type DebtQuerySort, type DebtRelationPredicateField } from "./query.js";
|
|
11
|
+
export type DebtDetail = Omit<DebtDetailFacts, "debt"> & Readonly<{
|
|
12
|
+
debt: DebtView;
|
|
13
|
+
}>;
|
|
14
|
+
export type DebtList = DebtOutcome<DebtPage<DebtRow>>;
|
|
15
|
+
export type BlockedDebtList = DebtOutcome<DebtPage<BlockedDebtRow>>;
|
|
16
|
+
export type DebtQueryResult = DebtOutcome<DebtPage<DebtQueryRow>>;
|
|
17
|
+
export type DebtContextSource = NamespaceContextSource;
|
|
18
|
+
export type { ResolvedNamespaceContext };
|
|
19
|
+
export type DebtContextResult = DebtOutcome<ResolvedNamespaceContext>;
|
|
20
|
+
export type DebtDoctorReport = Readonly<{
|
|
21
|
+
issues: readonly DebtDoctorIssue[];
|
|
22
|
+
}>;
|
|
23
|
+
export type DebtDecompositionTree = DebtOutcome<DebtTreeNode>;
|
|
24
|
+
export type { AddDebtDocumentInput, AddDebtInput, BlockedDebtRow, DebtBatchResult, DebtCleanupFailure, DebtDoctorIssue, DebtId, DebtMutationResult, DebtOutcome, DebtPriority, DebtRef, DebtRefusal, DebtRetry, DebtRow, DebtState, DebtTreeNode, DebtUpdateResult, DebtView, UpdateDebtInput, DebtPage, DebtQueryExpression, DebtQueryPredicate, DebtQueryRow, DebtQuerySort, DebtRelationPredicateField, };
|
|
25
|
+
export type { LibraryExecution } from "../akuma/requests.js";
|
|
26
|
+
export { DebtAuthorityCorruptionError, DEBT_RELATION_PREDICATE_FIELDS };
|
|
27
|
+
export { observeRecentDebtStatus, type RecentDebtStatusRow } from "./catalog.js";
|
|
28
|
+
export { boundedListLimit as debtRowViewLimit } from "../bounded-list.js";
|
|
29
|
+
/**
|
|
30
|
+
* The one bound operation table for a captured route. Each entry either calls the
|
|
31
|
+
* local Debt operations directly or sends the same validated values as the one
|
|
32
|
+
* forwarded request shape. Validation stays in the handle methods.
|
|
33
|
+
*/
|
|
34
|
+
type DebtOperations = Readonly<{
|
|
35
|
+
add(values: AddDebtInput): Promise<DebtMutationResult>;
|
|
36
|
+
addDocument(values: AddDebtDocumentInput): Promise<DebtMutationResult>;
|
|
37
|
+
update(id: DebtId, values: UpdateDebtInput): Promise<DebtUpdateResult>;
|
|
38
|
+
lifecycle(id: DebtId, verb: DebtLifecycleVerb, note: string | undefined, signal?: AbortSignal): Promise<DebtMutationResult>;
|
|
39
|
+
batch(verb: DebtLifecycleVerb, ids: readonly DebtId[], note: string | undefined, signal?: AbortSignal): Promise<DebtBatchResult>;
|
|
40
|
+
}>;
|
|
41
|
+
declare class DebtHandle {
|
|
42
|
+
readonly id: DebtId;
|
|
43
|
+
private readonly world;
|
|
44
|
+
private readonly operations;
|
|
45
|
+
constructor(id: DebtId, world: WorldRoot, operations: DebtOperations);
|
|
46
|
+
read(): Promise<DebtDetail | null>;
|
|
47
|
+
tree(): Promise<DebtDecompositionTree>;
|
|
48
|
+
update(input: UpdateDebtInput): Promise<DebtUpdateResult>;
|
|
49
|
+
private lifecycle;
|
|
50
|
+
done(input?: {
|
|
51
|
+
note?: string;
|
|
52
|
+
signal?: AbortSignal;
|
|
53
|
+
}): Promise<DebtMutationResult>;
|
|
54
|
+
drop(input?: {
|
|
55
|
+
note?: string;
|
|
56
|
+
signal?: AbortSignal;
|
|
57
|
+
}): Promise<DebtMutationResult>;
|
|
58
|
+
}
|
|
59
|
+
export type Debt = DebtHandle;
|
|
60
|
+
declare class DebtsHandle {
|
|
61
|
+
private readonly world;
|
|
62
|
+
readonly root: WorldRoot;
|
|
63
|
+
private readonly operations;
|
|
64
|
+
constructor(world: WorldRoot, execution: ExecutionContext);
|
|
65
|
+
debt(input: Readonly<{
|
|
66
|
+
id: string;
|
|
67
|
+
}>): Debt;
|
|
68
|
+
add(input: AddDebtInput): Promise<DebtMutationResult>;
|
|
69
|
+
addDocument(input: AddDebtDocumentInput): Promise<DebtMutationResult>;
|
|
70
|
+
list(input?: Readonly<{
|
|
71
|
+
selection?: "active" | "closed" | "all";
|
|
72
|
+
scope?: "namespace" | "world";
|
|
73
|
+
namespace?: readonly string[];
|
|
74
|
+
limit?: number;
|
|
75
|
+
}>): Promise<DebtList>;
|
|
76
|
+
ready(input?: Readonly<{
|
|
77
|
+
scope?: "namespace" | "world";
|
|
78
|
+
namespace?: readonly string[];
|
|
79
|
+
parent?: string;
|
|
80
|
+
limit?: number;
|
|
81
|
+
}>): Promise<DebtList>;
|
|
82
|
+
blocked(input?: Readonly<{
|
|
83
|
+
scope?: "namespace" | "world";
|
|
84
|
+
namespace?: readonly string[];
|
|
85
|
+
parent?: string;
|
|
86
|
+
limit?: number;
|
|
87
|
+
}>): Promise<BlockedDebtList>;
|
|
88
|
+
query(input?: Readonly<{
|
|
89
|
+
where?: DebtQueryExpression;
|
|
90
|
+
scope?: "namespace" | "world";
|
|
91
|
+
namespace?: readonly string[];
|
|
92
|
+
sort?: DebtQuerySort;
|
|
93
|
+
limit?: number;
|
|
94
|
+
}>): Promise<DebtQueryResult>;
|
|
95
|
+
doctor(): Promise<DebtDoctorReport>;
|
|
96
|
+
batch(input: Readonly<{
|
|
97
|
+
verb: "done" | "drop";
|
|
98
|
+
ids: readonly string[];
|
|
99
|
+
note?: string;
|
|
100
|
+
signal?: AbortSignal;
|
|
101
|
+
}>): Promise<DebtBatchResult>;
|
|
102
|
+
}
|
|
103
|
+
export type Debts = DebtsHandle;
|
|
104
|
+
/**
|
|
105
|
+
* The one Debts composition. Public `of` fixes local execution; CLI and Body pass their captured
|
|
106
|
+
* internal channel through `debtsWithExecution` instead of a second constructor.
|
|
107
|
+
*/
|
|
108
|
+
export declare function debtsWithExecution(world: WorldRoot, execution: ExecutionContext): Debts;
|
|
109
|
+
export declare const Debts: Readonly<{
|
|
110
|
+
of(world: WorldRoot): Debts;
|
|
111
|
+
}>;
|