@zalom/plastic 2.0.0-alpha.26 → 2.0.0-alpha.28

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 (224) hide show
  1. package/PLASTIC.md +13 -139
  2. package/README.md +337 -133
  3. package/agents/plastic-enforcer.md +12 -12
  4. package/agents/plastic-executor.md +2 -1
  5. package/agents/plastic-node-research.md +4 -2
  6. package/agents/plastic-node-verify.md +1 -0
  7. package/agents/plastic-node-work.md +1 -0
  8. package/agents/{plastic-advisor.md → plastic-primary-advisor.md} +6 -8
  9. package/agents/{plastic-faux-advisor.md → plastic-secondary-advisor.md} +9 -12
  10. package/bin/crap +4 -0
  11. package/bin/lib/context_budget.rb +35 -1
  12. package/bin/lib/skill_census.rb +839 -0
  13. package/bin/plastic +6 -0
  14. package/bin/plastic-skill-census +114 -0
  15. package/bin/verify-change +345 -0
  16. package/config_asks.yml +4 -4
  17. package/deprecations.yml +1 -1
  18. package/{skills/agent-advisor/references → docs/help}/advisor-protocol.md +19 -24
  19. package/{skills/auto/references → docs/help}/agent-architecture.md +7 -7
  20. package/{skills/conventions/references → docs/help}/completion-and-done.md +1 -1
  21. package/{skills/auto/references → docs/help}/human-report-contract.md +17 -19
  22. package/{skills/conventions/references → docs/help}/roadmaps.md +2 -2
  23. package/{skills/tutorial/references → docs/help}/track-1-guided.md +8 -8
  24. package/{skills/tutorial/references → docs/help}/track-2-auto.md +5 -5
  25. package/{skills/tutorial/references → docs/help}/track-3-projects-and-roadmaps.md +24 -17
  26. package/package.json +3 -2
  27. package/scripts/append-ledger +2 -1
  28. package/scripts/dashboard.rb +10 -9
  29. package/scripts/day-summary +2 -1
  30. package/scripts/doctor.rb +57 -49
  31. package/scripts/end-intent +2 -8
  32. package/scripts/file-session-intent +2 -1
  33. package/scripts/hook-capture +4 -3
  34. package/scripts/hook-close +2 -1
  35. package/scripts/hook-record +3 -2
  36. package/scripts/hook-savepoint +3 -2
  37. package/scripts/hook-session-start +5 -4
  38. package/scripts/hook-stop +2 -1
  39. package/scripts/insight-append +1 -2
  40. package/scripts/install.rb +7 -5
  41. package/scripts/lib/action_graph_shim.rb +3 -1
  42. package/scripts/lib/active_delivery.rb +1 -1
  43. package/scripts/lib/agent_models.rb +44 -26
  44. package/scripts/lib/arm.rb +2 -1
  45. package/scripts/lib/backup.rb +63 -0
  46. package/scripts/lib/cli/command.rb +85 -0
  47. package/scripts/lib/cli/commands/auto.rb +18 -0
  48. package/scripts/lib/cli/commands/auto_brief.rb +44 -0
  49. package/scripts/lib/cli/commands/auto_lock.rb +60 -0
  50. package/scripts/lib/cli/commands/auto_report.rb +50 -0
  51. package/scripts/lib/cli/commands/auto_take.rb +25 -0
  52. package/scripts/lib/cli/commands/backup.rb +43 -0
  53. package/scripts/lib/cli/commands/checkout.rb +25 -0
  54. package/scripts/lib/cli/commands/continue.rb +66 -0
  55. package/scripts/lib/cli/commands/doctor.rb +20 -0
  56. package/scripts/lib/cli/commands/feedback.rb +40 -0
  57. package/scripts/lib/cli/commands/help.rb +69 -0
  58. package/scripts/lib/cli/commands/hook.rb +32 -0
  59. package/scripts/lib/cli/commands/index.rb +23 -0
  60. package/scripts/lib/cli/commands/install.rb +21 -0
  61. package/scripts/lib/cli/commands/installer_verb.rb +37 -0
  62. package/scripts/lib/cli/commands/intent.rb +19 -0
  63. package/scripts/lib/cli/commands/intent_answer.rb +37 -0
  64. package/scripts/lib/cli/commands/intent_command.rb +53 -0
  65. package/scripts/lib/cli/commands/intent_end.rb +61 -0
  66. package/scripts/lib/cli/commands/intent_new.rb +62 -0
  67. package/scripts/lib/cli/commands/intent_note.rb +43 -0
  68. package/scripts/lib/cli/commands/intent_rule.rb +36 -0
  69. package/scripts/lib/cli/commands/intent_show.rb +25 -0
  70. package/scripts/lib/cli/commands/intent_spec.rb +44 -0
  71. package/scripts/lib/cli/commands/intent_step.rb +43 -0
  72. package/scripts/lib/cli/commands/intent_verify.rb +26 -0
  73. package/scripts/lib/cli/commands/migrate.rb +16 -0
  74. package/scripts/lib/cli/commands/migrate_stores.rb +31 -0
  75. package/scripts/lib/cli/commands/next.rb +49 -0
  76. package/scripts/lib/cli/commands/project.rb +19 -0
  77. package/scripts/lib/cli/commands/project_links.rb +42 -0
  78. package/scripts/lib/cli/commands/project_list.rb +20 -0
  79. package/scripts/lib/cli/commands/project_new.rb +72 -0
  80. package/scripts/lib/cli/commands/query.rb +31 -0
  81. package/scripts/lib/cli/commands/render.rb +25 -0
  82. package/scripts/lib/cli/commands/roadmap.rb +19 -0
  83. package/scripts/lib/cli/commands/roadmap_check.rb +44 -0
  84. package/scripts/lib/cli/commands/roadmap_log.rb +54 -0
  85. package/scripts/lib/cli/commands/roadmap_next.rb +34 -0
  86. package/scripts/lib/cli/commands/roadmap_show.rb +45 -0
  87. package/scripts/lib/cli/commands/rollback.rb +20 -0
  88. package/scripts/lib/cli/commands/search.rb +60 -0
  89. package/scripts/lib/cli/commands/session.rb +18 -0
  90. package/scripts/lib/cli/commands/session_commit.rb +42 -0
  91. package/scripts/lib/cli/commands/session_handoff.rb +34 -0
  92. package/scripts/lib/cli/commands/session_summary.rb +35 -0
  93. package/scripts/lib/cli/commands/status.rb +68 -0
  94. package/scripts/lib/cli/commands/subcommand_list.rb +36 -0
  95. package/scripts/lib/cli/commands/sync.rb +46 -0
  96. package/scripts/lib/cli/commands/uninstall.rb +20 -0
  97. package/scripts/lib/cli/commands/update.rb +20 -0
  98. package/scripts/lib/cli/commands/version.rb +53 -0
  99. package/scripts/lib/cli/frontier.rb +84 -0
  100. package/scripts/lib/cli/legacy.rb +50 -0
  101. package/scripts/lib/cli/output.rb +102 -0
  102. package/scripts/lib/cli/scope.rb +127 -0
  103. package/scripts/lib/cli/table.rb +64 -0
  104. package/scripts/lib/cli.rb +94 -0
  105. package/scripts/lib/codex_adapter.rb +5 -4
  106. package/scripts/lib/compact_instructions.rb +8 -0
  107. package/scripts/lib/day_summary.rb +4 -3
  108. package/scripts/lib/doctor_core.rb +7 -32
  109. package/scripts/lib/doctor_session_ledger.rb +2 -1
  110. package/scripts/lib/feedback_report.rb +1 -1
  111. package/scripts/lib/graph_measure_models.rb +4 -2
  112. package/scripts/lib/index_entry.rb +9 -0
  113. package/scripts/lib/installer_core.rb +175 -56
  114. package/scripts/lib/intent_screen.rb +3 -3
  115. package/scripts/lib/lock.rb +2 -2
  116. package/scripts/lib/node_file.rb +22 -2
  117. package/scripts/lib/node_input.rb +11 -6
  118. package/scripts/lib/node_return.rb +8 -3
  119. package/scripts/lib/preflight.rb +2 -4
  120. package/scripts/lib/project_config.rb +2 -1
  121. package/scripts/lib/project_validator.rb +3 -2
  122. package/scripts/lib/qmd_sync.rb +8 -7
  123. package/scripts/lib/reference_archive.rb +45 -0
  124. package/scripts/lib/release_guard.rb +2 -0
  125. package/scripts/lib/report_screen.rb +4 -3
  126. package/scripts/lib/rlm/corpus.rb +13 -0
  127. package/scripts/lib/rlm/probe.rb +29 -0
  128. package/scripts/lib/rlm/query.rb +22 -0
  129. package/scripts/lib/roadmap_queue.rb +2 -2
  130. package/scripts/lib/roadmap_savepoint.rb +1 -1
  131. package/scripts/lib/runner_absorb.rb +59 -2
  132. package/scripts/lib/runner_dispatch.rb +12 -8
  133. package/scripts/lib/runner_policy.rb +28 -10
  134. package/scripts/lib/search_index.rb +55 -0
  135. package/scripts/lib/session_git.rb +4 -3
  136. package/scripts/lib/sqlite.rb +22 -0
  137. package/scripts/lib/store_discovery.rb +7 -6
  138. package/scripts/lib/store_layout.rb +54 -0
  139. package/scripts/lib/store_provisioning.rb +2 -1
  140. package/scripts/lib/store_sync.rb +85 -0
  141. package/scripts/lib/stores_move.rb +93 -0
  142. package/scripts/lib/verify_intent.rb +2 -7
  143. package/scripts/lib/version_number.rb +48 -0
  144. package/scripts/lib/work_graph.rb +59 -0
  145. package/scripts/lib/worktree.rb +3 -8
  146. package/scripts/lib/worktree_sweep.rb +3 -2
  147. package/scripts/link-suggest +2 -1
  148. package/scripts/migrate-to-global +1 -1
  149. package/scripts/new-intent +3 -12
  150. package/scripts/node-run +2 -1
  151. package/scripts/plastic-lock +3 -2
  152. package/scripts/promote-session-item +3 -2
  153. package/scripts/read-config +44 -6
  154. package/scripts/release-check +10 -5
  155. package/scripts/report-screen +1 -1
  156. package/scripts/session-commit +2 -1
  157. package/scripts/spawn-preamble +2 -2
  158. package/scripts/update.rb +25 -4
  159. package/scripts/write-handoff +2 -1
  160. package/templates/agents.md +6 -6
  161. package/templates/config.yml +13 -6
  162. package/templates/node-research.md +4 -2
  163. package/templates/render.css +10 -0
  164. package/bin/plastic.js +0 -70
  165. package/skills/agent-advisor/SKILL.md +0 -92
  166. package/skills/auto/SKILL.md +0 -297
  167. package/skills/auto/evals/evals.json +0 -255
  168. package/skills/auto/references/end-tail.md +0 -64
  169. package/skills/conventions/SKILL.md +0 -29
  170. package/skills/dashboard/SKILL.md +0 -180
  171. package/skills/dashboard/evals/evals.json +0 -38
  172. package/skills/dashboard/references/classification.md +0 -22
  173. package/skills/dashboard/templates/dashboard-global.md +0 -20
  174. package/skills/dashboard/templates/dashboard-project.md +0 -19
  175. package/skills/direct/SKILL.md +0 -66
  176. package/skills/direct/references/request-signals.md +0 -59
  177. package/skills/doctor/SKILL.md +0 -305
  178. package/skills/doctor/report.md +0 -102
  179. package/skills/feedback/SKILL.md +0 -98
  180. package/skills/feedback/references/transport-and-privacy.md +0 -65
  181. package/skills/feedback/report.md +0 -36
  182. package/skills/install/SKILL.md +0 -217
  183. package/skills/intent-continuing/SKILL.md +0 -156
  184. package/skills/intent-continuing/references/board-fill.md +0 -52
  185. package/skills/intent-continuing/references/boarding-matrix.md +0 -35
  186. package/skills/intent-continuing/references/context-management.md +0 -28
  187. package/skills/intent-continuing/references/liveness-ranking.md +0 -57
  188. package/skills/intent-creating/SKILL.md +0 -89
  189. package/skills/intent-creating/evals/evals.json +0 -72
  190. package/skills/intent-creating/references/lifecycle.md +0 -81
  191. package/skills/intent-creating/references/wikilinks.md +0 -8
  192. package/skills/intent-ending/SKILL.md +0 -182
  193. package/skills/intent-ending/evals/evals.json +0 -74
  194. package/skills/intent-executing/SKILL.md +0 -87
  195. package/skills/intent-executing/evals/evals.json +0 -66
  196. package/skills/intent-executing/implementer-prompt.md +0 -47
  197. package/skills/intent-executing/spec-reviewer-prompt.md +0 -27
  198. package/skills/intent-speccing/SKILL.md +0 -136
  199. package/skills/intent-speccing/evals/evals.json +0 -126
  200. package/skills/intent-speccing/references/design-principles.md +0 -44
  201. package/skills/intent-speccing/references/per-section-fill-rules.md +0 -92
  202. package/skills/intent-speccing/references/self-verify-checklist.md +0 -37
  203. package/skills/project-creating/SKILL.md +0 -162
  204. package/skills/project-creating/references/hubs-projects.md +0 -55
  205. package/skills/project-creating/references/project-scaffolding.md +0 -97
  206. package/skills/releasing/SKILL.md +0 -376
  207. package/skills/releasing/references/deprecations.md +0 -60
  208. package/skills/releasing/references/promotion-and-tagging.md +0 -70
  209. package/skills/releasing/references/release-lines.md +0 -105
  210. package/skills/roadmap/SKILL.md +0 -90
  211. package/skills/roadmap/references/file-format.md +0 -134
  212. package/skills/roadmap/references/operations.md +0 -112
  213. package/skills/rollback/SKILL.md +0 -91
  214. package/skills/tutorial/SKILL.md +0 -66
  215. package/skills/tutorial/evals/evals.json +0 -186
  216. package/skills/uninstall/SKILL.md +0 -75
  217. package/skills/update/SKILL.md +0 -126
  218. /package/{skills/auto/references → docs/help}/agent-report-contract.md +0 -0
  219. /package/{skills/intent-executing → docs/help}/code-quality-reviewer-prompt.md +0 -0
  220. /package/{skills/conventions/references → docs/help}/knowledge-graph.md +0 -0
  221. /package/{skills/conventions/references → docs/help}/lifecycle-and-savepoints.md +0 -0
  222. /package/{skills/conventions/references → docs/help}/locks-and-worktrees.md +0 -0
  223. /package/{skills/conventions/references → docs/help}/maintenance-and-revisions.md +0 -0
  224. /package/{skills/intent-executing → docs/help}/plan-reviewer-prompt.md +0 -0
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Plastic::CLI::TABLE (intent 363) - the whole command line in one frozen hash:
4
+ # a command name mapped to the file that holds it, the class inside
5
+ # Plastic::CLI::Commands, and the one line `plastic help` prints beside it.
6
+ #
7
+ # Adding a command is one row here plus one file. `plastic help` reads this
8
+ # hash and loads nothing, so listing the commands costs no command file.
9
+ # test/cli/table_test.rb walks every row, so a half-wired command cannot ship.
10
+ module Plastic
11
+ class CLI
12
+ TABLE = {
13
+ "auto brief" => ["commands/auto_brief", "AutoBrief", "Print an intent's spawn preamble, and the advisor shapes for --role advisor"],
14
+ "auto lock" => ["commands/auto_lock", "AutoLock", "Inspect, repair, or release an intent's delivery lock"],
15
+ "auto report" => ["commands/auto_report", "AutoReport", "Print an intent's completion report, then the review-by-risk rules"],
16
+ "auto take" => ["commands/auto_take", "AutoTake", "Arm an intent's delivery lock for this session"],
17
+ "auto" => ["commands/auto", "Auto", "List the auto subcommands"],
18
+ "backup" => ["commands/backup", "Backup", "Write one archive of the three databases and the config"],
19
+ "checkout" => ["commands/checkout", "Checkout", "Restore missing store files from the databases"],
20
+ "continue" => ["commands/continue", "Continue", "Show where one project stands and what runs next"],
21
+ "doctor" => ["commands/doctor", "Doctor", "Diagnose Plastic installation health"],
22
+ "feedback" => ["commands/feedback", "Feedback", "File a feedback report, body on standard input"],
23
+ "help" => ["commands/help", "Help", "List the commands and help topics, or show one usage"],
24
+ "hook" => ["commands/hook", "Hook", "Run one harness hook event through its launcher"],
25
+ "index" => ["commands/index", "Index", "Rebuild the search index from every markdown file in the stores"],
26
+ "install" => ["commands/install", "Install", "Install Plastic into this machine's agents"],
27
+ "intent" => ["commands/intent", "Intent", "List the intent subcommands"],
28
+ "intent answer" => ["commands/intent_answer", "IntentAnswer", "Answer an intent's needs_decision node"],
29
+ "intent end" => ["commands/intent_end", "IntentEnd", "Close an intent as delivered or abandoned"],
30
+ "intent new" => ["commands/intent_new", "IntentNew", "Create a new intent"],
31
+ "intent note" => ["commands/intent_note", "IntentNote", "Append a savepoint note to an intent"],
32
+ "intent rule" => ["commands/intent_rule", "IntentRule", "Record a ruling in an intent's Insights"],
33
+ "intent show" => ["commands/intent_show", "IntentShow", "Print an intent's state screen"],
34
+ "intent spec" => ["commands/intent_spec", "IntentSpec", "Print an intent's state screen, then the speccing rules"],
35
+ "intent step" => ["commands/intent_step", "IntentStep", "Run the next ready step of an intent's graph"],
36
+ "intent verify" => ["commands/intent_verify", "IntentVerify", "Run an intent's merge-gate checks"],
37
+ "migrate" => ["commands/migrate", "Migrate", "List the migrate subcommands"],
38
+ "migrate stores" => ["commands/migrate_stores", "MigrateStores", "Move the stores under stores/, behind a full copy of the home"],
39
+ "next" => ["commands/next", "Next", "Print the next action in one line"],
40
+ "project" => ["commands/project", "Project", "List the project subcommands"],
41
+ "project links" => ["commands/project_links", "ProjectLinks", "Project every store's Links sections from frontmatter"],
42
+ "project list" => ["commands/project_list", "ProjectList", "List every store this machine holds"],
43
+ "project new" => ["commands/project_new", "ProjectNew", "Register, provision and validate a new project"],
44
+ "query" => ["commands/query", "Query", "Run one read-only SQL statement on the index"],
45
+ "render" => ["commands/render", "Render", "Print one markdown file as an HTML page"],
46
+ "roadmap" => ["commands/roadmap", "Roadmap", "List the roadmap subcommands"],
47
+ "roadmap check" => ["commands/roadmap_check", "RoadmapCheck", "Check a roadmap's graph for cycles and dangling ids"],
48
+ "roadmap log" => ["commands/roadmap_log", "RoadmapLog", "Append a savepoint line to a roadmap's ledger"],
49
+ "roadmap next" => ["commands/roadmap_next", "RoadmapNext", "Name the roadmap most worth continuing"],
50
+ "roadmap show" => ["commands/roadmap_show", "RoadmapShow", "Print a roadmap's state screen"],
51
+ "rollback" => ["commands/rollback", "Rollback", "Move to a Plastic version this machine has run before"],
52
+ "search" => ["commands/search", "Search", "Find text in the stores, ranked, with one excerpt each"],
53
+ "session commit" => ["commands/session_commit", "SessionCommit", "Commit one verified checklist item"],
54
+ "session handoff" => ["commands/session_handoff", "SessionHandoff", "Write this session's hand-off into the day ledger"],
55
+ "session summary" => ["commands/session_summary", "SessionSummary", "Print the day ledger's open items and recent activity"],
56
+ "session" => ["commands/session", "Session", "List the session subcommands"],
57
+ "status" => ["commands/status", "Status", "Show active work in every store"],
58
+ "sync" => ["commands/sync", "Sync", "Bring the store files and the three databases level"],
59
+ "uninstall" => ["commands/uninstall", "Uninstall", "Remove Plastic from this machine's agents"],
60
+ "update" => ["commands/update", "Update", "Move Plastic to the next version on its channel"],
61
+ "version" => ["commands/version", "Version", "Print the installed Plastic version"]
62
+ }.freeze
63
+ end
64
+ end
@@ -0,0 +1,94 @@
1
+ # encoding: UTF-8
2
+ # frozen_string_literal: true
3
+
4
+ require "did_you_mean"
5
+ require_relative "cli/table"
6
+ require_relative "cli/command"
7
+ require_relative "cli/output"
8
+
9
+ # Plastic::CLI (intent 363) - the dispatcher behind bin/plastic. It reads the
10
+ # command table, matches the longest command name the arguments begin with,
11
+ # requires that one file, and calls it. Nothing else is loaded, which is what
12
+ # keeps a call at about 20 milliseconds with RubyGems off.
13
+ #
14
+ # No arguments, or --help, print the command list. --version prints the
15
+ # version. A command's own --help prints that command's usage line, read from
16
+ # the class without building it. An unknown name exits 2 and names the closest
17
+ # command, so a typo never becomes a stack trace.
18
+ module Plastic
19
+ class CLI
20
+ FLAGS = {"--version" => "version", "-v" => "version",
21
+ "--help" => "help", "-h" => "help"}.freeze
22
+
23
+ def self.call(...)
24
+ new(...).call
25
+ end
26
+
27
+ def initialize(argv, out: $stdout, err: $stderr, env: ENV, home: Dir.home,
28
+ directory: Dir.pwd, table: TABLE)
29
+ @argv = argv.dup
30
+ @out = out
31
+ @err = err
32
+ @env = env
33
+ @home = home
34
+ @directory = directory
35
+ @table = table
36
+ end
37
+
38
+ def call
39
+ matched = match(expanded)
40
+ return unknown(expanded.first) unless matched
41
+
42
+ name, rest = matched
43
+ return usage(name, rest) if help?(rest)
44
+
45
+ command(name).call(rest, out: @out, err: @err, env: @env, home: @home,
46
+ directory: @directory)
47
+ end
48
+
49
+ def match(argv)
50
+ [2, 1].each do |width|
51
+ name = argv.first(width).join(" ")
52
+ return [name, argv.drop(width)] if @table.key?(name)
53
+ end
54
+ nil
55
+ end
56
+
57
+ private
58
+
59
+ def expanded
60
+ return ["help"] if @argv.empty?
61
+
62
+ [FLAGS.fetch(@argv.first, @argv.first)] + @argv.drop(1)
63
+ end
64
+
65
+ def help?(rest)
66
+ rest.any? { |argument| FLAGS[argument] == "help" }
67
+ end
68
+
69
+ def usage(name, rest)
70
+ Output.new(out: @out, err: @err)
71
+ .row("usage", command(name)::USAGE_LINE)
72
+ .flush(json: rest.include?("--json"))
73
+ Command::OK
74
+ end
75
+
76
+ def command(name)
77
+ file, const, = @table.fetch(name)
78
+ require_relative "cli/#{file}"
79
+ Commands.const_get(const)
80
+ end
81
+
82
+ def unknown(name)
83
+ suggestions = closest(name)
84
+ @err.puts "plastic: no command named #{name.inspect}"
85
+ @err.puts "Closest: #{suggestions.join(", ")}" unless suggestions.empty?
86
+ @err.puts "Run `plastic help` for the command list."
87
+ Command::USAGE
88
+ end
89
+
90
+ def closest(name)
91
+ DidYouMean::SpellChecker.new(dictionary: @table.keys).correct(name)
92
+ end
93
+ end
94
+ end
@@ -70,15 +70,16 @@ module CodexAdapter
70
70
  # worktree, never `~/.plastic`), `--output-last-message` at the path the
