@zalom/plastic 1.0.0-alpha.14 → 1.0.0-alpha.16

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.
Files changed (38) hide show
  1. package/PLASTIC.md +18 -18
  2. package/README.md +13 -6
  3. package/agents/future-intent-researcher.md +1 -1
  4. package/agents/intent-curator.md +1 -1
  5. package/deprecations.yml +6 -5
  6. package/package.json +1 -1
  7. package/scripts/doctor.rb +37 -30
  8. package/scripts/hook-auto-arm +3 -3
  9. package/scripts/hook-continue +1 -1
  10. package/scripts/hook-gate-check +3 -3
  11. package/scripts/hook-session-start +1 -1
  12. package/scripts/install.rb +175 -119
  13. package/scripts/lib/bridge.rb +1 -1
  14. package/scripts/migrate-to-global +1 -1
  15. package/skills/_active-intent-gate.md +1 -1
  16. package/skills/auto/SKILL.md +6 -6
  17. package/skills/auto/evals/evals.json +17 -17
  18. package/skills/auto/references/agent-architecture.md +1 -1
  19. package/skills/brainstorming/SKILL.md +8 -8
  20. package/skills/brainstorming-grill-me/SKILL.md +5 -5
  21. package/skills/continuing/SKILL.md +4 -4
  22. package/skills/creating-intent/SKILL.md +1 -1
  23. package/skills/creating-project/SKILL.md +4 -4
  24. package/skills/doctor/SKILL.md +4 -4
  25. package/skills/evaluating-skills/SKILL.md +1 -1
  26. package/skills/executing-plan/SKILL.md +1 -1
  27. package/skills/install/SKILL.md +32 -8
  28. package/skills/intent-curator/SKILL.md +3 -3
  29. package/skills/linking-intents/SKILL.md +1 -1
  30. package/skills/managing-index/SKILL.md +1 -1
  31. package/skills/releasing/SKILL.md +3 -3
  32. package/skills/research/SKILL.md +2 -2
  33. package/skills/savepoint/SKILL.md +1 -1
  34. package/skills/uninstall/SKILL.md +39 -28
  35. package/skills/update/SKILL.md +2 -2
  36. package/skills/writing-instructions/SKILL.md +2 -2
  37. package/skills/writing-plans/SKILL.md +5 -5
  38. package/templates/agents.md +7 -7
package/PLASTIC.md CHANGED
@@ -61,10 +61,10 @@ The connection: an intent's `## Insights` feeds the Coordinator's Observe phase.
61
61
 
62
62
  | Stage | Section | Deliverable | Detail |
63
63
  |-------|---------|-------------|--------|
64
- | **What** | `## Intent` | `{ID}--{slug}.md` | `plastic:creating-intent` |
65
- | **Why** | `## Context` + Decisions | `spec.md` | `plastic:brainstorming` |
66
- | **How** | Planning | `plan.md` + `actions/` + `checklist.md` | `plastic:writing-plans` |
67
- | **Exec** | Execution | `outcome.md` | `plastic:executing-plan` |
64
+ | **What** | `## Intent` | `{ID}--{slug}.md` | `plastic-creating-intent` |
65
+ | **Why** | `## Context` + Decisions | `spec.md` | `plastic-brainstorming` |
66
+ | **How** | Planning | `plan.md` + `actions/` + `checklist.md` | `plastic-writing-plans` |
67
+ | **Exec** | Execution | `outcome.md` | `plastic-executing-plan` |
68
68
 
69
69
  `## Insights` — append-only work log captured throughout ALL stages.
70
70
  For full lifecycle detail, the skills in the Detail column have references/.
@@ -136,7 +136,7 @@ A Zettelkasten structure note, not a table of contents. Clusters by meaning.
136
136
 
137
137
  Sections: `## Active`, `## Future`, `## Clusters`, `## Abandoned`, `## Completed`.
138
138
 
139
- For index maintenance, use `plastic:managing-index`.
139
+ For index maintenance, use `plastic-managing-index`.
140
140
 
141
141
  ## Rules for Skills
142
142
 
@@ -165,16 +165,16 @@ Detailed conventions live inside the skills that use them, not in this file.
165
165
 
166
166
  | Topic | Skill | References in skill |
