@zwbigi/ink-xy 0.1.2 → 0.1.4

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 (598) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/app-path-routes-manifest.json +2 -2
  3. package/.next/build-manifest.json +2 -2
  4. package/.next/server/app/_global-error.html +1 -1
  5. package/.next/server/app/_global-error.rsc +1 -1
  6. package/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  7. package/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  8. package/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  9. package/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  10. package/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  11. package/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  12. package/.next/server/app/_not-found.html +1 -1
  13. package/.next/server/app/_not-found.rsc +1 -1
  14. package/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  15. package/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  16. package/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  17. package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  18. package/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  19. package/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  20. package/.next/server/app/api/inkos/route.js.nft.json +1 -1
  21. package/.next/server/app/api/skills/install/route.js.nft.json +1 -1
  22. package/.next/server/app/api/skills/search/route.js.nft.json +1 -1
  23. package/.next/server/app/index.html +1 -1
  24. package/.next/server/app/index.rsc +1 -1
  25. package/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  26. package/.next/server/app/index.segments/_full.segment.rsc +1 -1
  27. package/.next/server/app/index.segments/_head.segment.rsc +1 -1
  28. package/.next/server/app/index.segments/_index.segment.rsc +1 -1
  29. package/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  30. package/.next/server/app-paths-manifest.json +2 -2
  31. package/.next/server/chunks/162.js +1 -1
  32. package/.next/server/middleware-build-manifest.js +1 -1
  33. package/.next/server/pages/404.html +1 -1
  34. package/.next/server/pages/500.html +1 -1
  35. package/.next/trace +4 -4
  36. package/.next/trace-build +1 -1
  37. package/bin/pi-web.js +4 -1
  38. package/inkos/.env.example +20 -0
  39. package/inkos/.node-version +1 -0
  40. package/inkos/.nvmrc +1 -0
  41. package/inkos/CHANGELOG.md +787 -0
  42. package/inkos/CONTRIBUTING.md +89 -0
  43. package/inkos/LICENSE +661 -0
  44. package/inkos/README.en.md +483 -0
  45. package/inkos/README.ja.md +461 -0
  46. package/inkos/README.md +272 -0
  47. package/inkos/assets/15qun.jpg +0 -0
  48. package/inkos/assets/41777702961_.pic.jpg +0 -0
  49. package/inkos/assets/inkos-short-demo-cover.png +0 -0
  50. package/inkos/assets/inkos-text.svg +40 -0
  51. package/inkos/assets/logo.svg +47 -0
  52. package/inkos/assets/screenshot-chapters.png +0 -0
  53. package/inkos/assets/screenshot-pipeline.png +0 -0
  54. package/inkos/assets/screenshot-state.png +0 -0
  55. package/inkos/assets/screenshot-terminal.png +0 -0
  56. package/inkos/assets/wechat-group-v8.jpg +0 -0
  57. package/inkos/package.json +42 -0
  58. package/inkos/packages/cli/package.json +74 -0
  59. package/inkos/packages/cli/src/__tests__/analytics.test.ts +154 -0
  60. package/inkos/packages/cli/src/__tests__/cli-integration.test.ts +1031 -0
  61. package/inkos/packages/cli/src/__tests__/daemon.test.ts +93 -0
  62. package/inkos/packages/cli/src/__tests__/doctor.test.ts +36 -0
  63. package/inkos/packages/cli/src/__tests__/interact-command.test.ts +142 -0
  64. package/inkos/packages/cli/src/__tests__/interaction-tools.test.ts +107 -0
  65. package/inkos/packages/cli/src/__tests__/llm-overrides.test.ts +25 -0
  66. package/inkos/packages/cli/src/__tests__/localization.test.ts +121 -0
  67. package/inkos/packages/cli/src/__tests__/progress-text.test.ts +92 -0
  68. package/inkos/packages/cli/src/__tests__/project-bootstrap.test.ts +71 -0
  69. package/inkos/packages/cli/src/__tests__/publish-package.test.ts +272 -0
  70. package/inkos/packages/cli/src/__tests__/revision-command.test.ts +82 -0
  71. package/inkos/packages/cli/src/__tests__/runtime-requirements.test.ts +89 -0
  72. package/inkos/packages/cli/src/__tests__/short-fiction-command.test.ts +48 -0
  73. package/inkos/packages/cli/src/__tests__/studio-runtime.test.ts +142 -0
  74. package/inkos/packages/cli/src/__tests__/studio.test.ts +87 -0
  75. package/inkos/packages/cli/src/__tests__/tui-activity-state.test.ts +20 -0
  76. package/inkos/packages/cli/src/__tests__/tui-agent-session.test.ts +213 -0
  77. package/inkos/packages/cli/src/__tests__/tui-chat-depth.test.ts +27 -0
  78. package/inkos/packages/cli/src/__tests__/tui-chat-draft.test.ts +44 -0
  79. package/inkos/packages/cli/src/__tests__/tui-command.test.ts +86 -0
  80. package/inkos/packages/cli/src/__tests__/tui-composer-caret.test.ts +46 -0
  81. package/inkos/packages/cli/src/__tests__/tui-composer-display.test.ts +40 -0
  82. package/inkos/packages/cli/src/__tests__/tui-dashboard.test.tsx +219 -0
  83. package/inkos/packages/cli/src/__tests__/tui-effects-i18n.test.ts +29 -0
  84. package/inkos/packages/cli/src/__tests__/tui-i18n.test.ts +22 -0
  85. package/inkos/packages/cli/src/__tests__/tui-input-chrome.test.ts +10 -0
  86. package/inkos/packages/cli/src/__tests__/tui-input-history.test.ts +40 -0
  87. package/inkos/packages/cli/src/__tests__/tui-layout.test.ts +55 -0
  88. package/inkos/packages/cli/src/__tests__/tui-local-commands.test.ts +47 -0
  89. package/inkos/packages/cli/src/__tests__/tui-session-store.test.ts +81 -0
  90. package/inkos/packages/cli/src/__tests__/tui-setup-i18n.test.ts +31 -0
  91. package/inkos/packages/cli/src/__tests__/tui-slash-autocomplete.test.ts +33 -0
  92. package/inkos/packages/cli/src/commands/agent.ts +65 -0
  93. package/inkos/packages/cli/src/commands/analytics.ts +77 -0
  94. package/inkos/packages/cli/src/commands/audit.ts +52 -0
  95. package/inkos/packages/cli/src/commands/book.ts +260 -0
  96. package/inkos/packages/cli/src/commands/compose.ts +50 -0
  97. package/inkos/packages/cli/src/commands/config.ts +328 -0
  98. package/inkos/packages/cli/src/commands/consolidate.ts +50 -0
  99. package/inkos/packages/cli/src/commands/daemon.ts +121 -0
  100. package/inkos/packages/cli/src/commands/detect.ts +125 -0
  101. package/inkos/packages/cli/src/commands/doctor.ts +391 -0
  102. package/inkos/packages/cli/src/commands/draft.ts +43 -0
  103. package/inkos/packages/cli/src/commands/eval.ts +217 -0
  104. package/inkos/packages/cli/src/commands/export.ts +45 -0
  105. package/inkos/packages/cli/src/commands/fanfic.ts +183 -0
  106. package/inkos/packages/cli/src/commands/genre.ts +160 -0
  107. package/inkos/packages/cli/src/commands/import.ts +158 -0
  108. package/inkos/packages/cli/src/commands/init.ts +47 -0
  109. package/inkos/packages/cli/src/commands/interact.ts +109 -0
  110. package/inkos/packages/cli/src/commands/plan.ts +54 -0
  111. package/inkos/packages/cli/src/commands/radar.ts +60 -0
  112. package/inkos/packages/cli/src/commands/review.ts +253 -0
  113. package/inkos/packages/cli/src/commands/revise.ts +58 -0
  114. package/inkos/packages/cli/src/commands/short-fiction.ts +294 -0
  115. package/inkos/packages/cli/src/commands/status.ts +138 -0
  116. package/inkos/packages/cli/src/commands/studio.ts +194 -0
  117. package/inkos/packages/cli/src/commands/style.ts +99 -0
  118. package/inkos/packages/cli/src/commands/tui.ts +18 -0
  119. package/inkos/packages/cli/src/commands/update.ts +45 -0
  120. package/inkos/packages/cli/src/commands/write.ts +324 -0
  121. package/inkos/packages/cli/src/index.ts +5 -0
  122. package/inkos/packages/cli/src/interaction/tools.ts +49 -0
  123. package/inkos/packages/cli/src/localization.ts +215 -0
  124. package/inkos/packages/cli/src/program.ts +106 -0
  125. package/inkos/packages/cli/src/progress-text.ts +85 -0
  126. package/inkos/packages/cli/src/project-bootstrap.ts +175 -0
  127. package/inkos/packages/cli/src/runtime-requirements.ts +135 -0
  128. package/inkos/packages/cli/src/tui/__tests__/markdown.test.ts +64 -0
  129. package/inkos/packages/cli/src/tui/activity-state.ts +41 -0
  130. package/inkos/packages/cli/src/tui/agent-input.ts +264 -0
  131. package/inkos/packages/cli/src/tui/ansi.ts +72 -0
  132. package/inkos/packages/cli/src/tui/app.ts +130 -0
  133. package/inkos/packages/cli/src/tui/chat-depth.ts +22 -0
  134. package/inkos/packages/cli/src/tui/chat-draft.ts +42 -0
  135. package/inkos/packages/cli/src/tui/composer-caret.ts +22 -0
  136. package/inkos/packages/cli/src/tui/composer-display.ts +26 -0
  137. package/inkos/packages/cli/src/tui/dashboard-model.ts +164 -0
  138. package/inkos/packages/cli/src/tui/dashboard.tsx +544 -0
  139. package/inkos/packages/cli/src/tui/effects.ts +542 -0
  140. package/inkos/packages/cli/src/tui/i18n.ts +278 -0
  141. package/inkos/packages/cli/src/tui/input-history.ts +69 -0
  142. package/inkos/packages/cli/src/tui/local-commands.ts +55 -0
  143. package/inkos/packages/cli/src/tui/markdown.ts +64 -0
  144. package/inkos/packages/cli/src/tui/session-store.ts +6 -0
  145. package/inkos/packages/cli/src/tui/setup.ts +397 -0
  146. package/inkos/packages/cli/src/tui/slash-autocomplete.ts +62 -0
  147. package/inkos/packages/cli/src/tui/theme.ts +17 -0
  148. package/inkos/packages/cli/src/utils.ts +222 -0
  149. package/inkos/packages/cli/tsconfig.json +9 -0
  150. package/inkos/packages/core/genres/cozy.md +43 -0
  151. package/inkos/packages/core/genres/cultivation.md +42 -0
  152. package/inkos/packages/core/genres/dungeon-core.md +40 -0
  153. package/inkos/packages/core/genres/horror.md +51 -0
  154. package/inkos/packages/core/genres/isekai.md +43 -0
  155. package/inkos/packages/core/genres/litrpg.md +43 -0
  156. package/inkos/packages/core/genres/other.md +24 -0
  157. package/inkos/packages/core/genres/progression.md +41 -0
  158. package/inkos/packages/core/genres/romantasy.md +45 -0
  159. package/inkos/packages/core/genres/sci-fi.md +42 -0
  160. package/inkos/packages/core/genres/system-apocalypse.md +40 -0
  161. package/inkos/packages/core/genres/tower-climber.md +41 -0
  162. package/inkos/packages/core/genres/urban.md +53 -0
  163. package/inkos/packages/core/genres/xianxia.md +46 -0
  164. package/inkos/packages/core/genres/xuanhuan.md +64 -0
  165. package/inkos/packages/core/package.json +61 -0
  166. package/inkos/packages/core/src/__tests__/agent-max-tokens-policy.test.ts +29 -0
  167. package/inkos/packages/core/src/__tests__/agent-session.test.ts +866 -0
  168. package/inkos/packages/core/src/__tests__/agent-system-prompt.test.ts +167 -0
  169. package/inkos/packages/core/src/__tests__/agent-tools-params.test.ts +197 -0
  170. package/inkos/packages/core/src/__tests__/agent-tools.test.ts +421 -0
  171. package/inkos/packages/core/src/__tests__/ai-tells.test.ts +90 -0
  172. package/inkos/packages/core/src/__tests__/architect-phase5-consolidated.test.ts +445 -0
  173. package/inkos/packages/core/src/__tests__/architect-phase5.test.ts +455 -0
  174. package/inkos/packages/core/src/__tests__/architect-phase7.test.ts +210 -0
  175. package/inkos/packages/core/src/__tests__/architect.test.ts +859 -0
  176. package/inkos/packages/core/src/__tests__/audit-parse.test.ts +78 -0
  177. package/inkos/packages/core/src/__tests__/book-id.test.ts +26 -0
  178. package/inkos/packages/core/src/__tests__/book-session-store.test.ts +447 -0
  179. package/inkos/packages/core/src/__tests__/book-session.test.ts +113 -0
  180. package/inkos/packages/core/src/__tests__/chapter-analyzer.test.ts +574 -0
  181. package/inkos/packages/core/src/__tests__/chapter-memo-parser.test.ts +247 -0
  182. package/inkos/packages/core/src/__tests__/chapter-persistence.test.ts +198 -0
  183. package/inkos/packages/core/src/__tests__/chapter-review-cycle.test.ts +294 -0
  184. package/inkos/packages/core/src/__tests__/chapter-splitter.test.ts +156 -0
  185. package/inkos/packages/core/src/__tests__/chapter-state-recovery.test.ts +235 -0
  186. package/inkos/packages/core/src/__tests__/chapter-truth-validation.test.ts +253 -0
  187. package/inkos/packages/core/src/__tests__/composer.test.ts +627 -0
  188. package/inkos/packages/core/src/__tests__/config-loader.test.ts +325 -0
  189. package/inkos/packages/core/src/__tests__/config-migration.test.ts +102 -0
  190. package/inkos/packages/core/src/__tests__/consolidator.test.ts +32 -0
  191. package/inkos/packages/core/src/__tests__/context-filter.test.ts +60 -0
  192. package/inkos/packages/core/src/__tests__/context-transform.test.ts +108 -0
  193. package/inkos/packages/core/src/__tests__/continuity.test.ts +391 -0
  194. package/inkos/packages/core/src/__tests__/detection-insights.test.ts +59 -0
  195. package/inkos/packages/core/src/__tests__/detector.test.ts +86 -0
  196. package/inkos/packages/core/src/__tests__/draft-directive-parser.test.ts +386 -0
  197. package/inkos/packages/core/src/__tests__/edit-controller.test.ts +190 -0
  198. package/inkos/packages/core/src/__tests__/effective-llm-config.test.ts +486 -0
  199. package/inkos/packages/core/src/__tests__/fanfic-dimensions.test.ts +58 -0
  200. package/inkos/packages/core/src/__tests__/fanfic-models.test.ts +69 -0
  201. package/inkos/packages/core/src/__tests__/governed-working-set.test.ts +155 -0
  202. package/inkos/packages/core/src/__tests__/hook-arbiter.test.ts +124 -0
  203. package/inkos/packages/core/src/__tests__/hook-governance.test.ts +228 -0
  204. package/inkos/packages/core/src/__tests__/hook-health.test.ts +166 -0
  205. package/inkos/packages/core/src/__tests__/hook-ledger-validator.test.ts +236 -0
  206. package/inkos/packages/core/src/__tests__/hook-promotion.test.ts +192 -0
  207. package/inkos/packages/core/src/__tests__/hook-stale-detection.test.ts +136 -0
  208. package/inkos/packages/core/src/__tests__/index-notify-lazy.test.ts +20 -0
  209. package/inkos/packages/core/src/__tests__/interaction-chat-tokens.test.ts +170 -0
  210. package/inkos/packages/core/src/__tests__/interaction-models.test.ts +155 -0
  211. package/inkos/packages/core/src/__tests__/interaction-nl-router.test.ts +223 -0
  212. package/inkos/packages/core/src/__tests__/interaction-runtime.test.ts +633 -0
  213. package/inkos/packages/core/src/__tests__/interaction-tools.test.ts +343 -0
  214. package/inkos/packages/core/src/__tests__/length-metrics.test.ts +82 -0
  215. package/inkos/packages/core/src/__tests__/length-normalizer.test.ts +331 -0
  216. package/inkos/packages/core/src/__tests__/list-models.test.ts +109 -0
  217. package/inkos/packages/core/src/__tests__/llm-env.test.ts +31 -0
  218. package/inkos/packages/core/src/__tests__/logger.test.ts +175 -0
  219. package/inkos/packages/core/src/__tests__/long-span-fatigue.test.ts +160 -0
  220. package/inkos/packages/core/src/__tests__/memory-retrieval.test.ts +1303 -0
  221. package/inkos/packages/core/src/__tests__/models.test.ts +918 -0
  222. package/inkos/packages/core/src/__tests__/outline-paths.test.ts +97 -0
  223. package/inkos/packages/core/src/__tests__/path-safety.test.ts +22 -0
  224. package/inkos/packages/core/src/__tests__/persisted-governed-plan.test.ts +134 -0
  225. package/inkos/packages/core/src/__tests__/phase5-cleanup.test.ts +393 -0
  226. package/inkos/packages/core/src/__tests__/phase5-hotfix.test.ts +288 -0
  227. package/inkos/packages/core/src/__tests__/phase7-hotfix.test.ts +614 -0
  228. package/inkos/packages/core/src/__tests__/pipeline-agent.test.ts +354 -0
  229. package/inkos/packages/core/src/__tests__/pipeline-runner-memory-sync.test.ts +317 -0
  230. package/inkos/packages/core/src/__tests__/pipeline-runner.test.ts +5200 -0
  231. package/inkos/packages/core/src/__tests__/planner-context.test.ts +137 -0
  232. package/inkos/packages/core/src/__tests__/planner-prompts-ratio.test.ts +11 -0
  233. package/inkos/packages/core/src/__tests__/planner-prompts.test.ts +171 -0
  234. package/inkos/packages/core/src/__tests__/planner.test.ts +362 -0
  235. package/inkos/packages/core/src/__tests__/planning-materials.test.ts +90 -0
  236. package/inkos/packages/core/src/__tests__/polisher.test.ts +189 -0
  237. package/inkos/packages/core/src/__tests__/post-write-validator.test.ts +291 -0
  238. package/inkos/packages/core/src/__tests__/probe.test.ts +77 -0
  239. package/inkos/packages/core/src/__tests__/project-interaction.test.ts +241 -0
  240. package/inkos/packages/core/src/__tests__/provider.test.ts +953 -0
  241. package/inkos/packages/core/src/__tests__/providers-group.test.ts +34 -0
  242. package/inkos/packages/core/src/__tests__/providers-lookup.test.ts +81 -0
  243. package/inkos/packages/core/src/__tests__/providers-schema.test.ts +158 -0
  244. package/inkos/packages/core/src/__tests__/proxy-fetch.test.ts +75 -0
  245. package/inkos/packages/core/src/__tests__/revise-foundation.test.ts +514 -0
  246. package/inkos/packages/core/src/__tests__/reviser.test.ts +859 -0
  247. package/inkos/packages/core/src/__tests__/runtime-state-store.test.ts +388 -0
  248. package/inkos/packages/core/src/__tests__/scheduler.test.ts +123 -0
  249. package/inkos/packages/core/src/__tests__/secrets-migration.test.ts +71 -0
  250. package/inkos/packages/core/src/__tests__/secrets.test.ts +95 -0
  251. package/inkos/packages/core/src/__tests__/sensitive-words.test.ts +88 -0
  252. package/inkos/packages/core/src/__tests__/service-presets-regression.test.ts +73 -0
  253. package/inkos/packages/core/src/__tests__/service-resolver-regression.test.ts +75 -0
  254. package/inkos/packages/core/src/__tests__/service-resolver.test.ts +228 -0
  255. package/inkos/packages/core/src/__tests__/session-transcript-restore.test.ts +1311 -0
  256. package/inkos/packages/core/src/__tests__/session-transcript.test.ts +195 -0
  257. package/inkos/packages/core/src/__tests__/settler-delta-parser.test.ts +133 -0
  258. package/inkos/packages/core/src/__tests__/short-fiction-public.test.ts +241 -0
  259. package/inkos/packages/core/src/__tests__/spot-fix-patches.test.ts +104 -0
  260. package/inkos/packages/core/src/__tests__/state-manager.test.ts +1298 -0
  261. package/inkos/packages/core/src/__tests__/state-projections.test.ts +130 -0
  262. package/inkos/packages/core/src/__tests__/state-reducer.test.ts +372 -0
  263. package/inkos/packages/core/src/__tests__/state-validator-agent.test.ts +165 -0
  264. package/inkos/packages/core/src/__tests__/state-validator.test.ts +122 -0
  265. package/inkos/packages/core/src/__tests__/style-analyzer.test.ts +61 -0
  266. package/inkos/packages/core/src/__tests__/temperature-constraints.test.ts +57 -0
  267. package/inkos/packages/core/src/__tests__/v13-hotfix-round4.test.ts +343 -0
  268. package/inkos/packages/core/src/__tests__/verify-service.test.ts +77 -0
  269. package/inkos/packages/core/src/__tests__/webhook.test.ts +91 -0
  270. package/inkos/packages/core/src/__tests__/writer-parser.test.ts +348 -0
  271. package/inkos/packages/core/src/__tests__/writer-prompts.test.ts +269 -0
  272. package/inkos/packages/core/src/__tests__/writer.test.ts +1360 -0
  273. package/inkos/packages/core/src/agent/agent-session.ts +737 -0
  274. package/inkos/packages/core/src/agent/agent-system-prompt.ts +199 -0
  275. package/inkos/packages/core/src/agent/agent-tools.ts +835 -0
  276. package/inkos/packages/core/src/agent/context-transform.ts +85 -0
  277. package/inkos/packages/core/src/agent/index.ts +14 -0
  278. package/inkos/packages/core/src/agents/ai-tells.ts +161 -0
  279. package/inkos/packages/core/src/agents/architect.ts +1291 -0
  280. package/inkos/packages/core/src/agents/base.ts +100 -0
  281. package/inkos/packages/core/src/agents/chapter-analyzer.ts +634 -0
  282. package/inkos/packages/core/src/agents/composer.ts +469 -0
  283. package/inkos/packages/core/src/agents/consolidator.ts +218 -0
  284. package/inkos/packages/core/src/agents/continuity.ts +824 -0
  285. package/inkos/packages/core/src/agents/detection-insights.ts +72 -0
  286. package/inkos/packages/core/src/agents/detector.ts +224 -0
  287. package/inkos/packages/core/src/agents/en-prompt-sections.ts +129 -0
  288. package/inkos/packages/core/src/agents/fanfic-canon-importer.ts +146 -0
  289. package/inkos/packages/core/src/agents/fanfic-dimensions.ts +87 -0
  290. package/inkos/packages/core/src/agents/fanfic-prompt-sections.ts +109 -0
  291. package/inkos/packages/core/src/agents/foundation-reviewer.ts +204 -0
  292. package/inkos/packages/core/src/agents/length-normalizer.ts +218 -0
  293. package/inkos/packages/core/src/agents/observer-prompts.ts +127 -0
  294. package/inkos/packages/core/src/agents/planner-context.ts +297 -0
  295. package/inkos/packages/core/src/agents/planner-prompts.ts +404 -0
  296. package/inkos/packages/core/src/agents/planner.ts +783 -0
  297. package/inkos/packages/core/src/agents/polisher.ts +153 -0
  298. package/inkos/packages/core/src/agents/post-write-validator.ts +873 -0
  299. package/inkos/packages/core/src/agents/radar-source.ts +123 -0
  300. package/inkos/packages/core/src/agents/radar.ts +120 -0
  301. package/inkos/packages/core/src/agents/reviser.ts +701 -0
  302. package/inkos/packages/core/src/agents/rules-reader.ts +155 -0
  303. package/inkos/packages/core/src/agents/sensitive-words.ts +142 -0
  304. package/inkos/packages/core/src/agents/settler-delta-parser.ts +53 -0
  305. package/inkos/packages/core/src/agents/settler-parser.ts +38 -0
  306. package/inkos/packages/core/src/agents/settler-prompts.ts +230 -0
  307. package/inkos/packages/core/src/agents/short-fiction.ts +429 -0
  308. package/inkos/packages/core/src/agents/state-validator.ts +322 -0
  309. package/inkos/packages/core/src/agents/style-analyzer.ts +93 -0
  310. package/inkos/packages/core/src/agents/writer-parser.ts +178 -0
  311. package/inkos/packages/core/src/agents/writer-prompts.ts +899 -0
  312. package/inkos/packages/core/src/agents/writer.ts +1450 -0
  313. package/inkos/packages/core/src/index.ts +392 -0
  314. package/inkos/packages/core/src/interaction/book-session-store.ts +226 -0
  315. package/inkos/packages/core/src/interaction/draft-directive-parser.ts +266 -0
  316. package/inkos/packages/core/src/interaction/edit-controller.ts +270 -0
  317. package/inkos/packages/core/src/interaction/events.ts +41 -0
  318. package/inkos/packages/core/src/interaction/export-artifact.ts +151 -0
  319. package/inkos/packages/core/src/interaction/intents.ts +63 -0
  320. package/inkos/packages/core/src/interaction/modes.ts +13 -0
  321. package/inkos/packages/core/src/interaction/nl-router.ts +258 -0
  322. package/inkos/packages/core/src/interaction/project-control.ts +150 -0
  323. package/inkos/packages/core/src/interaction/project-session-store.ts +81 -0
  324. package/inkos/packages/core/src/interaction/project-tools.ts +704 -0
  325. package/inkos/packages/core/src/interaction/request-router.ts +5 -0
  326. package/inkos/packages/core/src/interaction/runtime.ts +1167 -0
  327. package/inkos/packages/core/src/interaction/session-transcript-legacy.ts +113 -0
  328. package/inkos/packages/core/src/interaction/session-transcript-restore.ts +607 -0
  329. package/inkos/packages/core/src/interaction/session-transcript-schema.ts +76 -0
  330. package/inkos/packages/core/src/interaction/session-transcript.ts +189 -0
  331. package/inkos/packages/core/src/interaction/session.ts +226 -0
  332. package/inkos/packages/core/src/interaction/truth-authority.ts +45 -0
  333. package/inkos/packages/core/src/llm/config-migration.ts +58 -0
  334. package/inkos/packages/core/src/llm/cover-providers.ts +45 -0
  335. package/inkos/packages/core/src/llm/provider.ts +1331 -0
  336. package/inkos/packages/core/src/llm/providers/endpoints/ai360.ts +42 -0
  337. package/inkos/packages/core/src/llm/providers/endpoints/anthropic.ts +82 -0
  338. package/inkos/packages/core/src/llm/providers/endpoints/astronCodingPlan.ts +30 -0
  339. package/inkos/packages/core/src/llm/providers/endpoints/baichuan.ts +28 -0
  340. package/inkos/packages/core/src/llm/providers/endpoints/bailian.ts +65 -0
  341. package/inkos/packages/core/src/llm/providers/endpoints/bailianCodingPlan.ts +30 -0
  342. package/inkos/packages/core/src/llm/providers/endpoints/custom.ts +22 -0
  343. package/inkos/packages/core/src/llm/providers/endpoints/deepseek.ts +35 -0
  344. package/inkos/packages/core/src/llm/providers/endpoints/giteeai.ts +41 -0
  345. package/inkos/packages/core/src/llm/providers/endpoints/githubCopilot.ts +43 -0
  346. package/inkos/packages/core/src/llm/providers/endpoints/glmCodingPlan.ts +28 -0
  347. package/inkos/packages/core/src/llm/providers/endpoints/google.ts +51 -0
  348. package/inkos/packages/core/src/llm/providers/endpoints/hunyuan.ts +42 -0
  349. package/inkos/packages/core/src/llm/providers/endpoints/infiniai.ts +72 -0
  350. package/inkos/packages/core/src/llm/providers/endpoints/internlm.ts +28 -0
  351. package/inkos/packages/core/src/llm/providers/endpoints/kimiCode.ts +23 -0
  352. package/inkos/packages/core/src/llm/providers/endpoints/kimiCodingPlan.ts +24 -0
  353. package/inkos/packages/core/src/llm/providers/endpoints/kkaiapi.ts +56 -0
  354. package/inkos/packages/core/src/llm/providers/endpoints/longcat.ts +25 -0
  355. package/inkos/packages/core/src/llm/providers/endpoints/minimax.ts +39 -0
  356. package/inkos/packages/core/src/llm/providers/endpoints/minimaxCodingPlan.ts +28 -0
  357. package/inkos/packages/core/src/llm/providers/endpoints/mistral.ts +40 -0
  358. package/inkos/packages/core/src/llm/providers/endpoints/modelscope.ts +30 -0
  359. package/inkos/packages/core/src/llm/providers/endpoints/moonshot.ts +39 -0
  360. package/inkos/packages/core/src/llm/providers/endpoints/newapi.ts +21 -0
  361. package/inkos/packages/core/src/llm/providers/endpoints/ollama.ts +73 -0
  362. package/inkos/packages/core/src/llm/providers/endpoints/openai.ts +77 -0
  363. package/inkos/packages/core/src/llm/providers/endpoints/opencodeCodingPlan.ts +30 -0
  364. package/inkos/packages/core/src/llm/providers/endpoints/openrouter.ts +87 -0
  365. package/inkos/packages/core/src/llm/providers/endpoints/ppio.ts +86 -0
  366. package/inkos/packages/core/src/llm/providers/endpoints/qiniu.ts +32 -0
  367. package/inkos/packages/core/src/llm/providers/endpoints/sensenova.ts +45 -0
  368. package/inkos/packages/core/src/llm/providers/endpoints/siliconcloud.ts +126 -0
  369. package/inkos/packages/core/src/llm/providers/endpoints/spark.ts +33 -0
  370. package/inkos/packages/core/src/llm/providers/endpoints/stepfun.ts +35 -0
  371. package/inkos/packages/core/src/llm/providers/endpoints/tencentcloud.ts +25 -0
  372. package/inkos/packages/core/src/llm/providers/endpoints/volcengine.ts +52 -0
  373. package/inkos/packages/core/src/llm/providers/endpoints/volcengineCodingPlan.ts +42 -0
  374. package/inkos/packages/core/src/llm/providers/endpoints/wenxin.ts +106 -0
  375. package/inkos/packages/core/src/llm/providers/endpoints/xai.ts +34 -0
  376. package/inkos/packages/core/src/llm/providers/endpoints/xiaomimimo.ts +26 -0
  377. package/inkos/packages/core/src/llm/providers/endpoints/zeroone.ts +34 -0
  378. package/inkos/packages/core/src/llm/providers/endpoints/zhipu.ts +61 -0
  379. package/inkos/packages/core/src/llm/providers/index.ts +71 -0
  380. package/inkos/packages/core/src/llm/providers/lookup.ts +70 -0
  381. package/inkos/packages/core/src/llm/providers/probe.ts +35 -0
  382. package/inkos/packages/core/src/llm/providers/types.ts +89 -0
  383. package/inkos/packages/core/src/llm/providers/verify.ts +104 -0
  384. package/inkos/packages/core/src/llm/secrets.ts +77 -0
  385. package/inkos/packages/core/src/llm/service-presets.ts +215 -0
  386. package/inkos/packages/core/src/llm/service-resolver.ts +91 -0
  387. package/inkos/packages/core/src/models/book-rules.ts +126 -0
  388. package/inkos/packages/core/src/models/book.ts +70 -0
  389. package/inkos/packages/core/src/models/chapter.ts +42 -0
  390. package/inkos/packages/core/src/models/detection.ts +25 -0
  391. package/inkos/packages/core/src/models/genre-profile.ts +36 -0
  392. package/inkos/packages/core/src/models/input-governance.ts +99 -0
  393. package/inkos/packages/core/src/models/length-governance.ts +46 -0
  394. package/inkos/packages/core/src/models/project.ts +161 -0
  395. package/inkos/packages/core/src/models/runtime-state.ts +144 -0
  396. package/inkos/packages/core/src/models/state.ts +52 -0
  397. package/inkos/packages/core/src/models/style-profile.ts +15 -0
  398. package/inkos/packages/core/src/notify/dispatcher.ts +96 -0
  399. package/inkos/packages/core/src/notify/feishu.ts +34 -0
  400. package/inkos/packages/core/src/notify/telegram.ts +25 -0
  401. package/inkos/packages/core/src/notify/webhook.ts +58 -0
  402. package/inkos/packages/core/src/notify/wechat-work.ts +22 -0
  403. package/inkos/packages/core/src/pipeline/agent.ts +691 -0
  404. package/inkos/packages/core/src/pipeline/chapter-persistence.ts +79 -0
  405. package/inkos/packages/core/src/pipeline/chapter-review-cycle.ts +324 -0
  406. package/inkos/packages/core/src/pipeline/chapter-state-recovery.ts +236 -0
  407. package/inkos/packages/core/src/pipeline/chapter-truth-validation.ts +145 -0
  408. package/inkos/packages/core/src/pipeline/detection-runner.ts +164 -0
  409. package/inkos/packages/core/src/pipeline/persisted-governed-plan.ts +216 -0
  410. package/inkos/packages/core/src/pipeline/runner.ts +3438 -0
  411. package/inkos/packages/core/src/pipeline/scheduler.ts +411 -0
  412. package/inkos/packages/core/src/pipeline/short-fiction-runner.ts +801 -0
  413. package/inkos/packages/core/src/prompts/index.ts +1 -0
  414. package/inkos/packages/core/src/prompts/short-fiction.ts +273 -0
  415. package/inkos/packages/core/src/state/manager.ts +560 -0
  416. package/inkos/packages/core/src/state/memory-db.ts +359 -0
  417. package/inkos/packages/core/src/state/runtime-state-store.ts +164 -0
  418. package/inkos/packages/core/src/state/state-bootstrap.ts +657 -0
  419. package/inkos/packages/core/src/state/state-projections.ts +255 -0
  420. package/inkos/packages/core/src/state/state-reducer.ts +260 -0
  421. package/inkos/packages/core/src/state/state-validator.ts +117 -0
  422. package/inkos/packages/core/src/utils/analytics.ts +92 -0
  423. package/inkos/packages/core/src/utils/book-id.ts +31 -0
  424. package/inkos/packages/core/src/utils/cadence-policy.ts +46 -0
  425. package/inkos/packages/core/src/utils/chapter-cadence.ts +211 -0
  426. package/inkos/packages/core/src/utils/chapter-memo-parser.ts +157 -0
  427. package/inkos/packages/core/src/utils/chapter-splitter.ts +80 -0
  428. package/inkos/packages/core/src/utils/config-loader.ts +29 -0
  429. package/inkos/packages/core/src/utils/context-assembly.ts +98 -0
  430. package/inkos/packages/core/src/utils/context-filter.ts +190 -0
  431. package/inkos/packages/core/src/utils/effective-llm-config.ts +529 -0
  432. package/inkos/packages/core/src/utils/governed-context.ts +101 -0
  433. package/inkos/packages/core/src/utils/governed-working-set.ts +395 -0
  434. package/inkos/packages/core/src/utils/hook-arbiter.ts +332 -0
  435. package/inkos/packages/core/src/utils/hook-governance.ts +199 -0
  436. package/inkos/packages/core/src/utils/hook-health.ts +189 -0
  437. package/inkos/packages/core/src/utils/hook-ledger-validator.ts +277 -0
  438. package/inkos/packages/core/src/utils/hook-lifecycle.ts +224 -0
  439. package/inkos/packages/core/src/utils/hook-policy.ts +115 -0
  440. package/inkos/packages/core/src/utils/hook-promotion.ts +313 -0
  441. package/inkos/packages/core/src/utils/hook-stale-detection.ts +168 -0
  442. package/inkos/packages/core/src/utils/length-metrics.ts +123 -0
  443. package/inkos/packages/core/src/utils/llm-endpoint-auth.ts +40 -0
  444. package/inkos/packages/core/src/utils/llm-env.ts +74 -0
  445. package/inkos/packages/core/src/utils/logger.ts +123 -0
  446. package/inkos/packages/core/src/utils/long-span-fatigue.ts +545 -0
  447. package/inkos/packages/core/src/utils/memory-retrieval.ts +527 -0
  448. package/inkos/packages/core/src/utils/narrative-control.ts +177 -0
  449. package/inkos/packages/core/src/utils/outline-paths.ts +275 -0
  450. package/inkos/packages/core/src/utils/path-safety.ts +11 -0
  451. package/inkos/packages/core/src/utils/planning-materials.ts +185 -0
  452. package/inkos/packages/core/src/utils/pov-filter.ts +149 -0
  453. package/inkos/packages/core/src/utils/proxy-fetch.ts +44 -0
  454. package/inkos/packages/core/src/utils/runtime-writer.ts +41 -0
  455. package/inkos/packages/core/src/utils/spot-fix-patches.ts +189 -0
  456. package/inkos/packages/core/src/utils/story-markdown.ts +346 -0
  457. package/inkos/packages/core/src/utils/web-search.ts +82 -0
  458. package/inkos/packages/core/src/utils/writing-methodology.ts +164 -0
  459. package/inkos/packages/core/tsconfig.json +8 -0
  460. package/inkos/packages/core/vitest.config.ts +7 -0
  461. package/inkos/packages/studio/components.json +25 -0
  462. package/inkos/packages/studio/index.html +13 -0
  463. package/inkos/packages/studio/package.json +72 -0
  464. package/inkos/packages/studio/postcss.config.js +3 -0
  465. package/inkos/packages/studio/src/App.test.ts +25 -0
  466. package/inkos/packages/studio/src/App.tsx +280 -0
  467. package/inkos/packages/studio/src/api/__tests__/normalize-base-url.test.ts +40 -0
  468. package/inkos/packages/studio/src/api/book-create.test.ts +104 -0
  469. package/inkos/packages/studio/src/api/book-create.ts +94 -0
  470. package/inkos/packages/studio/src/api/errors.ts +17 -0
  471. package/inkos/packages/studio/src/api/index.ts +30 -0
  472. package/inkos/packages/studio/src/api/lib/run-store.ts +177 -0
  473. package/inkos/packages/studio/src/api/lib/sse.ts +50 -0
  474. package/inkos/packages/studio/src/api/phase5-hotfix.test.ts +335 -0
  475. package/inkos/packages/studio/src/api/safety.ts +6 -0
  476. package/inkos/packages/studio/src/api/server.test.ts +3162 -0
  477. package/inkos/packages/studio/src/api/server.ts +3666 -0
  478. package/inkos/packages/studio/src/api/v13-hotfix-round4.test.ts +226 -0
  479. package/inkos/packages/studio/src/app-state.test.ts +8 -0
  480. package/inkos/packages/studio/src/app-state.ts +1 -0
  481. package/inkos/packages/studio/src/components/ConfirmDialog.tsx +95 -0
  482. package/inkos/packages/studio/src/components/ServiceConfigSourceCard.tsx +139 -0
  483. package/inkos/packages/studio/src/components/ServiceQuickLinks.tsx +65 -0
  484. package/inkos/packages/studio/src/components/Sidebar.tsx +652 -0
  485. package/inkos/packages/studio/src/components/ai-elements/code-block.tsx +562 -0
  486. package/inkos/packages/studio/src/components/ai-elements/confirmation.tsx +174 -0
  487. package/inkos/packages/studio/src/components/ai-elements/message.tsx +360 -0
  488. package/inkos/packages/studio/src/components/ai-elements/prompt-input.tsx +1457 -0
  489. package/inkos/packages/studio/src/components/ai-elements/reasoning.tsx +226 -0
  490. package/inkos/packages/studio/src/components/ai-elements/shimmer.tsx +77 -0
  491. package/inkos/packages/studio/src/components/ai-elements/tool.tsx +173 -0
  492. package/inkos/packages/studio/src/components/chat/BookSidebar.tsx +291 -0
  493. package/inkos/packages/studio/src/components/chat/ChatMessage.tsx +39 -0
  494. package/inkos/packages/studio/src/components/chat/QuickActions.tsx +73 -0
  495. package/inkos/packages/studio/src/components/chat/ToolExecutionSteps.tsx +320 -0
  496. package/inkos/packages/studio/src/components/chat/__tests__/ToolExecutionSteps.test.ts +114 -0
  497. package/inkos/packages/studio/src/components/chat-utils.ts +56 -0
  498. package/inkos/packages/studio/src/components/chatbar-state.test.ts +69 -0
  499. package/inkos/packages/studio/src/components/sidebar/ChaptersSection.tsx +66 -0
  500. package/inkos/packages/studio/src/components/sidebar/CharacterSection.tsx +129 -0
  501. package/inkos/packages/studio/src/components/sidebar/FoundationSection.tsx +61 -0
  502. package/inkos/packages/studio/src/components/sidebar/ProgressSection.tsx +124 -0
  503. package/inkos/packages/studio/src/components/sidebar/SidebarCard.tsx +30 -0
  504. package/inkos/packages/studio/src/components/sidebar/SummarySection.tsx +89 -0
  505. package/inkos/packages/studio/src/components/ui/alert.tsx +76 -0
  506. package/inkos/packages/studio/src/components/ui/badge.tsx +52 -0
  507. package/inkos/packages/studio/src/components/ui/button-group.tsx +87 -0
  508. package/inkos/packages/studio/src/components/ui/button.tsx +58 -0
  509. package/inkos/packages/studio/src/components/ui/collapsible.tsx +19 -0
  510. package/inkos/packages/studio/src/components/ui/command.tsx +194 -0
  511. package/inkos/packages/studio/src/components/ui/dialog.tsx +158 -0
  512. package/inkos/packages/studio/src/components/ui/dropdown-menu.tsx +266 -0
  513. package/inkos/packages/studio/src/components/ui/hover-card.tsx +51 -0
  514. package/inkos/packages/studio/src/components/ui/input-group.tsx +158 -0
  515. package/inkos/packages/studio/src/components/ui/input.tsx +20 -0
  516. package/inkos/packages/studio/src/components/ui/select.tsx +199 -0
  517. package/inkos/packages/studio/src/components/ui/separator.tsx +23 -0
  518. package/inkos/packages/studio/src/components/ui/spinner.tsx +10 -0
  519. package/inkos/packages/studio/src/components/ui/textarea.tsx +18 -0
  520. package/inkos/packages/studio/src/components/ui/tooltip.tsx +66 -0
  521. package/inkos/packages/studio/src/constants/service-groups.ts +29 -0
  522. package/inkos/packages/studio/src/hooks/use-api.test.ts +93 -0
  523. package/inkos/packages/studio/src/hooks/use-api.ts +189 -0
  524. package/inkos/packages/studio/src/hooks/use-book-activity.test.ts +129 -0
  525. package/inkos/packages/studio/src/hooks/use-book-activity.ts +180 -0
  526. package/inkos/packages/studio/src/hooks/use-colors.ts +27 -0
  527. package/inkos/packages/studio/src/hooks/use-hash-route.test.ts +101 -0
  528. package/inkos/packages/studio/src/hooks/use-hash-route.ts +89 -0
  529. package/inkos/packages/studio/src/hooks/use-i18n.ts +289 -0
  530. package/inkos/packages/studio/src/hooks/use-session-events.ts +64 -0
  531. package/inkos/packages/studio/src/hooks/use-sse.test.ts +52 -0
  532. package/inkos/packages/studio/src/hooks/use-sse.ts +92 -0
  533. package/inkos/packages/studio/src/hooks/use-theme.test.ts +31 -0
  534. package/inkos/packages/studio/src/hooks/use-theme.ts +75 -0
  535. package/inkos/packages/studio/src/index.css +323 -0
  536. package/inkos/packages/studio/src/lib/error-copy.test.ts +34 -0
  537. package/inkos/packages/studio/src/lib/error-copy.ts +37 -0
  538. package/inkos/packages/studio/src/lib/utils.ts +6 -0
  539. package/inkos/packages/studio/src/main.tsx +10 -0
  540. package/inkos/packages/studio/src/pages/Analytics.tsx +80 -0
  541. package/inkos/packages/studio/src/pages/BookCreate.tsx +895 -0
  542. package/inkos/packages/studio/src/pages/BookDetail.tsx +652 -0
  543. package/inkos/packages/studio/src/pages/ChapterReader.tsx +266 -0
  544. package/inkos/packages/studio/src/pages/ChatPage.tsx +521 -0
  545. package/inkos/packages/studio/src/pages/DaemonControl.tsx +116 -0
  546. package/inkos/packages/studio/src/pages/Dashboard.tsx +379 -0
  547. package/inkos/packages/studio/src/pages/DoctorView.tsx +82 -0
  548. package/inkos/packages/studio/src/pages/GenreManager.tsx +464 -0
  549. package/inkos/packages/studio/src/pages/ImportManager.tsx +216 -0
  550. package/inkos/packages/studio/src/pages/LanguageSelector.tsx +74 -0
  551. package/inkos/packages/studio/src/pages/LogViewer.tsx +82 -0
  552. package/inkos/packages/studio/src/pages/RadarView.tsx +157 -0
  553. package/inkos/packages/studio/src/pages/ServiceDetailPage.tsx +393 -0
  554. package/inkos/packages/studio/src/pages/ServiceListPage.tsx +463 -0
  555. package/inkos/packages/studio/src/pages/StyleManager.tsx +225 -0
  556. package/inkos/packages/studio/src/pages/TruthFiles.tsx +194 -0
  557. package/inkos/packages/studio/src/pages/chat-page-state.test.ts +206 -0
  558. package/inkos/packages/studio/src/pages/chat-page-state.ts +112 -0
  559. package/inkos/packages/studio/src/pages/page-state.test.ts +258 -0
  560. package/inkos/packages/studio/src/pages/service-detail-state.test.ts +294 -0
  561. package/inkos/packages/studio/src/pages/service-detail-state.ts +234 -0
  562. package/inkos/packages/studio/src/pages/style-manager-state.test.ts +22 -0
  563. package/inkos/packages/studio/src/pages/truth-files-state.test.ts +61 -0
  564. package/inkos/packages/studio/src/shared/contracts.ts +143 -0
  565. package/inkos/packages/studio/src/store/chat/__tests__/message-parts.test.ts +172 -0
  566. package/inkos/packages/studio/src/store/chat/index.ts +3 -0
  567. package/inkos/packages/studio/src/store/chat/initialState.ts +8 -0
  568. package/inkos/packages/studio/src/store/chat/message-policy.test.ts +16 -0
  569. package/inkos/packages/studio/src/store/chat/message-policy.ts +5 -0
  570. package/inkos/packages/studio/src/store/chat/parts-builder.ts +187 -0
  571. package/inkos/packages/studio/src/store/chat/selectors.ts +13 -0
  572. package/inkos/packages/studio/src/store/chat/slices/create/action.ts +10 -0
  573. package/inkos/packages/studio/src/store/chat/slices/create/initialState.ts +9 -0
  574. package/inkos/packages/studio/src/store/chat/slices/message/action.ts +417 -0
  575. package/inkos/packages/studio/src/store/chat/slices/message/initialState.ts +10 -0
  576. package/inkos/packages/studio/src/store/chat/slices/message/runtime.test.ts +21 -0
  577. package/inkos/packages/studio/src/store/chat/slices/message/runtime.ts +233 -0
  578. package/inkos/packages/studio/src/store/chat/slices/message/stream-events.ts +272 -0
  579. package/inkos/packages/studio/src/store/chat/store.ts +11 -0
  580. package/inkos/packages/studio/src/store/chat/types.ts +169 -0
  581. package/inkos/packages/studio/src/store/service/index.ts +2 -0
  582. package/inkos/packages/studio/src/store/service/store.ts +123 -0
  583. package/inkos/packages/studio/src/store/service/types.ts +50 -0
  584. package/inkos/packages/studio/tsconfig.json +24 -0
  585. package/inkos/packages/studio/tsconfig.server.json +11 -0
  586. package/inkos/packages/studio/vite.config.ts +34 -0
  587. package/inkos/packages/studio/vitest.config.ts +14 -0
  588. package/inkos/pnpm-lock.yaml +9569 -0
  589. package/inkos/pnpm-workspace.yaml +2 -0
  590. package/inkos/scripts/prepare-package-for-publish.mjs +135 -0
  591. package/inkos/scripts/restore-package-json.mjs +31 -0
  592. package/inkos/scripts/set-package-versions.mjs +74 -0
  593. package/inkos/scripts/verify-no-workspace-protocol.mjs +140 -0
  594. package/inkos/skills/SKILL.md +654 -0
  595. package/inkos/tsconfig.json +19 -0
  596. package/package.json +4 -3
  597. /package/.next/static/{F2hMZMf1IyCVAWpkbtRz7 → -3vIrBZXdQ0rp7Wa3Kz40}/_buildManifest.js +0 -0
  598. /package/.next/static/{F2hMZMf1IyCVAWpkbtRz7 → -3vIrBZXdQ0rp7Wa3Kz40}/_ssgManifest.js +0 -0
