specline 1.4.0 → 2.0.1

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 (75) hide show
  1. package/README.md +132 -125
  2. package/adapters/claude/deploy.json +12 -0
  3. package/adapters/claude/hooks/hooks.json +12 -0
  4. package/adapters/claude/hooks.json +12 -0
  5. package/adapters/claude/orchestration.md +17 -0
  6. package/adapters/codex/agent.toml.hbs +7 -0
  7. package/adapters/codex/deploy.json +12 -0
  8. package/adapters/codex/hooks.json +12 -0
  9. package/adapters/codex/orchestration.md +18 -0
  10. package/adapters/cursor/deploy.json +12 -0
  11. package/adapters/cursor/hooks.json +9 -0
  12. package/adapters/cursor/orchestration.md +17 -0
  13. package/adapters/opencode/deploy.json +12 -0
  14. package/adapters/opencode/orchestration.md +18 -0
  15. package/adapters/opencode/plugin.js +10 -0
  16. package/cli.mjs +161 -558
  17. package/core/agents/specline-backend-dev.yaml +45 -0
  18. package/core/agents/specline-code-reviewer.yaml +67 -0
  19. package/core/agents/specline-config-dev.yaml +50 -0
  20. package/core/agents/specline-config-reviewer.yaml +70 -0
  21. package/core/agents/specline-explore-assistant.yaml +79 -0
  22. package/core/agents/specline-frontend-dev.yaml +45 -0
  23. package/core/agents/specline-spec-creator.yaml +58 -0
  24. package/core/agents/specline-spec-reviewer.yaml +58 -0
  25. package/core/agents/specline-test-runner.yaml +62 -0
  26. package/core/agents/specline-test-writer.yaml +67 -0
  27. package/core/bootstrap/using-specline.md +14 -0
  28. package/core/gates/pipeline-gate-checks/a1-covers-ref.sh +125 -0
  29. package/core/gates/pipeline-gate-checks/a2-a3-reverse.sh +171 -0
  30. package/core/gates/pipeline-gate-checks/c1-exception.sh +71 -0
  31. package/core/gates/pipeline-gate-checks/c2-vague.sh +60 -0
  32. package/core/gates/pipeline-gate-checks/common.sh +68 -0
  33. package/core/gates/pipeline-gate-checks/d1-cycle.sh +149 -0
  34. package/core/gates/pipeline-gate-checks/d3-type-file.sh +260 -0
  35. package/core/gates/pipeline-gate.sh +1456 -0
  36. package/core/hooks/session-start.sh +259 -0
  37. package/core/skills/specline-apply-change/SKILL.md +197 -0
  38. package/core/skills/specline-archive-change/SKILL.md +173 -0
  39. package/core/skills/specline-explore/SKILL.md +504 -0
  40. package/core/skills/specline-knowledge/SKILL.md +539 -0
  41. package/core/skills/specline-pipeline/SKILL.md +604 -0
  42. package/core/skills/specline-pipeline/references/error-recovery-details.md +49 -0
  43. package/core/skills/specline-pipeline/references/event-log-spec.md +59 -0
  44. package/core/skills/specline-pipeline/references/pipeline-state-schema.md +87 -0
  45. package/core/skills/specline-pipeline/templates/subagent-prompts.md +397 -0
  46. package/core/skills/specline-propose/SKILL.md +186 -0
  47. package/core/skills/specline-quickfix/SKILL.md +289 -0
  48. package/core/templates/AGENTS.md.hbs +5 -0
  49. package/core/templates/specline/config.yaml +15 -0
  50. package/lib/deploy-claude.mjs +80 -0
  51. package/lib/deploy-codex.mjs +77 -0
  52. package/lib/deploy-opencode.mjs +93 -0
  53. package/lib/deploy.mjs +668 -0
  54. package/lib/gate.mjs +103 -0
  55. package/lib/hash.mjs +13 -0
  56. package/lib/hook.mjs +105 -0
  57. package/lib/init.mjs +122 -0
  58. package/lib/lock.mjs +99 -0
  59. package/lib/merge.mjs +188 -0
  60. package/lib/paths.mjs +40 -0
  61. package/lib/platforms.mjs +74 -0
  62. package/lib/render-agents.mjs +88 -0
  63. package/lib/render.mjs +126 -0
  64. package/lib/sync.mjs +253 -0
  65. package/lib/tty-select.mjs +89 -0
  66. package/package.json +4 -1
  67. package/templates/.cursor/README.md +18 -0
  68. package/templates/.cursor/agents/specline-code-reviewer.md +18 -2
  69. package/templates/.cursor/agents/specline-spec-creator.md +51 -2
  70. package/templates/.cursor/agents/specline-test-runner.md +10 -1
  71. package/templates/.cursor/agents/specline-test-writer.md +58 -7
  72. package/templates/.cursor/hooks/specline-pipeline-gate-checks/a2-a3-reverse.sh +1 -1
  73. package/templates/.cursor/hooks/specline-pipeline-gate.sh +118 -0
  74. package/templates/.cursor/skills/specline-pipeline/SKILL.md +10 -4
  75. package/templates/.cursor/skills/specline-propose/SKILL.md +3 -3
