@zalom/plastic 2.0.0-alpha.2 → 2.0.0-alpha.20
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/agents/plastic-enforcer.md +3 -1
- package/agents/plastic-executor.md +9 -3
- package/hooks/hooks.json +12 -0
- package/hooks/message-display +134 -0
- package/hooks/statusline +4 -27
- package/package.json +2 -2
- package/scripts/agent-report +8 -2
- package/scripts/dashboard.rb +297 -18
- package/scripts/doctor.rb +652 -5
- package/scripts/end-intent +219 -0
- package/scripts/hook-capture +25 -113
- package/scripts/hook-message-display +81 -0
- package/scripts/hook-record +12 -4
- package/scripts/hook-session-start +23 -1
- package/scripts/index-projection +74 -0
- package/scripts/intent-screen +77 -0
- package/scripts/lib/action_graph_shim.rb +277 -0
- package/scripts/lib/arm.rb +26 -1
- package/scripts/lib/atomic_write.rb +31 -0
- package/scripts/lib/core_integrity.rb +71 -0
- package/scripts/lib/dashboard_screen.rb +40 -0
- package/scripts/lib/day_summary.rb +7 -2
- package/scripts/lib/doctor_core.rb +101 -5
- package/scripts/lib/doctor_session_ledger.rb +52 -0
- package/scripts/lib/graph_edges.rb +121 -0
- package/scripts/lib/graph_file.rb +246 -0
- package/scripts/lib/graph_tree.rb +98 -0
- package/scripts/lib/guarded_append.rb +155 -0
- package/scripts/lib/hook_registry.rb +14 -0
- package/scripts/lib/hook_replay.rb +211 -0
- package/scripts/lib/index_projection.rb +201 -0
- package/scripts/lib/installer_core.rb +131 -4
- package/scripts/lib/intent_screen.rb +309 -0
- package/scripts/lib/intent_screen_ansi.rb +262 -0
- package/scripts/lib/message_display.rb +586 -0
- package/scripts/lib/node_file.rb +214 -0
- package/scripts/lib/node_ids.rb +99 -0
- package/scripts/lib/node_ledger.rb +377 -0
- package/scripts/lib/node_packet.rb +886 -0
- package/scripts/lib/node_return.rb +199 -0
- package/scripts/lib/node_worktree.rb +337 -0
- package/scripts/lib/outcome_report.rb +440 -0
- package/scripts/lib/packet_wrapper.rb +132 -0
- package/scripts/lib/ready_set.rb +462 -0
- package/scripts/lib/release_guard.rb +16 -0
- package/scripts/lib/report_screen.rb +1967 -0
- package/scripts/lib/roadmap_graph.rb +210 -0
- package/scripts/lib/roadmap_migration.rb +95 -0
- package/scripts/lib/roadmap_queue.rb +155 -5
- package/scripts/lib/roadmap_render.rb +150 -0
- package/scripts/lib/roadmap_savepoint.rb +62 -12
- package/scripts/lib/runner_absorb.rb +620 -0
- package/scripts/lib/runner_answer.rb +206 -0
- package/scripts/lib/runner_core.rb +194 -0
- package/scripts/lib/runner_dispatch.rb +482 -0
- package/scripts/lib/runner_policy.rb +142 -0
- package/scripts/lib/runner_proposals.rb +254 -0
- package/scripts/lib/runner_rewind.rb +201 -0
- package/scripts/lib/runner_sweep.rb +231 -0
- package/scripts/lib/savepoint.rb +149 -12
- package/scripts/lib/screen_paint.rb +555 -0
- package/scripts/lib/screens/dashboard.rb +20 -0
- package/scripts/lib/screens/plan.rb +18 -0
- package/scripts/lib/screens/roadmap.rb +15 -0
- package/scripts/lib/session_git.rb +49 -18
- package/scripts/lib/session_ledger.rb +128 -0
- package/scripts/lib/verify_intent.rb +33 -0
- package/scripts/lib/work_graph_validator.rb +201 -0
- package/scripts/node-packet +92 -0
- package/scripts/node-transition +291 -0
- package/scripts/outcome-report +74 -0
- package/scripts/plastic-lock +8 -1
- package/scripts/ready-set +126 -0
- package/scripts/release-check +118 -0
- package/scripts/report-screen +281 -0
- package/scripts/roadmap-graph +119 -0
- package/scripts/roadmap-savepoint +7 -0
- package/scripts/runner +392 -0
- package/scripts/savepoint-note +69 -0
- package/scripts/spawn-preamble +9 -2
- package/scripts/validate-work-graph +39 -0
- package/scripts/verify-intent +2 -1
- package/skills/auto/SKILL.md +24 -17
- package/skills/auto/references/human-report-contract.md +136 -54
- package/skills/conventions/references/locks-and-worktrees.md +12 -0
- package/skills/dashboard/SKILL.md +13 -2
- package/skills/dashboard/templates/dashboard-global.md +1 -1
- package/skills/dashboard/templates/dashboard-project.md +2 -2
- package/skills/doctor/SKILL.md +10 -4
- package/skills/intent-continuing/SKILL.md +51 -41
- package/skills/intent-continuing/references/board-fill.md +9 -0
- package/skills/intent-continuing/references/boarding-matrix.md +6 -5
- package/skills/intent-continuing/references/context-management.md +1 -1
- package/skills/intent-ending/SKILL.md +36 -16
- package/skills/intent-executing/SKILL.md +17 -5
- package/skills/intent-executing/implementer-prompt.md +6 -1
- package/skills/intent-speccing/SKILL.md +7 -4
- package/skills/releasing/SKILL.md +39 -0
- package/skills/releasing/references/promotion-and-tagging.md +10 -6
- package/skills/releasing/references/release-lines.md +1 -1
- package/skills/roadmap/SKILL.md +26 -0
- package/skills/roadmap/references/file-format.md +10 -0
- package/templates/dashboard-screen.md +22 -0
- package/templates/display-fixture.md +21 -0
- package/templates/graph.md +16 -0
- package/templates/intent-screen.md +17 -0
- package/templates/node-decision.md +11 -0
- package/templates/node-research.md +11 -0
- package/templates/node-verify.md +13 -0
- package/templates/node-work.md +22 -0
- package/templates/outcome.md +19 -1
- package/templates/report-plan.md +15 -0
- package/templates/report-roadmap-delivered.md +10 -0
- package/templates/report-roadmap-plan.md +9 -0
- package/templates/report-roadmap-state.md +9 -0
- package/templates/report-state.md +11 -0
- package/templates/roadmap.md +13 -0
|
@@ -31,7 +31,9 @@ deliberately; the auto pipeline never dispatches them.
|
|
|
31
31
|
`plastic-intent-executing`'s `plan-reviewer-prompt.md`; fold every finding into the spec, the
|
|
32
32
|
matrix, and the tests.
|
|
33
33
|
4. **Dispatch one executor, tests first** - the executor commits the matrix's tests red, then
|
|
34
|
-
builds, then drives the full suite green; you verify
|
|
34
|
+
builds, then drives the full suite green; you verify tick-versus-diff at the
|
|
35
|
+
post-execution review and again before the merge. A mismatch is a review finding, not a
|
|
36
|
+
cleanup you perform silently.
|
|
35
37
|
5. **Review by risk** - dispatch the post-execution reviewer only when the auto skill's risk
|
|
36
38
|
rule fires; otherwise the green suite is the review.
|
|
37
39
|
6. **Close** - `outcome.md`, then `plastic-intent-ending`, which releases the worktree, clears
|
|
@@ -20,7 +20,11 @@ valid lifecycle artifacts. Honor it as your live state; do not re-derive or cont
|
|
|
20
20
|
any other change.
|
|
21
21
|
2. **Implement the actions** - make the code changes for each action in order, inside the
|
|
22
22
|
worktree the preamble names.
|
|
23
|
-
3. **
|
|
23
|
+
3. **Tick with the commit** - commit after each logical unit of work, and in the same step
|
|
24
|
+
tick the checklist item that unit lands: mark its box `[x]` and move the line to
|
|
25
|
+
`## Completed`, then append the savepoint `Commit` line
|
|
26
|
+
(`scripts/savepoint-note <intent_dir> --kind Commit --text "<sha> <what it proves>"`). A
|
|
27
|
+
commit without its tick is incomplete.
|
|
24
28
|
4. **Record insights** - capture durable discoveries and report them in the `insights:` field;
|
|
25
29
|
persist each to `## Insights` via the `insight-append` helper
|
|
26
30
|
(`scripts/insight-append <intent_dir> <text> --stage Exec --author "plastic-executor (autonomous)"`),
|
|
@@ -33,7 +37,8 @@ valid lifecycle artifacts. Honor it as your live state; do not re-derive or cont
|
|
|
33
37
|
real `ACTION_N.md` with its failure-mode matrix, pasted in by the lead. Execute the action
|
|
34
38
|
files in order.
|
|
35
39
|
2. Write the matrix's tests; commit red.
|
|
36
|
-
3. Work one action at a time,
|
|
40
|
+
3. Work one action at a time, ticking its checklist item in the same commit that lands it
|
|
41
|
+
(box marked, line moved); prefer safe, non-destructive routes.
|
|
37
42
|
4. Run the full suite, iterate to zero failures and zero errors; commit green.
|
|
38
43
|
5. Produce (output handoff): the code changes, a checked-off `checklist.md`, and `## Insights`.
|
|
39
44
|
6. Report (see `## Completion Report`); the lead applies the risk rule and may dispatch a
|
|
@@ -46,7 +51,8 @@ preamble's `REPORT_CONTRACT` and `skills/auto/references/agent-report-contract.m
|
|
|
46
51
|
finish silently. Carry the common envelope (role, intent id, stage, status, artifacts written,
|
|
47
52
|
verification, checklist deltas, deviations, blockers, insights) plus the executor payload:
|
|
48
53
|
|
|
49
|
-
- Actions implemented this turn, mapped to checklist items checked off (checked / total)
|
|
54
|
+
- Actions implemented this turn, mapped to checklist items checked off (checked / total);
|
|
55
|
+
checked / total must equal the items whose commits exist
|
|
50
56
|
- A summary of the code changed (files and the shape of the change)
|
|
51
57
|
- Test result: the red commit's failing count, then the full-suite command and its pass / fail
|
|
52
58
|
counts
|
package/hooks/hooks.json
CHANGED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# hooks/message-display (intent 316a, O6, round 3 concurrency fix): the
|
|
3
|
+
# MessageDisplay launcher. Fires on every streamed chunk of every assistant
|
|
4
|
+
# message (D11), so the common case — an ordinary chunk of an ordinary
|
|
5
|
+
# message — must decide with shell builtins alone and fork nothing. Only a
|
|
6
|
+
# candidate message hands off to Ruby (scripts/hook-message-display), which
|
|
7
|
+
# is the one place allowed to do real work.
|
|
8
|
+
#
|
|
9
|
+
# No command substitution, no backticks, no sed/jq/cat: case, [, parameter
|
|
10
|
+
# expansion and printf are all builtins. Deliberately does NOT copy hooks/
|
|
11
|
+
# capture's SCRIPT_DIR-via-subshell pattern (cd into dirname of $0, inside a
|
|
12
|
+
# command substitution, then pwd) — that forks a subshell on every single
|
|
13
|
+
# invocation, which is exactly the cost this hook cannot carry.
|
|
14
|
+
#
|
|
15
|
+
# A live run under a real pty found Claude Code fires these chunk processes
|
|
16
|
+
# CONCURRENTLY: a chunk with index > 0 can arrive, and be judged here,
|
|
17
|
+
# before chunk 0 ever runs. The OLD hand-off test — "does a buffer already
|
|
18
|
+
# exist for this message" — answered no in that race and silently dropped
|
|
19
|
+
# the chunk before Ruby ever saw it, no matter what MessageDisplay's own
|
|
20
|
+
# (correct) polling logic would have done. So a later chunk is now also
|
|
21
|
+
# handed off when its OWN delta looks like it could be part of a screen
|
|
22
|
+
# (leading "|" or "**Steps**", or blank — the same cheap test Ruby itself
|
|
23
|
+
# uses to decide whether a wait is worth paying for), and the final chunk is
|
|
24
|
+
# ALWAYS handed off, whatever it looks like, since it is the one that must
|
|
25
|
+
# not race. Ruby is the one place that actually waits (bounded, injectable
|
|
26
|
+
# for tests); this script only ever decides once, fast, and never sleeps.
|
|
27
|
+
#
|
|
28
|
+
# Claude adapter: Claude Code only; the core is harness-agnostic.
|
|
29
|
+
IFS= read -r -d '' INPUT # returns 1 at EOF: do NOT set -e
|
|
30
|
+
case $INPUT in *'"message_id"'*) ;; *) exit 0 ;; esac
|
|
31
|
+
rest=${INPUT#*\"message_id\"}; rest=${rest#*\"}; mid=${rest%%\"*}
|
|
32
|
+
rest=${INPUT#*\"session_id\"}; rest=${rest#*\"}; sid=${rest%%\"*}
|
|
33
|
+
|
|
34
|
+
SCRIPT_DIR=${0%/*}
|
|
35
|
+
TMP_ROOT=${PLASTIC_TMP:-${TMPDIR:-/tmp}}
|
|
36
|
+
export PLASTIC_TMP="$TMP_ROOT"
|
|
37
|
+
MSGDIR="$TMP_ROOT/plastic-message-display/$sid/$mid"
|
|
38
|
+
|
|
39
|
+
is_index_zero=0
|
|
40
|
+
case $INPUT in *'"index":0'*|*'"index": 0'*) is_index_zero=1 ;; esac
|
|
41
|
+
|
|
42
|
+
is_final=0
|
|
43
|
+
case $INPUT in *'"final":true'*|*'"final": true'*) is_final=1 ;; esac
|
|
44
|
+
|
|
45
|
+
handoff=0
|
|
46
|
+
if [ "$is_index_zero" = 1 ]; then
|
|
47
|
+
# Chunk 0 decides synchronously; a bare "#" first delta, in either JSON
|
|
48
|
+
# spacing, is the only shape that can possibly open a screen. Must be a
|
|
49
|
+
# single "#", not "##" — a real screen's own first delta can be as short
|
|
50
|
+
# as "## " — a "##" glob would filter out exactly the message this hook
|
|
51
|
+
# exists to recognize.
|
|
52
|
+
# 317a (B11): a screen can open with "## " (state, delivered), a bare "▶"
|
|
53
|
+
# (roster), or a bare "✔" (delay); the JSON may carry the glyph raw or
|
|
54
|
+
# \u-escaped depending on the encoder. All globs are literal bytes - case
|
|
55
|
+
# matching is byte-wise, so multibyte literals are safe under bash 3.2.
|
|
56
|
+
case $INPUT in
|
|
57
|
+
*'"delta":"#'*|*'"delta": "#'*) handoff=1 ;;
|
|
58
|
+
*'"delta":"▶'*|*'"delta": "▶'*) handoff=1 ;;
|
|
59
|
+
*'"delta":"✔'*|*'"delta": "✔'*) handoff=1 ;;
|
|
60
|
+
esac
|
|
61
|
+
# 331a review fix (M12e): chunk 0 is not exempt from D5 either. The
|
|
62
|
+
# intent's own flagship shape -- a lead-in sentence and the opener in the
|
|
63
|
+
# SAME first chunk -- never starts with "#", "▶", or "✔", so the arm
|
|
64
|
+
# above alone never sees it. Joins it with the identical opener-anywhere
|
|
65
|
+
# globs used for a later chunk (M12a) rather than replacing anything:
|
|
66
|
+
# same reasoning as the comment at that site applies verbatim here.
|
|
67
|
+
case $INPUT in
|
|
68
|
+
*'"delta":"'*'▶'*|*'"delta": "'*'▶'*) handoff=1 ;;
|
|
69
|
+
*'"delta":"'*'✔'*|*'"delta": "'*'✔'*) handoff=1 ;;
|
|
70
|
+
*'"delta":"'*'\u25b6'*|*'"delta": "'*'\u25b6'*) handoff=1 ;;
|
|
71
|
+
*'"delta":"'*'\u2714'*|*'"delta": "'*'\u2714'*) handoff=1 ;;
|
|
72
|
+
esac
|
|
73
|
+
else
|
|
74
|
+
# A later chunk: hand off when this message's directory already exists
|
|
75
|
+
# (chunk 0 already left a decision or a chunk file), when this chunk is
|
|
76
|
+
# final (it must always be checked, whatever it looks like), or when its
|
|
77
|
+
# own delta is shaped like part of a screen — a Markdown table row, the
|
|
78
|
+
# "**Steps**" heading, or a blank line, in either JSON spacing.
|
|
79
|
+
[ -d "$MSGDIR" ] && handoff=1
|
|
80
|
+
[ "$is_final" = 1 ] && handoff=1
|
|
81
|
+
case $INPUT in
|
|
82
|
+
*'"delta":"|'*|*'"delta": "|'*) handoff=1 ;;
|
|
83
|
+
*'"delta":"**'*|*'"delta": "**'*) handoff=1 ;;
|
|
84
|
+
*'"delta":""'*|*'"delta": ""'*) handoff=1 ;;
|
|
85
|
+
*'"delta":"\n"'*|*'"delta": "\n"'*) handoff=1 ;;
|
|
86
|
+
esac
|
|
87
|
+
# 331a (D5): the hook engages anywhere. An opener can now fall ANYWHERE
|
|
88
|
+
# inside a later chunk's own delta, not only at its start (the shape
|
|
89
|
+
# tests just above), so these globs search the delta value rather than
|
|
90
|
+
# anchor to its opening quote. Still anchored to the "delta":" key itself
|
|
91
|
+
# (never dropped, matrix M12d) so an ordinary field elsewhere in the
|
|
92
|
+
# payload can never be mistaken for the delta's own text; within that,
|
|
93
|
+
# every shipped opener (## ▶, ## ✔, ▶ In delivery, ✔ + digit) contains a
|
|
94
|
+
# bare ▶ or ✔, so matching the bare glyph anywhere covers all four at
|
|
95
|
+
# once. Prose that merely shapes like an opener still hands off this way
|
|
96
|
+
# (an accepted over-match: Ruby's own grammar is the final, stricter
|
|
97
|
+
# arbiter and fails open on anything that is not a real one). Raw glyph
|
|
98
|
+
# and \u-escaped forms both count, since the encoder's choice is not ours
|
|
99
|
+
# to predict.
|
|
100
|
+
case $INPUT in
|
|
101
|
+
*'"delta":"'*'▶'*|*'"delta": "'*'▶'*) handoff=1 ;;
|
|
102
|
+
*'"delta":"'*'✔'*|*'"delta": "'*'✔'*) handoff=1 ;;
|
|
103
|
+
*'"delta":"'*'\u25b6'*|*'"delta": "'*'\u25b6'*) handoff=1 ;;
|
|
104
|
+
*'"delta":"'*'\u2714'*|*'"delta": "'*'\u2714'*) handoff=1 ;;
|
|
105
|
+
esac
|
|
106
|
+
fi
|
|
107
|
+
|
|
108
|
+
[ "$handoff" = 1 ] || exit 0
|
|
109
|
+
|
|
110
|
+
# 331a1 (D1): chunk 0 is about to hand off to Ruby, which takes on the
|
|
111
|
+
# order of 150 ms to boot before it ever writes SCREEN or NOSCREEN. Claude
|
|
112
|
+
# Code fires the per-chunk hook PROCESSES CONCURRENTLY (see the header
|
|
113
|
+
# comment above), so a later chunk landing inside that window used to find
|
|
114
|
+
# no message directory at all, fail this script's own cheap shape test,
|
|
115
|
+
# and pass through as raw Markdown - measured at 15 to 21 chunks of every
|
|
116
|
+
# screen, against a stream-realistic 5 ms stagger. Staking a PENDING
|
|
117
|
+
# marker here, the instant the handoff gate above passes, closes that
|
|
118
|
+
# window down to microseconds: a later chunk's own "does the directory
|
|
119
|
+
# exist" check (below, unchanged) now finds it almost at once, and
|
|
120
|
+
# MessageDisplay polls for the real decision instead of judging the
|
|
121
|
+
# chunk's own shape. mkdir is the one non-builtin on this whole path - it
|
|
122
|
+
# forks, unlike everything else in this file - but it runs ONLY here,
|
|
123
|
+
# after the handoff gate, so the ordinary (non-candidate) chunk that is
|
|
124
|
+
# the overwhelming common case still forks nothing (matrix L8). A failed
|
|
125
|
+
# mkdir or printf (an unwritable tmp root, a race with another process) is
|
|
126
|
+
# silently swallowed: it must never change this script's own exit status
|
|
127
|
+
# or skip the Ruby handoff below - Ruby's own polling already fails open
|
|
128
|
+
# (D5) when no decision ever appears.
|
|
129
|
+
if [ "$is_index_zero" = 1 ]; then
|
|
130
|
+
mkdir -p "$MSGDIR" 2>/dev/null
|
|
131
|
+
printf '' > "$MSGDIR/PENDING" 2>/dev/null
|
|
132
|
+
fi
|
|
133
|
+
|
|
134
|
+
printf '%s' "$INPUT" | env -u RUBYOPT ruby "$SCRIPT_DIR/../scripts/hook-message-display"
|
package/hooks/statusline
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
# plastic-hook-version: 4.0.0
|
|
3
3
|
# StatusLine hook - Plastic owns the full statusline (no chaining).
|
|
4
4
|
# Renders: {model} - ctx {pct}% ({used}/{size}) - 5h {p}% - 7d {p}% - ${cost}
|
|
5
|
-
# -
|
|
6
|
-
# Every segment but
|
|
5
|
+
# - Plastic {version}[ -> {next}] - {path}
|
|
6
|
+
# Every segment but the Plastic version comes from the stdin payload.
|
|
7
7
|
# Pure bash (macOS 3.2 compatible). No ruby, no jq. Reads stdin once; small file reads
|
|
8
8
|
# only. The stdin JSON is walked in a single awk pass (below); nothing else in this
|
|
9
9
|
# script forks a second process per field, which is what keeps a render cheap.
|
|
@@ -17,7 +17,6 @@ C_OK='' # default - meter below 70%
|
|
|
17
17
|
C_WARN=$'\033[33m' # yellow - meter at 70% and above
|
|
18
18
|
C_CRIT=$'\033[38;2;231;76;60m' # red - meter at 90% and above
|
|
19
19
|
C_COST=$'\033[37m' # white - session cost
|
|
20
|
-
C_CLAUDISH=$'\033[38;2;249;140;30m' # orange - claudish rewrites
|
|
21
20
|
C_VER=$'\033[37m' # white - "Plastic {version}" and update arrow
|
|
22
21
|
C_NEXT=$'\033[33m' # yellow - next version
|
|
23
22
|
C_PATH=$'\033[38;2;128;134;144m' # gray - path (matches dim UI text)
|
|
@@ -309,40 +308,18 @@ if [ -n "$COST_RAW" ]; then
|
|
|
309
308
|
[ -n "$COST_FMT" ] && [ "$COST_FMT" != "0.00" ] && COST_SEG="${C_COST}\$${COST_FMT}${RST}"
|
|
310
309
|
fi
|
|
311
310
|
|
|
312
|
-
# --- claudish rewrites for THIS session (fork ledger, optional) ---
|
|
313
|
-
# Tab separated, one call per line; column 11 is the session id. Rows written
|
|
314
|
-
# before that column existed have 9 or 10 fields and never match, so an old
|
|
315
|
-
# ledger renders no segment instead of a wrong one.
|
|
316
|
-
CL_SEG=""
|
|
317
|
-
CL_LOG="${CLAUDISH_LOCAL_DIR:-$HOME/.claude/claudish-local}/usage.log"
|
|
318
|
-
if [ -n "$SID" ] && [ -f "$CL_LOG" ]; then
|
|
319
|
-
CL=$(awk -F'\t' -v sid="$SID" '
|
|
320
|
-
NF >= 11 && $11 == sid { n++; t += $5 + $6 }
|
|
321
|
-
END {
|
|
322
|
-
if (n > 0) {
|
|
323
|
-
if (t >= 1000) {
|
|
324
|
-
s = sprintf("%.1f", t / 1000); sub(/\.0$/, "", s); printf "%d %sk", n, s
|
|
325
|
-
} else {
|
|
326
|
-
printf "%d %d", n, t
|
|
327
|
-
}
|
|
328
|
-
}
|
|
329
|
-
}' "$CL_LOG" 2>/dev/null)
|
|
330
|
-
[ -n "$CL" ] && CL_SEG="${C_CLAUDISH}claudish ${CL%% *} rw / ${CL#* }${RST}"
|
|
331
|
-
fi
|
|
332
|
-
|
|
333
311
|
# --- Assemble segments in order, joined by " . " ---
|
|
334
312
|
PARTS=""
|
|
335
313
|
add() { [ -z "$1" ] && return; if [ -z "$PARTS" ]; then PARTS="$1"; else PARTS="$PARTS$SEP$1"; fi; }
|
|
336
314
|
|
|
337
|
-
# Order: identity first (model), then this session's spend (context, meters, cost,
|
|
338
|
-
#
|
|
315
|
+
# Order: identity first (model), then this session's spend (context, meters, cost),
|
|
316
|
+
# then the volatile-length values last (version, path) so the line does
|
|
339
317
|
# not visually jump as they change.
|
|
340
318
|
[ -n "$MODEL" ] && add "${C_MODEL}${MODEL}${RST}"
|
|
341
319
|
add "$CTX_SEG"
|
|
342
320
|
add "$M5"
|
|
343
321
|
add "$M7"
|
|
344
322
|
add "$COST_SEG"
|
|
345
|
-
add "$CL_SEG"
|
|
346
323
|
if [ -n "$VERSION" ]; then
|
|
347
324
|
vseg="${C_VER}Plastic ${VERSION}${RST}"
|
|
348
325
|
[ -n "$NEXT" ] && vseg="${vseg}${C_VER} "$'\342\206\222'" ${RST}${C_NEXT}${NEXT}${RST}"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zalom/plastic",
|
|
3
|
-
"version": "2.0.0-alpha.
|
|
3
|
+
"version": "2.0.0-alpha.20",
|
|
4
4
|
"description": "Intent-driven idea development system for AI coding agents",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"license": "MIT",
|
|
28
28
|
"repository": {
|
|
29
29
|
"type": "git",
|
|
30
|
-
"url": "https://github.com/zalom/plastic"
|
|
30
|
+
"url": "git+https://github.com/zalom/plastic.git"
|
|
31
31
|
},
|
|
32
32
|
"homepage": "https://github.com/zalom/plastic",
|
|
33
33
|
"files": [
|
package/scripts/agent-report
CHANGED
|
@@ -22,6 +22,8 @@
|
|
|
22
22
|
# Exit codes: 0 (report emitted), 2 (usage).
|
|
23
23
|
|
|
24
24
|
require_relative "lib/savepoint"
|
|
25
|
+
require_relative "lib/intent_screen"
|
|
26
|
+
|
|
25
27
|
def parse_args(argv)
|
|
26
28
|
role = nil
|
|
27
29
|
positional = []
|
|
@@ -67,11 +69,15 @@ STAGE_LABELS = {
|
|
|
67
69
|
"exec" => "Exec", "done" => "Done"
|
|
68
70
|
}.freeze
|
|
69
71
|
|
|
72
|
+
# Intent 317, D6: name the last LIFECYCLE line, never a trailing Lock/Review/
|
|
73
|
+
# Commit line (same guard as spawn-preamble; plan review finding B1).
|
|
70
74
|
def current_stage(intent_dir)
|
|
71
75
|
ledger = File.join(intent_dir, Savepoint::SAVEPOINT_FILE)
|
|
72
76
|
if File.exist?(ledger)
|
|
73
|
-
|
|
74
|
-
|
|
77
|
+
lines = File.read(ledger).each_line.map(&:strip).reject(&:empty?)
|
|
78
|
+
lifecycle = lines.select { |l| IntentScreen.lifecycle_line?(l) }
|
|
79
|
+
return lifecycle.last if lifecycle.any?
|
|
80
|
+
return lines.last if lines.any?
|
|
75
81
|
end
|
|
76
82
|
STAGE_LABELS.fetch(Savepoint.derive_stage(intent_dir), Savepoint.derive_stage(intent_dir))
|
|
77
83
|
end
|