@astrosheep/keiyaku 4.5.7 → 4.5.8
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 +10 -0
- package/build/integrations/marketplace/plugins/keiyaku/.claude-plugin/plugin.json +1 -1
- package/build/integrations/marketplace/plugins/keiyaku/.codex-plugin/plugin.json +1 -1
- package/build/integrations/marketplace/plugins/keiyaku/opencode.js +3 -2
- package/build/integrations/marketplace/plugins/keiyaku/package.json +1 -1
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku/SKILL.md +10 -9
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-akuma/SKILL.md +22 -1
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-babysit/SKILL.md +35 -96
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-bind/SKILL.md +28 -49
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-task/SKILL.md +21 -15
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-workflow/SKILL.md +148 -89
- package/build/src/akuma/abort.d.ts +2 -1
- package/build/src/akuma/abort.js +6 -23
- package/build/src/akuma/akuma-handle.js +4 -2
- package/build/src/akuma/akuma-observe.d.ts +2 -0
- package/build/src/akuma/akuma-observe.js +1 -0
- package/build/src/akuma/akuma-product.js +9 -7
- package/build/src/akuma/akuma.d.ts +372 -9
- package/build/src/akuma/akuma.js +31 -1
- package/build/src/akuma/allowed.d.ts +1 -1
- package/build/src/akuma/allowed.js +1 -0
- package/build/src/akuma/body.d.ts +6 -4
- package/build/src/akuma/body.js +5 -3
- package/build/src/akuma/call-request.d.ts +80 -0
- package/build/src/akuma/call-request.js +211 -0
- package/build/src/akuma/heart/facts.d.ts +6 -78
- package/build/src/akuma/heart/index.d.ts +1 -1
- package/build/src/akuma/heart/request-authority.d.ts +5 -4
- package/build/src/akuma/heart/request-authority.js +20 -34
- package/build/src/akuma/heart/request-rows.js +12 -23
- package/build/src/akuma/heart/schema.d.ts +1 -1
- package/build/src/akuma/heart/schema.js +5 -13
- package/build/src/akuma/index.d.ts +1 -1
- package/build/src/akuma/index.js +1 -1
- package/build/src/akuma/projection-read.d.ts +1 -0
- package/build/src/akuma/projection-read.js +8 -1
- package/build/src/akuma/projection.d.ts +856 -137
- package/build/src/akuma/projection.js +190 -0
- package/build/src/akuma/provider.d.ts +30 -3
- package/build/src/akuma/provider.js +104 -0
- package/build/src/akuma/providers/acp/core.d.ts +2 -2
- package/build/src/akuma/providers/acp/core.js +13 -6
- package/build/src/akuma/providers/acp/index.js +5 -4
- package/build/src/akuma/providers/claude/index.d.ts +3 -3
- package/build/src/akuma/providers/claude/index.js +16 -5
- package/build/src/akuma/providers/codex-app-server/events.js +1 -1
- package/build/src/akuma/providers/codex-app-server/index.js +18 -6
- package/build/src/akuma/providers/grok-build/index.js +5 -4
- package/build/src/akuma/providers/opencode-sdk/index.js +66 -25
- package/build/src/akuma/providers/opencode-sdk/session.d.ts +3 -2
- package/build/src/akuma/providers/opencode-sdk/session.js +28 -11
- package/build/src/akuma/providers/pi/index.js +42 -14
- package/build/src/akuma/request-lifecycle.d.ts +3 -9
- package/build/src/akuma/request-lifecycle.js +4 -4
- package/build/src/akuma/request-rendezvous.d.ts +26 -0
- package/build/src/akuma/request-rendezvous.js +100 -0
- package/build/src/akuma/request-serve.d.ts +5 -65
- package/build/src/akuma/request-serve.js +81 -208
- package/build/src/akuma/request-wire.d.ts +109 -115
- package/build/src/akuma/request-wire.js +63 -318
- package/build/src/akuma/requests.d.ts +19 -47
- package/build/src/akuma/requests.js +51 -107
- package/build/src/akuma/turn-drive.d.ts +5 -3
- package/build/src/akuma/turn-drive.js +32 -10
- package/build/src/akuma-body.d.ts +7 -2
- package/build/src/akuma-body.js +68 -46
- package/build/src/cli/accepted.d.ts +1 -1
- package/build/src/cli/accepted.js +2 -2
- package/build/src/cli/commands/akuma-invoke.d.ts +2 -0
- package/build/src/cli/commands/akuma-invoke.js +17 -9
- package/build/src/cli/commands/akuma.js +7 -7
- package/build/src/cli/commands/contract-invoke.d.ts +3 -2
- package/build/src/cli/commands/contract-invoke.js +26 -19
- package/build/src/cli/commands/contract.d.ts +13 -13
- package/build/src/cli/commands/contract.js +32 -17
- package/build/src/cli/commands/install.d.ts +1 -1
- package/build/src/cli/commands/install.js +1 -1
- package/build/src/cli/commands/task-invoke.d.ts +3 -0
- package/build/src/cli/commands/task-invoke.js +23 -140
- package/build/src/cli/commands/task.js +54 -20
- package/build/src/cli/invoke.js +39 -25
- package/build/src/cli/main.js +2 -1
- package/build/src/cli/parse.d.ts +2 -2
- package/build/src/cli/parse.js +37 -22
- package/build/src/cli/render/akuma-activity.d.ts +4 -1
- package/build/src/cli/render/akuma-activity.js +45 -30
- package/build/src/cli/render/akuma-tool.d.ts +5 -1
- package/build/src/cli/render/akuma.js +5 -9
- package/build/src/cli/render/audit.js +1 -1
- package/build/src/cli/render/catalog.js +80 -21
- package/build/src/cli/render/contract-observation.d.ts +2 -0
- package/build/src/cli/render/contract-observation.js +11 -0
- package/build/src/cli/render/contract.js +25 -65
- package/build/src/cli/render/kanshi-akuma.d.ts +8 -0
- package/build/src/cli/render/kanshi-akuma.js +111 -0
- package/build/src/cli/render/kanshi.js +108 -213
- package/build/src/cli/render/receipt.d.ts +1 -2
- package/build/src/cli/render/receipt.js +76 -26
- package/build/src/cli/render/refusal.js +2 -10
- package/build/src/cli/render/region.js +5 -2
- package/build/src/cli/render/settings.d.ts +1 -1
- package/build/src/cli/render/settings.js +27 -8
- package/build/src/cli/render/task.js +22 -5
- package/build/src/cli/render/terminal.d.ts +28 -0
- package/build/src/cli/render/terminal.js +65 -0
- package/build/src/cli/result.d.ts +3 -3
- package/build/src/cli/runtime.js +3 -1
- package/build/src/cli/selectors.d.ts +2 -1
- package/build/src/cli/selectors.js +4 -3
- package/build/src/cli/square-edge.js +120 -36
- package/build/src/cli/usage.js +2 -1
- package/build/src/contract-guidance.d.ts +5 -0
- package/build/src/contract-guidance.js +121 -0
- package/build/src/contract-worktree.d.ts +0 -1
- package/build/src/contract-worktree.js +32 -83
- package/build/src/coordination/sqlite-transaction-lock.d.ts +1 -0
- package/build/src/coordination/sqlite-transaction-lock.js +5 -0
- package/build/src/core/facts/codec.d.ts +2 -0
- package/build/src/core/facts/codec.js +4 -0
- package/build/src/core/verbs/placement.d.ts +6 -1
- package/build/src/core/verbs/placement.js +5 -3
- package/build/src/dispatch/index.d.ts +0 -2
- package/build/src/dispatch/index.js +54 -55
- package/build/src/git/admission.js +2 -2
- package/build/src/git/hooks.d.ts +9 -15
- package/build/src/git/hooks.js +23 -317
- package/build/src/git/nuke.d.ts +2 -1
- package/build/src/git/nuke.js +36 -18
- package/build/src/git/private-state-seat.d.ts +12 -0
- package/build/src/git/private-state-seat.js +39 -0
- package/build/src/git/process.d.ts +6 -0
- package/build/src/git/process.js +19 -7
- package/build/src/git/read-observation.js +29 -20
- package/build/src/git/reconcile.d.ts +11 -0
- package/build/src/git/reconcile.js +64 -11
- package/build/src/git/repository.d.ts +6 -2
- package/build/src/git/repository.js +8 -0
- package/build/src/git/target-placement.d.ts +1 -0
- package/build/src/git/target-placement.js +5 -0
- package/build/src/git/tender.d.ts +1 -0
- package/build/src/git/terminal-reconcile.d.ts +1 -1
- package/build/src/git/terminal-reconcile.js +22 -20
- package/build/src/git/workspace.d.ts +14 -0
- package/build/src/git/workspace.js +44 -0
- package/build/src/kanshi/index.d.ts +1 -1
- package/build/src/kanshi/read.js +16 -16
- package/build/src/kanshi/report.d.ts +2 -2
- package/build/src/library/address.d.ts +9 -3
- package/build/src/library/address.js +3 -2
- package/build/src/library/akuma-creation.d.ts +4 -3
- package/build/src/library/akuma-creation.js +19 -13
- package/build/src/library/audit.d.ts +1 -1
- package/build/src/library/audit.js +5 -3
- package/build/src/library/catalog.d.ts +3 -1
- package/build/src/library/catalog.js +20 -6
- package/build/src/library/composition.d.ts +371 -0
- package/build/src/library/composition.js +28 -0
- package/build/src/library/configuration.js +8 -2
- package/build/src/library/continuation.js +66 -30
- package/build/src/library/contract-bind.js +10 -2
- package/build/src/library/contract-forwarding-reconciliation-result.d.ts +96 -0
- package/build/src/library/contract-forwarding-reconciliation-result.js +83 -0
- package/build/src/library/contract-forwarding-result.d.ts +6723 -0
- package/build/src/library/contract-forwarding-result.js +521 -0
- package/build/src/library/contract-forwarding.d.ts +72 -0
- package/build/src/library/contract-forwarding.js +125 -0
- package/build/src/library/contract-handle.d.ts +36 -0
- package/build/src/library/contract-handle.js +313 -0
- package/build/src/library/contract-operations.d.ts +1044 -67
- package/build/src/library/contract-operations.js +190 -118
- package/build/src/library/contract.d.ts +11 -32
- package/build/src/library/contract.js +16 -289
- package/build/src/library/fleet-result.d.ts +1454 -0
- package/build/src/library/fleet-result.js +96 -0
- package/build/src/library/fleet.d.ts +112 -54
- package/build/src/library/fleet.js +211 -71
- package/build/src/library/input.d.ts +2 -0
- package/build/src/library/input.js +4 -0
- package/build/src/library/keiyaku.d.ts +371 -20
- package/build/src/library/keiyaku.js +8 -21
- package/build/src/library/mutation.d.ts +3 -3
- package/build/src/library/mutation.js +5 -9
- package/build/src/library/nuke.d.ts +1 -1
- package/build/src/library/nuke.js +4 -3
- package/build/src/library/reconcile.d.ts +4 -0
- package/build/src/library/reconcile.js +2 -0
- package/build/src/library/refusal.d.ts +0 -9
- package/build/src/library/refusal.js +0 -7
- package/build/src/protocol/amend.js +56 -50
- package/build/src/protocol/attempt.d.ts +2 -0
- package/build/src/protocol/attempt.js +8 -1
- package/build/src/protocol/completion.js +7 -0
- package/build/src/protocol/deliver.js +6 -2
- package/build/src/protocol/operations.d.ts +4 -1
- package/build/src/protocol/operations.js +5 -2
- package/build/src/protocol/placement.d.ts +1 -0
- package/build/src/protocol/placement.js +52 -38
- package/build/src/protocol/read/observation.d.ts +1 -4
- package/build/src/protocol/read/observation.js +2 -15
- package/build/src/protocol/reintegrate.js +62 -58
- package/build/src/protocol/review.js +5 -0
- package/build/src/protocol/run.js +17 -13
- package/build/src/runtime/proc/run.d.ts +8 -0
- package/build/src/runtime/proc/run.js +27 -0
- package/build/src/runtime/proc/termination.js +26 -22
- package/build/src/runtime/proc/windows-launch.exe +0 -0
- package/build/src/settlement/holder.d.ts +2 -1
- package/build/src/settlement/holder.js +15 -4
- package/build/src/settlement/settle.js +99 -33
- package/build/src/task/board.d.ts +68 -27
- package/build/src/task/board.js +31 -1
- package/build/src/task/catalog.d.ts +4 -0
- package/build/src/task/catalog.js +23 -0
- package/build/src/task/compose-language.js +33 -7
- package/build/src/task/compose-parser.d.ts +1 -1
- package/build/src/task/compose-parser.js +1 -1
- package/build/src/task/compose.js +2 -0
- package/build/src/task/index.d.ts +12 -4
- package/build/src/task/index.js +97 -16
- package/build/src/task/mutation-result.d.ts +923 -0
- package/build/src/task/mutation-result.js +140 -0
- package/build/src/task/mutation.d.ts +552 -28
- package/build/src/task/mutation.js +304 -97
- package/build/src/task/operations.d.ts +1 -4
- package/build/src/task/operations.js +0 -6
- package/build/src/task/public.d.ts +2 -0
- package/build/src/task/public.js +1 -0
- package/build/src/workspace-place.d.ts +7 -2
- package/build/src/workspace-place.js +34 -24
- package/build/src/world.d.ts +1 -0
- package/build/src/world.js +11 -0
- package/package.json +8 -6
- package/build/src/akuma/request-execution.d.ts +0 -8
- package/build/src/akuma/request-execution.js +0 -98
|
@@ -1,4 +1,12 @@
|
|
|
1
|
-
|
|
1
|
+
/* eslint-disable max-lines -- Task owns one coherent forwarded mutation boundary. */
|
|
2
|
+
import { World } from "../world.js";
|
|
3
|
+
import { requestBodyCommand } from "../akuma/request-rendezvous.js";
|
|
4
|
+
import { eraseRequestCommand } from "../akuma/request-wire.js";
|
|
5
|
+
import { addTask, addTaskDocument, batchTasks, lifecycleTask, updateTask, } from "./operations.js";
|
|
6
|
+
import { composeTasks } from "./compose.js";
|
|
7
|
+
import { isTaskSegment } from "./identity.js";
|
|
8
|
+
import { taskBatchResultSchema, taskCompositionResultSchema, taskMutationIdSchema, taskMutationResultSchema, taskUpdateResultSchema, isTaskMutationExecutionResult, } from "./mutation-result.js";
|
|
9
|
+
import { z } from "zod";
|
|
2
10
|
export const TASK_MUTATION_ACTIONS = Object.freeze([
|
|
3
11
|
"task.add",
|
|
4
12
|
"task.addDocument",
|
|
@@ -15,121 +23,320 @@ const TASK_MUTATION_ACTION_SET = new Set(TASK_MUTATION_ACTIONS);
|
|
|
15
23
|
export function isTaskMutationAction(value) {
|
|
16
24
|
return typeof value === "string" && TASK_MUTATION_ACTION_SET.has(value);
|
|
17
25
|
}
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
26
|
+
const nonblankTextSchema = z.string().refine((value) => value.trim() !== "");
|
|
27
|
+
const namespaceSchema = z.array(z.string().refine(isTaskSegment)).readonly();
|
|
28
|
+
const taskIdsBaseSchema = z.array(taskMutationIdSchema).superRefine((ids, context) => {
|
|
29
|
+
if (new Set(ids).size !== ids.length)
|
|
30
|
+
context.addIssue({ code: "custom", message: "TaskIds must be unique" });
|
|
31
|
+
});
|
|
32
|
+
const taskIdsSchema = taskIdsBaseSchema.readonly();
|
|
33
|
+
const nonemptyTaskIdsSchema = taskIdsBaseSchema.min(1).readonly();
|
|
34
|
+
const taskStateSchema = z.enum(["open", "in_progress", "on_hold", "done", "drop"]);
|
|
35
|
+
const taskPrioritySchema = z.union([z.literal(0), z.literal(1), z.literal(2), z.literal(3)]);
|
|
36
|
+
const addInputSchema = z
|
|
37
|
+
.object({
|
|
38
|
+
title: nonblankTextSchema,
|
|
39
|
+
namespace: namespaceSchema,
|
|
40
|
+
body: z.string().optional(),
|
|
41
|
+
note: z.string().optional(),
|
|
42
|
+
state: taskStateSchema.optional(),
|
|
43
|
+
priority: taskPrioritySchema.optional(),
|
|
44
|
+
needs: taskIdsSchema.optional(),
|
|
45
|
+
parent: taskMutationIdSchema.nullable().optional(),
|
|
46
|
+
supersedes: taskIdsSchema.optional(),
|
|
47
|
+
relates: taskIdsSchema.optional(),
|
|
48
|
+
})
|
|
49
|
+
.strict();
|
|
50
|
+
const updateInputSchema = z
|
|
51
|
+
.object({
|
|
52
|
+
title: nonblankTextSchema.optional(),
|
|
53
|
+
body: z.string().optional(),
|
|
54
|
+
appendBody: z.string().optional(),
|
|
55
|
+
note: z.string().optional(),
|
|
56
|
+
priority: taskPrioritySchema.optional(),
|
|
57
|
+
needs: taskIdsSchema.optional(),
|
|
58
|
+
addNeeds: taskIdsSchema.optional(),
|
|
59
|
+
dropNeeds: taskIdsSchema.optional(),
|
|
60
|
+
parent: taskMutationIdSchema.nullable().optional(),
|
|
61
|
+
supersedes: taskIdsSchema.optional(),
|
|
62
|
+
addSupersedes: taskIdsSchema.optional(),
|
|
63
|
+
dropSupersedes: taskIdsSchema.optional(),
|
|
64
|
+
relates: taskIdsSchema.optional(),
|
|
65
|
+
addRelates: taskIdsSchema.optional(),
|
|
66
|
+
dropRelates: taskIdsSchema.optional(),
|
|
67
|
+
})
|
|
68
|
+
.strict()
|
|
69
|
+
.superRefine((input, context) => {
|
|
70
|
+
if (input.body !== undefined && input.appendBody !== undefined)
|
|
71
|
+
context.addIssue({ code: "custom", message: "body and appendBody are mutually exclusive" });
|
|
72
|
+
if (Object.values(input).every((value) => value === undefined))
|
|
73
|
+
context.addIssue({ code: "custom", message: "update requires at least one field change" });
|
|
74
|
+
});
|
|
75
|
+
const addRequestSchema = z
|
|
76
|
+
.object({ input: addInputSchema })
|
|
77
|
+
.strict()
|
|
78
|
+
.transform(({ input }) => ({ action: "task.add", input }));
|
|
79
|
+
const addDocumentRequestSchema = z
|
|
80
|
+
.object({ input: z.object({ markdown: z.string(), namespace: namespaceSchema }).strict() })
|
|
81
|
+
.strict()
|
|
82
|
+
.transform(({ input }) => ({ action: "task.addDocument", input }));
|
|
83
|
+
const composeRequestSchema = z
|
|
84
|
+
.object({ markdown: z.string(), namespace: namespaceSchema })
|
|
85
|
+
.strict()
|
|
86
|
+
.transform((request) => ({ action: "task.compose", ...request }));
|
|
87
|
+
const updateRequestSchema = z
|
|
88
|
+
.object({ id: taskMutationIdSchema, input: updateInputSchema })
|
|
89
|
+
.strict()
|
|
90
|
+
.transform((request) => ({ action: "task.update", ...request }));
|
|
91
|
+
const singleOrBatchRequestSchema = (action) => z.union([
|
|
92
|
+
z
|
|
93
|
+
.object({ id: taskMutationIdSchema })
|
|
94
|
+
.strict()
|
|
95
|
+
.transform(({ id }) => ({ action, id })),
|
|
96
|
+
z
|
|
97
|
+
.object({ ids: nonemptyTaskIdsSchema })
|
|
98
|
+
.strict()
|
|
99
|
+
.transform(({ ids }) => ({ action, ids })),
|
|
100
|
+
]);
|
|
101
|
+
const singleRequestSchema = (action) => z
|
|
102
|
+
.object({ id: taskMutationIdSchema })
|
|
103
|
+
.strict()
|
|
104
|
+
.transform((request) => ({ action, ...request }));
|
|
105
|
+
const terminalRequestSchema = (action) => z.union([
|
|
106
|
+
z
|
|
107
|
+
.object({ id: taskMutationIdSchema, note: z.string().optional() })
|
|
108
|
+
.strict()
|
|
109
|
+
.transform(({ id, note }) => ({ action, id, ...(note === undefined ? {} : { note }) })),
|
|
110
|
+
z
|
|
111
|
+
.object({ ids: nonemptyTaskIdsSchema, note: z.string().optional() })
|
|
112
|
+
.strict()
|
|
113
|
+
.transform(({ ids, note }) => ({ action, ids, ...(note === undefined ? {} : { note }) })),
|
|
114
|
+
]);
|
|
115
|
+
const taskRequestSchemas = {
|
|
116
|
+
"task.add": addRequestSchema,
|
|
117
|
+
"task.addDocument": addDocumentRequestSchema,
|
|
118
|
+
"task.compose": composeRequestSchema,
|
|
119
|
+
"task.done": terminalRequestSchema("task.done"),
|
|
120
|
+
"task.drop": terminalRequestSchema("task.drop"),
|
|
121
|
+
"task.hold": singleOrBatchRequestSchema("task.hold"),
|
|
122
|
+
"task.resume": singleRequestSchema("task.resume"),
|
|
123
|
+
"task.start": singleOrBatchRequestSchema("task.start"),
|
|
124
|
+
"task.stop": singleRequestSchema("task.stop"),
|
|
125
|
+
"task.update": updateRequestSchema,
|
|
126
|
+
};
|
|
127
|
+
const worldPathSchema = z.string().min(1);
|
|
128
|
+
const taskBodyRequestSchemas = {
|
|
129
|
+
"task.add": z.object({ world: worldPathSchema, request: taskRequestSchemas["task.add"] }).strict(),
|
|
130
|
+
"task.addDocument": z.object({ world: worldPathSchema, request: taskRequestSchemas["task.addDocument"] }).strict(),
|
|
131
|
+
"task.compose": z.object({ world: worldPathSchema, request: taskRequestSchemas["task.compose"] }).strict(),
|
|
132
|
+
"task.done": z.object({ world: worldPathSchema, request: taskRequestSchemas["task.done"] }).strict(),
|
|
133
|
+
"task.drop": z.object({ world: worldPathSchema, request: taskRequestSchemas["task.drop"] }).strict(),
|
|
134
|
+
"task.hold": z.object({ world: worldPathSchema, request: taskRequestSchemas["task.hold"] }).strict(),
|
|
135
|
+
"task.resume": z.object({ world: worldPathSchema, request: taskRequestSchemas["task.resume"] }).strict(),
|
|
136
|
+
"task.start": z.object({ world: worldPathSchema, request: taskRequestSchemas["task.start"] }).strict(),
|
|
137
|
+
"task.stop": z.object({ world: worldPathSchema, request: taskRequestSchemas["task.stop"] }).strict(),
|
|
138
|
+
"task.update": z.object({ world: worldPathSchema, request: taskRequestSchemas["task.update"] }).strict(),
|
|
139
|
+
};
|
|
140
|
+
export const taskMutationServiceSchema = z.object({ action: z.enum(TASK_MUTATION_ACTIONS) }).strict();
|
|
141
|
+
export const forwardedTaskReferenceSchema = z
|
|
142
|
+
.object({ kind: z.literal("served-reference"), action: z.enum(TASK_MUTATION_ACTIONS) })
|
|
143
|
+
.strict();
|
|
144
|
+
function decodeTaskMutationExecutionContext(value) {
|
|
145
|
+
const context = resultRecord(value);
|
|
146
|
+
if (context === null ||
|
|
147
|
+
typeof context.requester !== "string" ||
|
|
148
|
+
context.requester.trim() === "" ||
|
|
149
|
+
!isAbortSignal(context.signal) ||
|
|
150
|
+
!isTaskMutationRequestPort(context.upstream))
|
|
151
|
+
throw new Error("invalid Task execution context");
|
|
152
|
+
return { requester: context.requester, signal: context.signal, upstream: context.upstream };
|
|
22
153
|
}
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
154
|
+
function isAbortSignal(value) {
|
|
155
|
+
return (value !== null &&
|
|
156
|
+
typeof value === "object" &&
|
|
157
|
+
typeof value.throwIfAborted === "function");
|
|
158
|
+
}
|
|
159
|
+
function isTaskMutationRequestPort(value) {
|
|
160
|
+
const port = resultRecord(value);
|
|
161
|
+
return port !== null && typeof port.task === "function";
|
|
162
|
+
}
|
|
163
|
+
function resultRecord(value) {
|
|
164
|
+
return value !== null && typeof value === "object" && !Array.isArray(value)
|
|
165
|
+
? value
|
|
166
|
+
: null;
|
|
167
|
+
}
|
|
168
|
+
function decodeTaskBodyRequest(action, value) {
|
|
169
|
+
const parsed = taskBodyRequestSchemas[action].safeParse(value);
|
|
170
|
+
return parsed.success ? parsed.data : null;
|
|
171
|
+
}
|
|
172
|
+
function decodeTaskService(action, value) {
|
|
173
|
+
const parsed = taskMutationServiceSchema.safeParse(value);
|
|
174
|
+
if (!parsed.success || parsed.data.action !== action)
|
|
175
|
+
throw new Error(`malformed stored Task service evidence for ${action}`);
|
|
176
|
+
return parsed.data;
|
|
177
|
+
}
|
|
178
|
+
function decodeTaskReference(action, value) {
|
|
179
|
+
const parsed = forwardedTaskReferenceSchema.safeParse(value);
|
|
180
|
+
if (!parsed.success || parsed.data.action !== action)
|
|
181
|
+
throw new Error(`malformed Task service reference for ${action}`);
|
|
182
|
+
return parsed.data;
|
|
183
|
+
}
|
|
184
|
+
/** Task owns forwarded mutation payload, live result, and durable service evidence. */
|
|
185
|
+
export function taskMutationRequestCommand(action) {
|
|
186
|
+
return {
|
|
187
|
+
action,
|
|
188
|
+
encodeRequest: (input) => {
|
|
189
|
+
const { action: _action, ...request } = input.request;
|
|
190
|
+
return { world: input.world, request };
|
|
191
|
+
},
|
|
192
|
+
decodeRequest: (value) => decodeTaskBodyRequest(action, value),
|
|
193
|
+
encodeResult: (result) => result,
|
|
194
|
+
decodeResult: (result) => {
|
|
195
|
+
if (!isTaskMutationExecutionResult(result)) {
|
|
196
|
+
throw new Error(`transport integrity: Task ${action} returned an invalid live result`);
|
|
197
|
+
}
|
|
198
|
+
return result;
|
|
199
|
+
},
|
|
200
|
+
encodeService: (service) => decodeTaskService(action, service),
|
|
201
|
+
decodeService: (service) => decodeTaskService(action, service),
|
|
202
|
+
projectService: (service) => decodeTaskReference(action, { kind: "served-reference", action: service.action }),
|
|
203
|
+
decodeReference: (reference) => decodeTaskReference(action, reference),
|
|
204
|
+
isPermitted: (allowed) => allowed.includes(action),
|
|
205
|
+
decodeExecutionContext: decodeTaskMutationExecutionContext,
|
|
206
|
+
execute: async (request, context) => {
|
|
207
|
+
const world = await World.prove(request.world);
|
|
208
|
+
return {
|
|
209
|
+
result: await context.upstream.task({
|
|
210
|
+
world,
|
|
211
|
+
request: request.request,
|
|
212
|
+
requester: context.requester,
|
|
213
|
+
signal: context.signal,
|
|
214
|
+
}),
|
|
215
|
+
service: { action: request.request.action },
|
|
216
|
+
};
|
|
217
|
+
},
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
export function taskMutationRequestCommands() {
|
|
221
|
+
return {
|
|
222
|
+
"task.add": eraseRequestCommand(taskMutationRequestCommand("task.add")),
|
|
223
|
+
"task.addDocument": eraseRequestCommand(taskMutationRequestCommand("task.addDocument")),
|
|
224
|
+
"task.compose": eraseRequestCommand(taskMutationRequestCommand("task.compose")),
|
|
225
|
+
"task.done": eraseRequestCommand(taskMutationRequestCommand("task.done")),
|
|
226
|
+
"task.drop": eraseRequestCommand(taskMutationRequestCommand("task.drop")),
|
|
227
|
+
"task.hold": eraseRequestCommand(taskMutationRequestCommand("task.hold")),
|
|
228
|
+
"task.resume": eraseRequestCommand(taskMutationRequestCommand("task.resume")),
|
|
229
|
+
"task.start": eraseRequestCommand(taskMutationRequestCommand("task.start")),
|
|
230
|
+
"task.stop": eraseRequestCommand(taskMutationRequestCommand("task.stop")),
|
|
231
|
+
"task.update": eraseRequestCommand(taskMutationRequestCommand("task.update")),
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
function taskResultForRequest(request, value) {
|
|
235
|
+
const schema = request.action === "task.compose"
|
|
236
|
+
? taskCompositionResultSchema
|
|
237
|
+
: request.action === "task.update"
|
|
238
|
+
? taskUpdateResultSchema
|
|
239
|
+
: "ids" in request
|
|
240
|
+
? taskBatchResultSchema
|
|
241
|
+
: taskMutationResultSchema;
|
|
242
|
+
return schema.safeParse(value).success;
|
|
243
|
+
}
|
|
244
|
+
export async function requestForwardedTask(input) {
|
|
245
|
+
const response = await requestBodyCommand({
|
|
246
|
+
directory: input.directory,
|
|
247
|
+
...(input.id === undefined ? {} : { id: input.id }),
|
|
248
|
+
command: taskMutationRequestCommand(input.request.action),
|
|
249
|
+
value: { world: input.world, request: input.request },
|
|
250
|
+
...(input.signal === undefined ? {} : { signal: input.signal }),
|
|
251
|
+
});
|
|
252
|
+
if (response.kind === "reference")
|
|
253
|
+
return response.reference;
|
|
254
|
+
if (!taskResultForRequest(input.request, response.result)) {
|
|
255
|
+
throw new Error(`transport integrity: request Task ${input.request.action} returned an invalid live result`);
|
|
91
256
|
}
|
|
257
|
+
return response.result;
|
|
258
|
+
}
|
|
259
|
+
export function decodeTaskMutationRequest(action, value) {
|
|
260
|
+
const parsed = taskRequestSchemas[action].safeParse(value);
|
|
261
|
+
if (!parsed.success)
|
|
262
|
+
throw new TypeError(`invalid ${action} request`);
|
|
263
|
+
return parsed.data;
|
|
264
|
+
}
|
|
265
|
+
function addTaskOptions(input, actor, signal) {
|
|
266
|
+
const { body, note, state, priority, needs, parent, supersedes, relates, ...required } = input;
|
|
267
|
+
return {
|
|
268
|
+
...required,
|
|
269
|
+
actor,
|
|
270
|
+
...(body === undefined ? {} : { body }),
|
|
271
|
+
...(note === undefined ? {} : { note }),
|
|
272
|
+
...(state === undefined ? {} : { state }),
|
|
273
|
+
...(priority === undefined ? {} : { priority }),
|
|
274
|
+
...(needs === undefined ? {} : { needs }),
|
|
275
|
+
...(parent === undefined ? {} : { parent }),
|
|
276
|
+
...(supersedes === undefined ? {} : { supersedes }),
|
|
277
|
+
...(relates === undefined ? {} : { relates }),
|
|
278
|
+
...(signal === undefined ? {} : { signal }),
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
function updateTaskOptions(input, signal) {
|
|
282
|
+
const { title, body, appendBody, note, priority, needs, addNeeds, dropNeeds, parent, supersedes, addSupersedes, dropSupersedes, relates, addRelates, dropRelates, } = input;
|
|
283
|
+
return {
|
|
284
|
+
...(title === undefined ? {} : { title }),
|
|
285
|
+
...(body === undefined ? {} : { body }),
|
|
286
|
+
...(appendBody === undefined ? {} : { appendBody }),
|
|
287
|
+
...(note === undefined ? {} : { note }),
|
|
288
|
+
...(priority === undefined ? {} : { priority }),
|
|
289
|
+
...(needs === undefined ? {} : { needs }),
|
|
290
|
+
...(addNeeds === undefined ? {} : { addNeeds }),
|
|
291
|
+
...(dropNeeds === undefined ? {} : { dropNeeds }),
|
|
292
|
+
...(parent === undefined ? {} : { parent }),
|
|
293
|
+
...(supersedes === undefined ? {} : { supersedes }),
|
|
294
|
+
...(addSupersedes === undefined ? {} : { addSupersedes }),
|
|
295
|
+
...(dropSupersedes === undefined ? {} : { dropSupersedes }),
|
|
296
|
+
...(relates === undefined ? {} : { relates }),
|
|
297
|
+
...(addRelates === undefined ? {} : { addRelates }),
|
|
298
|
+
...(dropRelates === undefined ? {} : { dropRelates }),
|
|
299
|
+
...(signal === undefined ? {} : { signal }),
|
|
300
|
+
};
|
|
92
301
|
}
|
|
93
302
|
export async function executeTaskMutation(input) {
|
|
94
|
-
const {
|
|
95
|
-
const tasks = Tasks.of(input.world);
|
|
96
|
-
const { request, signal } = input;
|
|
303
|
+
const { world, request, signal } = input;
|
|
97
304
|
const withSignal = signal === undefined ? {} : { signal };
|
|
98
305
|
switch (request.action) {
|
|
99
306
|
case "task.add":
|
|
100
|
-
return await
|
|
307
|
+
return await addTask(world, addTaskOptions(request.input, input.requester, signal));
|
|
101
308
|
case "task.addDocument":
|
|
102
|
-
return await
|
|
309
|
+
return await addTaskDocument(world, { ...request.input, actor: input.requester, ...withSignal });
|
|
103
310
|
case "task.compose":
|
|
104
|
-
return await
|
|
311
|
+
return await composeTasks({
|
|
312
|
+
world,
|
|
105
313
|
markdown: request.markdown,
|
|
106
|
-
|
|
314
|
+
defaultNamespace: request.namespace,
|
|
107
315
|
actor: input.requester,
|
|
316
|
+
planOnly: false,
|
|
108
317
|
...withSignal,
|
|
109
318
|
});
|
|
110
319
|
case "task.update":
|
|
111
|
-
return await
|
|
320
|
+
return await updateTask(world, request.id, updateTaskOptions(request.input, signal));
|
|
112
321
|
case "task.start":
|
|
113
|
-
|
|
322
|
+
if ("ids" in request)
|
|
323
|
+
return await batchTasks(world, "start", request.ids, signal);
|
|
324
|
+
return await lifecycleTask(world, request.id, "start", signal);
|
|
114
325
|
case "task.stop":
|
|
115
|
-
return await
|
|
326
|
+
return await lifecycleTask(world, request.id, "stop", signal);
|
|
116
327
|
case "task.resume":
|
|
117
|
-
return await
|
|
328
|
+
return await lifecycleTask(world, request.id, "resume", signal);
|
|
118
329
|
case "task.hold":
|
|
119
|
-
|
|
330
|
+
if ("ids" in request)
|
|
331
|
+
return await batchTasks(world, "hold", request.ids, signal);
|
|
332
|
+
return await lifecycleTask(world, request.id, "hold", signal);
|
|
120
333
|
case "task.done":
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
...withSignal,
|
|
125
|
-
...(request.note === undefined ? {} : { note: request.note }),
|
|
126
|
-
});
|
|
334
|
+
if ("ids" in request)
|
|
335
|
+
return await batchTasks(world, "done", request.ids, signal, request.note);
|
|
336
|
+
return await lifecycleTask(world, request.id, "done", signal, request.note);
|
|
127
337
|
case "task.drop":
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
...withSignal,
|
|
132
|
-
...(request.note === undefined ? {} : { note: request.note }),
|
|
133
|
-
});
|
|
338
|
+
if ("ids" in request)
|
|
339
|
+
return await batchTasks(world, "drop", request.ids, signal, request.note);
|
|
340
|
+
return await lifecycleTask(world, request.id, "drop", signal, request.note);
|
|
134
341
|
}
|
|
135
342
|
}
|
|
@@ -119,7 +119,7 @@ export declare function addTask(world: WorldRoot, input: AddTaskInput): Promise<
|
|
|
119
119
|
export declare function addTaskDocument(world: WorldRoot, input: AddTaskDocumentInput): Promise<TaskMutationResult>;
|
|
120
120
|
export declare function updateTask(world: WorldRoot, id: TaskId, input: UpdateTaskInput): Promise<TaskUpdateResult>;
|
|
121
121
|
export declare function lifecycleTask(world: WorldRoot, id: TaskId, verb: TaskLifecycleVerb, signal?: AbortSignal, note?: string): Promise<TaskMutationResult>;
|
|
122
|
-
export declare function batchTasks(world: WorldRoot, verb: "done" | "drop" | "hold", ids: readonly TaskId[], signal?: AbortSignal, note?: string): Promise<TaskBatchResult>;
|
|
122
|
+
export declare function batchTasks(world: WorldRoot, verb: "start" | "done" | "drop" | "hold", ids: readonly TaskId[], signal?: AbortSignal, note?: string): Promise<TaskBatchResult>;
|
|
123
123
|
export declare function settleTask(world: WorldRoot, id: TaskId): Promise<SettledTaskResult>;
|
|
124
124
|
export declare function listTasks(world: WorldRoot, namespace: readonly string[] | undefined, selection: "active" | "closed" | "all", scope?: "namespace" | "world", limit?: number): Promise<TaskOutcome<TaskPage<TaskRow>>>;
|
|
125
125
|
export declare function readTaskDetails(world: WorldRoot, ids: readonly TaskId[]): Promise<TaskOutcome<readonly TaskDetailFacts[]>>;
|
|
@@ -136,7 +136,4 @@ export declare function queryTasks(input: Readonly<{
|
|
|
136
136
|
sort?: TaskQuerySort;
|
|
137
137
|
limit?: number;
|
|
138
138
|
}>): Promise<TaskOutcome<TaskPage<TaskQueryRow>>>;
|
|
139
|
-
/** Internal composite observation from one complete Task board read. */
|
|
140
139
|
export declare function observeTaskBoard(world: WorldRoot): Promise<TaskBoardObservation>;
|
|
141
|
-
/** Internal identity catalog from one complete Task board read. */
|
|
142
|
-
export declare function observeTaskCatalogRows(world: WorldRoot): Promise<readonly TaskRow[]>;
|
|
@@ -304,12 +304,6 @@ export async function queryTasks(input) {
|
|
|
304
304
|
}),
|
|
305
305
|
};
|
|
306
306
|
}
|
|
307
|
-
/** Internal composite observation from one complete Task board read. */
|
|
308
307
|
export async function observeTaskBoard(world) {
|
|
309
308
|
return projectTaskBoardObservation((await readBoard(world)).board);
|
|
310
309
|
}
|
|
311
|
-
/** Internal identity catalog from one complete Task board read. */
|
|
312
|
-
export async function observeTaskCatalogRows(world) {
|
|
313
|
-
const board = (await readBoard(world)).board;
|
|
314
|
-
return projectRows(board, createTaskRelations(board), null, "all");
|
|
315
|
-
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { TASK_RELATION_PREDICATE_FIELDS, TaskAuthorityCorruptionError, Tasks } from "./index.js";
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { type ContractId } from "./core/facts/types.js";
|
|
2
2
|
import type { GitRepository } from "./git/process.js";
|
|
3
3
|
export declare const CONTRACT_PLACES: readonly string[];
|
|
4
|
+
declare const placeAuthorityFence: unique symbol;
|
|
4
5
|
export type Place = string & {
|
|
5
6
|
readonly [placeBrand]: "Place";
|
|
6
7
|
};
|
|
@@ -24,6 +25,9 @@ export type ManagedWorktreeAppointment = Readonly<{
|
|
|
24
25
|
kind: "failed";
|
|
25
26
|
diagnostic: string;
|
|
26
27
|
}>;
|
|
28
|
+
export type PlaceAuthorityFence = Readonly<{
|
|
29
|
+
readonly [placeAuthorityFence]: true;
|
|
30
|
+
}>;
|
|
27
31
|
export declare function placeRegisterPath(repository: GitRepository): string;
|
|
28
32
|
export declare function place(value: string): Place;
|
|
29
33
|
export declare function nextPlace(current?: Place): Place;
|
|
@@ -32,9 +36,10 @@ export declare function decodePlaceRegister(path: string, bytes: string): PlaceR
|
|
|
32
36
|
export declare function emptyPlaceRegister(): PlaceRegister;
|
|
33
37
|
export declare function readPlaceRegister(repository: GitRepository): Promise<PlaceRegister>;
|
|
34
38
|
export declare function appointmentFor(register: PlaceRegister, contract: ContractId): PlaceAppointment | undefined;
|
|
39
|
+
export declare function withPlaceAuthorityFence<T>(repository: GitRepository, action: (fence: PlaceAuthorityFence) => T | Promise<T>): Promise<T>;
|
|
35
40
|
export declare function appointManagedWorktrees(repository: GitRepository, contracts: readonly ContractId[]): Promise<PlaceRegister>;
|
|
36
|
-
export declare function releaseManagedWorktrees(repository: GitRepository, contracts: readonly ContractId[]): Promise<void>;
|
|
41
|
+
export declare function releaseManagedWorktrees(repository: GitRepository, contracts: readonly ContractId[], fence?: PlaceAuthorityFence): Promise<void>;
|
|
37
42
|
/** Remove only an already-empty Place authority. */
|
|
38
|
-
export declare function nukeEmptyPlaceAuthority(repository: GitRepository): Promise<void>;
|
|
43
|
+
export declare function nukeEmptyPlaceAuthority(repository: GitRepository, fence?: PlaceAuthorityFence): Promise<void>;
|
|
39
44
|
export declare function readManagedWorktreeAppointment(repository: GitRepository, contract: ContractId, register?: PlaceRegister): Promise<ManagedWorktreeAppointment>;
|
|
40
45
|
export {};
|
|
@@ -184,6 +184,7 @@ export const CONTRACT_PLACES = Object.freeze([
|
|
|
184
184
|
const PLACE_INDEX = new Map(CONTRACT_PLACES.map((base, index) => [base, index]));
|
|
185
185
|
const PLACE_VERSION = 1;
|
|
186
186
|
const GENERATION_SUFFIX = /^(?:[2-9]|[1-9][0-9]+)$/u;
|
|
187
|
+
const placeAuthorityFence = Symbol("place-authority-fence");
|
|
187
188
|
function placePaths(repository) {
|
|
188
189
|
return {
|
|
189
190
|
authority: join(repository.commonDirectory, "keiyaku", "places.json"),
|
|
@@ -305,29 +306,38 @@ export async function readPlaceRegister(repository) {
|
|
|
305
306
|
export function appointmentFor(register, contract) {
|
|
306
307
|
return register.byContract.get(contract);
|
|
307
308
|
}
|
|
308
|
-
async function
|
|
309
|
+
export async function withPlaceAuthorityFence(repository, action) {
|
|
309
310
|
const location = placePaths(repository);
|
|
310
311
|
const held = await acquireSqliteTransactionLock({ path: location.lock, mode: "immediate" });
|
|
311
312
|
try {
|
|
312
|
-
|
|
313
|
-
const next = mutate(current);
|
|
314
|
-
const bytes = canonicalPlaceRegister(next);
|
|
315
|
-
try {
|
|
316
|
-
if ((await readFile(location.authority, "utf8")) === bytes)
|
|
317
|
-
return next;
|
|
318
|
-
}
|
|
319
|
-
catch (error) {
|
|
320
|
-
if (error.code !== "ENOENT")
|
|
321
|
-
throw error;
|
|
322
|
-
}
|
|
323
|
-
await mkdir(dirname(location.authority), { recursive: true });
|
|
324
|
-
await replaceFileDurably(location.authority, bytes);
|
|
325
|
-
return next;
|
|
313
|
+
return await action({ [placeAuthorityFence]: true });
|
|
326
314
|
}
|
|
327
315
|
finally {
|
|
328
316
|
held.close();
|
|
329
317
|
}
|
|
330
318
|
}
|
|
319
|
+
async function mutatePlaceRegisterInFence(repository, mutate) {
|
|
320
|
+
const location = placePaths(repository);
|
|
321
|
+
const current = await readPlaceRegister(repository);
|
|
322
|
+
const next = mutate(current);
|
|
323
|
+
const bytes = canonicalPlaceRegister(next);
|
|
324
|
+
try {
|
|
325
|
+
if ((await readFile(location.authority, "utf8")) === bytes)
|
|
326
|
+
return next;
|
|
327
|
+
}
|
|
328
|
+
catch (error) {
|
|
329
|
+
if (error.code !== "ENOENT")
|
|
330
|
+
throw error;
|
|
331
|
+
}
|
|
332
|
+
await mkdir(dirname(location.authority), { recursive: true });
|
|
333
|
+
await replaceFileDurably(location.authority, bytes);
|
|
334
|
+
return next;
|
|
335
|
+
}
|
|
336
|
+
async function mutatePlaceRegister(repository, mutate, fence) {
|
|
337
|
+
if (fence !== undefined)
|
|
338
|
+
return await mutatePlaceRegisterInFence(repository, mutate);
|
|
339
|
+
return await withPlaceAuthorityFence(repository, async () => await mutatePlaceRegisterInFence(repository, mutate));
|
|
340
|
+
}
|
|
331
341
|
function withAppointments(register, contracts) {
|
|
332
342
|
const additions = [];
|
|
333
343
|
const occupied = new Set(register.byPlace.keys());
|
|
@@ -360,14 +370,14 @@ function firstUnoccupiedPlace(contract, occupied) {
|
|
|
360
370
|
export async function appointManagedWorktrees(repository, contracts) {
|
|
361
371
|
return await mutatePlaceRegister(repository, (current) => withAppointments(current, contracts));
|
|
362
372
|
}
|
|
363
|
-
export async function releaseManagedWorktrees(repository, contracts) {
|
|
373
|
+
export async function releaseManagedWorktrees(repository, contracts, fence) {
|
|
364
374
|
if (contracts.length === 0)
|
|
365
375
|
return;
|
|
366
376
|
const drop = new Set(contracts);
|
|
367
377
|
await mutatePlaceRegister(repository, (current) => {
|
|
368
378
|
const kept = current.appointments.filter((appointment) => !drop.has(appointment.contract));
|
|
369
379
|
return kept.length === current.appointments.length ? current : indexedRegister(kept);
|
|
370
|
-
});
|
|
380
|
+
}, fence);
|
|
371
381
|
}
|
|
372
382
|
async function regularFile(path) {
|
|
373
383
|
const value = await lstat(path).catch((error) => error.code === "ENOENT" ? undefined : Promise.reject(error));
|
|
@@ -378,22 +388,22 @@ async function regularFile(path) {
|
|
|
378
388
|
return true;
|
|
379
389
|
}
|
|
380
390
|
/** Remove only an already-empty Place authority. */
|
|
381
|
-
export async function nukeEmptyPlaceAuthority(repository) {
|
|
391
|
+
export async function nukeEmptyPlaceAuthority(repository, fence) {
|
|
382
392
|
const location = placePaths(repository);
|
|
383
393
|
const [authorityPresent, lockPresent] = [await regularFile(location.authority), await regularFile(location.lock)];
|
|
384
394
|
if (!authorityPresent && !lockPresent)
|
|
385
395
|
return;
|
|
386
|
-
const
|
|
387
|
-
try {
|
|
396
|
+
const nuke = async () => {
|
|
388
397
|
const current = await readPlaceRegister(repository);
|
|
389
398
|
if (current.appointments.length !== 0)
|
|
390
399
|
throw new Error("Place authority still has managed worktree appointments");
|
|
391
400
|
if (await regularFile(location.authority))
|
|
392
401
|
await unlink(location.authority);
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
402
|
+
};
|
|
403
|
+
if (fence !== undefined)
|
|
404
|
+
await nuke();
|
|
405
|
+
else
|
|
406
|
+
await withPlaceAuthorityFence(repository, nuke);
|
|
397
407
|
}
|
|
398
408
|
export async function readManagedWorktreeAppointment(repository, contract, register) {
|
|
399
409
|
try {
|
package/build/src/world.d.ts
CHANGED
package/build/src/world.js
CHANGED
|
@@ -113,6 +113,14 @@ async function exact(input) {
|
|
|
113
113
|
await ensureMarker(root);
|
|
114
114
|
return brand(root);
|
|
115
115
|
}
|
|
116
|
+
async function proved(input) {
|
|
117
|
+
const resolution = await resolved({ cwd: input, repositoryRoot: input });
|
|
118
|
+
const root = resolution.root;
|
|
119
|
+
if (root === null || input !== root) {
|
|
120
|
+
throw new WorldError("invalid-world", "world path must be its canonical physical directory coordinate");
|
|
121
|
+
}
|
|
122
|
+
return root;
|
|
123
|
+
}
|
|
116
124
|
async function resolved(input) {
|
|
117
125
|
const values = await inputValues(input, "world location");
|
|
118
126
|
const root = values.repositoryRoot === undefined ? await locateMarker(values.cwd) : brand(values.repositoryRoot);
|
|
@@ -147,4 +155,7 @@ export const World = Object.freeze({
|
|
|
147
155
|
at(input) {
|
|
148
156
|
return exact(input);
|
|
149
157
|
},
|
|
158
|
+
prove(input) {
|
|
159
|
+
return proved(input);
|
|
160
|
+
},
|
|
150
161
|
});
|