@zalom/plastic 1.7.1 → 1.9.0
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/PLASTIC.md +75 -535
- package/README.md +3 -2
- package/agents/plastic-intent-curator.md +2 -2
- package/deprecations.yml +10 -2
- package/hooks/{links-gate → edit-gates} +1 -1
- package/hooks/hooks.json +4 -44
- package/hooks/power-tools +8 -0
- package/package.json +1 -2
- package/scripts/codex-hook +17 -22
- package/scripts/doctor.rb +688 -186
- package/scripts/end-intent +65 -22
- package/scripts/hook-code-gate +13 -28
- package/scripts/hook-create-gate +10 -57
- package/scripts/hook-edit-gates +58 -0
- package/scripts/hook-links-gate +8 -31
- package/scripts/hook-lock-gate +13 -58
- package/scripts/hook-power-tools +38 -0
- package/scripts/hook-savepoint-pre +8 -11
- package/scripts/lib/bridge.rb +2 -2
- package/scripts/lib/edit_gates.rb +342 -0
- package/scripts/lib/hook_registry.rb +61 -29
- package/scripts/lib/installer_core.rb +100 -18
- package/scripts/lib/outcome_guard.rb +38 -0
- package/scripts/lib/qmd_hook.rb +21 -41
- package/scripts/lib/qmd_sync.rb +0 -15
- package/scripts/lib/revisions_writer.rb +1 -1
- package/scripts/maintenance-run +56 -2
- package/scripts/restore-intent-v1 +16 -11
- package/skills/auto/SKILL.md +15 -4
- package/skills/auto/evals/evals.json +2 -2
- package/skills/conventions/SKILL.md +31 -0
- package/skills/conventions/references/completion-and-done.md +40 -0
- package/skills/conventions/references/gates-and-enforcement.md +23 -0
- package/skills/conventions/references/knowledge-graph.md +47 -0
- package/skills/conventions/references/lifecycle-and-savepoints.md +11 -0
- package/skills/conventions/references/locks-and-worktrees.md +113 -0
- package/skills/conventions/references/maintenance-and-revisions.md +170 -0
- package/skills/conventions/references/roadmaps.md +44 -0
- package/skills/conventions/references/tiers-and-dispatch.md +134 -0
- package/skills/doctor/SKILL.md +59 -19
- package/skills/intent-brainstorming/SKILL.md +4 -0
- package/skills/intent-continuing/SKILL.md +4 -0
- package/skills/intent-creating/SKILL.md +7 -2
- package/skills/intent-ending/SKILL.md +20 -6
- package/skills/intent-executing/SKILL.md +10 -0
- package/skills/intent-linking/SKILL.md +4 -0
- package/skills/intent-locking/SKILL.md +4 -0
- package/skills/intent-planning/SKILL.md +7 -0
- package/skills/intent-savepoint/SKILL.md +4 -0
- package/skills/intent-speccing/SKILL.md +4 -0
- package/skills/intent-starting/SKILL.md +10 -0
- package/skills/project-creating/references/project-scaffolding.md +2 -2
- package/skills/roadmap/SKILL.md +4 -0
- package/skills/roadmap-continuing/SKILL.md +4 -0
- package/skills/skill-creating/SKILL.md +3 -0
- package/skills/skill-creating/references/defaults-first.md +23 -0
- package/skills/skill-creating/references/hooks.md +4 -1
- package/skills/store-curating/SKILL.md +8 -0
- package/skills/store-indexing/SKILL.md +8 -0
- package/skills/tutorial/references/track-2-auto.md +2 -3
- package/templates/agents.md +8 -0
- package/PLASTIC-reference.md +0 -138
- package/hooks/code-gate +0 -27
- package/hooks/create-gate +0 -3
- package/hooks/lock-gate +0 -21
- package/hooks/qmd-search +0 -8
- package/hooks/retrieval-gate +0 -10
- package/hooks/savepoint-pre +0 -10
- package/scripts/hook-qmd-search +0 -44
- package/scripts/hook-retrieval-gate +0 -148
- package/scripts/lib/legacy_bookend_amnesty.rb +0 -35
- package/scripts/lib/retrieval_gate.rb +0 -211
package/README.md
CHANGED
|
@@ -183,8 +183,9 @@ behind releases are part of the repository, not a hidden process.
|
|
|
183
183
|
|
|
184
184
|
## Conventions
|
|
185
185
|
|
|
186
|
-
|
|
187
|
-
and overwritten on every update.
|
|
186
|
+
The always-on core conventions live in `PLASTIC.md`, distributed to `~/.plastic/PLASTIC.md`
|
|
187
|
+
and overwritten on every update. Deeper doctrine lives in the `plastic-conventions` skill,
|
|
188
|
+
loaded on demand by the skills that need it. Project-specific rules live in `AGENTS.md`.
|
|
188
189
|
Run `plastic-doctor` to check installation health; it compares files against
|
|
189
190
|
the manifests, checks store state, and runs automatically after every update.
|
|
190
191
|
|
|
@@ -27,9 +27,9 @@ You are the Plastic Intent Curator. Your role is to maintain the health and navi
|
|
|
27
27
|
5. On a terminal-state transition (Completed OR Abandoned), do these things:
|
|
28
28
|
a. Author a real `outcome.md` in the intent directory from `~/.plastic/templates/outcome.md`, with the frontmatter `disposition: delivered` for a completed intent or `disposition: abandoned` for an abandoned one. `outcome.md` is MANDATORY at every terminal, delivered and abandoned alike: on abandon it records the abandonment reason and replaces the scaffolded placeholder sentinel (never leave `outcome.md` a placeholder at a terminal).
|
|
29
29
|
b. Call `plastic-intent-ending` for the terminal-transition close (INDEX move, savepoint `Done` bookend, store commit, disarm, and the QMD reindex last): `ruby ~/.plastic/scripts/end-intent --store <store> --id <id> --disposition delivered|abandoned`, then follow that skill's own disarm and reindex steps. Never restate the INDEX/savepoint/reindex one-liners here.
|
|
30
|
-
6. Structural maintenance is move-and-record, and it is NEVER done without its receipt: remove the misplaced section, file, or ref from its artifact, then create or append `revisions.md` in that intent directory (copy the FORM from `~/.plastic/templates/revisions.md`) IN THE SAME PASS as the edit. If you cannot write `revisions.md` for any reason (permissions, a read-only path), you MUST NOT make the structural edit either - report the blocker instead of leaving an unrecorded change (this mirrors the tool-side rule: project-links, rebuild-graph, and restore-intent-v1 refuse rather than write a change with no receipt; you hold yourself to the same rule by hand). One entry per relocated item, newest at the bottom: a `## Revision vN - YYYY-MM-DD-HH:MM` header, a one-sentence `Why` ending with `[rule: <tag>]`, `Prior location`, and either `Content held` (verbatim) or a one-line `Change` for a frontmatter edit. For a stray file, embed its full content and delete the original. The violation-tag catalog is canonical in
|
|
30
|
+
6. Structural maintenance is move-and-record, and it is NEVER done without its receipt: remove the misplaced section, file, or ref from its artifact, then create or append `revisions.md` in that intent directory (copy the FORM from `~/.plastic/templates/revisions.md`) IN THE SAME PASS as the edit. If you cannot write `revisions.md` for any reason (permissions, a read-only path), you MUST NOT make the structural edit either - report the blocker instead of leaving an unrecorded change (this mirrors the tool-side rule: project-links, rebuild-graph, and restore-intent-v1 refuse rather than write a change with no receipt; you hold yourself to the same rule by hand). One entry per relocated item, newest at the bottom: a `## Revision vN - YYYY-MM-DD-HH:MM` header, a one-sentence `Why` ending with `[rule: <tag>]`, `Prior location`, and either `Content held` (verbatim) or a one-line `Change` for a frontmatter edit. For a stray file, embed its full content and delete the original. The violation-tag catalog is canonical in `plastic-conventions > references/maintenance-and-revisions.md`. A graph edit must move TOWARD ground truth (drop a dangling/false edge, add a reciprocity-forced or documented-real one) and must NEVER invent a relationship - "might be related" is never a valid `[rule:]` reason (`plastic-conventions > references/maintenance-and-revisions.md`, WORK vs MAINTENANCE).
|
|
31
31
|
7. Before performing structural maintenance on ANY intent that is NOT the one your own session is currently delivering under its own held delivery lock, you must:
|
|
32
|
-
a. Check the target's lock freshness: `ruby ~/.plastic/scripts/plastic-lock status --intent-dir <target-intent-dir>` and read the `lock_fresh` field of its JSON output. If `true`, DEFER: make no edit to that intent, and report it as skipped (an active delivery is in progress). This is DETECT-ONLY - you never acquire, create, or hold any lock of your own for maintenance (
|
|
32
|
+
a. Check the target's lock freshness: `ruby ~/.plastic/scripts/plastic-lock status --intent-dir <target-intent-dir>` and read the `lock_fresh` field of its JSON output. If `true`, DEFER: make no edit to that intent, and report it as skipped (an active delivery is in progress). This is DETECT-ONLY - you never acquire, create, or hold any lock of your own for maintenance (`plastic-conventions > references/maintenance-and-revisions.md`, WORK vs MAINTENANCE; there is exactly one lock in Plastic, the delivery lock).
|
|
33
33
|
b. Require a clean store working tree before starting: `git -C ~/.plastic status --porcelain` (or the project store's own root, if not global) must be empty. If it is not, STOP and report the dirty paths rather than risk sweeping an unrelated concurrent change into your own commit; do not proceed until the tree is clean.
|
|
34
34
|
c. Create a fresh branch from the current tip of that repo's main: `git -C <repo-root> checkout -b maintenance/curator-<UTC-timestamp> main`.
|
|
35
35
|
d. Make the scoped edit plus its `revisions.md` receipt (step 6 above), touching nothing else.
|
package/deprecations.yml
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Plastic deprecation notices
|
|
2
2
|
# Each entry is shown to the user during SessionStart.
|
|
3
|
-
# See
|
|
3
|
+
# See the plastic-releasing skill for the full convention.
|
|
4
4
|
#
|
|
5
5
|
# Schema:
|
|
6
6
|
# id: unique-slug (used for dismissal tracking)
|
|
@@ -11,4 +11,12 @@
|
|
|
11
11
|
# removal: semver where feature is removed
|
|
12
12
|
# link: optional URL to migration guide
|
|
13
13
|
|
|
14
|
-
deprecations:
|
|
14
|
+
deprecations:
|
|
15
|
+
- id: plastic-reference-md-absorbed
|
|
16
|
+
severity: info
|
|
17
|
+
summary: "PLASTIC-reference.md has been absorbed into the plastic-conventions skill and removed; its content now lives in that skill's reference chapters."
|
|
18
|
+
migration_steps:
|
|
19
|
+
- "No action is required. Running plastic update removes the leftover ~/.plastic/PLASTIC-reference.md automatically."
|
|
20
|
+
- "If you hand-copied or hand-edited that file, delete your own copy; it is no longer read by Plastic."
|
|
21
|
+
introduced: "1.9.0"
|
|
22
|
+
removal: "1.11.0"
|
package/hooks/hooks.json
CHANGED
|
@@ -35,38 +35,8 @@
|
|
|
35
35
|
"hooks": [
|
|
36
36
|
{
|
|
37
37
|
"type": "command",
|
|
38
|
-
"command": "\"${CLAUDE_PLUGIN_ROOT}/hooks/run-hook\"
|
|
39
|
-
"statusMessage": "Checking
|
|
40
|
-
},
|
|
41
|
-
{
|
|
42
|
-
"type": "command",
|
|
43
|
-
"command": "\"${CLAUDE_PLUGIN_ROOT}/hooks/run-hook\" lock-gate",
|
|
44
|
-
"statusMessage": "Checking lock gate..."
|
|
45
|
-
}
|
|
46
|
-
]
|
|
47
|
-
},
|
|
48
|
-
{
|
|
49
|
-
"matcher": "Write|Edit",
|
|
50
|
-
"hooks": [
|
|
51
|
-
{
|
|
52
|
-
"type": "command",
|
|
53
|
-
"command": "\"${CLAUDE_PLUGIN_ROOT}/hooks/run-hook\" savepoint-pre",
|
|
54
|
-
"statusMessage": "Recording stage start..."
|
|
55
|
-
},
|
|
56
|
-
{
|
|
57
|
-
"type": "command",
|
|
58
|
-
"command": "\"${CLAUDE_PLUGIN_ROOT}/hooks/run-hook\" links-gate",
|
|
59
|
-
"statusMessage": "Checking Links gate..."
|
|
60
|
-
}
|
|
61
|
-
]
|
|
62
|
-
},
|
|
63
|
-
{
|
|
64
|
-
"matcher": "Write|Edit|mcp__serena__replace_content|mcp__serena__replace_symbol_body|mcp__serena__insert_after_symbol|mcp__serena__insert_before_symbol|mcp__serena__safe_delete_symbol|mcp__serena__rename_symbol",
|
|
65
|
-
"hooks": [
|
|
66
|
-
{
|
|
67
|
-
"type": "command",
|
|
68
|
-
"command": "\"${CLAUDE_PLUGIN_ROOT}/hooks/run-hook\" create-gate",
|
|
69
|
-
"statusMessage": "Checking create gate..."
|
|
38
|
+
"command": "\"${CLAUDE_PLUGIN_ROOT}/hooks/run-hook\" edit-gates",
|
|
39
|
+
"statusMessage": "Checking Plastic gates..."
|
|
70
40
|
}
|
|
71
41
|
]
|
|
72
42
|
},
|
|
@@ -79,16 +49,6 @@
|
|
|
79
49
|
"statusMessage": "Checking lifecycle gate..."
|
|
80
50
|
}
|
|
81
51
|
]
|
|
82
|
-
},
|
|
83
|
-
{
|
|
84
|
-
"matcher": "Bash|Read|Grep|Glob",
|
|
85
|
-
"hooks": [
|
|
86
|
-
{
|
|
87
|
-
"type": "command",
|
|
88
|
-
"command": "\"${CLAUDE_PLUGIN_ROOT}/hooks/run-hook\" retrieval-gate",
|
|
89
|
-
"statusMessage": "Checking retrieval gate..."
|
|
90
|
-
}
|
|
91
|
-
]
|
|
92
52
|
}
|
|
93
53
|
],
|
|
94
54
|
"PostToolUse": [
|
|
@@ -139,8 +99,8 @@
|
|
|
139
99
|
"hooks": [
|
|
140
100
|
{
|
|
141
101
|
"type": "command",
|
|
142
|
-
"command": "\"${CLAUDE_PLUGIN_ROOT}/hooks/run-hook\"
|
|
143
|
-
"statusMessage": "
|
|
102
|
+
"command": "\"${CLAUDE_PLUGIN_ROOT}/hooks/run-hook\" power-tools",
|
|
103
|
+
"statusMessage": "Checking power tools..."
|
|
144
104
|
}
|
|
145
105
|
]
|
|
146
106
|
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# power-tools mandate hook launcher (intents 66, 66b, 187, 246). No-op when there is no global store.
|
|
3
|
+
GLOBAL_INDEX="$HOME/.plastic/INDEX.md"
|
|
4
|
+
if [ ! -f "$GLOBAL_INDEX" ]; then
|
|
5
|
+
exit 0
|
|
6
|
+
fi
|
|
7
|
+
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
8
|
+
exec ruby "$SCRIPT_DIR/../scripts/hook-power-tools"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zalom/plastic",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.9.0",
|
|
4
4
|
"description": "Intent-driven idea development system for AI coding agents",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -38,7 +38,6 @@
|
|
|
38
38
|
"agents/",
|
|
39
39
|
"templates/",
|
|
40
40
|
"PLASTIC.md",
|
|
41
|
-
"PLASTIC-reference.md",
|
|
42
41
|
"deprecations.yml"
|
|
43
42
|
]
|
|
44
43
|
}
|
package/scripts/codex-hook
CHANGED
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
# Usage: codex-hook <gate>
|
|
6
6
|
# file-mutation gates: code-gate | lock-gate | savepoint-pre | gate-check | create-gate | links-gate
|
|
7
7
|
# live-state hooks (intent 199): session-start | check-update | continue |
|
|
8
|
-
# future-intent-check | auto-arm |
|
|
9
|
-
# shell-tool
|
|
8
|
+
# future-intent-check | auto-arm | power-tools | savepoint
|
|
9
|
+
# shell-tool gate (intent 203): bash-gate
|
|
10
10
|
#
|
|
11
11
|
# The Codex input adapter (intent 102, extended by 199 and 203). Reads a Codex
|
|
12
12
|
# hook stdin payload once. Three shapes exist and the gate name alone selects
|
|
@@ -20,17 +20,17 @@
|
|
|
20
20
|
# that hook (hooks/<name>), which is already harness-agnostic (resolves
|
|
21
21
|
# ~/.plastic off $HOME, reads only the common stdin fields the guide confirms
|
|
22
22
|
# Codex shares with Claude for these three events), so the body is reused, not
|
|
23
|
-
# rewritten (D3). The shell-tool
|
|
24
|
-
#
|
|
25
|
-
#
|
|
23
|
+
# rewritten (D3). The shell-tool gate (bash-gate) reports tool_name: "Bash" with
|
|
24
|
+
# the command in tool_input.command, but MUST NOT be routed through
|
|
25
|
+
# ApplyPatchEnvelope.parse below: a plain shell command has no
|
|
26
26
|
# *** Begin Patch/*** End Patch envelope, so it would parse to an empty op list
|
|
27
27
|
# and hit this file's own `exit 0 if ops.empty?` line, silently allowing every
|
|
28
|
-
# Bash call and reopening the exact hole intent 203 closes. So
|
|
29
|
-
#
|
|
30
|
-
#
|
|
31
|
-
#
|
|
32
|
-
#
|
|
33
|
-
#
|
|
28
|
+
# Bash call and reopening the exact hole intent 203 closes. So it execs the SAME
|
|
29
|
+
# scripts/hook-bash-gate file Claude already runs, unmodified, the identical
|
|
30
|
+
# "drive the body, relay its output" pattern used for the live-state hooks. The
|
|
31
|
+
# one adaptation shared by both the live-state and shell-tool paths is threading
|
|
32
|
+
# the payload's session_id into CLAUDE_CODE_SESSION_ID, since Codex's own
|
|
33
|
+
# process env never carries it, plus
|
|
34
34
|
# a bounded timeout: hooks/check-update backgrounds a real npm network call
|
|
35
35
|
# without redirecting its output away from the inherited stdout/stderr pipes,
|
|
36
36
|
# and Codex invokes hooks synchronously, so without a bound a slow network call
|
|
@@ -50,9 +50,9 @@ require_relative "lib/links_gate"
|
|
|
50
50
|
# caller that merges the dispatcher's own stdout and stderr.
|
|
51
51
|
$stdout.sync = true
|
|
52
52
|
|
|
53
|
-
STATE_HOOKS = %w[session-start check-update continue future-intent-check auto-arm
|
|
53
|
+
STATE_HOOKS = %w[session-start check-update continue future-intent-check auto-arm power-tools savepoint].freeze
|
|
54
54
|
STATE_TIMEOUT = 5
|
|
55
|
-
SHELL_HOOKS = %w[bash-gate
|
|
55
|
+
SHELL_HOOKS = %w[bash-gate].freeze
|
|
56
56
|
|
|
57
57
|
gate = ARGV[0].to_s
|
|
58
58
|
raw = ($stdin.read rescue nil)
|
|
@@ -78,20 +78,15 @@ if STATE_HOOKS.include?(gate)
|
|
|
78
78
|
end
|
|
79
79
|
|
|
80
80
|
if SHELL_HOOKS.include?(gate)
|
|
81
|
-
# bash-gate
|
|
82
|
-
#
|
|
83
|
-
#
|
|
84
|
-
#
|
|
85
|
-
# ApplyPatchEnvelope.parse below (see header comment).
|
|
81
|
+
# bash-gate (intent 203): a shell command has no apply_patch diff envelope, so
|
|
82
|
+
# this branch execs the SAME scripts/hook-bash-gate file Claude already runs,
|
|
83
|
+
# unmodified, and relays its exit code and stderr. It must never fall through
|
|
84
|
+
# to ApplyPatchEnvelope.parse below (see header comment).
|
|
86
85
|
cwd = payload["cwd"].to_s
|
|
87
86
|
cwd = Dir.pwd if cwd.empty? || !Dir.exist?(cwd)
|
|
88
87
|
env = { "CLAUDE_CODE_SESSION_ID" => (session.empty? ? nil : session) }
|
|
89
88
|
script = File.join(__dir__, "hook-#{gate}")
|
|
90
89
|
argv = [script]
|
|
91
|
-
# hook-retrieval-gate reads plastic_home off ARGV[0] (mirrors hooks/retrieval-gate's
|
|
92
|
-
# own launcher, which passes "$HOME/.plastic"); hook-bash-gate takes no args, it
|
|
93
|
-
# resolves Dir.home directly.
|
|
94
|
-
argv << ENV.fetch("PLASTIC_HOME") { File.join(Dir.home, ".plastic") } if gate == "retrieval-gate"
|
|
95
90
|
out, err, status = begin
|
|
96
91
|
Timeout.timeout(STATE_TIMEOUT) { Open3.capture3(env, RbConfig.ruby, *argv, stdin_data: raw, chdir: cwd) }
|
|
97
92
|
rescue StandardError
|