@zalom/plastic 2.0.0-alpha.9 → 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 (322) hide show
  1. package/PLASTIC.md +13 -136
  2. package/README.md +357 -133
  3. package/agents/plastic-enforcer.md +20 -15
  4. package/agents/plastic-executor.md +15 -4
  5. package/agents/plastic-node-research.md +30 -0
  6. package/agents/plastic-node-verify.md +28 -0
  7. package/agents/plastic-node-work.md +33 -0
  8. package/agents/{plastic-advisor.md → plastic-primary-advisor.md} +7 -9
  9. package/agents/{plastic-faux-advisor.md → plastic-secondary-advisor.md} +9 -12
  10. package/assets/plastic-logo.svg +1 -0
  11. package/bin/crap +4 -0
  12. package/bin/lib/context_budget.rb +43 -6
  13. package/bin/lib/skill_census.rb +839 -0
  14. package/bin/plastic +6 -0
  15. package/bin/plastic-skill-census +114 -0
  16. package/bin/test +24 -4
  17. package/bin/verify-change +345 -0
  18. package/config_asks.yml +4 -4
  19. package/deprecations.yml +1 -1
  20. package/{skills/agent-advisor/references → docs/help}/advisor-protocol.md +19 -24
  21. package/{skills/auto/references → docs/help}/agent-architecture.md +16 -14
  22. package/{skills/conventions/references → docs/help}/completion-and-done.md +15 -16
  23. package/docs/help/human-report-contract.md +152 -0
  24. package/{skills/conventions/references → docs/help}/knowledge-graph.md +9 -0
  25. package/{skills/conventions/references → docs/help}/locks-and-worktrees.md +11 -13
  26. package/{skills/conventions/references → docs/help}/maintenance-and-revisions.md +1 -1
  27. package/{skills/conventions/references → docs/help}/roadmaps.md +2 -2
  28. package/{skills/tutorial/references → docs/help}/track-1-guided.md +28 -47
  29. package/{skills/tutorial/references → docs/help}/track-2-auto.md +8 -8
  30. package/{skills/tutorial/references → docs/help}/track-3-projects-and-roadmaps.md +24 -17
  31. package/hooks/call-budget +4 -0
  32. package/hooks/hooks.json +24 -0
  33. package/hooks/message-display +55 -2
  34. package/hooks/session-start +5 -1
  35. package/hooks/statusline +32 -27
  36. package/hooks/stop +5 -0
  37. package/package.json +5 -3
  38. package/scripts/append-ledger +2 -1
  39. package/scripts/dashboard.rb +267 -16
  40. package/scripts/day-summary +2 -1
  41. package/scripts/doctor.rb +680 -39
  42. package/scripts/end-intent +153 -30
  43. package/scripts/exec-worktree +5 -5
  44. package/scripts/file-session-intent +2 -1
  45. package/scripts/graph-measure +249 -0
  46. package/scripts/hook-call-budget +222 -0
  47. package/scripts/hook-capture +24 -123
  48. package/scripts/hook-close +2 -1
  49. package/scripts/hook-message-display +7 -0
  50. package/scripts/hook-record +24 -16
  51. package/scripts/hook-savepoint +27 -3
  52. package/scripts/hook-session-start +359 -321
  53. package/scripts/hook-stop +58 -0
  54. package/scripts/index-projection +74 -0
  55. package/scripts/insight-append +17 -4
  56. package/scripts/install.rb +9 -7
  57. package/scripts/lib/action_graph_shim.rb +279 -0
  58. package/scripts/lib/active_delivery.rb +105 -0
  59. package/scripts/lib/agent_models.rb +63 -25
  60. package/scripts/lib/arm.rb +48 -83
  61. package/scripts/lib/atomic_write.rb +31 -0
  62. package/scripts/lib/backup.rb +65 -0
  63. package/scripts/lib/cli/command.rb +92 -0
  64. package/scripts/lib/cli/commands/auto.rb +18 -0
  65. package/scripts/lib/cli/commands/auto_brief.rb +44 -0
  66. package/scripts/lib/cli/commands/auto_lock.rb +99 -0
  67. package/scripts/lib/cli/commands/auto_report.rb +50 -0
  68. package/scripts/lib/cli/commands/auto_take.rb +31 -0
  69. package/scripts/lib/cli/commands/backup.rb +43 -0
  70. package/scripts/lib/cli/commands/checkout.rb +25 -0
  71. package/scripts/lib/cli/commands/continue.rb +66 -0
  72. package/scripts/lib/cli/commands/doctor.rb +81 -0
  73. package/scripts/lib/cli/commands/feedback.rb +40 -0
  74. package/scripts/lib/cli/commands/help.rb +69 -0
  75. package/scripts/lib/cli/commands/hook.rb +32 -0
  76. package/scripts/lib/cli/commands/index.rb +23 -0
  77. package/scripts/lib/cli/commands/install.rb +21 -0
  78. package/scripts/lib/cli/commands/installer_verb.rb +37 -0
  79. package/scripts/lib/cli/commands/intent.rb +19 -0
  80. package/scripts/lib/cli/commands/intent_answer.rb +37 -0
  81. package/scripts/lib/cli/commands/intent_command.rb +53 -0
  82. package/scripts/lib/cli/commands/intent_end.rb +62 -0
  83. package/scripts/lib/cli/commands/intent_new.rb +62 -0
  84. package/scripts/lib/cli/commands/intent_note.rb +43 -0
  85. package/scripts/lib/cli/commands/intent_rule.rb +36 -0
  86. package/scripts/lib/cli/commands/intent_show.rb +32 -0
  87. package/scripts/lib/cli/commands/intent_spec.rb +44 -0
  88. package/scripts/lib/cli/commands/intent_step.rb +71 -0
  89. package/scripts/lib/cli/commands/intent_verify.rb +26 -0
  90. package/scripts/lib/cli/commands/migrate.rb +16 -0
  91. package/scripts/lib/cli/commands/migrate_stores.rb +31 -0
  92. package/scripts/lib/cli/commands/next.rb +54 -0
  93. package/scripts/lib/cli/commands/project.rb +19 -0
  94. package/scripts/lib/cli/commands/project_links.rb +42 -0
  95. package/scripts/lib/cli/commands/project_list.rb +20 -0
  96. package/scripts/lib/cli/commands/project_new.rb +72 -0
  97. package/scripts/lib/cli/commands/query.rb +31 -0
  98. package/scripts/lib/cli/commands/render.rb +33 -0
  99. package/scripts/lib/cli/commands/roadmap.rb +19 -0
  100. package/scripts/lib/cli/commands/roadmap_check.rb +54 -0
  101. package/scripts/lib/cli/commands/roadmap_log.rb +54 -0
  102. package/scripts/lib/cli/commands/roadmap_migrate.rb +53 -0
  103. package/scripts/lib/cli/commands/roadmap_next.rb +70 -0
  104. package/scripts/lib/cli/commands/roadmap_show.rb +45 -0
  105. package/scripts/lib/cli/commands/rollback.rb +20 -0
  106. package/scripts/lib/cli/commands/search.rb +60 -0
  107. package/scripts/lib/cli/commands/session.rb +18 -0
  108. package/scripts/lib/cli/commands/session_commit.rb +42 -0
  109. package/scripts/lib/cli/commands/session_handoff.rb +34 -0
  110. package/scripts/lib/cli/commands/session_summary.rb +35 -0
  111. package/scripts/lib/cli/commands/status.rb +68 -0
  112. package/scripts/lib/cli/commands/subcommand_list.rb +36 -0
  113. package/scripts/lib/cli/commands/sync.rb +46 -0
  114. package/scripts/lib/cli/commands/uninstall.rb +20 -0
  115. package/scripts/lib/cli/commands/update.rb +20 -0
  116. package/scripts/lib/cli/commands/version.rb +53 -0
  117. package/scripts/lib/cli/frontier.rb +86 -0
  118. package/scripts/lib/cli/intent_progress.rb +36 -0
  119. package/scripts/lib/cli/legacy.rb +80 -0
  120. package/scripts/lib/cli/output.rb +137 -0
  121. package/scripts/lib/cli/scope.rb +134 -0
  122. package/scripts/lib/cli/table.rb +65 -0
  123. package/scripts/lib/cli.rb +94 -0
  124. package/scripts/lib/codex_adapter.rb +198 -0
  125. package/scripts/lib/compact_instructions.rb +13 -5
  126. package/scripts/lib/core_integrity.rb +71 -0
  127. package/scripts/lib/dashboard_screen.rb +40 -0
  128. package/scripts/lib/data_boundary.rb +132 -0
  129. package/scripts/lib/day_summary.rb +23 -14
  130. package/scripts/lib/doctor_core.rb +114 -38
  131. package/scripts/lib/doctor_session_ledger.rb +5 -53
  132. package/scripts/lib/engine_permissions.rb +88 -0
  133. package/scripts/lib/exec_worktree.rb +24 -21
  134. package/scripts/lib/feedback_report.rb +1 -1
  135. package/scripts/lib/graph_edges.rb +137 -0
  136. package/scripts/lib/graph_file.rb +246 -0
  137. package/scripts/lib/graph_measure.rb +645 -0
  138. package/scripts/lib/graph_measure_budget.rb +409 -0
  139. package/scripts/lib/graph_measure_cohorts.rb +487 -0
  140. package/scripts/lib/graph_measure_models.rb +413 -0
  141. package/scripts/lib/graph_measure_report.rb +532 -0
  142. package/scripts/lib/graph_tree.rb +98 -0
  143. package/scripts/lib/guarded_append.rb +155 -0
  144. package/scripts/lib/handoff.rb +40 -13
  145. package/scripts/lib/harness_adapter.rb +184 -0
  146. package/scripts/lib/hook_registry.rb +27 -3
  147. package/scripts/lib/hook_replay.rb +229 -0
  148. package/scripts/lib/index_entry.rb +62 -0
  149. package/scripts/lib/index_projection.rb +201 -0
  150. package/scripts/lib/insights.rb +1 -1
  151. package/scripts/lib/installer_core.rb +531 -71
  152. package/scripts/lib/intent_screen.rb +4 -4
  153. package/scripts/lib/intent_screen_ansi.rb +73 -12
  154. package/scripts/lib/intent_validator.rb +2 -2
  155. package/scripts/lib/lock.rb +10 -11
  156. package/scripts/lib/message_display.rb +350 -54
  157. package/scripts/lib/meter_watch.rb +185 -0
  158. package/scripts/lib/node_file.rb +234 -0
  159. package/scripts/lib/node_ids.rb +99 -0
  160. package/scripts/lib/node_input.rb +913 -0
  161. package/scripts/lib/node_input_compatibility.rb +62 -0
  162. package/scripts/lib/node_ledger.rb +386 -0
  163. package/scripts/lib/node_progress.rb +153 -0
  164. package/scripts/lib/node_return.rb +204 -0
  165. package/scripts/lib/node_worktree.rb +337 -0
  166. package/scripts/lib/outcome_report.rb +440 -0
  167. package/scripts/lib/preflight.rb +4 -6
  168. package/scripts/lib/project_config.rb +46 -0
  169. package/scripts/lib/project_validator.rb +3 -2
  170. package/scripts/lib/qmd_sync.rb +8 -7
  171. package/scripts/lib/ready_set.rb +462 -0
  172. package/scripts/lib/reference_archive.rb +45 -0
  173. package/scripts/lib/release_guard.rb +18 -0
  174. package/scripts/lib/report_screen.rb +1371 -47
  175. package/scripts/lib/rlm/corpus.rb +13 -0
  176. package/scripts/lib/rlm/probe.rb +29 -0
  177. package/scripts/lib/rlm/query.rb +22 -0
  178. package/scripts/lib/roadmap_graph.rb +210 -0
  179. package/scripts/lib/roadmap_migration.rb +95 -0
  180. package/scripts/lib/roadmap_queue.rb +158 -8
  181. package/scripts/lib/roadmap_render.rb +150 -0
  182. package/scripts/lib/roadmap_savepoint.rb +64 -14
  183. package/scripts/lib/runner_absorb.rb +703 -0
  184. package/scripts/lib/runner_answer.rb +206 -0
  185. package/scripts/lib/runner_core.rb +194 -0
  186. package/scripts/lib/runner_dispatch.rb +525 -0
  187. package/scripts/lib/runner_policy.rb +191 -0
  188. package/scripts/lib/runner_proposals.rb +275 -0
  189. package/scripts/lib/runner_rewind.rb +201 -0
  190. package/scripts/lib/runner_sweep.rb +231 -0
  191. package/scripts/lib/runner_until_empty.rb +252 -0
  192. package/scripts/lib/runner_watch.rb +389 -0
  193. package/scripts/lib/savepoint.rb +141 -19
  194. package/scripts/lib/scaffold_intent.rb +6 -3
  195. package/scripts/lib/screen_paint.rb +365 -28
  196. package/scripts/lib/screens/dashboard.rb +20 -0
  197. package/scripts/lib/screens/plan.rb +18 -0
  198. package/scripts/lib/screens/roadmap.rb +15 -0
  199. package/scripts/lib/search_index.rb +55 -0
  200. package/scripts/lib/session_close.rb +30 -28
  201. package/scripts/lib/session_git.rb +25 -18
  202. package/scripts/lib/session_ledger.rb +48 -4
  203. package/scripts/lib/session_usage.rb +190 -0
  204. package/scripts/lib/sqlite.rb +22 -0
  205. package/scripts/lib/stop_gate.rb +95 -0
  206. package/scripts/lib/store_discovery.rb +7 -6
  207. package/scripts/lib/store_layout.rb +54 -0
  208. package/scripts/lib/store_provisioning.rb +2 -1
  209. package/scripts/lib/store_sync.rb +85 -0
  210. package/scripts/lib/stores_move.rb +93 -0
  211. package/scripts/lib/verify_intent.rb +36 -8
  212. package/scripts/lib/version_number.rb +48 -0
  213. package/scripts/lib/work_graph.rb +59 -0
  214. package/scripts/lib/work_graph_validator.rb +201 -0
  215. package/scripts/lib/worktree.rb +27 -32
  216. package/scripts/lib/worktree_sweep.rb +6 -5
  217. package/scripts/link-suggest +2 -1
  218. package/scripts/meter-watch +57 -0
  219. package/scripts/migrate-to-global +1 -1
  220. package/scripts/new-intent +4 -13
  221. package/scripts/node-input +92 -0
  222. package/scripts/node-run +225 -0
  223. package/scripts/node-transition +291 -0
  224. package/scripts/outcome-report +74 -0
  225. package/scripts/plastic-lock +42 -33
  226. package/scripts/promote-session-item +3 -2
  227. package/scripts/read-config +53 -9
  228. package/scripts/ready-set +126 -0
  229. package/scripts/release-check +123 -0
  230. package/scripts/report-screen +177 -16
  231. package/scripts/roadmap-graph +119 -0
  232. package/scripts/roadmap-savepoint +7 -0
  233. package/scripts/runner +581 -0
  234. package/scripts/savepoint-note +11 -9
  235. package/scripts/session-commit +2 -1
  236. package/scripts/session-usage +56 -0
  237. package/scripts/skill-lint +115 -6
  238. package/scripts/spawn-preamble +2 -2
  239. package/scripts/update.rb +25 -4
  240. package/scripts/validate-work-graph +39 -0
  241. package/scripts/verify-intent +3 -2
  242. package/scripts/write-handoff +2 -1
  243. package/templates/agents.md +7 -7
  244. package/templates/config.yml +16 -9
  245. package/templates/dashboard-screen.md +22 -0
  246. package/templates/display-fixture.md +21 -0
  247. package/templates/graph.md +16 -0
  248. package/templates/index.md +1 -1
  249. package/templates/intent-screen.md +1 -1
  250. package/templates/node-decision.md +11 -0
  251. package/templates/node-research.md +13 -0
  252. package/templates/node-verify.md +13 -0
  253. package/templates/node-work.md +22 -0
  254. package/templates/outcome.md +8 -3
  255. package/templates/project.yml +1 -1
  256. package/templates/render.css +10 -0
  257. package/templates/report-plan.md +15 -0
  258. package/templates/report-roadmap-delivered.md +10 -0
  259. package/templates/report-roadmap-plan.md +9 -0
  260. package/templates/report-roadmap-state.md +9 -0
  261. package/templates/report-state.md +1 -1
  262. package/templates/roadmap.md +13 -0
  263. package/bin/plastic.js +0 -70
  264. package/scripts/lib/bridge.rb +0 -116
  265. package/skills/agent-advisor/SKILL.md +0 -92
  266. package/skills/auto/SKILL.md +0 -296
  267. package/skills/auto/evals/evals.json +0 -255
  268. package/skills/auto/references/end-tail.md +0 -66
  269. package/skills/auto/references/human-report-contract.md +0 -78
  270. package/skills/conventions/SKILL.md +0 -29
  271. package/skills/dashboard/SKILL.md +0 -169
  272. package/skills/dashboard/evals/evals.json +0 -38
  273. package/skills/dashboard/references/classification.md +0 -22
  274. package/skills/dashboard/templates/dashboard-global.md +0 -20
  275. package/skills/dashboard/templates/dashboard-project.md +0 -19
  276. package/skills/direct/SKILL.md +0 -66
  277. package/skills/direct/references/request-signals.md +0 -59
  278. package/skills/doctor/SKILL.md +0 -299
  279. package/skills/doctor/report.md +0 -102
  280. package/skills/feedback/SKILL.md +0 -98
  281. package/skills/feedback/references/transport-and-privacy.md +0 -65
  282. package/skills/feedback/report.md +0 -36
  283. package/skills/install/SKILL.md +0 -217
  284. package/skills/intent-continuing/SKILL.md +0 -154
  285. package/skills/intent-continuing/references/board-fill.md +0 -43
  286. package/skills/intent-continuing/references/boarding-matrix.md +0 -34
  287. package/skills/intent-continuing/references/context-management.md +0 -28
  288. package/skills/intent-continuing/references/liveness-ranking.md +0 -57
  289. package/skills/intent-creating/SKILL.md +0 -164
  290. package/skills/intent-creating/evals/evals.json +0 -72
  291. package/skills/intent-creating/references/lifecycle.md +0 -81
  292. package/skills/intent-creating/references/wikilinks.md +0 -8
  293. package/skills/intent-ending/SKILL.md +0 -176
  294. package/skills/intent-ending/evals/evals.json +0 -74
  295. package/skills/intent-executing/SKILL.md +0 -170
  296. package/skills/intent-executing/evals/evals.json +0 -66
  297. package/skills/intent-executing/implementer-prompt.md +0 -42
  298. package/skills/intent-executing/spec-reviewer-prompt.md +0 -27
  299. package/skills/intent-speccing/SKILL.md +0 -130
  300. package/skills/intent-speccing/evals/evals.json +0 -126
  301. package/skills/intent-speccing/references/design-principles.md +0 -44
  302. package/skills/intent-speccing/references/per-section-fill-rules.md +0 -92
  303. package/skills/intent-speccing/references/self-verify-checklist.md +0 -37
  304. package/skills/project-creating/SKILL.md +0 -162
  305. package/skills/project-creating/references/hubs-projects.md +0 -55
  306. package/skills/project-creating/references/project-scaffolding.md +0 -97
  307. package/skills/releasing/SKILL.md +0 -337
  308. package/skills/releasing/references/deprecations.md +0 -60
  309. package/skills/releasing/references/promotion-and-tagging.md +0 -66
  310. package/skills/releasing/references/release-lines.md +0 -105
  311. package/skills/roadmap/SKILL.md +0 -64
  312. package/skills/roadmap/references/file-format.md +0 -124
  313. package/skills/roadmap/references/operations.md +0 -112
  314. package/skills/rollback/SKILL.md +0 -91
  315. package/skills/tutorial/SKILL.md +0 -65
  316. package/skills/tutorial/evals/evals.json +0 -186
  317. package/skills/uninstall/SKILL.md +0 -75
  318. package/skills/update/SKILL.md +0 -126
  319. /package/{skills/auto/references → docs/help}/agent-report-contract.md +0 -0
  320. /package/{skills/intent-executing → docs/help}/code-quality-reviewer-prompt.md +0 -0
  321. /package/{skills/conventions/references → docs/help}/lifecycle-and-savepoints.md +0 -0
  322. /package/{skills/intent-executing → docs/help}/plan-reviewer-prompt.md +0 -0
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "yaml"
4
+ require "date"
5
+ require_relative "../command"
6
+ require_relative "../legacy"
7
+ require_relative "../../store_provisioning"
8
+
9
+ # `plastic project new` - registers a project in projects.yml, then provisions
10
+ # and validates its store (`provision-project-store`, `validate-project`, run
11
+ # through Legacy). The project directory must already exist; this command
12
+ # never makes one, and a slug already registered is a Failure.
13
+ module Plastic
14
+ class CLI
15
+ module Commands
16
+ class ProjectNew < Command
17
+ USAGE_LINE = "plastic project new SLUG --path PATH [--parent ID] [--json]"
18
+
19
+ def initialize(argv, runner: nil, **streams)
20
+ super(argv, **streams)
21
+ @runner = runner
22
+ end
23
+
24
+ def call
25
+ raise Usage, "SLUG is required" if slug.to_s.empty?
26
+ raise Usage, "--path is required" if options[:path].to_s.empty?
27
+ raise Failure, "#{options[:path]} does not exist" unless Dir.exist?(options[:path])
28
+ raise Failure, "#{options[:path]} has no AGENTS.md; write one first" unless File.file?(File.join(options[:path], "AGENTS.md"))
29
+ raise Failure, "#{slug} is already registered" if StoreProvisioning.registered?(slug, scope.plastic_home)
30
+
31
+ register
32
+ run("provision-project-store", slug, "--home", scope.plastic_home)
33
+ run("validate-project", slug, "--home", scope.plastic_home)
34
+ @output.next_step("plastic project links", because: "the new store's Links section needs projecting before anything cites it")
35
+ end
36
+
37
+ private
38
+
39
+ def slug
40
+ arguments.first
41
+ end
42
+
43
+ def switches(parser)
44
+ parser.on("--path PATH") { |v| @options[:path] = v }
45
+ parser.on("--parent ID") { |v| @options[:parent] = v }
46
+ end
47
+
48
+ def projects_yml
49
+ File.join(scope.plastic_home, "projects.yml")
50
+ end
51
+
52
+ def register
53
+ data = File.exist?(projects_yml) ? (YAML.safe_load_file(projects_yml) || {}) : {}
54
+ data["projects"] ||= {}
55
+ entry = {"path" => File.expand_path(options[:path]), "registered" => Date.today.to_s, "status" => "active"}
56
+ entry["parent"] = options[:parent] if options[:parent]
57
+ data["projects"][slug] = entry
58
+ File.write(projects_yml, YAML.dump(data))
59
+ end
60
+
61
+ def run(script, *args)
62
+ status = legacy.run(script, *args)
63
+ raise Failure, "#{script} exited #{status}" unless status.zero?
64
+ end
65
+
66
+ def legacy
67
+ @legacy ||= Legacy.new(env: @env, runner: @runner, output: @output, json: options[:json])
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../command"
4
+ require_relative "../../search_index"
5
+
6
+ module Plastic
7
+ class CLI
8
+ module Commands
9
+ class Query < Command
10
+ USAGE_LINE = "plastic query SQL [--json]"
11
+
12
+ def call
13
+ raise Usage, "SQL is missing" if arguments.empty?
14
+ raise Failure, "no index at #{database}; run plastic index" unless File.file?(database)
15
+
16
+ rows = Sqlite.call(database, arguments.join(" "), readonly: true)
17
+ rows.each_with_index { |row, index| @output.row((index + 1).to_s, row.map { |key, value| "#{key}=#{value}" }.join(" ")) }
18
+ @output.next_step("none", because: "the rows are the whole answer; the database is opened read-only")
19
+ rescue Sqlite::Error => e
20
+ raise Failure, e.message
21
+ end
22
+
23
+ private
24
+
25
+ def database
26
+ SearchIndex.path(scope.plastic_home)
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../command"
4
+
5
+ module Plastic
6
+ class CLI
7
+ module Commands
8
+ class Render < Command
9
+ USAGE_LINE = "plastic render FILE"
10
+ STYLE = File.expand_path("../../../../templates/render.css", __dir__)
11
+
12
+ def call
13
+ file = arguments.first or raise Usage, "FILE is the markdown file to render"
14
+ raise Failure, "no file at #{file}" unless File.file?(file)
15
+
16
+ require "rubygems"
17
+ require "rdoc"
18
+ body = RDoc::Markdown.parse(File.read(file, encoding: "UTF-8")).accept(html_formatter)
19
+ @output.raw("<!doctype html>\n<meta charset=\"utf-8\">\n<title>#{File.basename(file)}</title>\n" \
20
+ "<style>\n#{File.read(STYLE)}</style>\n#{body}")
21
+ end
22
+
23
+ private
24
+
25
+ def html_formatter(formatter_class = RDoc::Markup::ToHtml)
26
+ initializer = formatter_class.instance_method(:initialize)
27
+ options = (initializer.parameters.any? { |_, name| name == :options }) ? [RDoc::Options.new] : []
28
+ formatter_class.new(*options)
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "subcommand_list"
4
+
5
+ # `plastic roadmap` - the list of `plastic roadmap ...` subcommands, straight
6
+ # out of the table; a word that names none of them is a usage error naming
7
+ # the same list, so a typo never falls through to a script.
8
+ module Plastic
9
+ class CLI
10
+ module Commands
11
+ class Roadmap < SubcommandList
12
+ USAGE_LINE = "plastic roadmap SUBCOMMAND [options]"
13
+ PREFIX = "roadmap"
14
+ NEXT = "plastic roadmap next"
15
+ BECAUSE = "next names the roadmap most worth continuing, with no slug to guess"
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../command"
4
+ require_relative "../legacy"
5
+
6
+ # `plastic roadmap check` - the roadmap graph's batches, ready set and any
7
+ # cycle or dangling id (`roadmap-graph check`, run through Legacy).
8
+ #
9
+ # A roadmap with no `## Graph` section has nothing to check, and the script's
10
+ # own exit code says only that something failed. That case is named here, with
11
+ # the command that repairs it, so the reader never has to know which script ran.
12
+ module Plastic
13
+ class CLI
14
+ module Commands
15
+ class RoadmapCheck < Command
16
+ USAGE_LINE = "plastic roadmap check SLUG [--json]"
17
+
18
+ def initialize(argv, runner: nil, **streams)
19
+ super(argv, **streams)
20
+ @runner = runner
21
+ end
22
+
23
+ def call
24
+ raise Usage, "SLUG is required" if slug.to_s.empty?
25
+ raise Failure, "no roadmap #{slug} in #{File.basename(scope.roadmaps_dir)}" unless File.file?(path)
26
+ raise Failure, "#{slug} has no ## Graph section; plastic roadmap migrate #{slug} writes one from its batches" unless graph?
27
+
28
+ status = legacy.run("roadmap-graph", "check", path)
29
+ raise Failure, "roadmap-graph exited #{status}" unless status.zero?
30
+
31
+ @output.next_step("plastic roadmap show #{slug}", because: "the graph just checked out clean")
32
+ end
33
+
34
+ private
35
+
36
+ def graph?
37
+ File.foreach(path).any? { |line| line.start_with?("## Graph") }
38
+ end
39
+
40
+ def slug
41
+ arguments.first
42
+ end
43
+
44
+ def path
45
+ File.join(scope.roadmaps_dir, "#{slug}.md")
46
+ end
47
+
48
+ def legacy
49
+ @legacy ||= Legacy.new(env: @env, runner: @runner, output: @output, json: options[:json])
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../command"
4
+ require_relative "../legacy"
5
+
6
+ # `plastic roadmap log` - appends a savepoint line to a roadmap's ledger
7
+ # (`roadmap-savepoint append`, run through Legacy).
8
+ module Plastic
9
+ class CLI
10
+ module Commands
11
+ class RoadmapLog < Command
12
+ USAGE_LINE = 'plastic roadmap log SLUG EVENT "TEXT" [--json]'
13
+
14
+ def initialize(argv, runner: nil, **streams)
15
+ super(argv, **streams)
16
+ @runner = runner
17
+ end
18
+
19
+ def call
20
+ raise Usage, "SLUG is required" if slug.to_s.empty?
21
+ raise Usage, "EVENT is required" if event.to_s.empty?
22
+ raise Usage, "TEXT is required" if text.to_s.empty?
23
+
24
+ status = legacy.run("roadmap-savepoint", "append", "--roadmap", path, "--event", event, "--detail", text)
25
+ raise Failure, "roadmap-savepoint exited #{status}" unless status.zero?
26
+
27
+ @output.next_step("plastic roadmap show #{slug}", because: "the log line just landed on the state screen")
28
+ end
29
+
30
+ private
31
+
32
+ def slug
33
+ arguments[0]
34
+ end
35
+
36
+ def event
37
+ arguments[1]
38
+ end
39
+
40
+ def text
41
+ arguments[2]
42
+ end
43
+
44
+ def path
45
+ File.join(scope.roadmaps_dir, "#{slug}.md")
46
+ end
47
+
48
+ def legacy
49
+ @legacy ||= Legacy.new(env: @env, runner: @runner, output: @output, json: options[:json])
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../command"
4
+ require_relative "../legacy"
5
+
6
+ # `plastic roadmap migrate` - writes a roadmap's `## Graph` section from the
7
+ # batch headings it already carries (`roadmap-graph migrate`, run through
8
+ # Legacy). This is the repair `plastic roadmap check` names when a roadmap has
9
+ # no graph, so the CLI can perform every repair it asks for.
10
+ module Plastic
11
+ class CLI
12
+ module Commands
13
+ class RoadmapMigrate < Command
14
+ USAGE_LINE = "plastic roadmap migrate SLUG [--dry-run] [--json]"
15
+
16
+ def initialize(argv, runner: nil, **streams)
17
+ super(argv, **streams)
18
+ @runner = runner
19
+ end
20
+
21
+ def call
22
+ raise Usage, "SLUG is required" if slug.to_s.empty?
23
+ raise Failure, "no roadmap #{slug} in #{File.basename(scope.roadmaps_dir)}" unless File.file?(path)
24
+
25
+ arguments_for_script = ["migrate", path]
26
+ arguments_for_script << "--dry-run" if options[:dry_run]
27
+ status = legacy.run("roadmap-graph", *arguments_for_script)
28
+ raise Failure, "roadmap-graph exited #{status}" unless status.zero?
29
+
30
+ @output.next_step("plastic roadmap check #{slug}", because: "a written graph is what check reads")
31
+ end
32
+
33
+ private
34
+
35
+ def switches(parser)
36
+ parser.on("--dry-run") { @options[:dry_run] = true }
37
+ end
38
+
39
+ def slug
40
+ arguments.first
41
+ end
42
+
43
+ def path
44
+ File.join(scope.roadmaps_dir, "#{slug}.md")
45
+ end
46
+
47
+ def legacy
48
+ @legacy ||= Legacy.new(env: @env, runner: @runner, output: @output, json: options[:json])
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "json"
4
+ require_relative "../command"
5
+ require_relative "../legacy"
6
+
7
+ # `plastic roadmap next` - the roadmap most worth continuing right now
8
+ # (`roadmap-next --which`, run through Legacy). The script speaks JSON, so this
9
+ # command renders it as a screen and leaves the document to `--json`, the way
10
+ # every other command reads.
11
+ module Plastic
12
+ class CLI
13
+ module Commands
14
+ class RoadmapNext < Command
15
+ USAGE_LINE = "plastic roadmap next [--json]"
16
+ AFTER = "plastic roadmap show SLUG"
17
+ BECAUSE = "the winner it just named is the slug that command wants"
18
+
19
+ def initialize(argv, runner: nil, **streams)
20
+ super(argv, **streams)
21
+ @runner = runner
22
+ end
23
+
24
+ def call
25
+ report = parse(*legacy.capture("roadmap-next", "--roadmaps-dir", scope.roadmaps_dir, "--which"))
26
+ screen(report)
27
+ @output.next_step(after(report), because: BECAUSE)
28
+ end
29
+
30
+ private
31
+
32
+ def parse(text, status)
33
+ raise Failure, "roadmap-next exited #{status}" unless status.zero?
34
+
35
+ JSON.parse(text)
36
+ rescue JSON::ParserError
37
+ raise Failure, "roadmap-next did not print a report"
38
+ end
39
+
40
+ def after(report)
41
+ slug = report["roadmap"].to_s
42
+ slug.empty? ? AFTER : AFTER.sub("SLUG", slug)
43
+ end
44
+
45
+ def screen(report)
46
+ @output.row("state", report["state"])
47
+ @output.row("roadmap", report["roadmap"] || "none")
48
+ @output.row("wave", report["frontier_wave"]) unless report["frontier_wave"].to_s.empty?
49
+ @output.row("next", queue(report["dispatchable_queue"]))
50
+ @output.row("delivering", entries(report["in_flight"]))
51
+ @output.row("blocked", entries(report["blocked"]))
52
+ @output.row("tie", Array(report["tie_candidates"]).join(", ")) if report["tie"]
53
+ end
54
+
55
+ def queue(list)
56
+ rows = entries(list)
57
+ rows.empty? ? "none" : rows
58
+ end
59
+
60
+ def entries(list)
61
+ Array(list).map { |entry| [entry["id"], entry["status"], entry["wave"]].compact.join(" ") }
62
+ end
63
+
64
+ def legacy
65
+ @legacy ||= Legacy.new(env: @env, runner: @runner, output: @output, json: options[:json])
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../command"
4
+ require_relative "../legacy"
5
+
6
+ # `plastic roadmap show` - a roadmap's state screen (`report-screen roadmap
7
+ # FILE state`, run through Legacy). SLUG is required: `plastic roadmap next`
8
+ # is the command that picks one when the caller has none in mind.
9
+ module Plastic
10
+ class CLI
11
+ module Commands
12
+ class RoadmapShow < Command
13
+ USAGE_LINE = "plastic roadmap show SLUG [--json]"
14
+
15
+ def initialize(argv, runner: nil, **streams)
16
+ super(argv, **streams)
17
+ @runner = runner
18
+ end
19
+
20
+ def call
21
+ raise Usage, "SLUG is required" if slug.to_s.empty?
22
+
23
+ status = legacy.run("report-screen", "roadmap", path, "state")
24
+ raise Failure, "report-screen exited #{status}" unless status.zero?
25
+
26
+ @output.next_step("plastic roadmap log #{slug} EVENT \"TEXT\"", because: "a savepoint is how this state screen keeps moving")
27
+ end
28
+
29
+ private
30
+
31
+ def slug
32
+ arguments.first
33
+ end
34
+
35
+ def path
36
+ File.join(scope.roadmaps_dir, "#{slug}.md")
37
+ end
38
+
39
+ def legacy
40
+ @legacy ||= Legacy.new(env: @env, runner: @runner, output: @output, json: options[:json])
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "installer_verb"
4
+
5
+ # `plastic rollback` - steps back to a version this machine has already run. The
6
+ # work is still scripts/rollback.rb, run through Legacy.
7
+ module Plastic
8
+ class CLI
9
+ module Commands
10
+ class Rollback < InstallerVerb
11
+ USAGE_LINE = "plastic rollback [--version VERSION] [--downgrade] [--upgrade] [--reinstall]"
12
+ FLAGS = %w[--version --downgrade --upgrade --reinstall].freeze
13
+
14
+ SCRIPT = "rollback.rb"
15
+ AFTER = "plastic version"
16
+ BECAUSE = "the version says which build is installed"
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../command"
4
+ require_relative "../../search_index"
5
+ require_relative "../../rlm/query"
6
+
7
+ module Plastic
8
+ class CLI
9
+ module Commands
10
+ class Search < Command
11
+ USAGE_LINE = "plastic search TERMS [--ask] [--project SLUG] [--limit N] [--json]"
12
+ DEFAULT_LIMIT = 10
13
+
14
+ def call
15
+ raise Usage, "TERMS is missing" if arguments.empty?
16
+ raise Failure, "no index at #{database}; run plastic index" unless File.file?(database)
17
+
18
+ rows = options[:ask] ? RLM::Query.new(RLM::Probe.new(corpus, limit: limit)).call(arguments.join(" ")) : found(arguments, limit)
19
+ rows.each { |row| @output.row(row["path"], row["excerpt"].gsub(/\s+/, " ").strip) }
20
+ @output.row("result", "no match") if rows.empty?
21
+ @output.next_step("none", because: "the search is complete")
22
+ rescue Sqlite::Error => e
23
+ raise Failure, e.message
24
+ end
25
+
26
+ private
27
+
28
+ def switches(parser)
29
+ parser.on("--ask") { @options[:ask] = true }
30
+ parser.on("--project SLUG") { |slug| @options[:project] = slug }
31
+ parser.on("--limit N", Integer) { |limit| @options[:limit] = limit }
32
+ end
33
+
34
+ def limit
35
+ options[:limit] || DEFAULT_LIMIT
36
+ end
37
+
38
+ def found(terms, count)
39
+ SearchIndex.search(scope.plastic_home, terms, limit: count, prefix: prefix)
40
+ end
41
+
42
+ def corpus
43
+ RLM::Corpus.new(method(:found))
44
+ end
45
+
46
+ def database
47
+ SearchIndex.path(scope.plastic_home)
48
+ end
49
+
50
+ def prefix
51
+ return "" unless options[:project]
52
+
53
+ home = scope.plastic_home
54
+ root = (scope.slug == Scope::GLOBAL) ? StoreLayout.global_store(home) : StoreLayout.project_root(home, scope.slug)
55
+ "#{root.delete_prefix("#{home}/")}/"
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "subcommand_list"
4
+
5
+ # `plastic session` - the list of `plastic session ...` subcommands, straight
6
+ # out of the table.
7
+ module Plastic
8
+ class CLI
9
+ module Commands
10
+ class Session < SubcommandList
11
+ USAGE_LINE = "plastic session SUBCOMMAND [options]"
12
+ PREFIX = "session"
13
+ NEXT = 'plastic session commit "SUMMARY"'
14
+ BECAUSE = "a commit is the smallest unit every other session subcommand builds on"
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../command"
4
+ require_relative "../legacy"
5
+
6
+ # `plastic session commit` - one commit for a verified checklist item, on the
7
+ # directory this command was invoked from (`session-commit --cwd DIR
8
+ # --summary SUMMARY`, run through Legacy; fail-open by contract, so a Failure
9
+ # here means the script's own usage error, not a git failure).
10
+ module Plastic
11
+ class CLI
12
+ module Commands
13
+ class SessionCommit < Command
14
+ USAGE_LINE = 'plastic session commit "SUMMARY" [--json]'
15
+
16
+ def initialize(argv, runner: nil, **streams)
17
+ super(argv, **streams)
18
+ @runner = runner
19
+ end
20
+
21
+ def call
22
+ raise Usage, "SUMMARY is required" if summary.to_s.empty?
23
+
24
+ status = legacy.run("session-commit", "--cwd", @directory, "--summary", summary)
25
+ raise Failure, "session-commit exited #{status}" unless status.zero?
26
+
27
+ @output.next_step("plastic session handoff", because: "a handoff after a commit keeps the day ledger current")
28
+ end
29
+
30
+ private
31
+
32
+ def summary
33
+ arguments.first
34
+ end
35
+
36
+ def legacy
37
+ @legacy ||= Legacy.new(env: @env, runner: @runner, output: @output, json: options[:json])
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../command"
4
+ require_relative "../legacy"
5
+
6
+ # `plastic session handoff` - writes this session's hand-off into the day
7
+ # ledger (`write-handoff --trigger tick`, run through Legacy).
8
+ module Plastic
9
+ class CLI
10
+ module Commands
11
+ class SessionHandoff < Command
12
+ USAGE_LINE = "plastic session handoff [--json]"
13
+
14
+ def initialize(argv, runner: nil, **streams)
15
+ super(argv, **streams)
16
+ @runner = runner
17
+ end
18
+
19
+ def call
20
+ status = legacy.run("write-handoff", "--trigger", "tick")
21
+ raise Failure, "write-handoff exited #{status}" unless status.zero?
22
+
23
+ @output.next_step("plastic session summary", because: "the summary is what a fresh handoff feeds")
24
+ end
25
+
26
+ private
27
+
28
+ def legacy
29
+ @legacy ||= Legacy.new(env: @env, runner: @runner, output: @output, json: options[:json])
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../command"
4
+ require_relative "../legacy"
5
+
6
+ # `plastic session summary` - the block SessionStart injects at boot: open
7
+ # items, the last five done, live auto intents, other active sessions
8
+ # (`day-summary`, run through Legacy).
9
+ module Plastic
10
+ class CLI
11
+ module Commands
12
+ class SessionSummary < Command
13
+ USAGE_LINE = "plastic session summary [--json]"
14
+
15
+ def initialize(argv, runner: nil, **streams)
16
+ super(argv, **streams)
17
+ @runner = runner
18
+ end
19
+
20
+ def call
21
+ status = legacy.run("day-summary")
22
+ raise Failure, "day-summary exited #{status}" unless status.zero?
23
+
24
+ @output.next_step("plastic status", because: "the board is where the summary's open items are worked from")
25
+ end
26
+
27
+ private
28
+
29
+ def legacy
30
+ @legacy ||= Legacy.new(env: @env, runner: @runner, output: @output, json: options[:json])
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end