167
167
  |-------|-------|-------------------|
168
- | Creating intents, lifecycle | `plastic:creating-intent` | lifecycle, wikilinks |
169
- | Brainstorming, spec writing | `plastic:brainstorming` | — |
170
- | Planning, actions | `plastic:writing-plans` | — |
171
- | Execution, delivery | `plastic:executing-plan` | — |
172
- | Autonomous delivery | `plastic:auto` | agent architecture |
173
- | Save/restore state | `plastic:savepoint`, `plastic:continuing` | context management |
174
- | Knowledge graph, linking | `plastic:linking-intents` | zettelkasten, wikilinks |
175
- | Projects, hubs | `plastic:creating-project` | hubs, project stores |
176
- | Index maintenance | `plastic:managing-index` | — |
177
- | Releases, deprecations | `plastic:releasing` | deprecation process |
178
- | Health diagnostics | `plastic:doctor` | gate enforcement, stuck detection |
179
- | Writing agent instructions | `plastic:writing-instructions` | agentskills.io spec |
180
- | Evaluating skills, evals | `plastic:evaluating-skills` | eval methodology, convention checks |
168
+ | Creating intents, lifecycle | `plastic-creating-intent` | lifecycle, wikilinks |
169
+ | Brainstorming, spec writing | `plastic-brainstorming` | — |
170
+ | Planning, actions | `plastic-writing-plans` | — |
171
+ | Execution, delivery | `plastic-executing-plan` | — |
172
+ | Autonomous delivery | `plastic-auto` | agent architecture |
173
+ | Save/restore state | `plastic-savepoint`, `plastic-continuing` | context management |
174
+ | Knowledge graph, linking | `plastic-linking-intents` | zettelkasten, wikilinks |
175
+ | Projects, hubs | `plastic-creating-project` | hubs, project stores |
176
+ | Index maintenance | `plastic-managing-index` | — |
177
+ | Releases, deprecations | `plastic-releasing` | deprecation process |
178
+ | Health diagnostics | `plastic-doctor` | gate enforcement, stuck detection |
179
+ | Writing agent instructions | `plastic-writing-instructions` | agentskills.io spec |
180
+ | Evaluating skills, evals | `plastic-evaluating-skills` | eval methodology, convention checks |
package/README.md CHANGED
@@ -38,6 +38,13 @@ npx @zalom/plastic --claude
38
38
  Replace `--claude` with `--codex` for Codex CLI, `--hermes` for Hermes, or
39
39
  `--all` for all supported agents.
40
40
 
41
+ Bun users can substitute `bunx` for `npx` (e.g. `bunx @zalom/plastic@alpha --claude`).
42
+ Bun is never required.
43
+
44
+ Skills install as flat, hyphen-namespaced personal skills (`plastic-doctor`,
45
+ `plastic-auto`, …) — invoke them with a hyphen. Plastic is **not** a Claude Code
46
+ plugin; re-running the installer auto-removes any legacy plugin registration.
47
+
41
48
  ### Updating
42
49
 
43
50
  From within your agent, say "update plastic" or run:
@@ -46,25 +53,25 @@ From within your agent, say "update plastic" or run:
46
53
  npx @zalom/plastic@alpha --claude