71
71
  # caller names, and a bare `-` so the prompt is read from stdin (row 6.9) -
72
72
  # the node input itself never rides in this array.
73
- def build_argv(kind:, worktree:, output_last_message:)
74
- [
73
+ def build_argv(kind:, worktree:, output_last_message:, model: nil, effort: nil)
74
+ argv = [
75
75
  "codex", "exec",
76
76
  "-C", worktree.to_s,
77
77
  "--sandbox", sandbox_mode(kind),
78
78
  *add_dir_args(kind: kind, worktree: worktree),
79
- "--output-last-message", output_last_message.to_s,
80
- "-",
81
79
  ]
80
+ argv += ["--model", model.to_s] unless model.to_s.strip.empty?
81
+ argv += ["--config", %(model_reasoning_effort="#{effort}")] unless effort.to_s.strip.empty?
82
+ argv + ["--output-last-message", output_last_message.to_s, "-"]
82
83
  end
83
84
 
84
85
  # matrix row 6.23: the wall-clock bound comes from the KIND's own lease
@@ -28,7 +28,15 @@ module CompactInstructions
28
28
  # as stale, so the block states the shipped numbers and names the two keys as the
29
29
  # override instead. It names the hand-off in words and never by path, so it reads
30
30
  # correctly whether or not the hand-off writer is installed.
31
+ # The `@` line is a Claude Code import: the harness reads the named file into the
32
+ # session. It is the whole of ruling D43, that PLASTIC.md is the only instruction text
33
+ # Plastic carries. It names the installed copy under the Plastic home, because a bare
34
+ # `@PLASTIC.md` would resolve against ~/.claude, where no such file exists.
31
35
  BODY = <<~MD.freeze
36
+ Plastic runs from one command, `plastic`. Its instructions are one page, imported here:
37
+
38
+ @~/.plastic/PLASTIC.md
39
+
32
40
  Plastic watches this session's context. When the harness reports how much of the
33
41
  window is used:
34
42
 
@@ -8,6 +8,7 @@
8
8
  # heartbeat. Never the raw ledger (296 D36). No environment reads; every
9
9
  # path is injected.
10
10
 
11
+ require_relative "store_layout"
11
12
  require "time"
12
13
  require_relative "session_ledger"
13
14
  require_relative "handoff"
@@ -82,10 +83,10 @@ module DaySummary
82
83
  # The global store plus every projects/<slug>/store, each with its INDEX
83
84
  # one level up, the way doctor enumerates them.
84
85
  def stores(home)
85
- list = [[File.join(home, "INDEX.md"), File.join(home, "store")]]
86
- projects_root = File.join(home, "projects")
86
+ list = [[File.join(Plastic::StoreLayout.global_root(home), "INDEX.md"), Plastic::StoreLayout.global_store(home)]]
87
+ projects_root = Plastic::StoreLayout.projects_root(home)
87
88
  if File.directory?(projects_root)
88
- Dir.children(projects_root).sort.each do |slug|
89
+ Plastic::StoreLayout.project_slugs(home).each do |slug|
89
90
  list << [File.join(projects_root, slug, "INDEX.md"), File.join(projects_root, slug, "store")]
90
91
  end
91
92
  end
@@ -8,12 +8,13 @@
8
8
  # the store, conventions, intent and CLI halves, so Doctor stays one class with
9
9
  # one public surface and one definition of which checks are core (intent 36a).
10
10
 
11
+ require_relative "store_layout"
11
12
  require "json"
12
13
  require "yaml"
13
14
  require "time"
14
15
  require "digest"
15
- require "rubygems"
16
16
 
17
+ require_relative "version_number"
17
18
  require_relative "hook_registry"
18
19
  require_relative "compact_instructions"
19
20
 
@@ -301,7 +302,7 @@ class Doctor
301
302
  return checks
302
303
  end
303
304
 
304
- index_path = File.join(plastic_home, "INDEX.md")
305
+ index_path = File.join(Plastic::StoreLayout.global_root(plastic_home), "INDEX.md")
305
306
  if File.exist?(index_path)
306
307
  checks << check(
307
308
  category: "global_store", name: "global_index_reachable", status: "pass",
@@ -517,9 +518,6 @@ class Doctor
517
518
  checks << hooks_entries_owned_check(settings)
518
519
  end
519
520
 
520
- # skills_exist — flat, hyphen-namespaced personal skills (plastic-<name>/)
521
- checks << flat_skills_check(agent_dir, "--claude")
522
-
523
521
  # stray_skills — installed plastic-* skill dir with no manifest entry (a leftover,
524
522
  # e.g. an old-name copy after a rename; intent 158a AC15)
525
523
  checks << stray_skills_check(agent_dir, "--claude", File.join(agent_dir, "plastic", "manifest.json"))
@@ -630,24 +628,6 @@ class Doctor
630
628
  )
631
629
  end
632
630
 
633
- def flat_skills_check(agent_dir, installer_flag)
634
- skills_root = File.join(agent_dir, "skills")
635
- found = Dir.glob(File.join(skills_root, "plastic-*", "SKILL.md"))
636
-
637
- if !found.empty?
638
- check(
639
- category: "agent_registration", name: "skills_exist", status: "pass",
640
- message: "#{found.size} plastic-* skill(s) installed in #{tilde(skills_root)}"
641
- )
642
- else
643
- check(
644
- category: "agent_registration", name: "skills_exist", status: "fail",
645
- message: "No plastic-* skills found in #{tilde(skills_root)}",
646
- fixable: true, fix_hint: "Re-run the Plastic installer: npx @zalom/plastic@latest #{installer_flag}"
647
- )
648
- end
649
- end
650
-
651
631
  # Manifest-diff stray-skill check (intent 158a), extended (intent 276) to
652
632
  # never vanish on a missing manifest and to name the reserved-prefix rule.
653
633
  def stray_skills_check(agent_dir, installer_flag, manifest_path)
@@ -707,9 +687,6 @@ class Doctor
707
687
  def check_flat_skills_and_stray(agent_key, agent_dir)
708
688
  checks = []
709
689
 
710
- # For codex/hermes: just check skills exist (no settings.json hooks)
711
- checks << flat_skills_check(agent_dir, "--#{agent_key}")
712
-
713
690
  # stray_skills — installed plastic-* skill dir with no manifest entry (a leftover,
714
691
  # e.g. an old-name copy after a rename; intent 158a AC15)
715
692
  checks << stray_skills_check(agent_dir, "--#{agent_key}", File.join(agent_dir, "plastic", "manifest.json"))
@@ -1061,9 +1038,7 @@ class Doctor
1061
1038
  end
1062
1039
 
1063
1040
  def safe_version(str)
1064
- Gem::Version.new(str.to_s)
1065
- rescue ArgumentError
1066
- nil
1041
+ VersionNumber.parse(str)
1067
1042
  end
1068
1043
 
1069
1044
  def check_core_files(agent_key, include_drift: true)
@@ -1167,7 +1142,7 @@ class Doctor
1167
1142
  "#{tilde(agent_version_path)}: #{agent_version}",
1168
1143
  ],
