pneuma-skills 1.18.8 → 2.0.0

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 (157) hide show
  1. package/README.md +16 -10
  2. package/bin/pneuma.ts +311 -1
  3. package/core/mode-loader.ts +7 -0
  4. package/core/types/index.ts +2 -0
  5. package/core/types/mode-manifest.ts +43 -0
  6. package/dist/assets/{EditorPanel-BleuERxH.js → EditorPanel-0akZRyo5.js} +1 -1
  7. package/dist/assets/Launcher-CCi-6n7c.js +1 -0
  8. package/dist/assets/{ScaffoldConfirm-y_ee3Dfd.js → ScaffoldConfirm-CUg6eQ0U.js} +1 -1
  9. package/dist/assets/{TerminalPanel-Cn7WlSTk.js → TerminalPanel-BsmX9W8R.js} +1 -1
  10. package/dist/assets/{ar-SA-G6X2FPQ2-D3jsaCPH.js → ar-SA-G6X2FPQ2-CyJjWFnD.js} +1 -1
  11. package/dist/assets/{arc-DNF_Rvhl.js → arc-R5iRnrLz.js} +1 -1
  12. package/dist/assets/{az-AZ-76LH7QW2-B1w4wSUT.js → az-AZ-76LH7QW2-1n7ob6V6.js} +1 -1
  13. package/dist/assets/{bg-BG-XCXSNQG7-Cb8Z7rZq.js → bg-BG-XCXSNQG7-CaBcp9qd.js} +1 -1
  14. package/dist/assets/{blockDiagram-38ab4fdb-CP_JiaKU.js → blockDiagram-38ab4fdb-B1X3_GFX.js} +1 -1
  15. package/dist/assets/{bn-BD-2XOGV67Q-ChAjeqCN.js → bn-BD-2XOGV67Q-BtA4rXnE.js} +1 -1
  16. package/dist/assets/{c4Diagram-3d4e48cf-Bas06DhA.js → c4Diagram-3d4e48cf-BtqYi13m.js} +1 -1
  17. package/dist/assets/{ca-ES-6MX7JW3Y-B9H8UnNU.js → ca-ES-6MX7JW3Y-DUBFlXlo.js} +1 -1
  18. package/dist/assets/channel-gedPNWcr.js +1 -0
  19. package/dist/assets/{classDiagram-70f12bd4-Crf6gDW8.js → classDiagram-70f12bd4-DPYb9XVZ.js} +1 -1
  20. package/dist/assets/{classDiagram-v2-f2320105-Cw4vriY9.js → classDiagram-v2-f2320105-CmfvQEAX.js} +1 -1
  21. package/dist/assets/clone-BJt3SdgM.js +1 -0
  22. package/dist/assets/{createText-2e5e7dd3-B6z6IYvt.js → createText-2e5e7dd3-ByQRkWgK.js} +1 -1
  23. package/dist/assets/{cs-CZ-2BRQDIVT-DbtValfJ.js → cs-CZ-2BRQDIVT-OKf3CBFB.js} +1 -1
  24. package/dist/assets/{da-DK-5WZEPLOC-D0CZnl6S.js → da-DK-5WZEPLOC-BKcaFv7b.js} +1 -1
  25. package/dist/assets/{de-DE-XR44H4JA-BwUK-XWk.js → de-DE-XR44H4JA-BRDaTV6M.js} +1 -1
  26. package/dist/assets/{download-DLP4jMAA.js → download-B98bty0V.js} +1 -1
  27. package/dist/assets/{edges-e0da2a9e-DobexeDC.js → edges-e0da2a9e-DDhb7mIg.js} +1 -1
  28. package/dist/assets/{el-GR-BZB4AONW-Vu07mCI5.js → el-GR-BZB4AONW-DTlDpPbe.js} +1 -1
  29. package/dist/assets/{erDiagram-9861fffd-CCSTBb8R.js → erDiagram-9861fffd-DBVXKikK.js} +1 -1
  30. package/dist/assets/{es-ES-U4NZUMDT-iUcic2nH.js → es-ES-U4NZUMDT-DDLgPUOO.js} +1 -1
  31. package/dist/assets/{eu-ES-A7QVB2H4-BgU9SWVI.js → eu-ES-A7QVB2H4-Bz2xzMob.js} +1 -1
  32. package/dist/assets/{fa-IR-HGAKTJCU-BTCkvyWh.js → fa-IR-HGAKTJCU-P4zcEtxA.js} +1 -1
  33. package/dist/assets/{fi-FI-Z5N7JZ37-DWVFBCwg.js → fi-FI-Z5N7JZ37-D2q89-9c.js} +1 -1
  34. package/dist/assets/{flowDb-956e92f1-DwO84EWT.js → flowDb-956e92f1-BSfxVv-C.js} +1 -1
  35. package/dist/assets/{flowDiagram-66a62f08-CuDeqby5.js → flowDiagram-66a62f08-DPHp_TrQ.js} +1 -1
  36. package/dist/assets/flowDiagram-v2-96b9c2cf-DO_9RAPt.js +1 -0
  37. package/dist/assets/{flowchart-elk-definition-4a651766-C-Ogp6Jp.js → flowchart-elk-definition-4a651766-B-9INMbf.js} +1 -1
  38. package/dist/assets/{fr-FR-RHASNOE6-CVlNocmm.js → fr-FR-RHASNOE6-CYGGgFGJ.js} +1 -1
  39. package/dist/assets/{ganttDiagram-c361ad54-BAxD7Eoo.js → ganttDiagram-c361ad54-Lt3a4i9C.js} +1 -1
  40. package/dist/assets/{gitGraphDiagram-72cf32ee-CK_I_0zd.js → gitGraphDiagram-72cf32ee-CAJ5Ogtn.js} +1 -1
  41. package/dist/assets/{gl-ES-HMX3MZ6V-DLvyrdOn.js → gl-ES-HMX3MZ6V-CyN6LVPa.js} +1 -1
  42. package/dist/assets/{graph-C7CuZfOA.js → graph-CPcTKuJe.js} +1 -1
  43. package/dist/assets/{he-IL-6SHJWFNN-BElIsMIp.js → he-IL-6SHJWFNN-Bm8KblEy.js} +1 -1
  44. package/dist/assets/{hi-IN-IWLTKZ5I-CkNV-BOU.js → hi-IN-IWLTKZ5I-Ch9nEDMX.js} +1 -1
  45. package/dist/assets/{hu-HU-A5ZG7DT2-2S9Y7Svn.js → hu-HU-A5ZG7DT2-CjXf6kKD.js} +1 -1
  46. package/dist/assets/{id-ID-SAP4L64H-BjaLm4l6.js → id-ID-SAP4L64H-C_87xASV.js} +1 -1
  47. package/dist/assets/{index-3862675e-Cnnvl-8u.js → index-3862675e-CWsCtFSt.js} +1 -1
  48. package/dist/assets/{index-CQTyt1YM.js → index-44rIdSy5.js} +1 -1
  49. package/dist/assets/index-9_ngsavx.css +1 -0
  50. package/dist/assets/{index-DupDxaBk.js → index-BOvq7HF2.js} +4 -4
  51. package/dist/assets/{index-Dc0SptmK.js → index-Dg5w1pZN.js} +1 -1
  52. package/dist/assets/{index-DuLlGGas.js → index-Dsva36SB.js} +23 -23
  53. package/dist/assets/{infoDiagram-f8f76790-D0MyaMnN.js → infoDiagram-f8f76790-BhC7MVmC.js} +1 -1
  54. package/dist/assets/{it-IT-JPQ66NNP-DDKE0SJO.js → it-IT-JPQ66NNP-C4W_W79I.js} +1 -1
  55. package/dist/assets/{ja-JP-DBVTYXUO-DY6X7qK7.js → ja-JP-DBVTYXUO-DC8KJuas.js} +1 -1
  56. package/dist/assets/{journeyDiagram-49397b02-qgIUb-89.js → journeyDiagram-49397b02-BhQRP25G.js} +1 -1
  57. package/dist/assets/{kaa-6HZHGXH3-DiuMBUla.js → kaa-6HZHGXH3-Cs-7ua_I.js} +1 -1
  58. package/dist/assets/{kab-KAB-ZGHBKWFO-6e4XQ-tz.js → kab-KAB-ZGHBKWFO-DPFqm_A6.js} +1 -1
  59. package/dist/assets/{kk-KZ-P5N5QNE5-DfjIixsJ.js → kk-KZ-P5N5QNE5-Cf7o_GJW.js} +1 -1
  60. package/dist/assets/{km-KH-HSX4SM5Z-BhRmMVE_.js → km-KH-HSX4SM5Z-BeUIhFSc.js} +1 -1
  61. package/dist/assets/{ko-KR-MTYHY66A-Bjn9mXnA.js → ko-KR-MTYHY66A-CKQWpLZ0.js} +1 -1
  62. package/dist/assets/{ku-TR-6OUDTVRD-DJr9jfEi.js → ku-TR-6OUDTVRD-DAQg2oMr.js} +1 -1
  63. package/dist/assets/{layout-Dd69otLm.js → layout-Bx0l_BKn.js} +1 -1
  64. package/dist/assets/{line-DRfgXn85.js → line-CqdhvoBg.js} +1 -1
  65. package/dist/assets/{linear-DGr1PTPp.js → linear-BD2kl1Br.js} +1 -1
  66. package/dist/assets/{lt-LT-XHIRWOB4-ppVjyPnr.js → lt-LT-XHIRWOB4-qBbyF_JI.js} +1 -1
  67. package/dist/assets/{lv-LV-5QDEKY6T-CGS8BspW.js → lv-LV-5QDEKY6T-D2FWxPw_.js} +1 -1
  68. package/dist/assets/{manifest-BvnrtaQm.js → manifest-BmEn3LvA.js} +13 -6
  69. package/dist/assets/manifest-C0moSD5y.js +28 -0
  70. package/dist/assets/{manifest-BI8slOVt.js → manifest-D1rKRD_L.js} +15 -6
  71. package/dist/assets/{manifest-neauP7Gc.js → manifest-grHl8OxZ.js} +7 -3
  72. package/dist/assets/{manifest-BkKz5q4X.js → manifest-k4uV77LO.js} +17 -10
  73. package/dist/assets/{mindmap-definition-fc14e90a-AFmcyPtp.js → mindmap-definition-fc14e90a-BacEaxyV.js} +1 -1
  74. package/dist/assets/{mr-IN-CRQNXWMA-BHH01ypW.js → mr-IN-CRQNXWMA-DDvShQEG.js} +1 -1
  75. package/dist/assets/{my-MM-5M5IBNSE-t572CDde.js → my-MM-5M5IBNSE--mZq5Lsm.js} +1 -1
  76. package/dist/assets/{nb-NO-T6EIAALU-BiNtPMS2.js → nb-NO-T6EIAALU-C29pR6hl.js} +1 -1
  77. package/dist/assets/{nl-NL-IS3SIHDZ-DD-YrS7Y.js → nl-NL-IS3SIHDZ-BhRRuqV1.js} +1 -1
  78. package/dist/assets/{nn-NO-6E72VCQL-CAdSOdj3.js → nn-NO-6E72VCQL-DMn4kFnF.js} +1 -1
  79. package/dist/assets/{oc-FR-POXYY2M6-CggnZuUm.js → oc-FR-POXYY2M6-DimVPddm.js} +1 -1
  80. package/dist/assets/{pa-IN-N4M65BXN-CgQSRavt.js → pa-IN-N4M65BXN-DLzOv-Nt.js} +1 -1
  81. package/dist/assets/{percentages-BXMCSKIN-Cy39z5Py.js → percentages-BXMCSKIN-oPUMUK28.js} +7 -7
  82. package/dist/assets/{pica-C6y9YaE7.js → pica-BdG-S0W_.js} +1 -1
  83. package/dist/assets/{pieDiagram-8a3498a8-CywqbnUP.js → pieDiagram-8a3498a8-DD808_p6.js} +1 -1
  84. package/dist/assets/{pl-PL-T2D74RX3-DhZysyag.js → pl-PL-T2D74RX3-BVjLL-KO.js} +1 -1
  85. package/dist/assets/{pneuma-mode-DObfMJkD.js → pneuma-mode-BstV4WWa.js} +3 -3
  86. package/dist/assets/pneuma-mode-C8lXPcZY.js +6 -0
  87. package/dist/assets/{pneuma-mode-BawXqZD4.js → pneuma-mode-CvAzc7or.js} +1 -1
  88. package/dist/assets/{pneuma-mode-CvRaQvup.js → pneuma-mode-DA-nYcMo.js} +1 -1
  89. package/dist/assets/{pneuma-mode-tKG2TfhL.js → pneuma-mode-DzSNT6KB.js} +3 -3
  90. package/dist/assets/{pt-BR-5N22H2LF-DqmnKHfj.js → pt-BR-5N22H2LF-pjOi5yYu.js} +1 -1
  91. package/dist/assets/{pt-PT-UZXXM6DQ-Dr61yFqO.js → pt-PT-UZXXM6DQ-C0zzmeZg.js} +1 -1
  92. package/dist/assets/{quadrantDiagram-120e2f19-BBlGHWao.js → quadrantDiagram-120e2f19-2FBFHV1g.js} +1 -1
  93. package/dist/assets/{rasterize-34PCWURX-VXG9AwQG.js → rasterize-34PCWURX-BuR7lHwM.js} +1 -1
  94. package/dist/assets/{requirementDiagram-deff3bca-TQYdVQGJ.js → requirementDiagram-deff3bca-DgdDm7sw.js} +1 -1
  95. package/dist/assets/{ro-RO-JPDTUUEW-CAtABelS.js → ro-RO-JPDTUUEW-DrTbqAZB.js} +1 -1
  96. package/dist/assets/{ru-RU-B4JR7IUQ-C_3zWMxA.js → ru-RU-B4JR7IUQ-Dwoiqt7A.js} +1 -1
  97. package/dist/assets/{sankeyDiagram-04a897e0-BnnEsTPi.js → sankeyDiagram-04a897e0-DA6RPxOH.js} +1 -1
  98. package/dist/assets/{sequenceDiagram-704730f1-CMwpQj1K.js → sequenceDiagram-704730f1-D6rBSEZx.js} +1 -1
  99. package/dist/assets/{si-LK-N5RQ5JYF-BusDWMm7.js → si-LK-N5RQ5JYF-DEyeLAPX.js} +1 -1
  100. package/dist/assets/{sk-SK-C5VTKIMK-CQpZ58Ns.js → sk-SK-C5VTKIMK-DrrUEhZF.js} +1 -1
  101. package/dist/assets/{sl-SI-NN7IZMDC-dKFYj_L9.js → sl-SI-NN7IZMDC-LHNZL1i8.js} +1 -1
  102. package/dist/assets/{stateDiagram-587899a1-BUVV6Afi.js → stateDiagram-587899a1-BNbQ_MDY.js} +1 -1
  103. package/dist/assets/{stateDiagram-v2-d93cdb3a-eJtAzvCh.js → stateDiagram-v2-d93cdb3a-CLIyBUgq.js} +1 -1
  104. package/dist/assets/{styles-6aaf32cf-Kdv8aCGY.js → styles-6aaf32cf-JOpKCqiC.js} +1 -1
  105. package/dist/assets/{styles-9a916d00-CGR3lcaC.js → styles-9a916d00-lHkzP7SR.js} +1 -1
  106. package/dist/assets/{styles-c10674c1-BOkM08QZ.js → styles-c10674c1-DnuoD4Pf.js} +1 -1
  107. package/dist/assets/{subset-shared.chunk-CjkDX8VC.js → subset-shared.chunk-CN75hxTG.js} +1 -1
  108. package/dist/assets/{subset-worker.chunk-piclBFAr.js → subset-worker.chunk-BKXWmKBH.js} +1 -1
  109. package/dist/assets/{sv-SE-XGPEYMSR-B8RTK6WL.js → sv-SE-XGPEYMSR-CTNDbM3s.js} +1 -1
  110. package/dist/assets/{svgDrawCommon-08f97a94-B2mIk0L0.js → svgDrawCommon-08f97a94-Da2dJTri.js} +1 -1
  111. package/dist/assets/{ta-IN-2NMHFXQM-BQtdS-Ss.js → ta-IN-2NMHFXQM-ByyMZMP5.js} +1 -1
  112. package/dist/assets/{th-TH-HPSO5L25-B-yXVmv_.js → th-TH-HPSO5L25-CNejeYu_.js} +1 -1
  113. package/dist/assets/{timeline-definition-85554ec2-156uBejc.js → timeline-definition-85554ec2-4kZpETv4.js} +1 -1
  114. package/dist/assets/{toBlob-BLi9egoc.js → toBlob-WxcBwMU6.js} +1 -1
  115. package/dist/assets/{toCanvas-fcJ0RdLx.js → toCanvas-B_D439gh.js} +1 -1
  116. package/dist/assets/{toImg-CYywIo5R.js → toImg-DRze7wY3.js} +1 -1
  117. package/dist/assets/{tr-TR-DEFEU3FU-5fpLXM1X.js → tr-TR-DEFEU3FU-6my8X0k8.js} +1 -1
  118. package/dist/assets/{uk-UA-QMV73CPH-BxPzifFa.js → uk-UA-QMV73CPH-KDqsoc0U.js} +1 -1
  119. package/dist/assets/{vi-VN-M7AON7JQ-CS2A77bJ.js → vi-VN-M7AON7JQ-Bi4HhiiT.js} +1 -1
  120. package/dist/assets/{xychartDiagram-e933f94c-CZyrBggG.js → xychartDiagram-e933f94c-3fzlFPno.js} +1 -1
  121. package/dist/assets/{zh-CN-LNUGB5OW-DRQ1XwJd.js → zh-CN-LNUGB5OW-DHhoDUCR.js} +1 -1
  122. package/dist/assets/{zh-HK-E62DVLB3-CgKd6NNi.js → zh-HK-E62DVLB3-lR9JAu6O.js} +1 -1
  123. package/dist/assets/{zh-TW-RAJ6MFWO-BNfMd8MA.js → zh-TW-RAJ6MFWO-BBleOG0l.js} +1 -1
  124. package/dist/index.html +5 -2
  125. package/index.html +3 -0
  126. package/modes/doc/manifest.ts +18 -5
  127. package/modes/doc/skill/SKILL.md +75 -4
  128. package/modes/draw/manifest.ts +16 -5
  129. package/modes/draw/skill/SKILL.md +9 -0
  130. package/modes/evolve/manifest.ts +65 -0
  131. package/modes/evolve/pneuma-mode.ts +35 -0
  132. package/modes/evolve/skill/SKILL.md +44 -0
  133. package/modes/evolve/skill/scripts/_shared.ts +179 -0
  134. package/modes/evolve/skill/scripts/extract-tool-flow.ts +116 -0
  135. package/modes/evolve/skill/scripts/list-sessions.ts +78 -0
  136. package/modes/evolve/skill/scripts/search-messages.ts +119 -0
  137. package/modes/evolve/skill/scripts/session-digest.ts +90 -0
  138. package/modes/evolve/skill/scripts/session-stats.ts +110 -0
  139. package/modes/evolve/viewer/EvolutionPreview.tsx +507 -0
  140. package/modes/mode-maker/manifest.ts +7 -3
  141. package/modes/mode-maker/seed/manifest.ts +7 -2
  142. package/modes/mode-maker/seed/skill/SKILL.md +40 -1
  143. package/modes/mode-maker/skill/SKILL.md +30 -1
  144. package/modes/slide/manifest.ts +20 -9
  145. package/package.json +1 -1
  146. package/server/__tests__/e2e-skill-effectiveness.test.ts +255 -0
  147. package/server/__tests__/evolution-agent.test.ts +152 -0
  148. package/server/__tests__/evolution-proposal.test.ts +359 -0
  149. package/server/evolution-agent.ts +438 -0
  150. package/server/evolution-proposal.ts +399 -0
  151. package/server/evolution-routes.ts +254 -0
  152. package/server/index.ts +6 -0
  153. package/dist/assets/Launcher-CZR8la9p.js +0 -1
  154. package/dist/assets/channel-BBUf9t84.js +0 -1
  155. package/dist/assets/clone-CaGGICgt.js +0 -1
  156. package/dist/assets/flowDiagram-v2-96b9c2cf-xRcXFevM.js +0 -1
  157. package/dist/assets/index-CcSl8aZo.css +0 -1
