@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
|
@@ -8,23 +8,27 @@ allowed-tools: Bash(keiyaku *)
|
|
|
8
8
|
|
|
9
9
|
Planning notes that live in the repo. Executing them is `keiyaku-workflow` (`bind --task`).
|
|
10
10
|
|
|
11
|
-
##
|
|
11
|
+
## Core ideas
|
|
12
12
|
|
|
13
|
-
A task is a
|
|
13
|
+
A task is a tracked planning fact, not a worker or execution. Its immutable ID
|
|
14
|
+
is a normalized title slug with a numeric collision suffix when needed. It has
|
|
15
|
+
priority 0–3 (0 highest), optional body, and no branch of its own.
|
|
14
16
|
|
|
15
17
|
```
|
|
16
18
|
open ⇄ in_progress → done | drop
|
|
17
19
|
```
|
|
18
20
|
|
|
19
|
-
**Ready** = open + every `needs` dependency
|
|
21
|
+
**Ready** = open + every `needs` dependency satisfied. `needs` only orders
|
|
22
|
+
tasks; binding is what turns ready planning facts into one executable contract.
|
|
20
23
|
|
|
21
24
|
## Common usage
|
|
22
25
|
|
|
23
26
|
```bash
|
|
24
|
-
keiyaku task add
|
|
27
|
+
keiyaku task add - < task.md # literal - reads the task body from stdin
|
|
25
28
|
keiyaku task add "title" --pri 1 --needs k-aaa # priority + dependency at birth
|
|
26
|
-
keiyaku task ls # all
|
|
27
|
-
keiyaku task
|
|
29
|
+
keiyaku task ls # all nonterminal tasks
|
|
30
|
+
keiyaku task ls --filter state=ready --sort priority,modified
|
|
31
|
+
keiyaku task show k-xxxx # full detail and parent-children tree
|
|
28
32
|
keiyaku task start k-xxxx # mark in_progress (start ≠ execute)
|
|
29
33
|
keiyaku task stop k-xxxx # back to open
|
|
30
34
|
keiyaku task done k-xxxx
|
|
@@ -41,10 +45,15 @@ keiyaku task doctor # check board integrity
|
|
|
41
45
|
## Promoting to a contract
|
|
42
46
|
|
|
43
47
|
```bash
|
|
44
|
-
keiyaku bind --task
|
|
48
|
+
keiyaku bind --task fix-parser
|
|
49
|
+
keiyaku bind --task fix-parser --task fix-parser-help - < contract.md
|
|
45
50
|
```
|
|
46
51
|
|
|
47
|
-
Only
|
|
52
|
+
Only ready tasks bind. Multi-bind only when the tasks describe one delivery
|
|
53
|
+
intent, share a coherent write surface, and should settle together; otherwise
|
|
54
|
+
keep separate contracts and express order with task `needs` or contract
|
|
55
|
+
`--after`. The first task supplies name/objective defaults; provide a partial
|
|
56
|
+
bind document for any missing `Scope` or `Checks`.
|
|
48
57
|
|
|
49
58
|
## Gotcha
|
|
50
59
|
|
|
@@ -8,9 +8,15 @@ allowed-tools: Bash(keiyaku *)
|
|
|
8
8
|
|
|
9
9
|
How a contract lives. Running akuma is the `keiyaku-akuma` skill; task planning is `keiyaku-task`.
|
|
10
10
|
|
|
11
|
-
##
|
|
11
|
+
## Core ideas
|
|
12
12
|
|
|
13
|
-
A contract
|
|
13
|
+
- A contract is one delivery intent with one ledger, branch, and linked worktree.
|
|
14
|
+
- Workers edit and test; the host reviews their dirty tree and commits accepted bytes.
|
|
15
|
+
- `audit` reads one pinned candidate. `petition` is the settlement action.
|
|
16
|
+
- Scope is an audit boundary, not a write lock. Amend changed intent before delivery.
|
|
17
|
+
- An arc is a named story chapter for one coherent stretch inside the contract.
|
|
18
|
+
|
|
19
|
+
Lifecycle:
|
|
14
20
|
|
|
15
21
|
```
|
|
16
22
|
bound → active → petitioned → claimed | forfeited
|
|
@@ -21,13 +27,21 @@ bound → active → petitioned → claimed | forfeited
|
|
|
21
27
|
```bash
|
|
22
28
|
keiyaku bind --place fix-pump --objective "make the pump test pass" \
|
|
23
29
|
--scope "src/pump/**" --checks "pump tests green"
|
|
24
|
-
# or the same four fields as Markdown: keiyaku bind < contract.md
|
|
30
|
+
# or the same four fields as Markdown: keiyaku bind - < contract.md
|
|
25
31
|
# (# <name> / ## Objective / ## Scope / ## Checks)
|
|
26
|
-
# or promote
|
|
32
|
+
# or promote one or more ready tasks:
|
|
33
|
+
keiyaku bind --task fix-parser --task fix-parser-help - < contract.md
|
|
34
|
+
|
|
35
|
+
cd .keiyaku/wt/fix-pump # worker edits/tests here and leaves a dirty tree
|
|
27
36
|
|
|
28
|
-
|
|
37
|
+
# Back on the host after reviewing the worker's diff and test report:
|
|
38
|
+
git -C .keiyaku/wt/fix-pump add -- <accepted-paths>
|
|
39
|
+
git -C .keiyaku/wt/fix-pump commit -m "fix pump"
|
|
29
40
|
|
|
30
|
-
|
|
41
|
+
# Rehearse the exact pinned delivery before settlement:
|
|
42
|
+
keiyaku @fix-pump audit
|
|
43
|
+
|
|
44
|
+
keiyaku petition - <<'EOF'
|
|
31
45
|
## Oath
|
|
32
46
|
I made the pump test pass; ran the suite, all green.
|
|
33
47
|
EOF
|
|
@@ -37,21 +51,56 @@ EOF
|
|
|
37
51
|
# The oath is required (OATH_MISSING otherwise) and checked for presence, not content.
|
|
38
52
|
```
|
|
39
53
|
|
|
40
|
-
|
|
54
|
+
A task is optional planning, not a prerequisite. Bind directly for new work;
|
|
55
|
+
use `--task` only when promoting existing tracked planning into this contract.
|
|
56
|
+
|
|
57
|
+
That's the whole small case: bind → worker dirty-tree handoff → host review/commit → petition.
|
|
58
|
+
|
|
59
|
+
Multi-bind tasks only when they are evidence for the same delivery intent, share
|
|
60
|
+
one coherent write surface, and should settle together. This reduces competing
|
|
61
|
+
contracts/worktrees; it does not replace `needs` or contract `--after` ordering.
|
|
62
|
+
|
|
63
|
+
`audit` is read-only and never invokes an Akuma or settles the contract. Exit 0
|
|
64
|
+
means it constructed the report, not that the candidate is acceptable. Use
|
|
65
|
+
`--diff-budget BYTES` for bounded output and `--json` for complete typed facts.
|
|
66
|
+
|
|
67
|
+
Commissioned workers never write Git metadata. The host alone reviews and
|
|
68
|
+
commits accepted bytes before `arc`, `renew`, or `petition`.
|
|
41
69
|
|
|
42
70
|
## Mid-flight commands (use when needed, skip otherwise)
|
|
43
71
|
|
|
44
72
|
```bash
|
|
45
|
-
keiyaku arc < arc.md
|
|
73
|
+
keiyaku arc - < arc.md # optional iteration boundary: seals the current intent, opens
|
|
46
74
|
# the next. Markdown: # <title> / ## Objective / ## Brief.
|
|
47
75
|
# Only needed when one contract has multiple distinct pushes.
|
|
48
76
|
keiyaku renew # main moved under you → rebase onto it. Refuses on conflict
|
|
49
77
|
# instead of guessing; resolve, then renew again.
|
|
50
|
-
keiyaku amend < amendment.md # scope/checks changed → update the paper before the code
|
|
78
|
+
keiyaku amend - < amendment.md # scope/checks changed → update the paper before the code
|
|
79
|
+
# Scope terms can be appended durably during a lifecycle operation:
|
|
80
|
+
keiyaku @fix-pump arc --append-scope "docs/generated/**" - < arc.md
|
|
81
|
+
keiyaku @fix-pump renew --append-scope "docs/generated/**"
|
|
51
82
|
keiyaku log # this contract's history
|
|
52
83
|
```
|
|
53
84
|
|
|
85
|
+
`amend` accepts prose plus an optional ordered scope-pattern delta:
|
|
86
|
+
|
|
87
|
+
````markdown
|
|
88
|
+
Clarify the owned documentation surface.
|
|
89
|
+
|
|
90
|
+
## Scope Append
|
|
91
|
+
```
|
|
92
|
+
docs/**
|
|
93
|
+
!docs/generated/**
|
|
94
|
+
```
|
|
95
|
+
````
|
|
96
|
+
|
|
97
|
+
`Scope Append` appends ordered raw gitignore-subset lines in one column-zero
|
|
98
|
+
backtick fence; `Scope Add` and Markdown bullets are rejected. A later
|
|
99
|
+
`!pattern` can narrow earlier scope. Use `--append-scope PATTERN` when a
|
|
100
|
+
lifecycle operation discovers one durable term.
|
|
101
|
+
|
|
54
102
|
Gotchas:
|
|
103
|
+
- `-C DIR` selects the effective working directory; repository discovery starts there.
|
|
55
104
|
- Base drift blocks petition — if main moved, `renew` first; petition tells you.
|
|
56
105
|
- After an explicit `arc` seals, new loose commits need another `arc` before `renew`/`petition` accept them.
|
|
57
106
|
- Not in the worktree? Address a contract with `--contract ADDR` (place, slug, or full id) or the `keiyaku @addr <verb>` prefix.
|
|
@@ -1,329 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
import { Codex, } from "@openai/codex-sdk";
|
|
3
|
-
import { CODEX_MODEL_REASONING_EFFORT_CONFIG_KEY } from "../../keiyaku.js";
|
|
4
|
-
import { appendDebugBlock, appendDebugLog } from "../../telemetry/debug-log.js";
|
|
5
|
-
import { SUBAGENT_SESSION_VERSION } from "../session.js";
|
|
6
|
-
import { createProjectionDriver } from "../harness/execution-handle.js";
|
|
7
|
-
import { boundActivityExcerpt } from "../harness/activity-values.js";
|
|
8
|
-
import { buildSubagentEnv, emitProviderEvidence, sha256Utf8 } from "../harness/runtime.js";
|
|
9
|
-
import { coerceString } from "../harness/runtime.js";
|
|
10
|
-
import { AGENT_PLAN_ITEM_TEXT_MAX_CHARS, AGENT_PLAN_MAX_ITEMS, AGENT_THOUGHT_TEXT_MAX_CHARS, } from "../harness/events.js";
|
|
11
|
-
import { appendEventType, renderEventTypeSummary } from "./event-type-tail.js";
|
|
12
|
-
/** Identity-only opacity boundary for Codex SDK ThreadOptions modelReasoningEffort. */
|
|
13
|
-
function toCodexSdkModelReasoningEffort(effort) {
|
|
14
|
-
return effort;
|
|
15
|
-
}
|
|
16
|
-
function withCodexSdkModelReasoningEffort(threadOptions) {
|
|
17
|
-
const raw = threadOptions.modelReasoningEffort;
|
|
18
|
-
if (typeof raw !== "string")
|
|
19
|
-
return threadOptions;
|
|
20
|
-
return {
|
|
21
|
-
...threadOptions,
|
|
22
|
-
modelReasoningEffort: toCodexSdkModelReasoningEffort(raw),
|
|
23
|
-
};
|
|
24
|
-
}
|
|
25
|
-
let codexConstructor = Codex;
|
|
26
|
-
function getCodexConstructor(override) {
|
|
27
|
-
if (override)
|
|
28
|
-
return override;
|
|
29
|
-
return codexConstructor;
|
|
30
|
-
}
|
|
31
|
-
/** @deprecated Use CodexSdkOptions.codexConstructor instead. */
|
|
32
|
-
export function setCodexSdkConstructorForTests(constructor) {
|
|
33
|
-
codexConstructor = constructor;
|
|
34
|
-
}
|
|
35
|
-
/** @deprecated Use CodexSdkOptions.codexConstructor instead. */
|
|
36
|
-
export function resetCodexSdkConstructorForTests() {
|
|
37
|
-
codexConstructor = Codex;
|
|
38
|
-
}
|
|
39
|
-
export const codexThreadSchema = z.object({ threadId: z.string().trim().min(1) });
|
|
40
|
-
const CODEX_EVENT_THREAD_STARTED = "thread.started";
|
|
41
|
-
const CODEX_EVENT_TURN_STARTED = "turn.started";
|
|
42
|
-
const CODEX_EVENT_TURN_FAILED = "turn.failed";
|
|
43
|
-
const CODEX_EVENT_ERROR = "error";
|
|
44
|
-
const CODEX_EVENT_ITEM_STARTED = "item.started";
|
|
45
|
-
const CODEX_EVENT_ITEM_COMPLETED = "item.completed";
|
|
46
|
-
const CODEX_EVENT_ITEM_UPDATED = "item.updated";
|
|
47
|
-
const CODEX_EVENT_TURN_COMPLETED = "turn.completed";
|
|
48
|
-
const CODEX_SDK_PROVIDER = "codex-sdk";
|
|
49
|
-
const CODEX_SDK_ACKNOWLEDGED_UNPERSISTED = new Set([CODEX_EVENT_THREAD_STARTED]);
|
|
50
|
-
const CODEX_SDK_MAPPED = new Set([
|
|
51
|
-
CODEX_EVENT_TURN_STARTED,
|
|
52
|
-
CODEX_EVENT_TURN_COMPLETED,
|
|
53
|
-
CODEX_EVENT_TURN_FAILED,
|
|
54
|
-
CODEX_EVENT_ERROR,
|
|
55
|
-
CODEX_EVENT_ITEM_STARTED,
|
|
56
|
-
CODEX_EVENT_ITEM_UPDATED,
|
|
57
|
-
CODEX_EVENT_ITEM_COMPLETED,
|
|
58
|
-
]);
|
|
59
|
-
function codexSdkIngressDisposition(type) {
|
|
60
|
-
if (CODEX_SDK_ACKNOWLEDGED_UNPERSISTED.has(type))
|
|
61
|
-
return "acknowledged-unpersisted";
|
|
62
|
-
if (CODEX_SDK_MAPPED.has(type))
|
|
63
|
-
return "mapped";
|
|
64
|
-
return "unknown";
|
|
65
|
-
}
|
|
66
|
-
function extractAgentMessage(event) {
|
|
67
|
-
if (event.type !== CODEX_EVENT_ITEM_COMPLETED && event.type !== CODEX_EVENT_ITEM_UPDATED) {
|
|
68
|
-
return undefined;
|
|
69
|
-
}
|
|
70
|
-
if (event.item.type !== "agent_message")
|
|
71
|
-
return undefined;
|
|
72
|
-
const text = coerceString(event.item.text);
|
|
73
|
-
if (!text)
|
|
74
|
-
return undefined;
|
|
75
|
-
return { id: event.item.id, text };
|
|
76
|
-
}
|
|
77
|
-
function codexActivityCall(item) {
|
|
78
|
-
switch (item.type) {
|
|
79
|
-
case "command_execution": return { kind: "run", command: item.command };
|
|
80
|
-
case "file_change": return {
|
|
81
|
-
kind: "fileChange",
|
|
82
|
-
changes: item.changes.map((change) => ({ op: change.kind, path: change.path })),
|
|
83
|
-
};
|
|
84
|
-
case "mcp_tool_call": return { kind: "other", display: `${item.server}.${item.tool}` };
|
|
85
|
-
case "web_search": return { kind: "search", query: item.query };
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
function codexMcpResultMessage(item) {
|
|
89
|
-
if (item.error?.message)
|
|
90
|
-
return boundActivityExcerpt(item.error.message);
|
|
91
|
-
const text = item.result?.content.flatMap((block) => (block.type === "text" && typeof block.text === "string" ? [block.text] : [])).join("\n");
|
|
92
|
-
return text ? boundActivityExcerpt(text) : undefined;
|
|
93
|
-
}
|
|
94
|
-
function codexActivityResult(item) {
|
|
95
|
-
switch (item.type) {
|
|
96
|
-
case "command_execution": return {
|
|
97
|
-
status: item.status === "failed" || (item.exit_code !== undefined && item.exit_code !== 0) ? "error" : "ok",
|
|
98
|
-
...(item.aggregated_output ? { message: boundActivityExcerpt(item.aggregated_output) } : {}),
|
|
99
|
-
...(item.exit_code === undefined ? {} : { exitCode: item.exit_code }),
|
|
100
|
-
};
|
|
101
|
-
case "file_change": return { status: item.status === "failed" ? "error" : "ok" };
|
|
102
|
-
case "mcp_tool_call": {
|
|
103
|
-
const message = codexMcpResultMessage(item);
|
|
104
|
-
return { status: item.status === "failed" ? "error" : "ok", ...(message ? { message } : {}) };
|
|
105
|
-
}
|
|
106
|
-
case "web_search": return { status: "ok" };
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
function emitCodexSemanticEvent(builder, event) {
|
|
110
|
-
if (event.type === CODEX_EVENT_TURN_STARTED) {
|
|
111
|
-
builder.emit({ type: "turn", phase: "started" });
|
|
112
|
-
return;
|
|
113
|
-
}
|
|
114
|
-
if (event.type === CODEX_EVENT_TURN_COMPLETED) {
|
|
115
|
-
builder.emit({
|
|
116
|
-
type: "usage",
|
|
117
|
-
inputTokens: event.usage.input_tokens,
|
|
118
|
-
outputTokens: event.usage.output_tokens,
|
|
119
|
-
cachedInputTokens: event.usage.cached_input_tokens,
|
|
120
|
-
});
|
|
121
|
-
builder.emit({ type: "turn", phase: "completed" });
|
|
122
|
-
return;
|
|
123
|
-
}
|
|
124
|
-
if (event.type !== CODEX_EVENT_ITEM_STARTED &&
|
|
125
|
-
event.type !== CODEX_EVENT_ITEM_UPDATED &&
|
|
126
|
-
event.type !== CODEX_EVENT_ITEM_COMPLETED) {
|
|
127
|
-
return;
|
|
128
|
-
}
|
|
129
|
-
if (event.item.type === "reasoning" &&
|
|
130
|
-
(event.type === CODEX_EVENT_ITEM_UPDATED || event.type === CODEX_EVENT_ITEM_COMPLETED)) {
|
|
131
|
-
const truncated = event.item.text.length > AGENT_THOUGHT_TEXT_MAX_CHARS;
|
|
132
|
-
builder.emit({
|
|
133
|
-
type: "thought",
|
|
134
|
-
id: event.item.id,
|
|
135
|
-
text: event.item.text.slice(0, AGENT_THOUGHT_TEXT_MAX_CHARS),
|
|
136
|
-
final: event.type === CODEX_EVENT_ITEM_COMPLETED,
|
|
137
|
-
...(truncated ? { truncated: true } : {}),
|
|
138
|
-
});
|
|
139
|
-
return;
|
|
140
|
-
}
|
|
141
|
-
if (event.item.type === "todo_list") {
|
|
142
|
-
builder.emit({
|
|
143
|
-
type: "plan",
|
|
144
|
-
id: event.item.id,
|
|
145
|
-
items: event.item.items.slice(0, AGENT_PLAN_MAX_ITEMS).map((item) => ({
|
|
146
|
-
text: item.text.slice(0, AGENT_PLAN_ITEM_TEXT_MAX_CHARS),
|
|
147
|
-
done: item.completed,
|
|
148
|
-
})),
|
|
149
|
-
});
|
|
150
|
-
return;
|
|
151
|
-
}
|
|
152
|
-
if (event.item.type !== "command_execution" &&
|
|
153
|
-
event.item.type !== "file_change" &&
|
|
154
|
-
event.item.type !== "mcp_tool_call" &&
|
|
155
|
-
event.item.type !== "web_search") {
|
|
156
|
-
return;
|
|
157
|
-
}
|
|
158
|
-
const phase = event.type === CODEX_EVENT_ITEM_STARTED
|
|
159
|
-
? "started"
|
|
160
|
-
: event.type === CODEX_EVENT_ITEM_UPDATED
|
|
161
|
-
? "updated"
|
|
162
|
-
: "completed";
|
|
163
|
-
builder.emit({
|
|
164
|
-
type: "activity",
|
|
165
|
-
phase,
|
|
166
|
-
id: event.item.id,
|
|
167
|
-
tool: event.item.type,
|
|
168
|
-
call: codexActivityCall(event.item),
|
|
169
|
-
...(phase === "started" ? {} : { result: codexActivityResult(event.item) }),
|
|
170
|
-
});
|
|
171
|
-
}
|
|
172
|
-
/** @deprecated Use the codex-app-server adapter. */
|
|
173
|
-
export async function startCodexSdk(prompt, cwd, options) {
|
|
174
|
-
const threadId = options.threadId?.trim();
|
|
175
|
-
const recordedEventTypes = [];
|
|
176
|
-
let totalEventCount = 0;
|
|
177
|
-
let activeAbort;
|
|
178
|
-
let runReturned = false;
|
|
179
|
-
appendDebugLog(`startCodexSdk: executable=${options.executable ?? "codex"} model=${options.model ?? "default"} ${CODEX_MODEL_REASONING_EFFORT_CONFIG_KEY}=${String(options.config?.[CODEX_MODEL_REASONING_EFFORT_CONFIG_KEY] ?? "default")} mode=${threadId ? "resume" : "fresh"}`, { cwd, section: CODEX_SDK_PROVIDER });
|
|
180
|
-
return createProjectionDriver({
|
|
181
|
-
steerMode: "replay",
|
|
182
|
-
initialTurn: options.initialTurn,
|
|
183
|
-
onIngress: options.onIngress,
|
|
184
|
-
async abort(mode) {
|
|
185
|
-
activeAbort?.abort();
|
|
186
|
-
if (mode === "force" && !runReturned) {
|
|
187
|
-
throw new Error("codex-sdk cannot guarantee forced termination");
|
|
188
|
-
}
|
|
189
|
-
},
|
|
190
|
-
async run(builder) {
|
|
191
|
-
activeAbort = new AbortController();
|
|
192
|
-
const linked = options.signal ?? builder.signal;
|
|
193
|
-
const onOuterAbort = () => activeAbort?.abort();
|
|
194
|
-
linked.addEventListener("abort", onOuterAbort, { once: true });
|
|
195
|
-
if (linked.aborted)
|
|
196
|
-
onOuterAbort();
|
|
197
|
-
builder.signal.addEventListener("abort", onOuterAbort, { once: true });
|
|
198
|
-
try {
|
|
199
|
-
const env = buildSubagentEnv();
|
|
200
|
-
const codexOptions = {
|
|
201
|
-
codexPathOverride: options.executable,
|
|
202
|
-
profile: options.profile,
|
|
203
|
-
config: options.config,
|
|
204
|
-
env,
|
|
205
|
-
};
|
|
206
|
-
const sdk = new (getCodexConstructor(options.codexConstructor))(codexOptions);
|
|
207
|
-
const threadOptions = withCodexSdkModelReasoningEffort(options.threadOptions);
|
|
208
|
-
const thread = threadId ? sdk.resumeThread(threadId, threadOptions) : sdk.startThread(threadOptions);
|
|
209
|
-
const streamed = await thread.runStreamed(prompt, { signal: activeAbort.signal });
|
|
210
|
-
const eventIterator = streamed.events[Symbol.asyncIterator]();
|
|
211
|
-
// The SDK iterable is lazy: its first next() starts the native run.
|
|
212
|
-
// Record outbound bytes immediately before that crossing, then ack only
|
|
213
|
-
// after it settles (including a legitimate no-event completion).
|
|
214
|
-
if (options.onEvidence) {
|
|
215
|
-
emitProviderEvidence(options.onEvidence, {
|
|
216
|
-
type: "outbound",
|
|
217
|
-
provider: CODEX_SDK_PROVIDER,
|
|
218
|
-
direction: "input",
|
|
219
|
-
kind: "replay-prompt",
|
|
220
|
-
...sha256Utf8(prompt),
|
|
221
|
-
}, (text) => builder.emit({ type: "diagnostic", text }));
|
|
222
|
-
}
|
|
223
|
-
const firstEvent = await eventIterator.next();
|
|
224
|
-
if (options.onEvidence) {
|
|
225
|
-
emitProviderEvidence(options.onEvidence, {
|
|
226
|
-
type: "ack",
|
|
227
|
-
provider: CODEX_SDK_PROVIDER,
|
|
228
|
-
fence: { kind: "ordinal", ordinal: 0 },
|
|
229
|
-
outbound: "run",
|
|
230
|
-
}, (text) => builder.emit({ type: "diagnostic", text }));
|
|
231
|
-
}
|
|
232
|
-
const events = async function* () {
|
|
233
|
-
if (!firstEvent.done)
|
|
234
|
-
yield firstEvent.value;
|
|
235
|
-
while (true) {
|
|
236
|
-
const next = await eventIterator.next();
|
|
237
|
-
if (next.done)
|
|
238
|
-
return;
|
|
239
|
-
yield next.value;
|
|
240
|
-
}
|
|
241
|
-
};
|
|
242
|
-
let resumeToken;
|
|
243
|
-
let lastAgentMessage;
|
|
244
|
-
let turnFailedMessage;
|
|
245
|
-
let streamErrorMessage;
|
|
246
|
-
for await (const event of events()) {
|
|
247
|
-
if (activeAbort.signal.aborted) {
|
|
248
|
-
throw Object.assign(new Error(`${CODEX_SDK_PROVIDER} exec cancelled by client`), { name: "AbortError" });
|
|
249
|
-
}
|
|
250
|
-
totalEventCount += 1;
|
|
251
|
-
appendEventType(recordedEventTypes, event.type);
|
|
252
|
-
builder.ingress(CODEX_SDK_PROVIDER, event.type, event, codexSdkIngressDisposition(event.type), () => {
|
|
253
|
-
if (event.type === CODEX_EVENT_THREAD_STARTED) {
|
|
254
|
-
resumeToken = event.thread_id;
|
|
255
|
-
if (options.onEvidence)
|
|
256
|
-
emitProviderEvidence(options.onEvidence, { type: "session", provider: CODEX_SDK_PROVIDER, threadId: resumeToken }, (text) => builder.emit({ type: "diagnostic", text }));
|
|
257
|
-
}
|
|
258
|
-
else if (event.type === CODEX_EVENT_TURN_STARTED && !resumeToken) {
|
|
259
|
-
builder.emit({
|
|
260
|
-
type: "fail",
|
|
261
|
-
message: `${CODEX_SDK_PROVIDER} exec emitted turn.started before thread.started with thread_id`,
|
|
262
|
-
});
|
|
263
|
-
throw new Error(`${CODEX_SDK_PROVIDER} exec emitted turn.started before thread.started with thread_id`);
|
|
264
|
-
}
|
|
265
|
-
else if (event.type === CODEX_EVENT_TURN_FAILED) {
|
|
266
|
-
turnFailedMessage = coerceString(event.error.message) ?? `${CODEX_SDK_PROVIDER} turn failed`;
|
|
267
|
-
}
|
|
268
|
-
else if (event.type === CODEX_EVENT_ERROR) {
|
|
269
|
-
streamErrorMessage = coerceString(event.message) ?? `${CODEX_SDK_PROVIDER} stream error`;
|
|
270
|
-
builder.emit({ type: "diagnostic", text: `${streamErrorMessage}\n` });
|
|
271
|
-
}
|
|
272
|
-
emitCodexSemanticEvent(builder, event);
|
|
273
|
-
const message = extractAgentMessage(event);
|
|
274
|
-
if (message) {
|
|
275
|
-
lastAgentMessage = message.text;
|
|
276
|
-
builder.emit({ type: "message", id: message.id, text: message.text });
|
|
277
|
-
}
|
|
278
|
-
});
|
|
279
|
-
}
|
|
280
|
-
if (turnFailedMessage) {
|
|
281
|
-
builder.emit({ type: "diagnostic", text: turnFailedMessage });
|
|
282
|
-
builder.emit({ type: "fail", message: turnFailedMessage });
|
|
283
|
-
throw new Error(turnFailedMessage);
|
|
284
|
-
}
|
|
285
|
-
if (streamErrorMessage && !lastAgentMessage) {
|
|
286
|
-
builder.emit({ type: "fail", message: streamErrorMessage });
|
|
287
|
-
throw new Error(streamErrorMessage);
|
|
288
|
-
}
|
|
289
|
-
if (!resumeToken) {
|
|
290
|
-
appendDebugLog(`Missing required codex event: ${CODEX_EVENT_THREAD_STARTED} with thread_id.`, {
|
|
291
|
-
cwd,
|
|
292
|
-
section: CODEX_SDK_PROVIDER,
|
|
293
|
-
});
|
|
294
|
-
appendDebugBlock("codex-sdk stdout event types", renderEventTypeSummary(recordedEventTypes, totalEventCount), {
|
|
295
|
-
cwd,
|
|
296
|
-
section: CODEX_SDK_PROVIDER,
|
|
297
|
-
});
|
|
298
|
-
builder.emit({
|
|
299
|
-
type: "fail",
|
|
300
|
-
message: `${CODEX_SDK_PROVIDER} exec succeeded but did not emit a ${CODEX_EVENT_THREAD_STARTED} event with thread_id`,
|
|
301
|
-
});
|
|
302
|
-
throw new Error(`${CODEX_SDK_PROVIDER} exec succeeded but did not emit a ${CODEX_EVENT_THREAD_STARTED} event with thread_id`);
|
|
303
|
-
}
|
|
304
|
-
const finalMessage = lastAgentMessage ?? "";
|
|
305
|
-
const session = {
|
|
306
|
-
provider: "codex-sdk",
|
|
307
|
-
version: SUBAGENT_SESSION_VERSION,
|
|
308
|
-
handle: { threadId: resumeToken },
|
|
309
|
-
};
|
|
310
|
-
if (options.onEvidence)
|
|
311
|
-
emitProviderEvidence(options.onEvidence, { type: "checkpoint", provider: CODEX_SDK_PROVIDER, fence: { kind: "ordinal", ordinal: 1 }, source: "response" }, (text) => builder.emit({ type: "diagnostic", text }));
|
|
312
|
-
builder.emit({
|
|
313
|
-
type: "done",
|
|
314
|
-
finalMessage,
|
|
315
|
-
session,
|
|
316
|
-
});
|
|
317
|
-
return { finalMessage, session };
|
|
318
|
-
}
|
|
319
|
-
catch (error) {
|
|
320
|
-
appendDebugLog(`startCodexSdk error: ${error instanceof Error ? `${error.name}: ${error.message}` : String(error)}`, { cwd, section: CODEX_SDK_PROVIDER });
|
|
321
|
-
throw error;
|
|
322
|
-
}
|
|
323
|
-
finally {
|
|
324
|
-
runReturned = true;
|
|
325
|
-
linked.removeEventListener("abort", onOuterAbort);
|
|
326
|
-
}
|
|
327
|
-
},
|
|
328
|
-
});
|
|
329
|
-
}
|
package/build/core/command-io.js
DELETED
|
@@ -1,174 +0,0 @@
|
|
|
1
|
-
import { ACTOR_IDENTITY } from "../keiyaku.js";
|
|
2
|
-
import { FlowError } from "../flow-error.js";
|
|
3
|
-
import { parseMarkdownListSection, parseMarkdownStructure } from "./markdown/sections.js";
|
|
4
|
-
import { KeiyakuParseError } from "./markdown/types.js";
|
|
5
|
-
import { normalizeSectionTitle } from "./markdown/titles.js";
|
|
6
|
-
import { isBlankScopePatternLine, normalizeScopePattern, ScopePatternError } from "./scope.js";
|
|
7
|
-
function amendScopeHeading(name) {
|
|
8
|
-
return `## Scope ${name[0].toUpperCase()}${name.slice(1)}`;
|
|
9
|
-
}
|
|
10
|
-
function sourceLines(markdown) {
|
|
11
|
-
const lines = [];
|
|
12
|
-
let start = 0;
|
|
13
|
-
while (start < markdown.length) {
|
|
14
|
-
const newline = markdown.indexOf("\n", start);
|
|
15
|
-
const end = newline === -1 ? markdown.length : newline;
|
|
16
|
-
const next = newline === -1 ? markdown.length : newline + 1;
|
|
17
|
-
const raw = markdown.slice(start, end);
|
|
18
|
-
lines.push({ text: raw.endsWith("\r") ? raw.slice(0, -1) : raw, start, end, next });
|
|
19
|
-
start = next;
|
|
20
|
-
}
|
|
21
|
-
return lines;
|
|
22
|
-
}
|
|
23
|
-
function amendHeading(line) {
|
|
24
|
-
const match = line.match(/^ {0,3}(#{1,2})(?!#)[ \t]+(.+)$/);
|
|
25
|
-
if (!match)
|
|
26
|
-
return null;
|
|
27
|
-
const level = match[1].length;
|
|
28
|
-
const title = normalizeSectionTitle(match[2]);
|
|
29
|
-
if (level !== 2)
|
|
30
|
-
return { level };
|
|
31
|
-
if (title === "scope add")
|
|
32
|
-
return { level, name: "add" };
|
|
33
|
-
return { level };
|
|
34
|
-
}
|
|
35
|
-
function amendFence(line) {
|
|
36
|
-
const match = line.match(/^ {0,3}(`{3,}|~{3,})/);
|
|
37
|
-
if (!match)
|
|
38
|
-
return null;
|
|
39
|
-
const marker = match[1];
|
|
40
|
-
return { delimiter: marker[0], length: marker.length };
|
|
41
|
-
}
|
|
42
|
-
function parseAmendScopeSections(markdown) {
|
|
43
|
-
const lines = sourceLines(markdown);
|
|
44
|
-
const sections = {};
|
|
45
|
-
let active;
|
|
46
|
-
let fence;
|
|
47
|
-
let frontMatterEnd = -1;
|
|
48
|
-
if (lines[0]?.text.trim() === "---") {
|
|
49
|
-
for (let index = 1; index < lines.length; index += 1) {
|
|
50
|
-
if (lines[index].text.trim() === "---") {
|
|
51
|
-
frontMatterEnd = index;
|
|
52
|
-
break;
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
const finishActive = (end) => {
|
|
57
|
-
if (!active)
|
|
58
|
-
return;
|
|
59
|
-
sections[active.name] = { ...active, end };
|
|
60
|
-
active = undefined;
|
|
61
|
-
};
|
|
62
|
-
for (let index = 0; index < lines.length; index += 1) {
|
|
63
|
-
const line = lines[index];
|
|
64
|
-
if (index <= frontMatterEnd)
|
|
65
|
-
continue;
|
|
66
|
-
const marker = amendFence(line.text);
|
|
67
|
-
if (fence) {
|
|
68
|
-
if (marker && marker.delimiter === fence.delimiter && marker.length >= fence.length) {
|
|
69
|
-
fence = undefined;
|
|
70
|
-
}
|
|
71
|
-
continue;
|
|
72
|
-
}
|
|
73
|
-
if (marker) {
|
|
74
|
-
fence = marker;
|
|
75
|
-
continue;
|
|
76
|
-
}
|
|
77
|
-
const heading = amendHeading(line.text);
|
|
78
|
-
if (!heading)
|
|
79
|
-
continue;
|
|
80
|
-
finishActive(line.start);
|
|
81
|
-
if (!heading.name)
|
|
82
|
-
continue;
|
|
83
|
-
if (sections[heading.name]) {
|
|
84
|
-
throw new FlowError("INVALID_KEIYAKU_DRAFT", `amend input may contain ${amendScopeHeading(heading.name)} at most once`);
|
|
85
|
-
}
|
|
86
|
-
active = { name: heading.name, start: line.start, contentStart: line.next };
|
|
87
|
-
}
|
|
88
|
-
finishActive(markdown.length);
|
|
89
|
-
let prose = markdown;
|
|
90
|
-
for (const section of Object.values(sections).sort((left, right) => right.start - left.start)) {
|
|
91
|
-
prose = `${prose.slice(0, section.start)}${prose.slice(section.end)}`;
|
|
92
|
-
}
|
|
93
|
-
return { sections, prose };
|
|
94
|
-
}
|
|
95
|
-
function scopePatterns(markdown, section) {
|
|
96
|
-
const patterns = markdown
|
|
97
|
-
.slice(section.contentStart, section.end)
|
|
98
|
-
.split(/\r?\n/)
|
|
99
|
-
.filter((line) => !isBlankScopePatternLine(line))
|
|
100
|
-
.map((pattern) => {
|
|
101
|
-
try {
|
|
102
|
-
// Do not trim() here: gitignore treats trailing `\ ` as a significant space.
|
|
103
|
-
return normalizeScopePattern(pattern);
|
|
104
|
-
}
|
|
105
|
-
catch (error) {
|
|
106
|
-
if (error instanceof ScopePatternError) {
|
|
107
|
-
throw new FlowError("INVALID_KEIYAKU_DRAFT", error.message);
|
|
108
|
-
}
|
|
109
|
-
throw error;
|
|
110
|
-
}
|
|
111
|
-
});
|
|
112
|
-
if (patterns.length === 0) {
|
|
113
|
-
throw new FlowError("INVALID_KEIYAKU_DRAFT", `amend input has an empty ${amendScopeHeading(section.name)} section`);
|
|
114
|
-
}
|
|
115
|
-
return patterns;
|
|
116
|
-
}
|
|
117
|
-
export function buildAmendInput(markdown, cwd, contractId, contractAddressSource) {
|
|
118
|
-
const { sections, prose } = parseAmendScopeSections(markdown);
|
|
119
|
-
const add = sections.add ? scopePatterns(markdown, sections.add) : [];
|
|
120
|
-
if (!prose.trim()) {
|
|
121
|
-
throw new FlowError("EMPTY_PARAM", "amendment cannot be empty");
|
|
122
|
-
}
|
|
123
|
-
return {
|
|
124
|
-
cwd,
|
|
125
|
-
...(contractId ? { contractId } : {}),
|
|
126
|
-
...(contractAddressSource ? { contractAddressSource } : {}),
|
|
127
|
-
amendment: prose,
|
|
128
|
-
...(sections.add ? { scopeDelta: { add } } : {}),
|
|
129
|
-
};
|
|
130
|
-
}
|
|
131
|
-
export function defaultActorClock(nowMs = Date.now()) {
|
|
132
|
-
return { actor: ACTOR_IDENTITY, nowMs };
|
|
133
|
-
}
|
|
134
|
-
export function parseCommandMarkdown(content) {
|
|
135
|
-
try {
|
|
136
|
-
const parsed = parseMarkdownStructure(content);
|
|
137
|
-
const sections = new Map();
|
|
138
|
-
for (const [key, lines] of parsed.sections.entries()) {
|
|
139
|
-
sections.set(key, lines.join("\n").trim());
|
|
140
|
-
}
|
|
141
|
-
return { title: parsed.title, sections };
|
|
142
|
-
}
|
|
143
|
-
catch (error) {
|
|
144
|
-
if (error instanceof KeiyakuParseError) {
|
|
145
|
-
throw new FlowError("INVALID_KEIYAKU_DRAFT", error.message, { cause: error });
|
|
146
|
-
}
|
|
147
|
-
throw error;
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
export function requireMarkdownTextSection(parts, name) {
|
|
151
|
-
const normalized = normalizeSectionTitle(name);
|
|
152
|
-
const value = parts.sections.get(normalized)?.trim();
|
|
153
|
-
if (!value) {
|
|
154
|
-
throw new FlowError("INVALID_KEIYAKU_DRAFT", `missing required section: ## ${name}`);
|
|
155
|
-
}
|
|
156
|
-
return value;
|
|
157
|
-
}
|
|
158
|
-
export function requireMarkdownListSection(parts, name) {
|
|
159
|
-
const text = requireMarkdownTextSection(parts, name);
|
|
160
|
-
const items = parseMarkdownListSection(text)
|
|
161
|
-
.map((item) => item.trim())
|
|
162
|
-
.filter((item) => item.length > 0);
|
|
163
|
-
if (items.length === 0) {
|
|
164
|
-
throw new FlowError("INVALID_KEIYAKU_DRAFT", `missing required section: ## ${name}`);
|
|
165
|
-
}
|
|
166
|
-
return items;
|
|
167
|
-
}
|
|
168
|
-
export function requireMarkdownTitle(parts) {
|
|
169
|
-
const title = parts.title?.trim();
|
|
170
|
-
if (!title) {
|
|
171
|
-
throw new FlowError("INVALID_KEIYAKU_DRAFT", "missing required title: # Title");
|
|
172
|
-
}
|
|
173
|
-
return title;
|
|
174
|
-
}
|