1169
1144
  fixable: true,
1170
- fix_hint: "Re-sync the stale harness: npx @zalom/plastic@latest install --reinstall <flag>, or plastic-rollback to a prior version"
1145
+ fix_hint: "Re-sync the stale harness: npx @zalom/plastic@latest install --reinstall <flag>, or `plastic rollback` to a prior version"
1171
1146
  )
1172
1147
  end
1173
1148
  else
@@ -1175,7 +1150,7 @@ class Doctor
1175
1150
  category: "core_files", name: "version_match", status: "warn",
1176
1151
  message: "Agent-side VERSION file not found at #{tilde(agent_version_path)}",
1177
1152
  fixable: true,
1178
- fix_hint: "Re-sync the stale harness: npx @zalom/plastic@latest install --reinstall <flag>, or plastic-rollback to a prior version"
1153
+ fix_hint: "Re-sync the stale harness: npx @zalom/plastic@latest install --reinstall <flag>, or `plastic rollback` to a prior version"
1179
1154
  )
1180
1155
  end
1181
1156
  end
@@ -1280,7 +1255,7 @@ class Doctor
1280
1255
 
1281
1256
  DISPLAY_HOOK_FIX_HINT = "Re-run the Plastic installer to repair the hook registration: " \
1282
1257
  "npx @zalom/plastic@<channel> install --reinstall --claude " \
