@zalom/plastic 1.0.0-beta.6 → 1.0.0-beta.8

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.
@@ -18,20 +18,20 @@ You are the Plastic Intent Curator. Your role is to maintain the health and navi
18
18
 
19
19
  ## Your Responsibilities
20
20
 
21
- 1. **Intent lifecycle management** — move intents between Active/Future/Completed in INDEX.md, fill in `## Outcome` sections
22
- 2. **INDEX.md maintenance** — keep Active/Future/Clusters/Completed sections accurate and well-organized
21
+ 1. **Intent lifecycle management** — move intents between Active/Future/Completed/Abandoned in INDEX.md, fill in `## Outcome` sections (including the abandonment rationale when an intent is abandoned)
22
+ 2. **INDEX.md maintenance** — keep Active/Future/Clusters/Completed/Abandoned sections accurate and well-organized
23
23
  3. **Link discovery** — suggest connections between intents that share topics but aren't linked
24
24
  4. **Cluster management** — create new clusters when 3+ unlinked intents share tags, merge or rename clusters as topics evolve
25
25
  5. **Orphan detection** — flag intents with no links and no cluster membership
26
26
 
27
27
  ## How You Work
28
28
 
29
- 0. QMD-first (when available): when you need to locate a specific intent (to reclassify, link, or cluster it) rather than rebuild the whole landscape, before scanning the store with grep/Read run `ruby ~/.plastic/scripts/qmd-sync search "<terms>"` to surface candidate or related intents, then open the authoritative intent file for any hit you act on. The command is a no-op when QMD is absent, so fall back to the full scan below. (This is discovery; the reindex step at completion is separate.)
29
+ 0. QMD-first (when available): when you need to locate a specific intent (to reclassify, link, or cluster it) rather than rebuild the whole landscape, before scanning the store with grep/Read run `ruby ~/.plastic/scripts/qmd-sync search "<terms>"` to surface candidate or related intents, then open the authoritative intent file for any hit you act on. The command is a no-op when QMD is absent, so fall back to the full scan below. (This is discovery; the reindex step at a terminal-state transition is separate.)
30
30
  1. Scan `~/.plastic/store/*/ID--slug.md` (or project store) to understand the full intent landscape
31
31
  2. Read `~/.plastic/INDEX.md` (or project INDEX.md) to understand current organization
32
- 3. Compare: are there intents not in any cluster? Missing from Active/Completed? Status mismatches?
32
+ 3. Compare: are there intents not in any cluster? Missing from Active/Completed/Abandoned? Status mismatches?
33
33
  4. Make targeted edits to INDEX.md and intent frontmatter/links
34
- 5. On completion: whenever you move an intent to Completed, refresh the QMD index for that store so the new outcome is searchable. This is mandatory on completion and a no-op when QMD is absent, and it runs in the background so it never blocks: `ruby ~/.plastic/scripts/qmd-sync reindex --store <store-root> --async`
34
+ 5. On a terminal-state transition: whenever you move an intent to Completed OR Abandoned, refresh the QMD index for that store so the new outcome (or abandonment rationale) is searchable. This is mandatory on any terminal-state move and a no-op when QMD is absent, and it runs in the background so it never blocks: `ruby ~/.plastic/scripts/qmd-sync reindex --store <store-root> --async`
35
35
  6. Report what you changed
36
36
 
37
37
  ## Constraints
package/hooks/statusline CHANGED
@@ -84,9 +84,34 @@ else
84
84
  fi
85
85
  INDEX_DIR=$(dirname "$INDEX")
86
86
 
87
- # --- Most-recently-accessed active intent (mirror dashboard: last savepoint ts) ---
87
+ # --- Current-session work-unit: the live bridge wins over savepoint recency ---
88
+ # The statusline receives the real session_id on stdin; the session's bridge
89
+ # (plastic-{session_id}.json) is the authoritative "what THIS session is driving".
90
+ # This beats the shared, savepoint-recency heuristic so parallel sessions on one
91
+ # store no longer overwrite each other's line. grep/sed only - no jq, no ruby.
88
92
  WORK=""
