@spec-box/sdd 0.6.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 (161) hide show
  1. package/README.md +81 -0
  2. package/assets/adapters/openspec/instructions.md +47 -0
  3. package/assets/adapters/spec-box/instructions.md +44 -0
  4. package/assets/ci/Dockerfile +9 -0
  5. package/assets/ci/github-sbox-run.yml +85 -0
  6. package/assets/ci/github-tests.yml +25 -0
  7. package/assets/project/architecture.md +29 -0
  8. package/assets/project/contracts.md +29 -0
  9. package/assets/project/conventions.md +29 -0
  10. package/assets/project/decisions.README.md +3 -0
  11. package/assets/project/glossary.md +13 -0
  12. package/assets/project/overview.md +29 -0
  13. package/assets/project/testing.md +34 -0
  14. package/assets/project/workflow.md +29 -0
  15. package/assets/prompts/fill-project-docs.md +43 -0
  16. package/assets/roles/challenger.md +33 -0
  17. package/assets/roles/distiller.md +18 -0
  18. package/assets/roles/implementer.md +39 -0
  19. package/assets/roles/planner.md +58 -0
  20. package/assets/roles/researcher.md +47 -0
  21. package/assets/roles/reviewer.md +68 -0
  22. package/assets/roles/tester.md +36 -0
  23. package/assets/roles/verifier.md +57 -0
  24. package/assets/schema/default.yaml +121 -0
  25. package/assets/schema/sbox-answer.schema.json +42 -0
  26. package/assets/templates/coverage.yaml +12 -0
  27. package/assets/templates/design.md +48 -0
  28. package/assets/templates/proposal.md +27 -0
  29. package/assets/templates/tasks.md +9 -0
  30. package/assets/templates/test-plan.md +7 -0
  31. package/bin/sbox.js +5 -0
  32. package/dist/adapters/host/claude/index.js +112 -0
  33. package/dist/adapters/host/claude/index.js.map +1 -0
  34. package/dist/adapters/repo/git.js +81 -0
  35. package/dist/adapters/repo/git.js.map +1 -0
  36. package/dist/adapters/repo/github/index.js +136 -0
  37. package/dist/adapters/repo/github/index.js.map +1 -0
  38. package/dist/adapters/repo/index.js +4 -0
  39. package/dist/adapters/repo/index.js.map +1 -0
  40. package/dist/adapters/repo/local.js +47 -0
  41. package/dist/adapters/repo/local.js.map +1 -0
  42. package/dist/adapters/runner/claude.js +129 -0
  43. package/dist/adapters/runner/claude.js.map +1 -0
  44. package/dist/adapters/runner/codex.js +151 -0
  45. package/dist/adapters/runner/codex.js.map +1 -0
  46. package/dist/adapters/runner/index.js +4 -0
  47. package/dist/adapters/runner/index.js.map +1 -0
  48. package/dist/adapters/spec/index.js +4 -0
  49. package/dist/adapters/spec/index.js.map +1 -0
  50. package/dist/adapters/spec/openspec/delta.js +268 -0
  51. package/dist/adapters/spec/openspec/delta.js.map +1 -0
  52. package/dist/adapters/spec/openspec/index.js +107 -0
  53. package/dist/adapters/spec/openspec/index.js.map +1 -0
  54. package/dist/adapters/spec/openspec/parser.js +188 -0
  55. package/dist/adapters/spec/openspec/parser.js.map +1 -0
  56. package/dist/adapters/spec/spec-box/delta.js +198 -0
  57. package/dist/adapters/spec/spec-box/delta.js.map +1 -0
  58. package/dist/adapters/spec/spec-box/index.js +112 -0
  59. package/dist/adapters/spec/spec-box/index.js.map +1 -0
  60. package/dist/adapters/spec/spec-box/yaml.js +74 -0
  61. package/dist/adapters/spec/spec-box/yaml.js.map +1 -0
  62. package/dist/cli/commands/artifacts.js +86 -0
  63. package/dist/cli/commands/artifacts.js.map +1 -0
  64. package/dist/cli/commands/change.js +111 -0
  65. package/dist/cli/commands/change.js.map +1 -0
  66. package/dist/cli/commands/changeset.js +81 -0
  67. package/dist/cli/commands/changeset.js.map +1 -0
  68. package/dist/cli/commands/ci.js +45 -0
  69. package/dist/cli/commands/ci.js.map +1 -0
  70. package/dist/cli/commands/coverage.js +45 -0
  71. package/dist/cli/commands/coverage.js.map +1 -0
  72. package/dist/cli/commands/deliver.js +71 -0
  73. package/dist/cli/commands/deliver.js.map +1 -0
  74. package/dist/cli/commands/doctor.js +55 -0
  75. package/dist/cli/commands/doctor.js.map +1 -0
  76. package/dist/cli/commands/host.js +30 -0
  77. package/dist/cli/commands/host.js.map +1 -0
  78. package/dist/cli/commands/init.js +150 -0
  79. package/dist/cli/commands/init.js.map +1 -0
  80. package/dist/cli/commands/metrics.js +62 -0
  81. package/dist/cli/commands/metrics.js.map +1 -0
  82. package/dist/cli/commands/prompt.js +68 -0
  83. package/dist/cli/commands/prompt.js.map +1 -0
  84. package/dist/cli/commands/protocol.js +151 -0
  85. package/dist/cli/commands/protocol.js.map +1 -0
  86. package/dist/cli/commands/run.js +157 -0
  87. package/dist/cli/commands/run.js.map +1 -0
  88. package/dist/cli/commands/spec.js +84 -0
  89. package/dist/cli/commands/spec.js.map +1 -0
  90. package/dist/cli/commands/wiring.js +50 -0
  91. package/dist/cli/commands/wiring.js.map +1 -0
  92. package/dist/cli/context.js +18 -0
  93. package/dist/cli/context.js.map +1 -0
  94. package/dist/cli/main.js +63 -0
  95. package/dist/cli/main.js.map +1 -0
  96. package/dist/cli/output.js +31 -0
  97. package/dist/cli/output.js.map +1 -0
  98. package/dist/core/archive.js +77 -0
  99. package/dist/core/archive.js.map +1 -0
  100. package/dist/core/change.js +240 -0
  101. package/dist/core/change.js.map +1 -0
  102. package/dist/core/changeset.js +98 -0
  103. package/dist/core/changeset.js.map +1 -0
  104. package/dist/core/config.js +144 -0
  105. package/dist/core/config.js.map +1 -0
  106. package/dist/core/coverage.js +69 -0
  107. package/dist/core/coverage.js.map +1 -0
  108. package/dist/core/deliver.js +190 -0
  109. package/dist/core/deliver.js.map +1 -0
  110. package/dist/core/diagnostics.js +12 -0
  111. package/dist/core/diagnostics.js.map +1 -0
  112. package/dist/core/drift.js +44 -0
  113. package/dist/core/drift.js.map +1 -0
  114. package/dist/core/errors.js +12 -0
  115. package/dist/core/errors.js.map +1 -0
  116. package/dist/core/gates.js +76 -0
  117. package/dist/core/gates.js.map +1 -0
  118. package/dist/core/lock.js +57 -0
  119. package/dist/core/lock.js.map +1 -0
  120. package/dist/core/metrics.js +140 -0
  121. package/dist/core/metrics.js.map +1 -0
  122. package/dist/core/packet.js +172 -0
  123. package/dist/core/packet.js.map +1 -0
  124. package/dist/core/paths.js +63 -0
  125. package/dist/core/paths.js.map +1 -0
  126. package/dist/core/phases.js +203 -0
  127. package/dist/core/phases.js.map +1 -0
  128. package/dist/core/pr-body.js +64 -0
  129. package/dist/core/pr-body.js.map +1 -0
  130. package/dist/core/project-docs.js +246 -0
  131. package/dist/core/project-docs.js.map +1 -0
  132. package/dist/core/protect.js +47 -0
  133. package/dist/core/protect.js.map +1 -0
  134. package/dist/core/repo-host.js +11 -0
  135. package/dist/core/repo-host.js.map +1 -0
  136. package/dist/core/report.js +286 -0
  137. package/dist/core/report.js.map +1 -0
  138. package/dist/core/result.js +90 -0
  139. package/dist/core/result.js.map +1 -0
  140. package/dist/core/roles.js +18 -0
  141. package/dist/core/roles.js.map +1 -0
  142. package/dist/core/run.js +222 -0
  143. package/dist/core/run.js.map +1 -0
  144. package/dist/core/runner.js +40 -0
  145. package/dist/core/runner.js.map +1 -0
  146. package/dist/core/schema.js +104 -0
  147. package/dist/core/schema.js.map +1 -0
  148. package/dist/core/spec-adapter.js +12 -0
  149. package/dist/core/spec-adapter.js.map +1 -0
  150. package/dist/core/spec-model.js +8 -0
  151. package/dist/core/spec-model.js.map +1 -0
  152. package/dist/core/tasks.js +15 -0
  153. package/dist/core/tasks.js.map +1 -0
  154. package/dist/core/test-reports.js +60 -0
  155. package/dist/core/test-reports.js.map +1 -0
  156. package/dist/core/wiki.js +86 -0
  157. package/dist/core/wiki.js.map +1 -0
  158. package/dist/core/wiring.js +65 -0
  159. package/dist/core/wiring.js.map +1 -0
  160. package/docs/design.md +829 -0
  161. package/package.json +66 -0