@@ -0,0 +1,183 @@
1
+ import { Command } from "commander";
2
+ import { readFile, readdir, stat } from "node:fs/promises";
3
+ import { join, resolve, basename } from "node:path";
4
+ import { deriveBookIdFromTitle, normalizePlatformOrOther, PipelineRunner, type BookConfig, type FanficMode } from "@actalk/inkos-core";
5
+ import { loadConfig, buildPipelineConfig, findProjectRoot, resolveBookId, log, logError } from "../utils.js";
6
+
7
+ export const fanficCommand = new Command("fanfic")
8
+ .description("Fan fiction writing tools (同人创作)");
9
+
10
+ fanficCommand
11
+ .command("init")
12
+ .description("Create a fanfic book from external source material")
13
+ .requiredOption("--title <title>", "Book title")
14
+ .requiredOption("--from <path>", "Source file or directory (novel text, wiki, character docs)")
15
+ .option("--mode <mode>", "Fanfic mode: canon|au|ooc|cp", "canon")
16
+ .option("--genre <genre>", "Genre", "other")
17
+ .option("--platform <platform>", "Target platform", "other")
18
+ .option("--target-chapters <n>", "Target chapter count", "100")
19
+ .option("--chapter-words <n>", "Words per chapter", "3000")
20
+ .option("--lang <language>", "Writing language: zh or en. Defaults from genre.")
21
+ .option("--json", "Output JSON")
22
+ .action(async (opts) => {
23
+ try {
24
+ const config = await loadConfig();
25
+ const root = findProjectRoot();
26
+
27
+ const mode = opts.mode as FanficMode;
28
+ if (!["canon", "au", "ooc", "cp"].includes(mode)) {
29
+ throw new Error(`无效的同人模式:"${mode}"。可选:canon, au, ooc, cp`);
30
+ }
31
+
32
+ // Read source material
33
+ const sourcePath = resolve(opts.from);
34
+ const sourceText = await readSourceMaterial(sourcePath);
35
+ const sourceName = basename(sourcePath);
36
+
37
+ if (!sourceText || sourceText.length < 100) {
38
+ throw new Error(`源素材文件内容过短(${sourceText.length} 字符)。请提供至少 100 字符的原作素材。`);
39
+ }
40
+
41
+ const bookId = deriveBookIdFromTitle(opts.title) || `book-${Date.now().toString(36)}`;
42
+
43
+ const now = new Date().toISOString();
44
+ const book: BookConfig = {
45
+ id: bookId,
46
+ title: opts.title,
47
+ platform: normalizePlatformOrOther(opts.platform),
48
+ genre: opts.genre,
49
+ status: "outlining",
50
+ targetChapters: parseInt(opts.targetChapters, 10),
51
+ chapterWordCount: parseInt(opts.chapterWords, 10),
52
+ language: opts.lang ?? config.language,
53
+ createdAt: now,
54
+ updatedAt: now,
55
+ fanficMode: mode,
56
+ };
57
+
58
+ if (!opts.json) log(`Creating fanfic "${book.title}" (${mode} mode, ${book.genre})...`);
59
+ if (!opts.json) log(` Source: ${sourceName} (${sourceText.length} chars)`);
60
+
61
+ const pipeline = new PipelineRunner(buildPipelineConfig(config, root));
62
+ await pipeline.initFanficBook(book, sourceText, sourceName, mode);
63
+
64
+ if (opts.json) {
65
+ log(JSON.stringify({
66
+ bookId,
67
+ title: book.title,
68
+ genre: book.genre,
69
+ fanficMode: mode,
70
+ source: sourceName,
71
+ location: `books/${bookId}/`,
72
+ nextStep: `inkos write next ${bookId}`,
73
+ }, null, 2));
74
+ } else {
75
+ log(`Fanfic created: ${bookId}`);
76
+ log(` Mode: ${mode}`);
77
+ log(` Location: books/${bookId}/`);
78
+ log(` fanfic_canon.md + foundation generated.`);
79
+ log("");
80
+ log(`Next: inkos write next ${bookId}`);
81
+ }
82
+ } catch (e) {
83
+ if (opts.json) {
84
+ log(JSON.stringify({ error: String(e) }));
85
+ } else {
86
+ logError(`Failed to create fanfic: ${e}`);
87
+ }
88
+ process.exit(1);
89
+ }
90
+ });
91
+
92
+ fanficCommand
93
+ .command("show")
94
+ .description("Display parsed fanfic canon")
95
+ .argument("[book-id]", "Book ID (auto-detected if only one book)")
96
+ .option("--json", "Output JSON")
97
+ .action(async (bookIdArg: string | undefined, opts) => {
98
+ try {
99
+ await loadConfig();
100
+ const root = findProjectRoot();
101
+ const bookId = await resolveBookId(bookIdArg, root);
102
+ const { StateManager } = await import("@actalk/inkos-core");
103
+ const state = new StateManager(root);
104
+ const bookDir = state.bookDir(bookId);
105
+
106
+ let canon: string;
107
+ try {
108
+ canon = await readFile(join(bookDir, "story/fanfic_canon.md"), "utf-8");
109
+ } catch {
110
+ throw new Error(`该书没有同人正典文件。用 inkos fanfic init 创建同人书。`);
111
+ }
112
+
113
+ if (opts.json) {
114
+ log(JSON.stringify({ bookId, fanficCanon: canon }, null, 2));
115
+ } else {
116
+ log(`Fanfic Canon for "${bookId}":\n`);
117
+ log(canon);
118
+ }
119
+ } catch (e) {
120
+ if (opts.json) {
121
+ log(JSON.stringify({ error: String(e) }));
122
+ } else {
123
+ logError(String(e));
124
+ }
125
+ process.exit(1);
126
+ }
127
+ });
128
+
129
+ fanficCommand
130
+ .command("refresh")
131
+ .description("Re-import source material and regenerate fanfic canon")
132
+ .argument("[book-id]", "Book ID (auto-detected if only one book)")
133
+ .requiredOption("--from <path>", "Source file or directory")
134
+ .option("--json", "Output JSON")
135
+ .action(async (bookIdArg: string | undefined, opts) => {
136
+ try {
137
+ const config = await loadConfig();
138
+ const root = findProjectRoot();
139
+ const bookId = await resolveBookId(bookIdArg, root);
140
+ const { StateManager } = await import("@actalk/inkos-core");
141
+ const state = new StateManager(root);
142
+ const book = await state.loadBookConfig(bookId);
143
+
144
+ const mode = (book.fanficMode ?? "canon") as FanficMode;
145
+ const sourcePath = resolve(opts.from);
146
+ const sourceText = await readSourceMaterial(sourcePath);
147
+ const sourceName = basename(sourcePath);
148
+
149
+ if (!opts.json) log(`Refreshing fanfic canon for "${bookId}" from ${sourceName}...`);
150
+
151
+ const pipeline = new PipelineRunner(buildPipelineConfig(config, root));
152
+ await pipeline.importFanficCanon(bookId, sourceText, sourceName, mode);
153
+
154
+ if (opts.json) {
155
+ log(JSON.stringify({ bookId, source: sourceName, refreshedAt: new Date().toISOString() }));
156
+ } else {
157
+ log(`Canon refreshed from "${sourceName}".`);
158
+ }
159
+ } catch (e) {
160
+ if (opts.json) {
161
+ log(JSON.stringify({ error: String(e) }));
162
+ } else {
163
+ logError(`Failed to refresh canon: ${e}`);
164
+ }
165
+ process.exit(1);
166
+ }
167
+ });
168
+
169
+ async function readSourceMaterial(sourcePath: string): Promise<string> {
170
+ const s = await stat(sourcePath);
171
+ if (s.isDirectory()) {
172
+ const files = await readdir(sourcePath);
173
+ const textFiles = files.filter((f) => f.endsWith(".txt") || f.endsWith(".md"));
174
+ if (textFiles.length === 0) {
175
+ throw new Error(`目录 ${sourcePath} 中没有 .txt 或 .md 文件。`);
176
+ }
177
+ const contents = await Promise.all(
178
+ textFiles.sort().map((f) => readFile(join(sourcePath, f), "utf-8")),
179
+ );
180
+ return contents.join("\n\n---\n\n");
181
+ }
182
+ return readFile(sourcePath, "utf-8");
183
+ }
@@ -0,0 +1,160 @@
1
+ import { Command } from "commander";
2
+ import { writeFile, mkdir, readFile } from "node:fs/promises";
3
+ import { join } from "node:path";
4
+ import { listAvailableGenres, readGenreProfile, getBuiltinGenresDir } from "@actalk/inkos-core";
5
+ import { findProjectRoot, log, logError } from "../utils.js";
6
+
7
+ export const genreCommand = new Command("genre")
8
+ .description("Manage genre profiles");
9
+
10
+ genreCommand
11
+ .command("list")
12
+ .description("List all available genre profiles (built-in + project)")
13
+ .action(async () => {
14
+ try {
15
+ const root = findProjectRoot();
16
+ const genres = await listAvailableGenres(root);
17
+
18
+ if (genres.length === 0) {
19
+ log("No genre profiles found.");
20
+ return;
21
+ }
22
+
23
+ log("Available genres:\n");
24
+ for (const g of genres) {
25
+ const tag = g.source === "project" ? "[project]" : "[builtin]";
26
+ log(` ${g.id.padEnd(12)} ${g.name.padEnd(8)} ${tag}`);
27
+ }
28
+ log(`\nTotal: ${genres.length} genre(s)`);
29
+ } catch (e) {
30
+ logError(`Failed to list genres: ${e}`);
31
+ process.exit(1);
32
+ }
33
+ });
34
+
35
+ genreCommand
36
+ .command("show")
37
+ .description("Display a genre profile")
38
+ .argument("<id>", "Genre ID (e.g. xuanhuan, urban, horror)")
39
+ .action(async (id: string) => {
40
+ try {
41
+ const root = findProjectRoot();
42
+ const genres = await listAvailableGenres(root);
43
+ const exactMatch = genres.some(g => g.id === id);
44
+ if (!exactMatch) {
45
+ logError(`Genre "${id}" not found. Available: ${genres.map(g => g.id).join(", ")}`);
46
+ process.exit(1);
47
+ }
48
+ const { profile, body } = await readGenreProfile(root, id);
49
+
50
+ log(`Genre: ${profile.name} (${profile.id})\n`);
51
+ log(` Chapter types: ${profile.chapterTypes.join(", ")}`);
52
+ log(` Fatigue words: ${profile.fatigueWords.join(", ")}`);
53
+ log(` Numerical system: ${profile.numericalSystem}`);
54
+ log(` Power scaling: ${profile.powerScaling}`);
55
+ log(` Era research: ${profile.eraResearch}`);
56
+ log(` Pacing rule: ${profile.pacingRule}`);
57
+ log(` Satisfaction types: ${profile.satisfactionTypes.join(", ")}`);
58
+ log(` Audit dimensions: ${profile.auditDimensions.join(", ")}`);
59
+
60
+ if (body) {
61
+ log(`\n--- Body ---\n${body}`);
62
+ }
63
+ } catch (e) {
64
+ logError(`Failed to show genre: ${e}`);
65
+ process.exit(1);
66
+ }
67
+ });
68
+
69
+ genreCommand
70
+ .command("create")
71
+ .description("Scaffold a new genre profile in the project genres/ directory")
72
+ .argument("<id>", "Genre ID (e.g. scifi, wuxia, romance)")
73
+ .option("--name <name>", "Genre display name", "")
74
+ .option("--numerical", "Enable numerical system", false)
75
+ .option("--power", "Enable power scaling", false)
76
+ .option("--era", "Enable era research", false)
77
+ .action(async (id: string, opts) => {
78
+ try {
79
+ const root = findProjectRoot();
80
+ const genresDir = join(root, "genres");
81
+ const filePath = join(genresDir, `${id}.md`);
82
+
83
+ // Check if already exists
84
+ try {
85
+ await readFile(filePath, "utf-8");
86
+ logError(`Genre profile already exists: ${filePath}`);
87
+ process.exit(1);
88
+ } catch { /* file doesn't exist, good */ }
89
+
90
+ await mkdir(genresDir, { recursive: true });
91
+
92
+ const name = opts.name || id;
93
+ const template = `---
94
+ name: ${name}
95
+ id: ${id}
96
+ chapterTypes: ["推进章", "布局章", "过渡章", "回收章"]
97
+ fatigueWords: ["震惊", "不可思议", "难以置信"]
98
+ numericalSystem: ${opts.numerical}
99
+ powerScaling: ${opts.power}
100
+ eraResearch: ${opts.era}
101
+ pacingRule: "每2-3章有一个明确的进展或反馈"
102
+ satisfactionTypes: ["目标达成", "困难克服", "真相揭示"]
103
+ auditDimensions: [1,2,3,6,7,8,9,10,13,14,15,16,17,18,19]
104
+ ---
105
+
106
+ ## 题材禁忌
107
+
108
+ - (根据题材添加禁忌)
109
+
110
+ ## 叙事指导
111
+
112
+ (根据题材描述叙事重心和风格要求)
113
+ `;
114
+
115
+ await writeFile(filePath, template, "utf-8");
116
+ log(`Created genre profile: ${filePath}`);
117
+ log(`Edit the file to customize chapter types, fatigue words, rules, etc.`);
118
+ } catch (e) {
119
+ logError(`Failed to create genre: ${e}`);
120
+ process.exit(1);
121
+ }
122
+ });
123
+
124
+ genreCommand
125
+ .command("copy")
126
+ .description("Copy a built-in genre profile to project for customization")
127
+ .argument("<id>", "Genre ID to copy (e.g. xuanhuan)")
128
+ .action(async (id: string) => {
129
+ try {
130
+ const root = findProjectRoot();
131
+ const builtinDir = getBuiltinGenresDir();
132
+ const srcPath = join(builtinDir, `${id}.md`);
133
+ const genresDir = join(root, "genres");
134
+ const destPath = join(genresDir, `${id}.md`);
135
+
136
+ // Check if project override already exists
137
+ try {
138
+ await readFile(destPath, "utf-8");
139
+ logError(`Project genre profile already exists: ${destPath}`);
140
+ process.exit(1);
141
+ } catch { /* doesn't exist, good */ }
142
+
143
+ let content: string;
144
+ try {
145
+ content = await readFile(srcPath, "utf-8");
146
+ } catch {
147
+ logError(`Built-in genre "${id}" not found. Use 'inkos genre list' to see available genres.`);
148
+ process.exit(1);
149
+ return;
150
+ }
151
+
152
+ await mkdir(genresDir, { recursive: true });
153
+ await writeFile(destPath, content, "utf-8");
154
+ log(`Copied to: ${destPath}`);
155
+ log(`This project-level copy will override the built-in profile.`);
156
+ } catch (e) {
157
+ logError(`Failed to copy genre: ${e}`);
158
+ process.exit(1);
159
+ }
160
+ });
@@ -0,0 +1,158 @@
1
+ import { Command } from "commander";
2
+ import { PipelineRunner, StateManager, splitChapters } from "@actalk/inkos-core";
3
+ import { readFile, readdir, stat } from "node:fs/promises";
4
+ import { join, resolve } from "node:path";
5
+ import { loadConfig, buildPipelineConfig, findProjectRoot, resolveBookId, log, logError } from "../utils.js";
6
+ import {
7
+ formatImportCanonComplete,
8
+ formatImportCanonStart,
9
+ formatImportChaptersComplete,
10
+ formatImportChaptersDiscovery,
11
+ formatImportChaptersResume,
12
+ resolveCliLanguage,
13
+ } from "../localization.js";
14
+
15
+ export const importCommand = new Command("import")
16
+ .description("Import external data into a book");
17
+
18
+ importCommand
19
+ .command("canon")
20
+ .description("Import parent book's canon for spinoff writing")
21
+ .argument("[target-book-id]", "Target book ID (auto-detected if only one book)")
22
+ .requiredOption("--from <parent-book-id>", "Parent book ID to import canon from")
23
+ .option("--json", "Output JSON")
24
+ .action(async (targetBookIdArg: string | undefined, opts) => {
25
+ try {
26
+ const root = findProjectRoot();
27
+ const targetBookId = await resolveBookId(targetBookIdArg, root);
28
+ const config = await loadConfig();
29
+ const state = new StateManager(root);
30
+ const targetBook = await state.loadBookConfig(targetBookId);
31
+ const language = resolveCliLanguage(targetBook.language);
32
+
33
+ const pipeline = new PipelineRunner(buildPipelineConfig(config, root));
34
+
35
+ if (!opts.json) log(formatImportCanonStart(language, opts.from, targetBookId));
36
+
37
+ await pipeline.importCanon(targetBookId, opts.from);
38
+
39
+ if (opts.json) {
40
+ log(JSON.stringify({
41
+ targetBookId,
42
+ parentBookId: opts.from,
43
+ output: "story/parent_canon.md",
44
+ }, null, 2));
45
+ } else {
46
+ for (const line of formatImportCanonComplete(language)) {
47
+ log(line);
48
+ }
49
+ }
50
+ } catch (e) {
51
+ if (opts.json) {
52
+ log(JSON.stringify({ error: String(e) }));
53
+ } else {
54
+ logError(`Canon import failed: ${e}`);
55
+ }
56
+ process.exit(1);
57
+ }
58
+ });
59
+
60
+ importCommand
61
+ .command("chapters")
62
+ .description("Import existing chapters for continuation writing. Reverse-engineers all truth files.")
63
+ .argument("[book-id]", "Target book ID (auto-detected if only one book)")
64
+ .requiredOption("--from <path>", "Path to a text file (auto-split) or directory of .md/.txt files")
65
+ .option("--split <regex>", "Custom regex for chapter splitting (single-file mode)")
66
+ .option("--resume-from <n>", "Resume from chapter N (for interrupted imports)", parseInt)
67
+ .option("--series", "Treat as a new series (shared universe, independent story) instead of direct continuation")
68
+ .option("--json", "Output JSON")
69
+ .action(async (bookIdArg: string | undefined, opts) => {
70
+ try {
71
+ const root = findProjectRoot();
72
+ const bookId = await resolveBookId(bookIdArg, root);
73
+ const config = await loadConfig();
74
+
75
+ const state = new StateManager(root);
76
+ const book = await state.loadBookConfig(bookId);
77
+ const language = resolveCliLanguage(book.language);
78
+ const existingChapterCount = (await state.getNextChapterNumber(bookId)) - 1;
79
+ if (existingChapterCount > 0 && !opts.resumeFrom) {
80
+ throw new Error(
81
+ `Book "${bookId}" already has ${existingChapterCount} chapter(s). ` +
82
+ `Use --resume-from <n> to append, or delete existing chapters first.`
83
+ );
84
+ }
85
+
86
+ const fromPath = resolve(opts.from);
87
+ const fromStat = await stat(fromPath);
88
+
89
+ let chapters: Array<{ title: string; content: string }>;
90
+
91
+ if (fromStat.isDirectory()) {
92
+ // Directory mode: read each .md/.txt file in sorted order
93
+ const entries = await readdir(fromPath);
94
+ const textFiles = entries
95
+ .filter((f) => f.endsWith(".md") || f.endsWith(".txt"))
96
+ .sort();
97
+
98
+ if (textFiles.length === 0) {
99
+ throw new Error(`No .md or .txt files found in ${fromPath}`);
100
+ }
101
+
102
+ chapters = await Promise.all(
103
+ textFiles.map(async (f) => {
104
+ const content = await readFile(join(fromPath, f), "utf-8");
105
+ const title = f.replace(/\.(md|txt)$/, "").replace(/^\d+[_\-\s]*/, "");
106
+ return { title, content };
107
+ }),
108
+ );
109
+ } else {
110
+ // Single file mode: split by chapter pattern
111
+ const text = await readFile(fromPath, "utf-8");
112
+ chapters = [...splitChapters(text, opts.split)];
113
+
114
+ if (chapters.length === 0) {
115
+ throw new Error(
116
+ `No chapters found in ${fromPath}. ` +
117
+ `Default pattern matches "第X章" and "Chapter X". Use --split to provide a custom regex.`,
118
+ );
119
+ }
120
+ }
121
+
122
+ if (!opts.json) {
123
+ log(formatImportChaptersDiscovery(language, chapters.length, bookId));
124
+ if (opts.resumeFrom) {
125
+ log(formatImportChaptersResume(language, opts.resumeFrom));
126
+ }
127
+ }
128
+
129
+ const pipeline = new PipelineRunner(buildPipelineConfig(config, root));
130
+
131
+ const result = await pipeline.importChapters({
132
+ bookId,
133
+ chapters,
134
+ resumeFrom: opts.resumeFrom,
135
+ importMode: opts.series ? "series" : "continuation",
136
+ });
137
+
138
+ if (opts.json) {
139
+ log(JSON.stringify(result, null, 2));
140
+ } else {
141
+ for (const line of formatImportChaptersComplete(language, {
142
+ importedCount: result.importedCount,
143
+ totalWords: result.totalWords,
144
+ nextChapter: result.nextChapter,
145
+ continueBookId: bookId,
146
+ })) {
147
+ log(line);
148
+ }
149
+ }
150
+ } catch (e) {
151
+ if (opts.json) {
152
+ log(JSON.stringify({ error: String(e) }));
153
+ } else {
154
+ logError(`Chapter import failed: ${e}`);
155
+ }
156
+ process.exit(1);
157
+ }
158
+ });
@@ -0,0 +1,47 @@
1
+ import { Command } from "commander";
2
+ import { mkdir } from "node:fs/promises";
3
+ import { resolve } from "node:path";
4
+ import { log, logError } from "../utils.js";
5
+ import { initializeProjectDirectory } from "../project-bootstrap.js";
6
+
7
+ export const initCommand = new Command("init")
8
+ .description("Initialize an InkOS project (current directory by default)")
9
+ .argument("[name]", "Project name (creates subdirectory). Omit to init current directory.")
10
+ .option("--lang <language>", "Default writing language: zh (Chinese) or en (English)", "zh")
11
+ .action(async (name: string | undefined, opts: { lang?: string }) => {
12
+ const projectDir = name ? resolve(process.cwd(), name) : process.cwd();
13
+
14
+ try {
15
+ await mkdir(projectDir, { recursive: true });
16
+ await initializeProjectDirectory(projectDir, {
17
+ language: (opts.lang === "en" ? "en" : "zh"),
18
+ overwriteSupportFiles: true,
19
+ });
20
+
21
+ log(`Project initialized at ${projectDir}`);
22
+ log("");
23
+ const isEnglish = (opts.lang ?? "zh") === "en";
24
+ const exampleCreate = isEnglish
25
+ ? " inkos book create --title 'My Novel' --genre progression --platform royalroad --lang en"
26
+ : " inkos book create --title '我的小说' --genre xuanhuan --platform tomato";
27
+ if (global) {
28
+ log("Global LLM config detected. Ready to go!");
29
+ log("");
30
+ log("Next steps:");
31
+ if (name) log(` cd ${name}`);
32
+ log(exampleCreate);
33
+ } else {
34
+ log("Next steps:");
35
+ if (name) log(` cd ${name}`);
36
+ log(" # Option 1: Set global config (recommended, one-time):");
37
+ log(" inkos config set-global --provider openai --base-url <your-api-url> --api-key <your-key> --model <your-model>");
38
+ log(" # Option 2: Edit .env for this project only");
39
+ log("");
40
+ log(exampleCreate);
41
+ }
42
+ log(" inkos write next <book-id>");
43
+ } catch (e) {
44
+ logError(`Failed to initialize project: ${e}`);
45
+ process.exit(1);
46
+ }
47
+ });
@@ -0,0 +1,109 @@
1
+ import { Command } from "commander";
2
+ import {
3
+ processProjectInteractionInput,
4
+ type InteractionRuntimeTools,
5
+ } from "@actalk/inkos-core";
6
+ import { createInteractionTools } from "../interaction/tools.js";
7
+
8
+ export interface InteractCommandHooks {
9
+ readonly runInteraction?: (params: {
10
+ readonly projectRoot: string;
11
+ readonly input: string;
12
+ readonly activeBookId?: string;
13
+ readonly tools: InteractionRuntimeTools;
14
+ }) => Promise<{
15
+ readonly request: unknown;
16
+ readonly responseText?: string;
17
+ readonly session: {
18
+ readonly automationMode: string;
19
+ readonly activeBookId?: string;
20
+ readonly currentExecution?: unknown;
21
+ readonly pendingDecision?: unknown;
22
+ readonly messages: ReadonlyArray<unknown>;
23
+ readonly events: ReadonlyArray<unknown>;
24
+ };
25
+ }>;
26
+ readonly createTools?: (projectRoot: string) => Promise<InteractionRuntimeTools>;
27
+ readonly readInput?: () => Promise<string>;
28
+ }
29
+
30
+ async function readInteractionInput(
31
+ args: ReadonlyArray<string>,
32
+ explicitMessage: string | undefined,
33
+ readInput?: () => Promise<string>,
34
+ ): Promise<string> {
35
+ const explicit = explicitMessage?.trim();
36
+ if (explicit) {
37
+ return explicit;
38
+ }
39
+
40
+ const inline = args.join(" ").trim();
41
+ if (inline) {
42
+ return inline;
43
+ }
44
+
45
+ if (readInput) {
46
+ const provided = (await readInput()).trim();
47
+ if (provided) {
48
+ return provided;
49
+ }
50
+ }
51
+
52
+ if (!process.stdin.isTTY) {
53
+ const chunks: Buffer[] = [];
54
+ for await (const chunk of process.stdin) {
55
+ chunks.push(chunk as Buffer);
56
+ }
57
+ const piped = Buffer.concat(chunks).toString("utf-8").trim();
58
+ if (piped) {
59
+ return piped;
60
+ }
61
+ }
62
+
63
+ throw new Error("Interaction message is required. Pass text arguments or pipe input via stdin.");
64
+ }
65
+
66
+ export function createInteractCommand(hooks: InteractCommandHooks = {}): Command {
67
+ return new Command("interact")
68
+ .description("Run a shared natural-language interaction against the current project")
69
+ .argument("[message...]", "Natural-language message")
70
+ .option("--message <text>", "Explicit natural-language message")
71
+ .option("--book <bookId>", "Bind a specific active book for this interaction")
72
+ .option("--json", "Emit structured JSON for external agents")
73
+ .action(async (messageArgs: ReadonlyArray<string>, opts) => {
74
+ const input = await readInteractionInput(messageArgs, opts.message, hooks.readInput);
75
+ const projectRoot = process.cwd();
76
+ const tools = hooks.createTools
77
+ ? await hooks.createTools(projectRoot)
78
+ : hooks.runInteraction
79
+ ? ({} as InteractionRuntimeTools)
80
+ : await createInteractionTools(projectRoot, undefined, { requireApiKey: false });
81
+ const runInteraction = hooks.runInteraction ?? processProjectInteractionInput;
82
+ const result = await runInteraction({
83
+ projectRoot,
84
+ input,
85
+ activeBookId: opts.book,
86
+ tools,
87
+ });
88
+
89
+ if (opts.json) {
90
+ process.stdout.write(`${JSON.stringify({
91
+ request: result.request,
92
+ responseText: result.responseText,
93
+ session: result.session,
94
+ currentExecution: result.session.currentExecution ?? null,
95
+ pendingDecision: result.session.pendingDecision ?? null,
96
+ events: result.session.events,
97
+ }, null, 2)}\n`);
98
+ return;
99
+ }
100
+
101
+ const text = result.responseText
102
+ ?? (result.session.messages.at(-1) && "content" in (result.session.messages.at(-1) as Record<string, unknown>)
103
+ ? String((result.session.messages.at(-1) as Record<string, unknown>).content)
104
+ : "");
105
+ if (text) {
106
+ process.stdout.write(`${text}\n`);
107
+ }
108
+ });
109
+ }