package/README.md CHANGED
@@ -24,7 +24,7 @@ When humans and code agents co-create content, they need more than a chat window
24
24
 
25
25
  **Skills** — Domain-specific knowledge and seed templates injected into the agent per mode. A presentation skill teaches layout, rhythm, and export; a document skill teaches prose and structure. Skills version and evolve with each release, and sessions persist across runs — the agent picks up where it left off.
26
26
 
27
- **Continuous Learning** *(v2.0)* — Skills today are static presets. The next step: mine cross-session conversation history to extract user preferences and style patterns, then dynamically augment the preset skill. During a session, the agent further adapts in real-time learning what "good" looks like for *this* user, in *this* domain, over time.
27
+ **Continuous Learning** — Skills aren't static presets. The Evolution Agent mines cross-session conversation history to extract user preferences and style patterns, then augments the preset skill with learned knowledge. Run `pneuma evolve <mode>` to analyze your history, review AI-generated proposals with evidence citations, and apply them to personalize your experience.
28
28
 
29
29
  **Distribution** — A complete ecosystem for sharing capabilities. Build a custom mode with AI assistance via Mode Maker, publish to the marketplace, and let anyone `pneuma mode add` it instantly.
30
30
 
@@ -36,6 +36,7 @@ When humans and code agents co-create content, they need more than a chat window
36
36
  | **slide** | HTML presentations — content sets, drag-reorder, presenter mode, PDF/image export |
