@codetreker/daynight 0.21.11 → 0.22.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/README.md +300 -41
  2. package/config.example.yml +65 -0
  3. package/dist/api/client.d.ts +2 -1
  4. package/dist/api/client.js +7 -1
  5. package/dist/api/client.js.map +1 -1
  6. package/dist/api/parse.d.ts +2 -1
  7. package/dist/api/parse.js +19 -0
  8. package/dist/api/parse.js.map +1 -1
  9. package/dist/api/types.d.ts +11 -3
  10. package/dist/commands/review/config.d.ts +2 -1
  11. package/dist/commands/review/config.js +24 -32
  12. package/dist/commands/review/config.js.map +1 -1
  13. package/dist/commands/review/configuration-guide.js +4 -4
  14. package/dist/commands/review/configuration-guide.js.map +1 -1
  15. package/dist/commands/review/definition.js +1 -1
  16. package/dist/commands/review/definition.js.map +1 -1
  17. package/dist/commands/review/repositories.js +10 -17
  18. package/dist/commands/review/repositories.js.map +1 -1
  19. package/dist/commands/skill/skills/using-daynight/references/handoff.md +3 -3
  20. package/dist/commands/worker/attach.d.ts +3 -0
  21. package/dist/commands/worker/attach.js +53 -0
  22. package/dist/commands/worker/attach.js.map +1 -0
  23. package/dist/commands/worker/config.d.ts +10 -0
  24. package/dist/commands/worker/config.js +36 -8
  25. package/dist/commands/worker/config.js.map +1 -1
  26. package/dist/commands/worker/configuration-guide.d.ts +19 -0
  27. package/dist/commands/worker/configuration-guide.js +86 -0
  28. package/dist/commands/worker/configuration-guide.js.map +1 -0
  29. package/dist/commands/worker/control.d.ts +55 -0
  30. package/dist/commands/worker/control.js +151 -0
  31. package/dist/commands/worker/control.js.map +1 -0
  32. package/dist/commands/worker/coordinator.d.ts +1 -0
  33. package/dist/commands/worker/coordinator.js +53 -13
  34. package/dist/commands/worker/coordinator.js.map +1 -1
  35. package/dist/commands/worker/definition.js +62 -2
  36. package/dist/commands/worker/definition.js.map +1 -1
  37. package/dist/commands/worker/execution.js +90 -27
  38. package/dist/commands/worker/execution.js.map +1 -1
  39. package/dist/commands/worker/herdr/agents.d.ts +1 -0
  40. package/dist/commands/worker/herdr/agents.js +78 -6
  41. package/dist/commands/worker/herdr/agents.js.map +1 -1
  42. package/dist/commands/worker/herdr/codex-input.d.ts +2 -0
  43. package/dist/commands/worker/herdr/codex-input.js +35 -0
  44. package/dist/commands/worker/herdr/codex-input.js.map +1 -0
  45. package/dist/commands/worker/herdr/instance.d.ts +1 -0
  46. package/dist/commands/worker/herdr/instance.js +30 -5
  47. package/dist/commands/worker/herdr/instance.js.map +1 -1
  48. package/dist/commands/worker/index.d.ts +15 -0
  49. package/dist/commands/worker/index.js +59 -1
  50. package/dist/commands/worker/index.js.map +1 -1
  51. package/dist/commands/worker/instance-lock.d.ts +5 -0
  52. package/dist/commands/worker/instance-lock.js +11 -1
  53. package/dist/commands/worker/instance-lock.js.map +1 -1
  54. package/dist/commands/worker/remote.d.ts +6 -1
  55. package/dist/commands/worker/remote.js +12 -0
  56. package/dist/commands/worker/remote.js.map +1 -1
  57. package/dist/commands/worker/repositories.d.ts +23 -0
  58. package/dist/commands/worker/repositories.js +157 -0
  59. package/dist/commands/worker/repositories.js.map +1 -0
  60. package/dist/commands/worker/runtime.d.ts +9 -0
  61. package/dist/commands/worker/runtime.js +173 -7
  62. package/dist/commands/worker/runtime.js.map +1 -1
  63. package/dist/commands/worker/store.d.ts +18 -0
  64. package/dist/commands/worker/store.js +101 -17
  65. package/dist/commands/worker/store.js.map +1 -1
  66. package/dist/config/document.d.ts +1 -1
  67. package/dist/config/document.js +1 -9
  68. package/dist/config/document.js.map +1 -1
  69. package/dist/config/errors.d.ts +2 -2
  70. package/dist/config/errors.js.map +1 -1
  71. package/dist/platform/instance-lock.d.ts +4 -0
  72. package/dist/platform/instance-lock.js +9 -1
  73. package/dist/platform/instance-lock.js.map +1 -1
  74. package/dist/repository/location.d.ts +7 -0
  75. package/dist/repository/location.js +51 -0
  76. package/dist/repository/location.js.map +1 -0
  77. package/package.json +4 -3
