@zalom/plastic 1.0.0-alpha.36 → 1.0.0-alpha.37

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": "1.0.0-alpha.36",
3
+ "version": "1.0.0-alpha.37",
4
4
  "description": "Intent-driven idea development system for AI coding agents",
5
5
  "type": "module",
6
6
  "bin": {
@@ -10,6 +10,14 @@ require "digest"
10
10
  module Bridge
11
11
  STAGES = %w[what why how exec done].freeze
12
12
 
13
+ # Stale-bridge purge window (intent 67). The bridge file is ephemeral
14
+ # live-session gate state, NOT a continuation source: an intent is resumed from
15
+ # its savepoint.md ledger, never from a /tmp bridge. So any bridge older than
16
+ # this window is dead weight and safe to purge, regardless of arm state. No
17
+ # real session stays live for two days, so a 48h cutoff never removes a bridge
18
+ # an active run depends on.
19
+ PURGE_AGE_SECONDS = 48 * 3600 # 48 hours
20
+
13
21
  def self.intent_file(intent_dir)
14
22
  dir_name = File.basename(intent_dir)
15
23
  "#{intent_dir}/#{dir_name}.md"
@@ -106,6 +114,40 @@ module Bridge
106
114
  pool.max_by { |c| c[:mtime] }&.fetch(:data)
107
115
  end
108
116
 
117
+ # --- Stale-bridge purge (intent 67) ---------------------------------------
118
+ #
119
+ # Remove stale tmp/plastic-*.json bridge files so discover_bridge's per-fire
120
+ # scan stays bounded. Best-effort and non-raising: returns the array of removed
121
+ # paths. Continuation does not depend on these files (an intent resumes from its
122
+ # savepoint.md ledger), so the only safety rule is age: a bridge older than
123
+ # max_age_seconds is purged regardless of arm state, while anything newer is kept
124
+ # (it may be a live run). The current session's own bridge is never purged
125
+ # (preserves the disarm_auto contract that it stays readable). Wired into
126
+ # arm_auto and disarm_auto so both manual and auto delivery keep the temp dir
127
+ # clean.
128
+ def self.purge_stale_bridges(session:, now: Time.now, max_age_seconds: PURGE_AGE_SECONDS,
129
+ tmp: tmp_dir)
130
+ current = path(session, tmp: tmp)
131
+ removed = []
132
+ Dir.glob(File.join(tmp, "plastic-*.json")).each do |f|
133
+ next if f == current
134
+ begin
135
+ next if (now - File.mtime(f)) < max_age_seconds
136
+ File.delete(f)
137
+ removed << f
138
+ rescue Errno::ENOENT
139
+ # Raced with another job that already removed it; count as purged.
140
+ removed << f
141
+ rescue => e
142
+ $stderr.puts "plastic: purge skipped #{f}: #{e.message}"
143
+ end
144
+ end
145
+ removed
146
+ rescue => e
147
+ $stderr.puts "plastic: purge_stale_bridges failed: #{e.message}"
148
+ removed || []
149
+ end
150
+
109
151
  def self.read(session, tmp: tmp_dir)
110
152
  p = path(session, tmp: tmp)
111
153
  return nil unless File.exist?(p)
@@ -323,6 +365,7 @@ module Bridge
323
365
  data = derive(key, intent_id: intent_id, intent_dir: intent_dir, store: store, name: name)
324
366
  data["build"]["auto"] = true
325
367
  write(key, data)
368
+ purge_stale_bridges(session: key)
326
369
  data
327
370
  end
328
371
 
@@ -333,6 +376,7 @@ module Bridge
333
376
  data["build"] ||= {}
334
377
  data["build"]["auto"] = false
335
378
  write(session, data)
379
+ purge_stale_bridges(session: session)
336
380
  data
337
381
  end
338
382
 
@@ -194,6 +194,8 @@ During initial project creation, all decisions are non-destructive by definition
194
194
  ```bash
195
195
  ruby -r ~/.plastic/scripts/lib/bridge -e 'Bridge.disarm_auto(ENV["CLAUDE_SESSION_ID"])'
196
196
  ```
197
+ Disarming also purges stale bridge files from the temp directory automatically (it keeps the
198
+ current bridge and any live run), so no manual `/tmp` cleanup is needed.
197
199
  10. Notify user: "Intent [ID] — [name] delivered. [1-2 sentence summary]. See outcome.md for details."
198
200
 
199
201
  ## Error Handling