create-principles-disciple 1.76.0 → 1.78.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 (217) hide show
  1. package/console/dist/server/config/feature-flags.d.ts +25 -0
  2. package/console/dist/server/config/feature-flags.js +101 -0
  3. package/console/dist/server/index.js +16 -0
  4. package/console/dist/server/models/FeedbackReportConsoleModel.d.ts +49 -0
  5. package/console/dist/server/models/FeedbackReportConsoleModel.js +242 -0
  6. package/console/dist/server/routes/feedback-reports.d.ts +18 -0
  7. package/console/dist/server/routes/feedback-reports.js +165 -0
  8. package/console/dist/ui/App.js +2 -1
  9. package/console/dist/ui/api.d.ts +26 -2
  10. package/console/dist/ui/api.js +18 -1
  11. package/console/dist/ui/components/app-sidebar.js +2 -1
  12. package/console/dist/ui/components/error-boundary.js +9 -2
  13. package/console/dist/ui/i18n/en.json +67 -1
  14. package/console/dist/ui/i18n/zh-CN.json +67 -1
  15. package/console/dist/ui/pages/ReportProblemPage.d.ts +1 -0
  16. package/console/dist/ui/pages/ReportProblemPage.js +186 -0
  17. package/console/dist/ui/pages/ReportProblemValidators.d.ts +51 -0
  18. package/console/dist/ui/pages/ReportProblemValidators.js +114 -0
  19. package/console/dist/web/assets/app.css +18 -0
  20. package/console/dist/web/assets/app.js +1047 -125
  21. package/console/package.json +1 -0
  22. package/core/dist/runtime-v2/__tests__/architecture-regression.test.js +24 -1
  23. package/core/dist/runtime-v2/__tests__/architecture-regression.test.js.map +1 -1
  24. package/core/dist/runtime-v2/__tests__/feedback/create-report.test.d.ts +2 -0
  25. package/core/dist/runtime-v2/__tests__/feedback/create-report.test.d.ts.map +1 -0
  26. package/core/dist/runtime-v2/__tests__/feedback/create-report.test.js +402 -0
  27. package/core/dist/runtime-v2/__tests__/feedback/create-report.test.js.map +1 -0
  28. package/core/dist/runtime-v2/__tests__/feedback/privacy-preview.test.d.ts +2 -0
  29. package/core/dist/runtime-v2/__tests__/feedback/privacy-preview.test.d.ts.map +1 -0
  30. package/core/dist/runtime-v2/__tests__/feedback/privacy-preview.test.js +128 -0
  31. package/core/dist/runtime-v2/__tests__/feedback/privacy-preview.test.js.map +1 -0
  32. package/core/dist/runtime-v2/__tests__/feedback/redact-sensitive.test.d.ts +2 -0
  33. package/core/dist/runtime-v2/__tests__/feedback/redact-sensitive.test.d.ts.map +1 -0
  34. package/core/dist/runtime-v2/__tests__/feedback/redact-sensitive.test.js +231 -0
  35. package/core/dist/runtime-v2/__tests__/feedback/redact-sensitive.test.js.map +1 -0
  36. package/core/dist/runtime-v2/__tests__/feedback/render-github-url.test.d.ts +2 -0
  37. package/core/dist/runtime-v2/__tests__/feedback/render-github-url.test.d.ts.map +1 -0
  38. package/core/dist/runtime-v2/__tests__/feedback/render-github-url.test.js +102 -0
  39. package/core/dist/runtime-v2/__tests__/feedback/render-github-url.test.js.map +1 -0
  40. package/core/dist/runtime-v2/__tests__/feedback/render-markdown.test.d.ts +2 -0
  41. package/core/dist/runtime-v2/__tests__/feedback/render-markdown.test.d.ts.map +1 -0
  42. package/core/dist/runtime-v2/__tests__/feedback/render-markdown.test.js +130 -0
  43. package/core/dist/runtime-v2/__tests__/feedback/render-markdown.test.js.map +1 -0
  44. package/core/dist/runtime-v2/__tests__/workspace-guidance-migration.test.d.ts +2 -0
  45. package/core/dist/runtime-v2/__tests__/workspace-guidance-migration.test.d.ts.map +1 -0
  46. package/core/dist/runtime-v2/__tests__/workspace-guidance-migration.test.js +328 -0
  47. package/core/dist/runtime-v2/__tests__/workspace-guidance-migration.test.js.map +1 -0
  48. package/core/dist/runtime-v2/activation/__tests__/prompt-activation-reader-contract.test.d.ts +2 -0
  49. package/core/dist/runtime-v2/activation/__tests__/prompt-activation-reader-contract.test.d.ts.map +1 -0
  50. package/core/dist/runtime-v2/activation/__tests__/prompt-activation-reader-contract.test.js +343 -0
  51. package/core/dist/runtime-v2/activation/__tests__/prompt-activation-reader-contract.test.js.map +1 -0
  52. package/core/dist/runtime-v2/activation/index.d.ts +2 -0
  53. package/core/dist/runtime-v2/activation/index.d.ts.map +1 -1
  54. package/core/dist/runtime-v2/activation/index.js +1 -0
  55. package/core/dist/runtime-v2/activation/index.js.map +1 -1
  56. package/core/dist/runtime-v2/activation/prompt-activation-reader-contract.d.ts +34 -0
  57. package/core/dist/runtime-v2/activation/prompt-activation-reader-contract.d.ts.map +1 -0
  58. package/core/dist/runtime-v2/activation/prompt-activation-reader-contract.js +109 -0
  59. package/core/dist/runtime-v2/activation/prompt-activation-reader-contract.js.map +1 -0
  60. package/core/dist/runtime-v2/feature-flags/__tests__/feature-flag-contract.test.js +13 -0
  61. package/core/dist/runtime-v2/feature-flags/__tests__/feature-flag-contract.test.js.map +1 -1
  62. package/core/dist/runtime-v2/feature-flags/__tests__/plugin-surface-registry.test.d.ts +2 -0
  63. package/core/dist/runtime-v2/feature-flags/__tests__/plugin-surface-registry.test.d.ts.map +1 -0
  64. package/core/dist/runtime-v2/feature-flags/__tests__/plugin-surface-registry.test.js +141 -0
  65. package/core/dist/runtime-v2/feature-flags/__tests__/plugin-surface-registry.test.js.map +1 -0
  66. package/core/dist/runtime-v2/feature-flags/feature-flag-contract.d.ts.map +1 -1
  67. package/core/dist/runtime-v2/feature-flags/feature-flag-contract.js +4 -1
  68. package/core/dist/runtime-v2/feature-flags/feature-flag-contract.js.map +1 -1
  69. package/core/dist/runtime-v2/feature-flags/index.d.ts +2 -0
  70. package/core/dist/runtime-v2/feature-flags/index.d.ts.map +1 -1
  71. package/core/dist/runtime-v2/feature-flags/index.js +1 -0
  72. package/core/dist/runtime-v2/feature-flags/index.js.map +1 -1
  73. package/core/dist/runtime-v2/feature-flags/plugin-surface-registry.d.ts +25 -0
  74. package/core/dist/runtime-v2/feature-flags/plugin-surface-registry.d.ts.map +1 -0
  75. package/core/dist/runtime-v2/feature-flags/plugin-surface-registry.js +233 -0
  76. package/core/dist/runtime-v2/feature-flags/plugin-surface-registry.js.map +1 -0
  77. package/core/dist/runtime-v2/feedback/create-report.d.ts +14 -0
  78. package/core/dist/runtime-v2/feedback/create-report.d.ts.map +1 -0
  79. package/core/dist/runtime-v2/feedback/create-report.js +257 -0
  80. package/core/dist/runtime-v2/feedback/create-report.js.map +1 -0
  81. package/core/dist/runtime-v2/feedback/feedback-types.d.ts +120 -0
  82. package/core/dist/runtime-v2/feedback/feedback-types.d.ts.map +1 -0
  83. package/core/dist/runtime-v2/feedback/feedback-types.js +243 -0
  84. package/core/dist/runtime-v2/feedback/feedback-types.js.map +1 -0
  85. package/core/dist/runtime-v2/feedback/index.d.ts +9 -0
  86. package/core/dist/runtime-v2/feedback/index.d.ts.map +1 -0
  87. package/core/dist/runtime-v2/feedback/index.js +11 -0
  88. package/core/dist/runtime-v2/feedback/index.js.map +1 -0
  89. package/core/dist/runtime-v2/feedback/internal-guards.d.ts +2 -0
  90. package/core/dist/runtime-v2/feedback/internal-guards.d.ts.map +1 -0
  91. package/core/dist/runtime-v2/feedback/internal-guards.js +6 -0
  92. package/core/dist/runtime-v2/feedback/internal-guards.js.map +1 -0
  93. package/core/dist/runtime-v2/feedback/privacy-preview.d.ts +14 -0
  94. package/core/dist/runtime-v2/feedback/privacy-preview.d.ts.map +1 -0
  95. package/core/dist/runtime-v2/feedback/privacy-preview.js +128 -0
  96. package/core/dist/runtime-v2/feedback/privacy-preview.js.map +1 -0
  97. package/core/dist/runtime-v2/feedback/redact-sensitive.d.ts +37 -0
  98. package/core/dist/runtime-v2/feedback/redact-sensitive.d.ts.map +1 -0
  99. package/core/dist/runtime-v2/feedback/redact-sensitive.js +272 -0
  100. package/core/dist/runtime-v2/feedback/redact-sensitive.js.map +1 -0
  101. package/core/dist/runtime-v2/feedback/render-github-url.d.ts +21 -0
  102. package/core/dist/runtime-v2/feedback/render-github-url.d.ts.map +1 -0
  103. package/core/dist/runtime-v2/feedback/render-github-url.js +57 -0
  104. package/core/dist/runtime-v2/feedback/render-github-url.js.map +1 -0
  105. package/core/dist/runtime-v2/feedback/render-markdown.d.ts +12 -0
  106. package/core/dist/runtime-v2/feedback/render-markdown.d.ts.map +1 -0
  107. package/core/dist/runtime-v2/feedback/render-markdown.js +166 -0
  108. package/core/dist/runtime-v2/feedback/render-markdown.js.map +1 -0
  109. package/core/dist/runtime-v2/feedback/safe-stringify.d.ts +6 -0
  110. package/core/dist/runtime-v2/feedback/safe-stringify.d.ts.map +1 -0
  111. package/core/dist/runtime-v2/feedback/safe-stringify.js +115 -0
  112. package/core/dist/runtime-v2/feedback/safe-stringify.js.map +1 -0
  113. package/core/dist/runtime-v2/index.d.ts +8 -1
  114. package/core/dist/runtime-v2/index.d.ts.map +1 -1
  115. package/core/dist/runtime-v2/index.js +12 -1
  116. package/core/dist/runtime-v2/index.js.map +1 -1
  117. package/core/dist/runtime-v2/workspace-guidance-migration.d.ts +12 -0
  118. package/core/dist/runtime-v2/workspace-guidance-migration.d.ts.map +1 -0
  119. package/core/dist/runtime-v2/workspace-guidance-migration.js +193 -0
  120. package/core/dist/runtime-v2/workspace-guidance-migration.js.map +1 -0
  121. package/core/package.json +4 -0
  122. package/package.json +1 -1
  123. package/plugin/dist/commands/context.js +5 -5
  124. package/plugin/dist/commands/strategy.d.ts +0 -1
  125. package/plugin/dist/commands/strategy.js +0 -14
  126. package/plugin/dist/core/runtime-v2-prompt-activation-reader.d.ts +4 -13
  127. package/plugin/dist/core/runtime-v2-prompt-activation-reader.js +36 -74
  128. package/plugin/dist/core/surface-guard.d.ts +27 -0
  129. package/plugin/dist/core/surface-guard.js +82 -0
  130. package/plugin/dist/core/workspace-guidance-migrator.d.ts +12 -0
  131. package/plugin/dist/core/workspace-guidance-migrator.js +141 -0
  132. package/plugin/dist/hooks/prompt.js +20 -143
  133. package/plugin/dist/i18n/commands.js +2 -14
  134. package/plugin/dist/index.d.ts +27 -0
  135. package/plugin/dist/index.js +180 -65
  136. package/plugin/dist/service/correction-observer-service.d.ts +11 -0
  137. package/plugin/dist/service/correction-observer-service.js +172 -0
  138. package/plugin/dist/service/evolution-worker.js +1 -110
  139. package/plugin/dist/types.d.ts +2 -2
  140. package/plugin/dist/types.js +3 -3
  141. package/plugin/templates/langs/en/core/BOOTSTRAP.md +5 -19
  142. package/plugin/templates/langs/en/principles/THINKING_OS.md +1 -1
  143. package/plugin/templates/langs/en/skills/admin/SKILL.md +2 -2
  144. package/plugin/templates/langs/en/skills/bootstrap-tools/SKILL.md +1 -1
  145. package/plugin/templates/langs/en/skills/init-strategy/SKILL.md +1 -1
  146. package/plugin/templates/langs/en/skills/pd-mentor/SKILL.md +8 -23
  147. package/plugin/templates/langs/en/skills/reflection/SKILL.md +2 -2
  148. package/plugin/templates/langs/en/skills/report/SKILL.md +1 -1
  149. package/plugin/templates/langs/zh/core/BOOTSTRAP.md +3 -16
  150. package/plugin/templates/langs/zh/principles/THINKING_OS.md +1 -1
  151. package/plugin/templates/langs/zh/skills/admin/SKILL.md +2 -2
  152. package/plugin/templates/langs/zh/skills/bootstrap-tools/SKILL.md +1 -1
  153. package/plugin/templates/langs/zh/skills/init-strategy/SKILL.md +1 -1
  154. package/plugin/templates/langs/zh/skills/pd-mentor/SKILL.md +7 -22
  155. package/plugin/templates/langs/zh/skills/reflection/SKILL.md +2 -2
  156. package/plugin/templates/langs/zh/skills/report/SKILL.md +1 -1
  157. package/plugin/templates/workspace/.principles/THINKING_OS.md +1 -1
  158. package/templates/langs/en/core/BOOTSTRAP.md +1 -1
  159. package/templates/langs/en/principles/THINKING_OS.md +1 -1
  160. package/templates/langs/en/skills/admin/SKILL.md +2 -2
  161. package/templates/langs/en/skills/pd-grooming/SKILL.md +1 -1
  162. package/templates/langs/en/skills/reflection/SKILL.md +2 -2
  163. package/templates/langs/en/skills/report/SKILL.md +1 -1
  164. package/templates/langs/zh/core/BOOTSTRAP.md +1 -1
  165. package/templates/langs/zh/principles/THINKING_OS.md +1 -1
  166. package/templates/langs/zh/skills/admin/SKILL.md +2 -2
  167. package/templates/langs/zh/skills/pd-grooming/SKILL.md +1 -1
  168. package/templates/langs/zh/skills/reflection/SKILL.md +2 -2
  169. package/templates/langs/zh/skills/report/SKILL.md +1 -1
  170. package/plugin/templates/langs/en/skills/ai-sprint-orchestration/EXAMPLES.md +0 -63
  171. package/plugin/templates/langs/en/skills/ai-sprint-orchestration/REFERENCE.md +0 -136
  172. package/plugin/templates/langs/en/skills/ai-sprint-orchestration/SKILL.md +0 -67
  173. package/plugin/templates/langs/en/skills/ai-sprint-orchestration/references/agent-registry.json +0 -143
  174. package/plugin/templates/langs/en/skills/ai-sprint-orchestration/references/specs/bugfix-complex-template.json +0 -107
  175. package/plugin/templates/langs/en/skills/ai-sprint-orchestration/references/specs/feature-complex-template.json +0 -107
  176. package/plugin/templates/langs/en/skills/ai-sprint-orchestration/references/specs/workflow-validation-minimal-verify.json +0 -95
  177. package/plugin/templates/langs/en/skills/ai-sprint-orchestration/references/specs/workflow-validation-minimal.json +0 -98
  178. package/plugin/templates/langs/en/skills/ai-sprint-orchestration/references/workflow-v1-acceptance-checklist.md +0 -58
  179. package/plugin/templates/langs/en/skills/ai-sprint-orchestration/references/workflow-v1.4-work-unit-handoff.md +0 -190
  180. package/plugin/templates/langs/en/skills/ai-sprint-orchestration/scripts/lib/archive.mjs +0 -310
  181. package/plugin/templates/langs/en/skills/ai-sprint-orchestration/scripts/lib/contract-enforcement.mjs +0 -683
  182. package/plugin/templates/langs/en/skills/ai-sprint-orchestration/scripts/lib/decision.mjs +0 -604
  183. package/plugin/templates/langs/en/skills/ai-sprint-orchestration/scripts/lib/state-store.mjs +0 -32
  184. package/plugin/templates/langs/en/skills/ai-sprint-orchestration/scripts/lib/task-specs.mjs +0 -707
  185. package/plugin/templates/langs/en/skills/ai-sprint-orchestration/scripts/run.mjs +0 -3455
  186. package/plugin/templates/langs/en/skills/evolve-system/SKILL.md +0 -46
  187. package/plugin/templates/langs/en/skills/manage-okr/SKILL.md +0 -96
  188. package/plugin/templates/langs/en/skills/pd-daily/SKILL.md +0 -199
  189. package/plugin/templates/langs/en/skills/pd-grooming/SKILL.md +0 -46
  190. package/plugin/templates/langs/zh/skills/ai-sprint-orchestration/EXAMPLES.md +0 -63
  191. package/plugin/templates/langs/zh/skills/ai-sprint-orchestration/REFERENCE.md +0 -136
  192. package/plugin/templates/langs/zh/skills/ai-sprint-orchestration/SKILL.md +0 -67
  193. package/plugin/templates/langs/zh/skills/ai-sprint-orchestration/references/agent-registry.json +0 -143
  194. package/plugin/templates/langs/zh/skills/ai-sprint-orchestration/references/specs/bugfix-complex-template.json +0 -107
  195. package/plugin/templates/langs/zh/skills/ai-sprint-orchestration/references/specs/feature-complex-template.json +0 -107
  196. package/plugin/templates/langs/zh/skills/ai-sprint-orchestration/references/specs/nocturnal-trinity-quality-enhancement.json +0 -111
  197. package/plugin/templates/langs/zh/skills/ai-sprint-orchestration/references/specs/workflow-validation-minimal-verify.json +0 -95
  198. package/plugin/templates/langs/zh/skills/ai-sprint-orchestration/references/specs/workflow-validation-minimal.json +0 -98
  199. package/plugin/templates/langs/zh/skills/ai-sprint-orchestration/references/workflow-v1-acceptance-checklist.md +0 -58
  200. package/plugin/templates/langs/zh/skills/ai-sprint-orchestration/references/workflow-v1.4-work-unit-handoff.md +0 -190
  201. package/plugin/templates/langs/zh/skills/ai-sprint-orchestration/runtime/.gitignore +0 -2
  202. package/plugin/templates/langs/zh/skills/ai-sprint-orchestration/scripts/lib/archive.mjs +0 -310
  203. package/plugin/templates/langs/zh/skills/ai-sprint-orchestration/scripts/lib/contract-enforcement.mjs +0 -683
  204. package/plugin/templates/langs/zh/skills/ai-sprint-orchestration/scripts/lib/decision.mjs +0 -604
  205. package/plugin/templates/langs/zh/skills/ai-sprint-orchestration/scripts/lib/state-store.mjs +0 -32
  206. package/plugin/templates/langs/zh/skills/ai-sprint-orchestration/scripts/lib/task-specs.mjs +0 -707
  207. package/plugin/templates/langs/zh/skills/ai-sprint-orchestration/scripts/run.mjs +0 -3455
  208. package/plugin/templates/langs/zh/skills/ai-sprint-orchestration/test/archive.test.mjs +0 -230
  209. package/plugin/templates/langs/zh/skills/ai-sprint-orchestration/test/contract-enforcement.test.mjs +0 -672
  210. package/plugin/templates/langs/zh/skills/ai-sprint-orchestration/test/decision.test.mjs +0 -1321
  211. package/plugin/templates/langs/zh/skills/ai-sprint-orchestration/test/run.test.mjs +0 -1435
  212. package/plugin/templates/langs/zh/skills/evolve-system/SKILL.md +0 -46
  213. package/plugin/templates/langs/zh/skills/manage-okr/SKILL.md +0 -109
  214. package/plugin/templates/langs/zh/skills/pd-daily/SKILL.md +0 -283
  215. package/plugin/templates/langs/zh/skills/pd-grooming/SKILL.md +0 -46
  216. package/plugin/templates/workspace/PLAN.md +0 -2
  217. package/templates/workspace/PLAN.md +0 -2