package/README.md CHANGED
@@ -22,6 +22,7 @@ GitHub CLI and Copilot CLI on `PATH`.
22
22
  - [Task deletion](#task-deletion)
23
23
  - [Task attachments](#task-attachments)
24
24
  - [Worker configuration and startup](#worker-configuration-and-startup)
25
+ - [Worker manual management](#worker-manual-management)
25
26
  - [Review configuration and startup](#review-configuration-and-startup)
26
27
  - [Review status listing](#review-status-listing)
27
28
  - [Durable review state](#durable-review-state)
@@ -98,6 +99,14 @@ daynight login [--no-browser] # Authorize CLI access through the browser
98
99
  daynight logout # Revoke and remove the current CLI credential
99
100
  daynight worker # Show worker help
100
101
  daynight worker run # Run until interrupted
102
+ daynight worker attach # Open the worker Herdr session
103
+ daynight worker repo list [--json]
104
+ daynight worker repo add [--project <project-id>]
105
+ daynight worker repo remove [--project <project-id>]
106
+ daynight worker retry <task-id> --claim-id <claim-id> [--project <project-id>]
107
+ daynight worker release <task-id> --claim-id <claim-id> --if-version <version> [--project <project-id>]
108
+ daynight worker resume <task-id> --claim-id <previous-claim-id> --if-version <version> [--project <project-id>]
109
+ daynight worker transfer <task-id> --claim-id <claim-id> --if-version <version> [target options] [--project <project-id>]
101
110
  daynight review # Show review help
102
111
  daynight review run
103
112
  daynight review list # Also review ls
@@ -305,6 +314,24 @@ records startup-file ownership and installation limits.
305
314
 
306
315
  ## Configuration setup
307
316
 
317
+ The shared configuration file is `~/.daynight/config.yml`. The complete
318
+ [`config.example.yml`](config.example.yml) covers service access, review and worker
319
+ settings with their defaults and optional overrides. It is included at the root
320
+ of the npm package. For an npm global installation, locate it with:
321
+
322
+ ```bash
323
+ npm root --global
324
+ ```
325
+
326
+ Open `@codetreker/daynight/config.example.yml` beneath that directory. Select the
327
+ sections needed for your commands and replace the example repositories and local
328
+ paths. For a new configuration, save the selected settings to
329
+ `~/.daynight/config.yml`; for an existing file, merge them while preserving its
330
+ credential, generated `workerId` and unrelated settings. The example itself is
331
+ not loaded automatically. Repository paths resolve from the configuration
332
+ directory, with the rules in the [worker](#worker-configuration-and-startup) and
333
+ [review](#review-configuration-and-startup) guides.
334
+
308
335
  Project and task commands use `https://daynight.cc` when the configuration file or
309
336
  `serverUrl` is absent. A production connection needs no server configuration.
310
337
  Run `daynight login` to display an authorization code and open the verification
@@ -337,7 +364,8 @@ commands do not start login, follow redirects with credentials, or automatically
337
364
  repeat a write. Reconcile an unconfirmed business mutation before another one.
338
365
 
339
366
  The first `review run`, `review list` or `review ls` asks for a repository when
340
- the file or `repositories` field is absent. To configure one in advance, run:
367
+ the file, `review` section or `review.repositories` field is absent. To configure
368
+ one in advance, run:
341
369
 
342
370
  ```bash
343
371
  daynight review add-repo https://github.com/OWNER/REPO.git
@@ -769,12 +797,69 @@ integration/history instead of installing or changing global native settings.
769
797
  Git transport and tools used by the task, such as authenticated GitHub CLI for
770
798
  PR delivery, must also be ready.
771
799
 
772
- Run `daynight login` for Daynight authentication. Add the following mapping to
773
- the shared `~/.daynight/config.yml`, preserving existing connection and review
774
- settings:
800
+ Run `daynight login` for Daynight authentication, then select one or more
801
+ existing accessible Projects:
802
+
803
+ ```bash
804
+ daynight worker repo add
805
+ daynight worker repo list
806
+ daynight worker repo remove
807
+ ```
808
+
809
+ Add and remove list remote Projects for multiselection. Each choice includes its
810
+ name, UUID and repository URL. A new registration saves the selected Project ID,
811
+ original server repository URL and an absolute local path. Matching existing
812
+ registrations retain their configured transport URL, path and native settings;
813
+ a remote-only registration gains only its Project ID. Remove changes configuration
814
+ only: clones, claims, worktrees, native history and frozen execution settings
815
+ remain. A running worker reads its next selection at startup, without hot reload.
816
+ For scripts, identify one accessible existing Project explicitly:
817
+
818
+ ```bash
819
+ daynight worker repo add --project PROJECT_UUID
820
+ daynight worker repo remove --project PROJECT_UUID
821
+ daynight worker repo list --json
822
+ ```
823
+
824
+ `list` reads local registrations without remote discovery. Add and remove
825
+ operate on existing accessible remote Projects, not raw Git URLs or new Project
826
+ creation. Cancellation, empty choices, authentication or API failures, invalid
827
+ selections and save failures leave the selection unchanged.
828
+
829
+ An empty repository list makes interactive `worker run` offer the same Project
830
+ selection. Fresh startup saves the selection before creating worker identity,
831
+ SQLite, Git or Herdr resources. A restarted worker with retained state first
832
+ establishes its cleanup controller, so committed cleanup deadlines continue
833
+ while Project lookup or prompting waits. New task resources wait for successful
834
+ selection. Startup checks the service and selected worker settings from one
835
+ captured configuration source; changed service or credentials require restarting
836
+ the worker. Without terminal input and stderr, configure a Project with
837
+ `worker repo add --project PROJECT_UUID` before startup.
838
+
839
+ New paths use `worker.repositoryRoot`, defaulting to `~/daynights`, independently
840
+ of `review.repositoryRoot`. The worker root accepts the current home
841
+ shortcut (`~` or `~/`), absolute paths and paths relative to `config.yml`; Windows
842
+ also accepts `~\`. Registration resolves that root with the actual home and
843
+ saves absolute paths. Ordinary repositories use `<root>/<host>/<owner>/<repo>`;
844
+ generic transport, user, port or nested-path identities retain distinct encoded
845
+ coordinates. Existing Project paths and agent overrides survive repeat add and
846
+ root edits.
847
+
848
+ Network and interaction hold no configuration lock. The atomic writer rereads
849
+ current YAML, preserves comments and unrelated edits, and refuses changed
850
+ worker root, repository selection or service credentials. Save also rejects
851
+ shared YAML aliases that would alter unrelated effective settings; separate the
852
+ worker data from those aliases before retrying. Unaffected aliases remain valid.
853
+ Repository identities, Project IDs and logical or physical paths must remain
854
+ distinct, including the Daynight state directory. These commands do not clone
855
+ repositories, acquire tasks or start Herdr.
856
+
857
+ For explicit repository paths and runtime overrides, retain the shared
858
+ connection and review settings and configure `worker` directly:
775
859
 
776
860
  ```yaml
777
861
  worker:
862
+ repositoryRoot: ~/daynights
778
863
  maxConcurrent: 1
779
864
  pollIntervalMs: 5000
780
865
  recoveryLimit: 3
@@ -791,17 +876,25 @@ worker:
791
876
  args: []
792
877
  ```
793
878
 
794
- These are the defaults for all optional worker fields; `repositories` is
795
- required. Each entry requires `remote` and `path`, with optional `projectId`,
796
- `agent`, `model` and `args`. The service project must already exist and match the
797
- repository. Add `projectId` when more than one project matches. Missing local
798
- repositories are cloned; existing roots and origins are verified without
799
- resetting their files or branches. Use the native authentication configuration
800
- for credentials, keeping credentials out of repository URLs and argument lists.
801
-
802
- Paths are absolute or relative to the configuration file's directory, never
803
- the launch directory. Tilde expansion and drive-relative Windows paths are
804
- rejected. Repository identities, project IDs and paths cannot duplicate or
879
+ These are the defaults for the optional runtime fields. A missing configuration
880
+ file, an omitted `worker` mapping, and `worker: {}` use the same defaults.
881
+ Omitting `repositories` selects an empty acquisition list; worker repositories
882
+ are never inferred from review settings. Configuration reads do not create or
883
+ rewrite configuration files. Explicit `null` in non-nullable fields, malformed
884
+ settings, filesystem errors and cancellation remain errors; `model: null` keeps
885
+ its documented clearing semantics.
886
+
887
+ Each explicit repository entry requires `remote` and `path`, with optional
888
+ `projectId`, `agent`, `model` and `args`. The
889
+ service project must already exist and match the repository. Add `projectId`
890
+ when more than one project matches. Missing local repositories are cloned;
891
+ existing roots and origins are verified without resetting their files or
892
+ branches. Use the native authentication configuration for credentials, keeping
893
+ credentials out of repository URLs and argument lists.
894
+
895
+ Repository entry paths are absolute or relative to the configuration file's
896
+ directory, never the launch directory. They do not expand tilde and reject
897
+ drive-relative Windows paths. Repository identities, project IDs and paths cannot duplicate or
805
898
  overlap, including the fixed Daynight state directory. Unknown worker fields,
806
899
  wrong types, invalid arguments and unsupported path shapes fail visibly.
807
900
  `maxConcurrent` is a positive integer, `recoveryLimit` is nonnegative and
@@ -859,15 +952,45 @@ it is not replayed. A pause still reserves capacity. Recovering missing original
859
952
  configuration, history or stop evidence requires inspection, without creating a
860
953
  replacement conversation to conceal the loss.
861
954
 
862
- For human input, copy the safe `attach` descriptor printed after the running
863
- worker has completed inventory and private managed-instance readiness.
864
- Invoke its `executable` with its `arguments` (`herdr --session w` for the default
865
- executable), apply exactly its `environment` overrides and remove the names in
866
- `unsetEnvironment` **only for that attach client process**. The descriptor's
867
- private XDG values select the worker's exact Herdr instance; the existing task
868
- pane keeps its original native XDG and private HISTFILE. The descriptor contains
869
- routing and native-home paths, not a dump of authentication values. Continue in
870
- the original task pane so the worker can observe the same execution.
955
+ For human input, run this in another interactive terminal:
956
+
957
+ ```bash
958
+ daynight worker attach
959
+ ```
960
+
961
+ The command opens the existing private Herdr session with the correct directory
962
+ and environment. Continue in the original task pane so the worker can observe
963
+ the same execution. Detaching closes only the client connection; the worker,
964
+ original agent and task keep running. This command needs no Daynight login or
965
+ server request and does not take the worker lock. It connects only to an
966
+ existing session; if it is unavailable, start `daynight worker run` first.
967
+ Client startup and nonzero-exit errors remain visible.
968
+
969
+ The worker prints the attach command after inventory and private
970
+ managed-instance readiness. Its attachment descriptor remains the internal
971
+ source of routing, native-home and history settings. Only the client process
972
+ receives those settings and removal of inherited session identities; the
973
+ existing task pane retains its original native XDG and private HISTFILE.
974
+
975
+ Native startup can be waiting at a folder-trust or authorization screen even
976
+ when Herdr reports idle/interactiveReady. The worker checks the current Codex
977
+ input surface before automatic text and Enter, reports a blocking reason and
978
+ keeps the first prompt unsent. It does not choose native trust or change global
979
+ trust configuration. Configure that prerequisite normally in the native tool or
980
+ use the original attached task pane to make the decision explicitly, then leave
981
+ the business composer available for input. This check does not inspect arbitrary
982
+ human draft meaning or prove that a model consumed previously submitted text.
983
+
984
+ The checked Codex startup/restart layout is the standard/default business
985
+ composer together with a loaded model/reasoning and current-directory footer
986
+ (`model-with-reasoning · current-dir`). Ask text or a version header alone is
987
+ insufficient because provisional startup can show them too. A custom footer,
988
+ cropped footer or otherwise unrecognized visible layout remains unknown; the
989
+ original Operation bounds observation and ends not-submitted if that supported
990
+ surface never appears. In the original session, finish any blocking decision
991
+ and restore the supported standard native layout before requesting public retry.
992
+ The worker does not change the layout, infer arbitrary draft meaning or turn
993
+ this screen check into a native consumption receipt.
871
994
 
872
995
  For started executions, a successful complete own-claim inventory from the
873
996
  original account makes the original claim's absence cause
@@ -915,13 +1038,143 @@ shutdown initialization is isolated so one bad record does not prevent known
915
1038
  agents stopping. Untracked resources or unknown scope keep the private instance
916
1039
  when its stop cannot be confirmed.
917
1040
 
918
- Public worker release/transfer/resume/retry commands and the service's terminal
919
- management-protocol revision remain pending. Linux, Windows and macOS complete
920
- Goal acceptance is separate from the installed runtime and its component
921
- checks. The [worker requirements](../../docs/spec/daynight-worker.md) and
1041
+ Linux, Windows and macOS complete Goal acceptance is separate from the installed
1042
+ runtime and its component checks. The
1043
+ [worker requirements](../../docs/spec/daynight-worker.md) and
922
1044
  [worker design](../../docs/design/daynight-worker.md) own the behavior and
923
1045
  mechanisms, including native capability limits.
924
1046
 
1047
+ ## Worker manual management
1048
+
1049
+ Manual commands select one task and its exact original claim. They use the same
1050
+ fixed SQLite and singleton lock as `worker run`. With a foreground worker, that
1051
+ process remains the sole agent controller and consumes the persisted decision;
1052
+ without one, the command acquires the same lock and advances the same coordinator
1053
+ for that execution. There is no separate control service. Current configuration
1054
+ and Daynight authentication are required, and the original service origin must
1055
+ match. Release, transfer and retry require the unfinished original local record;
1056
+ resume can use an explicit project with its configured repository.
1057
+
1058
+ Read the current task before deciding a versioned operation:
1059
+
1060
+ ```bash
1061
+ daynight task show <task-id> --json
1062
+ daynight worker release <task-id> --claim-id <source-claim-id> --if-version <version>
1063
+ ```
1064
+
1065
+ Release and transfer first verify project access and source owner/admin
1066
+ permission, then persist the concrete source decision before cleanup. The
1067
+ controller requests the original agent's attributable temporary-resource cleanup,
1068
+ waits for its original deadline of at most 10 minutes, confirms that agent stopped,
1069
+ closes its task workspace and deletes its worktree. Only then can it submit the
1070
+ remote write at the exact supplied version. Other tasks keep their shared Herdr
1071
+ instance. Failed stopping or deletion retains the source responsibility and a
1072
+ visible error. Cleanup keeps its original deadline after restart; each HTTP
1073
+ request has an independent bounded scope, without a five-minute total command
1074
+ limit.
1075
+
1076
+ Release returns the task to `todo` and clears its execution interval. The daemon
1077
+ skips released tasks until explicitly resumed. Resume starts a fresh execution
1078
+ on this worker:
1079
+
1080
+ ```bash
1081
+ daynight worker resume <task-id> --claim-id <released-claim-id> --if-version <version> \
1082
+ --project <project-id>
1083
+ ```
1084
+
1085
+ The previous claim must still be released and the task ready. The original owner
1086
+ or a current project admin may resume it, retaining the explicit manual exception
1087
+ to automatic permission and platform filters. The new claim and worktree IDs are
1088
+ generated and persisted before submission. Its actual grant commits local
1089
+ `pending` with this repository's current effective agent/model/args; `worker run`
1090
+ then performs ordinary capacity checks and prepares a fresh native conversation.
1091
+ The deleted source worktree and native history are not required. Run
1092
+ `daynight worker run` if the foreground worker is stopped.
1093
+
1094
+ Transfer explicitly identifies the target's current user, stable worker and
1095
+ machine descriptor, actual platform and selected agent:
1096
+
1097
+ ```bash
1098
+ daynight worker transfer <task-id> --claim-id <source-claim-id> --if-version <version> \
1099
+ --target-user-id <user-id> --target-worker-id <worker-id> \
1100
+ --target-machine-id <machine-id> --target-machine-name "target-machine" \
1101
+ --target-platform linux --target-agent codex
1102
+ ```
1103
+
1104
+ Use the intended receiver's actual descriptor and the explicitly selected new
1105
+ agent type. A trace-free new transfer grant honors that agent even when the
1106
+ receiver's current repository defaults select the other type. It freezes
1107
+ `model: null` and `args: []` for that type, with the current recovery limit; a
1108
+ matching type uses the current effective model/args. Existing pending snapshots
1109
+ are retained. The source operator's owner/admin permission is checked separately
1110
+ from the target's
1111
+ current membership. Transfer still requires automatic execution permission,
1112
+ platform compatibility and completed dependencies. It preserves `in_progress`
1113
+ and the task's execution interval, installing a fresh target claim/worktree ID
1114
+ with empty runtime associations. The receiver discovers its actual grant through
1115
+ normal claim inventory and starts a new execution; an old task path still in use
1116
+ blocks preparation. No source files, SQLite snapshots or native history are
1117
+ transported. Target and source agents may differ. Public commands provide no
1118
+ claim/worktree-ID override or continuity confirmation option; the service and
1119
+ typed client reject deprecated `continuityConfirmed` input.
1120
+
1121
+ For a paused execution that still belongs to the original owner, authorize one
1122
+ extra recovery attempt:
1123
+
1124
+ ```bash
1125
+ daynight worker retry <task-id> --claim-id <claim-id>
1126
+ ```
1127
+
1128
+ Retry preserves the original claim, worktree/native identity and frozen
1129
+ settings, retaining the cumulative recovery count rather than resetting it.
1130
+ Concurrent or repeated requests do not accumulate extra authorization or launch
1131
+ a second agent. The controller consumes the single permit for that original
1132
+ execution; a further failure remains visible. Retry cannot replace terminal
1133
+ cleanup or recreate an execution that has ended.
1134
+
1135
+ A native launch acknowledged before a blocking startup screen has a specific
1136
+ continuation path when its first prompt is durably known unsent. Keep the
1137
+ original worker/native session running and use another terminal to attach to
1138
+ that original pane. Inspect the reported folder-trust/authorization requirement
1139
+ and make the native decision yourself. Once the business composer is available,
1140
+ run:
1141
+
1142
+ ```bash
1143
+ daynight worker retry <task-id> --claim-id <original-claim-id> --project <project-id>
1144
+ ```
1145
+
1146
+ The controller first checks the original worktree, full binding, frozen argv,
1147
+ workspace/launch evidence, same shell and every saved native key PID. Ordinary
1148
+ child-process changes do not replace the original proof. After that read-only
1149
+ identity check, it consumes one authorized recovery attempt (the cumulative
1150
+ count increases by one, without reset) and can deliver the first prompt once in
1151
+ the original native process without another agent.start or conversation. Missing
1152
+ an official native ID before the first turn does not by itself block this
1153
+ proven-unsent continuation. This is not permission to resend an earlier
1154
+ submitted/unknown prompt, infer loss from an empty-looking composer or restart
1155
+ an unproven missing-ID conversation. Legacy records with unknown native-process
1156
+ role remain fenced; migration does not construct identity from foreground PID
1157
+ order. Automated cleanup text and /exit use the same screen boundary; a blocking
1158
+ screen is not accepted with Enter merely to finish shutdown.
1159
+
1160
+ Management diagnostics identify the original claim and report persisted waiting,
1161
+ completion, rejection or unknown results. Interrupting the command retains its
1162
+ intent so the foreground controller or a later management invocation can
1163
+ continue. An unknown release/transfer write is reconciled by reading the actual
1164
+ task and saved target claim; it is never resent or assigned replacement IDs,
1165
+ even when a read still shows the old value. Reinvoking that same decision can
1166
+ reconcile its result by targeted reads, including beside a running foreground
1167
+ worker, without taking over resource control or resubmitting. An already-cleaned
1168
+ source is not restarted. Only a definitely rejected submission can be replaced by a new explicit
1169
+ decision, with the supplied `--if-version` matching a fresh task observation. The
1170
+ numeric version may remain the same when the refusal did not change the task,
1171
+ including a definite pre-dispatch failure or permission refusal. An unknown
1172
+ submission cannot be reset or replayed; `--if-version` is never silently replaced.
1173
+ Unknown resume requests likewise retain their original claim/worktree/config
1174
+ until the actual grant can be confirmed. These targeted reads reconcile manual
1175
+ writes; automatic cleanup still relies only on a complete successful inventory
1176
+ for the original authenticated user and worker.
1177
+
925
1178
  ## Review configuration and startup
926
1179
 
927
1180
  Register a repository explicitly, or let the first review operation guide registration:
@@ -940,23 +1193,29 @@ cloning, authentication checks, GitHub calls, SQLite initialization and PR bound
940
1193
  selection belong to review startup. An already running reviewer keeps its loaded
941
1194
  configuration until its next startup.
942
1195
 
943
- The same YAML also accepts the server client's `serverUrl` and optional
944
- `serverToken` fields. Review validates its own fields independently of server
945
- business values. The server projection requires a valid HTTP(S) origin and
1196
+ All review settings belong under the `review` mapping. The same YAML also
1197
+ accepts the server client's `serverUrl` and optional `serverToken` fields, the
1198
+ `worker` mapping and generated `workerId`. Review validates its own fields
1199
+ independently of server business values. The server projection requires a valid HTTP(S) origin and
946
1200
  validates any configured token and its transport. The shared parser still rejects
947
1201
  invalid YAML, duplicate keys and unknown root fields. Registration can add the
948
1202
  first review repository to a server-only file while preserving its server
949
- settings and comments.
1203
+ settings and comments. Unknown fields inside `review` are rejected by review
1204
+ commands. Existing flat review settings must be moved together under `review`,
1205
+ including `repositoryRoot`, `repositories`, numeric options and Copilot options;
1206
+ remove their old root entries. The old root fields are rejected, with no automatic
1207
+ migration.
950
1208
 
951
1209
  A configuration with an explicit addition root is:
952
1210
 
953
1211
  ```yaml
954
- repositoryRoot: ~/daynights
955
- copilotModel: auto
956
- copilotReasoningEffort: high
957
- repositories:
958
- - remote: https://github.com/OWNER/REPO.git
959
- path: ../daynights/github.com/owner/repo
1212
+ review:
1213
+ repositoryRoot: ~/daynights
1214
+ copilotModel: auto
1215
+ copilotReasoningEffort: high
1216
+ repositories:
1217
+ - remote: https://github.com/OWNER/REPO.git
1218
+ path: ../daynights/github.com/owner/repo
960
1219
  ```
961
1220
 
962
1221
  `copilotModel` and `copilotReasoningEffort` are independent optional fields for
@@ -968,11 +1227,11 @@ effort levels and model/effort compatibility; Daynight maintains no static lists
968
1227
  corresponding override and preserves Copilot's choice, so neither, either or both
969
1228
  may be configured. Changes take effect on the next `review run` startup. Guided configuration
970
1229
  and repository registration preserve both fields and YAML comments. The server
971
- configuration projection recognizes these shared keys without validating their
1230
+ configuration projection recognizes the `review` section without validating its
972
1231
  review-owned values.
973
1232
 
974
- `repositoryRoot` defaults to `~/daynights`. It is used only when `add-repo` has no
975
- `--path`: the command derives filesystem-safe components from the normalized
1233
+ `review.repositoryRoot` defaults to `~/daynights`. It is used only when
1234
+ `add-repo` has no `--path`: the command derives filesystem-safe components from the normalized
976
1235
  host/owner/name and saves the resulting absolute repository path. A configured
977
1236
  root may be absolute, config-directory-relative, or begin with `~` for the current
978
1237
  OS user's home. Other users' tilde forms are rejected. Changing the root affects
@@ -0,0 +1,65 @@
1
+ # Shared CLI configuration: ~/.daynight/config.yml.
2
+ # Select the sections needed for your commands and replace the example repositories
3
+ # and local paths. Merge settings into an existing file to retain credentials and
4
+ # other configuration; this file is a reference, not an automatically loaded config.
5
+
6
+ # Service origin only: no API path, query, credentials or fragment.
7
+ serverUrl: https://daynight.cc
8
+ # Prefer daynight login, which saves the credential for the selected service.
9
+ # For unattended provisioning, replace this placeholder with that origin's secret.
10
+ # serverToken: REPLACE_WITH_CREDENTIAL_FOR_THIS_ORIGIN
11
+ # Remove or replace an old token before changing serverUrl manually. Keep secrets
12
+ # out of repositories and logs; files containing a token need POSIX mode 0600.
13
+
14
+ # Review configuration. The numeric values below are the defaults; all are positive
15
+ # integers, and fields ending in Ms use milliseconds.
16
+ # Only repositoryRoot expands ~. It selects paths for future review add-repo calls
17
+ # without --path and does not relocate repositories already registered below.
18
+ review:
19
+ repositoryRoot: ~/daynights
20
+ pollIntervalMs: 60000
21
+ maxConcurrentWorker: 1
22
+ agentTimeoutMs: 1800000
23
+ maxAttempts: 3
24
+ retryDelayMs: 30000
25
+ # Optional review overrides, not defaults. Omission preserves Copilot's choices.
26
+ # Copilot owns supported model names, effort levels and their compatibility.
27
+ # copilotModel: auto
28
+ # copilotReasoningEffort: high
29
+ repositories:
30
+ - remote: https://github.com/OWNER/REPO.git
31
+ # Repository paths are absolute or relative to ~/.daynight/, never the launch
32
+ # directory, and do not expand ~. Keep review clones outside ~/.daynight/.
33
+ path: ../daynights/github.com/owner/repo
34
+
35
+ # Worker configuration. Omitted values use these defaults; an empty selection
36
+ # makes interactive worker run guide Project registration. The selected native
37
+ # agent and Herdr must already be configured.
38
+ worker:
39
+ # Used only for new worker repo registrations; independent of review's root.
40
+ repositoryRoot: ~/daynights
41
+ maxConcurrent: 1
42
+ pollIntervalMs: 5000
43
+ recoveryLimit: 3
44
+ agent: copilot
45
+ model: null
46
+ args: []
47
+ # maxConcurrent and pollIntervalMs are positive integers; pollIntervalMs uses
48
+ # milliseconds. recoveryLimit is nonnegative and applies to the whole worker.
49
+ repositories:
50
+ - remote: https://github.com/OWNER/REPO.git
51
+ # Paths follow the same config-directory-relative rule as review paths.
52
+ # Worker repository paths must not overlap each other or ~/.daynight/.
53
+ path: ../code/repo
54
+ # The matching Daynight project must exist. Set its actual UUID when remote
55
+ # discovery matches more than one project.
56
+ # projectId: REPLACE_WITH_MATCHING_PROJECT_UUID
57
+ # Repository overrides inherit fields independently for the same agent.
58
+ # Switching agent clears inherited model and args unless set here. Explicit
59
+ # null model or [] args clears that field; args replaces the entire list.
60
+ # agent: codex
61
+ # model: null
62
+ # args: []
63
+
64
+ # workerId is generated and saved by the CLI. Keep its existing value for this
65
+ # worker; do not copy another machine's identity into this configuration.
@@ -1,5 +1,5 @@
1
1
  import type { Operation } from "./operation.js";
2
- import type { AttachmentConsumer, CreateProjectInput, CreateTaskInput, DeleteTaskInput, ErrorDetails, Project, PutTaskAttachmentInput, ReadyTaskFilters, ServerError, Task, SetTaskStatusInput, TaskAttachment, TaskFilters, TaskGraph, UpdateTaskInput, ClaimWorkerTaskInput, CompleteWorkerTaskInput, ReleaseWorkerClaimInput, ResumeWorkerTaskInput, TransferWorkerClaimInput, UpdateWorkerClaimInput, User, Page, TaskPageQuery } from "./types.js";
2
+ import type { AttachmentConsumer, CreateProjectInput, CreateTaskInput, DeleteTaskInput, ErrorDetails, Project, ProjectMember, PutTaskAttachmentInput, ReadyTaskFilters, ServerError, Task, SetTaskStatusInput, TaskAttachment, TaskFilters, TaskGraph, UpdateTaskInput, ClaimWorkerTaskInput, CompleteWorkerTaskInput, ReleaseWorkerClaimInput, ResumeWorkerTaskInput, TransferWorkerClaimInput, UpdateWorkerClaimInput, User, Page, TaskPageQuery } from "./types.js";
3
3
  type Context = {
4
4
  readonly operation: string;
5
5
  readonly projectId?: string;
@@ -30,6 +30,7 @@ export type ApiClient = {
30
30
  createProject(input: CreateProjectInput): Promise<Project>;
31
31
  getProject(projectId: string): Promise<Project>;
32
32
  listProjects(): Promise<readonly Project[]>;
33
+ listProjectMembers(projectId: string): Promise<readonly ProjectMember[]>;
33
34
  createTask(projectId: string, input: CreateTaskInput): Promise<Task>;
34
35
  getTask(projectId: string, taskId: string): Promise<Task>;
35
36
  listTasks(projectId: string, filters?: TaskFilters): Promise<readonly Task[]>;
@@ -2,7 +2,7 @@ import { performance } from "node:perf_hooks";
2
2
  import { parseApiJson, stringifyApiJson } from "./json.js";
3
3
  import { OperationError } from "./operation.js";
4
4
  import { validateServerToken, validateTokenTransport } from "../config/server-token.js";
5
- import { canonicalId, parsePage, parseProject, parseServerError, parseTask, parseTaskGraph, parseTaskAttachment, parseUser, ProtocolError, validateAttachmentPath } from "./parse.js";
5
+ import { canonicalId, parsePage, parseProject, parseProjectMembers, parseServerError, parseTask, parseTaskGraph, parseTaskAttachment, parseUser, ProtocolError, validateAttachmentPath } from "./parse.js";
6
6
  export class ApiError extends Error {
7
7
  operation;
8
8
  phase;
@@ -354,6 +354,8 @@ export const createApiClient = (options) => {
354
354
  const herdrMatches = (actual, expected) => actual === null || expected === null ? actual === expected : actual.session === expected.session && actual.workspaceId === expected.workspaceId && actual.paneId === expected.paneId;
355
355
  const descriptorMatches = (worker, descriptor) => worker.claimId === canonicalId(descriptor.claimId) && worker.workerId === canonicalId(descriptor.workerId) && worker.machine.id === canonicalId(descriptor.machine.id) && worker.machine.name === descriptor.machine.name && worker.platform === descriptor.platform && worker.agent === descriptor.agent && worker.worktreeId === canonicalId(descriptor.worktreeId);
356
356
  const workerMutation = (projectId, taskId, action, suffix, method, input, matches, sameValue = false) => {
357
+ if (Object.hasOwn(input, "continuityConfirmed"))
358
+ throw new Error("continuityConfirmed is no longer accepted. New executions require fresh claim and worktree IDs.");
357
359
  const project = resourceId(projectId), task = resourceId(taskId);
358
360
  taskVersion(input.version);
359
361
  return exchange({ operation: action, projectId: project, taskId: task }, `/projects/${encodeURIComponent(project)}/tasks/${encodeURIComponent(task)}${suffix}`, method, { kind: "json", parse: (value) => {
@@ -372,6 +374,10 @@ export const createApiClient = (options) => {
372
374
  return request({ operation: "project.show", projectId: project }, `/projects/${encodeURIComponent(project)}`, "GET", (value) => parseProject(value, project));
373
375
  },
374
376
  listProjects: () => list({ operation: "project.list" }, "/projects", (value) => parseProject(value), (project) => project.id),
377
+ listProjectMembers: (projectId) => {
378
+ const project = resourceId(projectId);
379
+ return exchange({ operation: "project.members", projectId: project }, `/projects/${encodeURIComponent(project)}/members`, "GET", { kind: "json", parse: (value) => parseProjectMembers(value, project) }, [200], undefined, true);
380
+ },
375
381
  createTask: (projectId, input) => {
376
382
  const project = resourceId(projectId);
377
383
  writableProperties(input.properties);