kiokuko-dsh 0.2.34 → 0.2.37

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 (172) hide show
  1. package/PERMISSIONS.md +22 -7
  2. package/README.ja.md +56 -23
  3. package/README.ko.md +55 -24
  4. package/README.md +54 -23
  5. package/README.zh-CN.md +55 -24
  6. package/dist/deep-thinker/abortable-stream.d.ts.map +1 -1
  7. package/dist/deep-thinker/abortable-stream.js +2 -0
  8. package/dist/deep-thinker/abortable-stream.js.map +1 -1
  9. package/dist/deep-thinker/core/contracts.d.ts +5 -5
  10. package/dist/deep-thinker/memory-finalizer.d.ts +1 -1
  11. package/dist/deep-thinker/store.d.ts +1 -1
  12. package/dist/dsh/agenticreplay-security.d.ts +1 -0
  13. package/dist/dsh/agenticreplay-security.d.ts.map +1 -1
  14. package/dist/dsh/agenticreplay-security.js +1 -1
  15. package/dist/dsh/agenticreplay-security.js.map +1 -1
  16. package/dist/dsh/auxiliary-recovery.d.ts +68 -0
  17. package/dist/dsh/auxiliary-recovery.d.ts.map +1 -0
  18. package/dist/dsh/auxiliary-recovery.js +218 -0
  19. package/dist/dsh/auxiliary-recovery.js.map +1 -0
  20. package/dist/dsh/boundary-worker.js +1 -0
  21. package/dist/dsh/boundary-worker.js.map +1 -1
  22. package/dist/dsh/coding-workflow/intent.d.ts.map +1 -1
  23. package/dist/dsh/coding-workflow/intent.js +2 -0
  24. package/dist/dsh/coding-workflow/intent.js.map +1 -1
  25. package/dist/dsh/config.d.ts +16 -2
  26. package/dist/dsh/config.d.ts.map +1 -1
  27. package/dist/dsh/core/host.d.ts +14 -0
  28. package/dist/dsh/core/host.d.ts.map +1 -1
  29. package/dist/dsh/core/host.js +20 -6
  30. package/dist/dsh/core/host.js.map +1 -1
  31. package/dist/dsh/core/index.d.ts +56 -2
  32. package/dist/dsh/core/index.d.ts.map +1 -1
  33. package/dist/dsh/core/tasks.d.ts +4 -0
  34. package/dist/dsh/core/tasks.d.ts.map +1 -1
  35. package/dist/dsh/core/tasks.js +9 -0
  36. package/dist/dsh/core/tasks.js.map +1 -1
  37. package/dist/dsh/core-runtime.d.ts +2 -0
  38. package/dist/dsh/core-runtime.d.ts.map +1 -1
  39. package/dist/dsh/core-runtime.js +4 -0
  40. package/dist/dsh/core-runtime.js.map +1 -1
  41. package/dist/dsh/decisions/config.d.ts +29 -0
  42. package/dist/dsh/decisions/config.d.ts.map +1 -1
  43. package/dist/dsh/decisions/config.js +13 -2
  44. package/dist/dsh/decisions/config.js.map +1 -1
  45. package/dist/dsh/decisions/diagnostics.d.ts +30 -8
  46. package/dist/dsh/decisions/diagnostics.d.ts.map +1 -1
  47. package/dist/dsh/decisions/diagnostics.js +2 -1
  48. package/dist/dsh/decisions/diagnostics.js.map +1 -1
  49. package/dist/dsh/decisions/host.d.ts.map +1 -1
  50. package/dist/dsh/decisions/host.js +25 -6
  51. package/dist/dsh/decisions/host.js.map +1 -1
  52. package/dist/dsh/decisions/intent-assessment.d.ts +3 -1
  53. package/dist/dsh/decisions/intent-assessment.d.ts.map +1 -1
  54. package/dist/dsh/decisions/intent-assessment.js +1 -1
  55. package/dist/dsh/decisions/intent-assessment.js.map +1 -1
  56. package/dist/dsh/decisions/openai.d.ts +27 -0
  57. package/dist/dsh/decisions/openai.d.ts.map +1 -0
  58. package/dist/dsh/decisions/openai.js +107 -0
  59. package/dist/dsh/decisions/openai.js.map +1 -0
  60. package/dist/dsh/decisions/providers.d.ts +10 -1
  61. package/dist/dsh/decisions/providers.d.ts.map +1 -1
  62. package/dist/dsh/decisions/providers.js +2 -2
  63. package/dist/dsh/decisions/providers.js.map +1 -1
  64. package/dist/dsh/decisions/request-intent.d.ts +1 -1
  65. package/dist/dsh/decisions/service.d.ts +12 -1
  66. package/dist/dsh/decisions/service.d.ts.map +1 -1
  67. package/dist/dsh/decisions/service.js +63 -14
  68. package/dist/dsh/decisions/service.js.map +1 -1
  69. package/dist/dsh/execution-selection.d.ts +5 -5
  70. package/dist/dsh/host-adapter/routing.d.ts.map +1 -1
  71. package/dist/dsh/host-adapter/routing.js +8 -3
  72. package/dist/dsh/host-adapter/routing.js.map +1 -1
  73. package/dist/dsh/host-adapter/session-access.d.ts +2 -0
  74. package/dist/dsh/host-adapter/session-access.d.ts.map +1 -1
  75. package/dist/dsh/host-adapter/session-access.js +2 -0
  76. package/dist/dsh/host-adapter/session-access.js.map +1 -1
  77. package/dist/dsh/host-adapter.d.ts.map +1 -1
  78. package/dist/dsh/host-adapter.js +11 -3
  79. package/dist/dsh/host-adapter.js.map +1 -1
  80. package/dist/dsh/index.d.ts +32 -6
  81. package/dist/dsh/index.d.ts.map +1 -1
  82. package/dist/dsh/lisp/code-intelligence-contracts.js +2 -2
  83. package/dist/dsh/lisp/coding-choice.d.ts +7 -0
  84. package/dist/dsh/lisp/coding-choice.d.ts.map +1 -1
  85. package/dist/dsh/lisp/coding-choice.js +2 -0
  86. package/dist/dsh/lisp/coding-choice.js.map +1 -1
  87. package/dist/dsh/lisp/coding-preparation.d.ts +6 -1
  88. package/dist/dsh/lisp/coding-preparation.d.ts.map +1 -1
  89. package/dist/dsh/lisp/coding-preparation.js +40 -3
  90. package/dist/dsh/lisp/coding-preparation.js.map +1 -1
  91. package/dist/dsh/lisp/manager.d.ts +2 -0
  92. package/dist/dsh/lisp/manager.d.ts.map +1 -1
  93. package/dist/dsh/lisp/manager.js +74 -14
  94. package/dist/dsh/lisp/manager.js.map +1 -1
  95. package/dist/dsh/lisp/store.d.ts.map +1 -1
  96. package/dist/dsh/lisp/store.js +6 -10
  97. package/dist/dsh/lisp/store.js.map +1 -1
  98. package/dist/dsh/lisp/surface.d.ts.map +1 -1
  99. package/dist/dsh/lisp/surface.js +3 -2
  100. package/dist/dsh/lisp/surface.js.map +1 -1
  101. package/dist/dsh/lisp/worker.d.ts +4 -1
  102. package/dist/dsh/lisp/worker.d.ts.map +1 -1
  103. package/dist/dsh/lisp/worker.js +56 -6
  104. package/dist/dsh/lisp/worker.js.map +1 -1
  105. package/dist/dsh/lisp-config.js +1 -1
  106. package/dist/dsh/lisp-config.js.map +1 -1
  107. package/dist/dsh/managed-file-deployment.d.ts.map +1 -1
  108. package/dist/dsh/managed-file-deployment.js +3 -1
  109. package/dist/dsh/managed-file-deployment.js.map +1 -1
  110. package/dist/dsh/model-auto/coordinator.js +1 -1
  111. package/dist/dsh/model-auto/coordinator.js.map +1 -1
  112. package/dist/dsh/model-configuration.d.ts +6 -6
  113. package/dist/dsh/modules/enno.d.ts +1 -1
  114. package/dist/dsh/on-demand-intake.d.ts +15 -2
  115. package/dist/dsh/on-demand-intake.d.ts.map +1 -1
  116. package/dist/dsh/on-demand-intake.js +130 -9
  117. package/dist/dsh/on-demand-intake.js.map +1 -1
  118. package/dist/dsh/session-export-analysis.d.ts +20 -0
  119. package/dist/dsh/session-export-analysis.d.ts.map +1 -0
  120. package/dist/dsh/session-export-analysis.js +90 -0
  121. package/dist/dsh/session-export-analysis.js.map +1 -0
  122. package/dist/dsh/session-log-export.d.ts +1 -0
  123. package/dist/dsh/session-log-export.d.ts.map +1 -1
  124. package/dist/dsh/session-log-export.js +19 -3
  125. package/dist/dsh/session-log-export.js.map +1 -1
  126. package/dist/dsh/session-log-mirror.d.ts +1 -1
  127. package/dist/dsh/session-log-mirror.d.ts.map +1 -1
  128. package/dist/dsh/session-log-mirror.js +5 -2
  129. package/dist/dsh/session-log-mirror.js.map +1 -1
  130. package/dist/dsh/setup.d.ts +22 -0
  131. package/dist/dsh/setup.d.ts.map +1 -1
  132. package/dist/dsh/setup.js +50 -4
  133. package/dist/dsh/setup.js.map +1 -1
  134. package/dist/dsh/skill-prompts.json +1 -1
  135. package/dist/dsh/standard-skill-deployment.d.ts +12 -1
  136. package/dist/dsh/standard-skill-deployment.d.ts.map +1 -1
  137. package/dist/dsh/standard-skill-deployment.js +76 -4
  138. package/dist/dsh/standard-skill-deployment.js.map +1 -1
  139. package/dist/dsh/task-startup.d.ts +24 -0
  140. package/dist/dsh/task-startup.d.ts.map +1 -0
  141. package/dist/dsh/task-startup.js +126 -0
  142. package/dist/dsh/task-startup.js.map +1 -0
  143. package/dist/dsh/tool-exposure-config.d.ts +1 -1
  144. package/dist/locale/en.json +1 -1
  145. package/dist/locale/ja.json +1 -1
  146. package/dist/locale/ko.json +1 -1
  147. package/dist/locale/zh-CN.json +1 -1
  148. package/dist/memory/lifecycle.d.ts +1 -1
  149. package/docs/README.ja.md +1 -0
  150. package/docs/README.md +1 -0
  151. package/docs/dsh-plugin.md +42 -14
  152. package/docs/getting-started.ja.md +2 -0
  153. package/docs/getting-started.md +2 -0
  154. package/docs/lisp-hot-tools.md +7 -4
  155. package/docs/lisp.md +19 -5
  156. package/docs/model-selection.ja.md +2 -2
  157. package/docs/model-selection.md +2 -2
  158. package/docs/store-evidence.md +6 -0
  159. package/docs/typed-decisions.md +103 -2
  160. package/docs/typesafe.md +8 -3
  161. package/docs/verification.md +28 -3
  162. package/lisp/process-identity.d.mts +2 -0
  163. package/lisp/process-identity.mjs +34 -0
  164. package/lisp/repository-owner.d.mts +1 -0
  165. package/lisp/repository-owner.mjs +58 -0
  166. package/lisp/supervisor.mjs +19 -2
  167. package/lisp/tools.lisp +17 -5
  168. package/migrations/050_auxiliary_recovery.sql +11 -0
  169. package/package.json +6 -4
  170. package/scripts/prepare-build.mjs +13 -0
  171. package/scripts/setup-dsh.mjs +8 -3
  172. package/skills/kiokuko-lisp/SKILL.md +5 -3