47
54
  ```
48
55
 
49
- The `plastic:update` command shows available versions across all channels and
56
+ The `plastic-update` command shows available versions across all channels and
50
57
  lets you choose which to install.
51
58
 
52
59
  ## Quick Start
53
60
 
54
61
  After installation, run `/clear` to load Plastic conventions, then:
55
62
 
56
- 1. Say "new intent" or run `/plastic:creating-intent` to create your first intent
63
+ 1. Say "new intent" or run `/plastic-creating-intent` to create your first intent
57
64
  2. Describe what you want to accomplish
58
- 3. Use `/plastic:brainstorming` to explore the design
59
- 4. Use `/plastic:writing-plans` to create an implementation plan
60
- 5. Use `/plastic:executing-plan` to deliver it
65
+ 3. Use `/plastic-brainstorming` to explore the design
66
+ 4. Use `/plastic-writing-plans` to create an implementation plan
67
+ 5. Use `/plastic-executing-plan` to deliver it
61
68
 
62
69
  Or say "auto" to let the agent handle the full lifecycle autonomously.
63
70
 
64
71
  ## Conventions
65
72
 
66
73
  All conventions live in `AGENTS.md`, distributed to `~/.plastic/AGENTS.md`
67
- during installation. Run `plastic:doctor` to check installation health.
74
+ during installation. Run `plastic-doctor` to check installation health.
68
75
 
69
76
  ## License
70
77
 
@@ -1,5 +1,5 @@
1
1
  ---
2
- name: plastic:future-intent-researcher
2
+ name: plastic-future-intent-researcher
3
3
  description: |
4
4
  Use this agent to research future intents autonomously. Picks up parked
5
5
  intents from INDEX.md, investigates them via web search and codebase analysis,
@@ -1,5 +1,5 @@
1
1
  ---
2
- name: plastic:intent-curator
2
+ name: plastic-intent-curator
3
3
  description: |
4
4
  Use this agent when completing or reviewing intents, reorganizing the index,
5
5
  or when the intent store needs maintenance. Examples:
package/deprecations.yml CHANGED
@@ -12,12 +12,13 @@
12
12
  # link: optional URL to migration guide
13
13
 
14
14
  deprecations:
15
- - id: cc-plugin-to-npx
15
+ - id: cc-plugin-to-hyphen-skills
16
16
  severity: warning
17
- summary: "Plastic distribution is moving from Claude Code plugin to npx install"
17
+ summary: "Plastic now ships as flat hyphen-named personal skills (plastic-doctor), not a Claude Code plugin. Invocation changed from plastic:<name> to plastic-<name>."
18
18
  migration_steps:
19
- - "Install new distribution: npx @zalom/plastic@alpha --claude"
20
- - "Verify: check that ~/.plastic/ is intact and hooks work"
21
- - "Remove old plugin: /plugin remove plastic"
19
+ - "Re-run the installer: npx @zalom/plastic@latest --claude (bunx also works)"
20
+ - "It auto-removes the old plugin/marketplace registration no /plugin step needed"
21
+ - "Invoke skills with a hyphen now: /plastic-doctor, /plastic-auto, etc."
22
+ - "Run /plastic-doctor to verify"
22
23
  introduced: "1.0.0"
23
24
  removal: "2.0.0"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zalom/plastic",
3
- "version": "1.0.0-alpha.14",
3
+ "version": "1.0.0-alpha.16",
4
4
  "description": "Intent-driven idea development system for AI coding agents",
5
5
  "type": "module",
6
6
  "bin": {
package/scripts/doctor.rb CHANGED
@@ -12,6 +12,7 @@
12
12
  require "json"
13
13
  require "yaml"
14
14
  require "time"
15
+ require "date"
15
16
 
16
17
  PLASTIC_HOME = File.join(Dir.home, ".plastic")
17
18
 
@@ -150,21 +151,31 @@ def parse_frontmatter(path)
150
151
  parts = content.split("---", 3)
151
152
  return nil if parts.length < 3
152
153
 
153
- YAML.safe_load(parts[1]) || {}
154
+ # created: dates parse as Date objects, which safe_load rejects by default —
155
+ # permit Date/Time so valid frontmatter isn't misreported as missing.
156
+ YAML.safe_load(parts[1], permitted_classes: [Date, Time]) || {}
154
157
  rescue
155
158
  nil
156
159
  end
157
160
 
158
161
  # --- Collect all intent directories (global + project stores) ---
159
162
 
163
+ # Child directories of a store, excluding dotfiles/dot-directories
164
+ # (e.g. .obsidian, .git) which are tooling artifacts, not intents.
165
+ def store_intent_dirs(store)
166
+ Dir.children(store).reject { |e| e.start_with?(".") }.select do |e|
167
+ File.directory?(File.join(store, e))
168
+ end
169
+ end
170
+
160
171
  def all_intent_dirs
161
172
  dirs = []
162
173
 
163
174
  global_store = File.join(PLASTIC_HOME, "store")
164
175
  if File.directory?(global_store)
165
- Dir.children(global_store).each do |entry|
176
+ store_intent_dirs(global_store).each do |entry|
166
177
  full = File.join(global_store, entry)
167
- dirs << { path: full, name: entry, scope: "global" } if File.directory?(full)
178
+ dirs << { path: full, name: entry, scope: "global" }
168
179
  end
169
180
  end
170
181
 
@@ -174,9 +185,9 @@ def all_intent_dirs
174
185
  project_store = File.join(projects_root, project, "store")
175
186
  next unless File.directory?(project_store)
176
187
 
177
- Dir.children(project_store).each do |entry|
188
+ store_intent_dirs(project_store).each do |entry|
178
189
  full = File.join(project_store, entry)
179
- dirs << { path: full, name: entry, scope: "project:#{project}" } if File.directory?(full)
190
+ dirs << { path: full, name: entry, scope: "project:#{project}" }
180
191
  end
181
192
  end
182
193
  end
@@ -227,7 +238,7 @@ def check_global_store
227
238
  # orphaned_intents — directories in store/ not referenced in INDEX.md
228
239
  store_dir = File.join(PLASTIC_HOME, "store")
229
240
  if File.directory?(store_dir)
230
- intent_dirs = Dir.children(store_dir).select { |e| File.directory?(File.join(store_dir, e)) }
241
+ intent_dirs = store_intent_dirs(store_dir)
231
242
  orphans = intent_dirs.reject { |d| content.include?("store/#{d}") }
232
243
 
233
244
  if orphans.empty?
@@ -459,22 +470,30 @@ def check_claude_registration(agent_dir)
459
470
  end
460
471
  end
461
472
 
462
- # skills_exist
463
- skills_dir = File.join(agent_dir, "skills", "plastic")
464
- if File.directory?(skills_dir) && !Dir.empty?(skills_dir)
465
- checks << check(
473
+ # skills_exist — flat, hyphen-namespaced personal skills (plastic-<name>/)
474
+ checks << flat_skills_check(agent_dir, "--claude")
475
+
476
+ checks
477
+ end
478
+
479
+ # Plastic skills install as ~/.claude/skills/plastic-<name>/SKILL.md. Pass if at
480
+ # least one such skill is present.
481
+ def flat_skills_check(agent_dir, installer_flag)
482
+ skills_root = File.join(agent_dir, "skills")
483
+ found = Dir.glob(File.join(skills_root, "plastic-*", "SKILL.md"))
484
+
485
+ if !found.empty?
486
+ check(
466
487
  category: "agent_registration", name: "skills_exist", status: "pass",
467
- message: "Skills directory exists at #{tilde(skills_dir)}"
488
+ message: "#{found.size} plastic-* skill(s) installed in #{tilde(skills_root)}"
468
489
  )
469
490
  else
470
- checks << check(
491
+ check(
471
492
  category: "agent_registration", name: "skills_exist", status: "fail",
472
- message: "Skills directory missing or empty at #{tilde(skills_dir)}",
473
- fixable: true, fix_hint: "Re-run the Plastic installer: npx @zalom/plastic@latest --claude"
493
+ message: "No plastic-* skills found in #{tilde(skills_root)}",
494
+ fixable: true, fix_hint: "Re-run the Plastic installer: npx @zalom/plastic@latest #{installer_flag}"
474
495
  )
475
496
  end
476
-
477
- checks
478
497
  end
479
498
 
480
499
  def check_generic_agent_registration(agent_key, agent_dir)
@@ -482,19 +501,7 @@ def check_generic_agent_registration(agent_key, agent_dir)
482
501
  config = AGENTS[agent_key]
483
502
 
484
503
  # For codex/hermes: just check skills exist (no settings.json hooks)
485
- skills_dir = File.join(agent_dir, "skills", "plastic")
486
- if File.directory?(skills_dir) && !Dir.empty?(skills_dir)
487
- checks << check(
488
- category: "agent_registration", name: "skills_exist", status: "pass",
489
- message: "Skills directory exists at #{tilde(skills_dir)}"
490
- )
491
- else
492
- checks << check(
493
- category: "agent_registration", name: "skills_exist", status: "fail",
494
- message: "Skills directory missing or empty at #{tilde(skills_dir)}",
495
- fixable: true, fix_hint: "Re-run the Plastic installer: npx @zalom/plastic@latest --#{agent_key}"
496
- )
497
- end
504
+ checks << flat_skills_check(agent_dir, "--#{agent_key}")
498
505
 
499
506
  checks
500
507
  end
@@ -695,7 +702,7 @@ def check_project_stores
695
702
  checks << check(
696
703
  category: "project_stores", name: "project_yml_exists", status: "warn",
697
704
  message: "project.yml missing for project '#{slug}'",
698
- fixable: true, fix_hint: "Create project.yml from template — see plastic:creating-project"
705
+ fixable: true, fix_hint: "Create project.yml from template — see plastic-creating-project"
699
706
  )
700
707
  end
701
708
 
@@ -4,7 +4,7 @@
4
4
 
5
5
  # Usage: hook-auto-arm <message>
6
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.
7
+ # 1. Detect auto-trigger phrases -> steer the agent to invoke plastic-auto.
8
8
  # 2. If auto mode is armed and the active intent hasn't reached How -> remind the agent
9
9
  # that project-code edits are gate-blocked until plan.md + checklist.md exist.
10
10
  # Outputs UserPromptSubmit hookSpecificOutput JSON, or exits silently.
@@ -16,11 +16,11 @@ message = (ARGV[0] || "").downcase
16
16
  parts = []
17
17
 
18
18
  # --- 1. Auto-trigger steering ---
19
- AUTO_TRIGGERS = ["take it from here", "deliver this", "/plastic:auto", "auto mode"].freeze
19
+ AUTO_TRIGGERS = ["take it from here", "deliver this", "/plastic-auto", "auto mode"].freeze
20
20
  # bare "auto" only as a standalone word to avoid matching "automatic", "automation", etc.
21
21
  triggered = AUTO_TRIGGERS.any? { |p| message.include?(p) } || message.match?(/\bauto\b/)
22
22
  if triggered
23
- parts << "Auto-mode request detected. Invoke the plastic:auto skill to deliver the " \
23
+ parts << "Auto-mode request detected. Invoke the plastic-auto skill to deliver the " \
24
24
  "active intent autonomously — it arms the lifecycle gate so project code " \
25
25
  "cannot be edited before plan.md + checklist.md exist."
26
26
  end
@@ -116,7 +116,7 @@ if stale.any?
116
116
  parts << ""
117
117
  end
118
118
 
119
- parts << "Follow the plastic:continuing skill workflow.\n"
119
+ parts << "Follow the plastic-continuing skill workflow.\n"
120
120
  parts << "1. If active intents exist: read their state and resume\n"
121
121
  parts << "2. If no active intents: present future intents as options\n"
122
122
  parts << "3. If stale intents exist: surface them and ask user to decide"
@@ -102,9 +102,9 @@ if is_stage_file || is_action_file
102
102
  stage_labels = { "what" => "What", "why" => "Why", "how" => "How", "exec" => "Exec", "done" => "Done" }
103
103
  next_hints = {
104
104
  "why" => "write spec.md",
105
- "how" => "Why complete. Invoke plastic:auto to deliver autonomously, or write plan.md manually.",
106
- "exec" => "How complete. Invoke plastic:auto or plastic:executing-plan to execute, or work through the checklist manually.",
107
- "done" => "Exec complete. Intent must be completed now — write outcome.md, update INDEX.md, auto-commit. Use plastic:auto or do it manually."
105
+ "how" => "Why complete. Invoke plastic-auto to deliver autonomously, or write plan.md manually.",
106
+ "exec" => "How complete. Invoke plastic-auto or plastic-executing-plan to execute, or work through the checklist manually.",
107
+ "done" => "Exec complete. Intent must be completed now — write outcome.md, update INDEX.md, auto-commit. Use plastic-auto or do it manually."
108
108
  }
109
109
 
110
110
  context_parts = ["PLASTIC"]
@@ -168,7 +168,7 @@ cache_file = "#{store_root}/.cache/update-check.json"
168
168
  if File.exist?(cache_file)
169
169
  cache = JSON.parse(File.read(cache_file)) rescue {}
170
170
  if cache["updateAvailable"]
171
- update_notice = "Plastic update available: #{cache["current"]} -> #{cache["latest"]} — run /plastic:update"
171
+ update_notice = "Plastic update available: #{cache["current"]} -> #{cache["latest"]} — run /plastic-update"
172
172
  end
173
173
  end
174
174