@zalom/plastic 1.0.0-alpha.22 → 1.0.0-alpha.24
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
|
@@ -7,6 +7,8 @@ require "json"
|
|
|
7
7
|
require "date"
|
|
8
8
|
require "yaml"
|
|
9
9
|
require_relative "lib/bridge"
|
|
10
|
+
require_relative "lib/boot_banner"
|
|
11
|
+
require_relative "doctor"
|
|
10
12
|
|
|
11
13
|
index_path, store_root, mode, plugin_root = ARGV
|
|
12
14
|
exit 0 unless index_path && store_root && mode
|
|
@@ -172,6 +174,18 @@ if File.exist?(cache_file)
|
|
|
172
174
|
end
|
|
173
175
|
end
|
|
174
176
|
|
|
177
|
+
# --- Run core health in-process (intent 36a) ---
|
|
178
|
+
# Reuse Doctor's own --core checks so there is one source of truth for "core
|
|
179
|
+
# health" (no second process spawn, no duplicated check list). Never blocks the
|
|
180
|
+
# session: any failure or exception degrades to a banner and we continue.
|
|
181
|
+
|
|
182
|
+
core_health = begin
|
|
183
|
+
Doctor.new(plastic_home: store_root).run_core_checks("claude")
|
|
184
|
+
rescue
|
|
185
|
+
nil
|
|
186
|
+
end
|
|
187
|
+
core_banner = BootBanner.render(health: core_health, version: current_version)
|
|
188
|
+
|
|
175
189
|
# --- Assemble session context ---
|
|
176
190
|
|
|
177
191
|
all_active = active + project_active
|
|
@@ -184,6 +198,12 @@ all_future = future + project_future
|
|
|
184
198
|
|
|
185
199
|
parts = []
|
|
186
200
|
|
|
201
|
+
# Boot banner first: every session start surfaces that Plastic loaded, with the
|
|
202
|
+
# version (clean) or the first failing core check (degraded). Owned by the hook
|
|
203
|
+
# so it runs by construction — the plastic-continuing skill no longer does this.
|
|
204
|
+
parts << core_banner
|
|
205
|
+
parts << ""
|
|
206
|
+
|
|
187
207
|
if plastic_md
|
|
188
208
|
# Conventions always loaded first
|
|
189
209
|
parts << plastic_md
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# encoding: UTF-8
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
# Renders the SessionStart boot banner from a core-health result (intent 36a).
|
|
5
|
+
#
|
|
6
|
+
# Pure and dependency-injected: it takes the health hash (the return value of
|
|
7
|
+
# Doctor#run_core_checks) and the version string, and returns a single banner
|
|
8
|
+
# line. No I/O, no globals, no ENV — so it is unit-testable in isolation while
|
|
9
|
+
# the hook feeds it real data.
|
|
10
|
+
module BootBanner
|
|
11
|
+
module_function
|
|
12
|
+
|
|
13
|
+
# health: the Hash returned by Doctor#run_core_checks, or nil if the check
|
|
14
|
+
# itself raised (degraded to an error banner).
|
|
15
|
+
# version: the installed Plastic version string, or nil.
|
|
16
|
+
def render(health:, version:)
|
|
17
|
+
return "Plastic Core: health check error — run /plastic-doctor" if health.nil?
|
|
18
|
+
|
|
19
|
+
if health[:status] == "pass"
|
|
20
|
+
"Plastic Core loaded — v#{version || "unknown"}"
|
|
21
|
+
else
|
|
22
|
+
bad = first_problem(health[:checks])
|
|
23
|
+
if bad
|
|
24
|
+
"Plastic Core loaded with issues — #{bad[:name]}: #{bad[:message]} — run /plastic-doctor"
|
|
25
|
+
else
|
|
26
|
+
"Plastic Core loaded with issues — run /plastic-doctor"
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# First failing check, else first warning, else nil.
|
|
32
|
+
def first_problem(checks)
|
|
33
|
+
checks = checks || []
|
|
34
|
+
checks.find { |c| c[:status] == "fail" } || checks.find { |c| c[:status] == "warn" }
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -198,6 +198,7 @@ class InstallerCore
|
|
|
198
198
|
"scripts/hook-bash-gate" => "scripts/hook-bash-gate",
|
|
199
199
|
"scripts/hook-auto-arm" => "scripts/hook-auto-arm",
|
|
200
200
|
"scripts/lib/bridge.rb" => "scripts/lib/bridge.rb",
|
|
201
|
+
"scripts/lib/boot_banner.rb" => "scripts/lib/boot_banner.rb",
|
|
201
202
|
"scripts/lib/installer_core.rb" => "scripts/lib/installer_core.rb",
|
|
202
203
|
"scripts/install.rb" => "scripts/install.rb",
|
|
203
204
|
"scripts/update.rb" => "scripts/update.rb",
|
|
@@ -1,59 +1,37 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: plastic-continuing
|
|
3
|
-
description: Use when the user says "continue", "resume", or "pick up where we left off", or when starting a new session.
|
|
3
|
+
description: Use when the user says "continue", "resume", or "pick up where we left off", or when starting a new session. Continues work with the latest project context: lands on the right dashboard, then presents choices. Boot (health check, core context, version, statusline) is owned by the SessionStart hook, not this skill. Does not drive work autonomously (that is plastic-auto).
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Continuing
|
|
7
7
|
|
|
8
|
-
`plastic-continuing`
|
|
9
|
-
then stops. It does NOT execute work autonomously (that is `plastic-auto`) and does
|
|
10
|
-
the dashboard itself (it only invokes it).
|
|
8
|
+
`plastic-continuing` continues work. It presents the latest state via the dashboard and offers
|
|
9
|
+
choices, then stops. It does NOT execute work autonomously (that is `plastic-auto`) and does
|
|
10
|
+
NOT render the dashboard itself (it only invokes it).
|
|
11
|
+
|
|
12
|
+
**Boot is not this skill's job.** The `hook-session-start` hook already runs by construction on
|
|
13
|
+
every session start: it runs the core health check (`doctor --core`), primes `PLASTIC.md` +
|
|
14
|
+
store/project state, and prints the `Plastic Core loaded — v{version}` banner. The
|
|
15
|
+
`plastic-statusline` hook sets the statusline. So by the time this skill runs, core is loaded
|
|
16
|
+
and healthy (or the banner already warned otherwise). This skill picks up from there and
|
|
17
|
+
continues work. This is the seam future continue-flags build on (see [[39]]).
|
|
11
18
|
|
|
12
19
|
## When to Use
|
|
13
20
|
- UserPromptSubmit hook detects "continue" (automatic)
|
|
14
21
|
- User says "continue", "resume", or "pick up where we left off"
|
|
15
|
-
- Starting a new session with
|
|
22
|
+
- Starting a new session and you want to resume work with the latest context
|
|
16
23
|
|
|
17
24
|
## Determine Store
|
|
18
25
|
|
|
19
26
|
1. **Global store** — `~/.plastic/INDEX.md` exists → global mode.
|
|
20
27
|
2. **Local store** — a project store under `~/.plastic/projects/{slug}/` whose registered
|
|
21
28
|
path (in `~/.plastic/projects.yml`) matches the current working directory → project mode.
|
|
22
|
-
|
|
23
|
-
|
|
29
|
+
The SessionStart hook already detects this; here you only need the slug to scope the
|
|
30
|
+
dashboard.
|
|
24
31
|
3. If neither exists → announce "No Plastic store found. Run /plastic-install."
|
|
25
32
|
|
|
26
|
-
##
|
|
27
|
-
|
|
28
|
-
### 1. Core doctor (health first)
|
|
29
|
-
Run the fast runtime-liveness check synchronously (it returns in well under a second):
|
|
30
|
-
|
|
31
|
-
```bash
|
|
32
|
-
ruby ~/.plastic/scripts/doctor.rb --core
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
Print one compact health line:
|
|
36
|
-
- All pass → `Plastic core: healthy`
|
|
37
|
-
- Otherwise → `Plastic core: issues` followed by the failing checks (name + message).
|
|
38
|
-
|
|
39
|
-
This runs first so a broken runtime (missing hooks, scripts, core files) surfaces before any
|
|
40
|
-
state is loaded on top of it. For a full diagnosis, point the user at `/plastic-doctor`.
|
|
41
|
-
|
|
42
|
-
### 2. Load core (context + state)
|
|
43
|
-
- Prime `PLASTIC.md` and the harness docs so the conventions are in mind.
|
|
44
|
-
- Load live state:
|
|
45
|
-
- Read the active store `INDEX.md` (`## Active`, `## Future`).
|
|
46
|
-
- Read `~/.plastic/projects.yml`.
|
|
47
|
-
- **Detect the current project** by matching CWD against registered project paths.
|
|
48
|
-
- If in a project: load that project's `INDEX.md`; load the governing intent (from
|
|
49
|
-
`parent` in projects.yml) and the tactical intents from
|
|
50
|
-
`~/.plastic/projects/{slug}/store/`.
|
|
51
|
-
|
|
52
|
-
### 3. Version + statusline
|
|
53
|
-
- Print the current Plastic version (from `~/.plastic/VERSION`).
|
|
54
|
-
- Set the statusline.
|
|
33
|
+
## Continue (present the dashboard)
|
|
55
34
|
|
|
56
|
-
### 4. Dashboard
|
|
57
35
|
Land on the Markdown board via the `plastic-dashboard` skill. Rendering belongs there, not
|
|
58
36
|
here — run the data payload and fill + present the matching template:
|
|
59
37
|
- Project loaded → `ruby ~/.plastic/scripts/dashboard.rb project <slug> --data`
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"skill_name": "plastic-continuing",
|
|
3
|
-
"notes": "Intent 36. Scopes: description triggering (1-8) and behavior/convention compliance of the
|
|
3
|
+
"notes": "Intent 36, updated for 36a (boot moved into hook-session-start; the skill is now work-continuation only). Scopes: description triggering (1-8) and behavior/convention compliance of the work-continuation skill (9-14). Triggering assertions follow the plastic-auto eval style (one subagent router per case). Behavior assertions are convention checks against the SKILL.md.",
|
|
4
4
|
"results": {
|
|
5
5
|
"triggering": { "cases": 8, "passed": 8, "run": "2026-06-16, one subagent per case" },
|
|
6
6
|
"behavior": { "cases": 6, "passed": 6, "evidence": "convention checks against skills/continuing/SKILL.md after the intent-36 rewrite; doctor --core verified at 0.07s with 9 liveness checks and full doctor unchanged at 30 checks" }
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
{
|
|
37
37
|
"id": 4, "scope": "triggering", "set": "train",
|
|
38
38
|
"prompt": "boot plastic and show me where things stand",
|
|
39
|
-
"expected_output": "Activates plastic-continuing (
|
|
39
|
+
"expected_output": "Activates plastic-continuing (continuing work + presenting state is the skill's purpose; boot itself is hook-owned).",
|
|
40
40
|
"files": [],
|
|
41
41
|
"assertions": [
|
|
42
42
|
{ "type": "code", "check": "router CHOICE == plastic-continuing", "observed": "plastic-continuing", "result": "pass" }
|
|
@@ -80,20 +80,20 @@
|
|
|
80
80
|
},
|
|
81
81
|
{
|
|
82
82
|
"id": 9, "scope": "behavior", "set": "train",
|
|
83
|
-
"prompt": "Does the skill
|
|
84
|
-
"expected_output": "SKILL.md
|
|
83
|
+
"prompt": "Does the skill defer boot to the SessionStart hook rather than running it itself?",
|
|
84
|
+
"expected_output": "SKILL.md states boot (health check, core context, version banner, statusline) is owned by hook-session-start / plastic-statusline, not this skill.",
|
|
85
85
|
"files": ["skills/continuing/SKILL.md"],
|
|
86
86
|
"assertions": [
|
|
87
|
-
{ "type": "convention", "check": "boot
|
|
87
|
+
{ "type": "convention", "check": "SKILL.md says boot is owned by the SessionStart hook and the skill does not run it", "observed": "'Boot is not this skill's job.' paragraph naming hook-session-start and plastic-statusline", "result": "pass" }
|
|
88
88
|
]
|
|
89
89
|
},
|
|
90
90
|
{
|
|
91
91
|
"id": 10, "scope": "behavior", "set": "train",
|
|
92
|
-
"prompt": "Does
|
|
93
|
-
"expected_output": "
|
|
92
|
+
"prompt": "Does the skill avoid running doctor / setting the statusline itself?",
|
|
93
|
+
"expected_output": "SKILL.md does NOT instruct running doctor.rb --core or setting the statusline; it attributes those to the hooks.",
|
|
94
94
|
"files": ["skills/continuing/SKILL.md"],
|
|
95
95
|
"assertions": [
|
|
96
|
-
{ "type": "convention", "check": "
|
|
96
|
+
{ "type": "convention", "check": "no in-skill boot step invokes doctor.rb --core or sets the statusline; both are attributed to hooks", "observed": "doctor --core and statusline mentioned only as hook-owned in the 'Boot is not this skill's job' note", "result": "pass" }
|
|
97
97
|
]
|
|
98
98
|
},
|
|
99
99
|
{
|
|
@@ -102,7 +102,7 @@
|
|
|
102
102
|
"expected_output": "Project loaded -> `dashboard.rb project <slug>`; otherwise -> `dashboard.rb continue`. Skill only invokes, does not render.",
|
|
103
103
|
"files": ["skills/continuing/SKILL.md"],
|
|
104
104
|
"assertions": [
|
|
105
|
-
{ "type": "convention", "check": "both dashboard invocations present and gated on project detection", "observed": "'dashboard.rb project <slug>' and 'dashboard.rb continue' in '
|
|
105
|
+
{ "type": "convention", "check": "both dashboard invocations present and gated on project detection", "observed": "'dashboard.rb project <slug>' and 'dashboard.rb continue' in the 'Continue (present the dashboard)' section", "result": "pass" }
|
|
106
106
|
]
|
|
107
107
|
},
|
|
108
108
|
{
|