@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,164 @@
1
+ /**
2
+ * Full writing methodology for style_guide.md injection.
3
+ * This is the complete reference material (with examples) that the
4
+ * compact "craft card" in the system prompt summarizes.
5
+ *
6
+ * Injected once during initBook/generateStyleGuide, then read by
7
+ * writer on every chapter as part of the style_guide context.
8
+ */
9
+ export function buildWritingMethodologySection(language: "zh" | "en"): string {
10
+ if (language === "en") {
11
+ return buildEnglishMethodology();
12
+ }
13
+ return buildChineseMethodology();
14
+ }
15
+
16
+ function buildChineseMethodology(): string {
17
+ return `---
18
+
19
+ # 写作方法论参考(完整版)
20
+
21
+ 以下方法论是写作质量的完整参考。写作时应内化这些原则。
22
+
23
+ ## 一、去AI味:正反例对照
24
+
25
+ ### 情绪描写
26
+ | 反例(AI味) | 正例(人味) | 要点 |
27
+ |---|---|---|
28
+ | 他感到非常愤怒。 | 他捏碎了手中的茶杯,滚烫的茶水流过指缝,但他像没感觉一样。 | 用动作外化情绪 |
29
+ | 她心里很悲伤,眼泪流了下来。 | 她攥紧手机,指节发白,屏幕上的聊天记录模糊成一片。 | 用身体细节替代直白标签 |
30
+ | 他感到一阵恐惧。 | 他后背的汗毛竖了起来,脚底像踩在了冰上。 | 五感传递恐惧 |
31
+
32
+ ### 转折与衔接
33
+ | 反例 | 正例 | 要点 |
34
+ |---|---|---|
35
+ | 虽然他很强,但是他还是输了。 | 他确实强,可对面那个老东西更脏。 | 口语化转折 |
36
+ | 然而,事情并没有那么简单。 | 哪有那么便宜的事。 | 角色内心吐槽替代"然而" |
37
+ | 因此,他决定采取行动。 | 他站起来,把凳子踢到一边。 | 删掉因果连词,直接写动作 |
38
+
39
+ ### "了"字控制
40
+ | 反例 | 正例 |
41
+ |---|---|
42
+ | 他走了过去,拿了杯子,喝了一口水。 | 他走过去,端起杯子,灌了一口。 |
43
+ | 她笑了笑,转身离开了房间。 | 她嘴角一扬,转身出门。 |
44
+
45
+ ## 二、六步走人物心理分析
46
+
47
+ 每个重要角色在关键场景中的行为,必须经过以下六步推导:
48
+
49
+ 1. **当前处境**:角色此刻面临什么局面?手上有什么牌?
50
+ 2. **核心动机**:角色最想要什么?最害怕什么?
51
+ 3. **信息边界**:角色知道什么?不知道什么?对局势有什么误判?
52
+ 4. **性格过滤**:同样的局面,这个角色的性格会怎么反应?
53
+ 5. **行为选择**:基于以上四点,角色会做出什么选择?
54
+ 6. **情绪外化**:这个选择伴随什么情绪?用什么身体语言、表情、语气表达?
55
+
56
+ 禁止跳过步骤直接写行为。
57
+
58
+ ## 三、配角设计方法论
59
+
60
+ - 配角必须有反击,有自己的算盘。主角的强大在于压服聪明人,而不是碾压傻子。
61
+ - 每个配角的行为动机必须与主线产生关联。
62
+ - 核心标签 + 反差细节 = 活人(表面冷硬的角色偷偷照顾流浪动物)。
63
+ - 通过事件立人设,禁止通过外貌和形容词堆砌。
64
+ - 不同角色的说话方式必须有辨识度。
65
+ - 群戏中不写"众人齐声惊呼",挑1-2个角色写具体反应。
66
+
67
+ ## 四、代入感六大支柱
68
+
69
+ 1. **基础信息交代**:一句话能交代身份、性格、地位——"小爷我乃镇南府世子林峰"
70
+ 2. **具体化/可视化**:描写具体到读者脑海能浮现——"搪瓷缸白汽直冒""冰镇汽水嘶嘶响"
71
+ 3. **熟悉感**:接地气的场景自带代入感——"高考后小树林的分手""医院走廊的消毒水味"
72
+ 4. **共鸣**:主角的困境必须有普遍性——被欺压、不公待遇、被低估
73
+ 5. **欲望驱动**:
74
+ - 基础欲望(被动):不劳而获、高人一等、扬眉吐气
75
+ - 主动欲望(期待感):作者刻意制造的情绪缺口→读者期待释放→释放超过预期
76
+ 6. **五感描写**:视觉、听觉、嗅觉、触觉、味觉——"潮湿的短袖黏在后背上"
77
+
78
+ ## 五、强情绪升级法(避免流水账)
79
+
80
+ 流水账的修法不是删掉日常,而是给日常加"料":
81
+
82
+ 1. **加入前因后果**:下班回家→加上"催债电话刚打来"→日常有了紧迫感
83
+ 2. **情绪递进**:坏事叠坏事——被骂→赶不上公交→手机掉了→直播课结束了→包子噎住了。每层比上一层过分
84
+ 3. **日常必须为主线服务**:万物皆为"饵"。日常段要么埋伏笔,要么推关系,要么建立反差
85
+
86
+ ## 六、写前自检清单
87
+
88
+ 1. 本章对应卷纲中的哪个节点?是否推进了该节点?
89
+ 2. 主角此刻利益最大化的选择是什么?
90
+ 3. 冲突是谁先动手,为什么非做不可?
91
+ 4. 配角/反派是否有明确诉求和反制?
92
+ 5. 反派当前掌握了哪些信息?有无信息越界?
93
+ 6. 章尾是否留了钩子?
94
+ 7. 有没有流水账?如有,加前因后果或强情绪
95
+ 8. 本章是否推进了主线目标?`;
96
+ }
97
+
98
+ function buildEnglishMethodology(): string {
99
+ return `---
100
+
101
+ # Writing Methodology Reference (Full Version)
102
+
103
+ Complete reference material for writing quality. Internalize these principles.
104
+
105
+ ## 1. Anti-AI Pattern Guide
106
+
107
+ ### Emotion
108
+ | Bad (AI-like) | Good (Human) | Key |
109
+ |---|---|---|
110
+ | He felt very angry. | He crushed the teacup in his hand. Scalding water ran through his fingers, but he didn't flinch. | Externalize through action |
111
+ | She was very sad and tears fell. | She gripped her phone until her knuckles went white. The chat log blurred. | Body detail replaces label |
112
+
113
+ ### Transitions
114
+ | Bad | Good | Key |
115
+ |---|---|---|
116
+ | Although he was strong, he still lost. | He was strong, sure. But the old bastard across from him fought dirtier. | Colloquial voice |
117
+ | However, things were not so simple. | No such luck. | Character thought replaces "however" |
118
+ | Therefore, he decided to take action. | He stood up and kicked the chair aside. | Cut causal connectors, show action |
119
+
120
+ ## 2. Six-Step Character Psychology
121
+
122
+ For every important character action:
123
+ 1. **Situation**: What's the character facing? What cards do they hold?
124
+ 2. **Core motivation**: What do they want most? Fear most?
125
+ 3. **Information boundary**: What do they know? Not know? Misjudge?
126
+ 4. **Personality filter**: Given the same situation, how would THIS character react?
127
+ 5. **Behavioral choice**: Based on 1-4, what do they choose?
128
+ 6. **Emotional expression**: What emotion accompanies this? Body language, expression, tone?
129
+
130
+ ## 3. Supporting Character Design
131
+
132
+ - Every side character has their own agenda. Protagonist wins by outsmarting smart people.
133
+ - Core tag + contrast detail = alive (cold-exterior character secretly feeds strays).
134
+ - Establish character through events, not description dumps.
135
+ - Different characters speak differently — vocabulary, length, verbal tics.
136
+ - In group scenes: never "everyone gasped" — pick 1-2 specific reactions.
137
+
138
+ ## 4. Immersion Pillars
139
+
140
+ 1. **Info delivery**: One line of dialogue can establish identity, status, personality
141
+ 2. **Concrete/visual**: "The back seat of a taxi stuck in traffic for forty minutes" not "a big city"
142
+ 3. **Familiarity**: Scenes readers have lived through carry natural immersion
143
+ 4. **Resonance**: Protagonist's struggle must feel universal — injustice, being underestimated
144
+ 5. **Desire engine**: Create emotional gap → reader anticipates release → release exceeds expectation
145
+ 6. **Five senses**: Wet shirt on the back, hospital disinfectant, rain puddles at the bus stop
146
+
147
+ ## 5. Emotional Escalation (Anti-Flowchart)
148
+
149
+ Fix boring daily scenes by adding fuel:
150
+ 1. **Add causality**: Coming home → add "debt collector just called" → instant urgency
151
+ 2. **Progressive escalation**: Stack bad things — scolded → missed bus → phone fell in drain → livestream ended → choked on stale bread. Each layer worse.
152
+ 3. **Daily serves mainline**: Every quiet scene must plant a hook, advance a relationship, or build contrast.
153
+
154
+ ## 6. Pre-Write Checklist
155
+
156
+ 1. Which outline node does this chapter correspond to?
157
+ 2. What's the protagonist's optimal move right now?
158
+ 3. Who starts the conflict and why must they?
159
+ 4. Do antagonists have clear motives and countermoves?
160
+ 5. What information does each character have? Any boundary violations?
161
+ 6. Does the chapter end with a hook?
162
+ 7. Any flowchart passages? If so, add causality or strong emotion.
163
+ 8. Does this chapter advance the main plotline?`;
164
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "extends": "../../tsconfig.json",
3
+ "compilerOptions": {
4
+ "outDir": "dist",
5
+ "rootDir": "src"
6
+ },
7
+ "include": ["src"]
8
+ }
@@ -0,0 +1,7 @@
1
+ import { defineConfig } from "vitest/config";
2
+
3
+ export default defineConfig({
4
+ test: {
5
+ include: ["src/__tests__/**/*.test.ts"],
6
+ },
7
+ });
@@ -0,0 +1,25 @@
1
+ {
2
+ "$schema": "https://ui.shadcn.com/schema.json",
3
+ "style": "base-nova",
4
+ "rsc": false,
5
+ "tsx": true,
6
+ "tailwind": {
7
+ "config": "",
8
+ "css": "src/index.css",
9
+ "baseColor": "neutral",
10
+ "cssVariables": true,
11
+ "prefix": ""
12
+ },
13
+ "iconLibrary": "lucide",
14
+ "rtl": false,
15
+ "aliases": {
16
+ "components": "@/components",
17
+ "utils": "@/lib/utils",
18
+ "ui": "@/components/ui",
19
+ "lib": "@/lib",
20
+ "hooks": "@/hooks"
21
+ },
22
+ "menuColor": "default",
23
+ "menuAccent": "subtle",
24
+ "registries": {}
25
+ }
@@ -0,0 +1,13 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>📜</text></svg>">
7
+ <title>InkOS Studio</title>
8
+ </head>
9
+ <body>
10
+ <div id="root"></div>
11
+ <script type="module" src="/src/main.tsx"></script>
12
+ </body>
13
+ </html>
@@ -0,0 +1,72 @@
1
+ {
2
+ "name": "@actalk/inkos-studio",
3
+ "version": "1.4.1",
4
+ "description": "InkOS Studio — Web workbench for novel writing",
5
+ "type": "module",
6
+ "main": "dist/api/index.js",
7
+ "types": "dist/api/index.d.ts",
8
+ "files": [
9
+ "dist",
10
+ "!dist/**/*.test.*"
11
+ ],
12
+ "license": "AGPL-3.0-only",
13
+ "repository": {
14
+ "type": "git",
15
+ "url": "https://github.com/Narcooo/inkos.git",
16
+ "directory": "packages/studio"
17
+ },
18
+ "scripts": {
19
+ "prepack": "npm run build && node ../../scripts/prepare-package-for-publish.mjs",
20
+ "postpack": "node ../../scripts/restore-package-json.mjs",
21
+ "prepublishOnly": "node ../../scripts/verify-no-workspace-protocol.mjs .",
22
+ "dev": "INKOS_STUDIO_PORT=4569 INKOS_PROJECT_ROOT=../.. tsx watch --clear-screen=false src/api/index.ts & vite --host --port 4567 ; kill %1 2>/dev/null",
23
+ "dev:client": "vite --host --port 4567",
24
+ "dev:server": "INKOS_STUDIO_PORT=4569 INKOS_PROJECT_ROOT=../.. tsx watch src/api/index.ts",
25
+ "build": "npm run build:client && npm run build:server",
26
+ "build:client": "vite build",
27
+ "build:server": "tsc -p tsconfig.server.json",
28
+ "preview": "vite preview",
29
+ "test": "vitest run",
30
+ "typecheck": "tsc --noEmit && tsc -p tsconfig.server.json --noEmit"
31
+ },
32
+ "dependencies": {
33
+ "@actalk/inkos-core": "workspace:*",
34
+ "@base-ui/react": "^1.3.0",
35
+ "@fontsource-variable/geist": "^5.2.8",
36
+ "@hono/node-server": "^1.13.0",
37
+ "@radix-ui/react-use-controllable-state": "^1.2.2",
38
+ "@streamdown/cjk": "^1.0.3",
39
+ "@streamdown/code": "^1.1.1",
40
+ "@streamdown/math": "^1.0.2",
41
+ "@streamdown/mermaid": "^1.0.2",
42
+ "ai": "^6.0.159",
43
+ "class-variance-authority": "^0.7.1",
44
+ "clsx": "^2.1.1",
45
+ "cmdk": "^1.1.1",
46
+ "hono": "^4.7.0",
47
+ "lucide-react": "^0.577.0",
48
+ "motion": "^12.38.0",
49
+ "nanoid": "^5.1.7",
50
+ "react": "^19.0.0",
51
+ "react-dom": "^19.0.0",
52
+ "shadcn": "^4.2.0",
53
+ "shiki": "^4.0.2",
54
+ "streamdown": "^2.5.0",
55
+ "tailwind-merge": "^3.5.0",
56
+ "tw-animate-css": "^1.4.0",
57
+ "zustand": "^5.0.12"
58
+ },
59
+ "devDependencies": {
60
+ "@tailwindcss/vite": "^4.0.0",
61
+ "@types/node": "^22.0.0",
62
+ "@types/react": "^19.0.0",
63
+ "@types/react-dom": "^19.0.0",
64
+ "@vitejs/plugin-react": "^4.4.0",
65
+ "autoprefixer": "^10.4.0",
66
+ "tailwindcss": "^4.0.0",
67
+ "tsx": "^4.20.6",
68
+ "typescript": "^5.8.0",
69
+ "vite": "^6.0.0",
70
+ "vitest": "^3.0.0"
71
+ }
72
+ }
@@ -0,0 +1,3 @@
1
+ export default {
2
+ plugins: {}
3
+ };
@@ -0,0 +1,25 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { deriveActiveBookId, isBookCreateChatRoute } from "./App";
3
+
4
+ describe("deriveActiveBookId", () => {
5
+ it("returns the current book across book-centered routes", () => {
6
+ expect(deriveActiveBookId({ page: "book", bookId: "alpha" })).toBe("alpha");
7
+ expect(deriveActiveBookId({ page: "chapter", bookId: "beta", chapterNumber: 3 })).toBe("beta");
8
+ expect(deriveActiveBookId({ page: "truth", bookId: "gamma" })).toBe("gamma");
9
+ expect(deriveActiveBookId({ page: "analytics", bookId: "delta" })).toBe("delta");
10
+ expect(deriveActiveBookId({ page: "book-settings", bookId: "epsilon" })).toBe("epsilon");
11
+ });
12
+
13
+ it("returns undefined for non-book routes", () => {
14
+ expect(deriveActiveBookId({ page: "dashboard" })).toBeUndefined();
15
+ expect(deriveActiveBookId({ page: "services" })).toBeUndefined();
16
+ expect(deriveActiveBookId({ page: "style" })).toBeUndefined();
17
+ });
18
+ });
19
+
20
+ describe("isBookCreateChatRoute", () => {
21
+ it("routes new-book creation through chat instead of the standalone form page", () => {
22
+ expect(isBookCreateChatRoute({ page: "book-create" })).toBe(true);
23
+ expect(isBookCreateChatRoute({ page: "book", bookId: "alpha" })).toBe(false);
24
+ });
25
+ });
@@ -0,0 +1,280 @@
1
+ import { useState, useEffect } from "react";
2
+ import { useHashRoute } from "./hooks/use-hash-route";
3
+ import type { HashRoute } from "./hooks/use-hash-route";
4
+ import { Sidebar } from "./components/Sidebar";
5
+ import { Dashboard } from "./pages/Dashboard";
6
+ import { ChatPage } from "./pages/ChatPage";
7
+ import { BookDetail } from "./pages/BookDetail";
8
+ import { ChapterReader } from "./pages/ChapterReader";
9
+ import { Analytics } from "./pages/Analytics";
10
+ import { ServiceListPage } from "./pages/ServiceListPage";
11
+ import { ServiceDetailPage } from "./pages/ServiceDetailPage";
12
+ import { TruthFiles } from "./pages/TruthFiles";
13
+ import { DaemonControl } from "./pages/DaemonControl";
14
+ import { LogViewer } from "./pages/LogViewer";
15
+ import { GenreManager } from "./pages/GenreManager";
16
+ import { StyleManager } from "./pages/StyleManager";
17
+ import { ImportManager } from "./pages/ImportManager";
18
+ import { RadarView } from "./pages/RadarView";
19
+ import { DoctorView } from "./pages/DoctorView";
20
+ import { LanguageSelector } from "./pages/LanguageSelector";
21
+ import { BookSidebar, BookSidebarToggle } from "./components/chat/BookSidebar";
22
+ import { useSSE } from "./hooks/use-sse";
23
+ import { useSessionEvents } from "./hooks/use-session-events";
24
+ import { useTheme } from "./hooks/use-theme";
25
+ import { useI18n } from "./hooks/use-i18n";
26
+ import { postApi, putApi, useApi } from "./hooks/use-api";
27
+ import { Sun, Moon } from "lucide-react";
28
+ import { House } from "lucide-react";
29
+
30
+ export type { HashRoute as Route } from "./hooks/use-hash-route";
31
+
32
+ export function deriveActiveBookId(route: HashRoute): string | undefined {
33
+ if ("bookId" in route) return route.bookId;
34
+ return undefined;
35
+ }
36
+
37
+ export function isBookCreateChatRoute(route: HashRoute): boolean {
38
+ return route.page === "book-create";
39
+ }
40
+
41
+ export function App() {
42
+ const { route, setRoute } = useHashRoute();
43
+ const sse = useSSE();
44
+ const { theme, setTheme } = useTheme();
45
+ const { t, lang: currentLang } = useI18n();
46
+ const { data: project, refetch: refetchProject } = useApi<{ language: string; languageExplicit: boolean }>("/project");
47
+ const [showLanguageSelector, setShowLanguageSelector] = useState(false);
48
+ const [ready, setReady] = useState(false);
49
+
50
+ const isDark = theme === "dark";
51
+
52
+ useEffect(() => {
53
+ document.documentElement.classList.toggle("dark", isDark);
54
+ }, [isDark]);
55
+
56
+ useEffect(() => {
57
+ if (project) {
58
+ if (!project.languageExplicit) {
59
+ setShowLanguageSelector(true);
60
+ }
61
+ setReady(true);
62
+ }
63
+ }, [project]);
64
+
65
+ useSessionEvents(sse, route, setRoute);
66
+
67
+ const nav = {
68
+ toDashboard: () => setRoute({ page: "dashboard" }),
69
+ toChat: () => setRoute({ page: "chat" }),
70
+ toBook: (bookId: string) => setRoute({ page: "book", bookId }),
71
+ toBookSettings: (bookId: string) => setRoute({ page: "book-settings", bookId }),
72
+ toBookCreate: () => setRoute({ page: "book-create" }),
73
+ toChapter: (bookId: string, chapterNumber: number) =>
74
+ setRoute({ page: "chapter", bookId, chapterNumber }),
75
+ toAnalytics: (bookId: string) => setRoute({ page: "analytics", bookId }),
76
+ toServices: () => setRoute({ page: "services" }),
77
+ toServiceDetail: (id: string) => setRoute({ page: "service-detail", serviceId: id }),
78
+ toTruth: (bookId: string) => setRoute({ page: "truth", bookId }),
79
+ toDaemon: () => setRoute({ page: "daemon" }),
80
+ toLogs: () => setRoute({ page: "logs" }),
81
+ toGenres: () => setRoute({ page: "genres" }),
82
+ toStyle: () => setRoute({ page: "style" }),
83
+ toImport: () => setRoute({ page: "import" }),
84
+ toRadar: () => setRoute({ page: "radar" }),
85
+ toDoctor: () => setRoute({ page: "doctor" }),
86
+ };
87
+
88
+ const activeBookId = deriveActiveBookId(route);
89
+ const activePage =
90
+ activeBookId
91
+ ? `book:${activeBookId}`
92
+ : route.page === "service-detail"
93
+ ? "services"
94
+ : route.page;
95
+
96
+ if (!ready) {
97
+ return (
98
+ <div className="min-h-screen bg-background flex items-center justify-center">
99
+ <div className="w-12 h-12 border-4 border-primary/20 border-t-primary rounded-full animate-spin" />
100
+ </div>
101
+ );
102
+ }
103
+
104
+ if (showLanguageSelector) {
105
+ return (
106
+ <LanguageSelector
107
+ onSelect={async (lang) => {
108
+ await postApi("/project/language", { language: lang });
109
+ setShowLanguageSelector(false);
110
+ refetchProject();
111
+ }}
112
+ />
113
+ );
114
+ }
115
+
116
+ return (
117
+ <div className="h-screen bg-background text-foreground flex overflow-hidden font-sans">
118
+ {/* Left Sidebar */}
119
+ <Sidebar nav={nav} activePage={activePage} sse={sse} t={t} />
120
+
121
+ {/* Center Content */}
122
+ <div className="flex-1 flex flex-col min-w-0 bg-background/30 backdrop-blur-sm">
123
+ {/* Header Strip */}
124
+ <header className="h-14 shrink-0 flex items-center justify-between px-8 border-b border-border/40">
125
+ <div className="flex items-center gap-2">
126
+ <button
127
+ onClick={nav.toDashboard}
128
+ className="inline-flex items-center gap-2 rounded-lg border border-border/50 bg-card/70 px-3 py-1.5 text-sm font-semibold text-foreground hover:bg-secondary/50 transition-colors"
129
+ >
130
+ <House size={14} />
131
+ <span>首页</span>
132
+ <span className="text-muted-foreground/70">/</span>
133
+ <span className="font-serif">InkOS Studio</span>
134
+ </button>
135
+ </div>
136
+
137
+ <div className="flex items-center gap-3">
138
+ <div className="flex gap-0.5 bg-muted/50 rounded-md p-0.5">
139
+ <button
140
+ onClick={async () => {
141
+ await putApi("/project", { language: "zh" });
142
+ refetchProject();
143
+ }}
144
+ className={`text-xs px-2 py-0.5 rounded ${currentLang === "zh" ? "bg-primary text-primary-foreground" : "text-muted-foreground"}`}
145
+ >
146
+
147
+ </button>
148
+ <button
149
+ onClick={async () => {
150
+ await putApi("/project", { language: "en" });
151
+ refetchProject();
152
+ }}
153
+ className={`text-xs px-2 py-0.5 rounded ${currentLang === "en" ? "bg-primary text-primary-foreground" : "text-muted-foreground"}`}
154
+ >
155
+ EN
156
+ </button>
157
+ </div>
158
+
159
+ <button
160
+ onClick={() => setTheme(isDark ? "light" : "dark")}
161
+ className="text-muted-foreground hover:text-foreground transition-colors"
162
+ >
163
+ {isDark ? <Sun size={14} /> : <Moon size={14} />}
164
+ </button>
165
+ </div>
166
+ </header>
167
+
168
+ {/* Main Content Area */}
169
+ <main className="flex-1 relative overflow-y-auto scroll-smooth">
170
+ {route.page === "dashboard" && (
171
+ <div className="max-w-4xl mx-auto px-6 py-12 md:px-12 lg:py-16 fade-in">
172
+ <Dashboard nav={nav} sse={sse} theme={theme} t={t} />
173
+ </div>
174
+ )}
175
+ {isBookCreateChatRoute(route) && (
176
+ <div className="absolute inset-0 flex min-w-0">
177
+ <ChatPage
178
+ mode="book-create"
179
+ nav={nav}
180
+ theme={theme}
181
+ t={t}
182
+ sse={sse}
183
+ />
184
+ </div>
185
+ )}
186
+ {route.page === "chat" && (
187
+ <div className="absolute inset-0 flex min-w-0">
188
+ <ChatPage
189
+ mode="project-chat"
190
+ nav={nav}
191
+ theme={theme}
192
+ t={t}
193
+ sse={sse}
194
+ />
195
+ </div>
196
+ )}
197
+ {route.page === "book" && (
198
+ <div className="absolute inset-0 flex min-w-0">
199
+ <ChatPage
200
+ activeBookId={route.bookId}
201
+ mode="book"
202
+ nav={nav}
203
+ theme={theme}
204
+ t={t}
205
+ sse={sse}
206
+ />
207
+ <BookSidebar bookId={route.bookId} theme={theme} t={t} sse={sse} />
208
+ <BookSidebarToggle bookId={route.bookId} theme={theme} t={t} sse={sse} />
209
+ </div>
210
+ )}
211
+ {route.page === "book-settings" && (
212
+ <div className="max-w-4xl mx-auto px-6 py-12 md:px-12 lg:py-16 fade-in">
213
+ <BookDetail bookId={route.bookId} nav={nav} theme={theme} t={t} sse={sse} />
214
+ </div>
215
+ )}
216
+ {route.page === "chapter" && (
217
+ <div className="max-w-4xl mx-auto px-6 py-12 md:px-12 lg:py-16 fade-in">
218
+ <ChapterReader bookId={route.bookId} chapterNumber={route.chapterNumber} nav={nav} theme={theme} t={t} />
219
+ </div>
220
+ )}
221
+ {route.page === "analytics" && (
222
+ <div className="max-w-4xl mx-auto px-6 py-12 md:px-12 lg:py-16 fade-in">
223
+ <Analytics bookId={route.bookId} nav={nav} theme={theme} t={t} />
224
+ </div>
225
+ )}
226
+ {route.page === "services" && (
227
+ <div className="max-w-4xl mx-auto px-6 py-12 md:px-12 lg:py-16 fade-in">
228
+ <ServiceListPage nav={nav} />
229
+ </div>
230
+ )}
231
+ {route.page === "service-detail" && (
232
+ <div className="max-w-4xl mx-auto px-6 py-12 md:px-12 lg:py-16 fade-in">
233
+ <ServiceDetailPage serviceId={route.serviceId} nav={nav} />
234
+ </div>
235
+ )}
236
+ {route.page === "truth" && (
237
+ <div className="max-w-4xl mx-auto px-6 py-12 md:px-12 lg:py-16 fade-in">
238
+ <TruthFiles bookId={route.bookId} nav={nav} theme={theme} t={t} />
239
+ </div>
240
+ )}
241
+ {route.page === "daemon" && (
242
+ <div className="max-w-4xl mx-auto px-6 py-12 md:px-12 lg:py-16 fade-in">
243
+ <DaemonControl nav={nav} theme={theme} t={t} sse={sse} />
244
+ </div>
245
+ )}
246
+ {route.page === "logs" && (
247
+ <div className="max-w-4xl mx-auto px-6 py-12 md:px-12 lg:py-16 fade-in">
248
+ <LogViewer nav={nav} theme={theme} t={t} />
249
+ </div>
250
+ )}
251
+ {route.page === "genres" && (
252
+ <div className="max-w-4xl mx-auto px-6 py-12 md:px-12 lg:py-16 fade-in">
253
+ <GenreManager nav={nav} theme={theme} t={t} />
254
+ </div>
255
+ )}
256
+ {route.page === "style" && (
257
+ <div className="max-w-4xl mx-auto px-6 py-12 md:px-12 lg:py-16 fade-in">
258
+ <StyleManager nav={nav} theme={theme} t={t} />
259
+ </div>
260
+ )}
261
+ {route.page === "import" && (
262
+ <div className="max-w-4xl mx-auto px-6 py-12 md:px-12 lg:py-16 fade-in">
263
+ <ImportManager nav={nav} theme={theme} t={t} />
264
+ </div>
265
+ )}
266
+ {route.page === "radar" && (
267
+ <div className="max-w-4xl mx-auto px-6 py-12 md:px-12 lg:py-16 fade-in">
268
+ <RadarView nav={nav} theme={theme} t={t} />
269
+ </div>
270
+ )}
271
+ {route.page === "doctor" && (
272
+ <div className="max-w-4xl mx-auto px-6 py-12 md:px-12 lg:py-16 fade-in">
273
+ <DoctorView nav={nav} theme={theme} t={t} />
274
+ </div>
275
+ )}
276
+ </main>
277
+ </div>
278
+ </div>
279
+ );
280
+ }
@@ -0,0 +1,40 @@
1
+ import { describe, it, expect } from "vitest";
2
+
3
+ // normalizeBaseUrl is not exported, so we test the behavior through the
4
+ // server module's internal logic. We replicate the function here for unit testing.
5
+ // If the implementation changes, this test will catch regressions.
6
+ function normalizeBaseUrl(url: string): string {
7
+ const trimmed = url.replace(/\/+$/, "");
8
+ if (/\/v\d+$/.test(trimmed)) return trimmed;
9
+ return trimmed + "/v1";
10
+ }
11
+
12
+ describe("normalizeBaseUrl", () => {
13
+ it("appends /v1 when missing", () => {
14
+ expect(normalizeBaseUrl("https://timesniper.club")).toBe("https://timesniper.club/v1");
15
+ });
16
+
17
+ it("strips trailing slash then appends /v1", () => {
18
+ expect(normalizeBaseUrl("https://timesniper.club/")).toBe("https://timesniper.club/v1");
19
+ });
20
+
21
+ it("strips multiple trailing slashes", () => {
22
+ expect(normalizeBaseUrl("https://timesniper.club///")).toBe("https://timesniper.club/v1");
23
+ });
24
+
25
+ it("preserves existing /v1", () => {
26
+ expect(normalizeBaseUrl("https://timesniper.club/v1")).toBe("https://timesniper.club/v1");
27
+ });
28
+
29
+ it("preserves other version paths like /v2", () => {
30
+ expect(normalizeBaseUrl("https://api.example.com/v2")).toBe("https://api.example.com/v2");
31
+ });
32
+
33
+ it("all three forms are equivalent", () => {
34
+ const a = normalizeBaseUrl("https://timesniper.club/v1");
35
+ const b = normalizeBaseUrl("https://timesniper.club/");
36
+ const c = normalizeBaseUrl("https://timesniper.club");
37
+ expect(a).toBe(b);
38
+ expect(b).toBe(c);
39
+ });
40
+ });