@astrosheep/keiyaku 2.9.3 → 2.9.5
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/build/.tsbuildinfo +1 -1
- package/build/agents/call-terms.js +14 -94
- package/build/agents/harness/activity-values.js +16 -0
- package/build/agents/harness/event-persistence.js +218 -0
- package/build/agents/harness/execution-handle.js +26 -222
- package/build/agents/harness/index.js +3 -1
- package/build/agents/harness/outcome.js +68 -5
- package/build/agents/harness/projection.js +179 -124
- package/build/agents/harness/provider-adapter.js +58 -0
- package/build/agents/harness/router.js +11 -187
- package/build/agents/harness/runtime.js +17 -4
- package/build/agents/harness/session.js +15 -0
- package/build/agents/launch-snapshot/model.js +15 -236
- package/build/agents/launch-snapshot/parse-helpers.js +114 -0
- package/build/agents/launch-snapshot/resolve.js +17 -43
- package/build/agents/opencode-sdk.js +45 -12
- package/build/agents/providers/claude-agent-sdk/adapter.js +6 -17
- package/build/agents/providers/claude-agent-sdk/registration.js +214 -0
- package/build/agents/providers/claude-agent-sdk/session-schema.js +2 -0
- package/build/agents/providers/codex-app-server/adapter.js +82 -53
- package/build/agents/providers/codex-app-server/events.js +90 -11
- package/build/agents/providers/codex-app-server/identity.js +1 -0
- package/build/agents/providers/codex-app-server/policy.js +29 -0
- package/build/agents/providers/codex-app-server/registration.js +248 -0
- package/build/agents/providers/codex-app-server/session-schema.js +6 -0
- package/build/agents/providers/codex-app-server/session.js +23 -17
- package/build/agents/providers/codex-app-server/terms.js +1 -0
- package/build/agents/providers/opencode-sdk/adapter.js +94 -50
- package/build/agents/providers/opencode-sdk/events.js +8 -4
- package/build/agents/providers/opencode-sdk/registration.js +135 -0
- package/build/agents/providers/opencode-sdk/session-schema.js +2 -0
- package/build/agents/providers/opencode-sdk/session.js +21 -14
- package/build/agents/providers/opencode-sdk/terms.js +1 -0
- package/build/agents/providers/pi/adapter.js +36 -30
- package/build/agents/providers/pi/events.js +4 -3
- package/build/agents/providers/pi/registration.js +145 -0
- package/build/agents/providers/pi/session-schema.js +6 -0
- package/build/agents/providers/pi/terms.js +1 -0
- package/build/agents/providers/registration.js +7 -0
- package/build/agents/providers/registry.js +76 -0
- package/build/agents/selector.js +2 -29
- package/build/agents/types.js +10 -0
- package/build/artifact-directories.js +22 -0
- package/build/cli/commands/akuma/akuma/handler.js +1 -1
- package/build/cli/commands/akuma/akuma/meta.js +1 -1
- package/build/cli/commands/akuma/list/meta-ls.js +1 -1
- package/build/cli/commands/akuma/view/handler.js +5 -4
- package/build/cli/commands/akuma/view/meta.js +1 -1
- package/build/cli/commands/akuma.js +6 -0
- package/build/cli/commands/contract/amend/handler.js +8 -2
- package/build/cli/commands/contract/amend/meta.js +4 -4
- package/build/cli/commands/contract/arc/handler.js +8 -2
- package/build/cli/commands/contract/arc/meta.js +4 -4
- package/build/cli/commands/contract/audit/handler.js +16 -0
- package/build/cli/commands/contract/audit/meta.js +16 -0
- package/build/cli/commands/contract/bind/handler.js +4 -3
- package/build/cli/commands/contract/bind/meta.js +44 -8
- package/build/cli/commands/contract/catalog.js +2 -0
- package/build/cli/commands/contract/forfeit/handler.js +4 -4
- package/build/cli/commands/contract/forfeit/meta.js +1 -1
- package/build/cli/commands/contract/log/handler.js +3 -3
- package/build/cli/commands/contract/log/meta.js +1 -1
- package/build/cli/commands/contract/petition/handler.js +5 -8
- package/build/cli/commands/contract/petition/meta.js +6 -6
- package/build/cli/commands/contract/renew/handler.js +20 -6
- package/build/cli/commands/contract/renew/meta.js +6 -5
- package/build/cli/commands/metadata.js +59 -0
- package/build/cli/commands/projection/call/handler.js +6 -5
- package/build/cli/commands/projection/call/meta.js +4 -1
- package/build/cli/commands/projection/kill/handler.js +16 -32
- package/build/cli/commands/projection/kill/meta.js +1 -1
- package/build/cli/commands/projection/revive/meta.js +4 -1
- package/build/cli/commands/projection/shared.js +28 -0
- package/build/cli/commands/projection/status/handler.js +1 -1
- package/build/cli/commands/projection/status/meta.js +1 -1
- package/build/cli/commands/projection/tell/handler.js +14 -30
- package/build/cli/commands/projection/tell/meta.js +4 -1
- package/build/cli/commands/projection/wait/handler.js +45 -22
- package/build/cli/commands/projection/wait/meta.js +8 -3
- package/build/cli/commands/registry.js +2 -54
- package/build/cli/commands/shared.js +10 -7
- package/build/cli/commands/skills/install/handler.js +2 -5
- package/build/cli/commands/skills/install/meta.js +1 -1
- package/build/cli/commands/skills/skills/handler.js +1 -1
- package/build/cli/commands/skills/skills/meta.js +1 -1
- package/build/cli/commands/system/completion/meta.js +1 -1
- package/build/cli/commands/system/dump-env/meta.js +1 -1
- package/build/cli/commands/system/guide/meta.js +1 -1
- package/build/cli/commands/task/add/handler.js +7 -15
- package/build/cli/commands/task/add/meta.js +4 -1
- package/build/cli/commands/task/catalog.js +2 -2
- package/build/cli/commands/task/doctor/meta.js +1 -1
- package/build/cli/commands/task/done/handler.js +4 -8
- package/build/cli/commands/task/done/meta.js +1 -1
- package/build/cli/commands/task/drop/handler.js +3 -6
- package/build/cli/commands/task/drop/meta.js +1 -1
- package/build/cli/commands/task/ls/handler.js +12 -8
- package/build/cli/commands/task/ls/meta.js +3 -3
- package/build/cli/commands/task/shared.js +14 -4
- package/build/cli/commands/task/{view → show}/handler.js +7 -8
- package/build/cli/commands/task/show/meta.js +8 -0
- package/build/cli/commands/task/start/handler.js +3 -6
- package/build/cli/commands/task/start/meta.js +1 -1
- package/build/cli/commands/task/stop/handler.js +4 -8
- package/build/cli/commands/task/stop/meta.js +1 -1
- package/build/cli/commands/task/task/handler.js +1 -1
- package/build/cli/commands/task/task/meta.js +1 -1
- package/build/cli/commands/task/update/handler.js +6 -11
- package/build/cli/commands/task/update/meta.js +4 -1
- package/build/cli/completion.js +1 -1
- package/build/cli/flags.js +37 -6
- package/build/cli/help.js +7 -14
- package/build/cli/index.js +112 -154
- package/build/cli/missing-subcommand.js +7 -0
- package/build/cli/output-stream-error-policy.js +19 -5
- package/build/cli/parse-flags.js +33 -7
- package/build/cli/parse-metadata.js +3 -9
- package/build/cli/parse-selectors.js +2 -1
- package/build/cli/parse.js +35 -5
- package/build/cli/projection-address.js +12 -12
- package/build/cli/render/address.js +41 -37
- package/build/cli/render/arc.js +24 -12
- package/build/cli/render/audit.js +121 -0
- package/build/cli/render/call.js +11 -5
- package/build/cli/render/errors.js +36 -1
- package/build/cli/render/format.js +4 -0
- package/build/cli/render/kanshi.js +6 -12
- package/build/cli/render/kill.js +9 -0
- package/build/cli/render/misc.js +58 -13
- package/build/cli/render/petition.js +20 -15
- package/build/cli/render/projection-activity.js +15 -6
- package/build/cli/render/shared.js +60 -21
- package/build/cli/render/skills.js +10 -0
- package/build/cli/render/status.js +56 -23
- package/build/cli/render/success-response.js +78 -0
- package/build/cli/render/task.js +66 -57
- package/build/cli/render/tell.js +5 -0
- package/build/cli/render/terminal-failure.js +63 -0
- package/build/cli/render/types.js +1 -0
- package/build/cli/render/wait.js +68 -38
- package/build/cli/types.js +1 -1
- package/build/config/akuma-loader.js +0 -5
- package/build/config/env-keys.js +3 -1
- package/build/config/env.js +3 -0
- package/build/config/provider-policy-ownership.js +3 -32
- package/build/config/settings/disease.js +8 -1
- package/build/config/settings/loader.js +11 -3
- package/build/config/settings/provider-instance-fields.js +51 -0
- package/build/config/settings/schema.js +6 -176
- package/build/core/addressing.js +66 -16
- package/build/core/amend.js +61 -18
- package/build/core/arc.js +33 -73
- package/build/core/audit.js +650 -0
- package/build/core/bind.js +82 -35
- package/build/core/call/call.js +15 -9
- package/build/core/call/context.js +6 -51
- package/build/core/call/execution.js +22 -22
- package/build/core/call/prompt.js +14 -1
- package/build/core/command-markdown.js +45 -0
- package/build/core/context.js +13 -7
- package/build/core/contract-view.js +22 -6
- package/build/core/draft.js +139 -19
- package/build/core/entry.js +3 -4
- package/build/core/forfeit.js +5 -2
- package/build/core/hints.js +1 -75
- package/build/core/identifier-slug.js +66 -0
- package/build/core/ids.js +25 -11
- package/build/core/ledger.js +20 -68
- package/build/core/markdown/lex.js +2 -1
- package/build/core/markdown/parser.js +0 -68
- package/build/core/markdown/render.js +68 -0
- package/build/core/markdown/sections.js +2 -1
- package/build/core/outcome-base.js +4 -0
- package/build/core/projection/generation/database.js +41 -52
- package/build/core/projection/generation/model.js +63 -2
- package/build/core/{projection-generation-continuation.js → projection/generation/projection-generation-continuation.js} +3 -3
- package/build/core/{projection-generation-execution.js → projection/generation/projection-generation-execution.js} +36 -53
- package/build/core/{projection-generation-identity.js → projection/generation/projection-generation-identity.js} +2 -2
- package/build/core/{projection-generation-launcher.js → projection/generation/projection-generation-launcher.js} +9 -7
- package/build/core/{projection-generation-process.js → projection/generation/projection-generation-process.js} +2 -1
- package/build/core/{projection-generation-runner.js → projection/generation/projection-generation-runner.js} +19 -3
- package/build/core/projection/generation/store.js +3 -3
- package/build/core/projection/generation/transitions.js +19 -3
- package/build/core/projection/index.js +27 -0
- package/build/core/{projection-activity.js → projection/projection-activity.js} +12 -0
- package/build/core/{projection-alias.js → projection/projection-alias.js} +13 -13
- package/build/core/projection/projection-coordinate.js +61 -0
- package/build/core/{projection-core.js → projection/projection-core.js} +9 -9
- package/build/core/{projection-execution-observer.js → projection/projection-execution-observer.js} +37 -78
- package/build/core/{projection-identity.js → projection/projection-identity.js} +1 -1
- package/build/core/{projection-kill.js → projection/projection-kill.js} +1 -1
- package/build/core/{projection-life-observer.js → projection/projection-life-observer.js} +16 -2
- package/build/core/{projection-mint.js → projection/projection-mint.js} +10 -10
- package/build/core/{projection-status.js → projection/projection-status.js} +163 -45
- package/build/core/projection/projection-terminal-failure.js +106 -0
- package/build/core/projection/projection-wait.js +275 -0
- package/build/core/projection/projection-wake.js +227 -0
- package/build/core/provider-loader-ports.js +4 -0
- package/build/core/ref-log.js +65 -40
- package/build/core/registry.js +63 -10
- package/build/core/renew-session.js +128 -0
- package/build/core/renew.js +448 -102
- package/build/core/scope.js +272 -68
- package/build/core/seal.js +165 -40
- package/build/core/{claim-delivery.js → settlement/claim-delivery.js} +8 -8
- package/build/core/{claim.js → settlement/claim.js} +32 -8
- package/build/core/settlement/index.js +19 -0
- package/build/core/{petition-claim-gates.js → settlement/petition-claim-gates.js} +24 -49
- package/build/core/{petition-forfeit.js → settlement/petition-forfeit.js} +2 -2
- package/build/core/{petition-head-guard.js → settlement/petition-head-guard.js} +2 -2
- package/build/core/settlement/petition-io.js +1 -0
- package/build/core/{petition-preview.js → settlement/petition-preview.js} +2 -2
- package/build/core/{petition.js → settlement/petition.js} +21 -12
- package/build/core/settlement/queue-read-model.js +143 -0
- package/build/core/settlement/queue-seat-allocation.js +156 -0
- package/build/core/settlement/queue.js +6 -0
- package/build/core/settlement/settlement.js +288 -0
- package/build/core/{verdict.js → settlement/verdict.js} +9 -37
- package/build/core/settlement/verification.js +59 -0
- package/build/core/status/board.js +62 -41
- package/build/core/status/ledger-batch.js +158 -0
- package/build/core/status/reconciliation.js +10 -4
- package/build/core/stored-agent-event.js +6 -2
- package/build/core/task/board.js +41 -4
- package/build/core/task/commands.js +45 -28
- package/build/core/task/document.js +5 -0
- package/build/core/task/index.js +12 -0
- package/build/core/task/model.js +8 -1
- package/build/core/task/query.js +172 -0
- package/build/core/task/settlement-git.js +265 -74
- package/build/core/task/settlement-policy.js +67 -29
- package/build/core/task/source-board.js +1 -0
- package/build/core/task/task-contract.js +444 -0
- package/build/core/{task-doctor.js → task/task-doctor.js} +1 -1
- package/build/core/{task-git-actor.js → task/task-git-actor.js} +5 -10
- package/build/core/{task-git-runtime.js → task/task-git-runtime.js} +3 -3
- package/build/core/{task-git-store.js → task/task-git-store.js} +90 -19
- package/build/core/task/task-repository.js +1 -0
- package/build/core/{task-store-repository.js → task/task-store-repository.js} +6 -4
- package/build/core/task/task-store.js +1 -0
- package/build/core/{task-worktree.js → task/task-worktree.js} +2 -1
- package/build/core/task/task.js +7 -0
- package/build/core/task/tree.js +37 -0
- package/build/core/task/validation.js +5 -2
- package/build/core/transcripts.js +15 -3
- package/build/core/worktree-path.js +43 -28
- package/build/flow-error.js +83 -39
- package/build/fs/path-coordinate.js +16 -0
- package/build/generated/version.js +3 -2
- package/build/git/branches.js +2 -1
- package/build/git/core.js +106 -2
- package/build/git/diff/parsers.js +23 -13
- package/build/git/diff/structured.js +127 -0
- package/build/git/path-coordinate.js +17 -0
- package/build/git/refs.js +57 -0
- package/build/git/streaming-batch.js +301 -0
- package/build/git/worktree.js +65 -0
- package/build/index.js +9 -9
- package/build/keiyaku.js +2 -36
- package/build/telemetry/logger.js +4 -2
- package/package.json +4 -10
- package/skills/keiyaku/SKILL.md +5 -4
- package/skills/keiyaku-akuma/SKILL.md +25 -11
- package/skills/keiyaku-task/SKILL.md +17 -8
- package/skills/keiyaku-workflow/SKILL.md +58 -9
- package/build/agents/providers/codex-sdk.js +0 -329
- package/build/cli/commands/task/view/meta.js +0 -8
- package/build/core/command-io.js +0 -174
- package/build/core/path-coordinate.js +0 -27
- package/build/core/petition-claim.js +0 -117
- package/build/core/petition-run.js +0 -83
- package/build/core/projection-coordinate.js +0 -63
- package/build/core/projection-wait.js +0 -165
- package/build/core/projection-wake.js +0 -136
- package/build/core/queue.js +0 -343
- package/build/core/task-contract.js +0 -237
- package/build/core/task.js +0 -4
- /package/build/{core/task-repository.js → agents/launch-snapshot/types.js} +0 -0
- /package/build/{core/task-store.js → agents/providers/claude-agent-sdk/terms.js} +0 -0
- /package/build/core/{projection-generation-runtime.js → projection/generation/projection-generation-runtime.js} +0 -0
- /package/build/core/{projection-life-protocol.js → projection/projection-life-protocol.js} +0 -0
- /package/build/core/{projection-runner-lock.js → projection/projection-runner-lock.js} +0 -0
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import { wrapGitError, runGitProcess } from "../../git/core.js";
|
|
2
|
+
import { GitStreamingBatchFramingError, GitStreamingBatchResponseEndedError, openGitStreamingBatch, } from "../../git/streaming-batch.js";
|
|
3
|
+
import { parseLedgerEntryCommitMessage } from "../entry.js";
|
|
4
|
+
import { ACTIVE_LEDGER_REF_PREFIX, } from "../ledger.js";
|
|
5
|
+
const MAX_LEDGER_COMMIT_BYTES = 1024 * 1024;
|
|
6
|
+
async function runStatusGit(cwd, args) {
|
|
7
|
+
const result = await runGitProcess(cwd, args);
|
|
8
|
+
if (result.error || result.status !== 0) {
|
|
9
|
+
throw wrapGitError(args.join(" "), {
|
|
10
|
+
message: result.error?.message
|
|
11
|
+
?? `git exited with status ${result.status ?? "unknown"}`,
|
|
12
|
+
stderr: result.stderr,
|
|
13
|
+
stdout: result.stdout,
|
|
14
|
+
}, cwd);
|
|
15
|
+
}
|
|
16
|
+
return Buffer.from(result.stdout, "utf8");
|
|
17
|
+
}
|
|
18
|
+
async function queryBatchObject(batch, expression) {
|
|
19
|
+
const record = await batch.request(expression, {
|
|
20
|
+
maxContentBytes: MAX_LEDGER_COMMIT_BYTES,
|
|
21
|
+
});
|
|
22
|
+
if (record.kind === "missing" || record.kind === "ambiguous") {
|
|
23
|
+
throw new Error(`[git cat-file ${expression}] object is ${record.kind === "missing" ? "missing" : "ambiguous"}`);
|
|
24
|
+
}
|
|
25
|
+
return {
|
|
26
|
+
oid: record.record.oid,
|
|
27
|
+
type: record.record.type,
|
|
28
|
+
content: record.record.content,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
function parseCommitObject(object) {
|
|
32
|
+
if (object.type !== "commit") {
|
|
33
|
+
throw new Error(`git cat-file expected commit ${object.oid}, received ${object.type}`);
|
|
34
|
+
}
|
|
35
|
+
const content = object.content.toString("utf8");
|
|
36
|
+
const messageStart = content.indexOf("\n\n");
|
|
37
|
+
if (messageStart < 0)
|
|
38
|
+
throw new Error(`git commit ${object.oid} has no message separator`);
|
|
39
|
+
const parents = [];
|
|
40
|
+
for (const line of content.slice(0, messageStart).split("\n")) {
|
|
41
|
+
if (!line.startsWith("parent "))
|
|
42
|
+
continue;
|
|
43
|
+
const parent = line.slice("parent ".length);
|
|
44
|
+
if (!/^[0-9a-f]{40,64}$/.test(parent)) {
|
|
45
|
+
throw new Error(`git commit ${object.oid} has an invalid parent header`);
|
|
46
|
+
}
|
|
47
|
+
parents.push(parent);
|
|
48
|
+
}
|
|
49
|
+
return { oid: object.oid, parents, message: content.slice(messageStart + 2) };
|
|
50
|
+
}
|
|
51
|
+
function parseLedgerRefs(output) {
|
|
52
|
+
return output
|
|
53
|
+
.toString("utf8")
|
|
54
|
+
.split(/\r?\n/)
|
|
55
|
+
.filter((ref) => ref.startsWith(ACTIVE_LEDGER_REF_PREFIX))
|
|
56
|
+
.map((ref) => ({ contractId: ref.slice(ACTIVE_LEDGER_REF_PREFIX.length), ref }));
|
|
57
|
+
}
|
|
58
|
+
async function readLedgerFromBatch(batch, ref, commits) {
|
|
59
|
+
const headObject = await queryBatchObject(batch, `${ref.ref}^{commit}`);
|
|
60
|
+
const head = parseCommitObject(headObject);
|
|
61
|
+
commits.set(head.oid, Promise.resolve(head));
|
|
62
|
+
const ordered = [];
|
|
63
|
+
const visited = new Set();
|
|
64
|
+
const visiting = new Set();
|
|
65
|
+
const visit = async (oid) => {
|
|
66
|
+
if (visited.has(oid))
|
|
67
|
+
return;
|
|
68
|
+
if (visiting.has(oid))
|
|
69
|
+
throw new Error(`git ledger ancestry contains a cycle at ${oid}`);
|
|
70
|
+
visiting.add(oid);
|
|
71
|
+
let pending = commits.get(oid);
|
|
72
|
+
if (!pending) {
|
|
73
|
+
pending = queryBatchObject(batch, oid).then(parseCommitObject);
|
|
74
|
+
commits.set(oid, pending);
|
|
75
|
+
}
|
|
76
|
+
const commit = await pending;
|
|
77
|
+
for (const parent of commit.parents)
|
|
78
|
+
await visit(parent);
|
|
79
|
+
visiting.delete(oid);
|
|
80
|
+
visited.add(oid);
|
|
81
|
+
ordered.push(commit);
|
|
82
|
+
};
|
|
83
|
+
await visit(head.oid);
|
|
84
|
+
return {
|
|
85
|
+
contractId: ref.contractId,
|
|
86
|
+
ref: ref.ref,
|
|
87
|
+
head: head.oid,
|
|
88
|
+
entries: ordered.map((commit) => parseLedgerEntryCommitMessage(commit.message)),
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Read the aggregate status ledger snapshot with at most two Git processes:
|
|
93
|
+
* ref-name discovery and one framed, streaming object session.
|
|
94
|
+
*/
|
|
95
|
+
export async function readStatusLedgers(cwd) {
|
|
96
|
+
const refOutput = await runStatusGit(cwd, [
|
|
97
|
+
"for-each-ref",
|
|
98
|
+
"--sort=refname",
|
|
99
|
+
"--format=%(refname)",
|
|
100
|
+
ACTIVE_LEDGER_REF_PREFIX,
|
|
101
|
+
]);
|
|
102
|
+
const refs = parseLedgerRefs(refOutput);
|
|
103
|
+
if (refs.length === 0)
|
|
104
|
+
return [];
|
|
105
|
+
const batch = openGitStreamingBatch(cwd);
|
|
106
|
+
const commits = new Map();
|
|
107
|
+
const results = [];
|
|
108
|
+
let readError;
|
|
109
|
+
try {
|
|
110
|
+
for (let index = 0; index < refs.length; index += 1) {
|
|
111
|
+
const ref = refs[index];
|
|
112
|
+
try {
|
|
113
|
+
results.push(await readLedgerFromBatch(batch, ref, commits));
|
|
114
|
+
}
|
|
115
|
+
catch (error) {
|
|
116
|
+
const diagnostic = error instanceof Error ? error : new Error(String(error));
|
|
117
|
+
results.push({ id: ref.contractId, error: diagnostic });
|
|
118
|
+
// Framing and mid-frame EOF both destroy the batch channel; isolate remaining refs.
|
|
119
|
+
if (error instanceof GitStreamingBatchFramingError
|
|
120
|
+
|| error instanceof GitStreamingBatchResponseEndedError) {
|
|
121
|
+
const isolationReason = error instanceof GitStreamingBatchResponseEndedError
|
|
122
|
+
? "response ended"
|
|
123
|
+
: "malformed frame";
|
|
124
|
+
for (const pending of refs.slice(index + 1)) {
|
|
125
|
+
results.push({
|
|
126
|
+
id: pending.contractId,
|
|
127
|
+
error: new Error(`git cat-file batch terminated after ${isolationReason}: ${diagnostic.message}`),
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
break;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
catch (error) {
|
|
136
|
+
readError = error;
|
|
137
|
+
}
|
|
138
|
+
try {
|
|
139
|
+
const close = await batch.close();
|
|
140
|
+
if (!close.aborted && (close.timedOut || close.signal || close.code !== 0)) {
|
|
141
|
+
throw wrapGitError("cat-file --batch", {
|
|
142
|
+
message: close.timedOut
|
|
143
|
+
? "git timed out"
|
|
144
|
+
: close.signal
|
|
145
|
+
? `git exited from signal ${close.signal}`
|
|
146
|
+
: `git exited with status ${close.code ?? "unknown"}`,
|
|
147
|
+
stderr: close.stderr.toString("utf8"),
|
|
148
|
+
}, cwd);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
catch (error) {
|
|
152
|
+
if (!readError)
|
|
153
|
+
readError = error;
|
|
154
|
+
}
|
|
155
|
+
if (readError)
|
|
156
|
+
throw readError;
|
|
157
|
+
return results;
|
|
158
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as fs from "node:fs";
|
|
2
2
|
import * as path from "node:path";
|
|
3
|
-
import { createGit } from "../../git/core.js";
|
|
3
|
+
import { createGit, parseRevListOutput, wrapGitError } from "../../git/core.js";
|
|
4
4
|
import { stableRepoRoot } from "../worktree-path.js";
|
|
5
5
|
function isClaimReceipt(value) {
|
|
6
6
|
if (!value || typeof value !== "object")
|
|
@@ -51,7 +51,13 @@ export async function computeClaimReconciliation(cwd, defaultBranch) {
|
|
|
51
51
|
if (receiptLines.length === 0)
|
|
52
52
|
return null;
|
|
53
53
|
const git = createGit(cwd);
|
|
54
|
-
|
|
54
|
+
let firstParentHistory;
|
|
55
|
+
try {
|
|
56
|
+
firstParentHistory = parseRevListOutput(await git.raw(["rev-list", "--first-parent", defaultBranch.head]));
|
|
57
|
+
}
|
|
58
|
+
catch (error) {
|
|
59
|
+
throw wrapGitError(`rev-list --first-parent ${defaultBranch.head}`, error, cwd);
|
|
60
|
+
}
|
|
55
61
|
const firstParentSet = new Set(firstParentHistory);
|
|
56
62
|
let baselineIndex = -1;
|
|
57
63
|
for (let index = receiptLines.length - 1; index >= 0; index -= 1) {
|
|
@@ -70,10 +76,10 @@ export async function computeClaimReconciliation(cwd, defaultBranch) {
|
|
|
70
76
|
return line.record?.kind === "baseline" ? [{ line: line.line, reason: "non-chain" }] : [];
|
|
71
77
|
});
|
|
72
78
|
// Only records after the latest valid baseline belong to this fence window.
|
|
79
|
+
// Intentional degrade: rev-list failure yields empty segments plus non-chain receipt issues.
|
|
73
80
|
let revList;
|
|
74
81
|
try {
|
|
75
|
-
|
|
76
|
-
revList = output.trim().split("\n").filter((h) => h.length > 0);
|
|
82
|
+
revList = parseRevListOutput(await git.raw(["rev-list", "--first-parent", "--reverse", `${baseline.head}..${defaultBranch.head}`]));
|
|
77
83
|
}
|
|
78
84
|
catch {
|
|
79
85
|
return {
|
|
@@ -1,17 +1,21 @@
|
|
|
1
1
|
import { activityEventBodySchema, AGENT_EVENT_TEXT_MAX_CHARS, AGENT_UNKNOWN_PAYLOAD_MAX_CHARS, EXEC_EVENT_BUFFER_HARD_CAP, } from "../agents/harness/index.js";
|
|
2
2
|
import { isSubagentProvider } from "../keiyaku.js";
|
|
3
|
-
const FAIL_CODES = new Set(["SUBAGENT_TIMEOUT", "SUBAGENT_NON_ZERO_EXIT", "SUBAGENT_SPAWN_ERROR", "SUBAGENT_EXEC_ERROR", "SUBAGENT_PROVIDER_UNAVAILABLE", "PROJECTION_STATE_ERROR"]);
|
|
3
|
+
const FAIL_CODES = new Set(["SUBAGENT_TIMEOUT", "SUBAGENT_TRANSPORT_ERROR", "SUBAGENT_POLICY_BUDGET", "SUBAGENT_NON_ZERO_EXIT", "SUBAGENT_SPAWN_ERROR", "SUBAGENT_EXEC_ERROR", "SUBAGENT_PROVIDER_UNAVAILABLE", "PROJECTION_STATE_ERROR"]);
|
|
4
4
|
const KNOWN = new Set(["message", "unknown", "activity", "thought", "plan", "turn", "usage", "warning", "diagnostic", "truncation", "done", "fail"]);
|
|
5
5
|
const record = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
|
|
6
6
|
const finite = (value) => typeof value === "number" && Number.isFinite(value);
|
|
7
|
+
const nonNegativeFinite = (value) => finite(value) && value >= 0;
|
|
7
8
|
const optionalString = (value, key) => value[key] === undefined || typeof value[key] === "string";
|
|
8
9
|
const nonNegativeSafeInteger = (value) => typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
|
|
9
10
|
const safeIntegerOrNull = (value) => value === null || (typeof value === "number" && Number.isSafeInteger(value));
|
|
10
11
|
function isValidStoredWarning(warning) {
|
|
12
|
+
if (warning.reason === "rate-limit") {
|
|
13
|
+
return warning.state === "exhausted" && Object.keys(warning).length === 2;
|
|
14
|
+
}
|
|
11
15
|
if (warning.reason === "retry") {
|
|
12
16
|
return nonNegativeSafeInteger(warning.attempt)
|
|
13
17
|
&& nonNegativeSafeInteger(warning.maxRetries)
|
|
14
|
-
&&
|
|
18
|
+
&& nonNegativeFinite(warning.retryDelayMs)
|
|
15
19
|
&& safeIntegerOrNull(warning.errorStatus);
|
|
16
20
|
}
|
|
17
21
|
if (warning.reason === "refusal" || warning.reason === "overload") {
|
package/build/core/task/board.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { FlowError } from "../../flow-error.js";
|
|
2
|
-
import {
|
|
3
|
-
const TASK_READ_ID = /^k-[0-9a-f]{7,12}$/;
|
|
2
|
+
import { isTaskId } from "./validation.js";
|
|
4
3
|
function compareText(left, right) {
|
|
5
4
|
return left < right ? -1 : left > right ? 1 : 0;
|
|
6
5
|
}
|
|
@@ -60,6 +59,30 @@ function cycleComponents(tasks) {
|
|
|
60
59
|
visit(id);
|
|
61
60
|
return cycles;
|
|
62
61
|
}
|
|
62
|
+
function parentCycleComponents(tasks) {
|
|
63
|
+
const cycles = [];
|
|
64
|
+
const visited = new Set();
|
|
65
|
+
for (const start of [...tasks.keys()].sort()) {
|
|
66
|
+
if (visited.has(start))
|
|
67
|
+
continue;
|
|
68
|
+
const path = [];
|
|
69
|
+
const positions = new Map();
|
|
70
|
+
let current = start;
|
|
71
|
+
while (current !== null && tasks.has(current) && !visited.has(current)) {
|
|
72
|
+
const prior = positions.get(current);
|
|
73
|
+
if (prior !== undefined) {
|
|
74
|
+
cycles.push(new Set(path.slice(prior)));
|
|
75
|
+
break;
|
|
76
|
+
}
|
|
77
|
+
positions.set(current, path.length);
|
|
78
|
+
path.push(current);
|
|
79
|
+
current = tasks.get(current).parent;
|
|
80
|
+
}
|
|
81
|
+
for (const id of path)
|
|
82
|
+
visited.add(id);
|
|
83
|
+
}
|
|
84
|
+
return cycles;
|
|
85
|
+
}
|
|
63
86
|
/** Derive the complete storage-neutral board from domain records. */
|
|
64
87
|
export function buildTaskBoardFromDocuments(documents) {
|
|
65
88
|
const diseases = [];
|
|
@@ -91,6 +114,17 @@ export function buildTaskBoardFromDocuments(documents) {
|
|
|
91
114
|
candidates.delete(id);
|
|
92
115
|
}
|
|
93
116
|
}
|
|
117
|
+
for (const component of parentCycleComponents(candidates)) {
|
|
118
|
+
const relatedIds = [...component].sort();
|
|
119
|
+
for (const id of relatedIds) {
|
|
120
|
+
diseases.push({
|
|
121
|
+
code: "parent_cycle",
|
|
122
|
+
message: `task ${id} participates in a parent cycle`,
|
|
123
|
+
id,
|
|
124
|
+
relatedIds,
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
}
|
|
94
128
|
let changed = true;
|
|
95
129
|
while (changed) {
|
|
96
130
|
changed = false;
|
|
@@ -129,6 +163,7 @@ export function buildTaskBoardFromDocuments(documents) {
|
|
|
129
163
|
parent: task.parent,
|
|
130
164
|
from: [...task.from],
|
|
131
165
|
createdAt: task.createdAt,
|
|
166
|
+
...(task.updatedAt === undefined ? {} : { updatedAt: task.updatedAt }),
|
|
132
167
|
creator: task.creator,
|
|
133
168
|
...(task.startedAt === undefined ? {} : { startedAt: task.startedAt }),
|
|
134
169
|
...(task.contractId === undefined ? {} : { contractId: task.contractId }),
|
|
@@ -148,9 +183,11 @@ export function resolveTaskReadId(board, input) {
|
|
|
148
183
|
return resolveTaskId(board, input);
|
|
149
184
|
}
|
|
150
185
|
export function resolveTaskId(board, input) {
|
|
151
|
-
if (!
|
|
186
|
+
if (!isTaskId(input)) {
|
|
152
187
|
throw new FlowError("INVALID_TARGET", `invalid task id '${input}'`);
|
|
153
188
|
}
|
|
189
|
+
if (board.byId.has(input))
|
|
190
|
+
return input;
|
|
154
191
|
const matches = board.tasks
|
|
155
192
|
.map((task) => task.id)
|
|
156
193
|
.filter((id) => id.startsWith(input))
|
|
@@ -163,7 +200,7 @@ export function resolveTaskId(board, input) {
|
|
|
163
200
|
return matches[0];
|
|
164
201
|
}
|
|
165
202
|
export function requireCanonicalTaskId(input) {
|
|
166
|
-
if (!
|
|
203
|
+
if (!isTaskId(input)) {
|
|
167
204
|
throw new FlowError("INVALID_TARGET", "task mutations require a canonical full task id");
|
|
168
205
|
}
|
|
169
206
|
return input;
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { FlowError } from "../../flow-error.js";
|
|
2
|
+
import { IdentifierSlugError, normalizeIdentifierSlug, SUFFIXABLE_IDENTIFIER_SLUG_MAX_UTF8_BYTES, } from "../identifier-slug.js";
|
|
2
3
|
import { requireCanonicalTaskId, requireHealthy, resolveTaskId, } from "./board.js";
|
|
3
4
|
import { dateTimestamp, invalid, nonblank, } from "./validation.js";
|
|
5
|
+
import { advancedTaskUpdatedAt } from "./model.js";
|
|
4
6
|
export async function readTaskBoard(repository) {
|
|
5
7
|
return repository.read();
|
|
6
8
|
}
|
|
@@ -14,15 +16,17 @@ function documentFromView(view) {
|
|
|
14
16
|
parent: view.parent,
|
|
15
17
|
from: [...view.from],
|
|
16
18
|
createdAt: view.createdAt,
|
|
19
|
+
...(view.updatedAt === undefined ? {} : { updatedAt: view.updatedAt }),
|
|
17
20
|
creator: view.creator,
|
|
18
21
|
...(view.startedAt === undefined ? {} : { startedAt: view.startedAt }),
|
|
19
22
|
...(view.contractId === undefined ? {} : { contractId: view.contractId }),
|
|
20
23
|
body: view.body,
|
|
21
24
|
};
|
|
22
25
|
}
|
|
23
|
-
function replaceDocument(document) {
|
|
26
|
+
function replaceDocument(document, subject) {
|
|
24
27
|
return {
|
|
25
28
|
replacements: [document],
|
|
29
|
+
subject,
|
|
26
30
|
select(resulting) {
|
|
27
31
|
const value = resulting.byId.get(document.id);
|
|
28
32
|
if (!value)
|
|
@@ -43,6 +47,16 @@ function resolveMutationIds(board, ids) {
|
|
|
43
47
|
export async function createTask(repository, input, deps) {
|
|
44
48
|
nonblank("title", input.title);
|
|
45
49
|
nonblank("creator", input.creator);
|
|
50
|
+
let baseId;
|
|
51
|
+
try {
|
|
52
|
+
baseId = normalizeIdentifierSlug(input.title, SUFFIXABLE_IDENTIFIER_SLUG_MAX_UTF8_BYTES);
|
|
53
|
+
}
|
|
54
|
+
catch (error) {
|
|
55
|
+
if (error instanceof IdentifierSlugError) {
|
|
56
|
+
throw new FlowError("INVALID_TARGET", `task title ${error.message}`, { cause: error });
|
|
57
|
+
}
|
|
58
|
+
throw error;
|
|
59
|
+
}
|
|
46
60
|
const pri = input.pri ?? 2;
|
|
47
61
|
if (!Number.isInteger(pri) || pri < 0 || pri > 3)
|
|
48
62
|
invalid("task priority must be an integer from 0 through 3");
|
|
@@ -55,19 +69,14 @@ export async function createTask(repository, input, deps) {
|
|
|
55
69
|
const from = resolveMutationIds(board, input.from ?? []);
|
|
56
70
|
if (new Set(from).size !== from.length)
|
|
57
71
|
invalid("task from edges must be unique");
|
|
58
|
-
let id;
|
|
59
|
-
for (let
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
throw new FlowError("INTERNAL_STATE", "randomBytes(6) must return exactly 6 bytes");
|
|
63
|
-
const candidate = `k-${Buffer.from(bytes).toString("hex")}`;
|
|
64
|
-
if (!board.byId.has(candidate)) {
|
|
65
|
-
id = candidate;
|
|
66
|
-
break;
|
|
72
|
+
let id = baseId;
|
|
73
|
+
for (let ordinal = 2; board.byId.has(id); ordinal += 1) {
|
|
74
|
+
if (!Number.isSafeInteger(ordinal)) {
|
|
75
|
+
throw new FlowError("INTERNAL_STATE", `task id collision ordinal exceeded the safe integer range for ${baseId}`);
|
|
67
76
|
}
|
|
77
|
+
id = `${baseId}-${ordinal}`;
|
|
68
78
|
}
|
|
69
|
-
|
|
70
|
-
throw new FlowError("CONCURRENT_MODIFICATION", "could not allocate a unique task id after 32 attempts");
|
|
79
|
+
const now = deps.now();
|
|
71
80
|
const document = {
|
|
72
81
|
id,
|
|
73
82
|
title: input.title,
|
|
@@ -76,14 +85,15 @@ export async function createTask(repository, input, deps) {
|
|
|
76
85
|
needs,
|
|
77
86
|
parent,
|
|
78
87
|
from,
|
|
79
|
-
createdAt: dateTimestamp("createdAt",
|
|
88
|
+
createdAt: dateTimestamp("createdAt", now),
|
|
89
|
+
updatedAt: dateTimestamp("updatedAt", now),
|
|
80
90
|
creator: input.creator,
|
|
81
91
|
body: input.body ?? "",
|
|
82
92
|
};
|
|
83
|
-
return replaceDocument(document);
|
|
93
|
+
return replaceDocument(document, `Add task ${id}`);
|
|
84
94
|
});
|
|
85
95
|
}
|
|
86
|
-
export async function updateTask(repository, fullIdValue, patch) {
|
|
96
|
+
export async function updateTask(repository, fullIdValue, patch, now = new Date()) {
|
|
87
97
|
const hasChange = Object.values(patch).some((value) => value !== undefined);
|
|
88
98
|
if (!hasChange)
|
|
89
99
|
throw new FlowError("EMPTY_PARAM", "task update requires at least one change");
|
|
@@ -112,18 +122,21 @@ export async function updateTask(repository, fullIdValue, patch) {
|
|
|
112
122
|
if (JSON.stringify(document) === JSON.stringify(documentFromView(current))) {
|
|
113
123
|
throw new FlowError("EMPTY_PARAM", "task update requires at least one change");
|
|
114
124
|
}
|
|
115
|
-
|
|
125
|
+
document.updatedAt = advancedTaskUpdatedAt(current, now);
|
|
126
|
+
return replaceDocument(document, `Update task ${id}`);
|
|
116
127
|
});
|
|
117
128
|
}
|
|
118
|
-
async function transition(repository, fullIdValue, apply) {
|
|
129
|
+
async function transition(repository, fullIdValue, apply, subject, now) {
|
|
119
130
|
return repository.mutate((board) => {
|
|
120
131
|
requireHealthy(board);
|
|
121
132
|
const id = fullIdValue === undefined
|
|
122
133
|
? selectSoleInProgress(board).id
|
|
123
134
|
: resolveTaskId(board, fullIdValue);
|
|
124
|
-
const
|
|
135
|
+
const current = requireExisting(board, id);
|
|
136
|
+
const document = documentFromView(current);
|
|
125
137
|
apply(document);
|
|
126
|
-
|
|
138
|
+
document.updatedAt = advancedTaskUpdatedAt(current, now);
|
|
139
|
+
return replaceDocument(document, subject(id));
|
|
127
140
|
});
|
|
128
141
|
}
|
|
129
142
|
function rejectBound(document, action = "state") {
|
|
@@ -141,18 +154,18 @@ export async function startTask(repository, fullId, now) {
|
|
|
141
154
|
invalid(`task ${document.id} is ${document.state}, not open`);
|
|
142
155
|
document.state = "in_progress";
|
|
143
156
|
document.startedAt = dateTimestamp("startedAt", now);
|
|
144
|
-
});
|
|
157
|
+
}, (id) => `Start task ${id}`, now);
|
|
145
158
|
}
|
|
146
|
-
export async function stopTask(repository, fullId) {
|
|
159
|
+
export async function stopTask(repository, fullId, now = new Date()) {
|
|
147
160
|
return transition(repository, fullId, (document) => {
|
|
148
161
|
rejectBound(document);
|
|
149
162
|
if (document.state !== "in_progress")
|
|
150
163
|
invalid(`task ${document.id} is ${document.state}, not in_progress`);
|
|
151
164
|
document.state = "open";
|
|
152
165
|
delete document.startedAt;
|
|
153
|
-
});
|
|
166
|
+
}, (id) => `Stop task ${id}`, now);
|
|
154
167
|
}
|
|
155
|
-
export async function doneTask(repository, fullId) {
|
|
168
|
+
export async function doneTask(repository, fullId, now = new Date()) {
|
|
156
169
|
return transition(repository, fullId, (document) => {
|
|
157
170
|
rejectBound(document);
|
|
158
171
|
if (document.state !== "open" && document.state !== "in_progress") {
|
|
@@ -160,9 +173,9 @@ export async function doneTask(repository, fullId) {
|
|
|
160
173
|
}
|
|
161
174
|
document.state = "done";
|
|
162
175
|
delete document.startedAt;
|
|
163
|
-
});
|
|
176
|
+
}, (id) => `Done task ${id}`, now);
|
|
164
177
|
}
|
|
165
|
-
export async function dropTask(repository, fullId) {
|
|
178
|
+
export async function dropTask(repository, fullId, now = new Date()) {
|
|
166
179
|
return transition(repository, fullId, (document) => {
|
|
167
180
|
rejectBound(document, "drop");
|
|
168
181
|
if (document.state !== "open" && document.state !== "in_progress") {
|
|
@@ -170,7 +183,7 @@ export async function dropTask(repository, fullId) {
|
|
|
170
183
|
}
|
|
171
184
|
document.state = "drop";
|
|
172
185
|
delete document.startedAt;
|
|
173
|
-
});
|
|
186
|
+
}, (id) => `Drop task ${id}`, now);
|
|
174
187
|
}
|
|
175
188
|
export function selectSoleInProgress(board) {
|
|
176
189
|
const candidates = board.tasks.filter((task) => task.state === "in_progress");
|
|
@@ -184,7 +197,7 @@ export function selectSoleInProgress(board) {
|
|
|
184
197
|
}
|
|
185
198
|
/** Reopen task pointers whose contract authority has disappeared. The caller
|
|
186
199
|
* supplies the ledger fact; this operation itself remains storage-neutral. */
|
|
187
|
-
export async function rollbackOrphanTaskPointers(repository, contractIds) {
|
|
200
|
+
export async function rollbackOrphanTaskPointers(repository, contractIds, now = new Date()) {
|
|
188
201
|
const before = await repository.read();
|
|
189
202
|
const orphans = before.tasks
|
|
190
203
|
.filter((task) => task.contractId !== undefined && !contractIds.has(task.contractId))
|
|
@@ -199,13 +212,17 @@ export async function rollbackOrphanTaskPointers(repository, contractIds) {
|
|
|
199
212
|
return [];
|
|
200
213
|
const document = documentFromView(current);
|
|
201
214
|
document.state = "open";
|
|
215
|
+
document.updatedAt = advancedTaskUpdatedAt(current, now);
|
|
202
216
|
delete document.startedAt;
|
|
203
217
|
delete document.contractId;
|
|
204
218
|
return [document];
|
|
205
219
|
});
|
|
206
220
|
if (replacements.length === 0)
|
|
207
221
|
throw new FlowError("CONCURRENT_MODIFICATION", "task pointers changed while doctor was reconciling them");
|
|
208
|
-
|
|
222
|
+
const subject = replacements.length === 1
|
|
223
|
+
? `Clear orphan contract pointer from task ${replacements[0].id}`
|
|
224
|
+
: `Clear orphan contract pointers from ${replacements.length} tasks`;
|
|
225
|
+
return { replacements, subject, select: () => undefined };
|
|
209
226
|
});
|
|
210
227
|
return orphans;
|
|
211
228
|
}
|
|
@@ -9,6 +9,7 @@ const FIELD_ORDER = [
|
|
|
9
9
|
"parent",
|
|
10
10
|
"from",
|
|
11
11
|
"createdAt",
|
|
12
|
+
"updatedAt",
|
|
12
13
|
"creator",
|
|
13
14
|
"startedAt",
|
|
14
15
|
"contractId",
|
|
@@ -134,6 +135,8 @@ export function parseTaskDocument(source) {
|
|
|
134
135
|
if (from.includes(id))
|
|
135
136
|
invalid("task field 'from' must not reference itself");
|
|
136
137
|
const createdAt = canonicalTimestamp("createdAt", values.get("createdAt"));
|
|
138
|
+
const updatedValue = values.get("updatedAt");
|
|
139
|
+
const updatedAt = updatedValue === undefined ? undefined : canonicalTimestamp("updatedAt", updatedValue);
|
|
137
140
|
const creator = nonblank("creator", values.get("creator"));
|
|
138
141
|
const startedValue = values.get("startedAt");
|
|
139
142
|
const contractValue = values.get("contractId");
|
|
@@ -154,6 +157,7 @@ export function parseTaskDocument(source) {
|
|
|
154
157
|
parent,
|
|
155
158
|
from,
|
|
156
159
|
createdAt,
|
|
160
|
+
...(updatedAt === undefined ? {} : { updatedAt }),
|
|
157
161
|
creator,
|
|
158
162
|
...(startedAt === undefined ? {} : { startedAt }),
|
|
159
163
|
...(contractId === undefined ? {} : { contractId }),
|
|
@@ -174,6 +178,7 @@ function serializeUnchecked(document) {
|
|
|
174
178
|
parent: document.parent,
|
|
175
179
|
from: document.from,
|
|
176
180
|
createdAt: document.createdAt,
|
|
181
|
+
...(document.updatedAt === undefined ? {} : { updatedAt: document.updatedAt }),
|
|
177
182
|
creator: document.creator,
|
|
178
183
|
};
|
|
179
184
|
if (document.startedAt !== undefined)
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public surface for the task package.
|
|
3
|
+
* Only symbols required by current external consumers are re-exported.
|
|
4
|
+
* Package-internal modules must import each other directly, not through this file.
|
|
5
|
+
*/
|
|
6
|
+
export { reconcileTaskForfeit, settleTaskBoardForBind, settleTaskBoardForLanding, } from "./task-contract.js";
|
|
7
|
+
export { resolveTaskCreator } from "./task-git-actor.js";
|
|
8
|
+
export { openTaskCommandRepository, readTaskDoctor, taskCommandContractId, } from "./task-git-runtime.js";
|
|
9
|
+
export { openTaskStore } from "./task-git-store.js";
|
|
10
|
+
export { taskRepositoryFromStore } from "./task-store-repository.js";
|
|
11
|
+
export { isTaskId } from "./validation.js";
|
|
12
|
+
export { buildTaskTree, createTask, doneTask, dropTask, parseTaskDocument, readTaskBoard, resolveTaskReadId, serializeTaskDocument, startTask, stopTask, updateTask, deriveTaskDisplay, selectTaskList, taskUpdatedAt, advancedTaskUpdatedAt, } from "./task.js";
|
package/build/core/task/model.js
CHANGED
|
@@ -1 +1,8 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export function taskUpdatedAt(task) {
|
|
2
|
+
return task.updatedAt ?? task.createdAt;
|
|
3
|
+
}
|
|
4
|
+
export function advancedTaskUpdatedAt(task, observed) {
|
|
5
|
+
const observedMs = observed instanceof Date ? observed.getTime() : Date.parse(observed);
|
|
6
|
+
const priorMs = Date.parse(taskUpdatedAt(task));
|
|
7
|
+
return new Date(Math.max(observedMs, priorMs + 1)).toISOString();
|
|
8
|
+
}
|