37
37
  | **draw** | Excalidraw whiteboard with `.excalidraw` file editing |
38
38
  | **mode-maker** | Create custom modes with AI — fork, play-test, publish |
39
+ | **evolve** | Evolution Agent — analyze history, propose skill improvements, apply/rollback |
39
40
 
40
41
  ## Prerequisites
41
42
 
@@ -84,6 +85,7 @@ Modes:
84
85
  slide Presentation editing mode (HTML slides with iframe preview)
85
86
  draw Excalidraw whiteboard drawing mode
86
87
  mode-maker Create and develop custom modes with AI
88
+ evolve Launch the Evolution Agent for skill learning
87
89
  /path/to/mode Load mode from a local directory
88
90
  github:user/repo Load mode from a GitHub repository
89
91
  github:user/repo#branch Load mode from a specific branch/tag
@@ -99,6 +101,7 @@ Options:
99
101
  --dev Force dev mode (Vite)
100
102
 
101
103
  Subcommands:
104
+ evolve <mode> Analyze history and propose skill improvements
102
105
  mode add <url> Install a remote mode to ~/.pneuma/modes/
103
106
  mode list List published modes on the R2 registry
104
107
  mode publish Publish the current workspace as a mode
@@ -172,7 +175,7 @@ When Claude Code edits files, chokidar detects the changes and pushes updated co
172
175
  | **ViewerContract** | Preview component, context extraction, file workspace model, agent-callable actions | Custom renderers, viewport tracking, action protocols |
