@zalom/plastic 2.0.0-alpha.8 → 2.0.1
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 +13 -136
- package/README.md +357 -133
- package/agents/plastic-enforcer.md +20 -15
- package/agents/plastic-executor.md +15 -4
- package/agents/plastic-node-research.md +30 -0
- package/agents/plastic-node-verify.md +28 -0
- package/agents/plastic-node-work.md +33 -0
- package/agents/{plastic-advisor.md → plastic-primary-advisor.md} +7 -9
- package/agents/{plastic-faux-advisor.md → plastic-secondary-advisor.md} +9 -12
- package/assets/plastic-logo.svg +1 -0
- package/bin/crap +4 -0
- package/bin/lib/context_budget.rb +43 -6
- package/bin/lib/skill_census.rb +839 -0
- package/bin/plastic +6 -0
- package/bin/plastic-skill-census +114 -0
- package/bin/test +24 -4
- package/bin/verify-change +345 -0
- package/config_asks.yml +4 -4
- package/deprecations.yml +1 -1
- package/{skills/agent-advisor/references → docs/help}/advisor-protocol.md +19 -24
- package/{skills/auto/references → docs/help}/agent-architecture.md +16 -14
- package/{skills/conventions/references → docs/help}/completion-and-done.md +15 -16
- package/docs/help/human-report-contract.md +152 -0
- package/{skills/conventions/references → docs/help}/knowledge-graph.md +9 -0
- package/{skills/conventions/references → docs/help}/locks-and-worktrees.md +23 -13
- package/{skills/conventions/references → docs/help}/maintenance-and-revisions.md +1 -1
- package/{skills/conventions/references → docs/help}/roadmaps.md +2 -2
- package/{skills/tutorial/references → docs/help}/track-1-guided.md +28 -47
- package/{skills/tutorial/references → docs/help}/track-2-auto.md +8 -8
- package/{skills/tutorial/references → docs/help}/track-3-projects-and-roadmaps.md +24 -17
- package/hooks/call-budget +4 -0
- package/hooks/hooks.json +24 -0
- package/hooks/message-display +62 -1
- package/hooks/session-start +5 -1
- package/hooks/statusline +32 -27
- package/hooks/stop +5 -0
- package/package.json +5 -3
- package/scripts/append-ledger +2 -1
- package/scripts/dashboard.rb +267 -16
- package/scripts/day-summary +2 -1
- package/scripts/doctor.rb +680 -39
- package/scripts/end-intent +238 -22
- package/scripts/exec-worktree +5 -5
- package/scripts/file-session-intent +2 -1
- package/scripts/graph-measure +249 -0
- package/scripts/hook-call-budget +222 -0
- package/scripts/hook-capture +24 -123
- package/scripts/hook-close +2 -1
- package/scripts/hook-message-display +19 -5
- package/scripts/hook-record +24 -16
- package/scripts/hook-savepoint +27 -3
- package/scripts/hook-session-start +359 -321
- package/scripts/hook-stop +58 -0
- package/scripts/index-projection +74 -0
- package/scripts/insight-append +17 -4
- package/scripts/install.rb +9 -7
- package/scripts/lib/action_graph_shim.rb +279 -0
- package/scripts/lib/active_delivery.rb +105 -0
- package/scripts/lib/agent_models.rb +63 -25
- package/scripts/lib/arm.rb +48 -83
- package/scripts/lib/atomic_write.rb +31 -0
- package/scripts/lib/backup.rb +65 -0
- package/scripts/lib/cli/command.rb +92 -0
- package/scripts/lib/cli/commands/auto.rb +18 -0
- package/scripts/lib/cli/commands/auto_brief.rb +44 -0
- package/scripts/lib/cli/commands/auto_lock.rb +99 -0
- package/scripts/lib/cli/commands/auto_report.rb +50 -0
- package/scripts/lib/cli/commands/auto_take.rb +31 -0
- package/scripts/lib/cli/commands/backup.rb +43 -0
- package/scripts/lib/cli/commands/checkout.rb +25 -0
- package/scripts/lib/cli/commands/continue.rb +66 -0
- package/scripts/lib/cli/commands/doctor.rb +81 -0
- package/scripts/lib/cli/commands/feedback.rb +40 -0
- package/scripts/lib/cli/commands/help.rb +69 -0
- package/scripts/lib/cli/commands/hook.rb +32 -0
- package/scripts/lib/cli/commands/index.rb +23 -0
- package/scripts/lib/cli/commands/install.rb +21 -0
- package/scripts/lib/cli/commands/installer_verb.rb +37 -0
- package/scripts/lib/cli/commands/intent.rb +19 -0
- package/scripts/lib/cli/commands/intent_answer.rb +37 -0
- package/scripts/lib/cli/commands/intent_command.rb +53 -0
- package/scripts/lib/cli/commands/intent_end.rb +62 -0
- package/scripts/lib/cli/commands/intent_new.rb +62 -0
- package/scripts/lib/cli/commands/intent_note.rb +43 -0
- package/scripts/lib/cli/commands/intent_rule.rb +36 -0
- package/scripts/lib/cli/commands/intent_show.rb +32 -0
- package/scripts/lib/cli/commands/intent_spec.rb +44 -0
- package/scripts/lib/cli/commands/intent_step.rb +71 -0
- package/scripts/lib/cli/commands/intent_verify.rb +26 -0
- package/scripts/lib/cli/commands/migrate.rb +16 -0
- package/scripts/lib/cli/commands/migrate_stores.rb +31 -0
- package/scripts/lib/cli/commands/next.rb +54 -0
- package/scripts/lib/cli/commands/project.rb +19 -0
- package/scripts/lib/cli/commands/project_links.rb +42 -0
- package/scripts/lib/cli/commands/project_list.rb +20 -0
- package/scripts/lib/cli/commands/project_new.rb +72 -0
- package/scripts/lib/cli/commands/query.rb +31 -0
- package/scripts/lib/cli/commands/render.rb +33 -0
- package/scripts/lib/cli/commands/roadmap.rb +19 -0
- package/scripts/lib/cli/commands/roadmap_check.rb +54 -0
- package/scripts/lib/cli/commands/roadmap_log.rb +54 -0
- package/scripts/lib/cli/commands/roadmap_migrate.rb +53 -0
- package/scripts/lib/cli/commands/roadmap_next.rb +70 -0
- package/scripts/lib/cli/commands/roadmap_show.rb +45 -0
- package/scripts/lib/cli/commands/rollback.rb +20 -0
- package/scripts/lib/cli/commands/search.rb +60 -0
- package/scripts/lib/cli/commands/session.rb +18 -0
- package/scripts/lib/cli/commands/session_commit.rb +42 -0
- package/scripts/lib/cli/commands/session_handoff.rb +34 -0
- package/scripts/lib/cli/commands/session_summary.rb +35 -0
- package/scripts/lib/cli/commands/status.rb +68 -0
- package/scripts/lib/cli/commands/subcommand_list.rb +36 -0
- package/scripts/lib/cli/commands/sync.rb +46 -0
- package/scripts/lib/cli/commands/uninstall.rb +20 -0
- package/scripts/lib/cli/commands/update.rb +20 -0
- package/scripts/lib/cli/commands/version.rb +53 -0
- package/scripts/lib/cli/frontier.rb +86 -0
- package/scripts/lib/cli/intent_progress.rb +36 -0
- package/scripts/lib/cli/legacy.rb +80 -0
- package/scripts/lib/cli/output.rb +137 -0
- package/scripts/lib/cli/scope.rb +134 -0
- package/scripts/lib/cli/table.rb +65 -0
- package/scripts/lib/cli.rb +94 -0
- package/scripts/lib/codex_adapter.rb +198 -0
- package/scripts/lib/compact_instructions.rb +13 -5
- package/scripts/lib/core_integrity.rb +71 -0
- package/scripts/lib/dashboard_screen.rb +40 -0
- package/scripts/lib/data_boundary.rb +132 -0
- package/scripts/lib/day_summary.rb +30 -16
- package/scripts/lib/doctor_core.rb +114 -38
- package/scripts/lib/doctor_session_ledger.rb +5 -53
- package/scripts/lib/engine_permissions.rb +88 -0
- package/scripts/lib/exec_worktree.rb +24 -21
- package/scripts/lib/feedback_report.rb +1 -1
- package/scripts/lib/graph_edges.rb +137 -0
- package/scripts/lib/graph_file.rb +246 -0
- package/scripts/lib/graph_measure.rb +645 -0
- package/scripts/lib/graph_measure_budget.rb +409 -0
- package/scripts/lib/graph_measure_cohorts.rb +487 -0
- package/scripts/lib/graph_measure_models.rb +413 -0
- package/scripts/lib/graph_measure_report.rb +532 -0
- package/scripts/lib/graph_tree.rb +98 -0
- package/scripts/lib/guarded_append.rb +155 -0
- package/scripts/lib/handoff.rb +40 -13
- package/scripts/lib/harness_adapter.rb +184 -0
- package/scripts/lib/hook_registry.rb +27 -3
- package/scripts/lib/hook_replay.rb +229 -0
- package/scripts/lib/index_entry.rb +62 -0
- package/scripts/lib/index_projection.rb +201 -0
- package/scripts/lib/insights.rb +1 -1
- package/scripts/lib/installer_core.rb +532 -71
- package/scripts/lib/intent_screen.rb +9 -6
- package/scripts/lib/intent_screen_ansi.rb +73 -12
- package/scripts/lib/intent_validator.rb +2 -2
- package/scripts/lib/lock.rb +10 -11
- package/scripts/lib/message_display.rb +377 -173
- package/scripts/lib/meter_watch.rb +185 -0
- package/scripts/lib/node_file.rb +234 -0
- package/scripts/lib/node_ids.rb +99 -0
- package/scripts/lib/node_input.rb +913 -0
- package/scripts/lib/node_input_compatibility.rb +62 -0
- package/scripts/lib/node_ledger.rb +386 -0
- package/scripts/lib/node_progress.rb +153 -0
- package/scripts/lib/node_return.rb +204 -0
- package/scripts/lib/node_worktree.rb +337 -0
- package/scripts/lib/outcome_report.rb +440 -0
- package/scripts/lib/preflight.rb +4 -6
- package/scripts/lib/project_config.rb +46 -0
- package/scripts/lib/project_validator.rb +3 -2
- package/scripts/lib/qmd_sync.rb +8 -7
- package/scripts/lib/ready_set.rb +462 -0
- package/scripts/lib/reference_archive.rb +45 -0
- package/scripts/lib/release_guard.rb +18 -0
- package/scripts/lib/report_screen.rb +1460 -74
- package/scripts/lib/rlm/corpus.rb +13 -0
- package/scripts/lib/rlm/probe.rb +29 -0
- package/scripts/lib/rlm/query.rb +22 -0
- package/scripts/lib/roadmap_graph.rb +210 -0
- package/scripts/lib/roadmap_migration.rb +95 -0
- package/scripts/lib/roadmap_queue.rb +158 -8
- package/scripts/lib/roadmap_render.rb +150 -0
- package/scripts/lib/roadmap_savepoint.rb +64 -14
- package/scripts/lib/runner_absorb.rb +703 -0
- package/scripts/lib/runner_answer.rb +206 -0
- package/scripts/lib/runner_core.rb +194 -0
- package/scripts/lib/runner_dispatch.rb +525 -0
- package/scripts/lib/runner_policy.rb +191 -0
- package/scripts/lib/runner_proposals.rb +275 -0
- package/scripts/lib/runner_rewind.rb +201 -0
- package/scripts/lib/runner_sweep.rb +231 -0
- package/scripts/lib/runner_until_empty.rb +252 -0
- package/scripts/lib/runner_watch.rb +389 -0
- package/scripts/lib/savepoint.rb +141 -19
- package/scripts/lib/scaffold_intent.rb +6 -3
- 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/search_index.rb +55 -0
- package/scripts/lib/session_close.rb +30 -28
- package/scripts/lib/session_git.rb +25 -18
- package/scripts/lib/session_ledger.rb +48 -4
- package/scripts/lib/session_usage.rb +190 -0
- package/scripts/lib/sqlite.rb +22 -0
- package/scripts/lib/stop_gate.rb +95 -0
- package/scripts/lib/store_discovery.rb +7 -6
- package/scripts/lib/store_layout.rb +54 -0
- package/scripts/lib/store_provisioning.rb +2 -1
- package/scripts/lib/store_sync.rb +85 -0
- package/scripts/lib/stores_move.rb +93 -0
- package/scripts/lib/verify_intent.rb +36 -8
- package/scripts/lib/version_number.rb +48 -0
- package/scripts/lib/work_graph.rb +59 -0
- package/scripts/lib/work_graph_validator.rb +201 -0
- package/scripts/lib/worktree.rb +27 -32
- package/scripts/lib/worktree_sweep.rb +6 -5
- package/scripts/link-suggest +2 -1
- package/scripts/meter-watch +57 -0
- package/scripts/migrate-to-global +1 -1
- package/scripts/new-intent +4 -13
- package/scripts/node-input +92 -0
- package/scripts/node-run +225 -0
- package/scripts/node-transition +291 -0
- package/scripts/outcome-report +74 -0
- package/scripts/plastic-lock +42 -33
- package/scripts/promote-session-item +3 -2
- package/scripts/read-config +53 -9
- package/scripts/ready-set +126 -0
- package/scripts/release-check +123 -0
- package/scripts/report-screen +192 -30
- package/scripts/roadmap-graph +119 -0
- package/scripts/roadmap-savepoint +7 -0
- package/scripts/runner +581 -0
- package/scripts/savepoint-note +11 -9
- package/scripts/session-commit +2 -1
- package/scripts/session-usage +56 -0
- package/scripts/skill-lint +115 -6
- package/scripts/spawn-preamble +2 -2
- package/scripts/update.rb +25 -4
- package/scripts/validate-work-graph +39 -0
- package/scripts/verify-intent +3 -2
- package/scripts/write-handoff +2 -1
- package/templates/agents.md +7 -7
- package/templates/config.yml +16 -9
- package/templates/dashboard-screen.md +22 -0
- package/templates/display-fixture.md +21 -0
- package/templates/graph.md +16 -0
- package/templates/index.md +1 -1
- package/templates/intent-screen.md +1 -1
- package/templates/node-decision.md +11 -0
- package/templates/node-research.md +13 -0
- package/templates/node-verify.md +13 -0
- package/templates/node-work.md +22 -0
- package/templates/outcome.md +15 -2
- package/templates/project.yml +1 -1
- package/templates/render.css +10 -0
- 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 +1 -1
- package/templates/roadmap.md +13 -0
- package/bin/plastic.js +0 -70
- package/scripts/lib/bridge.rb +0 -116
- package/skills/agent-advisor/SKILL.md +0 -92
- package/skills/auto/SKILL.md +0 -295
- package/skills/auto/evals/evals.json +0 -255
- package/skills/auto/references/end-tail.md +0 -66
- package/skills/auto/references/human-report-contract.md +0 -78
- package/skills/conventions/SKILL.md +0 -29
- package/skills/dashboard/SKILL.md +0 -169
- package/skills/dashboard/evals/evals.json +0 -38
- package/skills/dashboard/references/classification.md +0 -22
- package/skills/dashboard/templates/dashboard-global.md +0 -20
- package/skills/dashboard/templates/dashboard-project.md +0 -19
- package/skills/direct/SKILL.md +0 -66
- package/skills/direct/references/request-signals.md +0 -59
- package/skills/doctor/SKILL.md +0 -299
- package/skills/doctor/report.md +0 -102
- package/skills/feedback/SKILL.md +0 -98
- package/skills/feedback/references/transport-and-privacy.md +0 -65
- package/skills/feedback/report.md +0 -36
- package/skills/install/SKILL.md +0 -217
- package/skills/intent-continuing/SKILL.md +0 -154
- package/skills/intent-continuing/references/board-fill.md +0 -43
- package/skills/intent-continuing/references/boarding-matrix.md +0 -34
- package/skills/intent-continuing/references/context-management.md +0 -28
- package/skills/intent-continuing/references/liveness-ranking.md +0 -57
- package/skills/intent-creating/SKILL.md +0 -164
- package/skills/intent-creating/evals/evals.json +0 -72
- package/skills/intent-creating/references/lifecycle.md +0 -81
- package/skills/intent-creating/references/wikilinks.md +0 -8
- package/skills/intent-ending/SKILL.md +0 -173
- package/skills/intent-ending/evals/evals.json +0 -74
- package/skills/intent-executing/SKILL.md +0 -170
- package/skills/intent-executing/evals/evals.json +0 -66
- package/skills/intent-executing/implementer-prompt.md +0 -42
- package/skills/intent-executing/spec-reviewer-prompt.md +0 -27
- package/skills/intent-speccing/SKILL.md +0 -130
- package/skills/intent-speccing/evals/evals.json +0 -126
- package/skills/intent-speccing/references/design-principles.md +0 -44
- package/skills/intent-speccing/references/per-section-fill-rules.md +0 -92
- package/skills/intent-speccing/references/self-verify-checklist.md +0 -37
- package/skills/project-creating/SKILL.md +0 -162
- package/skills/project-creating/references/hubs-projects.md +0 -55
- package/skills/project-creating/references/project-scaffolding.md +0 -97
- package/skills/releasing/SKILL.md +0 -337
- package/skills/releasing/references/deprecations.md +0 -60
- package/skills/releasing/references/promotion-and-tagging.md +0 -66
- package/skills/releasing/references/release-lines.md +0 -105
- package/skills/roadmap/SKILL.md +0 -64
- package/skills/roadmap/references/file-format.md +0 -124
- package/skills/roadmap/references/operations.md +0 -112
- package/skills/rollback/SKILL.md +0 -91
- package/skills/tutorial/SKILL.md +0 -65
- package/skills/tutorial/evals/evals.json +0 -186
- package/skills/uninstall/SKILL.md +0 -75
- package/skills/update/SKILL.md +0 -126
- /package/{skills/auto/references → docs/help}/agent-report-contract.md +0 -0
- /package/{skills/intent-executing → docs/help}/code-quality-reviewer-prompt.md +0 -0
- /package/{skills/conventions/references → docs/help}/lifecycle-and-savepoints.md +0 -0
- /package/{skills/intent-executing → docs/help}/plan-reviewer-prompt.md +0 -0
|
@@ -9,7 +9,7 @@ will exist with more than one intent inside it and a roadmap file describing the
|
|
|
9
9
|
|
|
10
10
|
## Before you start
|
|
11
11
|
|
|
12
|
-
Run
|
|
12
|
+
Run `plastic update` first, so the commands below match what is
|
|
13
13
|
actually installed.
|
|
14
14
|
|
|
15
15
|
Work in a sandbox: this whole track is a walked example. It creates a real project directory
|
|
@@ -20,11 +20,11 @@ one this tutorial keeps or ships.
|
|
|
20
20
|
|
|
21
21
|
### 1. Start from a founding implementation intent
|
|
22
22
|
|
|
23
|
-
Create and board an intent the same way as track 1, stations 1 and 2:
|
|
24
|
-
then
|
|
23
|
+
Create and board an intent the same way as track 1, stations 1 and 2: `plastic intent new`,
|
|
24
|
+
then `plastic continue`. Describe something meant to grow into a small real project,
|
|
25
25
|
for example "build a personal todo app."
|
|
26
26
|
|
|
27
|
-
Then type
|
|
27
|
+
Then type `plastic intent spec` and record a couple of real rulings on this founding
|
|
28
28
|
intent, for example the language or how tasks get stored. Keep it short: this intent only
|
|
29
29
|
needs enough decisions for the new project to inherit, not a full design.
|
|
30
30
|
|
|
@@ -33,17 +33,21 @@ into a whole new project.
|
|
|
33
33
|
|
|
34
34
|
### 2. Grow it into a project
|
|
35
35
|
|
|
36
|
-
|
|
36
|
+
Make the project directory yourself and write its `AGENTS.md`, carrying forward at least one
|
|
37
|
+
decision from the founding intent. Plastic does not create the directory or fill that file;
|
|
38
|
+
that is ordinary agent work, done once, before the project exists. Once the directory exists,
|
|
39
|
+
run `plastic project new SLUG --path PATH` to register it in `projects.yml` and provision and
|
|
40
|
+
validate its store.
|
|
37
41
|
|
|
38
|
-
Artifact: a new project directory
|
|
39
|
-
|
|
42
|
+
Artifact: a new project directory with its `AGENTS.md`, the project's own intent store, and a
|
|
43
|
+
new entry in `projects.yml` registering it.
|
|
40
44
|
|
|
41
45
|
Checkpoint: open `AGENTS.md` and find at least one line that traces back to a decision
|
|
42
46
|
recorded in the founding intent back in station 1.
|
|
43
47
|
|
|
44
48
|
### 3. Add more intents inside the project
|
|
45
49
|
|
|
46
|
-
|
|
50
|
+
Run `plastic intent new` at least twice, from inside the project, describing two
|
|
47
51
|
pieces of real work, for example "add a task list model" and "add a due date field."
|
|
48
52
|
|
|
49
53
|
Artifact: two or more intent directories inside the project's own store, separate from the
|
|
@@ -54,13 +58,16 @@ in the global store.
|
|
|
54
58
|
|
|
55
59
|
### 4. Plan a delivery batch
|
|
56
60
|
|
|
57
|
-
|
|
61
|
+
Copy `templates/roadmap.md` to `roadmaps/<slug>.md`, next to the project's `INDEX.md`, and fill
|
|
62
|
+
it by hand: a title and short meta header, a `## Goal` section in prose describing what "done"
|
|
63
|
+
looks like for the whole batch, a `## Batches` section (an ordered list of groups of intents;
|
|
64
|
+
intents inside one batch are safe to run in parallel, batches themselves run one after another),
|
|
65
|
+
and an append-only, dated `## Log`. `INDEX.md` stays the single source of truth for each
|
|
66
|
+
intent's status; the roadmap only mirrors it. List the two or more intents from station 3
|
|
67
|
+
across one or more batches.
|
|
58
68
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
ordered list of groups of intents; intents inside one batch are safe to run in parallel,
|
|
62
|
-
batches themselves run one after another), and an append-only, dated `## Log`. `INDEX.md`
|
|
63
|
-
stays the single source of truth for each intent's status; the roadmap only mirrors it.
|
|
69
|
+
Run `plastic roadmap check <slug>` to confirm the file parses, then `plastic roadmap show
|
|
70
|
+
<slug>` to see it rendered as a report.
|
|
64
71
|
|
|
65
72
|
Artifact: a new `roadmaps/<slug>.md` file, sitting next to the project's `INDEX.md`, listing
|
|
66
73
|
the two or more intents from station 3 across one or more batches.
|
|
@@ -93,8 +100,8 @@ sections you turned into the condition above.
|
|
|
93
100
|
|
|
94
101
|
No command run here; describe the step instead. Each delivered intent's code merges to main
|
|
95
102
|
as it lands. When the batch (or a meaningful slice of it) is ready to ship, cutting a release
|
|
96
|
-
|
|
97
|
-
intents it collects.
|
|
103
|
+
is a push to `alpha`, `beta`, or `main`: the version files are bumped in that push, and CI
|
|
104
|
+
tags, publishes, and completes the intents it collects.
|
|
98
105
|
|
|
99
106
|
Releases and any npm publish step are described here, not run: this walkthrough stays in a
|
|
100
107
|
sandbox and never touches a real package registry.
|
|
@@ -108,4 +115,4 @@ This is the same What, Why, How, Exec cycle from tracks 1 and 2, repeated across
|
|
|
108
115
|
and gathered by a roadmap. Read
|
|
109
116
|
[`using-plastic-with-claude-code.md`](https://github.com/zalom/plastic/blob/main/docs/guides/using-plastic-with-claude-code.md) for roadmap-driven delivery in more depth,
|
|
110
117
|
including a real worked roadmap. For the exact roadmap file format beyond what this
|
|
111
|
-
walkthrough covers,
|
|
118
|
+
walkthrough covers, [`docs/help/roadmaps.md`](roadmaps.md) is the reference.
|
package/hooks/hooks.json
CHANGED
|
@@ -17,6 +17,18 @@
|
|
|
17
17
|
]
|
|
18
18
|
}
|
|
19
19
|
],
|
|
20
|
+
"PreToolUse": [
|
|
21
|
+
{
|
|
22
|
+
"matcher": "",
|
|
23
|
+
"hooks": [
|
|
24
|
+
{
|
|
25
|
+
"type": "command",
|
|
26
|
+
"command": "\"${CLAUDE_PLUGIN_ROOT}/hooks/run-hook\" call-budget",
|
|
27
|
+
"statusMessage": ""
|
|
28
|
+
}
|
|
29
|
+
]
|
|
30
|
+
}
|
|
31
|
+
],
|
|
20
32
|
"PreCompact": [
|
|
21
33
|
{
|
|
22
34
|
"matcher": "",
|
|
@@ -76,6 +88,18 @@
|
|
|
76
88
|
}
|
|
77
89
|
]
|
|
78
90
|
}
|
|
91
|
+
],
|
|
92
|
+
"Stop": [
|
|
93
|
+
{
|
|
94
|
+
"matcher": "",
|
|
95
|
+
"hooks": [
|
|
96
|
+
{
|
|
97
|
+
"type": "command",
|
|
98
|
+
"command": "\"${CLAUDE_PLUGIN_ROOT}/hooks/run-hook\" stop",
|
|
99
|
+
"statusMessage": ""
|
|
100
|
+
}
|
|
101
|
+
]
|
|
102
|
+
}
|
|
79
103
|
]
|
|
80
104
|
}
|
|
81
105
|
}
|
package/hooks/message-display
CHANGED
|
@@ -49,8 +49,26 @@ if [ "$is_index_zero" = 1 ]; then
|
|
|
49
49
|
# single "#", not "##" — a real screen's own first delta can be as short
|
|
50
50
|
# as "## " — a "##" glob would filter out exactly the message this hook
|
|
51
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.
|
|
52
56
|
case $INPUT in
|
|
53
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 ;;
|
|
54
72
|
esac
|
|
55
73
|
else
|
|
56
74
|
# A later chunk: hand off when this message's directory already exists
|
|
@@ -62,12 +80,55 @@ else
|
|
|
62
80
|
[ "$is_final" = 1 ] && handoff=1
|
|
63
81
|
case $INPUT in
|
|
64
82
|
*'"delta":"|'*|*'"delta": "|'*) handoff=1 ;;
|
|
65
|
-
*'"delta":"**
|
|
83
|
+
*'"delta":"**'*|*'"delta": "**'*) handoff=1 ;;
|
|
66
84
|
*'"delta":""'*|*'"delta": ""'*) handoff=1 ;;
|
|
67
85
|
*'"delta":"\n"'*|*'"delta": "\n"'*) handoff=1 ;;
|
|
68
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
|
|
69
106
|
fi
|
|
70
107
|
|
|
71
108
|
[ "$handoff" = 1 ] || exit 0
|
|
72
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
|
+
|
|
73
134
|
printf '%s' "$INPUT" | env -u RUBYOPT ruby "$SCRIPT_DIR/../scripts/hook-message-display"
|
package/hooks/session-start
CHANGED
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)
|
|
@@ -188,6 +187,7 @@ FIELDS=$(printf '%s' "$INPUT" | awk '
|
|
|
188
187
|
wanted["context_window.current_usage.cache_read_input_tokens"] = 1
|
|
189
188
|
wanted["cost.total_cost_usd"] = 1
|
|
190
189
|
wanted["rate_limits.five_hour.used_percentage"] = 1
|
|
190
|
+
wanted["rate_limits.five_hour.resets_at"] = 1
|
|
191
191
|
wanted["rate_limits.seven_day.used_percentage"] = 1
|
|
192
192
|
}
|
|
193
193
|
{ buf = buf $0 " " }
|
|
@@ -210,6 +210,7 @@ CU_CC=""
|
|
|
210
210
|
CU_CR=""
|
|
211
211
|
COST_RAW=""
|
|
212
212
|
M5_PCT=""
|
|
213
|
+
M5_RESETS=""
|
|
213
214
|
M7_PCT=""
|
|
214
215
|
|
|
215
216
|
while IFS=$'\t' read -r k v; do
|
|
@@ -225,6 +226,7 @@ while IFS=$'\t' read -r k v; do
|
|
|
225
226
|
context_window.current_usage.cache_read_input_tokens) CU_CR="$v" ;;
|
|
226
227
|
cost.total_cost_usd) COST_RAW="$v" ;;
|
|
227
228
|
rate_limits.five_hour.used_percentage) M5_PCT="$v" ;;
|
|
229
|
+
rate_limits.five_hour.resets_at) M5_RESETS="$v" ;;
|
|
228
230
|
rate_limits.seven_day.used_percentage) M7_PCT="$v" ;;
|
|
229
231
|
esac
|
|
230
232
|
done <<FIELDS_EOF
|
|
@@ -302,6 +304,31 @@ meter_seg() { # $1 = label, $2 = raw percentage
|
|
|
302
304
|
M5=$(meter_seg "5h" "$M5_PCT")
|
|
303
305
|
M7=$(meter_seg "7d" "$M7_PCT")
|
|
304
306
|
|
|
307
|
+
# --- Rate-limits cache for MeterWatch (graph.md D11) ---
|
|
308
|
+
# Written only when the payload carries a meter at all; an API-key session
|
|
309
|
+
# with no rate_limits section leaves the cache untouched. A present meter
|
|
310
|
+
# with no matching value writes null rather than dropping the key, so
|
|
311
|
+
# MeterWatch always sees the same three fields. Temp file in the cache
|
|
312
|
+
# directory, then mv, so MeterWatch never reads a half-written file.
|
|
313
|
+
if [ -n "$M5_PCT" ] || [ -n "$M7_PCT" ]; then
|
|
314
|
+
CACHE_DIR="$HOME/.plastic/.cache"
|
|
315
|
+
mkdir -p "$CACHE_DIR"
|
|
316
|
+
CACHE5=$(to_int "$M5_PCT")
|
|
317
|
+
CACHE7=$(to_int "$M7_PCT")
|
|
318
|
+
[ -z "$CACHE5" ] && CACHE5=null
|
|
319
|
+
[ -z "$CACHE7" ] && CACHE7=null
|
|
320
|
+
if [ -n "$M5_RESETS" ]; then
|
|
321
|
+
RESETS_JSON="\"$M5_RESETS\""
|
|
322
|
+
else
|
|
323
|
+
RESETS_JSON=null
|
|
324
|
+
fi
|
|
325
|
+
CACHE_AT=$(date -u +%Y-%m-%dT%H:%M:%SZ)
|
|
326
|
+
CACHE_TMP="$CACHE_DIR/.rate-limits.json.tmp.$$"
|
|
327
|
+
printf '{"five_hour":%s,"seven_day":%s,"resets_at":%s,"at":"%s"}\n' \
|
|
328
|
+
"$CACHE5" "$CACHE7" "$RESETS_JSON" "$CACHE_AT" > "$CACHE_TMP"
|
|
329
|
+
mv "$CACHE_TMP" "$CACHE_DIR/rate-limits.json"
|
|
330
|
+
fi
|
|
331
|
+
|
|
305
332
|
# --- Session cost (stdin cost.total_cost_usd); hidden when it renders as $0.00 ---
|
|
306
333
|
COST_SEG=""
|
|
307
334
|
if [ -n "$COST_RAW" ]; then
|
|
@@ -309,40 +336,18 @@ if [ -n "$COST_RAW" ]; then
|
|
|
309
336
|
[ -n "$COST_FMT" ] && [ "$COST_FMT" != "0.00" ] && COST_SEG="${C_COST}\$${COST_FMT}${RST}"
|
|
310
337
|
fi
|
|
311
338
|
|
|
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
339
|
# --- Assemble segments in order, joined by " . " ---
|
|
334
340
|
PARTS=""
|
|
335
341
|
add() { [ -z "$1" ] && return; if [ -z "$PARTS" ]; then PARTS="$1"; else PARTS="$PARTS$SEP$1"; fi; }
|
|
336
342
|
|
|
337
|
-
# Order: identity first (model), then this session's spend (context, meters, cost,
|
|
338
|
-
#
|
|
343
|
+
# Order: identity first (model), then this session's spend (context, meters, cost),
|
|
344
|
+
# then the volatile-length values last (version, path) so the line does
|
|
339
345
|
# not visually jump as they change.
|
|
340
346
|
[ -n "$MODEL" ] && add "${C_MODEL}${MODEL}${RST}"
|
|
341
347
|
add "$CTX_SEG"
|
|
342
348
|
add "$M5"
|
|
343
349
|
add "$M7"
|
|
344
350
|
add "$COST_SEG"
|
|
345
|
-
add "$CL_SEG"
|
|
346
351
|
if [ -n "$VERSION" ]; then
|
|
347
352
|
vseg="${C_VER}Plastic ${VERSION}${RST}"
|
|
348
353
|
[ -n "$NEXT" ] && vseg="${vseg}${C_VER} "$'\342\206\222'" ${RST}${C_NEXT}${NEXT}${RST}"
|
package/hooks/stop
ADDED
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zalom/plastic",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.1",
|
|
4
4
|
"description": "Intent-driven idea development system for AI coding agents",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
|
-
"plastic": "bin/plastic
|
|
7
|
+
"plastic": "bin/plastic"
|
|
8
8
|
},
|
|
9
9
|
"engines": {
|
|
10
10
|
"node": ">=18.0.0"
|
|
@@ -27,13 +27,15 @@
|
|
|
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": [
|
|
34
|
+
"assets/",
|
|
34
35
|
"bin/",
|
|
35
36
|
"scripts/",
|
|
36
37
|
"skills/",
|
|
38
|
+
"docs/help/",
|
|
37
39
|
"hooks/",
|
|
38
40
|
"agents/",
|
|
39
41
|
"templates/",
|
package/scripts/append-ledger
CHANGED
|
@@ -30,6 +30,7 @@
|
|
|
30
30
|
# 2 - usage error, or promote/tick found nothing to address (no write happens)
|
|
31
31
|
# 3 - promote/tick could not take an exclusive lock (filesystem without flock support)
|
|
32
32
|
|
|
33
|
+
require_relative "lib/store_layout"
|
|
33
34
|
require_relative "lib/session_ledger"
|
|
34
35
|
require_relative "lib/handoff"
|
|
35
36
|
|
|
@@ -162,7 +163,7 @@ def main(argv)
|
|
|
162
163
|
usage_abort("verb must be one of #{VERBS.join(", ")}, got #{opts[:verb].inspect}") unless VERBS.include?(opts[:verb])
|
|
163
164
|
|
|
164
165
|
plastic_home = expand(ENV.fetch("PLASTIC_HOME", "~/.plastic"))
|
|
165
|
-
store = opts[:store] ? expand(opts[:store]) :
|
|
166
|
+
store = opts[:store] ? expand(opts[:store]) : Plastic::StoreLayout.global_store(plastic_home)
|
|
166
167
|
templates = opts[:templates] ? expand(opts[:templates]) : default_templates_dir
|
|
167
168
|
usage_abort("templates dir not found: #{templates}") unless Dir.exist?(templates)
|
|
168
169
|
opts[:templates] = templates
|