@zalom/plastic 1.14.1 → 2.0.0-alpha.10

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 (213) hide show
  1. package/PLASTIC.md +101 -294
  2. package/README.md +5 -6
  3. package/agents/plastic-advisor.md +18 -17
  4. package/agents/plastic-enforcer.md +57 -69
  5. package/agents/plastic-executor.md +34 -20
  6. package/agents/plastic-faux-advisor.md +18 -18
  7. package/bin/lib/context_budget.rb +453 -0
  8. package/bin/plastic-bench +78 -0
  9. package/config_asks.yml +38 -0
  10. package/hooks/capture +4 -0
  11. package/hooks/close +5 -0
  12. package/hooks/hooks.json +14 -42
  13. package/hooks/message-display +81 -0
  14. package/hooks/record +4 -0
  15. package/hooks/savepoint +5 -5
  16. package/package.json +3 -2
  17. package/scripts/agent-report +15 -10
  18. package/scripts/append-ledger +208 -0
  19. package/scripts/codex-hook +78 -90
  20. package/scripts/dashboard.rb +43 -14
  21. package/scripts/day-summary +53 -0
  22. package/scripts/doctor.rb +269 -43
  23. package/scripts/end-intent +170 -76
  24. package/scripts/exec-worktree +11 -20
  25. package/scripts/file-session-intent +61 -0
  26. package/scripts/hook-capture +255 -0
  27. package/scripts/hook-close +36 -0
  28. package/scripts/hook-message-display +74 -0
  29. package/scripts/hook-record +157 -0
  30. package/scripts/hook-savepoint +45 -0
  31. package/scripts/hook-session-start +128 -12
  32. package/scripts/install.rb +8 -6
  33. package/scripts/intent-screen +77 -0
  34. package/scripts/lib/agent_models.rb +1 -7
  35. package/scripts/lib/arm.rb +308 -0
  36. package/scripts/lib/backfill_intent.rb +316 -0
  37. package/scripts/lib/bridge.rb +24 -1597
  38. package/scripts/lib/compact_instructions.rb +56 -0
  39. package/scripts/lib/day_summary.rb +211 -0
  40. package/scripts/lib/doctor_core.rb +66 -88
  41. package/scripts/lib/doctor_session_ledger.rb +158 -0
  42. package/scripts/lib/exec_worktree.rb +14 -60
  43. package/scripts/lib/handoff.rb +184 -0
  44. package/scripts/lib/harness_text.rb +5 -4
  45. package/scripts/lib/hook_registry.rb +57 -106
  46. package/scripts/lib/insights.rb +3 -4
  47. package/scripts/lib/installer_core.rb +136 -41
  48. package/scripts/lib/intent_screen.rb +309 -0
  49. package/scripts/lib/intent_screen_ansi.rb +262 -0
  50. package/scripts/lib/lock.rb +6 -26
  51. package/scripts/lib/message_display.rb +290 -0
  52. package/scripts/lib/outcome_guard.rb +7 -5
  53. package/scripts/lib/project_validator.rb +30 -1
  54. package/scripts/lib/report_screen.rb +648 -0
  55. package/scripts/lib/roadmap_queue.rb +3 -3
  56. package/scripts/lib/roadmap_savepoint.rb +1 -1
  57. package/scripts/lib/rule_catalog.rb +6 -3
  58. package/scripts/lib/savepoint.rb +334 -0
  59. package/scripts/lib/scaffold_intent.rb +13 -179
  60. package/scripts/lib/screen_paint.rb +276 -0
  61. package/scripts/lib/session_backfill.rb +184 -0
  62. package/scripts/lib/session_close.rb +104 -0
  63. package/scripts/lib/session_git.rb +500 -0
  64. package/scripts/lib/session_ledger.rb +621 -0
  65. package/scripts/lib/store_discovery.rb +1 -1
  66. package/scripts/lib/store_provisioning.rb +1 -1
  67. package/scripts/maintenance-run +7 -7
  68. package/scripts/new-intent +63 -4
  69. package/scripts/plastic-lock +101 -41
  70. package/scripts/promote-session-item +150 -0
  71. package/scripts/read-config +3 -0
  72. package/scripts/rebuild-graph +1 -1
  73. package/scripts/report-screen +120 -0
  74. package/scripts/roadmap-next +2 -2
  75. package/scripts/rollback.rb +48 -3
  76. package/scripts/savepoint-note +67 -0
  77. package/scripts/scaffold-intent +37 -63
  78. package/scripts/session-commit +116 -0
  79. package/scripts/spawn-preamble +14 -7
  80. package/scripts/update.rb +7 -3
  81. package/scripts/write-handoff +60 -0
  82. package/skills/agent-advisor/SKILL.md +3 -3
  83. package/skills/agent-advisor/references/advisor-protocol.md +20 -20
  84. package/skills/auto/SKILL.md +223 -317
  85. package/skills/auto/evals/evals.json +10 -10
  86. package/skills/auto/references/agent-architecture.md +102 -90
  87. package/skills/auto/references/agent-report-contract.md +4 -21
  88. package/skills/auto/references/end-tail.md +47 -53
  89. package/skills/auto/references/human-report-contract.md +62 -56
  90. package/skills/conventions/SKILL.md +1 -3
  91. package/skills/conventions/references/lifecycle-and-savepoints.md +35 -1
  92. package/skills/conventions/references/locks-and-worktrees.md +62 -58
  93. package/skills/conventions/references/maintenance-and-revisions.md +12 -12
  94. package/skills/dashboard/SKILL.md +1 -1
  95. package/skills/direct/SKILL.md +66 -0
  96. package/skills/direct/references/request-signals.md +59 -0
  97. package/skills/doctor/SKILL.md +58 -11
  98. package/skills/doctor/report.md +3 -1
  99. package/skills/install/SKILL.md +11 -9
  100. package/skills/intent-continuing/SKILL.md +142 -91
  101. package/skills/intent-continuing/references/boarding-matrix.md +34 -0
  102. package/skills/intent-continuing/references/context-management.md +3 -3
  103. package/skills/intent-creating/SKILL.md +2 -2
  104. package/skills/intent-creating/references/lifecycle.md +1 -1
  105. package/skills/intent-ending/SKILL.md +34 -37
  106. package/skills/intent-ending/evals/evals.json +4 -4
  107. package/skills/intent-executing/SKILL.md +15 -46
  108. package/skills/intent-executing/plan-reviewer-prompt.md +39 -0
  109. package/skills/intent-speccing/SKILL.md +108 -51
  110. package/skills/intent-speccing/evals/evals.json +5 -5
  111. package/skills/intent-speccing/references/per-section-fill-rules.md +4 -4
  112. package/skills/intent-speccing/references/self-verify-checklist.md +1 -2
  113. package/skills/project-creating/SKILL.md +1 -1
  114. package/skills/releasing/SKILL.md +7 -8
  115. package/skills/tutorial/SKILL.md +2 -2
  116. package/skills/tutorial/references/track-1-guided.md +16 -18
  117. package/skills/tutorial/references/track-2-auto.md +12 -13
  118. package/skills/tutorial/references/track-3-projects-and-roadmaps.md +2 -2
  119. package/templates/agents.md +4 -7
  120. package/templates/config.yml +5 -0
  121. package/templates/intent-screen.md +17 -0
  122. package/templates/outcome.md +14 -1
  123. package/templates/project.yml +7 -0
  124. package/templates/report-state.md +11 -0
  125. package/templates/roadmap.md +1 -1
  126. package/templates/savepoint.md +2 -2
  127. package/templates/session-intent.md +29 -0
  128. package/agents/plastic-brainstorming.md +0 -48
  129. package/agents/plastic-future-intent-researcher.md +0 -35
  130. package/agents/plastic-intent-curator.md +0 -47
  131. package/agents/plastic-intent-discovery.md +0 -43
  132. package/agents/plastic-planner.md +0 -56
  133. package/agents/plastic-spec-specialist.md +0 -53
  134. package/hooks/auto-arm +0 -5
  135. package/hooks/bash-gate +0 -3
  136. package/hooks/continue +0 -31
  137. package/hooks/edit-gates +0 -3
  138. package/hooks/future-intent-check +0 -25
  139. package/hooks/gate-check +0 -12
  140. package/hooks/power-tools +0 -8
  141. package/scripts/hook-auto-arm +0 -51
  142. package/scripts/hook-bash-gate +0 -78
  143. package/scripts/hook-code-gate +0 -38
  144. package/scripts/hook-continue +0 -48
  145. package/scripts/hook-create-gate +0 -51
  146. package/scripts/hook-edit-gates +0 -58
  147. package/scripts/hook-future-intent-check +0 -90
  148. package/scripts/hook-gate-check +0 -169
  149. package/scripts/hook-links-gate +0 -54
  150. package/scripts/hook-lock-gate +0 -47
  151. package/scripts/hook-power-tools +0 -38
  152. package/scripts/hook-savepoint-pre +0 -32
  153. package/scripts/lib/codex_edit_gates.rb +0 -138
  154. package/scripts/lib/edit_gates.rb +0 -398
  155. package/scripts/lib/links_gate.rb +0 -140
  156. package/scripts/lib/qmd_hook.rb +0 -41
  157. package/scripts/lib/spec_header.rb +0 -83
  158. package/scripts/lib/start_intent.rb +0 -296
  159. package/scripts/start-intent +0 -89
  160. package/skills/_active-intent-gate.md +0 -26
  161. package/skills/auto/references/tiers.md +0 -100
  162. package/skills/continuing/SKILL.md +0 -34
  163. package/skills/continuing/evals/evals.json +0 -91
  164. package/skills/conventions/references/gates-and-enforcement.md +0 -53
  165. package/skills/conventions/references/tiers-and-dispatch.md +0 -135
  166. package/skills/doctor/references/gates-stuck-detection.md +0 -43
  167. package/skills/intent-brainstorming/SKILL.md +0 -118
  168. package/skills/intent-brainstorming/evals/evals.json +0 -67
  169. package/skills/intent-continuing/evals/evals.json +0 -145
  170. package/skills/intent-discovering/SKILL.md +0 -56
  171. package/skills/intent-grilling/SKILL.md +0 -108
  172. package/skills/intent-linking/SKILL.md +0 -128
  173. package/skills/intent-linking/evals/evals.json +0 -22
  174. package/skills/intent-linking/references/zettelkasten.md +0 -45
  175. package/skills/intent-locking/SKILL.md +0 -64
  176. package/skills/intent-planning/SKILL.md +0 -145
  177. package/skills/intent-planning/evals/evals.json +0 -81
  178. package/skills/intent-planning/references/plan-format.md +0 -130
  179. package/skills/intent-researching/SKILL.md +0 -123
  180. package/skills/intent-researching/evals/evals.json +0 -22
  181. package/skills/intent-savepoint/SKILL.md +0 -83
  182. package/skills/intent-savepoint/references/context-management.md +0 -32
  183. package/skills/intent-starting/SKILL.md +0 -151
  184. package/skills/intent-starting/evals/evals.json +0 -117
  185. package/skills/intent-starting/references/boarding-matrix.md +0 -35
  186. package/skills/project-continuing/SKILL.md +0 -119
  187. package/skills/project-continuing/evals/evals.json +0 -100
  188. package/skills/roadmap-continuing/SKILL.md +0 -89
  189. package/skills/roadmap-continuing/evals/evals.json +0 -82
  190. package/skills/skill-creating/SKILL.md +0 -75
  191. package/skills/skill-creating/evals/evals.json +0 -108
  192. package/skills/skill-creating/references/agents.md +0 -168
  193. package/skills/skill-creating/references/defaults-first.md +0 -23
  194. package/skills/skill-creating/references/evals.md +0 -41
  195. package/skills/skill-creating/references/hooks.md +0 -251
  196. package/skills/skill-creating/references/progressive-disclosure.md +0 -176
  197. package/skills/skill-creating/references/scripts.md +0 -166
  198. package/skills/skill-creating/references/skills.md +0 -169
  199. package/skills/skill-creating/scripts/scaffold.rb +0 -313
  200. package/skills/skill-evaluating/SKILL.md +0 -141
  201. package/skills/skill-evaluating/assets/eval-template.json +0 -12
  202. package/skills/skill-evaluating/evals/evals.json +0 -75
  203. package/skills/skill-evaluating/references/convention-checks.md +0 -76
  204. package/skills/skill-evaluating/references/eval-methodology.md +0 -154
  205. package/skills/store-curating/SKILL.md +0 -64
  206. package/skills/store-curating/evals/evals.json +0 -38
  207. package/skills/store-indexing/SKILL.md +0 -93
  208. package/skills/store-indexing/evals/evals.json +0 -22
  209. package/skills/store-indexing/references/zettelkasten-linking.md +0 -32
  210. package/skills/store-provisioning/SKILL.md +0 -55
  211. /package/skills/{project-continuing → intent-continuing}/references/board-fill.md +0 -0
  212. /package/skills/{roadmap-continuing → intent-continuing}/references/liveness-ranking.md +0 -0
  213. /package/skills/{intent-brainstorming → intent-speccing}/references/design-principles.md +0 -0