@@ -0,0 +1,112 @@
1
+ import path from 'node:path';
2
+ import { loadRoleText } from '../../../core/roles.js';
3
+ import { ROLES } from '../../../core/phases.js';
4
+ import { defaultHostModel } from '../../../core/runner.js';
5
+ import { writeText } from '../../../core/paths.js';
6
+ const AGENT_ROLES = ['researcher', 'planner', 'tester', 'implementer', 'reviewer', 'verifier', 'challenger'];
7
+ const TOOLS = {
8
+ researcher: 'Read, Grep, Glob, Bash',
9
+ planner: 'Read, Write, Edit, Grep, Glob, Bash',
10
+ challenger: 'Read, Grep, Glob, Bash',
11
+ tester: 'Read, Write, Edit, Grep, Glob, Bash',
12
+ implementer: 'Read, Write, Edit, Grep, Glob, Bash',
13
+ reviewer: 'Read, Grep, Glob, Bash',
14
+ verifier: 'Read, Grep, Glob, Bash',
15
+ distiller: 'Read, Write, Edit, Grep, Glob',
16
+ };
17
+ const DESCRIPTIONS = {
18
+ researcher: 'Исследователь @spec-box/sdd: Evidence Pack по изменению. Вызывается только скиллом sbox-run.',
19
+ planner: 'Планировщик @spec-box/sdd: proposal, дельты спецификаций, design, tasks. Вызывается только скиллом sbox-run.',
20
+ challenger: 'Аудитор плана @spec-box/sdd. Вызывается только скиллом sbox-run.',
21
+ tester: 'Тестировщик @spec-box/sdd: тесты по сценариям до реализации. Вызывается только скиллом sbox-run.',
22
+ implementer: 'Реализатор @spec-box/sdd: выполняет tasks.md, не трогая защищённые тесты. Вызывается только скиллом sbox-run.',
23
+ reviewer: 'Ревьюер @spec-box/sdd: тесты против спецификаций, код против артефактов. Вызывается только скиллом sbox-run.',
24
+ verifier: 'Верификатор @spec-box/sdd: полнота, корректность, согласованность. Вызывается только скиллом sbox-run.',
25
+ distiller: 'Дистиллятор знаний @spec-box/sdd.',
26
+ };
27
+ /** Материалы для Claude Code: тонкий скилл-оркестратор и по агенту на роль (docs/design.md, раздел 11). */
28
+ export function installClaudeMaterials(root, config) {
29
+ const written = [];
30
+ const skill = path.join(root, '.claude', 'skills', 'sbox-run', 'SKILL.md');
31
+ writeText(skill, RUN_SKILL);
32
+ written.push(skill);
33
+ const approve = path.join(root, '.claude', 'skills', 'sbox-approve', 'SKILL.md');
34
+ writeText(approve, APPROVE_SKILL);
35
+ written.push(approve);
36
+ for (const role of ROLES) {
37
+ if (!AGENT_ROLES.includes(role))
38
+ continue;
39
+ const file = path.join(root, '.claude', 'agents', `sbox-${role}.md`);
40
+ writeText(file, agentFile(root, role, config?.runner.models[role], config?.runner.efforts[role] ?? config?.runner.defaultEffort ?? 'medium'));
41
+ written.push(file);
42
+ }
43
+ return written;
44
+ }
45
+ /** Имя модели для фронтматтера агента Claude Code: псевдонимы sonnet/opus/haiku или полный идентификатор. */
46
+ function agentModel(configured) {
47
+ if (!configured)
48
+ return null;
49
+ const v = configured.toLowerCase();
50
+ if (v.includes('opus'))
51
+ return 'opus';
52
+ if (v.includes('sonnet'))
53
+ return 'sonnet';
54
+ if (v.includes('haiku'))
55
+ return 'haiku';
56
+ return configured;
57
+ }
58
+ function agentFile(root, role, configuredModel, effort = 'medium') {
59
+ const body = loadRoleText(root, role);
60
+ const model = agentModel(configuredModel) ?? defaultHostModel(role);
61
+ // Без явного effort субагент наследует усилие сессии (в пилоте это был xhigh на каждом ходе).
62
+ return `---
63
+ name: sbox-${role}
64
+ description: ${DESCRIPTIONS[role]}
65
+ tools: ${TOOLS[role]}
66
+ model: ${model}
67
+ effort: ${effort}
68
+ ---
69
+
70
+ Ты выполняешь роль ${role} инструмента @spec-box/sdd. Во входном сообщении путь к JSON-пакету (\`packet\`). Прочитай пакет целиком: там цель, допущенные файлы, ограничения, правила проекта, инструкции к артефактам и путь \`resultFile\`.
71
+
72
+ Порядок работы: прочитай пакет → выполни этапы роли ниже → запиши полный ответ (Markdown и завершающий блок \`# sbox-result\`) в файл \`resultFile\` из пакета → в сообщении верни только две строки: путь к resultFile и статус.
73
+
74
+ ${body.trim()}
75
+ `;
76
+ }
77
+ const RUN_SKILL = `---
78
+ name: sbox-run
79
+ description: Выполнить следующий шаг изменения @spec-box/sdd — запросить пакет у CLI, выполнить роль субагентом и сдать отчёт. Используй, когда пользователь просит продвинуть изменение, запустить sbox, выполнить следующий шаг.
80
+ ---
81
+
82
+ # sbox-run
83
+
84
+ Ты оркестратор: не исследуешь проект и не решаешь задачу сам. Роли выполняют субагенты \`sbox-<role>\`.
85
+
86
+ 1. Определи изменение: из аргумента, из контекста или \`sbox change list --json\`. Если активных изменений несколько и не ясно, какое брать, спроси пользователя.
87
+ 2. Запроси следующий шаг: \`sbox next --change <id> --brief --json\`. Никогда не запрашивай \`next\` без \`--brief\` и не читай packet.json сам: пакет нужен субагенту, а не тебе.
88
+ 3. По полю \`kind\` ответа:
89
+ - \`role\`: если субагент этой роли уже запускался в этой сессии, продолжи его тем же сообщением через SendMessage (он помнит проект и артефакты, повторное чтение не нужно); иначе запусти нового субагента \`sbox-<role>\`. Сообщение: \`packet: <path из поля packetFile>\`. Дождись ответа. Затем сдай отчёт: \`sbox report --change <id> --role <role> --json\`. Ответ \`report\` уже содержит статус и диагностику: не читай result.md и evidence целиком, покажи пользователю только строку статуса и ошибки. Если CLI вернул ошибки (например, не создан артефакт или изменены защищённые файлы), передай их тому же субагенту одним сообщением и повтори отчёт; не больше двух повторов.
90
+ - \`gate\`: покажи пользователю пути артефактов из ответа и спроси: «Утвердить <gate>? Ответьте «да» или замечанием». «да» → \`sbox approve <gate> --change <id> --by <user>\`; замечание → \`sbox reject <gate> --change <id> --comment "<текст>"\`. Мелкие правки формулировок пользователь может внести в артефакт сам и ответить «да»: отклонение запускает цикл доработки роли. Затем вернись к шагу 2.
91
+ - \`deliver\`: покажи чеклист \`sbox deliver --change <id> --check\` и предложи доставку \`sbox deliver --change <id>\` (архив, коммит, push, пул-реквест). Не запускай доставку без просьбы пользователя.
92
+ - \`wait\`: покажи статус и блокер, спроси пользователя, что делать.
93
+ - \`done\`: сообщи об окончании.
94
+ 4. Повторяй шаги 2–3, пока не встретишь gate, wait, deliver или done. Не запускай субагентов параллельно.
95
+
96
+ Полезные команды: \`sbox status --change <id>\` (состояние, change-set, привязка ревью), \`sbox changeset show\` (запечатанный диф и дрейф), \`sbox coverage --report jest=<path>\` (покрытие утверждений тестами), \`sbox change resume --returns N\` (продолжить после parked).
97
+
98
+ Экономия контекста: не читай артефакты изменения (design.md, спецификации, отчёты) целиком; тебе нужны только ответы CLI. Запрещено: переформулировать задачу пользователя, редактировать артефакты, вызывать роли напрямую в обход пакета, менять код.
99
+ `;
100
+ const APPROVE_SKILL = `---
101
+ name: sbox-approve
102
+ description: Утвердить или отклонить гейт изменения @spec-box/sdd (proposal, plan, tests). Используй, когда пользователь говорит «утверждаю», «одобряю план», «отклоняю с замечанием».
103
+ ---
104
+
105
+ # sbox-approve
106
+
107
+ 1. Определи изменение и гейт: \`sbox status --change <id> --json\` показывает ожидающий гейт.
108
+ 2. Утверждение: \`sbox approve <gate> --change <id> --by <user> [--comment "..."] [--answer Q1=B]\`.
109
+ 3. Отклонение: \`sbox reject <gate> --change <id> --by <user> --comment "<замечание>"\`.
110
+ 4. Покажи результат и предложи продолжить скиллом sbox-run.
111
+ `;
112
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/adapters/host/claude/index.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACtD,OAAO,EAAE,KAAK,EAAa,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAGnD,MAAM,WAAW,GAAW,CAAC,YAAY,EAAE,SAAS,EAAE,QAAQ,EAAE,aAAa,EAAE,UAAU,EAAE,UAAU,EAAE,YAAY,CAAC,CAAC;AAErH,MAAM,KAAK,GAAyB;IAClC,UAAU,EAAE,wBAAwB;IACpC,OAAO,EAAE,qCAAqC;IAC9C,UAAU,EAAE,wBAAwB;IACpC,MAAM,EAAE,qCAAqC;IAC7C,WAAW,EAAE,qCAAqC;IAClD,QAAQ,EAAE,wBAAwB;IAClC,QAAQ,EAAE,wBAAwB;IAClC,SAAS,EAAE,+BAA+B;CAC3C,CAAC;AAEF,MAAM,YAAY,GAAyB;IACzC,UAAU,EAAE,8FAA8F;IAC1G,OAAO,EAAE,8GAA8G;IACvH,UAAU,EAAE,kEAAkE;IAC9E,MAAM,EAAE,kGAAkG;IAC1G,WAAW,EAAE,+GAA+G;IAC5H,QAAQ,EAAE,8GAA8G;IACxH,QAAQ,EAAE,wGAAwG;IAClH,SAAS,EAAE,mCAAmC;CAC/C,CAAC;AAEF,2GAA2G;AAC3G,MAAM,UAAU,sBAAsB,CAAC,IAAY,EAAE,MAAe;IAClE,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,UAAU,EAAE,UAAU,CAAC,CAAC;IAC3E,SAAS,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;IAC5B,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACpB,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,cAAc,EAAE,UAAU,CAAC,CAAC;IACjF,SAAS,CAAC,OAAO,EAAE,aAAa,CAAC,CAAC;IAClC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACtB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,IAAI,CAAC;YAAE,SAAS;QAC1C,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,IAAI,KAAK,CAAC,CAAC;QACrE,SAAS,CAAC,IAAI,EAAE,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,MAAM,EAAE,MAAM,CAAC,aAAa,IAAI,QAAQ,CAAC,CAAC,CAAC;QAC9I,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACrB,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,6GAA6G;AAC7G,SAAS,UAAU,CAAC,UAA8B;IAChD,IAAI,CAAC,UAAU;QAAE,OAAO,IAAI,CAAC;IAC7B,MAAM,CAAC,GAAG,UAAU,CAAC,WAAW,EAAE,CAAC;IACnC,IAAI,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC;QAAE,OAAO,MAAM,CAAC;IACtC,IAAI,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC;QAAE,OAAO,QAAQ,CAAC;IAC1C,IAAI,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC;QAAE,OAAO,OAAO,CAAC;IACxC,OAAO,UAAU,CAAC;AACpB,CAAC;AAED,SAAS,SAAS,CAAC,IAAY,EAAE,IAAU,EAAE,eAAwB,EAAE,MAAM,GAAG,QAAQ;IACtF,MAAM,IAAI,GAAG,YAAY,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IACtC,MAAM,KAAK,GAAG,UAAU,CAAC,eAAe,CAAC,IAAI,gBAAgB,CAAC,IAAI,CAAC,CAAC;IACpE,8FAA8F;IAC9F,OAAO;aACI,IAAI;eACF,YAAY,CAAC,IAAI,CAAC;SACxB,KAAK,CAAC,IAAI,CAAC;SACX,KAAK;UACJ,MAAM;;;qBAGK,IAAI;;;;EAIvB,IAAI,CAAC,IAAI,EAAE;CACZ,CAAC;AACF,CAAC;AAED,MAAM,SAAS,GAAG;;;;;;;;;;;;;;;;;;;;;;CAsBjB,CAAC;AAEF,MAAM,aAAa,GAAG;;;;;;;;;;;CAWrB,CAAC"}
@@ -0,0 +1,81 @@
1
+ import { execFileSync } from 'node:child_process';
2
+ import { SboxError } from '../../core/errors.js';
3
+ /** Локальные операции git, общие для адаптеров GitHub и local. */
4
+ export class GitOps {
5
+ root;
6
+ constructor(root) {
7
+ this.root = root;
8
+ }
9
+ run(args, opts = {}) {
10
+ try {
11
+ return execFileSync('git', args, { cwd: this.root, encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'] });
12
+ }
13
+ catch (e) {
14
+ if (opts.allowFail)
15
+ return '';
16
+ const err = e;
17
+ throw new SboxError('GIT_FAILED', `git ${args.join(' ')}: ${(err.stderr ?? err.message).trim()}`);
18
+ }
19
+ }
20
+ currentBranch() {
21
+ return this.run(['rev-parse', '--abbrev-ref', 'HEAD']).trim();
22
+ }
23
+ branchExists(name) {
24
+ return this.run(['rev-parse', '--verify', '--quiet', `refs/heads/${name}`], { allowFail: true }).trim().length > 0;
25
+ }
26
+ ensureBranch(name, from) {
27
+ if (this.currentBranch() === name)
28
+ return;
29
+ if (this.branchExists(name))
30
+ this.run(['checkout', name]);
31
+ else
32
+ this.run(['checkout', '-b', name, from]);
33
+ }
34
+ findCommitByIntent(intentKey) {
35
+ const out = this.run(['log', '--all', '--format=%H', `--grep=Sbox-Intent-Key: ${intentKey}`], { allowFail: true }).trim();
36
+ return out ? out.split('\n')[0] : null;
37
+ }
38
+ commitAll(message, intentKey) {
39
+ this.run(['add', '-A']);
40
+ const staged = this.run(['diff', '--cached', '--name-only']).trim();
41
+ if (!staged) {
42
+ const existing = this.findCommitByIntent(intentKey);
43
+ if (existing)
44
+ return existing;
45
+ throw new SboxError('NOTHING_TO_COMMIT', 'Нет изменений для коммита.');
46
+ }
47
+ const full = `${message.trimEnd()}\n\nSbox-Intent-Key: ${intentKey}\n`;
48
+ this.run(['commit', '-q', '-F', '-'], { allowFail: false });
49
+ void full;
50
+ return this.run(['rev-parse', 'HEAD']).trim();
51
+ }
52
+ commitAllWithMessage(message, intentKey) {
53
+ this.run(['add', '-A']);
54
+ const staged = this.run(['diff', '--cached', '--name-only']).trim();
55
+ if (!staged) {
56
+ const existing = this.findCommitByIntent(intentKey);
57
+ if (existing)
58
+ return existing;
59
+ throw new SboxError('NOTHING_TO_COMMIT', 'Нет изменений для коммита.');
60
+ }
61
+ const full = `${message.trimEnd()}\n\nSbox-Intent-Key: ${intentKey}\n`;
62
+ execFileSync('git', ['commit', '-q', '-F', '-'], { cwd: this.root, input: full, encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe'] });
63
+ return this.run(['rev-parse', 'HEAD']).trim();
64
+ }
65
+ hasRemote(name = 'origin') {
66
+ return this.run(['remote'], { allowFail: true }).split('\n').map((l) => l.trim()).includes(name);
67
+ }
68
+ push(branch, remote = 'origin') {
69
+ this.run(['push', '-u', remote, branch]);
70
+ }
71
+ remoteUrl(remote = 'origin') {
72
+ const out = this.run(['remote', 'get-url', remote], { allowFail: true }).trim();
73
+ return out || null;
74
+ }
75
+ }
76
+ /** owner/repo из URL GitHub: https://github.com/o/r(.git) или git@github.com:o/r(.git). */
77
+ export function parseGitHubRemote(url) {
78
+ const m = url.match(/github\.com[:/]([^/]+)\/([^/]+?)(?:\.git)?\/?$/);
79
+ return m ? { owner: m[1], repo: m[2] } : null;
80
+ }
81
+ //# sourceMappingURL=git.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git.js","sourceRoot":"","sources":["../../../src/adapters/repo/git.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,136 @@
1
+ import { SboxError } from '../../../core/errors.js';
2
+ import { registerRepoHost } from '../../../core/repo-host.js';
3
+ import { GitOps, parseGitHubRemote } from '../git.js';
4
+ /** REST-клиент GitHub на fetch с токеном из переменной окружения; без зависимости от gh. */
5
+ export class FetchGitHubApi {
6
+ apiUrl;
7
+ token;
8
+ constructor(apiUrl, token) {
9
+ this.apiUrl = apiUrl;
10
+ this.token = token;
11
+ }
12
+ async request(method, path, body) {
13
+ const res = await fetch(`${this.apiUrl}${path}`, {
14
+ method,
15
+ headers: {
16
+ Authorization: `Bearer ${this.token}`,
17
+ Accept: 'application/vnd.github+json',
18
+ 'X-GitHub-Api-Version': '2022-11-28',
19
+ ...(body ? { 'Content-Type': 'application/json' } : {}),
20
+ },
21
+ ...(body ? { body: JSON.stringify(body) } : {}),
22
+ });
23
+ const text = await res.text();
24
+ let json = null;
25
+ try {
26
+ json = text ? JSON.parse(text) : null;
27
+ }
28
+ catch {
29
+ json = text;
30
+ }
31
+ return { status: res.status, json };
32
+ }
33
+ }
34
+ export class GitHubRepoHost {
35
+ api;
36
+ owner;
37
+ repo;
38
+ name = 'github';
39
+ git;
40
+ constructor(root, api, owner, repo) {
41
+ this.api = api;
42
+ this.owner = owner;
43
+ this.repo = repo;
44
+ this.git = new GitOps(root);
45
+ }
46
+ get base() {
47
+ return `/repos/${this.owner}/${this.repo}`;
48
+ }
49
+ currentBranch() {
50
+ return this.git.currentBranch();
51
+ }
52
+ ensureBranch(name, from) {
53
+ this.git.ensureBranch(name, from);
54
+ }
55
+ findCommitByIntent(intentKey) {
56
+ return this.git.findCommitByIntent(intentKey);
57
+ }
58
+ commitAll(message, intentKey) {
59
+ return this.git.commitAllWithMessage(message, intentKey);
60
+ }
61
+ push(branch) {
62
+ this.git.push(branch);
63
+ }
64
+ toRef(p) {
65
+ return { number: p.number, url: p.html_url, draft: Boolean(p.draft), head: p.head.ref, base: p.base.ref };
66
+ }
67
+ async findPullRequest(branch) {
68
+ const res = await this.api.request('GET', `${this.base}/pulls?state=open&head=${encodeURIComponent(`${this.owner}:${branch}`)}&per_page=5`);
69
+ if (res.status !== 200)
70
+ throw new SboxError('GITHUB_API', `GitHub GET pulls: ${res.status} ${JSON.stringify(res.json).slice(0, 200)}`);
71
+ const list = res.json;
72
+ return list.length > 0 ? this.toRef(list[0]) : null;
73
+ }
74
+ async openPullRequest(input) {
75
+ const res = await this.api.request('POST', `${this.base}/pulls`, { title: input.title, body: input.body, head: input.branch, base: input.base, draft: input.draft });
76
+ if (res.status !== 201)
77
+ throw new SboxError('GITHUB_API', `GitHub POST pulls: ${res.status} ${JSON.stringify(res.json).slice(0, 300)}`);
78
+ return this.toRef(res.json);
79
+ }
80
+ async updatePullRequest(pr, patch) {
81
+ const body = {};
82
+ if (patch.title !== undefined)
83
+ body.title = patch.title;
84
+ if (patch.body !== undefined)
85
+ body.body = patch.body;
86
+ if (Object.keys(body).length > 0) {
87
+ const res = await this.api.request('PATCH', `${this.base}/pulls/${pr.number}`, body);
88
+ if (res.status !== 200)
89
+ throw new SboxError('GITHUB_API', `GitHub PATCH pull: ${res.status}`);
90
+ }
91
+ if (patch.draft === false && pr.draft) {
92
+ // Перевод из черновика в готовый доступен только через GraphQL.
93
+ const node = await this.api.request('GET', `${this.base}/pulls/${pr.number}`);
94
+ const nodeId = node.json.node_id;
95
+ const gql = await this.api.request('POST', '/graphql', { query: `mutation { markPullRequestReadyForReview(input: { pullRequestId: "${nodeId}" }) { pullRequest { isDraft } } }` });
96
+ if (gql.status !== 200)
97
+ throw new SboxError('GITHUB_API', `GitHub markPullRequestReadyForReview: ${gql.status}`);
98
+ }
99
+ const fresh = await this.api.request('GET', `${this.base}/pulls/${pr.number}`);
100
+ return this.toRef(fresh.json);
101
+ }
102
+ async readComments(pr, since) {
103
+ const q = since ? `?since=${encodeURIComponent(since)}&per_page=100` : '?per_page=100';
104
+ const res = await this.api.request('GET', `${this.base}/issues/${pr.number}/comments${q}`);
105
+ if (res.status !== 200)
106
+ throw new SboxError('GITHUB_API', `GitHub GET comments: ${res.status}`);
107
+ return res.json.map((c) => ({ id: c.id, author: c.user.login, body: c.body, createdAt: c.created_at }));
108
+ }
109
+ async postComment(pr, body) {
110
+ const res = await this.api.request('POST', `${this.base}/issues/${pr.number}/comments`, { body });
111
+ if (res.status !== 201)
112
+ throw new SboxError('GITHUB_API', `GitHub POST comment: ${res.status}`);
113
+ }
114
+ async isMerged(pr) {
115
+ const res = await this.api.request('GET', `${this.base}/pulls/${pr.number}`);
116
+ return res.status === 200 && Boolean(res.json.merged);
117
+ }
118
+ }
119
+ export function resolveGitHubRepo(root, config) {
120
+ const c = config.repo.github;
121
+ if (c.owner && c.repo)
122
+ return { owner: c.owner, repo: c.repo };
123
+ const url = new GitOps(root).remoteUrl();
124
+ const parsed = url ? parseGitHubRemote(url) : null;
125
+ if (!parsed)
126
+ throw new SboxError('GITHUB_REPO', 'Не удалось определить owner/repo GitHub.', 'Укажите repo.github.owner и repo.github.repo в .sbox/config.yaml или настройте remote origin.');
127
+ return parsed;
128
+ }
129
+ registerRepoHost('github', (root, config) => {
130
+ const token = process.env[config.repo.github.tokenEnv] ?? process.env.GH_TOKEN;
131
+ if (!token)
132
+ throw new SboxError('GITHUB_TOKEN', `Нет токена GitHub в переменной ${config.repo.github.tokenEnv}.`);
133
+ const { owner, repo } = resolveGitHubRepo(root, config);
134
+ return new GitHubRepoHost(root, new FetchGitHubApi(config.repo.github.apiUrl, token), owner, repo);
135
+ });
136
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/adapters/repo/github/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ /** Регистрация адаптеров репозитория: импортировать один раз при старте CLI. */
2
+ import './local.js';
3
+ import './github/index.js';
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/adapters/repo/index.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,OAAO,YAAY,CAAC;AACpB,OAAO,mBAAmB,CAAC"}
@@ -0,0 +1,47 @@
1
+ import { SboxError } from '../../core/errors.js';
2
+ import { registerRepoHost } from '../../core/repo-host.js';
3
+ import { GitOps } from './git.js';
4
+ /** Локальный адаптер: только git, без пул-реквестов. Для interactive-режима и тестов. */
5
+ export class LocalRepoHost {
6
+ name = 'local';
7
+ git;
8
+ constructor(root) {
9
+ this.git = new GitOps(root);
10
+ }
11
+ currentBranch() {
12
+ return this.git.currentBranch();
13
+ }
14
+ ensureBranch(name, from) {
15
+ this.git.ensureBranch(name, from);
16
+ }
17
+ findCommitByIntent(intentKey) {
18
+ return this.git.findCommitByIntent(intentKey);
19
+ }
20
+ commitAll(message, intentKey) {
21
+ return this.git.commitAllWithMessage(message, intentKey);
22
+ }
23
+ push(branch) {
24
+ if (this.git.hasRemote())
25
+ this.git.push(branch);
26
+ }
27
+ async findPullRequest() {
28
+ return null;
29
+ }
30
+ async openPullRequest() {
31
+ throw new SboxError('NO_PR_SUPPORT', 'Локальный адаптер не создаёт пул-реквесты.', 'Задайте repo.adapter: github.');
32
+ }
33
+ async updatePullRequest(pr) {
34
+ return pr;
35
+ }
36
+ async readComments() {
37
+ return [];
38
+ }
39
+ async postComment() {
40
+ /* нет канала */
41
+ }
42
+ async isMerged() {
43
+ return false;
44
+ }
45
+ }
46
+ registerRepoHost('local', (root) => new LocalRepoHost(root));
47
+ //# sourceMappingURL=local.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"local.js","sourceRoot":"","sources":["../../../src/adapters/repo/local.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAA+D,MAAM,yBAAyB,CAAC;AACxH,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAElC,yFAAyF;AACzF,MAAM,OAAO,aAAa;IACf,IAAI,GAAG,OAAO,CAAC;IACf,GAAG,CAAS;IAErB,YAAY,IAAY;QACtB,IAAI,CAAC,GAAG,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,CAAC;IAC9B,CAAC;IAED,aAAa;QACX,OAAO,IAAI,CAAC,GAAG,CAAC,aAAa,EAAE,CAAC;IAClC,CAAC;IACD,YAAY,CAAC,IAAY,EAAE,IAAY;QACrC,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IACpC,CAAC;IACD,kBAAkB,CAAC,SAAiB;QAClC,OAAO,IAAI,CAAC,GAAG,CAAC,kBAAkB,CAAC,SAAS,CAAC,CAAC;IAChD,CAAC;IACD,SAAS,CAAC,OAAe,EAAE,SAAiB;QAC1C,OAAO,IAAI,CAAC,GAAG,CAAC,oBAAoB,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;IAC3D,CAAC;IACD,IAAI,CAAC,MAAc;QACjB,IAAI,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE;YAAE,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAClD,CAAC;IACD,KAAK,CAAC,eAAe;QACnB,OAAO,IAAI,CAAC;IACd,CAAC;IACD,KAAK,CAAC,eAAe;QACnB,MAAM,IAAI,SAAS,CAAC,eAAe,EAAE,4CAA4C,EAAE,+BAA+B,CAAC,CAAC;IACtH,CAAC;IACD,KAAK,CAAC,iBAAiB,CAAC,EAAkB;QACxC,OAAO,EAAE,CAAC;IACZ,CAAC;IACD,KAAK,CAAC,YAAY;QAChB,OAAO,EAAE,CAAC;IACZ,CAAC;IACD,KAAK,CAAC,WAAW;QACf,gBAAgB;IAClB,CAAC;IACD,KAAK,CAAC,QAAQ;QACZ,OAAO,KAAK,CAAC;IACf,CAAC;CACF;AAED,gBAAgB,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC"}
@@ -0,0 +1,129 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { query } from '@anthropic-ai/claude-agent-sdk';
4
+ import { registerRunner } from '../../core/runner.js';
5
+ const CAPACITY_RE = /(rate limit|overloaded|capacity|529|429)/i;
6
+ const TRANSPORT_RE = /(ECONNRESET|ETIMEDOUT|ENOTFOUND|socket hang up|network|fetch failed|connection)/i;
7
+ /**
8
+ * Адаптер среды Claude через Claude Agent SDK (docs/design.md, раздел 11).
9
+ * События сессии пишутся в JSONL вне репозитория, ответ читается из файла роли или из последнего сообщения.
10
+ */
11
+ export class ClaudeRunner {
12
+ options;
13
+ name = 'claude';
14
+ supportsResume = true;
15
+ constructor(options) {
16
+ this.options = options;
17
+ }
18
+ async run(req) {
19
+ fs.mkdirSync(req.stateDir, { recursive: true });
20
+ const eventsPath = path.join(req.stateDir, 'events.jsonl');
21
+ const stderrPath = path.join(req.stateDir, 'stderr.log');
22
+ const events = fs.createWriteStream(eventsPath, { flags: 'a' });
23
+ const stderr = fs.createWriteStream(stderrPath, { flags: 'a' });
24
+ const started = new Date().toISOString();
25
+ const abort = new AbortController();
26
+ let finishedBy = null;
27
+ const onAbort = () => {
28
+ finishedBy = 'stopped';
29
+ abort.abort();
30
+ };
31
+ req.signal.addEventListener('abort', onAbort);
32
+ let lastProgress = Date.now();
33
+ const hard = setTimeout(() => {
34
+ finishedBy = 'timeout';
35
+ abort.abort();
36
+ }, req.timeoutMs);
37
+ const idle = setInterval(() => {
38
+ if (Date.now() - lastProgress > req.idleTimeoutMs) {
39
+ finishedBy = 'timeout';
40
+ abort.abort();
41
+ }
42
+ }, 5000);
43
+ const tools = req.readOnly ? this.options.readOnlyTools : this.options.allowedTools;
44
+ const options = {
45
+ cwd: req.cwd,
46
+ model: req.model,
47
+ abortController: abort,
48
+ allowedTools: tools,
49
+ permissionMode: req.readOnly ? 'default' : this.options.permissionMode,
50
+ ...(req.resumeSession ? { resume: req.resumeSession } : {}),
51
+ ...(this.options.executable ? { pathToClaudeCodeExecutable: this.options.executable } : {}),
52
+ ...(this.options.maxBudgetUsd ? { maxBudgetUsd: this.options.maxBudgetUsd } : {}),
53
+ ...(this.options.maxTurns ? { maxTurns: this.options.maxTurns } : {}),
54
+ ...(req.effort ? { effort: req.effort } : {}),
55
+ env: { ...process.env, ...(req.env ?? {}) },
56
+ stderr: (data) => {
57
+ stderr.write(data);
58
+ },
59
+ };
60
+ let resultText = null;
61
+ let session;
62
+ let costUsd;
63
+ let errorText = '';
64
+ let isError = false;
65
+ try {
66
+ for await (const message of query({ prompt: req.prompt, options })) {
67
+ lastProgress = Date.now();
68
+ events.write(`${JSON.stringify(summarize(message))}\n`);
69
+ if (message.type === 'system' && 'session_id' in message)
70
+ session = message.session_id;
71
+ if (message.type === 'result') {
72
+ session = message.session_id ?? session;
73
+ costUsd = message.total_cost_usd;
74
+ if (message.subtype === 'success')
75
+ resultText = message.result;
76
+ else {
77
+ isError = true;
78
+ errorText = `${message.subtype}: ${JSON.stringify(message.errors ?? '')}`.slice(0, 500);
79
+ }
80
+ }
81
+ }
82
+ }
83
+ catch (e) {
84
+ errorText = e.message;
85
+ isError = true;
86
+ }
87
+ finally {
88
+ clearTimeout(hard);
89
+ clearInterval(idle);
90
+ req.signal.removeEventListener('abort', onAbort);
91
+ events.end();
92
+ stderr.end();
93
+ }
94
+ const finished = new Date().toISOString();
95
+ const base = { started, finished, eventsPath, stderrPath, session, costUsd, exitCode: isError ? 1 : 0 };
96
+ if (finishedBy === 'stopped')
97
+ return { ...base, usable: false, markdown: null, failure: 'stopped', failureMessage: 'остановлено' };
98
+ if (finishedBy === 'timeout')
99
+ return { ...base, usable: false, markdown: null, failure: 'timeout', failureMessage: 'таймаут запуска или бездействия' };
100
+ let markdown = null;
101
+ if (fs.existsSync(req.resultFile))
102
+ markdown = fs.readFileSync(req.resultFile, 'utf8');
103
+ else if (resultText && resultText.trim())
104
+ markdown = resultText;
105
+ if (markdown && markdown.trim())
106
+ return { ...base, usable: true, markdown };
107
+ const failure = CAPACITY_RE.test(errorText) ? 'capacity' : TRANSPORT_RE.test(errorText) ? 'transport' : isError ? 'tool' : 'no-result';
108
+ return { ...base, usable: false, markdown: null, failure, failureMessage: errorText.slice(0, 500) };
109
+ }
110
+ }
111
+ /** Компактная запись события без содержимого файлов и длинных текстов. */
112
+ function summarize(message) {
113
+ const m = message;
114
+ const out = { at: new Date().toISOString(), type: m.type };
115
+ if (typeof m.subtype === 'string')
116
+ out.subtype = m.subtype;
117
+ if (m.type === 'assistant' && m.message && typeof m.message === 'object') {
118
+ const content = m.message.content ?? [];
119
+ out.content = content.map((c) => (c.type === 'tool_use' ? `tool:${c.name}` : c.type === 'text' ? `text:${(c.text ?? '').length}` : c.type));
120
+ }
121
+ if (m.type === 'result') {
122
+ out.num_turns = m.num_turns;
123
+ out.total_cost_usd = m.total_cost_usd;
124
+ out.is_error = m.is_error;
125
+ }
126
+ return out;
127
+ }
128
+ registerRunner('claude', (_root, config) => new ClaudeRunner(config.runner.claude));
129
+ //# sourceMappingURL=claude.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claude.js","sourceRoot":"","sources":["../../../src/adapters/runner/claude.ts"],"names":[],"mappings":"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"}