173
176
  | **AgentBackend** | Launch, resume, kill, capability declaration | Other agents (Codex, Aider) |
174
177
 
175
- Contracts are defined in `core/types/` with 274 tests across 17 test files.
178
+ Contracts are defined in `core/types/` with 316 tests across 20 test files.
176
179
 
177
180
  ## Project Structure
178
181
 
@@ -193,7 +196,8 @@ pneuma-skills/
193
196
  │ ├── doc/ # Doc Mode — markdown editing
194
197
  │ ├── slide/ # Slide Mode — presentation editing
195
198
  │ ├── draw/ # Draw Mode — Excalidraw whiteboard
196
- └── mode-maker/ # Mode Maker — create custom modes with AI
199
+ ├── mode-maker/ # Mode Maker — create custom modes with AI
200
+ │ └── evolve/ # Evolve Mode — evolution agent dashboard
197
201
  │ ├── manifest.ts # Mode manifest (fork, play, publish workflow)
198
202
  │ ├── seed/ # Template files for new modes
199
203
  │ ├── skill/ # Skill prompt for mode development
@@ -212,7 +216,10 @@ pneuma-skills/
212
216
  │ ├── terminal-manager.ts # PTY terminal sessions
213
217
  │ ├── path-resolver.ts # Binary PATH resolution (cross-platform)