89
- if [ -f "$INDEX" ]; then
93
+ SID=$(json_str "session_id")
94
+ if [ -n "$SID" ]; then
95
+ BRIDGE="${PLASTIC_TMP:-/tmp}/plastic-${SID}.json"
96
+ if [ -f "$BRIDGE" ]; then
97
+ # Bridge JSON is pretty-printed (one field per line). Scope extraction to the
98
+ # "intent" object so a sibling top-level "id"/"name" can never win (the intent
99
+ # object holds only string fields, so the first "}" closes it). grep/sed only.
100
+ INTENT_BLOCK=$(sed -n '/"intent"[[:space:]]*:[[:space:]]*{/,/}/p' "$BRIDGE" 2>/dev/null)
101
+ B_ID=$(printf '%s\n' "$INTENT_BLOCK" | grep -o '"id"[[:space:]]*:[[:space:]]*"[^"]*"' | head -1 \
102
+ | sed 's/.*"id"[[:space:]]*:[[:space:]]*"//;s/"$//')
103
+ B_NAME=$(printf '%s\n' "$INTENT_BLOCK" | grep -o '"name"[[:space:]]*:[[:space:]]*"[^"]*"' | head -1 \
104
+ | sed 's/.*"name"[[:space:]]*:[[:space:]]*"//;s/"$//')
105
+ if [ -n "$B_ID" ] && [ -n "$B_NAME" ]; then
106
+ EMDASH=$'\342\200\224'
107
+ WORK="${B_ID} ${EMDASH} ${B_NAME}"
108
+ fi
109
+ fi
110
+ fi
111
+
112
+ # --- Most-recently-accessed active intent (mirror dashboard: last savepoint ts) ---
113
+ # Fallback only: runs when no session bridge resolved a work-unit above.
114
+ if [ -z "$WORK" ] && [ -f "$INDEX" ]; then
90
115
  BEST_TS=""
91
116
  while IFS= read -r line; do
92
117
  [ -z "$line" ] && continue
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zalom/plastic",
3
- "version": "1.0.0-beta.6",
3
+ "version": "1.0.0-beta.8",
4
4
  "description": "Intent-driven idea development system for AI coding agents",
5
5
  "type": "module",
6
6
  "bin": {
@@ -58,11 +58,20 @@ module Bridge
58
58
  end
59
59
 
60
60
  # Resolve a bridge session: first non-empty of explicit, CLAUDE_SESSION_ID,
61
- # then a derived key. Never returns nil/empty. Whitespace-only counts as empty.
61
+ # CLAUDE_CODE_SESSION_ID, then a derived key. Never returns nil/empty.
62
+ # Whitespace-only counts as empty.
63
+ #
64
+ # The CLAUDE_CODE_SESSION_ID fallback (intent 79) is additive: it only changes
65
+ # behavior when CLAUDE_SESSION_ID is blank but CLAUDE_CODE_SESSION_ID is set —
66
+ # the bg/headless case where the real session id lives in CLAUDE_CODE_SESSION_ID.
67
+ # Keying by the real id (instead of a derived hash) lets the statusline, which
68
+ # receives that same id on stdin, find the bridge by direct filename lookup.
62
69
  def self.resolve_session(explicit, intent_id:, store:)
63
70
  return explicit.to_s.strip unless blank?(explicit)
64
71
  env = ENV["CLAUDE_SESSION_ID"]
65
72
  return env.to_s.strip unless blank?(env)
73
+ code_env = ENV["CLAUDE_CODE_SESSION_ID"]
74
+ return code_env.to_s.strip unless blank?(code_env)
66
75
  derive_key(store, intent_id)
67
76
  end
68
77
 
@@ -386,7 +395,7 @@ module Bridge
386
395
  # (mid-session intent creation). Re-derives intent state, then sets build.auto.
387
396
  def self.arm_auto(session, intent_id:, intent_dir:, store:, name:)
388
397
  key = resolve_session(session, intent_id: intent_id, store: store)
389
- if blank?(session) && blank?(ENV["CLAUDE_SESSION_ID"])
398
+ if blank?(session) && blank?(ENV["CLAUDE_SESSION_ID"]) && blank?(ENV["CLAUDE_CODE_SESSION_ID"])
390
399
  $stderr.puts "plastic: no session id available; arming auto with derived bridge key #{key}"
391
400
  end
392
401
  data = derive(key, intent_id: intent_id, intent_dir: intent_dir, store: store, name: name)
@@ -33,11 +33,11 @@ Invoke the `plastic-intent-curator` agent via the Agent tool with `subagent_type
33
33
 
34
34
  The agent handles:
35
35
  - Intent lifecycle management (status transitions, Outcome sections)
36
- - INDEX.md maintenance (Active/Future/Clusters/Completed sections)
36
+ - INDEX.md maintenance (Active/Future/Clusters/Completed/Abandoned sections)
37
37
  - Link discovery between related intents
38
38
  - Cluster management (create, merge, rename)
39
39
  - Orphan detection
40
40
 
41
- When an intent is moved to Completed, refresh the QMD index for the affected store (no-op when QMD absent), running in the background so it never blocks: `ruby ~/.plastic/scripts/qmd-sync reindex --store <store-root> --async`.
41
+ When an intent reaches a terminal state — moved to Completed OR Abandoned — refresh the QMD index for the affected store (no-op when QMD absent), running in the background so it never blocks: `ruby ~/.plastic/scripts/qmd-sync reindex --store <store-root> --async`.
42
42
 
43
43
  After the agent completes, report what changed.