@zalom/plastic 2.0.0-alpha.17 → 2.0.0-alpha.18

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zalom/plastic",
3
- "version": "2.0.0-alpha.17",
3
+ "version": "2.0.0-alpha.18",
4
4
  "description": "Intent-driven idea development system for AI coding agents",
5
5
  "type": "module",
6
6
  "bin": {
@@ -5,12 +5,11 @@
5
5
  # Usage: hook-capture (reads the UserPromptSubmit stdin JSON payload)
6
6
  # Intent 298. One UserPromptSubmit process replacing hook-continue,
7
7
  # hook-future-intent-check, and hook-auto-arm: it appends a pending line to
8
- # the session day ledger, detects "continue" and "auto" prompts, and hints at
9
- # matching Future intents. Every job runs in its own rescue and the hook
10
- # always exits 0 (spec D2).
8
+ # the session day ledger and detects "continue" and "auto" prompts. Every job
9
+ # runs in its own rescue and the hook always exits 0 (spec D2). Intent 345
10
+ # (D7, 323) removed the per-prompt Future-intent hint step entirely.
11
11
 
12
12
  require "json"
13
- require "yaml"
14
13
  require "open3"
15
14
  require "fileutils"
16
15
  require_relative "lib/session_ledger"
@@ -42,87 +41,6 @@ templates = File.expand_path("../templates", __dir__)
42
41
  sid = SessionLedger.short_session_id(nil, session_id)
43
42
  today = SessionLedger.day_id
44
43
 
45
- # --- Extracted matching logic, shared by both the global and project store
46
- # passes of job (f) below (mirrors hook-future-intent-check verbatim). ---
47
- def future_intent_matches(store_root, message)
48
- index_path = File.join(store_root, "INDEX.md")
49
- return [] unless File.exist?(index_path)
50
-
51
- lines = File.readlines(index_path)
52
- future_dirs = []
53
- section = nil
54
-
55
- lines.each do |line|
56
- section = :future if line.start_with?("## Future")
57
- section = nil if line.start_with?("## ") && !line.start_with?("## Future")
58
- next unless section == :future && line.strip.start_with?("- [")
59
-
60
- future_dirs << $1 if line =~ /store\/([\w-]+)\//
61
- end
62
- return [] if future_dirs.empty?
63
-
64
- matches = []
65
- message_words = message.split(/\W+/).reject { |w| w.length < 4 }
66
-
67
- future_dirs.each do |dir|
68
- intent_path = File.join(store_root, "store", dir, "#{dir}.md")
69
- next unless File.exist?(intent_path)
70
-
71
- content = File.read(intent_path)
72
-
73
- tags = []
74
- tags = $1.split(",").map(&:strip).map(&:downcase) if content =~ /^tags:\s*\[([^\]]+)\]/
75
-
76
- intent_name = ""
77
- intent_name = $1.downcase if content =~ /^intent:\s*["']?(.+?)["']?\s*$/
78
-
79
- keywords = (tags + intent_name.split(/\W+/).reject { |w| w.length < 4 }).map(&:downcase).uniq
80
-
81
- matched_keywords = keywords.select { |kw| message.include?(kw) }
82
- name_matches = message_words.select { |w| intent_name.include?(w) }
83
- matched_keywords = (matched_keywords + name_matches).uniq
84
-
85
- next if matched_keywords.empty?
86
-
87
- index_line = lines.find { |l| l.include?(dir) }&.strip || "#{dir} - #{intent_name}"
88
- matches << { "index_line" => index_line, "keywords" => matched_keywords }
89
- end
90
- matches
91
- end
92
-
93
- # The store_root that carries the current project's own store, resolved from
94
- # cwd through projects.yml, mirroring SessionLedger.project_slug's matching
95
- # but returning nil (not "global") when nothing matches, since there is then
96
- # no distinct second store to hint against.
97
- def resolve_project_store_root(cwd, plastic_home)
98
- projects_path = File.join(plastic_home, "projects.yml")
99
- return nil unless File.exist?(projects_path)
100
-
101
- data = begin
102
- YAML.safe_load(File.read(projects_path))
103
- rescue StandardError
104
- nil
105
- end
106
- data = {} unless data.is_a?(Hash)
107
- projects = data["projects"].is_a?(Hash) ? data["projects"] : {}
108
- expanded_cwd = File.expand_path(cwd)
109
-
110
- matches = projects.filter_map do |slug, info|
111
- next unless info.is_a?(Hash) && slug.is_a?(String)
112
-
113
- path = info["path"]
114
- next unless path
115
-
116
- root = File.expand_path(path)
117
- next unless expanded_cwd == root || expanded_cwd.start_with?("#{root}#{File::SEPARATOR}")
118
-
119
- [root.length, slug]
120
- end
121
-
122
- best = matches.max_by { |(length, _slug)| length }
123
- best ? File.join(plastic_home, "projects", best[1]) : nil
124
- end
125
-
126
44
  def truncate(text, max)
127
45
  return text if text.length <= max
128
46
 
@@ -183,7 +101,7 @@ system_message = nil
183
101
 
184
102
  # --- (d) "continue" cockpit -------------------------------------------------
185
103
  begin
186
- if prompt.match?(/\bcontinue\b/i)
104
+ if prompt.to_s.strip.downcase == "continue"
187
105
  dashboard = File.expand_path("dashboard.rb", __dir__)
188
106
  if File.exist?(dashboard)
189
107
  cockpit, _err, status = Open3.capture3({ "RUBYOPT" => nil }, "ruby", dashboard, "continue")
@@ -224,25 +142,6 @@ rescue StandardError
224
142
  nil
225
143
  end
226
144
 
227
- # --- (f) Future-intent hint, global store then the project's own store -----
228
- begin
229
- message = prompt.to_s.downcase
230
- if message.strip.length >= 10 && message.strip != "continue"
231
- matches = future_intent_matches(plastic_home, message)
232
- project_root = resolve_project_store_root(cwd, plastic_home)
233
- matches += future_intent_matches(project_root, message) if project_root
234
-
235
- if matches.any?
236
- parts = ["PLASTIC - Future intents related to this message:\n"]
237
- matches.each { |m| parts << "#{m["index_line"]} (matched: #{m["keywords"].join(", ")})" }
238
- parts << "\nConsider asking the user if they want to activate any of these, or note the connection."
239
- context_parts << parts.join("\n")
240
- end
241
- end
242
- rescue StandardError
243
- nil
244
- end
245
-
246
145
  exit 0 if context_parts.empty?
247
146
 
248
147
  payload_out = {