@@ -0,0 +1,93 @@
1
+ import { readFileSync, writeFileSync, existsSync, mkdirSync, copyFileSync } from 'node:fs';
2
+ import { join, dirname } from 'node:path';
3
+ import { PACKAGE_ROOT } from './paths.mjs';
4
+ import { getOpencodeUpstreamManifest, writeManifestToProject } from './deploy.mjs';
5
+ import { mergeOpencodeJson } from './merge.mjs';
6
+
7
+ const PLUGIN_REL = 'specline/opencode-plugin/plugin.js';
8
+ const OPENCODE_JSON_REL = 'opencode.json';
9
+ const PLUGIN_ENTRY = './specline/opencode-plugin';
10
+
11
+ /**
12
+ * Deploy Specline assets to an OpenCode project.
13
+ *
14
+ * Skills -> .opencode/skills/ | Plugin -> specline/opencode-plugin/plugin.js
15
+ * Merge opencode.json plugin entry. No agent files generated.
16
+ *
17
+ * @param {string} projectDir Target project root
18
+ * @param {{ packageRoot?: string, dryRun?: boolean }} [options]
19
+ * @returns {{ filesWritten: string[], opencodeJsonAction: 'created'|'merged'|'unchanged' }}
20
+ */
21
+ export function deployOpencode(projectDir, options = {}) {
22
+ const { packageRoot = PACKAGE_ROOT, dryRun = false } = options;
23
+
24
+ const manifest = getOpencodeUpstreamManifest(packageRoot);
25
+
26
+ manifest.delete(PLUGIN_REL);
27
+ manifest.delete(OPENCODE_JSON_REL);
28
+
29
+ const filesWritten = [];
30
+
31
+ if (!dryRun) {
32
+ for (const dir of ['.opencode/skills', 'specline/opencode-plugin']) {
33
+ const full = join(projectDir, dir);
34
+ if (!existsSync(full)) mkdirSync(full, { recursive: true });
35
+ }
36
+ writeManifestToProject(projectDir, manifest);
37
+ }
38
+ for (const rel of manifest.keys()) filesWritten.push(rel);
39
+
40
+ deployPluginJs(projectDir, packageRoot, dryRun);
41
+ filesWritten.push(PLUGIN_REL);
42
+
43
+ const opencodeJsonAction = mergeOpencodeJsonFile(projectDir, dryRun);
44
+ filesWritten.push(OPENCODE_JSON_REL);
45
+
46
+ return { filesWritten, opencodeJsonAction };
47
+ }
48
+
49
+ /**
50
+ * Copy plugin.js from adapters/opencode/ to specline/opencode-plugin/.
51
+ */
52
+ function deployPluginJs(projectDir, packageRoot, dryRun) {
53
+ const src = join(packageRoot, 'adapters', 'opencode', 'plugin.js');
54
+ const dest = join(projectDir, PLUGIN_REL);
55
+ if (!existsSync(src)) return;
56
+
57
+ if (!dryRun) {
58
+ const dir = dirname(dest);
59
+ if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
60
+ copyFileSync(src, dest);
61
+ }
62
+ }
63
+
64
+ /**
65
+ * Merge opencode.json in project root.
66
+ *
67
+ * - Existing file: ensure "plugin" array includes specline entry, preserve rest
68
+ * - No file: create minimal { "plugin": ["./specline/opencode-plugin"] }
69
+ *
70
+ * @param {string} projectDir
71
+ * @param {boolean} dryRun
72
+ * @returns {'created'|'merged'|'unchanged'}
73
+ */
74
+ function mergeOpencodeJsonFile(projectDir, dryRun) {
75
+ const jsonPath = join(projectDir, OPENCODE_JSON_REL);
76
+
77
+ if (existsSync(jsonPath)) {
78
+ const existingContent = readFileSync(jsonPath, 'utf-8');
79
+ const merged = mergeOpencodeJson(existingContent, PLUGIN_ENTRY);
80
+ if (merged === existingContent) return 'unchanged';
81
+
82
+ if (!dryRun) {
83
+ writeFileSync(jsonPath, merged, 'utf-8');
84
+ }
85
+ return 'merged';
86
+ }
87
+
88
+ if (!dryRun) {
89
+ const fresh = mergeOpencodeJson('', PLUGIN_ENTRY);
90
+ writeFileSync(jsonPath, fresh, 'utf-8');
91
+ }
92
+ return 'created';
93
+ }