1283
- "(plastic-install --repair)".freeze
1258
+ "(plastic install --reinstall)".freeze
1284
1259
 
1285
1260
  # display_hook_registered (intent 331e, D1, category "display"): the Claude
1286
1261
  # settings carry the plastic-message-display command, on-disk, executable.
@@ -1,6 +1,7 @@
1
1
  # encoding: UTF-8
2
2
  # frozen_string_literal: true
3
3
 
4
+ require_relative "store_layout"
4
5
  require "time"
5
6
  require_relative "session_ledger"
6
7
 
@@ -38,7 +39,7 @@ module DoctorSessionLedger
38
39
  def check_session_ledger(scopes: nil, now: Time.now)
39
40
  return [] unless scopes.nil? || scopes.include?("global")
40
41
 
41
- store_dir = File.join(plastic_home, "store")
42
+ store_dir = Plastic::StoreLayout.global_store(plastic_home)
42
43
  orphans = orphaned_session_dirs(store_dir, now)
43
44
  shape = day_ledger_shape_problems(store_dir)
44
45
 
@@ -18,7 +18,7 @@ require "fileutils"
18
18
  # Trust model: this class never sends anything anywhere. `compose` returns a
19
19
  # Result carrying a local file path and a browser URL; only the human, in
20
20
  # their own authenticated browser, submits it. There is no send method here