214
218
  │ ├── system-bridge.ts # OS-level operations (open, reveal, openUrl)
215
- └── mode-maker-routes.ts # Mode Maker API routes (fork, play, publish, reset)
219
+ ├── mode-maker-routes.ts # Mode Maker API routes (fork, play, publish, reset)
220
+ │ ├── evolution-agent.ts # Evolution Agent launcher (spawns CC with analysis tools)
221
+ │ ├── evolution-proposal.ts # Proposal CRUD + apply/rollback + CLAUDE.md sync
222
+ │ └── evolution-routes.ts # Evolution API routes (/api/evolve/*)
216
223
  ├── src/
217
224
  │ ├── App.tsx # Root layout (dynamic viewer from store)
218
225
  │ ├── store.ts # Zustand state (session, messages, viewer)
@@ -276,6 +283,8 @@ pneuma-skills/
276
283
  - **Image upload** — Drag & drop or paste images into chat
277
284
  - **Viewer context enrichment** — `<viewer-context>` XML blocks align agent perception with user viewport
278
285
  - **Viewer action protocol** — Agent can invoke viewer capabilities (navigate, toggle UI, capture)
286
+ - **Evolution Agent** — `pneuma evolve <mode>` analyzes conversation history, proposes skill improvements with evidence
287
+ - **Proposal lifecycle** — Review, apply, rollback, discard, or fork proposals into custom modes
279
288
  - **Windows compatibility** — Cross-platform PATH resolution, terminal, browser opening, process management
280
289
  - **Debug mode** — `--debug` flag shows enriched CLI payloads for each message
281
290
 
@@ -298,13 +307,10 @@ pneuma-skills/
298
307
  - [x] Launcher process management — Monitor and kill child processes
299
308
  - [x] Next-gen visual redesign — Ethereal Tech aesthetic (glassmorphism, cinematic dark UI)
300
309
  - [x] Export & image capture — Slide export via `@zumer/snapdom`
310
+ - [x] Evolution Agent — AI-native continuous skill learning (`pneuma evolve <mode>`)
311
+ - [x] Skill effectiveness optimization — standardized claudeMdSection + YAML frontmatter for native skill discovery
301
312
  - [ ] Additional agent backends — Codex CLI, custom agents
302
-
303
- ### v2.0 — Continuous Learning
304
-
305
- - [ ] Cross-session preference extraction — mine conversation history to discover user style, tone, and layout preferences
306
- - [ ] Dynamic skill augmentation — automatically append learned preferences to preset skills at session start
307
- - [ ] In-session adaptation — agent refines its approach in real-time based on user feedback patterns
313
+ - [ ] In-session adaptation — agent refines its approach in real-time based on feedback within a session
308
314
 
309
315
  ## Acknowledgements
310
316
 
package/bin/pneuma.ts CHANGED
@@ -276,8 +276,308 @@ function checkClaudeCode() {
276
276
  }
277
277
  }
278
278
 