@@ -0,0 +1,231 @@
1
+ // redact-sensitive.test.ts
2
+ // ERR-001/005: no `as` casts on untrusted input.
3
+ // ERR-002: structured return with reason/nextAction.
4
+ // ERR-003: segment-exact key matching, never substring.
5
+ // ERR-014/016/017: bounded output, BigInt-safe, no throws on non-string.
6
+ import { describe, it, expect } from 'vitest';
7
+ import { redactAbsolutePaths, redactTokenLikeValues, redactEnvLikeValues, redactStackTrace, redactSensitiveFields, REDACTED_PATH, REDACTED_VALUE, } from '../../feedback/redact-sensitive.js';
8
+ describe('redactAbsolutePaths', () => {
9
+ it('replaces Windows-style absolute paths with <redacted-path>', () => {
10
+ const text = 'See C:\\Users\\alice\\project\\file.ts for details';
11
+ const result = redactAbsolutePaths(text);
12
+ expect(result).toContain(REDACTED_PATH);
13
+ expect(result).not.toContain('C:\\Users\\alice');
14
+ });
15
+ it('replaces POSIX absolute paths with <redacted-path>', () => {
16
+ const text = 'Config at /home/alice/.config/app/settings.json';
17
+ const result = redactAbsolutePaths(text);
18
+ expect(result).toContain(REDACTED_PATH);
19
+ expect(result).not.toContain('/home/alice');
20
+ });
21
+ it('leaves relative paths alone', () => {
22
+ const text = 'Open src/index.ts and ./relative/path.ts please';
23
+ const result = redactAbsolutePaths(text);
24
+ expect(result).toBe(text);
25
+ });
26
+ it('handles multiple absolute paths in one string', () => {
27
+ const text = 'From C:\\a\\b.ts to D:\\c\\d.ts works';
28
+ const result = redactAbsolutePaths(text);
29
+ const matches = result.match(new RegExp(REDACTED_PATH.replace(/[<>]/g, '\\$&'), 'g'));
30
+ expect(matches?.length ?? 0).toBeGreaterThanOrEqual(2);
31
+ });
32
+ });
33
+ describe('redactTokenLikeValues', () => {
34
+ it('redacts OpenAI-style sk- tokens', () => {
35
+ const text = 'My key is sk-abcdefghijklmnopqrstuvwxyz0123456789ABCDEF and it works';
36
+ const result = redactTokenLikeValues(text);
37
+ expect(result).toContain(REDACTED_VALUE);
38
+ expect(result).not.toContain('sk-abcdefghijklmnopqrstuvwxyz');
39
+ });
40
+ it('redacts GitHub-style ghp_ tokens', () => {
41
+ const text = 'Token: ghp_1234567890abcdefghijklmnopqrstuvwxyzABCD';
42
+ const result = redactTokenLikeValues(text);
43
+ expect(result).toContain(REDACTED_VALUE);
44
+ expect(result).not.toContain('ghp_1234567890');
45
+ });
46
+ it('redacts "Bearer xxx" headers', () => {
47
+ const text = 'Authorization: Bearer abc123.def456.ghi789';
48
+ const result = redactTokenLikeValues(text);
49
+ expect(result).toContain(REDACTED_VALUE);
50
+ expect(result).not.toContain('abc123.def456.ghi789');
51
+ });
52
+ it('redacts api_key= and token= style assignments', () => {
53
+ const text = 'config: api_key=mysecretvalue and token=othertokenvalue';
54
+ const result = redactTokenLikeValues(text);
55
+ expect(result).toContain(REDACTED_VALUE);
56
+ expect(result).not.toContain('mysecretvalue');
57
+ expect(result).not.toContain('othertokenvalue');
58
+ });
59
+ it('leaves normal text alone', () => {
60
+ const text = 'This is a normal sentence with no tokens inside.';
61
+ const result = redactTokenLikeValues(text);
62
+ expect(result).toBe(text);
63
+ });
64
+ });
65
+ describe('redactEnvLikeValues', () => {
66
+ it('redacts KEY=value patterns', () => {
67
+ const text = 'Run with API_KEY=verysecretvalue and continue';
68
+ const result = redactEnvLikeValues(text);
69
+ expect(result).toContain(REDACTED_VALUE);
70
+ expect(result).not.toContain('verysecretvalue');
71
+ });
72
+ it('redacts KEY="value" quoted patterns', () => {
73
+ const text = 'export DATABASE_URL="postgres://user:pass@host/db"';
74
+ const result = redactEnvLikeValues(text);
75
+ expect(result).toContain(REDACTED_VALUE);
76
+ expect(result).not.toContain('user:pass@host');
77
+ });
78
+ it('leaves normal text alone', () => {
79
+ const text = 'There is no env var assignment in this sentence.';
80
+ const result = redactEnvLikeValues(text);
81
+ expect(result).toBe(text);
82
+ });
83
+ });
84
+ describe('redactStackTrace', () => {
85
+ it('returns error name + bounded top frame for full stack', () => {
86
+ const text = [
87
+ 'TypeError: cannot read property foo of undefined',
88
+ ' at doWork (C:\\Users\\alice\\project\\src\\a.ts:10:5)',
89
+ ' at callIt (C:\\Users\\alice\\project\\src\\b.ts:25:3)',
90
+ ' at handle (C:\\Users\\alice\\project\\src\\c.ts:99:1)',
91
+ ].join('\n');
92
+ const result = redactStackTrace(text, 1);
93
+ expect(result).toContain('TypeError');
94
+ expect(result).toContain(REDACTED_PATH);
95
+ expect(result).not.toContain('b.ts');
96
+ expect(result).not.toContain('c.ts');
97
+ });
98
+ it('returns "<no-stack>" for empty input', () => {
99
+ expect(redactStackTrace('', 3)).toBe('<no-stack>');
100
+ });
101
+ });
102
+ describe('redactSensitiveFields', () => {
103
+ it('redacts exact sensitive keys (password, token, secret, apiKey, authorization)', () => {
104
+ const input = {
105
+ username: 'alice',
106
+ password: 'supersecret',
107
+ token: 'tok_abc123',
108
+ apiKey: 'ak_live_123',
109
+ authorization: 'Bearer xyz',
110
+ };
111
+ const result = redactSensitiveFields(input);
112
+ expect(result.ok).toBe(true);
113
+ if (!result.ok)
114
+ return;
115
+ const redacted = result.value;
116
+ expect(redacted.username).toBe('alice');
117
+ expect(redacted.password).toBe(REDACTED_VALUE);
118
+ expect(redacted.token).toBe(REDACTED_VALUE);
119
+ expect(redacted.apiKey).toBe(REDACTED_VALUE);
120
+ expect(redacted.authorization).toBe(REDACTED_VALUE);
121
+ expect(result.notes.length).toBeGreaterThan(0);
122
+ });
123
+ it('uses segment-exact key matching (not substring) — "author" should NOT match "auth"', () => {
124
+ const input = { author: 'alice', authenticated: true, authtoken: 'should-redact' };
125
+ const result = redactSensitiveFields(input);
126
+ expect(result.ok).toBe(true);
127
+ if (!result.ok)
128
+ return;
129
+ const redacted = result.value;
130
+ expect(redacted.author).toBe('alice');
131
+ expect(redacted.authenticated).toBe(true);
132
+ // "authtoken" is not a sensitive segment; only exact "authorization" / "auth_token" / "authtoken" forms should match
133
+ // We test that "author" (containing "auth") is NOT redacted (substring pattern is the bug)
134
+ expect(redacted.author).not.toBe(REDACTED_VALUE);
135
+ });
136
+ it('handles circular references without throwing', () => {
137
+ const input = { name: 'root' };
138
+ input.self = input;
139
+ const result = redactSensitiveFields(input);
140
+ expect(result.ok).toBe(true);
141
+ if (!result.ok)
142
+ return;
143
+ const redacted = result.value;
144
+ expect(redacted.name).toBe('root');
145
+ // The circular self-reference should be marked as a redaction note
146
+ expect(result.notes.some((n) => n.includes('circular') || n.includes('cycle'))).toBe(true);
147
+ });
148
+ it('does NOT throw on non-object input — returns structured error', () => {
149
+ const result = redactSensitiveFields(42);
150
+ expect(result.ok).toBe(false);
151
+ if (result.ok)
152
+ return;
153
+ expect(result.error).toBeDefined();
154
+ expect(result.nextAction).toBeDefined();
155
+ });
156
+ it('does NOT throw on null — returns structured error', () => {
157
+ const result = redactSensitiveFields(null);
158
+ expect(result.ok).toBe(false);
159
+ });
160
+ it('handles arrays without throwing', () => {
161
+ const input = [{ password: 'secret1' }, { name: 'safe' }];
162
+ const result = redactSensitiveFields(input);
163
+ expect(result.ok).toBe(true);
164
+ if (!result.ok)
165
+ return;
166
+ const arr = result.value;
167
+ expect(arr[0]?.password).toBe(REDACTED_VALUE);
168
+ expect(arr[1]?.name).toBe('safe');
169
+ });
170
+ it('BigInt values are stringified safely, not thrown', () => {
171
+ const input = { count: BigInt('9999999999999999'), password: 'secret' };
172
+ const result = redactSensitiveFields(input);
173
+ expect(result.ok).toBe(true);
174
+ if (!result.ok)
175
+ return;
176
+ const redacted = result.value;
177
+ expect(redacted.password).toBe(REDACTED_VALUE);
178
+ expect(typeof redacted.count).toBe('string');
179
+ });
180
+ it('records redaction note when string value contains token-like pattern', () => {
181
+ const input = { buildLog: 'Build started. API key sk-ant-1234567890abcdef1234567890 used.' };
182
+ const result = redactSensitiveFields(input);
183
+ expect(result.ok).toBe(true);
184
+ if (!result.ok)
185
+ return;
186
+ const redacted = result.value;
187
+ expect(redacted.buildLog).not.toContain('sk-ant-');
188
+ expect(result.notes.some((n) => n.includes('redacted'))).toBe(true);
189
+ });
190
+ it('records redaction note when string value contains absolute path', () => {
191
+ const input = { cwd: 'Working in C:\\Users\\alice\\secret-project\\src' };
192
+ const result = redactSensitiveFields(input);
193
+ expect(result.ok).toBe(true);
194
+ if (!result.ok)
195
+ return;
196
+ const redacted = result.value;
197
+ expect(redacted.cwd).not.toContain('alice');
198
+ expect(result.notes.some((n) => n.includes('redacted'))).toBe(true);
199
+ });
200
+ it('records redaction note when string value is truncated', () => {
201
+ const longValue = 'x'.repeat(3000);
202
+ const input = { bigField: longValue };
203
+ const result = redactSensitiveFields(input);
204
+ expect(result.ok).toBe(true);
205
+ if (!result.ok)
206
+ return;
207
+ const redacted = result.value;
208
+ expect(redacted.bigField.length).toBeLessThan(longValue.length);
209
+ expect(result.notes.some((n) => n.includes('truncated'))).toBe(true);
210
+ });
211
+ it('records redaction note when string value contains env-like assignment', () => {
212
+ const input = { envDump: 'DATABASE_URL=postgres://user:pass@host:5432/db' };
213
+ const result = redactSensitiveFields(input);
214
+ expect(result.ok).toBe(true);
215
+ if (!result.ok)
216
+ return;
217
+ const redacted = result.value;
218
+ expect(redacted.envDump).not.toContain('postgres://user:pass');
219
+ expect(result.notes.some((n) => n.includes('redacted'))).toBe(true);
220
+ });
221
+ it('does NOT record redaction note for clean string values', () => {
222
+ const input = { message: 'hello world', name: 'test' };
223
+ const result = redactSensitiveFields(input);
224
+ expect(result.ok).toBe(true);
225
+ if (!result.ok)
226
+ return;
227
+ expect(result.notes.some((n) => n.includes('string value redacted'))).toBe(false);
228
+ expect(result.notes.some((n) => n.includes('truncated'))).toBe(false);
229
+ });
230
+ });
231
+ //# sourceMappingURL=redact-sensitive.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"redact-sensitive.test.js","sourceRoot":"","sources":["../../../../src/runtime-v2/__tests__/feedback/redact-sensitive.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=render-github-url.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render-github-url.test.d.ts","sourceRoot":"","sources":["../../../../src/runtime-v2/__tests__/feedback/render-github-url.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,102 @@
1
+ // render-github-url.test.ts
2
+ // ERR-001/005: no `as FeedbackType` cast; use isFeedbackType validator.
3
+ // ERR-014/016: correct '\n' newlines, bounded body.
4
+ // Redacts title before embedding in URL.
5
+ import { describe, it, expect } from 'vitest';
6
+ import { buildGitHubIssueDraftUrl, MAX_URL_BODY_LENGTH, GITHUB_REPO, } from '../../feedback/render-github-url.js';
7
+ describe('buildGitHubIssueDraftUrl', () => {
8
+ it('returns a valid GitHub issue URL with type prefix in title', () => {
9
+ const result = buildGitHubIssueDraftUrl('Cannot open page', 'bug', 'short summary');
10
+ expect(result.ok).toBe(true);
11
+ if (!result.ok)
12
+ return;
13
+ expect(result.url).toContain(`https://github.com/${GITHUB_REPO}/issues/new`);
14
+ expect(result.url).toContain('title=');
15
+ expect(result.url).toContain('bug');
16
+ expect(result.url).toContain('Cannot%20open%20page');
17
+ });
18
+ it('redacts absolute paths in title before embedding', () => {
19
+ const result = buildGitHubIssueDraftUrl('Error at C:\\Users\\alice\\secret\\path.ts', 'bug', 'short summary');
20
+ expect(result.ok).toBe(true);
21
+ if (!result.ok)
22
+ return;
23
+ // The raw path should NOT be in the URL
24
+ expect(result.url).not.toContain('C%3A%5CUsers%5Calice');
25
+ // The redacted marker should be present
26
+ expect(result.url).toContain('redacted-path');
27
+ });
28
+ it('binds the body to MAX_URL_BODY_LENGTH', () => {
29
+ const longSummary = 'x'.repeat(5000);
30
+ const result = buildGitHubIssueDraftUrl('title', 'bug', longSummary);
31
+ expect(result.ok).toBe(true);
32
+ if (!result.ok)
33
+ return;
34
+ // The body=... portion of the URL must not exceed the bound
35
+ const bodyMatch = /[?&]body=([^&]*)/.exec(result.url);
36
+ expect(bodyMatch).not.toBeNull();
37
+ if (bodyMatch === null)
38
+ return;
39
+ const raw = bodyMatch[1] ?? '';
40
+ const bodyValue = decodeURIComponent(raw);
41
+ expect(bodyValue.length).toBeLessThanOrEqual(MAX_URL_BODY_LENGTH);
42
+ });
43
+ it('preserves \\n newlines in body (encoded as %0A) instead of literal \\n', () => {
44
+ const summary = 'line one\nline two\nline three';
45
+ const result = buildGitHubIssueDraftUrl('title', 'bug', summary);
46
+ expect(result.ok).toBe(true);
47
+ if (!result.ok)
48
+ return;
49
+ // The body must contain %0A (encoded newline), not literal \n chars
50
+ expect(result.url).toContain('%0A');
51
+ expect(result.url).not.toMatch(/(?<!\\)\\\\n/); // no escaped backslash-n
52
+ });
53
+ it('returns structured error for invalid type — does NOT throw or use `as` cast', () => {
54
+ const result = buildGitHubIssueDraftUrl('title', 'not-a-valid-type', 'summary');
55
+ expect(result.ok).toBe(false);
56
+ if (result.ok)
57
+ return;
58
+ expect(result.error).toBeDefined();
59
+ expect(result.nextAction).toBeDefined();
60
+ expect(typeof result.nextAction).toBe('string');
61
+ });
62
+ it('handles empty summary without throwing', () => {
63
+ const result = buildGitHubIssueDraftUrl('title', 'bug', '');
64
+ expect(result.ok).toBe(true);
65
+ if (!result.ok)
66
+ return;
67
+ expect(result.url).toContain('https://github.com/');
68
+ });
69
+ it('redacts env-like values in title (OPENAI_API_KEY=sk-... does not appear in URL)', () => {
70
+ const result = buildGitHubIssueDraftUrl('Crash with OPENAI_API_KEY=sk-abc1234567890123456789abcdef in env', 'bug', 'short summary');
71
+ expect(result.ok).toBe(true);
72
+ if (!result.ok)
73
+ return;
74
+ // The secret value must be redacted; the key name may remain but the token must not
75
+ expect(result.url).not.toContain('sk-abc1234567890123456789abcdef');
76
+ expect(result.url).toContain('%5BREDACTED%5D');
77
+ });
78
+ it('redacts env-like values in body (OPENAI_API_KEY=sk-... does not appear in URL)', () => {
79
+ const result = buildGitHubIssueDraftUrl('title', 'bug', 'details: OPENAI_API_KEY=sk-abc1234567890123456789abcdef leaked');
80
+ expect(result.ok).toBe(true);
81
+ if (!result.ok)
82
+ return;
83
+ // The secret value must be redacted; the key name may remain but the token must not
84
+ expect(result.url).not.toContain('sk-abc1234567890123456789abcdef');
85
+ expect(result.url).toContain('%5BREDACTED%5D');
86
+ });
87
+ it('returns structured error when shortSummary is not a string', () => {
88
+ const nullResult = buildGitHubIssueDraftUrl('title', 'bug', null);
89
+ expect(nullResult.ok).toBe(false);
90
+ if (nullResult.ok)
91
+ return;
92
+ expect(nullResult.error).toBe('shortSummary must be a string');
93
+ expect(nullResult.nextAction).toBe('provide a string value for shortSummary');
94
+ const numResult = buildGitHubIssueDraftUrl('title', 'bug', 42);
95
+ expect(numResult.ok).toBe(false);
96
+ if (numResult.ok)
97
+ return;
98
+ expect(numResult.error).toBe('shortSummary must be a string');
99
+ expect(numResult.nextAction).toBe('provide a string value for shortSummary');
100
+ });
101
+ });
102
+ //# sourceMappingURL=render-github-url.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render-github-url.test.js","sourceRoot":"","sources":["../../../../src/runtime-v2/__tests__/feedback/render-github-url.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=render-markdown.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render-markdown.test.d.ts","sourceRoot":"","sources":["../../../../src/runtime-v2/__tests__/feedback/render-markdown.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,130 @@
1
+ // render-markdown.test.ts
2
+ // ERR-014/016/017: bounded output, correct '\n' newlines (not '\\n'), BigInt-safe.
3
+ import { describe, it, expect } from 'vitest';
4
+ import { renderReportMarkdown, MAX_MARKDOWN_LENGTH } from '../../feedback/render-markdown.js';
5
+ function makeReport(overrides = {}) {
6
+ return {
7
+ id: 'fb-test-1',
8
+ createdAt: '2026-06-01T00:00:00.000Z',
9
+ type: 'bug',
10
+ title: 'Cannot open pain page',
11
+ userText: {
12
+ description: 'Clicking the pain link throws TypeError',
13
+ stepsToReproduce: '1. Go to Overview\n2. Click Pain',
14
+ expectedBehavior: 'Page should open',
15
+ actualBehavior: 'Page throws error',
16
+ userSeverity: 'high',
17
+ },
18
+ diagnosticSummary: {
19
+ versions: { '@principles/core': '1.0.0' },
20
+ platform: { os: 'darwin', node: '20.0.0' },
21
+ featureFlags: { 'mvp-core': true },
22
+ canary: { status: 'available', summary: 'healthy' },
23
+ recentEvents: [
24
+ { type: 'pain_signal', at: '2026-06-01T00:00:00.000Z', summary: 'pain detected' },
25
+ ],
26
+ },
27
+ contextRefs: [{ kind: 'page', id: 'overview' }],
28
+ privacy: {
29
+ includedSections: ['versions', 'platform', 'featureFlags', 'canary', 'userText'],
30
+ excludedByDefault: ['rawPrompt', 'rawChat', 'fileContents', 'envVars', 'tokens', 'fullPaths', 'stackTraces'],
31
+ redactionNotes: [],
32
+ },
33
+ outputs: { markdown: '', emailText: '', githubIssueUrl: '' },
34
+ ...overrides,
35
+ };
36
+ }
37
+ describe('renderReportMarkdown', () => {
38
+ it('uses real \\n newlines, not literal \\n', () => {
39
+ const report = makeReport();
40
+ const md = renderReportMarkdown(report);
41
+ // The markdown must contain actual newline characters separating sections
42
+ expect(md.split('\n').length).toBeGreaterThan(5);
43
+ // The rendered output must NOT contain escaped \n (which would render as backslash-n)
44
+ expect(md).not.toMatch(/\\n/);
45
+ });
46
+ it('contains the type, title, and user-entered text', () => {
47
+ const report = makeReport();
48
+ const md = renderReportMarkdown(report);
49
+ expect(md).toContain('bug');
50
+ expect(md).toContain('Cannot open pain page');
51
+ expect(md).toContain('Clicking the pain link throws TypeError');
52
+ });
53
+ it('contains diagnostics sections (versions, platform, canary)', () => {
54
+ const report = makeReport();
55
+ const md = renderReportMarkdown(report);
56
+ expect(md).toContain('versions');
57
+ expect(md).toContain('platform');
58
+ expect(md).toContain('canary');
59
+ });
60
+ it('contains context refs', () => {
61
+ const report = makeReport();
62
+ const md = renderReportMarkdown(report);
63
+ expect(md).toContain('overview');
64
+ });
65
+ it('is bounded to MAX_MARKDOWN_LENGTH characters', () => {
66
+ const hugeSteps = 'step '.repeat(2000);
67
+ const hugeDescription = 'desc '.repeat(2000);
68
+ const report = makeReport({
69
+ userText: {
70
+ description: hugeDescription,
71
+ stepsToReproduce: hugeSteps,
72
+ expectedBehavior: 'x',
73
+ actualBehavior: 'y',
74
+ userSeverity: 'low',
75
+ },
76
+ });
77
+ const md = renderReportMarkdown(report);
78
+ expect(md.length).toBeLessThanOrEqual(MAX_MARKDOWN_LENGTH);
79
+ });
80
+ it('truncates oversized fields and records a redaction note in privacy.redactionNotes', () => {
81
+ const hugeSteps = 'step '.repeat(2000);
82
+ const report = makeReport({
83
+ userText: {
84
+ description: 'short',
85
+ stepsToReproduce: hugeSteps,
86
+ expectedBehavior: 'x',
87
+ actualBehavior: 'y',
88
+ userSeverity: 'low',
89
+ },
90
+ });
91
+ const md = renderReportMarkdown(report);
92
+ expect(md.length).toBeLessThanOrEqual(MAX_MARKDOWN_LENGTH);
93
+ expect(report.privacy.redactionNotes.some((n) => n.includes('truncat') || n.includes('truncated'))).toBe(true);
94
+ });
95
+ it('BigInt values in diagnostics do not throw (ERR-017)', () => {
96
+ const report = makeReport({
97
+ diagnosticSummary: {
98
+ versions: { count: BigInt(9999999999999) },
99
+ platform: { os: 'linux' },
100
+ featureFlags: {},
101
+ canary: { status: 'unavailable', unavailableReason: 'offline' },
102
+ recentEvents: [],
103
+ },
104
+ });
105
+ let thrown = null;
106
+ try {
107
+ const md = renderReportMarkdown(report);
108
+ expect(md).toBeDefined();
109
+ }
110
+ catch (e) {
111
+ thrown = e;
112
+ }
113
+ expect(thrown).toBeNull();
114
+ });
115
+ it('reflects canary unavailable status in output without throwing', () => {
116
+ const report = makeReport({
117
+ diagnosticSummary: {
118
+ versions: {},
119
+ platform: { os: 'linux' },
120
+ featureFlags: {},
121
+ canary: { status: 'unavailable', unavailableReason: 'no network' },
122
+ recentEvents: [],
123
+ },
124
+ });
125
+ const md = renderReportMarkdown(report);
126
+ expect(md).toContain('unavailable');
127
+ expect(md).toContain('no network');
128
+ });
129
+ });
130
+ //# sourceMappingURL=render-markdown.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render-markdown.test.js","sourceRoot":"","sources":["../../../../src/runtime-v2/__tests__/feedback/render-markdown.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=workspace-guidance-migration.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workspace-guidance-migration.test.d.ts","sourceRoot":"","sources":["../../../src/runtime-v2/__tests__/workspace-guidance-migration.test.ts"],"names":[],"mappings":""}