@@ -25,7 +25,7 @@ require "json"
25
25
  require "yaml"
26
26
  require "date"
27
27
  require_relative "doctor"
28
- require_relative "lib/bridge"
28
+ require_relative "lib/savepoint"
29
29
  require_relative "lib/lock"
30
30
 
31
31
  PLASTIC_HOME = ENV.fetch("PLASTIC_HOME") { File.join(Dir.home, ".plastic") }
@@ -36,7 +36,7 @@ def today
36
36
  end
37
37
 
38
38
  # A generic "about a month" threshold, not tuned to any one store's item count.
39
- # Deliberately independent from plastic-project-continuing's separate stale_threshold_days
39
+ # Deliberately independent from plastic-intent-continuing's separate stale_threshold_days
40
40
  # config: that one is a proactive boot-time triage nudge, this is a board annotation.
41
41
  # Unifying the two is a follow-up, not this intent.
42
42
  STALE_DAYS = 30
@@ -56,13 +56,26 @@ rescue StandardError
56
56
  nil
57
57
  end
58
58
 
59
- # Returns the set of intent ids listed under a given INDEX.md section.
59
+ # The link form's id: "- [id](path)...". The class excludes "[" (as well as
60
+ # "]" and whitespace) so this can never match a wikilink line's OWN opening
61
+ # bracket and key it as "[71" (row F, spec 315b): "- [[71]] ..." fails this
62
+ # pattern outright (the character right after "- [" is itself "[", which the
63
+ # class disallows), leaving it to WIKILINK_ID_RE below.
64
+ LINK_ID_RE = /^- \[([^\[\]\s]+)/
65
+
66
+ # The wikilink form's id: "- [[id]] name (em dash) description (date; ...)",
67
+ # the shape mihradesign's INDEX.md and others use. Bare id, no brackets.
68
+ WIKILINK_ID_RE = /^- \[\[([^\[\]]+)\]\]/
69
+
70
+ # Returns the set of intent ids listed under a given INDEX.md section, link
71
+ # form and wikilink form alike (row F5: Active, Abandoned, Completed, and a
72
+ # store's Future section can all mix both forms).
60
73
  def index_section_ids(index_path, header)
61
74
  return [] unless File.exist?(index_path)
62
75
  body = File.read(index_path)
63
76
  seg = body[/^#{Regexp.escape(header)}\s*\n(.*?)(?=^## |\z)/m, 1]
64
77
  return [] unless seg
65
- seg.scan(/^- \[([^\]\s]+)/).flatten
78
+ seg.scan(LINK_ID_RE).flatten + seg.scan(WIKILINK_ID_RE).flatten
66
79
  end
67
80
 
68
81
  # Bug found at intent 202's gate review: the date used to be anchored to the END of the
@@ -77,21 +90,37 @@ end
77
90
  # (end-intent's own Bridge.index_entry_match accepts either on read). Because regex
78
91
  # alternation is leftmost-first, this only ever matches the date immediately after the
79
92
  # link. It never continues scanning into the note prose, so a second date mentioned
80
- # later in a note's free text cannot be mistaken for the completion date.
81
- COMPLETION_DATE_RE = /^- \[([^\]\s]+).*?\)\s*[\u2014-]\s*(\d{4}-\d{2}-\d{2})\b/
93
+ # later in a note's free text cannot be mistaken for the completion date. The id class
94
+ # excludes "[" (row F) so this can never fire on a wikilink line's own opening bracket.
95
+ COMPLETION_DATE_RE = /^- \[([^\[\]\s]+).*?\)\s*[\u2014-]\s*(\d{4}-\d{2}-\d{2})\b/
96
+
97
+ # The wikilink form's completion date: "- [[id]] name (em dash) description
98
+ # (date; other notes)". Real shape (mihradesign's INDEX.md): the date is the
99
+ # first thing inside the entry's trailing parenthetical. A SEPARATE regex
100
+ # from COMPLETION_DATE_RE (row F review finding), not one four-group
101
+ # alternation: a four-group `scan` breaks `String#scan(...).to_h`, and a bare
102
+ # `\(` alternative on the link form would harvest a date out of note prose on
103
+ # an entry with no canonical date of its own.
104
+ WIKILINK_COMPLETION_DATE_RE = /^- \[\[([^\[\]]+)\]\].*?\((\d{4}-\d{2}-\d{2})\b/
82
105
 
83
106
  # Map of intent id -> completion date string, parsed from the "## Completed" section
84
- # (lines like "- [12 (em dash) title](link) (em dash) 2026-06-10 optional note text").
85
- # Deterministic, content-derived. Observability: a populated "## Completed" section that
86
- # yields not one single dated entry is a parser regression, not a legitimately empty
87
- # result, so it is surfaced with a stderr warning rather than rotting invisibly (the same
88
- # silent-failure class intent 202's gate review caught this file already committing).
107
+ # (lines like "- [12 (em dash) title](link) (em dash) 2026-06-10 optional note text",
108
+ # or the wikilink form "- [[12]] title (em dash) description (2026-06-10; notes)").
109
+ # Deterministic, content-derived. Two regexes scanned separately and merged into one
110
+ # hash (row F), so each form's own matching rules stay independent: the wikilink
111
+ # alternative can never steal a date out of a link-form entry's note prose, because it
112
+ # never even looks at a link-form line (its "- [[" anchor cannot match a line whose
113
+ # second character is not itself "["). Observability: a populated "## Completed"
114
+ # section that yields not one single dated entry is a parser regression, not a
115
+ # legitimately empty result, so it is surfaced with a stderr warning rather than
116
+ # rotting invisibly (the same silent-failure class intent 202's gate review caught this
117
+ # file already committing).
89
118
  def completion_dates(index_path)
90
119
  return {} unless File.exist?(index_path)
91
120
  body = File.read(index_path)
92
121
  seg = body[/^## Completed\s*\n(.*?)(?=^## |\z)/m, 1] || ""
93
122
  entry_count = seg.scan(/^- \[/).size
94
- dates = seg.scan(COMPLETION_DATE_RE).to_h
123
+ dates = seg.scan(COMPLETION_DATE_RE).to_h.merge(seg.scan(WIKILINK_COMPLETION_DATE_RE).to_h)
95
124
  if entry_count.positive? && dates.empty?
96
125
  warn "dashboard: completion_dates parsed 0/#{entry_count} dates from the " \
97
126
  "\"## Completed\" section of #{index_path}; treat this as a parser regression, " \
@@ -163,7 +192,7 @@ end
163
192
 
164
193
  # True iff the savepoint ledger's last non-blank line shows real post-birth
165
194
  # activity, not just the one-line birth stamp every intent gets at creation
166
- # (scripts/new-intent's Bridge.append_savepoint call, stage "What"). Reads the
195
+ # (scripts/new-intent's Savepoint.append_savepoint call, stage "What"). Reads the
167
196
  # last line, extracts the stage token (second whitespace-separated field, same
168
197
  # ledger shape last_accessed_at already parses), and treats any stage other
169
198
  # than "What" as progress. Returns false when the file is missing/empty.
@@ -192,7 +221,7 @@ def parse_intent(store_info, dir_name, status_index)
192
221
  # Sentinel-aware presence for lifecycle files (intent 60b): a scaffolded
193
222
  # placeholder spec/plan/checklist/outcome reads as absent, so a freshly
194
223
  # scaffolded intent reports What/Why and is never marked completed/advanced.
195
- real = ->(f) { Bridge.stage_file_present?(File.join(dir, f)) }
224
+ real = ->(f) { Savepoint.stage_file_present?(File.join(dir, f)) }
196
225
  body = File.exist?(md) ? File.read(md) : ""
197
226
 
198
227
  status =
@@ -0,0 +1,53 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: UTF-8
3
+ # frozen_string_literal: true
4
+
5
+ # day-summary (intent 311): print the block SessionStart injects at boot
6
+ # (open items, the last five done, live auto intents, other active
7
+ # sessions). Prints nothing when there is nothing to say.
8
+ #
9
+ # Usage:
10
+ # day-summary [--store <dir>] [--day <YYYYMMDD>] [--session <id>] [--home <dir>]
11
+ #
12
+ # Defaults: the home is $PLASTIC_HOME (~/.plastic), the store is <home>/store,
13
+ # the day is today (local wall clock), the session is $CLAUDE_CODE_SESSION_ID.
14
+ #
15
+ # Exit codes: 0 done; 2 usage error.
16
+
17
+ require_relative "lib/session_ledger"
18
+ require_relative "lib/day_summary"
19
+
20
+ def usage_abort(message)
21
+ warn "day-summary: #{message}"
22
+ exit 2
23
+ end
24
+
25
+ def expand(path)
26
+ File.expand_path(path.to_s.sub(/\A~/, Dir.home))
27
+ end
28
+
29
+ def parse_args(argv)
30
+ opts = {}
31
+ i = 0
32
+ while i < argv.length
33
+ flag = argv[i]
34
+ usage_abort("unknown argument #{flag.inspect}") unless flag.start_with?("--")
35
+ usage_abort("#{flag} requires a value") if i + 1 >= argv.length
36
+ key = flag.delete_prefix("--").to_sym
37
+ usage_abort("unknown flag #{flag.inspect}") unless %i[store day session home].include?(key)
38
+ opts[key] = argv[i + 1]
39
+ i += 2
40
+ end
41
+ opts
42
+ end
43
+
44
+ opts = parse_args(ARGV)
45
+ home = opts[:home] ? expand(opts[:home]) : expand(ENV.fetch("PLASTIC_HOME", "~/.plastic"))
46
+ store = opts[:store] ? expand(opts[:store]) : File.join(home, "store")
47
+ day = opts[:day] || SessionLedger.day_id
48
+ usage_abort("--day must be eight digits parsing as a real date, got #{day.inspect}") unless SessionLedger.valid_day_id?(day)
49
+ session = SessionLedger.short_session_id(opts[:session], ENV["CLAUDE_CODE_SESSION_ID"])
50
+
51
+ text = DaySummary.build(store: store, day: day, session: session, home: home)
52
+ puts text unless text.empty?
53
+ exit 0