@zalom/plastic 2.0.0-alpha.9 → 2.0.2
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 +21 -16
- 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 +8 -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/docs/help/completion-and-done.md +53 -0
- 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 +11 -13
- package/{skills/conventions/references → docs/help}/maintenance-and-revisions.md +1 -1
- package/{skills/conventions/references → docs/help}/roadmaps.md +5 -4
- 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 +55 -2
- 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 +378 -56
- 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 +7 -0
- 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 +74 -91
- 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 +111 -0
- package/scripts/lib/cli/commands/auto_report.rb +50 -0
- package/scripts/lib/cli/commands/auto_take.rb +68 -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 +58 -0
- package/scripts/lib/cli/commands/intent_end.rb +75 -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 +79 -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 +46 -0
- package/scripts/lib/cli/commands/project_list.rb +20 -0
- package/scripts/lib/cli/commands/project_new.rb +95 -0
- package/scripts/lib/cli/commands/query.rb +31 -0
- package/scripts/lib/cli/commands/render.rb +35 -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 +77 -0
- package/scripts/lib/cli/commands/roadmap_show.rb +65 -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 +55 -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 +23 -14
- 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 +235 -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 +543 -71
- package/scripts/lib/intent_screen.rb +4 -4
- 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 +350 -54
- 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 +921 -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 +1371 -47
- 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 +170 -12
- 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 +526 -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 +365 -28
- 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 +67 -19
- 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/untouched_scaffold.rb +51 -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 +65 -60
- package/scripts/project-links +6 -21
- 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 +177 -16
- package/scripts/roadmap-graph +125 -0
- package/scripts/roadmap-savepoint +7 -0
- package/scripts/rollback.rb +5 -1
- 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 +31 -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 +8 -3
- 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 -296
- 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/conventions/references/completion-and-done.md +0 -43
- 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 -176
- 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
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../command"
|
|
4
|
+
require_relative "../legacy"
|
|
5
|
+
|
|
6
|
+
# `plastic project links` - projects every store's `## Links` sections from
|
|
7
|
+
# frontmatter (`project-links`, run through Legacy).
|
|
8
|
+
module Plastic
|
|
9
|
+
class CLI
|
|
10
|
+
module Commands
|
|
11
|
+
class ProjectLinks < Command
|
|
12
|
+
USAGE_LINE = "plastic project links [--dry-run] [--json]"
|
|
13
|
+
|
|
14
|
+
def initialize(argv, runner: nil, **streams)
|
|
15
|
+
super(argv, **streams)
|
|
16
|
+
@runner = runner
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def call
|
|
20
|
+
status = legacy.run("project-links", "--plastic-home", scope.plastic_home, *dry_run_flag)
|
|
21
|
+
raise Failure, "project-links exited #{status}" unless status.zero?
|
|
22
|
+
|
|
23
|
+
if options[:dry_run]
|
|
24
|
+
@output.next_step("none", because: "the preview wrote no files")
|
|
25
|
+
else
|
|
26
|
+
@output.next_step("plastic status", because: "the Links sections just rebuilt across every store")
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
private
|
|
31
|
+
|
|
32
|
+
def switches(parser)
|
|
33
|
+
parser.on("--dry-run") { @options[:dry_run] = true }
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def dry_run_flag
|
|
37
|
+
options[:dry_run] ? ["--dry-run"] : []
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def legacy
|
|
41
|
+
@legacy ||= Legacy.new(env: @env, runner: @runner, output: @output, json: options[:json])
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../command"
|
|
4
|
+
|
|
5
|
+
# `plastic project list` - every store this machine holds, global and
|
|
6
|
+
# project, straight from Scope#stores, in this process.
|
|
7
|
+
module Plastic
|
|
8
|
+
class CLI
|
|
9
|
+
module Commands
|
|
10
|
+
class ProjectList < Command
|
|
11
|
+
USAGE_LINE = "plastic project list [--json]"
|
|
12
|
+
|
|
13
|
+
def call
|
|
14
|
+
scope.stores.each { |store| @output.row(store[:slug], store[:root]) }
|
|
15
|
+
@output.next_step("plastic status", because: "status shows what is active in each store this just listed")
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "yaml"
|
|
4
|
+
require "date"
|
|
5
|
+
require_relative "../command"
|
|
6
|
+
require_relative "../legacy"
|
|
7
|
+
require_relative "../../store_provisioning"
|
|
8
|
+
|
|
9
|
+
# `plastic project new` - registers a project in projects.yml, then provisions
|
|
10
|
+
# and validates its store (`provision-project-store`, `validate-project`, run
|
|
11
|
+
# through Legacy). The project directory must already exist; this command
|
|
12
|
+
# never makes one. A slug is lowercase letters, digits and hyphens, starting
|
|
13
|
+
# with a letter or digit, and never `global`. A slug or a path already
|
|
14
|
+
# registered is a Failure.
|
|
15
|
+
module Plastic
|
|
16
|
+
class CLI
|
|
17
|
+
module Commands
|
|
18
|
+
class ProjectNew < Command
|
|
19
|
+
USAGE_LINE = "plastic project new SLUG --path PATH [--parent ID] [--json]"
|
|
20
|
+
|
|
21
|
+
SLUG = /\A[a-z0-9][a-z0-9-]*\z/
|
|
22
|
+
RESERVED = "global"
|
|
23
|
+
|
|
24
|
+
def initialize(argv, runner: nil, **streams)
|
|
25
|
+
super(argv, **streams)
|
|
26
|
+
@runner = runner
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def call
|
|
30
|
+
raise Usage, "SLUG is required" if slug.to_s.empty?
|
|
31
|
+
raise Usage, "--path is required" if options[:path].to_s.empty?
|
|
32
|
+
unless slug.match?(SLUG) && slug != RESERVED
|
|
33
|
+
raise Usage, "SLUG must be lowercase letters, digits and hyphens, start with a letter or digit, and not be global"
|
|
34
|
+
end
|
|
35
|
+
raise Failure, "#{options[:path]} does not exist" unless Dir.exist?(options[:path])
|
|
36
|
+
raise Failure, "#{options[:path]} has no AGENTS.md; write one first" unless File.file?(File.join(options[:path], "AGENTS.md"))
|
|
37
|
+
raise Failure, "#{slug} is already registered" if StoreProvisioning.registered?(slug, scope.plastic_home)
|
|
38
|
+
owner = slug_for_path
|
|
39
|
+
raise Failure, "#{options[:path]} is already registered as #{owner}" if owner
|
|
40
|
+
|
|
41
|
+
register
|
|
42
|
+
run("provision-project-store", slug, "--home", scope.plastic_home)
|
|
43
|
+
run("validate-project", slug, "--home", scope.plastic_home)
|
|
44
|
+
@output.next_step("plastic project links", because: "the new store's Links section needs projecting before anything cites it")
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
private
|
|
48
|
+
|
|
49
|
+
def slug
|
|
50
|
+
arguments.first
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def switches(parser)
|
|
54
|
+
parser.on("--path PATH") { |v| @options[:path] = v }
|
|
55
|
+
parser.on("--parent ID") { |v| @options[:parent] = v }
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def slug_for_path
|
|
59
|
+
path = File.realpath(options[:path])
|
|
60
|
+
projects.find do |_slug, info|
|
|
61
|
+
registered = info.is_a?(Hash) && info["path"].is_a?(String) && info["path"]
|
|
62
|
+
registered && Dir.exist?(registered) && File.realpath(registered) == path
|
|
63
|
+
end&.first
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def projects
|
|
67
|
+
data = File.exist?(projects_yml) ? YAML.safe_load_file(projects_yml) : nil
|
|
68
|
+
(data.is_a?(Hash) && data["projects"].is_a?(Hash)) ? data["projects"] : {}
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def projects_yml
|
|
72
|
+
File.join(scope.plastic_home, "projects.yml")
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def register
|
|
76
|
+
data = File.exist?(projects_yml) ? (YAML.safe_load_file(projects_yml) || {}) : {}
|
|
77
|
+
data["projects"] ||= {}
|
|
78
|
+
entry = {"path" => File.expand_path(options[:path]), "registered" => Date.today.to_s, "status" => "active"}
|
|
79
|
+
entry["parent"] = options[:parent] if options[:parent]
|
|
80
|
+
data["projects"][slug] = entry
|
|
81
|
+
File.write(projects_yml, YAML.dump(data))
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def run(script, *args)
|
|
85
|
+
status = legacy.run(script, *args)
|
|
86
|
+
raise Failure, "#{script} exited #{status}" unless status.zero?
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def legacy
|
|
90
|
+
@legacy ||= Legacy.new(env: @env, runner: @runner, output: @output, json: options[:json])
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../command"
|
|
4
|
+
require_relative "../../search_index"
|
|
5
|
+
|
|
6
|
+
module Plastic
|
|
7
|
+
class CLI
|
|
8
|
+
module Commands
|
|
9
|
+
class Query < Command
|
|
10
|
+
USAGE_LINE = "plastic query SQL [--json]"
|
|
11
|
+
|
|
12
|
+
def call
|
|
13
|
+
raise Usage, "SQL is missing" if arguments.empty?
|
|
14
|
+
raise Failure, "no index at #{database}; run plastic index" unless File.file?(database)
|
|
15
|
+
|
|
16
|
+
rows = Sqlite.call(database, arguments.join(" "), readonly: true)
|
|
17
|
+
rows.each_with_index { |row, index| @output.row((index + 1).to_s, row.map { |key, value| "#{key}=#{value}" }.join(" ")) }
|
|
18
|
+
@output.next_step("none", because: "the rows are the whole answer; the database is opened read-only")
|
|
19
|
+
rescue Sqlite::Error => e
|
|
20
|
+
raise Failure, e.message
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
private
|
|
24
|
+
|
|
25
|
+
def database
|
|
26
|
+
SearchIndex.path(scope.plastic_home)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../command"
|
|
4
|
+
|
|
5
|
+
module Plastic
|
|
6
|
+
class CLI
|
|
7
|
+
module Commands
|
|
8
|
+
class Render < Command
|
|
9
|
+
USAGE_LINE = "plastic render FILE"
|
|
10
|
+
STYLE = File.expand_path("../../../../templates/render.css", __dir__)
|
|
11
|
+
# A leading YAML block is metadata; RDoc would render it as body text.
|
|
12
|
+
FRONTMATTER = /\A---\r?\n.*?^---[ \t]*(\r?\n|\z)/m
|
|
13
|
+
|
|
14
|
+
def call
|
|
15
|
+
file = arguments.first or raise Usage, "FILE is the markdown file to render"
|
|
16
|
+
raise Failure, "no file at #{file}" unless File.file?(file)
|
|
17
|
+
|
|
18
|
+
require "rubygems"
|
|
19
|
+
require "rdoc"
|
|
20
|
+
body = RDoc::Markdown.parse(File.read(file, encoding: "UTF-8").sub(FRONTMATTER, "")).accept(html_formatter)
|
|
21
|
+
@output.raw("<!doctype html>\n<meta charset=\"utf-8\">\n<title>#{File.basename(file)}</title>\n" \
|
|
22
|
+
"<style>\n#{File.read(STYLE)}</style>\n#{body}")
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
private
|
|
26
|
+
|
|
27
|
+
def html_formatter(formatter_class = RDoc::Markup::ToHtml)
|
|
28
|
+
initializer = formatter_class.instance_method(:initialize)
|
|
29
|
+
options = (initializer.parameters.any? { |_, name| name == :options }) ? [RDoc::Options.new] : []
|
|
30
|
+
formatter_class.new(*options)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "subcommand_list"
|
|
4
|
+
|
|
5
|
+
# `plastic roadmap` - the list of `plastic roadmap ...` subcommands, straight
|
|
6
|
+
# out of the table; a word that names none of them is a usage error naming
|
|
7
|
+
# the same list, so a typo never falls through to a script.
|
|
8
|
+
module Plastic
|
|
9
|
+
class CLI
|
|
10
|
+
module Commands
|
|
11
|
+
class Roadmap < SubcommandList
|
|
12
|
+
USAGE_LINE = "plastic roadmap SUBCOMMAND [options]"
|
|
13
|
+
PREFIX = "roadmap"
|
|
14
|
+
NEXT = "plastic roadmap next"
|
|
15
|
+
BECAUSE = "next names the roadmap most worth continuing, with no slug to guess"
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../command"
|
|
4
|
+
require_relative "../legacy"
|
|
5
|
+
|
|
6
|
+
# `plastic roadmap check` - the roadmap graph's batches, ready set and any
|
|
7
|
+
# cycle or dangling id (`roadmap-graph check`, run through Legacy).
|
|
8
|
+
#
|
|
9
|
+
# A roadmap with no `## Graph` section has nothing to check, and the script's
|
|
10
|
+
# own exit code says only that something failed. That case is named here, with
|
|
11
|
+
# the command that repairs it, so the reader never has to know which script ran.
|
|
12
|
+
module Plastic
|
|
13
|
+
class CLI
|
|
14
|
+
module Commands
|
|
15
|
+
class RoadmapCheck < Command
|
|
16
|
+
USAGE_LINE = "plastic roadmap check SLUG [--json]"
|
|
17
|
+
|
|
18
|
+
def initialize(argv, runner: nil, **streams)
|
|
19
|
+
super(argv, **streams)
|
|
20
|
+
@runner = runner
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def call
|
|
24
|
+
raise Usage, "SLUG is required" if slug.to_s.empty?
|
|
25
|
+
raise Failure, "no roadmap #{slug} in #{File.basename(scope.roadmaps_dir)}" unless File.file?(path)
|
|
26
|
+
raise Failure, "#{slug} has no ## Graph section; plastic roadmap migrate #{slug} writes one from its batches" unless graph?
|
|
27
|
+
|
|
28
|
+
status = legacy.run("roadmap-graph", "check", path)
|
|
29
|
+
raise Failure, "roadmap-graph exited #{status}" unless status.zero?
|
|
30
|
+
|
|
31
|
+
@output.next_step("plastic roadmap show #{slug}", because: "the graph just checked out clean")
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
private
|
|
35
|
+
|
|
36
|
+
def graph?
|
|
37
|
+
File.foreach(path).any? { |line| line.start_with?("## Graph") }
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def slug
|
|
41
|
+
arguments.first
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def path
|
|
45
|
+
File.join(scope.roadmaps_dir, "#{slug}.md")
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def legacy
|
|
49
|
+
@legacy ||= Legacy.new(env: @env, runner: @runner, output: @output, json: options[:json])
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../command"
|
|
4
|
+
require_relative "../legacy"
|
|
5
|
+
|
|
6
|
+
# `plastic roadmap log` - appends a savepoint line to a roadmap's ledger
|
|
7
|
+
# (`roadmap-savepoint append`, run through Legacy).
|
|
8
|
+
module Plastic
|
|
9
|
+
class CLI
|
|
10
|
+
module Commands
|
|
11
|
+
class RoadmapLog < Command
|
|
12
|
+
USAGE_LINE = 'plastic roadmap log SLUG EVENT "TEXT" [--json]'
|
|
13
|
+
|
|
14
|
+
def initialize(argv, runner: nil, **streams)
|
|
15
|
+
super(argv, **streams)
|
|
16
|
+
@runner = runner
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def call
|
|
20
|
+
raise Usage, "SLUG is required" if slug.to_s.empty?
|
|
21
|
+
raise Usage, "EVENT is required" if event.to_s.empty?
|
|
22
|
+
raise Usage, "TEXT is required" if text.to_s.empty?
|
|
23
|
+
|
|
24
|
+
status = legacy.run("roadmap-savepoint", "append", "--roadmap", path, "--event", event, "--detail", text)
|
|
25
|
+
raise Failure, "roadmap-savepoint exited #{status}" unless status.zero?
|
|
26
|
+
|
|
27
|
+
@output.next_step("plastic roadmap show #{slug}", because: "the log line just landed on the state screen")
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
private
|
|
31
|
+
|
|
32
|
+
def slug
|
|
33
|
+
arguments[0]
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def event
|
|
37
|
+
arguments[1]
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def text
|
|
41
|
+
arguments[2]
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def path
|
|
45
|
+
File.join(scope.roadmaps_dir, "#{slug}.md")
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def legacy
|
|
49
|
+
@legacy ||= Legacy.new(env: @env, runner: @runner, output: @output, json: options[:json])
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../command"
|
|
4
|
+
require_relative "../legacy"
|
|
5
|
+
|
|
6
|
+
# `plastic roadmap migrate` - writes a roadmap's `## Graph` section from the
|
|
7
|
+
# batch headings it already carries (`roadmap-graph migrate`, run through
|
|
8
|
+
# Legacy). This is the repair `plastic roadmap check` names when a roadmap has
|
|
9
|
+
# no graph, so the CLI can perform every repair it asks for.
|
|
10
|
+
module Plastic
|
|
11
|
+
class CLI
|
|
12
|
+
module Commands
|
|
13
|
+
class RoadmapMigrate < Command
|
|
14
|
+
USAGE_LINE = "plastic roadmap migrate SLUG [--dry-run] [--json]"
|
|
15
|
+
|
|
16
|
+
def initialize(argv, runner: nil, **streams)
|
|
17
|
+
super(argv, **streams)
|
|
18
|
+
@runner = runner
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def call
|
|
22
|
+
raise Usage, "SLUG is required" if slug.to_s.empty?
|
|
23
|
+
raise Failure, "no roadmap #{slug} in #{File.basename(scope.roadmaps_dir)}" unless File.file?(path)
|
|
24
|
+
|
|
25
|
+
arguments_for_script = ["migrate", path]
|
|
26
|
+
arguments_for_script << "--dry-run" if options[:dry_run]
|
|
27
|
+
status = legacy.run("roadmap-graph", *arguments_for_script)
|
|
28
|
+
raise Failure, "roadmap-graph exited #{status}" unless status.zero?
|
|
29
|
+
|
|
30
|
+
@output.next_step("plastic roadmap check #{slug}", because: "a written graph is what check reads")
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
private
|
|
34
|
+
|
|
35
|
+
def switches(parser)
|
|
36
|
+
parser.on("--dry-run") { @options[:dry_run] = true }
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def slug
|
|
40
|
+
arguments.first
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def path
|
|
44
|
+
File.join(scope.roadmaps_dir, "#{slug}.md")
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def legacy
|
|
48
|
+
@legacy ||= Legacy.new(env: @env, runner: @runner, output: @output, json: options[:json])
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "json"
|
|
4
|
+
require_relative "../command"
|
|
5
|
+
require_relative "../legacy"
|
|
6
|
+
|
|
7
|
+
# `plastic roadmap next` - the roadmap most worth continuing right now
|
|
8
|
+
# (`roadmap-next --which`, run through Legacy). The script speaks JSON, so this
|
|
9
|
+
# command renders it as a screen and leaves the document to `--json`, the way
|
|
10
|
+
# every other command reads.
|
|
11
|
+
module Plastic
|
|
12
|
+
class CLI
|
|
13
|
+
module Commands
|
|
14
|
+
class RoadmapNext < Command
|
|
15
|
+
USAGE_LINE = "plastic roadmap next [--json]"
|
|
16
|
+
AFTER = "plastic roadmap show SLUG"
|
|
17
|
+
BECAUSE = "the winner it just named is the slug that command wants"
|
|
18
|
+
TIED = "the roadmaps tie; the first is shown, and any of them may be picked"
|
|
19
|
+
|
|
20
|
+
def initialize(argv, runner: nil, **streams)
|
|
21
|
+
super(argv, **streams)
|
|
22
|
+
@runner = runner
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def call
|
|
26
|
+
report = parse(*legacy.capture("roadmap-next", "--roadmaps-dir", scope.roadmaps_dir, "--which"))
|
|
27
|
+
screen(report)
|
|
28
|
+
@output.next_step(after(report), because: (report["state"] == "tie") ? TIED : BECAUSE)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
private
|
|
32
|
+
|
|
33
|
+
def parse(text, status)
|
|
34
|
+
raise Failure, "roadmap-next exited #{status}" unless status.zero?
|
|
35
|
+
|
|
36
|
+
JSON.parse(text)
|
|
37
|
+
rescue JSON::ParserError
|
|
38
|
+
raise Failure, "roadmap-next did not print a report"
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def after(report)
|
|
42
|
+
slug = (report["roadmap"] || tied(report).first).to_s
|
|
43
|
+
slug.empty? ? AFTER : AFTER.sub("SLUG", slug)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# roadmap-next --which reports a tie as state "tie" with "tie" false and
|
|
47
|
+
# each candidate as an object; older reports carried plain names.
|
|
48
|
+
def tied(report)
|
|
49
|
+
Array(report["tie_candidates"]).map { |candidate| candidate.is_a?(Hash) ? candidate["roadmap"] : candidate }
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def screen(report)
|
|
53
|
+
@output.row("state", report["state"])
|
|
54
|
+
@output.row("roadmap", report["roadmap"] || "none")
|
|
55
|
+
@output.row("wave", report["frontier_wave"]) unless report["frontier_wave"].to_s.empty?
|
|
56
|
+
@output.row("next", queue(report["dispatchable_queue"]))
|
|
57
|
+
@output.row("delivering", entries(report["in_flight"]))
|
|
58
|
+
@output.row("blocked", entries(report["blocked"]))
|
|
59
|
+
@output.row("tie", tied(report).join(", ")) if report["tie"] || report["state"] == "tie"
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def queue(list)
|
|
63
|
+
rows = entries(list)
|
|
64
|
+
rows.empty? ? "none" : rows
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def entries(list)
|
|
68
|
+
Array(list).map { |entry| [entry["id"], entry["status"], entry["wave"]].compact.join(" ") }
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def legacy
|
|
72
|
+
@legacy ||= Legacy.new(env: @env, runner: @runner, output: @output, json: options[:json])
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../command"
|
|
4
|
+
require_relative "../legacy"
|
|
5
|
+
require_relative "../../roadmap_graph"
|
|
6
|
+
|
|
7
|
+
# `plastic roadmap show` - a roadmap's state screen (`report-screen roadmap
|
|
8
|
+
# FILE state`, run through Legacy). SLUG is required: `plastic roadmap next`
|
|
9
|
+
# is the command that picks one when the caller has none in mind.
|
|
10
|
+
module Plastic
|
|
11
|
+
class CLI
|
|
12
|
+
module Commands
|
|
13
|
+
class RoadmapShow < Command
|
|
14
|
+
USAGE_LINE = "plastic roadmap show SLUG [--json]"
|
|
15
|
+
|
|
16
|
+
def initialize(argv, runner: nil, **streams)
|
|
17
|
+
super(argv, **streams)
|
|
18
|
+
@runner = runner
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def call
|
|
22
|
+
raise Usage, "SLUG is required" if slug.to_s.empty?
|
|
23
|
+
|
|
24
|
+
status = legacy.run("report-screen", "roadmap", path, "state")
|
|
25
|
+
raise Failure, "report-screen exited #{status}" unless status.zero?
|
|
26
|
+
|
|
27
|
+
problems = graph_problems
|
|
28
|
+
problems.each { |problem| @output.row("warning", problem) }
|
|
29
|
+
if problems.empty?
|
|
30
|
+
@output.next_step("plastic roadmap log #{slug} EVENT \"TEXT\"", because: "a savepoint is how this state screen keeps moving")
|
|
31
|
+
else
|
|
32
|
+
@output.next_step("plastic roadmap check #{slug}", because: "the graph has problems the state screen cannot show")
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
private
|
|
37
|
+
|
|
38
|
+
# A cycle or a graph id no batch lists (acceptance N8). The state screen
|
|
39
|
+
# cannot show either, so they are named under it.
|
|
40
|
+
def graph_problems
|
|
41
|
+
return [] unless File.file?(path)
|
|
42
|
+
|
|
43
|
+
result = RoadmapGraph.analyze(path)
|
|
44
|
+
problems = []
|
|
45
|
+
problems << "cyclic graph: #{result[:cycle].join(" > ")}" if result[:cycle]
|
|
46
|
+
dangling = Array(result[:dangling])
|
|
47
|
+
problems << "graph names #{dangling.join(", ")}, no batch entry" unless dangling.empty?
|
|
48
|
+
problems
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def slug
|
|
52
|
+
arguments.first
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def path
|
|
56
|
+
File.join(scope.roadmaps_dir, "#{slug}.md")
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def legacy
|
|
60
|
+
@legacy ||= Legacy.new(env: @env, runner: @runner, output: @output, json: options[:json])
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "installer_verb"
|
|
4
|
+
|
|
5
|
+
# `plastic rollback` - steps back to a version this machine has already run. The
|
|
6
|
+
# work is still scripts/rollback.rb, run through Legacy.
|
|
7
|
+
module Plastic
|
|
8
|
+
class CLI
|
|
9
|
+
module Commands
|
|
10
|
+
class Rollback < InstallerVerb
|
|
11
|
+
USAGE_LINE = "plastic rollback [--version VERSION] [--downgrade] [--upgrade] [--reinstall]"
|
|
12
|
+
FLAGS = %w[--version --downgrade --upgrade --reinstall].freeze
|
|
13
|
+
|
|
14
|
+
SCRIPT = "rollback.rb"
|
|
15
|
+
AFTER = "plastic version"
|
|
16
|
+
BECAUSE = "the version says which build is installed"
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../command"
|
|
4
|
+
require_relative "../../search_index"
|
|
5
|
+
require_relative "../../rlm/query"
|
|
6
|
+
|
|
7
|
+
module Plastic
|
|
8
|
+
class CLI
|
|
9
|
+
module Commands
|
|
10
|
+
class Search < Command
|
|
11
|
+
USAGE_LINE = "plastic search TERMS [--ask] [--project SLUG] [--limit N] [--json]"
|
|
12
|
+
DEFAULT_LIMIT = 10
|
|
13
|
+
|
|
14
|
+
def call
|
|
15
|
+
raise Usage, "TERMS is missing" if arguments.empty?
|
|
16
|
+
raise Failure, "no index at #{database}; run plastic index" unless File.file?(database)
|
|
17
|
+
|
|
18
|
+
rows = options[:ask] ? RLM::Query.new(RLM::Probe.new(corpus, limit: limit)).call(arguments.join(" ")) : found(arguments, limit)
|
|
19
|
+
rows.each { |row| @output.row(row["path"], row["excerpt"].gsub(/\s+/, " ").strip) }
|
|
20
|
+
@output.row("result", "no match") if rows.empty?
|
|
21
|
+
@output.next_step("none", because: "the search is complete")
|
|
22
|
+
rescue Sqlite::Error => e
|
|
23
|
+
raise Failure, e.message
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
private
|
|
27
|
+
|
|
28
|
+
def switches(parser)
|
|
29
|
+
parser.on("--ask") { @options[:ask] = true }
|
|
30
|
+
parser.on("--project SLUG") { |slug| @options[:project] = slug }
|
|
31
|
+
parser.on("--limit N", Integer) { |limit| @options[:limit] = limit }
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def limit
|
|
35
|
+
options[:limit] || DEFAULT_LIMIT
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def found(terms, count)
|
|
39
|
+
SearchIndex.search(scope.plastic_home, terms, limit: count, prefix: prefix)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def corpus
|
|
43
|
+
RLM::Corpus.new(method(:found))
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def database
|
|
47
|
+
SearchIndex.path(scope.plastic_home)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def prefix
|
|
51
|
+
return "" unless options[:project]
|
|
52
|
+
|
|
53
|
+
home = scope.plastic_home
|
|
54
|
+
root = (scope.slug == Scope::GLOBAL) ? StoreLayout.global_store(home) : StoreLayout.project_root(home, scope.slug)
|
|
55
|
+
"#{root.delete_prefix("#{home}/")}/"
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "subcommand_list"
|
|
4
|
+
|
|
5
|
+
# `plastic session` - the list of `plastic session ...` subcommands, straight
|
|
6
|
+
# out of the table.
|
|
7
|
+
module Plastic
|
|
8
|
+
class CLI
|
|
9
|
+
module Commands
|
|
10
|
+
class Session < SubcommandList
|
|
11
|
+
USAGE_LINE = "plastic session SUBCOMMAND [options]"
|
|
12
|
+
PREFIX = "session"
|
|
13
|
+
NEXT = 'plastic session commit "SUMMARY"'
|
|
14
|
+
BECAUSE = "a commit is the smallest unit every other session subcommand builds on"
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|