21
- # and there must never be one (see skills/feedback/references/transport-and-privacy.md).
21
+ # and there must never be one (see SECURITY.md).
22
22
  class FeedbackReport
23
23
  GITHUB_REPO = "zalom/plastic"
24
24
  CAP_BYTES = 7500
@@ -1,6 +1,7 @@
1
1
  # encoding: UTF-8
2
2
  # frozen_string_literal: true
3
3
 
4
+ require_relative "store_layout"
4
5
  require "json"
5
6
  require "tmpdir"
6
7
  require_relative "node_ledger"
@@ -24,7 +25,7 @@ require_relative "agent_models"
24
25
  # through `RunnerPolicy.model_for(kind, config:)`, the one place that maps a
25
26
  # node's kind to the role the runner actually dispatched it against - never
26
27
  # a hand-rolled kind-to-role table, and never `AgentModels::TIER_DEFAULTS`
27
- # directly, which carries no `plastic-advisor` entry at all (that agent is a
28
+ # directly, which carries no `plastic-primary-advisor` entry at all (that agent is a
28
29
  # consultation agent, never auto-dispatched). Adds no second parser:
29
30
  # `NodeLedger` owns the transition-line format, `NodeFile` owns the kind
30
31
  # envelope and the `KIND_PREFIX` fallback, `RunnerPolicy`/`AgentModels` own
