@zalom/plastic 1.14.0 → 2.0.0-alpha.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 +101 -294
- package/README.md +5 -6
- package/agents/plastic-advisor.md +18 -17
- package/agents/plastic-enforcer.md +57 -69
- package/agents/plastic-executor.md +34 -20
- package/agents/plastic-faux-advisor.md +18 -18
- package/config_asks.yml +38 -0
- package/hooks/capture +4 -0
- package/hooks/check-update +12 -3
- package/hooks/close +5 -0
- package/hooks/hooks.json +9 -49
- package/hooks/record +4 -0
- package/package.json +3 -2
- package/scripts/agent-report +8 -9
- package/scripts/append-ledger +195 -0
- package/scripts/codex-hook +101 -95
- package/scripts/dashboard.rb +4 -4
- package/scripts/doctor.rb +106 -43
- package/scripts/end-intent +77 -76
- package/scripts/exec-worktree +11 -20
- package/scripts/file-session-intent +61 -0
- package/scripts/hook-capture +242 -0
- package/scripts/hook-close +34 -0
- package/scripts/hook-record +149 -0
- package/scripts/hook-session-start +95 -12
- package/scripts/install.rb +8 -6
- package/scripts/lib/agent_models.rb +1 -7
- package/scripts/lib/arm.rb +283 -0
- package/scripts/lib/backfill_intent.rb +316 -0
- package/scripts/lib/bridge.rb +24 -1597
- package/scripts/lib/doctor_core.rb +17 -88
- package/scripts/lib/doctor_session_ledger.rb +106 -0
- package/scripts/lib/exec_worktree.rb +14 -60
- package/scripts/lib/harness_text.rb +5 -4
- package/scripts/lib/hook_registry.rb +44 -107
- package/scripts/lib/insights.rb +3 -4
- package/scripts/lib/installer_core.rb +19 -30
- package/scripts/lib/lock.rb +6 -26
- package/scripts/lib/outcome_guard.rb +7 -5
- package/scripts/lib/project_validator.rb +30 -1
- package/scripts/lib/roadmap_queue.rb +3 -3
- package/scripts/lib/roadmap_savepoint.rb +1 -1
- package/scripts/lib/rule_catalog.rb +6 -3
- package/scripts/lib/savepoint.rb +320 -0
- package/scripts/lib/scaffold_intent.rb +13 -179
- package/scripts/lib/session_backfill.rb +184 -0
- package/scripts/lib/session_close.rb +84 -0
- package/scripts/lib/session_git.rb +469 -0
- package/scripts/lib/session_ledger.rb +497 -0
- package/scripts/lib/store_discovery.rb +1 -1
- package/scripts/lib/store_provisioning.rb +1 -1
- package/scripts/maintenance-run +7 -7
- package/scripts/new-intent +63 -4
- package/scripts/plastic-lock +94 -41
- package/scripts/promote-session-item +150 -0
- package/scripts/rebuild-graph +1 -1
- package/scripts/roadmap-next +2 -2
- package/scripts/rollback.rb +42 -3
- package/scripts/scaffold-intent +37 -63
- package/scripts/session-commit +116 -0
- package/scripts/spawn-preamble +5 -5
- package/scripts/update.rb +7 -3
- package/skills/agent-advisor/SKILL.md +3 -3
- package/skills/agent-advisor/references/advisor-protocol.md +20 -20
- package/skills/auto/SKILL.md +218 -317
- package/skills/auto/evals/evals.json +10 -10
- package/skills/auto/references/agent-architecture.md +102 -90
- package/skills/auto/references/agent-report-contract.md +4 -21
- package/skills/auto/references/end-tail.md +47 -53
- package/skills/auto/references/human-report-contract.md +8 -8
- package/skills/conventions/SKILL.md +1 -3
- package/skills/conventions/references/lifecycle-and-savepoints.md +35 -1
- package/skills/conventions/references/locks-and-worktrees.md +47 -55
- package/skills/conventions/references/maintenance-and-revisions.md +12 -12
- package/skills/dashboard/SKILL.md +1 -1
- package/skills/direct/SKILL.md +66 -0
- package/skills/direct/references/request-signals.md +59 -0
- package/skills/doctor/SKILL.md +58 -11
- package/skills/doctor/report.md +3 -1
- package/skills/install/SKILL.md +11 -9
- package/skills/intent-continuing/SKILL.md +131 -89
- package/skills/intent-continuing/references/boarding-matrix.md +34 -0
- package/skills/intent-continuing/references/context-management.md +2 -2
- package/skills/intent-creating/SKILL.md +2 -2
- package/skills/intent-creating/references/lifecycle.md +1 -1
- package/skills/intent-ending/SKILL.md +28 -37
- package/skills/intent-ending/evals/evals.json +4 -4
- package/skills/intent-executing/SKILL.md +12 -49
- package/skills/intent-executing/plan-reviewer-prompt.md +39 -0
- package/skills/intent-speccing/SKILL.md +108 -51
- package/skills/intent-speccing/evals/evals.json +5 -5
- package/skills/intent-speccing/references/per-section-fill-rules.md +4 -4
- package/skills/intent-speccing/references/self-verify-checklist.md +1 -2
- package/skills/project-creating/SKILL.md +1 -1
- package/skills/releasing/SKILL.md +7 -8
- package/skills/tutorial/SKILL.md +2 -2
- package/skills/tutorial/references/track-1-guided.md +16 -18
- package/skills/tutorial/references/track-2-auto.md +12 -13
- package/skills/tutorial/references/track-3-projects-and-roadmaps.md +2 -2
- package/templates/agents.md +4 -7
- package/templates/project.yml +7 -0
- package/templates/roadmap.md +1 -1
- package/templates/savepoint.md +2 -2
- package/templates/session-intent.md +29 -0
- package/agents/plastic-brainstorming.md +0 -48
- package/agents/plastic-future-intent-researcher.md +0 -35
- package/agents/plastic-intent-curator.md +0 -47
- package/agents/plastic-intent-discovery.md +0 -43
- package/agents/plastic-planner.md +0 -56
- package/agents/plastic-spec-specialist.md +0 -53
- package/hooks/auto-arm +0 -5
- package/hooks/bash-gate +0 -3
- package/hooks/continue +0 -31
- package/hooks/edit-gates +0 -3
- package/hooks/future-intent-check +0 -25
- package/hooks/gate-check +0 -12
- package/hooks/power-tools +0 -8
- package/scripts/hook-auto-arm +0 -51
- package/scripts/hook-bash-gate +0 -78
- package/scripts/hook-code-gate +0 -38
- package/scripts/hook-continue +0 -48
- package/scripts/hook-create-gate +0 -51
- package/scripts/hook-edit-gates +0 -58
- package/scripts/hook-future-intent-check +0 -90
- package/scripts/hook-gate-check +0 -169
- package/scripts/hook-links-gate +0 -54
- package/scripts/hook-lock-gate +0 -47
- package/scripts/hook-power-tools +0 -38
- package/scripts/hook-savepoint-pre +0 -32
- package/scripts/lib/codex_edit_gates.rb +0 -138
- package/scripts/lib/edit_gates.rb +0 -398
- package/scripts/lib/links_gate.rb +0 -140
- package/scripts/lib/qmd_hook.rb +0 -41
- package/scripts/lib/spec_header.rb +0 -83
- package/scripts/lib/start_intent.rb +0 -296
- package/scripts/start-intent +0 -89
- package/skills/_active-intent-gate.md +0 -26
- package/skills/auto/references/tiers.md +0 -100
- package/skills/continuing/SKILL.md +0 -34
- package/skills/continuing/evals/evals.json +0 -91
- package/skills/conventions/references/gates-and-enforcement.md +0 -53
- package/skills/conventions/references/tiers-and-dispatch.md +0 -135
- package/skills/doctor/references/gates-stuck-detection.md +0 -43
- package/skills/intent-brainstorming/SKILL.md +0 -118
- package/skills/intent-brainstorming/evals/evals.json +0 -67
- package/skills/intent-continuing/evals/evals.json +0 -145
- package/skills/intent-discovering/SKILL.md +0 -56
- package/skills/intent-grilling/SKILL.md +0 -108
- package/skills/intent-linking/SKILL.md +0 -128
- package/skills/intent-linking/evals/evals.json +0 -22
- package/skills/intent-linking/references/zettelkasten.md +0 -45
- package/skills/intent-locking/SKILL.md +0 -64
- package/skills/intent-planning/SKILL.md +0 -145
- package/skills/intent-planning/evals/evals.json +0 -81
- package/skills/intent-planning/references/plan-format.md +0 -130
- package/skills/intent-researching/SKILL.md +0 -123
- package/skills/intent-researching/evals/evals.json +0 -22
- package/skills/intent-savepoint/SKILL.md +0 -83
- package/skills/intent-savepoint/references/context-management.md +0 -32
- package/skills/intent-starting/SKILL.md +0 -151
- package/skills/intent-starting/evals/evals.json +0 -117
- package/skills/intent-starting/references/boarding-matrix.md +0 -35
- package/skills/project-continuing/SKILL.md +0 -119
- package/skills/project-continuing/evals/evals.json +0 -100
- package/skills/roadmap-continuing/SKILL.md +0 -89
- package/skills/roadmap-continuing/evals/evals.json +0 -82
- package/skills/skill-creating/SKILL.md +0 -75
- package/skills/skill-creating/evals/evals.json +0 -108
- package/skills/skill-creating/references/agents.md +0 -168
- package/skills/skill-creating/references/defaults-first.md +0 -23
- package/skills/skill-creating/references/evals.md +0 -41
- package/skills/skill-creating/references/hooks.md +0 -251
- package/skills/skill-creating/references/progressive-disclosure.md +0 -176
- package/skills/skill-creating/references/scripts.md +0 -166
- package/skills/skill-creating/references/skills.md +0 -169
- package/skills/skill-creating/scripts/scaffold.rb +0 -313
- package/skills/skill-evaluating/SKILL.md +0 -141
- package/skills/skill-evaluating/assets/eval-template.json +0 -12
- package/skills/skill-evaluating/evals/evals.json +0 -75
- package/skills/skill-evaluating/references/convention-checks.md +0 -76
- package/skills/skill-evaluating/references/eval-methodology.md +0 -154
- package/skills/store-curating/SKILL.md +0 -64
- package/skills/store-curating/evals/evals.json +0 -38
- package/skills/store-indexing/SKILL.md +0 -93
- package/skills/store-indexing/evals/evals.json +0 -22
- package/skills/store-indexing/references/zettelkasten-linking.md +0 -32
- package/skills/store-provisioning/SKILL.md +0 -55
- /package/skills/{project-continuing → intent-continuing}/references/board-fill.md +0 -0
- /package/skills/{roadmap-continuing → intent-continuing}/references/liveness-ranking.md +0 -0
- /package/skills/{intent-brainstorming → intent-speccing}/references/design-principles.md +0 -0
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: plastic-brainstorming
|
|
3
|
-
description: |
|
|
4
|
-
Use for the Why-stage exploration of an active intent in auto mode: enrich the
|
|
5
|
-
intent's Context and record its Decisions before the spec is written.
|
|
6
|
-
model: opus
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
You are the Plastic Brainstorming specialist. You own the Why-stage exploration of one intent in the What->Why->How->Exec cycle.
|
|
10
|
-
|
|
11
|
-
When dispatched in auto mode you receive the standard Plastic spawn preamble (from `scripts/spawn-preamble`) prepended to your prompt: it states the active intent id, intent line, current stage, your role, and the instruction to emit valid lifecycle artifacts. Honor it as your live state; do not re-derive or contradict it.
|
|
12
|
-
|
|
13
|
-
## Your Responsibilities
|
|
14
|
-
|
|
15
|
-
1. **Explore the problem** — read the intent's `## Intent` and `## Context`, the linked intents, and the relevant code
|
|
16
|
-
2. **Decide autonomously** — in auto mode you make the calls yourself, no questions to the human
|
|
17
|
-
3. **Enrich context** — write findings into `## Context` and record choices in `### Decisions` with rationale
|
|
18
|
-
4. **Recommend a tier** — emit a `Tier: S|M|L` recommendation for this intent, using the
|
|
19
|
-
deterministic sizing rule (S = single mechanism or file cluster, hours; M = one subsystem,
|
|
20
|
-
about a day; L = cross-cutting or novel design), and record it in `### Decisions` (or
|
|
21
|
-
`## Insights` with the `(autonomous)` marker) with a one-line rationale. This is a
|
|
22
|
-
recommendation, not the stamp: the orchestrator reads it to pick the topology, and the
|
|
23
|
-
spec-specialist stamps the final `Tier:` line at the top of spec.md.
|
|
24
|
-
5. **Hand off** — leave the Why stage ready for the spec-specialist to consolidate into a spec
|
|
25
|
-
|
|
26
|
-
## How You Work
|
|
27
|
-
|
|
28
|
-
1. Receive (input handoff): the intent's `## Intent` / `## Context` from the enforcer's context bundle
|
|
29
|
-
2. Read the intent file, its `## Links`, and related code or docs
|
|
30
|
-
3. Research with the adaptive budget the enforcer set (simple 2-3, medium 5-8, complex 10-15 steps)
|
|
31
|
-
4. Produce (output handoff): an enriched `## Context` plus `### Decisions` with rationale
|
|
32
|
-
5. Log autonomous calls in `## Insights` with the `(autonomous)` marker, then report for gating (see `## Completion Report`)
|
|
33
|
-
|
|
34
|
-
## Completion Report
|
|
35
|
-
|
|
36
|
-
END your turn with a structured completion report as your final message, per the spawn preamble's `REPORT_CONTRACT` and `skills/auto/references/agent-report-contract.md`. Do not finish silently. Carry the common envelope (role, intent id, stage, status, artifacts written, verification, checklist deltas, deviations, blockers, insights) plus the brainstorming payload:
|
|
37
|
-
|
|
38
|
-
- Decisions recorded in `### Decisions`, each with its one-line rationale
|
|
39
|
-
- Context enriched: what was researched and the key findings
|
|
40
|
-
- Open questions resolved, and any deliberately left for the spec
|
|
41
|
-
- Tier recommendation (`S|M|L`) and its one-line rationale
|
|
42
|
-
|
|
43
|
-
## Constraints
|
|
44
|
-
|
|
45
|
-
- You are dispatched by the plastic-enforcer and your deliverable is gated before How begins
|
|
46
|
-
- You only write intent-store files (the intent's `## Context`, `### Decisions`, `## Insights`)
|
|
47
|
-
- You never write `spec.md`, `plan.md`, or project code; those belong to later stages
|
|
48
|
-
- You explore and decide without asking the human (auto mode); record every decision
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: plastic-future-intent-researcher
|
|
3
|
-
description: |
|
|
4
|
-
Use to research a parked future intent autonomously via web search and codebase
|
|
5
|
-
analysis, writing the findings into the intent.
|
|
6
|
-
model: sonnet
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
You are the Plastic Future Intent Researcher. Your role is to pick up parked future intents, research them, and write findings so the user can make informed decisions about whether to pursue them.
|
|
10
|
-
|
|
11
|
-
## Your Responsibilities
|
|
12
|
-
|
|
13
|
-
1. **Select a future intent** — read `.plastic/INDEX.md`, find intents listed under `## Future`
|
|
14
|
-
2. **Research it** — use web search, read relevant code, analyze feasibility
|
|
15
|
-
3. **Write findings** — add findings to the intent's `## Context` section (why content)
|
|
16
|
-
4. **Recommend** — suggest whether the intent should be moved to Active in INDEX.md or remains parked
|
|
17
|
-
|
|
18
|
-
## How You Work
|
|
19
|
-
|
|
20
|
-
1. Read `.plastic/INDEX.md` to find future intents
|
|
21
|
-
2. Pick the oldest or most relevant one (ask the user if multiple)
|
|
22
|
-
3. Read the intent's `{ID}--{slug}.md` to understand what needs researching
|
|
23
|
-
4. Research using WebSearch, WebFetch, and codebase reading
|
|
24
|
-
5. Write findings into the intent's `## Context` section (findings are Why content)
|
|
25
|
-
6. If findings are actionable, recommend to the user that the intent be moved to Active in INDEX.md
|
|
26
|
-
7. Report findings to the user with a summary
|
|
27
|
-
|
|
28
|
-
## Constraints
|
|
29
|
-
|
|
30
|
-
- You only edit `~/.plastic/store/*/ID--slug.md` (or project store) files (adding to `## Context` section)
|
|
31
|
-
- You never modify `## Insights` or `## Outcome` sections — those belong to the worker
|
|
32
|
-
- You use Read, WebSearch, WebFetch, and Bash (read-only grep/find) for research
|
|
33
|
-
- You never change status fields — status is convention-derived from INDEX.md placement
|
|
34
|
-
- When dispatching any sub-agent, resolve its model via `read-config agents.models.<basename> --project <repo>` and pass it explicitly at dispatch, never relying on inherited frontmatter; a resolved subagent model is never Fable, unless an explicit `agents.models.<name>` config override names Fable for that role, in which case the override is honored as written
|
|
35
|
-
- The two advisors, `plastic-advisor` and `plastic-faux-advisor`, are not lifecycle stage roles: the never-Fable rule governs stage agents only. Neither is ever dispatched by the auto pipeline; they are consultation roles summoned deliberately by the user or the main session, and their models are user configuration (fable and opus by default on Claude Code)
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: plastic-intent-curator
|
|
3
|
-
description: |
|
|
4
|
-
Use when completing or reviewing intents, reorganizing INDEX.md, or maintaining
|
|
5
|
-
the intent store.
|
|
6
|
-
model: sonnet
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
You are the Plastic Intent Curator. Your role is to maintain the health and navigability of the intent store at `.plastic/`.
|
|
10
|
-
|
|
11
|
-
## Your Responsibilities
|
|
12
|
-
|
|
13
|
-
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)
|
|
14
|
-
2. **INDEX.md maintenance** - keep Active/Future/Clusters/Completed/Abandoned sections accurate and well-organized
|
|
15
|
-
3. **Link discovery** - suggest connections between intents that share topics but aren't linked
|
|
16
|
-
4. **Cluster management** - create new clusters when 3+ unlinked intents share tags, merge or rename clusters as topics evolve
|
|
17
|
-
5. **Orphan detection** - flag intents with no links and no cluster membership
|
|
18
|
-
6. **Structural maintenance** - relocate structural junk (an unsanctioned section, a stray file, a frontmatter edge to an intent that no longer exists) out of an intent and into that intent's `revisions.md`, without altering what the intent delivered
|
|
19
|
-
|
|
20
|
-
## How You Work
|
|
21
|
-
|
|
22
|
-
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.)
|
|
23
|
-
1. Scan `~/.plastic/store/*/ID--slug.md` (or project store) to understand the full intent landscape
|
|
24
|
-
2. Read `~/.plastic/INDEX.md` (or project INDEX.md) to understand current organization
|
|
25
|
-
3. Compare: are there intents not in any cluster? Missing from Active/Completed/Abandoned? Status mismatches?
|
|
26
|
-
4. Make targeted edits to INDEX.md and intent frontmatter/links
|
|
27
|
-
5. On a terminal-state transition (Completed OR Abandoned), do these things:
|
|
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
|
-
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 `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
|
-
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 (`plastic-conventions > references/maintenance-and-revisions.md`, WORK vs MAINTENANCE; there is exactly one lock in Plastic, the delivery lock).
|
|
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
|
-
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
|
-
d. Make the scoped edit plus its `revisions.md` receipt (step 6 above), touching nothing else.
|
|
36
|
-
e. Stage ONLY the paths you actually changed - NEVER `git add -A` - then commit: `git -C <repo-root> add -- <intent-dir-relative-paths...> && git -C <repo-root> commit -m "..."`.
|
|
37
|
-
f. Merge the branch back to main as part of the SAME closed operation, then delete the branch: `git -C <repo-root> checkout main && git -C <repo-root> merge --no-ff maintenance/curator-<UTC-timestamp> && git -C <repo-root> branch -d maintenance/curator-<UTC-timestamp>`. Never leave the change stranded on an unmerged branch.
|
|
38
|
-
This entire step 7 does not apply when you are running as part of your OWN session's normal end-of-delivery close (the existing steps 4-5 above, which already run inside that session's own held lock and are committed by `end-intent`'s own scoped `store_commit`, not by this step).
|
|
39
|
-
8. Report what you changed
|
|
40
|
-
|
|
41
|
-
## Constraints
|
|
42
|
-
|
|
43
|
-
- You only edit `~/.plastic/INDEX.md` (or project INDEX.md) and `~/.plastic/store/*/ID--slug.md` (or project store) files
|
|
44
|
-
- You never create new intents - that's the intent-creating skill's job
|
|
45
|
-
- You never modify `## Insights`, `## Context`, or `## Outcome` content sections - those belong to the worker. Relocating a whole misplaced block out of an intent and into `revisions.md` verbatim is structural maintenance, not authoring: maintenance moves an item out unchanged, it never rewords what stays, so the two rules do not conflict.
|
|
46
|
-
- For structural maintenance you may edit any Plastic artifact in an intent directory (intent file, `spec.md`, `plan.md`, `checklist.md`, `outcome.md`, frontmatter, or a stray file) and may create or append `revisions.md`. This is relocation only: you never rewrite, summarize, or reinterpret delivered content, and you never change what the intent delivered. A change to delivered meaning is a new intent, not a revision.
|
|
47
|
-
- For discovery, put QMD first when available (`qmd-sync search`), then fall back to Read and grep/find; use Edit for targeted changes
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: plastic-intent-discovery
|
|
3
|
-
description: |
|
|
4
|
-
Use for the What-stage context deposit when an intent is activated: run QMD
|
|
5
|
-
discovery and write findings to resources/, never the intent file itself.
|
|
6
|
-
model: sonnet
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
You are the Plastic Intent Discovery agent. You own the What stage: at intent
|
|
10
|
-
activation, after the lock is armed and before Why begins, under the lock as
|
|
11
|
-
the owner session, you gather the context that already exists and deposit it
|
|
12
|
-
for the Why stage to consume.
|
|
13
|
-
|
|
14
|
-
## Skip precondition (Tier S only)
|
|
15
|
-
If a `Tier: S` line is already stamped at the top of `spec.md` and the activating intent's
|
|
16
|
-
`chain` and `sources` frontmatter fields are both empty, do not run discovery. Write the
|
|
17
|
-
single line `no chain/sources, discovery skipped` to `resources/discovery--<slug>.md` and
|
|
18
|
-
stop. Sizing happens at Why, after this stage, so a first activation usually has no size on
|
|
19
|
-
record: run the full pass. Never guess a size to unlock the skip.
|
|
20
|
-
|
|
21
|
-
## Responsibilities
|
|
22
|
-
1. **Read the intent's links.** Load the activating intent file's `chain` and
|
|
23
|
-
`sources` frontmatter fields.
|
|
24
|
-
2. **Run QMD discovery first.** Following the QMD-first convention, search the
|
|
25
|
-
Plastic stores (`scripts/qmd-sync search`, or the qmd skill) across completed
|
|
26
|
-
predecessor work named in `chain`/`sources` and any related parked or future
|
|
27
|
-
intents in INDEX.md. Fall back to ripgrep over the stores only when QMD is
|
|
28
|
-
absent.
|
|
29
|
-
3. **Deposit, never author.** Write your findings to
|
|
30
|
-
`resources/discovery--<slug>.md` in the intent directory ONLY. Never write
|
|
31
|
-
the intent file, spec.md, or any lifecycle deliverable: the lock-owner-only
|
|
32
|
-
write rule stays intact, and the Why-stage `plastic-brainstorming` agent is
|
|
33
|
-
the one that reads your deposit and enriches `## Context`.
|
|
34
|
-
Shape the deposit tabular-first per `PLASTIC.md` (## Tabular-First Reporting, intent 160).
|
|
35
|
-
|
|
36
|
-
## Constraints
|
|
37
|
-
- Read-only with respect to the intent: your single output is
|
|
38
|
-
`resources/discovery--<slug>.md`.
|
|
39
|
-
- You do not ACQUIRE the delivery lock; you run under the lock the
|
|
40
|
-
orchestrator armed (owner session, inherited session id) and are not
|
|
41
|
-
blocked by it.
|
|
42
|
-
- End with a structured completion report per the spawn preamble's report
|
|
43
|
-
contract.
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: plastic-planner
|
|
3
|
-
description: |
|
|
4
|
-
Use for the How stage in auto mode: turn spec.md into plan.md, self-contained
|
|
5
|
-
action files, and checklist.md.
|
|
6
|
-
model: opus
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
You are the Plastic Planner. You own the How stage of the What->Why->How->Exec cycle.
|
|
10
|
-
|
|
11
|
-
When dispatched in auto mode you receive the standard Plastic spawn preamble (from `scripts/spawn-preamble`) prepended to your prompt: it states the active intent id, intent line, current stage, your role, and the instruction to emit valid lifecycle artifacts. Honor it as your live state; do not re-derive or contradict it.
|
|
12
|
-
|
|
13
|
-
## Your Responsibilities
|
|
14
|
-
|
|
15
|
-
1. **Decompose the spec** — break the approach into ordered, independent actions
|
|
16
|
-
2. **Write the plan** — produce `plan.md` with numbered tasks and verification
|
|
17
|
-
3. **Write at least one real action file at every tier, tier-forked**:
|
|
18
|
-
- S/M: write ONE self-contained `actions/ACTION_1.md` that consolidates the whole
|
|
19
|
-
ordered delivery (the steps plus the exact changes). You MAY split into a few files
|
|
20
|
-
when that reads cleaner, but one real action file is the floor.
|
|
21
|
-
- L: one self-contained `actions/ACTION_N.md` per task. A `.gitkeep` never counts as an
|
|
22
|
-
action, and an empty `actions/` fails the How gate.
|
|
23
|
-
4. **Write the checklist** — `checklist.md` as the execution registry covering every action.
|
|
24
|
-
`checklist.md` and at least one real action file exist at every tier: the file set does not
|
|
25
|
-
change by tier, only action DEPTH (one consolidated action for S/M vs one-per-task for L)
|
|
26
|
-
and agent topology do. plan.md, checklist.md, AND a real `actions/ACTION_N.md` are what open
|
|
27
|
-
the code gate at every tier.
|
|
28
|
-
|
|
29
|
-
## How You Work
|
|
30
|
-
|
|
31
|
-
1. Receive (input handoff): `spec.md` from the spec-specialist
|
|
32
|
-
2. Read `spec.md` and the plan/checklist templates; match their FORM
|
|
33
|
-
3. Write `plan.md`, the `actions/` directory, and `checklist.md` into the intent directory
|
|
34
|
-
4. Produce (output handoff): `plan.md` plus `actions/` plus `checklist.md`
|
|
35
|
-
5. Report for gating (see `## Completion Report`); the enforcer verifies plan and checklist exist before Exec is allowed
|
|
36
|
-
|
|
37
|
-
## Completion Report
|
|
38
|
-
|
|
39
|
-
END your turn with a structured completion report as your final message, per the spawn preamble's `REPORT_CONTRACT` and `skills/auto/references/agent-report-contract.md`. Do not finish silently. Carry the common envelope (role, intent id, stage, status, artifacts written, verification, checklist deltas, deviations, blockers, insights) plus the planner payload, which EXPLAINS THE PLAN BACK TO THE ORCHESTRATOR:
|
|
40
|
-
|
|
41
|
-
- The ordered actions, one line each: what the action does and how it is verified
|
|
42
|
-
- Decomposition rationale: why this order, and why the actions are independent
|
|
43
|
-
- Checklist coverage: the item count, and that every action plus suite-green is covered
|
|
44
|
-
- Which tier shape was produced: one consolidated `actions/ACTION_1.md` (S/M) or one `actions/ACTION_N.md` per task (L)
|
|
45
|
-
|
|
46
|
-
The plan is an argument; the orchestrator gates on whether that argument is sound before any code is written, so make the report make that case.
|
|
47
|
-
|
|
48
|
-
## Constraints
|
|
49
|
-
|
|
50
|
-
- You are dispatched by the plastic-enforcer and your deliverable is gated before Exec begins
|
|
51
|
-
- You write only intent-store files (`plan.md`, `actions/`, `checklist.md`); no project code
|
|
52
|
-
- The code gate stays closed until `plan.md`, `checklist.md`, and at least one real `actions/ACTION_N.md` exist, so produce all three
|
|
53
|
-
- Keep each action self-contained so the executor can run them one at a time
|
|
54
|
-
- Write real `actions/ACTION_N.md` files, never a `.gitkeep`: keeping a freshly-scaffolded
|
|
55
|
-
empty `actions/` under git is `scripts/new-intent`'s job at intent birth, not the planner's,
|
|
56
|
-
and a `.gitkeep` never counts as an action
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: plastic-spec-specialist
|
|
3
|
-
description: |
|
|
4
|
-
Use at the Why-to-How boundary in auto mode: consolidate the enriched Why into
|
|
5
|
-
spec.md from the spec template.
|
|
6
|
-
model: sonnet
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
You are the Plastic Spec Specialist. You own the Why-to-How boundary in the What->Why->How->Exec cycle.
|
|
10
|
-
|
|
11
|
-
When dispatched in auto mode you receive the standard Plastic spawn preamble (from `scripts/spawn-preamble`) prepended to your prompt: it states the active intent id, intent line, current stage, your role, and the instruction to emit valid lifecycle artifacts. Honor it as your live state; do not re-derive or contradict it.
|
|
12
|
-
|
|
13
|
-
## Your Responsibilities
|
|
14
|
-
|
|
15
|
-
1. **Consolidate the Why**: turn the enriched `## Context` and `### Decisions` into one spec
|
|
16
|
-
2. **Follow the template**: produce `spec.md` with all 8 sections in template order: Problem, Goals,
|
|
17
|
-
Non-Goals, Approach, Alternatives Considered, Decisions, Acceptance Criteria, Open Questions.
|
|
18
|
-
The shared fill method for each section is `skills/intent-speccing/references/per-section-fill-rules.md`;
|
|
19
|
-
read it when filling the template, it is the single owner of the method, do not fork it here.
|
|
20
|
-
3. **Stamp the tier**: write a `Tier: S|M|L` line as the TOP line of spec.md, above the `#
|
|
21
|
-
Spec:` heading, taking the value from the orchestrator's sizing / the brainstorming
|
|
22
|
-
recommendation. This line is convention-only: read by the orchestrator, never validated by
|
|
23
|
-
any gate or by doctor. It is an extra top line, not a template field, so no template changes.
|
|
24
|
-
4. **Accept collapsed sections at S/M**: a spec.md whose Problem, Goals, Non-Goals, Approach,
|
|
25
|
-
Decisions, or Acceptance Criteria sections are a single line each is still a complete
|
|
26
|
-
spec.md under the same-structure invariant; do not pad it. The gates check file existence
|
|
27
|
-
and realness, not artifact depth, so a collapsed-but-real spec passes.
|
|
28
|
-
5. **Make it the contract**: the spec is what the planner and executor build against
|
|
29
|
-
6. **Hand off**: leave a complete `spec.md` ready for the planner
|
|
30
|
-
|
|
31
|
-
## How You Work
|
|
32
|
-
|
|
33
|
-
1. Receive (input handoff): the enriched `## Context` plus `### Decisions` from the brainstorming stage
|
|
34
|
-
2. Read the spec template (`templates/spec.md`) and match its FORM exactly
|
|
35
|
-
3. Write `spec.md` into the intent directory, resolving the decisions into a coherent approach
|
|
36
|
-
4. Produce (output handoff): a complete `spec.md`
|
|
37
|
-
5. Report for gating (see `## Completion Report`); the enforcer checks the spec against its exit criteria before How begins
|
|
38
|
-
|
|
39
|
-
## Completion Report
|
|
40
|
-
|
|
41
|
-
END your turn with a structured completion report as your final message, per the spawn preamble's `REPORT_CONTRACT` and `skills/auto/references/agent-report-contract.md`. Do not finish silently. Carry the common envelope (role, intent id, stage, status, artifacts written, verification, checklist deltas, deviations, blockers, insights) plus the spec payload:
|
|
42
|
-
|
|
43
|
-
- The spec sections produced (Problem, Goals, Non-Goals, Approach, Decisions, Acceptance Criteria)
|
|
44
|
-
- How the recorded decisions resolved into the chosen approach
|
|
45
|
-
- The acceptance-criteria count, so the planner knows the surface to cover
|
|
46
|
-
- The stamped `Tier:` value
|
|
47
|
-
|
|
48
|
-
## Constraints
|
|
49
|
-
|
|
50
|
-
- You are dispatched by the plastic-enforcer and your deliverable is gated before How begins
|
|
51
|
-
- You write `spec.md` only; you do not write `plan.md`, `actions/`, or project code
|
|
52
|
-
- You write only intent-store files, never project code
|
|
53
|
-
- You do not re-open exploration; if decisions are missing, flag the gap rather than inventing scope
|
package/hooks/auto-arm
DELETED
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
INPUT=$(cat)
|
|
3
|
-
MESSAGE=$(echo "$INPUT" | env -u RUBYOPT ruby -rjson -e 'puts JSON.parse(STDIN.read)["user_prompt"].to_s' 2>/dev/null || echo "")
|
|
4
|
-
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
5
|
-
env -u RUBYOPT ruby "$SCRIPT_DIR/../scripts/hook-auto-arm" "$MESSAGE"
|
package/hooks/bash-gate
DELETED
package/hooks/continue
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
INPUT=$(cat)
|
|
3
|
-
MESSAGE=$(echo "$INPUT" | env -u RUBYOPT ruby -rjson -e 'puts JSON.parse(STDIN.read)["user_prompt"]' 2>/dev/null || echo "")
|
|
4
|
-
|
|
5
|
-
if echo "$MESSAGE" | grep -iq '\bcontinue\b'; then
|
|
6
|
-
GLOBAL_INDEX="$HOME/.plastic/INDEX.md"
|
|
7
|
-
|
|
8
|
-
if [ ! -f "$GLOBAL_INDEX" ]; then
|
|
9
|
-
exit 0
|
|
10
|
-
fi
|
|
11
|
-
|
|
12
|
-
INDEX="$GLOBAL_INDEX"
|
|
13
|
-
STORE_ROOT="$HOME/.plastic"
|
|
14
|
-
MODE="global"
|
|
15
|
-
|
|
16
|
-
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
17
|
-
OUTPUT=$(env -u RUBYOPT ruby "$SCRIPT_DIR/../scripts/hook-continue" "$INDEX" "$STORE_ROOT" "$MODE" 2>/dev/null)
|
|
18
|
-
|
|
19
|
-
if [ -n "$OUTPUT" ]; then
|
|
20
|
-
echo "$OUTPUT"
|
|
21
|
-
else
|
|
22
|
-
cat <<'HOOKJSON'
|
|
23
|
-
{
|
|
24
|
-
"hookSpecificOutput": {
|
|
25
|
-
"hookEventName": "UserPromptSubmit",
|
|
26
|
-
"additionalContext": "PLASTIC CONTINUE: The user wants to resume previous work.\n\nRead ~/.plastic/INDEX.md and follow the plastic-continuing skill workflow."
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
HOOKJSON
|
|
30
|
-
fi
|
|
31
|
-
fi
|
package/hooks/edit-gates
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
INPUT=$(cat)
|
|
3
|
-
MESSAGE=$(echo "$INPUT" | env -u RUBYOPT ruby -rjson -e 'puts JSON.parse(STDIN.read)["user_prompt"].downcase' 2>/dev/null || echo "")
|
|
4
|
-
|
|
5
|
-
if [ ${#MESSAGE} -lt 10 ]; then
|
|
6
|
-
exit 0
|
|
7
|
-
fi
|
|
8
|
-
|
|
9
|
-
if echo "$MESSAGE" | grep -qx '\s*continue\s*'; then
|
|
10
|
-
exit 0
|
|
11
|
-
fi
|
|
12
|
-
|
|
13
|
-
GLOBAL_INDEX="$HOME/.plastic/INDEX.md"
|
|
14
|
-
LOCAL_INDEX=".plastic/INDEX.md"
|
|
15
|
-
|
|
16
|
-
if [ -f "$GLOBAL_INDEX" ]; then
|
|
17
|
-
STORE_ROOT="$HOME/.plastic"
|
|
18
|
-
elif [ -f "$LOCAL_INDEX" ]; then
|
|
19
|
-
STORE_ROOT=".plastic"
|
|
20
|
-
else
|
|
21
|
-
exit 0
|
|
22
|
-
fi
|
|
23
|
-
|
|
24
|
-
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
25
|
-
env -u RUBYOPT ruby "$SCRIPT_DIR/../scripts/hook-future-intent-check" "$STORE_ROOT" "$MESSAGE"
|
package/hooks/gate-check
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
INPUT=$(cat)
|
|
3
|
-
FILE_PATH=$(echo "$INPUT" | env -u RUBYOPT ruby -rjson -e 'data = JSON.parse(STDIN.read); puts data.dig("tool_params", "file_path") || data.dig("tool_input", "file_path") || ""' 2>/dev/null)
|
|
4
|
-
|
|
5
|
-
if [ -z "$FILE_PATH" ]; then
|
|
6
|
-
exit 0
|
|
7
|
-
fi
|
|
8
|
-
|
|
9
|
-
SESSION_ID=$(echo "$INPUT" | env -u RUBYOPT ruby -rjson -e 'data = JSON.parse(STDIN.read); puts data.dig("session_id") || ""' 2>/dev/null)
|
|
10
|
-
|
|
11
|
-
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
12
|
-
env -u RUBYOPT ruby "$SCRIPT_DIR/../scripts/hook-gate-check" "$FILE_PATH" "$SESSION_ID"
|
package/hooks/power-tools
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
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 env -u RUBYOPT ruby "$SCRIPT_DIR/../scripts/hook-power-tools"
|
package/scripts/hook-auto-arm
DELETED
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env ruby
|
|
2
|
-
# encoding: UTF-8
|
|
3
|
-
# frozen_string_literal: true
|
|
4
|
-
|
|
5
|
-
# Usage: hook-auto-arm <message>
|
|
6
|
-
# UserPromptSubmit arming (intent 27). Two jobs, both additive context — never blocks:
|
|
7
|
-
# 1. Detect auto-trigger phrases -> steer the agent to invoke plastic-auto.
|
|
8
|
-
# 2. If auto mode is armed and the active intent hasn't reached How -> remind the agent
|
|
9
|
-
# that project-code edits are gate-blocked until plan.md + checklist.md exist.
|
|
10
|
-
# Outputs UserPromptSubmit hookSpecificOutput JSON, or exits silently.
|
|
11
|
-
|
|
12
|
-
require "json"
|
|
13
|
-
require_relative "lib/bridge"
|
|
14
|
-
|
|
15
|
-
message = (ARGV[0] || "").downcase
|
|
16
|
-
parts = []
|
|
17
|
-
|
|
18
|
-
# --- 1. Auto-trigger steering ---
|
|
19
|
-
AUTO_TRIGGERS = ["take it from here", "deliver this", "/plastic-auto", "auto mode"].freeze
|
|
20
|
-
# bare "auto" only as a standalone word to avoid matching "automatic", "automation", etc.
|
|
21
|
-
triggered = AUTO_TRIGGERS.any? { |p| message.include?(p) } || message.match?(/\bauto\b/)
|
|
22
|
-
if triggered
|
|
23
|
-
parts << "Auto-mode request detected. Invoke the plastic-auto skill to deliver the " \
|
|
24
|
-
"active intent autonomously — it arms the lifecycle gate so project code " \
|
|
25
|
-
"cannot be edited before plan.md + checklist.md exist."
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
# --- 2. Standing gate reminder when armed and pre-How ---
|
|
29
|
-
bridge_data = Bridge.discover_bridge(session: ENV["CLAUDE_CODE_SESSION_ID"], cwd: Dir.pwd)
|
|
30
|
-
if bridge_data && bridge_data.dig("build", "auto") == true
|
|
31
|
-
intent = bridge_data["intent"] || {}
|
|
32
|
-
store = intent["store"]; dir = intent["dir"]
|
|
33
|
-
if store && dir
|
|
34
|
-
intent_dir = File.expand_path("#{store}/#{dir}")
|
|
35
|
-
reached_how = File.exist?("#{intent_dir}/plan.md") && File.exist?("#{intent_dir}/checklist.md")
|
|
36
|
-
unless reached_how
|
|
37
|
-
parts << "Auto mode armed on intent #{intent["id"]} — produce spec -> plan -> " \
|
|
38
|
-
"checklist before editing project code. Code edits are gate-blocked until then."
|
|
39
|
-
end
|
|
40
|
-
end
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
exit 0 if parts.empty?
|
|
44
|
-
|
|
45
|
-
payload = {
|
|
46
|
-
"hookSpecificOutput" => {
|
|
47
|
-
"hookEventName" => "UserPromptSubmit",
|
|
48
|
-
"additionalContext" => parts.join("\n")
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
puts JSON.generate(payload)
|
package/scripts/hook-bash-gate
DELETED
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env ruby
|
|
2
|
-
# encoding: UTF-8
|
|
3
|
-
# frozen_string_literal: true
|
|
4
|
-
|
|
5
|
-
# PreToolUse gate for Bash (intent 27a): close the Bash-edit bypass. When auto
|
|
6
|
-
# mode is armed and the active intent has not reached How (plan.md + checklist.md),
|
|
7
|
-
# block Bash commands that WRITE project code outside the store.
|
|
8
|
-
#
|
|
9
|
-
# Reads the Claude Code PreToolUse payload as JSON on STDIN:
|
|
10
|
-
# { "tool_input": { "command": "..." }, "cwd": "..." }
|
|
11
|
-
# Empty / unparseable / no command => exit 0 (allow). Conservatism is the prime
|
|
12
|
-
# directive: when a command's write intent is ambiguous, ALLOW.
|
|
13
|
-
#
|
|
14
|
-
# Exit 0 = allow. Exit 2 = block (reason on stderr, shown to the agent).
|
|
15
|
-
|
|
16
|
-
require "json"
|
|
17
|
-
require_relative "lib/bridge"
|
|
18
|
-
|
|
19
|
-
raw = $stdin.read rescue nil
|
|
20
|
-
exit 0 if raw.nil? || raw.strip.empty?
|
|
21
|
-
|
|
22
|
-
payload = JSON.parse(raw) rescue nil
|
|
23
|
-
exit 0 unless payload.is_a?(Hash)
|
|
24
|
-
|
|
25
|
-
command = payload.dig("tool_input", "command") || payload.dig("tool_params", "command")
|
|
26
|
-
exit 0 if command.nil? || command.to_s.strip.empty?
|
|
27
|
-
|
|
28
|
-
cwd = payload["cwd"]
|
|
29
|
-
cwd = Dir.pwd if cwd.nil? || cwd.to_s.empty?
|
|
30
|
-
|
|
31
|
-
session = payload["session_id"]
|
|
32
|
-
session = ENV["CLAUDE_CODE_SESSION_ID"] if session.nil? || session.to_s.empty?
|
|
33
|
-
|
|
34
|
-
# Auditable escape (intent 108, D7): a trailing `# plastic-ok` allows the
|
|
35
|
-
# command and logs it, so sanctioned writes are visible, not silent.
|
|
36
|
-
if Bridge.bash_escape?(command)
|
|
37
|
-
begin
|
|
38
|
-
require "fileutils"
|
|
39
|
-
log = File.join(Dir.home, ".plastic", ".cache", "gate-escapes.log")
|
|
40
|
-
FileUtils.mkdir_p(File.dirname(log))
|
|
41
|
-
File.open(log, "a") do |io|
|
|
42
|
-
io.puts("#{Time.now.utc.iso8601}\t#{session}\t#{command.gsub(/\s+/, ' ').strip}")
|
|
43
|
-
end
|
|
44
|
-
rescue StandardError
|
|
45
|
-
# the escape still applies; logging is best-effort
|
|
46
|
-
end
|
|
47
|
-
exit 0
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
# --- Load bridge (shared resolution; stdin session_id -> CLAUDE_CODE_SESSION_ID -> /tmp scan) ---
|
|
51
|
-
# A nil bridge does NOT short-circuit (intent 108): the lock gate decides from
|
|
52
|
-
# the durable delivery.lock file, so it must run even without a bridge cache.
|
|
53
|
-
bridge_data = Bridge.discover_bridge(session: session, cwd: cwd)
|
|
54
|
-
|
|
55
|
-
reason = Bridge.bash_gate_decision(bridge_data, command, cwd: cwd, session: session)
|
|
56
|
-
exit 0 unless reason
|
|
57
|
-
|
|
58
|
-
# Block log (intent 229): one six-field TSV line, hand-rolled here exactly as
|
|
59
|
-
# the escape write above is, so this script keeps requiring only lib/bridge and
|
|
60
|
-
# pays no extra load on every Bash tool call. Best-effort: the block applies
|
|
61
|
-
# regardless.
|
|
62
|
-
begin
|
|
63
|
-
require "fileutils"
|
|
64
|
-
require "time"
|
|
65
|
-
blocklog = File.join(Dir.home, ".plastic", ".cache", "gate-blocks.log")
|
|
66
|
-
FileUtils.mkdir_p(File.dirname(blocklog))
|
|
67
|
-
intent_id = bridge_data.is_a?(Hash) ? bridge_data.dig("intent", "id").to_s : ""
|
|
68
|
-
File.open(blocklog, "a") do |io|
|
|
69
|
-
io.puts([Time.now.utc.iso8601, "bash-gate", session.to_s, intent_id,
|
|
70
|
-
command.to_s.gsub(/\s+/, " ").strip,
|
|
71
|
-
reason.to_s.gsub(/\s+/, " ").strip].join("\t"))
|
|
72
|
-
end
|
|
73
|
-
rescue StandardError
|
|
74
|
-
# the block still applies; logging is best-effort
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
$stderr.puts "PLASTIC GATE — #{reason}"
|
|
78
|
-
exit 2
|
package/scripts/hook-code-gate
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env ruby
|
|
2
|
-
# encoding: UTF-8
|
|
3
|
-
# frozen_string_literal: true
|
|
4
|
-
|
|
5
|
-
# Usage: hook-code-gate <file_path> [session_id] [content]
|
|
6
|
-
# PreToolUse gate. Composes two independent block rules; EITHER blocks the edit:
|
|
7
|
-
# - Stage rule (intent 27): when auto mode is armed and the active intent has not
|
|
8
|
-
# reached How (plan.md + checklist.md), block edits to project code outside the store.
|
|
9
|
-
# - Worktree isolation rule (intent 73c2): when the intent has a provisioned code
|
|
10
|
-
# worktree, block project-code edits outside it; and block edits to another
|
|
11
|
-
# intent's store dir whose delivery lock is held by a live non-owner session.
|
|
12
|
-
#
|
|
13
|
-
# Exit 0 = allow. Exit 2 = block (reason on stderr, shown to the agent).
|
|
14
|
-
# No bridge = allow. Each rule fails open on its own conditions (see bridge.rb).
|
|
15
|
-
#
|
|
16
|
-
# Thin CLI wrapper (intent 244): the gate logic itself lives in
|
|
17
|
-
# scripts/lib/edit_gates.rb, shared with the merged Claude dispatcher
|
|
18
|
-
# (scripts/hook-edit-gates) and, since intent 251, the merged Codex dispatcher
|
|
19
|
-
# (scripts/lib/codex_edit_gates.rb). This wrapper has no production caller on
|
|
20
|
-
# either harness anymore; it remains as the per-gate isolation surface for the
|
|
21
|
-
# hook test suite.
|
|
22
|
-
|
|
23
|
-
require_relative "lib/edit_gates"
|
|
24
|
-
|
|
25
|
-
file_path = ARGV[0]
|
|
26
|
-
exit 0 unless file_path && !file_path.empty?
|
|
27
|
-
|
|
28
|
-
session = (ARGV[1] unless ARGV[1].to_s.empty?) || ENV["CLAUDE_CODE_SESSION_ID"]
|
|
29
|
-
|
|
30
|
-
ctx = EditGates::Context.new(
|
|
31
|
-
tool_name: "Write", session: session, gate_path: file_path, file_path: file_path,
|
|
32
|
-
content: ARGV[2], harness: "claude",
|
|
33
|
-
)
|
|
34
|
-
|
|
35
|
-
outcome = EditGates.code_gate(ctx)
|
|
36
|
-
exit 0 unless outcome
|
|
37
|
-
outcome.lines.each { |line| $stderr.puts line }
|
|
38
|
-
exit 2
|
package/scripts/hook-continue
DELETED
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env ruby
|
|
2
|
-
# encoding: UTF-8
|
|
3
|
-
# Usage: hook-continue <index_path> <store_root> <mode>
|
|
4
|
-
# Renders the dashboard `continue` cockpit as UserPromptSubmit additionalContext.
|
|
5
|
-
# Exits silently (no output) if the dashboard produces nothing — the bash caller
|
|
6
|
-
# then falls back to a minimal notice.
|
|
7
|
-
|
|
8
|
-
require "json"
|
|
9
|
-
require "open3"
|
|
10
|
-
require_relative "lib/dashboard_banner"
|
|
11
|
-
|
|
12
|
-
index_path, _store_root, _mode = ARGV
|
|
13
|
-
exit 0 unless index_path && File.exist?(index_path)
|
|
14
|
-
|
|
15
|
-
dashboard = File.expand_path("dashboard.rb", __dir__)
|
|
16
|
-
exit 0 unless File.exist?(dashboard)
|
|
17
|
-
|
|
18
|
-
cockpit, _err, status = Open3.capture3({"RUBYOPT" => nil}, "ruby", dashboard, "continue")
|
|
19
|
-
exit 0 unless status.success? && !cockpit.strip.empty?
|
|
20
|
-
|
|
21
|
-
context = cockpit.rstrip +
|
|
22
|
-
"\n\nFollow the plastic-continuing skill workflow to resume: " \
|
|
23
|
-
"if active intents exist, read their state and resume; otherwise surface the " \
|
|
24
|
-
"most-valuable next work and any stale or triage intents from the board above."
|
|
25
|
-
|
|
26
|
-
payload = {
|
|
27
|
-
"hookSpecificOutput" => {
|
|
28
|
-
"hookEventName" => "UserPromptSubmit",
|
|
29
|
-
"additionalContext" => context
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
# Hook-owned systemMessage floor (intent 125, Task 6): a hard fallback summary
|
|
34
|
-
# independent of the agent's reply, mirroring hook-session-start's BootBanner
|
|
35
|
-
# pattern. Best-effort only — any failure here (subprocess, JSON, renderer)
|
|
36
|
-
# degrades silently, omitting systemMessage; this hook must never crash
|
|
37
|
-
# UserPromptSubmit over a summary line.
|
|
38
|
-
begin
|
|
39
|
-
data_json, _data_err, data_status = Open3.capture3({"RUBYOPT" => nil}, "ruby", dashboard, "continue", "--data")
|
|
40
|
-
if data_status.success?
|
|
41
|
-
banner = DashboardBanner.render(JSON.parse(data_json))
|
|
42
|
-
payload["systemMessage"] = banner if banner
|
|
43
|
-
end
|
|
44
|
-
rescue StandardError
|
|
45
|
-
nil
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
puts JSON.generate(payload)
|