@@ -14,7 +14,7 @@ DSHの権限判定、必要な検証を維持し、役小角の契約・WorkUnit
14
14
 
15
15
  Webプロファイルでは [Kiokuko Models](kiokuko-models.md) から接続を設定できます。DSH本体のModelsで設定する必要はありません。登録したモデルは、通常会話・Enno・Deepでネイティブ接続と併用できます。
16
16
 
17
- 通常版・modular coreとも `modelAutoMode.mode: off` が既定です。同じDSHプロファイルでKiokuko Modelsまたはdsh-codexからCodexを認証し、JevかLayaの判定を準備したうえで、まず `observe` で選択案を確認します。
17
+ 通常版・modular coreとも `modelAutoMode.mode: off` が既定です。同じDSHプロファイルでKiokuko Modelsまたはdsh-codexからCodexを認証し、Jev・Laya・[OpenAI](typed-decisions.md#openai-credentials)のいずれかの判定を準備したうえで、まず `observe` で選択案を確認します。
18
18
 
19
19
  ```yaml
20
20
  modelAutoMode:
@@ -34,7 +34,7 @@ modelAutoMode:
34
34
 
35
35
  初期候補は `gpt-6-luna` の low・medium・high と `gpt-6-sol` の high です。`modelAutoMode.routes` には最大4件、`id`(`luna-low`、`luna-medium`、`luna-high`、`sol-high`)と `binding`(`provider`、`model`、`reasoningEffort`)を指定できます。IDは経路のラベルなので、登録済みのAstraなども正確なbindingで割り当てられます。候補はCodex由来とResponses方式を確認でき、現在のモデル一覧、文脈容量・入力形式・推論強度、要求設定の検証、token meterを通った接続に限定します。ネイティブの `openai-codex` とKiokuko所有のCodex接続が対象です。名前だけを似せた接続やOpenAI API接続は対象外です。有効なbindingが2件未満なら判定しません。
36
36
 
37
- 新しい受付済みの通常タスクでは、現在の依頼文、タスク種別、添付の種類、経路IDと判定基準を選択中のJevかLayaへ送ります。この判定のために添付の内容、全履歴、リポジトリ全体は送信しません。Choice 1問の結果をrunに保存し、継続では同じ経路を使います。再起動時に判定結果が不明なら再送せず元のモデルを維持します。`observe`、棄権、probe失敗、metadata不足、非対応effort、timeout、入力超過でも元のモデルを維持します。取消、セッション同一性の不一致、保存の整合性エラーでは要求を止めます。認証・利用枠・モデル利用不可によるdispatch失敗を別モデルへ自動再送しません。
37
+ 新しい受付済みの通常タスクでは、現在の依頼文、タスク種別、添付の種類、経路IDと判定基準を選択中のJev・Laya・OpenAIへ送ります。この判定のために添付の内容、全履歴、リポジトリ全体は送信しません。Choice 1問の結果をrunに保存し、継続では同じ経路を使います。再起動時に判定結果が不明なら再送せず元のモデルを維持します。`observe`、棄権、probe失敗、metadata不足、非対応effort、timeout、入力超過でも元のモデルを維持します。取消、セッション同一性の不一致、保存の整合性エラーでは要求を止めます。認証・利用枠・モデル利用不可によるdispatch失敗を別モデルへ自動再送しません。
38
38
 
39
39
  状態表示では、設定・準備状態・選択案・適用したbindingと、nativeの `request/header` で確認した実モデルを区別します。初期候補は判定基準であり、品質・時間・利用枠の改善を保証しません。Enno、Deep、子、雑談、回答の再検討、保護されたLisp実行は既存の経路を使います。実装失敗後の自動昇格は初期版に含めません。
40
40
 
@@ -15,7 +15,7 @@ plan approval or automatic Enno continuation.
15
15
 
16
16
  In Web profiles, [Kiokuko Models](kiokuko-models.md) manages connections without requiring DSH's Models settings. Its registered models are available to ordinary chat, Enno and Deep alongside native connections.
17
17
 
18
- `modelAutoMode` is off by default in both the full plugin and modular core. To try it, authenticate Codex through Kiokuko Models or dsh-codex in the same DSH profile, configure a Jev or Laya typed-decision backend, then use `observe` before enabling automatic routing:
18
+ `modelAutoMode` is off by default in both the full plugin and modular core. To try it, authenticate Codex through Kiokuko Models or dsh-codex in the same DSH profile, configure a Jev, Laya or [OpenAI typed-decision backend](typed-decisions.md#openai-credentials), then use `observe` before enabling automatic routing:
19
19
 
20
20
  ```yaml
21
21
  modelAutoMode:
@@ -35,7 +35,7 @@ The command changes only the current native session. `on` also clears its manual
35
35
 
36
36
  The initial preset offers `gpt-6-luna` at low, medium and high effort, plus `gpt-6-sol` at high effort. Up to four exact route bindings can be configured under `modelAutoMode.routes`; each has an `id` from `luna-low`, `luna-medium`, `luna-high`, `sol-high`, and a `binding` with `provider`, `model`, and `reasoningEffort`. These are route labels, so a registered Astra or other GPT model may be assigned explicitly. No new model ID is guessed or substituted. A candidate must have a validated Codex origin and Responses protocol, live model context and modality metadata, supported efforts, call-config validation and token meter. Both native `openai-codex` and Kiokuko-owned Codex routes qualify; an arbitrary provider name or OpenAI API connection does not. Fewer than two valid bindings skips classification.
37
37
 
38
- For a new admitted normal task, Kiokuko sends the current task text, task type, attachment kinds, route IDs and rubric to the selected Jev or Laya backend. It does not send attachment bytes, full history or repository contents for this classification. One Choice result selects a route or abstains. The route is stored against the exact run and reused for continuations; an unknown in-flight decision after restart is retained without another classifier call. `observe` records a proposal but keeps the current model. A failed probe, missing metadata, unsupported effort, timeout, oversized input or abstention also keeps the current model. Cancellation, stale session identity and storage integrity failures stop the request. Dispatch authentication, quota and unavailable-model errors remain ordinary failures; no alternate model is retried automatically.
38
+ For a new admitted normal task, Kiokuko sends the current task text, task type, attachment kinds, route IDs and rubric to the selected Jev, Laya or OpenAI backend. It does not send attachment bytes, full history or repository contents for this classification. One Choice result selects a route or abstains. The route is stored against the exact run and reused for continuations; an unknown in-flight decision after restart is retained without another classifier call. `observe` records a proposal but keeps the current model. A failed probe, missing metadata, unsupported effort, timeout, oversized input or abstention also keeps the current model. Cancellation, stale session identity and storage integrity failures stop the request. Dispatch authentication, quota and unavailable-model errors remain ordinary failures; no alternate model is retried automatically.
39
39
 
40
40
  The status distinguishes the configured mode, readiness, proposal and selected binding from the model observed in a native `request/header`. The initial preset is a rubric, not a claim that it improves quality, elapsed time or subscription usage. Enno, Deep, children, chat, review continuation and protected Lisp execution retain their existing owners. Automatic escalation after a failed implementation pass is not enabled.
41
41
 
@@ -17,6 +17,12 @@ permissions, and disposable-profile result independently.
17
17
  | npm lifecycle | `prepare: npm run build` |
18
18
  | Automatic size policy | intentionally exceeded; manual `user-reviewed` track |
19
19
 
20
+ This table records the **0.1.3 review snapshot**, including its original lifecycle
21
+ command; it is not the current package's release evidence. Current source uses
22
+ `prepare: node scripts/prepare-build.mjs` with normal builds and an explicit CI-only
23
+ deferral. See [current lifecycle and permissions](../PERMISSIONS.md#installation-lifecycle)
24
+ and [CI build ownership](verification.md#consolidated-duplicate-invocations).
25
+
20
26
  The Commit field is filled only after the user commits and pushes the verified
21
27
  working tree. The catalog must point to that full immutable Commit, not a branch
22
28
  name or moving tag.
@@ -23,7 +23,7 @@ excerpted or rewritten, and classification grants no execution permission.
23
23
  The common API also accepts explicit `noul` (yes probability) and `score`
24
24
  (ordered rubric) questions. Their validated answers have `status: "measured"`;
25
25
  they grant no permission. The existing Choice request and answer shapes remain
26
- valid. TypeSafe can evaluate all three question types in one batch. Nimble and
26
+ valid. TypeSafe and OpenAI can evaluate all three question types in one batch. Nimble and
27
27
  Laya accept Choice only and return `DECISION_UNSUPPORTED` before inference for
28
28
  other kinds. The separate Lisp `kioku.typesafe:evaluate` API retains its own
29
29
  wire contract.
@@ -33,6 +33,7 @@ Switch backends in DSH without a restart:
33
33
  ```text
34
34
  /kioku-decisions use jev
35
35
  /kioku-decisions use laya
36
+ /kioku-decisions use openai
36
37
  /kioku-decisions use nimble
37
38
  /kioku-decisions use default
38
39
  ```
@@ -48,8 +49,107 @@ base configuration. A stale host cannot overwrite a selection saved by another
48
49
  host; restart it to load the latest choice. Changing the base configuration uses
49
50
  that configuration's selection, with the YAML provider as the default.
50
51
 
52
+ <a id="openai-credentials"></a>
53
+ ## OpenAI credentials
54
+
55
+ Jev remains the default; OpenAI, local Laya and Nimble are alternatives. OpenAI uses the official [Decisions API](https://developers.openai.com/api/docs/guides/decisions), `POST /v1/decisions`, with `gpt-6-luna` as this checkout's default decision model. This is separate from the main chat model: ChatGPT/Codex OAuth login does not supply `OPENAI_API_KEY`, and a TypeSafe/Jev key cannot replace it.
56
+
57
+ These instructions describe the current source. They do not assert that the published npm `latest` already includes OpenAI support. If `use openai` is unavailable, check the installed build's command support first.
58
+
59
+ 1. Create an API key for your OpenAI API project and add it to the credential store used by the running DSH. With the standard `credentials-local` provider, choose the path as follows:
60
+
61
+ | Configuration | Credential file |
62
+ |---|---|
63
+ | Default harness home | `~/.dsh/.credentials.yaml` |
64
+ | Custom `DSH_HOME` | `$DSH_HOME/.credentials.yaml` |
65
+ | Explicit `credentials.path` (the provider's `config.path`) | The configured path, overriding the home default |
66
+
67
+ `--profile web` keeps profile packages and patches under `$DSH_HOME/profiles/web`; it does **not** by itself move credentials there. A profile can override `credentials.path`, or its launcher can use another `DSH_HOME`. Use that effective file, not a guessed `profiles/web/.credentials.yaml`.
68
+
69
+ 2. In an existing file, add only `OPENAI_API_KEY` under `refs` and preserve all other `refs` and `records`. This is a minimal **new-file example**, with a nonfunctional placeholder:
70
+
71
+ ```yaml
72
+ version: 1
73
+ refs:
74
+ OPENAI_API_KEY: "OPENAI_API_KEY_EXAMPLE_ONLY"
75
+ records: {}
76
+ ```
77
+
78
+ Replace the placeholder privately with your key. On macOS/Linux, protect the actual file; for the default path:
79
+
80
+ ```sh
81
+ chmod 600 "$HOME/.dsh/.credentials.yaml"
82
+ ```
83
+
84
+ Use your configured path instead when it differs. The default `watch: true` reloads valid file edits automatically for subsequent requests; restarting DSH is unnecessary. Do not paste keys into chat, screenshots or Git.
85
+
86
+ 3. In DSH's command input, select OpenAI and inspect the result:
87
+
88
+ ```text
89
+ /kioku-decisions use openai
90
+ /kioku-decisions status
91
+ ```
92
+
93
+ `use openai` makes a real API probe, which may incur usage charges. Only a successful probe and save persist the choice for this project and new requests; failure or cancellation keeps the prior choice. Existing requests keep their binding. `status` makes no inference call. Optional `/kioku-decisions probe` makes another real probe.
94
+
95
+ The standard provider resolves **saved file > launch environment > project `.env` > harness-home `.env`**. Environment variables still work when the credentials service is present, unless a saved value overrides them. For an environment-only setup, export the key **before** launching DSH from that shell:
96
+
97
+ ```sh
98
+ export OPENAI_API_KEY='OPENAI_API_KEY_EXAMPLE_ONLY'
99
+ ```
100
+
101
+ This is a placeholder, not a usable key. An export in another shell after DSH has started does not update its launch snapshot; use the watched file to update an already running instance. Keep credential-bearing `.env` files out of Git.
102
+
103
+ ## Provider configuration
104
+
51
105
  Configure `typedDecisions` on the full plugin or modular core:
52
106
 
107
+ OpenAI uses the distinct official [Decisions API](https://developers.openai.com/api/docs/guides/decisions),
108
+ `POST https://api.openai.com/v1/decisions`, rather than Responses JSON output.
109
+ It maps Choice, Noul (predicate) and Score to the native API and validates ordered
110
+ named answers, distributions, rubric levels and individual refusals. The default
111
+ model is `gpt-6-luna`; probability ≥ 0.9 and margin ≥ 0.2 are required for Choice.
112
+ Kiokuko resolves `OPENAI_API_KEY` through `ctx.credentials.resolve` when the service
113
+ exists; the standard local provider includes the launch environment and `.env`
114
+ fallbacks described [above](#openai-credentials). Only a composition without that
115
+ service uses Kiokuko's direct `process.env` fallback. A different credential
116
+ provider may have different resolution rules. TypeSafe credentials are never substituted. No redirects,
117
+ automatic retries, or provider fallback are added. `use openai` probes before
118
+ persisting; missing credentials, failed probes and cancellation leave selection unchanged.
119
+ Existing Jev/Laya stored configuration digests retain their original shape.
120
+ Current token records retain input/output totals; cached-token breakdown is not recorded.
121
+
122
+ To select OpenAI in the plugin or core configuration instead of a project command:
123
+
124
+ ```yaml
125
+ typedDecisions:
126
+ mode: auto
127
+ provider: openai
128
+ openai:
129
+ model: gpt-6-luna
130
+ timeoutMs: 5000
131
+ ```
132
+
133
+ Keep keys in the credential store, not in `typedDecisions`. A configured provider
134
+ is not evidence of a successful API call; use the command probe to verify access.
135
+
136
+ The normal startup card offers the four decision/Lisp ON/OFF combinations and Cancel
137
+ in one question before model tool assembly. It uses the currently selected backend,
138
+ shown in the card; selection does not prove authentication or successful inference.
139
+ Immutable existing decision bindings also retain the task choice, without granting
140
+ tool or file authority. The same request and explicit continuation reuse the choice;
141
+ an unrelated new request asks again. Cancel/Skip starts no task. Headless operation
142
+ keeps the configured decision mode and explicit manual Lisp preference; an explicit
143
+ `typedDecisions.startup: { decision: true, lisp: true }` config selects both.
144
+ Runtime failures retain the choice and permit explicit recovery without a new question.
145
+
146
+ Semantic-comparison diagnostics retain only the known criterion names
147
+ (`action`, `reference`, `constraints`, `latest-answer`) and finite verdicts, with
148
+ backend, elapsed time, gate outcome and existing request/decision correlation.
149
+ They contain no source text, credentials or private reasoning. `providerDispatched`
150
+ means the provider adapter was invoked; it does not prove a successful HTTP exchange.
151
+ These diagnostic fields never change acceptance or native permissions.
152
+
53
153
  ```yaml
54
154
  typedDecisions:
55
155
  mode: auto
@@ -99,7 +199,8 @@ A live comparison requires explicit
99
199
  `TYPESAFE_API_KEY`; it sends only the checked-in synthetic fixture and must not
100
200
  be interpreted as a production accuracy estimate.
101
201
 
102
- Set the TypeSafe key through DSH, then inspect status:
202
+ The following commands manage only the TypeSafe/Jev key; for OpenAI, use the
203
+ [credential-file setup](#openai-credentials). Set the TypeSafe key through DSH, then inspect status:
103
204
 
104
205
  ```text
105
206
  /kioku-typesafe-key <key>
package/docs/typesafe.md CHANGED
@@ -31,9 +31,14 @@ not verified. Invoke the same command with a new key to replace it immediately.
31
31
 
32
32
  The first command reports configuration, source and writability. Clear removes
33
33
  the stored key and reports any remaining source. DSH resolves `TYPESAFE_API_KEY`
34
- for each call. Its inherited environment takes precedence and makes changes
35
- read-only; the managed credential store precedes project/user environment files.
36
- To change an inherited key, update that launch environment and restart DSH.
34
+ for each call. With the standard credentials-local provider, the saved file wins,
35
+ then the launch environment, project `.env` and harness-home `.env`. Saving writes
36
+ the higher-priority file even when an environment fallback exists. Default file
37
+ watching applies valid edits without a restart; an environment-only change must
38
+ be present when DSH is launched. Preserve existing `refs` and `records`.
39
+ See [credential paths, permissions and precedence](typed-decisions.md#openai-credentials).
40
+ Those storage rules also apply to `TYPESAFE_API_KEY`, but `/kioku-typesafe-key`
41
+ does not set `OPENAI_API_KEY`; ChatGPT/Codex OAuth is separate from both keys.
37
42
  With no credential provider, evaluation can use the host's `TYPESAFE_API_KEY`,
38
43
  but save/clear return `TYPESAFE_STORAGE_UNAVAILABLE`. Kiokuko creates no separate
39
44
  credential file and never supplies the key to workers or their subprocesses.
@@ -15,9 +15,19 @@ Native fixture preparation is deferred until a selected, executable check declar
15
15
  root dependencies (`npm ci`), not the DSH runtime fixture. Missing or invalid native
16
16
  fixtures remain `prerequisite-missing` for checks that require them.
17
17
 
18
- The required CI `verify` aggregate waits for `verify-main`, the complete Protected
19
- Lisp matrix and the complete semantic platform matrix. All three dependency results
20
- must be `success`; failure, cancellation, skipped or missing results fail the aggregate.
18
+ CI schedules **Linux x64** and **macOS ARM64**. Full selection has 21 jobs:
19
+ selection, two native micro-judge builds, 17 verification lanes and the aggregate.
20
+ Linux ARM64 is not scheduled or claimed as CI coverage. Its runtime/build support
21
+ remains in the native target registry; this workflow does not produce its binary.
22
+
23
+ The required `verify` aggregate consumes `select`, `micro-judge-native` and `checks`.
24
+ Every selected lane and native artifact must be present, successful, fresh and
25
+ bound to the same selected plan and source. Failure, cancellation, a missing
26
+ selected report, an extra target or an altered artifact fails acceptance. Only
27
+ prose-only selection can legitimately skip both executable job groups. The
28
+ remaining Linux x64/macOS ARM64 check inventories and their deadlines are unchanged.
29
+ The CI review bundle contains exactly its selected targets; standalone native
30
+ bundle verification still requires the complete supported-target inventory.
21
31
 
22
32
  Output defaults to a fresh OS temporary directory. Supply an empty directory
23
33
  outside the repository with `--output`. `plan.json`, per-command logs, official
@@ -80,6 +90,21 @@ arbitrary stdout or a successful no-op process is insufficient.
80
90
 
81
91
  ## Consolidated duplicate invocations
82
92
 
93
+ Selected CI dependency installs set `KIOKUKO_CI_DEFER_PREPARE=1` only on the root
94
+ `npm ci` step. With `CI=true`, this defers this package's `prepare` build to the
95
+ verifier's required clean build; it does not disable dependency lifecycle scripts.
96
+ Ordinary npm/pnpm preparation still builds, including in CI without this explicit
97
+ flag, and build failure remains a failed prepare. The verifier's source/build
98
+ digests, packed-artifact receipts and stale-source rejection remain mandatory.
99
+
100
+ For full coverage, Linux ARM64 removal changes the planned job count from 27 to
101
+ 21 and official DSH fixture builds from 19 to 15. Deferring prepare removes one
102
+ redundant plugin build in each of the remaining 17 verification lanes. This is an
103
+ execution-plan comparison, not a measured hosted-CI duration improvement. Official
104
+ DSH still builds separately for each selected fixture lane; no OS/architecture,
105
+ Node/ABI or native dependency is reused across platforms.
106
+
107
+
83
108
  - `skill-prompts` is covered by `native-unit`: `tests/dsh/unit/skill-compiler.test.ts`, `tests/dsh/unit/skill-snapshot.test.ts`.
84
109
  - `index-reasoning` is covered by `native-integration`: `tests/dsh/integration/index-reasoning.test.ts`, `tests/dsh/integration/index-reasoning-native.test.ts`, `tests/dsh/integration/index-reasoning-evaluation.test.ts`.
85
110
  - `index-evaluation` is covered by `native-integration`: `tests/dsh/integration/index-reasoning-evaluation.test.ts`.
@@ -0,0 +1,2 @@
1
+ export function processIdentity(pid: number): string | undefined
2
+ export function sameProcess(pid: number, identity: string | undefined): boolean
@@ -0,0 +1,34 @@
1
+ import { readFileSync } from 'node:fs'
2
+ import { execFileSync } from 'node:child_process'
3
+ import { createHash } from 'node:crypto'
4
+
5
+ /** OS birth identity, not PID liveness alone. Unavailable identity stays conservative. */
6
+ export function processIdentity(pid) {
7
+ if (!Number.isSafeInteger(pid) || pid < 1) throw new Error('INVALID_PROCESS_ID')
8
+ try {
9
+ let birth
10
+ if (process.platform === 'linux') {
11
+ const stat=readFileSync(`/proc/${pid}/stat`,'utf8')
12
+ birth=[readFileSync('/proc/sys/kernel/random/boot_id','utf8').trim(),stat.slice(stat.lastIndexOf(')')+2).split(' ')[19]]
13
+ if(!/^\d+$/.test(birth[1]??''))throw new Error('INVALID_PROCESS_IDENTITY')
14
+ } else if(process.platform === 'darwin') {
15
+ const started=execFileSync('/bin/ps',['-p',String(pid),'-o','lstart='],{encoding:'utf8',timeout:1000,stdio:['ignore','pipe','ignore'],env:{...process.env,LC_ALL:'C',TZ:'UTC'}}).trim()
16
+ if(!started)return undefined
17
+ birth=[started]
18
+ } else return undefined
19
+ return createHash('sha256').update(JSON.stringify([process.platform,pid,...birth])).digest('hex')
20
+ } catch(error) {
21
+ if(['ENOENT','ESRCH'].includes(error.code)||error.status===1)return undefined
22
+ throw error
23
+ }
24
+ }
25
+
26
+ export function sameProcess(pid, identity) {
27
+ try { process.kill(pid,0) } catch(error) { if(error.code==='ESRCH')return false;throw error }
28
+ if(process.platform==='linux'){
29
+ try{const stat=readFileSync(`/proc/${pid}/stat`,'utf8');if(['Z','X'].includes(stat.slice(stat.lastIndexOf(')')+2).split(' ')[0]))return false}
30
+ catch(error){if(error.code==='ENOENT')return false;throw error}
31
+ }
32
+ const current=identity?processIdentity(pid):undefined
33
+ return !current || !identity || current===identity
34
+ }
@@ -0,0 +1 @@
1
+ export function claimRepository(root: string): { recordRuntime(pid: number): string | null; close(): void }
@@ -0,0 +1,58 @@
1
+ // The existing supervisor holds this OS-backed SQLite lock until its runtime exits.
2
+ // The user directory is independent of DSH's DB, session and worker TMPDIR.
3
+ import { DatabaseSync } from 'node:sqlite'
4
+ import { createHash } from 'node:crypto'
5
+ import { lstatSync, mkdirSync, realpathSync, readFileSync, writeFileSync, renameSync, unlinkSync } from 'node:fs'
6
+ import { randomUUID } from 'node:crypto'
7
+ import { processIdentity, sameProcess } from './process-identity.mjs'
8
+ import { tmpdir } from 'node:os'
9
+ import { join } from 'node:path'
10
+
11
+ export function claimRepository(root) {
12
+ const canonical = realpathSync(root)
13
+ const directory = join(process.platform === 'win32' ? tmpdir() : '/tmp', `kiokuko-lisp-owners-${process.getuid?.() ?? 'user'}`)
14
+ mkdirSync(directory, { recursive: true, mode: 0o700 })
15
+ const info = lstatSync(directory)
16
+ if (!info.isDirectory() || info.isSymbolicLink() || (process.getuid && info.uid !== process.getuid()) || (info.mode & 0o077))
17
+ throw new Error('REPOSITORY_LOCK_DIRECTORY')
18
+ const path = join(directory, `${createHash('sha256').update(canonical).digest('hex')}.sqlite3`)
19
+ try { const file=lstatSync(path);if (!file.isFile() || file.isSymbolicLink()) throw new Error('REPOSITORY_LOCK_FILE') }
20
+ catch(error) { if(error.code !== 'ENOENT') throw error }
21
+ const db = new DatabaseSync(path)
22
+ const metadata=path+'.owner.json',token=randomUUID()
23
+ try {
24
+ // Opening a new SQLite file briefly takes reader locks in *both* contenders.
25
+ // A zero busy timeout can make both exclusive acquisitions fail before
26
+ // either owns the repository. Allow those short initialization reads to
27
+ // drain; an existing owner's lifetime transaction still rejects in 250ms.
28
+ db.exec('PRAGMA busy_timeout=250; BEGIN EXCLUSIVE; CREATE TABLE IF NOT EXISTS repository_owner(root TEXT NOT NULL)')
29
+ try {
30
+ const owner=JSON.parse(readFileSync(metadata,'utf8'))
31
+ if(!Number.isSafeInteger(owner.pid)||owner.pid<1||owner.root!==canonical||typeof owner.token!=='string'
32
+ ||owner.identity!==null&&!/^[a-f0-9]{64}$/.test(owner.identity))throw new Error('REPOSITORY_LOCK_METADATA')
33
+ // A supervisor killed before cleanup must not donate its still-live runtime.
34
+ if(sameProcess(owner.pid,owner.identity??undefined))throw new Error('REPOSITORY_IN_USE')
35
+ } catch(error) { if(error.code!=='ENOENT')throw error }
36
+ db.prepare('DELETE FROM repository_owner').run()
37
+ db.prepare('INSERT INTO repository_owner VALUES(?)').run(canonical)
38
+ let recorded=false
39
+ return {
40
+ recordRuntime(pid){
41
+ const temporary=metadata+'.'+token
42
+ const identity=processIdentity(pid)??null
43
+ writeFileSync(temporary,JSON.stringify({root:canonical,pid,identity,token})+'\n',{flag:'wx',mode:0o600})
44
+ renameSync(temporary,metadata);recorded=true
45
+ return identity
46
+ },
47
+ close(){
48
+ // Called only after runtime exit. A crash leaves evidence for the next owner.
49
+ if(recorded){const owner=JSON.parse(readFileSync(metadata,'utf8'));if(owner.token===token)unlinkSync(metadata)}
50
+ db.close()
51
+ },
52
+ } // Transaction stays uncommitted; the OS releases it when this supervisor dies.
53
+ } catch(error) {
54
+ db.close()
55
+ if(error.errcode === 5 || error.code === 'SQLITE_BUSY') throw new Error('REPOSITORY_IN_USE')
56
+ throw error
57
+ }
58
+ }
@@ -2,7 +2,16 @@
2
2
  // pipe. It stays outside the worker sandbox so arbitrary Lisp cannot disable it.
3
3
  import { spawn } from 'node:child_process'
4
4
  import { openSync, closeSync, writeSync } from 'node:fs'
5
+ import { claimRepository } from './repository-owner.mjs'
5
6
  const launch = JSON.parse(process.argv[2])
7
+ let repositoryLease
8
+ if (launch.repositoryRoot) {
9
+ try { repositoryLease = claimRepository(launch.repositoryRoot) }
10
+ catch(error) {
11
+ writeSync(4, JSON.stringify({ type: 'error', code: error.message === 'REPOSITORY_IN_USE' ? 'REPOSITORY_IN_USE' : 'REPOSITORY_LOCK_FAILED' })+'\n')
12
+ process.exit(73)
13
+ }
14
+ }
6
15
  let child, closing = false, terminationSent = false
7
16
  const kill = () => {
8
17
  if (!child?.pid || terminationSent) return
@@ -28,10 +37,18 @@ child = spawn(launch.command, launch.args, { cwd: launch.cwd, env: launch.env, s
28
37
  if (filter !== undefined) closeSync(filter)
29
38
  // Stream one JSON object: older readers still consume the complete terminal
30
39
  // object, while current readers observe the prefix only after actual spawn.
31
- child.once('spawn',()=>{if(launch.report){try{writeSync(4,'{"processStarted":true,')}catch{/* host already stopped */}}})
40
+ child.once('spawn',()=>{
41
+ if(launch.repositoryRoot){
42
+ try{const identity=repositoryLease.recordRuntime(child.pid);writeSync(4,JSON.stringify({type:'runtime',pid:child.pid,identity})+'\n')}
43
+ catch{try{writeSync(4,JSON.stringify({type:'error',code:'REPOSITORY_LOCK_FAILED'})+'\n')}finally{stop()}}
44
+ }
45
+ if(launch.report){try{writeSync(4,'{"processStarted":true,')}catch{/* host already stopped */}}
46
+ })
32
47
  child.once('error', error => { process.stderr.write(`LISP_LAUNCH_ERROR: ${error.message}\n`); process.exit(70) })
33
48
  child.once('exit', (code, signal) => {
34
49
  if(launch.report){try{writeSync(4,JSON.stringify({exitCode:code,signal}).slice(1)+'\n')}catch{/* host already stopped */}}
35
- if (launch.group) kill(); process.exit(signal ? 128 : code ?? 70)
50
+ if (launch.group) kill()
51
+ repositoryLease?.close()
52
+ process.exit(signal ? 128 : code ?? 70)
36
53
  })
37
54
  if (closing) kill()
package/lisp/tools.lisp CHANGED
@@ -20,6 +20,7 @@
20
20
  (defvar *generation* (uiop:getenv "KIOKU_GENERATION"))
21
21
  (defvar *counter* 0)
22
22
  (defvar *request* nil)
23
+ (defvar *task-scratch* nil)
23
24
  (defun object (&rest pairs)
24
25
  (let ((h (make-hash-table :test 'equal)))
25
26
  (loop for (key value) on pairs by #'cddr do (setf (gethash key h) value)) h))
@@ -68,7 +69,7 @@
68
69
  (if (< (length (sb-ext:string-to-octets json :external-format :utf-8)) 524288) (kioku.data:parse-json json) nil))
69
70
  (error () nil)))))
70
71
  (defun compile-task (code)
71
- (let ((*package* (find-package :kioku.user)) (*read-eval* nil))
72
+ (let ((*read-eval* nil))
72
73
  (let ((form (with-input-from-string (stream code)
73
74
  (let ((value (read stream nil stream)))
74
75
  (when (or (eq value stream) (not (eq (read stream nil stream) stream)))
@@ -78,7 +79,7 @@
78
79
  (compile nil form))))
79
80
  (defun evaluate-task (code input-path)
80
81
  "Run one generated function with JSON data; leave the full result in scratch."
81
- (let ((*package* (find-package :kioku.user)) (*read-eval* nil))
82
+ (let ((*read-eval* nil))
82
83
  (let* ((function (compile-task code))
83
84
  (input (kioku.data:parse-json (uiop:read-file-string input-path)))
84
85
  (result (funcall function input))
@@ -88,6 +89,18 @@
88
89
  (error "TASK_RESULT_LIMIT"))
89
90
  (kioku.files:write-text path json)
90
91
  (object "path" "task-result.json" "bytes" (length (sb-ext:string-to-octets json :external-format :utf-8))))))
92
+ (defun task-request (request)
93
+ ;; Fresh unqualified symbols and object refs; the same owner's process remains.
94
+ ;; Arbitrary Common Lisp is not a heap security boundary.
95
+ (let* ((*package* (make-package (symbol-name (gensym "KIOKU.TASK.")) :use '(:cl)))
96
+ (*objects* (make-hash-table :test 'equal))
97
+ (*task-scratch* (let ((scratch (gethash "scratch" request)))
98
+ (when scratch (uiop:ensure-directory-pathname scratch)))))
99
+ (unwind-protect
100
+ (if (equal "task-compile" (gethash "method" request))
101
+ (progn (compile-task (gethash "code" request)) (object "compiled" yason:true))
102
+ (evaluate-task (gethash "code" request) (gethash "input" request)))
103
+ (delete-package *package*))))
91
104
  (defun serve ()
92
105
  (setf *wire* (sb-sys:make-fd-stream 3 :input t :output t :element-type 'character :external-format :utf-8 :buffering :line))
93
106
  (emit (object "version" 1 "type" "ready"))
@@ -95,8 +108,7 @@
95
108
  (let ((*request* (gethash "id" request)) (*proposals* nil) (*inputs* (gethash "inputs" request #())))
96
109
  (handler-case
97
110
  (let ((value (cond ((equal "eval" (gethash "method" request)) (evaluate-code (gethash "code" request)))
98
- ((equal "task" (gethash "method" request)) (evaluate-task (gethash "code" request) (gethash "input" request)))
99
- ((equal "task-compile" (gethash "method" request)) (progn (compile-task (gethash "code" request)) (object "compiled" yason:true)))
111
+ ((member (gethash "method" request) '("task" "task-compile") :test #'equal) (task-request request))
100
112
  ((equal "describe" (gethash "method" request)) (kioku.tools:describe-symbol (gethash "symbol" request "")))
101
113
  ((equal "inspect" (gethash "method" request)) (kioku.objects:inspect-ref (gethash "ref" request)))
102
114
  (t (error "UNKNOWN_METHOD")))))
@@ -129,7 +141,7 @@
129
141
  (defun regex-matches (pattern text) (cl-ppcre:all-matches-as-strings pattern text))
130
142
  (defun regex-replace (pattern text replacement) (cl-ppcre:regex-replace-all pattern text replacement))
131
143
  (in-package :kioku.files)
132
- (defun scratch () (pathname (uiop:getenv "KIOKU_SCRATCH")))
144
+ (defun scratch () (or kioku.internal::*task-scratch* (pathname (uiop:getenv "KIOKU_SCRATCH"))))
133
145
  (defun %scratch-path (name &key must-exist)
134
146
  "Resolve NAME below scratch without accepting absolute paths, traversal, or links."
135
147
  (let* ((root (truename (scratch)))
@@ -0,0 +1,11 @@
1
+ -- Payload-free quarantine. These rows never grant execution or adopt memory.
2
+ CREATE TABLE dsh_auxiliary_recovery (
3
+ id TEXT PRIMARY KEY, session_id TEXT NOT NULL, native_turn INTEGER NOT NULL,
4
+ origin TEXT NOT NULL CHECK(origin IN ('answer-context','intent-assessment')),
5
+ source_digest TEXT NOT NULL, context_digest TEXT NOT NULL,
6
+ state TEXT NOT NULL CHECK(state IN ('pending','running','retry_wait','verified','rejected','stale')),
7
+ attempts INTEGER NOT NULL DEFAULT 0 CHECK(attempts BETWEEN 0 AND 3),
8
+ lease_nonce TEXT, lease_until INTEGER, next_at INTEGER NOT NULL DEFAULT 0,
9
+ last_reason TEXT NOT NULL, updated_at INTEGER NOT NULL
10
+ );
11
+ CREATE INDEX dsh_auxiliary_recovery_session ON dsh_auxiliary_recovery(session_id,native_turn);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kiokuko-dsh",
3
- "version": "0.2.34",
3
+ "version": "0.2.37",
4
4
  "description": "Kiokuko plugin for DeepSeek Harness",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -24,6 +24,7 @@
24
24
  "skills/",
25
25
  "dsh/cordis.patch.yml",
26
26
  "docs/",
27
+ "scripts/prepare-build.mjs",
27
28
  "scripts/backfill-akinator-memory.mjs",
28
29
  "scripts/setup-dsh.mjs",
29
30
  "scripts/repair-session-log.mjs",
@@ -147,7 +148,7 @@
147
148
  "DSH-configured model providers for explicitly started Deep planning and its budgeted memory extraction",
148
149
  "The explicitly selected DSH model provider for a user-started Diff review without tools",
149
150
  "DSH-configured model provider for automatic memory review (active by default, up to 12 worker dispatches per project per UTC day), ordinary finalization and configured memory evolution",
150
- "Configured TypeSafe fixed endpoint or explicit Nimble HTTPS/loopback endpoint for automatic task/Skill/draft decisions and independent original-source/candidate comparison, projected memory reuse after a synthetic readiness probe, and Lisp; no redirects, retries or provider substitution; exact roles.check no-tool fallback for complete draft review",
151
+ "Configured TypeSafe or explicitly selected OpenAI Decisions fixed endpoint, or explicit Nimble HTTPS/loopback endpoint, for automatic task/Skill/draft decisions and independent original-source/candidate comparison, projected memory reuse after a synthetic readiness probe, and Lisp; no redirects, retries or provider substitution; exact roles.check no-tool fallback for complete draft review",
151
152
  "Explicit Laya-CoreML Unix socket for local finite decisions using the existing v1 worker or optional strict operations; no subprocess client, automatic worker startup, model downloads or provider substitution",
152
153
  "DSH-configured admitted provider/model for default-active source-backed index reasoning: up to 8 worker dispatches per workspace per UTC day; no retrieval-time generation or automatic resend of uncertain dispatches",
153
154
  "User-configured AI API endpoints and vendored provider OAuth flows through Kiokuko Models"
@@ -155,6 +156,7 @@
155
156
  "credentials": [
156
157
  "Optional user-provided GitHub or embedding credentials; never bundled or persisted by the plugin",
157
158
  "TYPESAFE_API_KEY resolved per explicit call; optional DSH-managed set/unset via /kioku-typesafe-key, inherited environment precedence, no worker or Kiokuko storage exposure; input visible while typing",
159
+ "OPENAI_API_KEY resolved separately through DSH credentials, or inherited environment only without a credentials service; never stored in decision records or substituted with a TypeSafe key",
158
160
  "Optional separate Nimble bearer credential reference through DSH; TYPESAFE_API_KEY is prohibited for Nimble; credentials are never persisted in decision records",
159
161
  "Shared dsh-auth credentials: human Web login/key replacement/logout; logout also affects dsh-cli"
160
162
  ],
@@ -167,7 +169,7 @@
167
169
  "Enabled source-candidate assessment distinguishes unavailable and incomplete checks from proof; the micro judge is native-verified on Apple Silicon macOS only, unsupported platforms report unavailable, and explicit typed-decision OFF records no assessment"
168
170
  ],
169
171
  "lifecycleEvidence": [
170
- "prepare runs only npm run build",
172
+ "prepare builds by default; selected CI installs defer to the verifier clean build",
171
173
  "Git installs use repository-scoped pnpm allowBuilds approval on a supporting pnpm version; source revision pinning is optional and separate",
172
174
  "Disposable-profile install, Web start, and uninstall evidence is recorded by CI"
173
175
  ]
@@ -200,7 +202,7 @@
200
202
  "publint": "publint",
201
203
  "pack:check": "node scripts/pack-check.mjs",
202
204
  "prepublishOnly": "node scripts/prepublish.mjs",
203
- "prepare": "npm run build",
205
+ "prepare": "node scripts/prepare-build.mjs",
204
206
  "test:agenticreplay:package": "npm run build && node scripts/verify-agenticreplay-consumer.mjs && node scripts/verify-agenticreplay-consumer.mjs --pnpm",
205
207
  "test:memory-review": "node scripts/run-tests.mjs tests/dsh/unit/memory-review tests/dsh/integration/memory-review",
206
208
  "test:evolution": "node scripts/run-tests.mjs tests/dsh/unit/evolution tests/dsh/integration/evolution",
@@ -0,0 +1,13 @@
1
+ // CI dependency installation may defer only this package's duplicate build.
2
+ // Dependency lifecycle scripts still run; the selected verifier builds from source.
3
+ import { spawnSync } from 'node:child_process'
4
+
5
+ if (process.env.CI === 'true' && process.env.KIOKUKO_CI_DEFER_PREPARE === '1') {
6
+ console.log('Deferring package prepare build to the selected verifier clean build.')
7
+ } else {
8
+ const runner=process.env.npm_execpath
9
+ if (!runner) throw new Error('Run prepare through npm or pnpm.')
10
+ const result=spawnSync(process.execPath,[runner,'run','build'],{stdio:'inherit'})
11
+ if (result.error) throw result.error
12
+ process.exitCode=result.status ?? 1
13
+ }
@@ -1,14 +1,19 @@
1
1
  import { parseArgs } from 'node:util'
2
- import { setupDsh } from '../dist/dsh/setup.js'
2
+ import { removeDshSetup, setupDsh } from '../dist/dsh/setup.js'
3
3
 
4
4
  try {
5
5
  const { values } = parseArgs({ options: {
6
6
  cwd: { type: 'string' }, home: { type: 'string' },
7
7
  check: { type: 'boolean', default: false }, json: { type: 'boolean', default: false },
8
+ remove: { type: 'boolean', default: false },
8
9
  } })
9
- const result = await setupDsh({ cwd: values.cwd, homeDirectory: values.home, check: values.check })
10
+ const result = await (values.remove ? removeDshSetup : setupDsh)({ cwd: values.cwd, homeDirectory: values.home, check: values.check })
10
11
  if (values.json) console.log(JSON.stringify(result, null, 2))
11
- else {
12
+ else if (values.remove) {
13
+ console.log(values.check ? result.current ? 'Removal is current.' : 'Removal is needed; run again without --check.' : 'Removal complete.')
14
+ console.log(`Skills: ${result.skills.directory} (${result.skills.removed} ${values.check ? 'removable' : 'removed'}, ${result.skills.preserved} preserved)`)
15
+ console.log(`Project instructions: ${result.instructions.path} (${result.instructions.status})`)
16
+ } else {
12
17
  console.log(values.check ? result.current ? 'Setup is current.' : 'Setup needs updating; run again without --check.' : 'Setup complete. Reload existing sessions to refresh their instructions.')
13
18
  console.log(`Skills: ${result.skills.directory} (${result.skills.created} ${values.check ? 'missing' : 'created'}, ${result.skills.updated} ${values.check ? 'stale' : 'updated'}, ${result.skills.unchanged} unchanged)`)
14
19
  console.log(`Project instructions: ${result.instructions.path} (${result.instructions.status})`)
@@ -145,8 +145,10 @@ Clear native implementation requests offer Lisp before model generation. A task
145
145
  ## Project-shared functions
146
146
 
147
147
  Project-shared functions work in both Lisp modes without a mode switch after the
148
- coding choice. They execute in separate workers under the selected execution mode, preserving the persistent
149
- worker's APIs and heap. `lisp_hot_contract` applies the profile approval policy to
148
+ coding choice. The exact session/agent/repo owner reuses its resident worker, preserving
149
+ PID, generation and definitions. Each call uses a fresh package, object table and result scratch;
150
+ this is not heap security isolation. Use pure functions with explicit dependencies. Other owners
151
+ cannot borrow that worker. Without a resident worker, task mode uses disposable workers. `lisp_hot_contract` applies the profile approval policy to
150
152
  schemas and 1–32 finite input/expected cases. Only the host grants approval. `lisp_hot_install` validates against that immutable contract and replaces
151
153
  the active version only at the expected revision. Dependency code is snapshotted.
152
154
  `lisp_hot_call` pins the active version by name; input/result refs stay owner-local.
@@ -154,7 +156,7 @@ the active version only at the expected revision. Dependency code is snapshotted
154
156
  uses the same profile approval policy. Approving new conditions preserves the old active
155
157
  version until a candidate passes; old conditions cannot authorize a new install.
156
158
  Finite cases are not a proof for every input. Active code/dependencies do not
157
- expire; retired versions may be collected after 30 days. No shared heap or RPC.
159
+ expire; retired versions may be collected after 30 days. Resident shared-function requests deny host RPC.
158
160
  Use `/kioku-lisp hot [NAME]` for human inspection. Never rerun UNKNOWN operations.
159
161
 
160
162
  ## Task-mode API details