@@ -112,7 +113,8 @@ module GraphMeasureModels
112
113
  # purpose - two different silences over the same store, agreeing with
113
114
  # each other only by accident.
114
115
  def project_config_path(store_dir)
115
- File.join(File.dirname(store_dir.to_s), "config.yml")
116
+ home, slug = Plastic::StoreLayout.locate(store_dir.to_s)
117
+ File.join((slug == Plastic::StoreLayout::GLOBAL) ? home : File.dirname(store_dir.to_s), "config.yml")
116
118
  end
117
119
 
118
120
  # --- rendering ---------------------------------------------------------------
@@ -10,6 +10,8 @@
10
10
  # plain hyphen as the id/title separator on READ; every WRITE still emits the
11
11
  # real em dash (D10). The separator is built from the codepoint, not a
12
12
  # literal byte, so this file stays em-dash free.
13
+ require_relative "atomic_write"
14
+
13
15
  module IndexEntry
14
16
  module_function
15
17
 
@@ -22,6 +24,13 @@ module IndexEntry
22
24
  line.to_s.match(ENTRY_RE)
23
25
  end
24
26
 
27
+ def add_active(index_path, dir_name:, title:)
28
+ id = dir_name.split("--").first
29
+ line = "- [#{id} #{EM_DASH} #{title}](store/#{dir_name}/#{dir_name}.md)\n"
30
+ text = File.read(index_path, encoding: "UTF-8")
31
+ AtomicWrite.write(index_path, text.sub(/^## Active\n/) { |heading| heading + line })
32
+ end
33
+
25
34
  # True iff the intent is Active in its store's INDEX.md, which lives at the
26
35
  # PARENT of the store/ dir. Non-raising: any failure (missing or unreadable
27
36
  # INDEX, bad arg) returns false. `index_active_ids` is a pure-data test