279
+ async function handleEvolveCommand(args: string[]) {
280
+ let workspace = process.cwd();
281
+ let modeName = "";
282
+ let subAction = ""; // "apply", "rollback", "show", or "" (propose)
283
+
284
+ for (let i = 0; i < args.length; i++) {
285
+ const arg = args[i];
286
+ if (arg === "--workspace" && i + 1 < args.length) {
287
+ workspace = resolve(args[++i]);
288
+ } else if (arg === "--mode" && i + 1 < args.length) {
289
+ modeName = args[++i];
290
+ } else if (["apply", "rollback", "show", "list"].includes(arg)) {
291
+ subAction = arg;
292
+ }
293
+ }
294
+
295
+ workspace = resolve(workspace);
296
+
297
+ const {
298
+ loadProposal, loadLatestProposal, listProposals,
299
+ applyProposal, rollbackProposal, formatProposalForDisplay,
300
+ } = await import("../server/evolution-proposal.js");
301
+
302
+ if (subAction === "list") {
303
+ const proposals = listProposals(workspace);
304
+ if (proposals.length === 0) {
305
+ p.log.info("No evolution proposals found.");
306
+ } else {
307
+ p.log.info(`${proposals.length} proposal(s):`);
308
+ for (const prop of proposals) {
309
+ const changesCount = prop.changes.length;
310
+ p.log.message(` ${prop.id} [${prop.status}] ${prop.mode} ${changesCount} change(s) ${prop.createdAt}`);
311
+ }
312
+ }
313
+ return;
314
+ }
315
+
316
+ if (subAction === "show") {
317
+ const proposal = loadLatestProposal(workspace);
318
+ if (!proposal) {
319
+ p.log.error("No proposals found. Run `pneuma evolve` first.");
320
+ process.exit(1);
321
+ }
322
+ console.log(formatProposalForDisplay(proposal));
323
+ return;
324
+ }
325
+
326
+ if (subAction === "apply") {
327
+ const proposal = loadLatestProposal(workspace);
328
+ if (!proposal) {
329
+ p.log.error("No proposals found. Run `pneuma evolve` first.");
330
+ process.exit(1);
331
+ }
332
+ if (proposal.status !== "pending") {
333
+ p.log.error(`Proposal ${proposal.id} is already ${proposal.status}.`);
334
+ process.exit(1);
335
+ }
336
+
337
+ console.log(formatProposalForDisplay(proposal));
338
+ console.log("");
339
+
340
+ const confirm = await p.confirm({ message: "Apply this proposal?" });
341
+ if (p.isCancel(confirm) || !confirm) {
342
+ p.log.info("Cancelled.");
343
+ return;
344
+ }
345
+
346
+ const result = applyProposal(workspace, proposal.id);
347
+ if (result.success) {
348
+ p.log.success(`Applied ${result.appliedFiles.length} file(s). Use \`pneuma evolve rollback\` to revert.`);
349
+ for (const f of result.appliedFiles) {
350
+ p.log.step(` ✓ ${f}`);
351
+ }
352
+ } else {
353
+ p.log.error(`Apply failed: ${result.error}`);
354
+ }
355
+ return;
356
+ }
357
+
358
+ if (subAction === "rollback") {
359
+ const proposals = listProposals(workspace);
360
+ const applied = proposals.find(p => p.status === "applied");
361
+ if (!applied) {
362
+ p.log.error("No applied proposals to rollback.");
363
+ process.exit(1);
364
+ }
365
+
366
+ const confirm = await p.confirm({ message: `Rollback proposal ${applied.id}?` });
367
+ if (p.isCancel(confirm) || !confirm) {
368
+ p.log.info("Cancelled.");
369
+ return;
370
+ }
371
+
372
+ const result = rollbackProposal(workspace, applied.id);
373
+ if (result.success) {
374
+ p.log.success(`Rolled back ${result.restoredFiles.length} file(s).`);
375
+ for (const f of result.restoredFiles) {
376
+ p.log.step(` ✓ ${f}`);
377
+ }
378
+ } else {
379
+ p.log.error(`Rollback failed: ${result.error}`);
380
+ }
381
+ return;
382
+ }
383
+
384
+ // Default: launch evolution agent as a standard pneuma session
385
+ let port = 0;
386
+ let noOpen = false;
387
+ let noPrompt = false;
388
+ let debug = false;
389
+ let forceDev = false;
390
+
391
+ // Re-parse flags from the evolve subcommand args
392
+ for (let i = 0; i < args.length; i++) {
393
+ const arg = args[i];
394
+ if (arg === "--port" && i + 1 < args.length) {
395
+ port = Number(args[++i]);
396
+ } else if (arg === "--no-open") {
397
+ noOpen = true;
398
+ } else if (arg === "--no-prompt") {
399
+ noPrompt = true;
400
+ } else if (arg === "--debug") {
401
+ debug = true;
402
+ } else if (arg === "--dev") {
403
+ forceDev = true;
404
+ }
405
+ }
406
+
407
+ // Resolve target mode from --mode flag or existing session
408
+ if (!modeName) {
409
+ const session = loadSession(workspace);
410
+ if (session?.mode) {
411
+ modeName = session.mode;
412
+ } else {
413
+ // Check if targetMode was passed via config (from Launcher)
414
+ const configPath = join(workspace, ".pneuma", "config.json");
415
+ try {
416
+ const config = JSON.parse(readFileSync(configPath, "utf-8"));
417
+ if (config.targetMode) modeName = config.targetMode;
418
+ } catch {}
419
+ }
420
+ if (!modeName) {
421
+ p.cancel("No mode specified and no .pneuma/session.json found.\nUse: pneuma evolve --mode <mode> --workspace <path>");
422
+ process.exit(1);
423
+ }
424
+ }
425
+
426
+ checkClaudeCode();
427
+
428
+ // 1. Resolve target mode and build evolution data
429
+ let resolved: ResolvedMode;
430
+ try {
431
+ resolved = await resolveModeSource(modeName, PROJECT_ROOT);
432
+ } catch (err) {
433
+ const msg = err instanceof Error ? err.message : String(err);
434
+ p.cancel(`Failed to resolve mode "${modeName}": ${msg}`);
435
+ process.exit(1);
436
+ }
437
+
438
+ if (resolved.type !== "builtin") {
439
+ registerExternalMode(resolved.name, resolved.path);
440
+ }
441
+
442
+ let manifest: ModeManifest;
443
+ try {
444
+ manifest = await loadModeManifest(resolved.name);
445
+ } catch (err) {
446
+ const msg = err instanceof Error ? err.message : String(err);
447
+ p.cancel(`Failed to load mode "${resolved.name}": ${msg}`);
448
+ process.exit(1);
449
+ }
450
+
451
+ p.log.step(`Evolving skill for ${manifest.displayName} mode...`);
452
+ p.log.info(`Workspace: ${workspace}`);
453
+
454
+ // 2. Build evolution prompt + metadata, save metadata as initParams
455
+ const { buildEvolutionPrompt, buildEvolutionMetadata } = await import("../server/evolution-agent.js");
456
+ const evolutionPrompt = buildEvolutionPrompt({ workspace, manifest });
457
+ const metadata = buildEvolutionMetadata({ workspace, manifest });
458
+
459
+ // Save metadata to .pneuma/config.json so the viewer dashboard can read it
460
+ const pneumaDir = join(workspace, ".pneuma");
461
+ mkdirSync(pneumaDir, { recursive: true });
462
+ writeFileSync(join(pneumaDir, "config.json"), JSON.stringify(metadata, null, 2));
463
+
464
+ // 3. Install evolve skill (so agent has dashboard context in SKILL.md)
465
+ const evolveManifest = await loadModeManifest("evolve");
466
+ const evolveModeSourceDir = join(PROJECT_ROOT, "modes", "evolve");
467
+ installSkill(workspace, evolveManifest.skill, evolveModeSourceDir, {}, evolveManifest.viewerApi);
468
+
469
+ // 4. Determine dev vs production mode
470
+ const distDir = resolve(PROJECT_ROOT, "dist");
471
+ const isDev = forceDev || !existsSync(join(distDir, "index.html"));
472
+ const effectivePort = port || (isDev ? 17007 : 17996);
473
+
474
+ // 5. Start server with evolution routes
475
+ const { server, wsBridge, port: actualPort } = startServer({
476
+ port: effectivePort,
477
+ workspace,
478
+ watchPatterns: [],
479
+ ...(isDev ? {} : { distDir }),
480
+ modeName: "evolve",
481
+ projectRoot: PROJECT_ROOT,
482
+ debug,
483
+ forceDev: isDev,
484
+ initParams: metadata as unknown as Record<string, string | number>,
485
+ });
486
+
487
+ // 6. Launch agent via ClaudeCodeBackend (fresh session, bypassPermissions)
488
+ const backend = new ClaudeCodeBackend(actualPort);
489
+ const session = backend.launch({
490
+ cwd: workspace,
491
+ permissionMode: "bypassPermissions",
492
+ });
493
+
494
+ p.log.info(`Agent session: ${session.sessionId}`);
495
+
496
+ // 7. Inject evolution prompt as greeting (dynamic, not from manifest)
497
+ wsBridge.injectGreeting(session.sessionId, evolutionPrompt);
498
+ console.log("[pneuma] Sent evolution prompt to agent");
499
+
500
+ // 8. Start Vite (dev) or serve dist (prod), open browser
501
+ let viteProc: ReturnType<typeof Bun.spawn> | null = null;
502
+ let browserPort = actualPort;
503
+
504
+ if (isDev) {
505
+ const VITE_PORT = 17996;
506
+ p.log.step(`Starting Vite dev server on port ${VITE_PORT}...`);
507
+
508
+ const viteEnv: Record<string, string> = {
509
+ ...process.env as Record<string, string>,
510
+ VITE_API_PORT: String(actualPort),
511
+ };
512
+
513
+ viteProc = Bun.spawn(
514
+ ["bunx", "vite", "--port", String(VITE_PORT)],
515
+ { cwd: PROJECT_ROOT, stdout: "pipe", stderr: "pipe", env: viteEnv },
516
+ );
517
+
518
+ let vitePortResolved = false;
519
+ browserPort = await new Promise<number>((resolvePort) => {
520
+ const timeout = setTimeout(() => {
521
+ if (!vitePortResolved) { vitePortResolved = true; resolvePort(VITE_PORT); }
522
+ }, 10_000);
523
+
524
+ const pipeAndParse = async (stream: ReadableStream<Uint8Array>) => {
525
+ const reader = stream.getReader();
526
+ const decoder = new TextDecoder();
527
+ while (true) {
528
+ const { done, value } = await reader.read();
529
+ if (done) break;
530
+ const text = decoder.decode(value, { stream: true });
531
+ for (const line of text.split("\n")) {
532
+ if (line.trim()) console.log(`[vite] ${line}`);
533
+ if (!vitePortResolved) {
534
+ const match = line.match(/Local:\s+https?:\/\/[^:]+:(\d+)/);
535
+ if (match) {
536
+ vitePortResolved = true;
537
+ clearTimeout(timeout);
538
+ resolvePort(parseInt(match[1], 10));
539
+ }
540
+ }
541
+ }
542
+ }
543
+ };
544
+ if (viteProc!.stdout && typeof viteProc!.stdout !== "number") pipeAndParse(viteProc!.stdout);
545
+ if (viteProc!.stderr && typeof viteProc!.stderr !== "number") pipeAndParse(viteProc!.stderr);
546
+ });
547
+ }
548
+
549
+ // 9. Open browser with evolution mode dashboard
550
+ const debugParam = debug ? "&debug=1" : "";
551
+ const browserUrl = `http://localhost:${browserPort}?session=${session.sessionId}&mode=evolve${debugParam}`;
552
+ console.log(`[pneuma] ready ${browserUrl}`);
553
+
554
+ if (!noOpen) {
555
+ p.log.success(`Ready → ${browserUrl}`);
556
+ try {
557
+ if (process.platform === "win32") {
558
+ Bun.spawn(["cmd", "/c", "start", "", browserUrl], { stdout: "ignore", stderr: "ignore" });
559
+ } else {
560
+ const opener = process.platform === "darwin" ? "open" : "xdg-open";
561
+ Bun.spawn([opener, browserUrl], { stdout: "ignore", stderr: "ignore" });
562
+ }
563
+ } catch {
564
+ p.log.warn(`Could not open browser. Visit: ${browserUrl}`);
565
+ }
566
+ }
567
+
568
+ // 10. Graceful shutdown
569
+ const shutdown = async () => {
570
+ viteProc?.kill();
571
+ await backend.killAll();
572
+ server.stop(true);
573
+ p.outro("Goodbye!");
574
+ process.exit(0);
575
+ };
576
+ process.on("SIGINT", shutdown);
577
+ process.on("SIGTERM", shutdown);
578
+ }
579
+
279
580
  async function main() {
280
- // Read version from package.json
281
581
  const pkgPath = join(PROJECT_ROOT, "package.json");
282
582
  const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
283
583
 
@@ -352,6 +652,16 @@ async function main() {
352
652
  // Unknown mode subcommand — fall through to normal mode resolution
353
653
  }
354
654
 
655
+ // Evolve subcommand — AI-native skill evolution
656
+ // Find "evolve" in rawArgs (may be preceded by flags like --dev)
657
+ const evolveIdx = rawArgs.findIndex(a => a === "evolve");
658
+ if (evolveIdx !== -1) {
659
+ // Pass all args except "evolve" itself to the handler
660
+ const evolveArgs = [...rawArgs.slice(0, evolveIdx), ...rawArgs.slice(evolveIdx + 1)];
661
+ await handleEvolveCommand(evolveArgs);
662
+ return;
663
+ }
664
+
355
665
  const { mode, workspace, port, noOpen, debug, forceDev, noPrompt, skipSkill } = parseArgs(process.argv);
356
666
 
357
667
  // Launcher mode — no mode arg → start marketplace UI
@@ -61,6 +61,13 @@ const builtinModes: Record<string, ModeSource> = {
61
61
  definitionLoader: () =>
62
62
  import("../modes/mode-maker/pneuma-mode.js").then((m) => m.default),
63
63
  },
64
+ evolve: {
65
+ type: "builtin",
66
+ manifestLoader: () =>
67
+ import("../modes/evolve/manifest.js").then((m) => m.default),
68
+ definitionLoader: () =>
69
+ import("../modes/evolve/pneuma-mode.js").then((m) => m.default),
70
+ },
64
71
  };
65
72
 
66
73
  /** 外部 mode 注册表 — 由 CLI 在启动时通过 registerExternalMode 注册 */
@@ -14,6 +14,8 @@ export type {
14
14
  AgentPreferences,
15
15
  InitConfig,
16
16
  ViewerApiConfig,
17
+ EvolutionConfig,
18
+ EvolutionTool,
17
19
  } from "./mode-manifest.js";
18
20
 
19
21
  export type {
@@ -159,6 +159,47 @@ export interface ViewerApiConfig {
159
159
  };
160
160
  }
161
161
 
162
+ /**
163
+ * Skill 演进配置 — 定义 Evolution Agent 的目标方向和可用工具。
164
+ *
165
+ * Evolution Agent 是一个独立的 Agent 过程,分析用户历史并增强 skill 文件。
166
+ * 它输出一个 proposal(附带证据和引用),用户审核后可 apply 或取消。
167
+ */
168
+ export interface EvolutionConfig {
169
+ /**
170
+ * 演进方向 — 给 Evolution Agent 的目标描述。
171
+ * 告诉 Agent 这个 Mode 的 skill 应该朝什么方向个性化。
172
+ *
173
+ * @example
174
+ * "Learn the user's presentation style preferences: typography choices,
175
+ * color palette tendencies, layout density, slide structure patterns.
176
+ * Augment the skill to guide the main agent toward these preferences
177
+ * as defaults while respecting explicit user instructions."
178
+ */
179
+ directive: string;
180
+
181
+ /**
182
+ * 额外的数据获取工具(预留,第一版不实现)。
183
+ * 框架已内置基础工具(读取 CC 历史等),这里声明 Mode 特有的。
184
+ */
185
+ tools?: EvolutionTool[];
186
+ }
187
+
188
+ /**
189
+ * Evolution Agent 可用的外部数据获取工具(预留)。
190
+ * 第一版不实现,框架内置工具足够。
191
+ */
192
+ export interface EvolutionTool {
193
+ /** 工具名称 */
194
+ name: string;
195
+ /** 工具描述(给 Agent 看的) */
196
+ description: string;
197
+ /** 实现方式 */
198
+ type: "command" | "http" | "mcp";
199
+ /** 具体配置 */
200
+ config: Record<string, unknown>;
201
+ }
202
+
162
203
  /** Mode 的完整声明式描述 */
163
204
  export interface ModeManifest {
164
205
  /** Mode 唯一标识 (e.g. "doc", "slide") */
@@ -182,4 +223,6 @@ export interface ModeManifest {
182
223
  init?: InitConfig;
183
224
  /** Viewer 自描述 API — 纯数据声明,后端可读,自动注入 CLAUDE.md */
184
225
  viewerApi?: ViewerApiConfig;
226
+ /** Skill 演进配置 — 定义 Evolution Agent 的演进方向 (可选) */
227
+ evolution?: EvolutionConfig;
185
228
  }