principles 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/exe/principles +10 -0
- data/lib/principles/after_commit_hook_options.rb +44 -0
- data/lib/principles/cli.rb +149 -0
- data/lib/principles/command_line.rb +188 -0
- data/lib/principles/command_routes.rb +60 -0
- data/lib/principles/controllers/acknowledgement.rb +106 -0
- data/lib/principles/controllers/answer.rb +172 -0
- data/lib/principles/controllers/audit.rb +203 -0
- data/lib/principles/controllers/audit_completion.rb +113 -0
- data/lib/principles/controllers/command.rb +201 -0
- data/lib/principles/controllers/correction.rb +99 -0
- data/lib/principles/controllers/help.rb +107 -0
- data/lib/principles/controllers/inventory.rb +181 -0
- data/lib/principles/controllers/mapping.rb +56 -0
- data/lib/principles/controllers/member_entries.rb +149 -0
- data/lib/principles/controllers/members_a_commit_changed.rb +43 -0
- data/lib/principles/controllers/members_to_assess.rb +160 -0
- data/lib/principles/controllers/meta_principle_setup.rb +92 -0
- data/lib/principles/controllers/repoint.rb +68 -0
- data/lib/principles/controllers/running_tool.rb +41 -0
- data/lib/principles/data/audit_files.rb +96 -0
- data/lib/principles/data/bounded_file.rb +45 -0
- data/lib/principles/data/candidate_files_found.rb +105 -0
- data/lib/principles/data/command-steps.json +305 -0
- data/lib/principles/data/command_steps_file.rb +50 -0
- data/lib/principles/data/expected_type.rb +71 -0
- data/lib/principles/data/ignored_by_git.rb +54 -0
- data/lib/principles/data/json_text.rb +57 -0
- data/lib/principles/data/known_fields.rb +42 -0
- data/lib/principles/data/linked_path.rb +102 -0
- data/lib/principles/data/map_files.rb +104 -0
- data/lib/principles/data/principle_id.rb +32 -0
- data/lib/principles/data/principles_subfolder.rb +93 -0
- data/lib/principles/data/project_files.rb +109 -0
- data/lib/principles/data/repository.rb +165 -0
- data/lib/principles/data/running_version.rb +44 -0
- data/lib/principles/data/schema_check.rb +139 -0
- data/lib/principles/data/schemas/acknowledgement-answer.schema.json +25 -0
- data/lib/principles/data/schemas/answer-guide.schema.json +99 -0
- data/lib/principles/data/schemas/assessment-answer.schema.json +332 -0
- data/lib/principles/data/schemas/audit-record.schema.json +277 -0
- data/lib/principles/data/schemas/command-steps.schema.json +83 -0
- data/lib/principles/data/schemas/correction-answer-guide.schema.json +68 -0
- data/lib/principles/data/schemas/correction-answer.schema.json +306 -0
- data/lib/principles/data/schemas/member-map.schema.json +39 -0
- data/lib/principles/data/schemas/repointing-answer.schema.json +44 -0
- data/lib/principles/error.rb +102 -0
- data/lib/principles/invocation_options.rb +77 -0
- data/lib/principles/models/accepted_loading.rb +36 -0
- data/lib/principles/models/acknowledgement.rb +203 -0
- data/lib/principles/models/activation.rb +64 -0
- data/lib/principles/models/agent_loads.rb +64 -0
- data/lib/principles/models/answer_fields.rb +67 -0
- data/lib/principles/models/answer_place.rb +53 -0
- data/lib/principles/models/answer_text.rb +37 -0
- data/lib/principles/models/answered_time.rb +65 -0
- data/lib/principles/models/assessment_answer.rb +131 -0
- data/lib/principles/models/assessment_basis.rb +47 -0
- data/lib/principles/models/assessment_report.rb +62 -0
- data/lib/principles/models/audit.rb +200 -0
- data/lib/principles/models/audit_record.rb +249 -0
- data/lib/principles/models/audit_records.rb +103 -0
- data/lib/principles/models/audit_start.rb +96 -0
- data/lib/principles/models/audited_member_lines.rb +45 -0
- data/lib/principles/models/candidate_files.rb +66 -0
- data/lib/principles/models/candidate_inventory.rb +67 -0
- data/lib/principles/models/candidate_listing.rb +32 -0
- data/lib/principles/models/carried_assessments.rb +76 -0
- data/lib/principles/models/check_since_last_audit.rb +61 -0
- data/lib/principles/models/cited_files.rb +39 -0
- data/lib/principles/models/command_steps.rb +270 -0
- data/lib/principles/models/commits_brought_in.rb +27 -0
- data/lib/principles/models/commits_since_base.rb +32 -0
- data/lib/principles/models/correction_answer.rb +66 -0
- data/lib/principles/models/correction_basis.rb +70 -0
- data/lib/principles/models/dated_line.rb +29 -0
- data/lib/principles/models/decided_prior_findings.rb +106 -0
- data/lib/principles/models/declared_map_changes.rb +156 -0
- data/lib/principles/models/disposition.rb +233 -0
- data/lib/principles/models/entry_file.rb +65 -0
- data/lib/principles/models/entry_files.rb +46 -0
- data/lib/principles/models/evidence_item.rb +48 -0
- data/lib/principles/models/evidence_lines_since.rb +57 -0
- data/lib/principles/models/evidence_replacements.rb +99 -0
- data/lib/principles/models/finding_write_ups.rb +108 -0
- data/lib/principles/models/findings_left_open.rb +34 -0
- data/lib/principles/models/first_raised_claim.rb +128 -0
- data/lib/principles/models/frontmatter_fields.rb +128 -0
- data/lib/principles/models/hook_commands.rb +100 -0
- data/lib/principles/models/ignored_candidates.rb +46 -0
- data/lib/principles/models/json_digest.rb +35 -0
- data/lib/principles/models/json_path_query.rb +131 -0
- data/lib/principles/models/json_path_selectors.rb +64 -0
- data/lib/principles/models/json_path_string.rb +76 -0
- data/lib/principles/models/kept_prior_finding.rb +70 -0
- data/lib/principles/models/last_completed_revision.rb +70 -0
- data/lib/principles/models/line_span.rb +49 -0
- data/lib/principles/models/loaded_files.rb +60 -0
- data/lib/principles/models/loading_decision.rb +45 -0
- data/lib/principles/models/loading_facts.rb +45 -0
- data/lib/principles/models/loads_to_check.rb +93 -0
- data/lib/principles/models/locate_refusal.rb +23 -0
- data/lib/principles/models/located_text.rb +43 -0
- data/lib/principles/models/locator.rb +52 -0
- data/lib/principles/models/map_members.rb +171 -0
- data/lib/principles/models/markdown_file.rb +92 -0
- data/lib/principles/models/member.rb +171 -0
- data/lib/principles/models/member_assessments.rb +144 -0
- data/lib/principles/models/member_elsewhere.rb +74 -0
- data/lib/principles/models/member_file.rb +156 -0
- data/lib/principles/models/member_grounds.rb +32 -0
- data/lib/principles/models/member_history.rb +68 -0
- data/lib/principles/models/member_lines.rb +95 -0
- data/lib/principles/models/member_loads.rb +197 -0
- data/lib/principles/models/member_map.rb +219 -0
- data/lib/principles/models/member_map_history.rb +143 -0
- data/lib/principles/models/member_maps.rb +185 -0
- data/lib/principles/models/member_moves.rb +95 -0
- data/lib/principles/models/member_problems.rb +253 -0
- data/lib/principles/models/member_sighting.rb +176 -0
- data/lib/principles/models/member_snapshots.rb +36 -0
- data/lib/principles/models/member_state.rb +35 -0
- data/lib/principles/models/members_elsewhere.rb +46 -0
- data/lib/principles/models/members_sharing_lines.rb +116 -0
- data/lib/principles/models/meta_principle.rb +51 -0
- data/lib/principles/models/missing_files.rb +85 -0
- data/lib/principles/models/misspelt_member_id.rb +45 -0
- data/lib/principles/models/open_finding.rb +221 -0
- data/lib/principles/models/open_findings_elsewhere.rb +45 -0
- data/lib/principles/models/other_principles.rb +47 -0
- data/lib/principles/models/placement.rb +42 -0
- data/lib/principles/models/plain_text_file.rb +32 -0
- data/lib/principles/models/principles_folder_move.rb +59 -0
- data/lib/principles/models/principles_package.rb +53 -0
- data/lib/principles/models/prior_finding_decision.rb +162 -0
- data/lib/principles/models/prior_finding_outcomes.rb +60 -0
- data/lib/principles/models/prior_findings.rb +109 -0
- data/lib/principles/models/problem_report.rb +110 -0
- data/lib/principles/models/project.rb +214 -0
- data/lib/principles/models/project_history.rb +203 -0
- data/lib/principles/models/record_judged_against.rb +42 -0
- data/lib/principles/models/recorded_entry.rb +93 -0
- data/lib/principles/models/recorded_finding.rb +97 -0
- data/lib/principles/models/recorded_findings.rb +58 -0
- data/lib/principles/models/recorded_members.rb +149 -0
- data/lib/principles/models/repoint.rb +112 -0
- data/lib/principles/models/reported_check.rb +130 -0
- data/lib/principles/models/request_id.rb +70 -0
- data/lib/principles/models/runs_from.rb +36 -0
- data/lib/principles/models/skill_loads.rb +123 -0
- data/lib/principles/models/still_holds_restatement.rb +87 -0
- data/lib/principles/models/text_size.rb +26 -0
- data/lib/principles/models/uncommitted_outside_the_map.rb +30 -0
- data/lib/principles/models/waits_on.rb +58 -0
- data/lib/principles/models/write_up_opening.rb +93 -0
- data/lib/principles/models/write_up_pointer.rb +50 -0
- data/lib/principles/models/write_up_repoint.rb +39 -0
- data/lib/principles/prose_list.rb +23 -0
- data/lib/principles/supported_ruby.rb +93 -0
- data/lib/principles/version.rb +11 -0
- data/lib/principles/views/acknowledged_since_last_audit.rb +34 -0
- data/lib/principles/views/acknowledgement_result.rb +44 -0
- data/lib/principles/views/activation_in_hand.rb +47 -0
- data/lib/principles/views/assessment_request.rb +131 -0
- data/lib/principles/views/audit_changes.rb +79 -0
- data/lib/principles/views/audit_commit.rb +55 -0
- data/lib/principles/views/audit_result.rb +147 -0
- data/lib/principles/views/candidate_files_result.rb +95 -0
- data/lib/principles/views/check_result_template.rb +75 -0
- data/lib/principles/views/diff_since_last_audit.rb +29 -0
- data/lib/principles/views/findings_result.rb +45 -0
- data/lib/principles/views/help.rb +119 -0
- data/lib/principles/views/invocation.rb +66 -0
- data/lib/principles/views/landed_since_base.rb +27 -0
- data/lib/principles/views/lines_shared_with_member.rb +111 -0
- data/lib/principles/views/loads_to_check_result.rb +45 -0
- data/lib/principles/views/map_result.rb +169 -0
- data/lib/principles/views/member_change_since_baseline.rb +58 -0
- data/lib/principles/views/member_repairs.rb +82 -0
- data/lib/principles/views/members_a_commit_changed.rb +66 -0
- data/lib/principles/views/members_with_no_baseline.rb +56 -0
- data/lib/principles/views/meta_principle_passage.rb +23 -0
- data/lib/principles/views/meta_principle_result.rb +170 -0
- data/lib/principles/views/open_findings_elsewhere_result.rb +32 -0
- data/lib/principles/views/open_findings_line.rb +125 -0
- data/lib/principles/views/other_principles_unjudged_result.rb +32 -0
- data/lib/principles/views/outside_the_map_result.rb +31 -0
- data/lib/principles/views/package_since_last_audit_result.rb +34 -0
- data/lib/principles/views/principle_read_result.rb +86 -0
- data/lib/principles/views/principle_with_changed_members.rb +26 -0
- data/lib/principles/views/principles_with_no_completed_audit.rb +30 -0
- data/lib/principles/views/printed_principle.rb +45 -0
- data/lib/principles/views/prior_finding_decisions_result.rb +35 -0
- data/lib/principles/views/prior_findings_result.rb +80 -0
- data/lib/principles/views/problem_lines.rb +84 -0
- data/lib/principles/views/problem_result.rb +107 -0
- data/lib/principles/views/prompts/acknowledge-a-change/say-whether-the-change-keeps-the-meaning.md +12 -0
- data/lib/principles/views/prompts/answer-any-judgement-request/what-a-self-audit-cannot-show.md +6 -0
- data/lib/principles/views/prompts/assess-every-member/answer-guide.json +63 -0
- data/lib/principles/views/prompts/assess-every-member/assess-each-member-and-the-set.md +12 -0
- data/lib/principles/views/prompts/assess-every-member/check-roles-other-principles-give-these-lines.md +7 -0
- data/lib/principles/views/prompts/assess-every-member/decide-each-member-loading.md +17 -0
- data/lib/principles/views/prompts/assess-every-member/decide-each-prior-finding.md +38 -0
- data/lib/principles/views/prompts/assess-every-member/give-problem-evidence-at-still-holds.md +2 -0
- data/lib/principles/views/prompts/assess-every-member/give-the-evidence-a-prior-finding-lacks.md +7 -0
- data/lib/principles/views/prompts/assess-every-member/have-a-changed-check-reviewed-before-running-it.md +4 -0
- data/lib/principles/views/prompts/assess-every-member/have-a-new-check-reviewed-before-running-it.md +3 -0
- data/lib/principles/views/prompts/assess-every-member/have-hidden-characters-in-a-check-explained.md +4 -0
- data/lib/principles/views/prompts/assess-every-member/judge-acknowledged-edits-together.md +6 -0
- data/lib/principles/views/prompts/assess-every-member/judge-the-keeping-against-the-other-principles.md +7 -0
- data/lib/principles/views/prompts/assess-every-member/judge-the-keeping-under-the-release-since-the-last-audit.md +10 -0
- data/lib/principles/views/prompts/assess-every-member/judge-the-set-with-carried-assessments.md +10 -0
- data/lib/principles/views/prompts/assess-every-member/keep-the-last-review-basis-unless-you-give-a-new-one.md +1 -0
- data/lib/principles/views/prompts/assess-every-member/name-another-principles-open-finding-rather-than-raise-it.md +9 -0
- data/lib/principles/views/prompts/assess-every-member/read-whether-each-prior-finding-s-evidence-changed.md +12 -0
- data/lib/principles/views/prompts/assess-every-member/run-a-named-check-at-every-full-audit.md +2 -0
- data/lib/principles/views/prompts/assess-every-member/run-the-check-then-report-it.md +2 -0
- data/lib/principles/views/prompts/assess-every-member/run-the-reviewed-check-and-say-what-its-review-rested-on.md +6 -0
- data/lib/principles/views/prompts/assess-every-member/uncommitted-files-outside-the-map.md +4 -0
- data/lib/principles/views/prompts/assess-every-member/why-each-member-is-judged-again.md +24 -0
- data/lib/principles/views/prompts/dispose-of-each-finding/answer-guide.json +34 -0
- data/lib/principles/views/prompts/dispose-of-each-finding/fix-or-record-each-finding.md +24 -0
- data/lib/principles/views/prompts/find-a-principle-to-map/ask-the-owner-before-mapping.md +1 -0
- data/lib/principles/views/prompts/find-a-principle-to-map/choose-one-principle.md +5 -0
- data/lib/principles/views/prompts/find-a-principle-to-map/owner-ask-ignored-folders.md +2 -0
- data/lib/principles/views/prompts/find-a-principle-to-map/owner-ask-ignored.md +3 -0
- data/lib/principles/views/prompts/find-a-principle-to-map/owner-ask-possibly-test-data.md +2 -0
- data/lib/principles/views/prompts/find-a-principle-to-map/owner-ask-untracked.md +2 -0
- data/lib/principles/views/prompts/find-a-principle-to-map/what-each-command-writes.md +4 -0
- data/lib/principles/views/prompts/find-a-principle-to-map/where-the-inventory-looks.md +10 -0
- data/lib/principles/views/prompts/learn-what-a-command-does/add-member.md +45 -0
- data/lib/principles/views/prompts/learn-what-a-command-does/change-activation.md +21 -0
- data/lib/principles/views/prompts/learn-what-a-command-does/change-description.md +2 -0
- data/lib/principles/views/prompts/learn-what-a-command-does/change-member-check.md +17 -0
- data/lib/principles/views/prompts/learn-what-a-command-does/change-member-role.md +9 -0
- data/lib/principles/views/prompts/learn-what-a-command-does/create-principle.md +6 -0
- data/lib/principles/views/prompts/learn-what-a-command-does/every-command-and-how-they-chain.md +28 -0
- data/lib/principles/views/prompts/learn-what-a-command-does/list-candidate-files.md +17 -0
- data/lib/principles/views/prompts/learn-what-a-command-does/list-member-problems.md +73 -0
- data/lib/principles/views/prompts/learn-what-a-command-does/list-open-findings.md +71 -0
- data/lib/principles/views/prompts/learn-what-a-command-does/list-principles.md +7 -0
- data/lib/principles/views/prompts/learn-what-a-command-does/move-member.md +11 -0
- data/lib/principles/views/prompts/learn-what-a-command-does/remove-member-check.md +10 -0
- data/lib/principles/views/prompts/learn-what-a-command-does/remove-member.md +6 -0
- data/lib/principles/views/prompts/learn-what-a-command-does/show-answer-check.md +16 -0
- data/lib/principles/views/prompts/learn-what-a-command-does/show-audit.md +20 -0
- data/lib/principles/views/prompts/learn-what-a-command-does/show-meta-principle-passage.md +52 -0
- data/lib/principles/views/prompts/learn-what-a-command-does/show-principle.md +86 -0
- data/lib/principles/views/prompts/learn-what-a-command-does/start-audit.md +68 -0
- data/lib/principles/views/prompts/learn-what-a-command-does/submit-answer.md +56 -0
- data/lib/principles/views/prompts/repoint-write-ups/point-each-moved-write-up-at-its-new-place.md +10 -0
- data/lib/principles/views/prompts/report-after-a-commit/it-refused-after-the-commits-touched-the-maps.md +2 -0
- data/lib/principles/views/prompts/report-after-a-commit/others-are-still-listed.md +1 -0
- data/lib/principles/views/prompts/report-after-a-commit/the-commits-changed-these-members.md +2 -0
- data/lib/principles/views/prompts/report-after-a-commit/this-command-shows-each-one.md +1 -0
- data/lib/principles/views/prompts/report-the-completed-audit/commit-only-what-the-audit-changed.md +2 -0
- data/lib/principles/views/prompts/report-the-completed-audit/replace-the-default-commit-message.md +4 -0
- data/lib/principles/views/prompts/report-the-completed-audit/what-completion-means.md +2 -0
- data/lib/principles/views/prompts/set-principles-up/entry-file-passage.md +3 -0
- data/lib/principles/views/prompts/set-principles-up/name-the-step-each-member-lacks.md +15 -0
- data/lib/principles/views/prompts/set-principles-up/place-the-passage-with-the-user.md +31 -0
- data/lib/principles/views/prompts/set-principles-up/set-up-first.md +2 -0
- data/lib/principles/views/prompts/set-principles-up/what-the-passage-presumes.md +4 -0
- data/lib/principles/views/prompts/start-a-session/act-on-the-open-findings.md +5 -0
- data/lib/principles/views/prompts/start-a-session/it-returns-after-each-clear-or-compaction-too.md +1 -0
- data/lib/principles/views/prompts/start-a-session/it-returns-at-each-session-start.md +1 -0
- data/lib/principles/views/prompts/start-a-session/raise-them-at-the-next-pause.md +1 -0
- data/lib/principles/views/prompts/start-a-session/raise-them-before-the-first-task.md +1 -0
- data/lib/principles/views/prompts.rb +71 -0
- data/lib/principles/views/repoint_result.rb +80 -0
- data/lib/principles/views/request_part.rb +26 -0
- data/lib/principles/views/request_parts.rb +26 -0
- data/lib/principles/views/shell_word.rb +29 -0
- data/lib/principles/views/visible_text.rb +26 -0
- data/lib/principles/views/workflow_diagram.rb +77 -0
- data/lib/principles.rb +5 -0
- metadata +326 -0
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# typed: strict
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require_relative "../prose_list"
|
|
5
|
+
|
|
6
|
+
module Principles
|
|
7
|
+
# What this tool prints, from plain values a controller hands it. views/CLAUDE.md owns the boundary.
|
|
8
|
+
module Views
|
|
9
|
+
# What add-member's result says of the members sharing a line with the member it added, show-principle
|
|
10
|
+
# beside each member it shows (#541), and a full audit's request beside each member, of other maps only (#719):
|
|
11
|
+
# those in its map (overlaps), those of them spanning exactly its lines
|
|
12
|
+
# (same_lines_as, #442), and those in other maps, with their roles there and same_lines when they span exactly
|
|
13
|
+
# its lines, spans_these_lines when their lines include all of its and within_these_lines when its lines
|
|
14
|
+
# include theirs (mapped_elsewhere, #383, #718). Each field is printed only when there are some; add-member
|
|
15
|
+
# also prints the sentences that say what it means for the agent.
|
|
16
|
+
class LinesSharedWithMember
|
|
17
|
+
# Why the agent checks the text where the lines meet, unless each member holding another's lines is a whole
|
|
18
|
+
# file, which holds every line's text (#756).
|
|
19
|
+
TEXT_CHECK = "Lines are not text: where two share a first or last line, a passage can start or end partway " \
|
|
20
|
+
"through it, so check the text there before deciding which edit reaches which member. " #: String
|
|
21
|
+
|
|
22
|
+
# text_check says whether a member holding another's lines is not a whole file, so the text needs checking.
|
|
23
|
+
#: (?overlaps: Array[String], ?same_lines_as: Array[String], ?mapped_elsewhere: Array[Hash[String, untyped]],
|
|
24
|
+
#| ?text_check: bool) -> void
|
|
25
|
+
def initialize(overlaps: [], same_lines_as: [], mapped_elsewhere: [], text_check: false)
|
|
26
|
+
@overlaps = overlaps
|
|
27
|
+
@same_lines_as = same_lines_as
|
|
28
|
+
@mapped_elsewhere = mapped_elsewhere
|
|
29
|
+
@text_check = text_check
|
|
30
|
+
freeze
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# The fields to merge into added, each only when there are some.
|
|
34
|
+
#: () -> Hash[String, untyped]
|
|
35
|
+
def to_h
|
|
36
|
+
{ "overlaps" => @overlaps, "same_lines_as" => @same_lines_as, "mapped_elsewhere" => @mapped_elsewhere }
|
|
37
|
+
.reject { |_field, shared| shared.empty? }
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# The sentences the question carries for them, or none.
|
|
41
|
+
#: () -> String
|
|
42
|
+
def note
|
|
43
|
+
"#{overlap_note}#{elsewhere_note}#{same_lines_note}"
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
private
|
|
47
|
+
|
|
48
|
+
#: () -> String
|
|
49
|
+
def overlap_note
|
|
50
|
+
return "" if @overlaps.empty?
|
|
51
|
+
|
|
52
|
+
"It shares lines with #{@overlaps.join(", ")}, so one edit there will show as a change to each. "
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
#: () -> String
|
|
56
|
+
def elsewhere_note
|
|
57
|
+
return "" if @mapped_elsewhere.empty?
|
|
58
|
+
|
|
59
|
+
"Members of other principles share lines with this one (mapped_elsewhere), so an edit to the lines they " \
|
|
60
|
+
"share changes each. #{spans_note}Check that this member's role fits beside the roles they give it there. "
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Which of them span all of this member's lines and which lie within them, so the agent can work out which
|
|
64
|
+
# member an edit reaches (#718). Lines are not text, so the agent checks where they share a first or last line.
|
|
65
|
+
#: () -> String
|
|
66
|
+
def spans_note
|
|
67
|
+
spans = @mapped_elsewhere.filter_map do |each|
|
|
68
|
+
if each["spans_these_lines"] then spanning(each)
|
|
69
|
+
elsif each["within_these_lines"] then within(each)
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
"#{spans.join}#{TEXT_CHECK if @text_check && spans.any?}"
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# One that spans all of this member's lines: an edit to this member reaches it, and one outside them only it.
|
|
76
|
+
#: (Hash[String, untyped]) -> String
|
|
77
|
+
def spanning(each)
|
|
78
|
+
id = "`#{each.fetch("member_id")}`"
|
|
79
|
+
"#{id} in #{each.fetch("principle_id")} spans all of this member's lines, so every edit to this member's " \
|
|
80
|
+
"text is an edit to it too, and an edit outside the shared lines reaches only #{id}. "
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# One within this member's lines: an edit to it reaches this member, and one outside them only this member.
|
|
84
|
+
#: (Hash[String, untyped]) -> String
|
|
85
|
+
def within(each)
|
|
86
|
+
"`#{each.fetch("member_id")}` in #{each.fetch("principle_id")} lies within this member's lines, so every " \
|
|
87
|
+
"edit to its text is an edit to this member's too, and an edit outside the shared lines reaches only " \
|
|
88
|
+
"this member. "
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# Equal lines are not equal text, as a passage can end within its last line, so the agent decides.
|
|
92
|
+
#: () -> String
|
|
93
|
+
def same_lines_note
|
|
94
|
+
return "" if @same_lines_as.empty? && @mapped_elsewhere.none? { |each| each["same_lines"] }
|
|
95
|
+
|
|
96
|
+
named = same_lines_named
|
|
97
|
+
"#{ProseList.new(named)} #{named.length > 1 ? "span" : "spans"} exactly these lines " \
|
|
98
|
+
"(same_lines), under another id. If they are meant to be one member, decide which to keep; if both are " \
|
|
99
|
+
"meant, say why in this member's role. "
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
# Each member spanning exactly these lines, by id, with its principle when it is in another (#445).
|
|
103
|
+
#: () -> Array[String]
|
|
104
|
+
def same_lines_named
|
|
105
|
+
elsewhere = @mapped_elsewhere.select { |each| each["same_lines"] }
|
|
106
|
+
@same_lines_as.map { |id| "`#{id}`" } +
|
|
107
|
+
elsewhere.map { |each| "`#{each.fetch("member_id")}` in #{each.fetch("principle_id")}" }
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# typed: strict
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require_relative "invocation"
|
|
5
|
+
require_relative "prompts"
|
|
6
|
+
require_relative "request_part"
|
|
7
|
+
|
|
8
|
+
module Principles
|
|
9
|
+
# What this tool prints, from plain values a controller hands it. views/CLAUDE.md owns the boundary.
|
|
10
|
+
module Views
|
|
11
|
+
# How a full audit's request shows the members to check against the principle's activation (#355 slice 3).
|
|
12
|
+
class LoadsToCheckResult
|
|
13
|
+
# listed is the members to check, nil when there are none, and id the principle they belong to.
|
|
14
|
+
#: (Invocation, Hash[String, untyped]?, String) -> void
|
|
15
|
+
def initialize(invocation, listed, id)
|
|
16
|
+
@invocation = invocation
|
|
17
|
+
@listed = listed
|
|
18
|
+
@id = id
|
|
19
|
+
freeze
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# The request's part that lists the members to check against the activation, how to decide them, and a
|
|
23
|
+
# decision to fill in for each; nil when there are none to list.
|
|
24
|
+
#: () -> RequestPart?
|
|
25
|
+
def part
|
|
26
|
+
listed = @listed or return
|
|
27
|
+
|
|
28
|
+
decisions = listed.fetch("rows").map { |row| { "member_id" => row.fetch("member_id"), "decision" => nil } }
|
|
29
|
+
RequestPart.new(shown: { "loads_to_check_against_activation" => listed,
|
|
30
|
+
"loads_to_check_instruction" => instruction },
|
|
31
|
+
slots: { "loading_decisions" => decisions })
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
private
|
|
35
|
+
|
|
36
|
+
# How to decide each listed member, naming the activation change for a principle whose work is in hand in
|
|
37
|
+
# every session (#509).
|
|
38
|
+
#: () -> String
|
|
39
|
+
def instruction
|
|
40
|
+
always = @invocation.in_project("change-activation", @id, options: ["--always"])
|
|
41
|
+
Prompts.text("assess-every-member/decide-each-member-loading", always: always)
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
# typed: strict
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require_relative "invocation"
|
|
5
|
+
require_relative "printed_principle"
|
|
6
|
+
require_relative "lines_shared_with_member"
|
|
7
|
+
require_relative "activation_in_hand"
|
|
8
|
+
require_relative "prompts"
|
|
9
|
+
|
|
10
|
+
module Principles
|
|
11
|
+
# What this tool prints, from plain values a controller hands it. views/CLAUDE.md owns the boundary.
|
|
12
|
+
module Views
|
|
13
|
+
# The JSON results of the commands that write a principle's map, with commands for the invocation running now.
|
|
14
|
+
# PrincipleReadResult prints the reads.
|
|
15
|
+
class MapResult
|
|
16
|
+
# The placeholders each printed command leaves for the agent to fill.
|
|
17
|
+
ADD_MEMBER_USAGE = "PATH [--section \"Exact heading text\"] [--starting-at \"text that occurs once\" " \
|
|
18
|
+
"[--ending-at \"text that closes the passage\"]] [--query '$.description'] " \
|
|
19
|
+
"--role \"The part it plays\""
|
|
20
|
+
|
|
21
|
+
CREATED = "Which files or Markdown sections reinforce this principle? Add each one with the part it plays, " \
|
|
22
|
+
"for example: states the principle, lists the checks, records settled terms, reminds on a timer, " \
|
|
23
|
+
"fails the build. When a member is one item inside a larger file or section, narrow it with " \
|
|
24
|
+
"--starting-at, and --ending-at for more than one line. Add one member per command. Leave out the " \
|
|
25
|
+
"material the members govern."
|
|
26
|
+
|
|
27
|
+
# in_git says whether the project is in git, where a committed map is each member's baseline until its first
|
|
28
|
+
# full audit (#623).
|
|
29
|
+
#: (Invocation, in_git: bool) -> void
|
|
30
|
+
def initialize(invocation, in_git:)
|
|
31
|
+
@invocation = invocation
|
|
32
|
+
@in_git = in_git
|
|
33
|
+
freeze
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
#: (PrintedPrinciple) -> Hash[String, untyped]
|
|
37
|
+
def created(principle)
|
|
38
|
+
question(principle, CREATED, add_member_command(principle.id))
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
#: (PrintedPrinciple) -> Hash[String, untyped]
|
|
42
|
+
def description_changed(principle)
|
|
43
|
+
question(principle, "Changed the description of #{principle.id}.", start_audit(principle.id))
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# What this tool recorded of when the work is in hand, and what a full audit lists against it, as
|
|
47
|
+
# Models::Activation#full_audit_lists names it (#355, #523).
|
|
48
|
+
#: (PrintedPrinciple, lists: String) -> Hash[String, untyped]
|
|
49
|
+
def activation_changed(principle, lists:)
|
|
50
|
+
question(principle, ActivationInHand.new(principle.activation || {}).recorded(principle.id, lists),
|
|
51
|
+
start_audit(principle.id), shown: { "activation" => principle.activation })
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# change-activation when the map already held that activation, so it wrote nothing (#474).
|
|
55
|
+
#: (PrintedPrinciple) -> Hash[String, untyped]
|
|
56
|
+
def activation_unchanged(principle)
|
|
57
|
+
question(principle, ActivationInHand.new(principle.activation || {}).unchanged(principle.id),
|
|
58
|
+
@invocation.in_project("show-principle", principle.id),
|
|
59
|
+
shown: { "activation" => principle.activation })
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# shared says which members share a line with the new one; added lists them only when there are some, as it
|
|
63
|
+
# carries a check only when one is named.
|
|
64
|
+
#: (PrintedPrinciple, added: Hash[String, untyped], ?shared: LinesSharedWithMember) -> Hash[String, untyped]
|
|
65
|
+
def member_added(principle, added:, shared: LinesSharedWithMember.new)
|
|
66
|
+
added = added.merge(shared.to_h)
|
|
67
|
+
shown = @invocation.in_project("show-principle", principle.id)
|
|
68
|
+
question(principle, "#{span(added)}#{shared.note}Add the next member the same way. Commit " \
|
|
69
|
+
"#{principle.file} as it changes, so the project's history shows each change; in git, " \
|
|
70
|
+
"start-audit refuses a map that is not committed.\n" \
|
|
71
|
+
"To see the map so far: #{shown}\n#{start_when_mapped(principle.id)}",
|
|
72
|
+
add_member_command(principle.id), shown: { "member_count" => principle.members.length })
|
|
73
|
+
.merge("added" => added)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# add-member's report of the map it started, with the description and activation it wrote, which the agent
|
|
77
|
+
# never typed (#929).
|
|
78
|
+
#: (PrintedPrinciple) -> Hash[String, untyped]
|
|
79
|
+
def map_created(principle)
|
|
80
|
+
{ "map_created" => { "description" => principle.description, "activation" => principle.activation } }
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# move-member: the member's old id, and its new id with the lines it now spans.
|
|
84
|
+
#: (PrintedPrinciple, from: String, moved: Hash[String, untyped]) -> Hash[String, untyped]
|
|
85
|
+
def member_moved(principle, from:, moved:)
|
|
86
|
+
id = moved.fetch("id")
|
|
87
|
+
question(principle, "#{id} now spans lines #{moved.fetch("first_line")} to #{moved.fetch("last_line")}" \
|
|
88
|
+
"#{" (moved from #{from})" unless from == id}; if that is not the passage you meant, " \
|
|
89
|
+
"move it again. Check the other members, then start the audit.", start_audit(principle.id))
|
|
90
|
+
.merge("moved" => moved)
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# change-member-check: the stored command is the member's check in the map printed beside this, so the
|
|
94
|
+
# agent can see it byte for byte; the question names that field rather than quoting project text (#227).
|
|
95
|
+
# hidden names each character in the check that prints escaped or not at all (#260).
|
|
96
|
+
#: (PrintedPrinciple, member: String, hidden: Array[String]) -> Hash[String, untyped]
|
|
97
|
+
def check_changed(principle, member:, hidden:)
|
|
98
|
+
done = "#{member} is now enforced by the check named in its map entry. The next audit marks it new or " \
|
|
99
|
+
"changed and asks for a review before it runs; nothing runs it automatically: " \
|
|
100
|
+
"you run it when an audit asks for its result."
|
|
101
|
+
return member_replaced(principle, member: member, done: done) if hidden.empty?
|
|
102
|
+
|
|
103
|
+
member_replaced(principle, member: member,
|
|
104
|
+
done: "#{done} The check holds characters that print escaped or not at all, " \
|
|
105
|
+
"which check_hidden_characters names; make sure each is meant.")
|
|
106
|
+
.merge("check_hidden_characters" => hidden)
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# change-member-role, change-member-check and remove-member-check: done says what changed. This tool cannot
|
|
110
|
+
# tell in git whether a full audit's correction is open, so the next step names both cases (D40, #461), and
|
|
111
|
+
# the other case by what the agent holds: a correction request (second alpha user on 8e5b3f9).
|
|
112
|
+
#: (PrintedPrinciple, member: String, done: String) -> Hash[String, untyped]
|
|
113
|
+
def member_replaced(principle, member:, done:)
|
|
114
|
+
question(principle, "#{done} Check the other members, then start the audit.\nIf you hold a correction " \
|
|
115
|
+
"request from submit-answer (phase correction), list #{member} in the " \
|
|
116
|
+
"changed_map_entries of the fixed disposition this change fixes, and submit it instead: " \
|
|
117
|
+
"#{@invocation.submit_answer("REQUEST")}",
|
|
118
|
+
start_audit(principle.id))
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
#: (PrintedPrinciple, removed: String) -> Hash[String, untyped]
|
|
122
|
+
def member_removed(principle, removed:)
|
|
123
|
+
question(principle, "Removed #{removed}. Add or remove members until the map is right.\n" \
|
|
124
|
+
"#{start_when_mapped(principle.id)}",
|
|
125
|
+
add_member_command(principle.id))
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
private
|
|
129
|
+
|
|
130
|
+
# The lines a member spans, said so that a passage cut short shows; it ends with a space.
|
|
131
|
+
#: (Hash[String, untyped]) -> String
|
|
132
|
+
def span(member)
|
|
133
|
+
"#{member.fetch("id")} spans lines #{member.fetch("first_line")} to #{member.fetch("last_line")}; " \
|
|
134
|
+
"if that is not the passage you meant, move it with move-member. "
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
# shown is what the result prints of the map: the whole map unless the caller names less, as add-member
|
|
138
|
+
# does (#400).
|
|
139
|
+
#: (PrintedPrinciple, String, String, ?shown: Hash[String, untyped]) -> Hash[String, untyped]
|
|
140
|
+
def question(principle, text, answer_with, shown: { "map" => principle.map })
|
|
141
|
+
{ "status" => "question", "principle_id" => principle.id, "map_file" => principle.file, **shown,
|
|
142
|
+
"question" => text, "answer_with" => answer_with }
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
#: (String) -> String
|
|
146
|
+
def start_audit(id)
|
|
147
|
+
@invocation.in_project("start-audit", id)
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
# The step after adding members, as the question's last line, since answer_with is the next add-member.
|
|
151
|
+
#: (String) -> String
|
|
152
|
+
def start_when_mapped(id)
|
|
153
|
+
if @in_git
|
|
154
|
+
return "When the map lists every member, commit it: list-member-problems then reports any change to a " \
|
|
155
|
+
"member since that commit. Only a full audit judges whether they reinforce the principle.\n" \
|
|
156
|
+
"To start it when you choose: #{start_audit(id)}"
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
"When the map lists every member, start the audit. It judges whether they reinforce the principle, and " \
|
|
160
|
+
"gives each member the baseline list-member-problems compares it with.\nTo start it: #{start_audit(id)}"
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
#: (String) -> String
|
|
164
|
+
def add_member_command(id)
|
|
165
|
+
@invocation.in_project("add-member", id, usage: ADD_MEMBER_USAGE)
|
|
166
|
+
end
|
|
167
|
+
end
|
|
168
|
+
end
|
|
169
|
+
end
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# typed: strict
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require_relative "shell_word"
|
|
5
|
+
|
|
6
|
+
module Principles
|
|
7
|
+
# What this tool prints, from plain values a controller hands it. views/CLAUDE.md owns the boundary.
|
|
8
|
+
module Views
|
|
9
|
+
# One member's change since its baseline, as a one-member audit's request shows it: the member's id, role and
|
|
10
|
+
# evidence, the commit its baseline text is at, the commit the audit is based on, the member's own lines at
|
|
11
|
+
# each (#379), and the command that shows its file's change between them, following a move (D33, #551).
|
|
12
|
+
class MemberChangeSinceBaseline
|
|
13
|
+
# member holds the member's id, role and evidence; commits holds "base", HEAD, and "baseline", the commit
|
|
14
|
+
# the member's baseline text is at, and "audit_base" when the baseline is later than the audit's base;
|
|
15
|
+
# member_lines holds its own lines at each, or their counts when too long; paths holds the paths the change
|
|
16
|
+
# spans, its path at the baseline first.
|
|
17
|
+
#: (member: Hash[String, untyped], commits: Hash[String, String], member_lines: Hash[String, untyped],
|
|
18
|
+
#| paths: Array[String]) -> void
|
|
19
|
+
def initialize(member:, commits:, member_lines:, paths:)
|
|
20
|
+
@member = member
|
|
21
|
+
@commits = commits
|
|
22
|
+
@member_lines = member_lines
|
|
23
|
+
@paths = paths
|
|
24
|
+
freeze
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
#: () -> String
|
|
28
|
+
def member_id
|
|
29
|
+
@member.fetch("id")
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
#: () -> String
|
|
33
|
+
def base_commit
|
|
34
|
+
@commits.fetch("base")
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# The fields as the request prints them. Lines left out for their length point at read_the_change instead,
|
|
38
|
+
# so the request is never silently partial (D38).
|
|
39
|
+
#: () -> Hash[String, untyped]
|
|
40
|
+
def to_h
|
|
41
|
+
read = read_the_change
|
|
42
|
+
lines = @member_lines.key?("omitted") ? @member_lines.merge("read_instead" => read) : @member_lines
|
|
43
|
+
{ "member" => @member, "baseline_commit" => @commits.fetch("baseline"), "base_commit" => base_commit,
|
|
44
|
+
**@commits.slice("audit_base").transform_keys { "audit_base_commit" },
|
|
45
|
+
"member_lines" => lines, "read_the_change" => read }
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
private
|
|
49
|
+
|
|
50
|
+
# Each word quoted for the shell, and every path read by git as written, not as a pattern (#558).
|
|
51
|
+
#: () -> String
|
|
52
|
+
def read_the_change
|
|
53
|
+
words = [@commits.fetch("baseline"), base_commit, "--", *@paths].map { |word| ShellWord.new(word).to_s }
|
|
54
|
+
"git --literal-pathspecs diff -M #{words.join(" ")}"
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# typed: strict
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require_relative "invocation"
|
|
5
|
+
|
|
6
|
+
module Principles
|
|
7
|
+
# What this tool prints, from plain values a controller hands it. views/CLAUDE.md owns the boundary.
|
|
8
|
+
module Views
|
|
9
|
+
# The commands that repair a member this tool cannot find: move it, or remove it. A member whose file is
|
|
10
|
+
# gone is moved to the path the agent finds, keeping its own section, passage or query, so a rename keeps
|
|
11
|
+
# its audit (#268). A member whose place in its file is gone is moved within it, or to another file its text
|
|
12
|
+
# moved into (#378); a passage keeps its anchors, so a move cannot silently widen it to its whole new
|
|
13
|
+
# section (#251). Which fits is the agent's to judge.
|
|
14
|
+
class MemberRepairs
|
|
15
|
+
# The flag that names each locator field in a printed command.
|
|
16
|
+
FLAGS = { "section" => "--section", "starting_at" => "--starting-at", "ending_at" => "--ending-at",
|
|
17
|
+
"query" => "--query" }.freeze #: Hash[String, String]
|
|
18
|
+
|
|
19
|
+
#: (Invocation) -> void
|
|
20
|
+
def initialize(invocation)
|
|
21
|
+
@invocation = invocation
|
|
22
|
+
freeze
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# The repairs for member, a printed member with its "id", its locator fields and the code of the refusal
|
|
26
|
+
# that says why it cannot be found, as "code" or show-principle's "error", of principle id. Each is
|
|
27
|
+
# copyable as it is: move-member, with NEW_PATH, HEADING or QUERY to fill in, then, for a section or
|
|
28
|
+
# passage lost from a file that is still there, the same move into another file, then remove-member.
|
|
29
|
+
#: (String, Hash[String, untyped]) -> Array[String]
|
|
30
|
+
def commands(id, member)
|
|
31
|
+
member_id = member.fetch("id")
|
|
32
|
+
[move(id, member_id, member), *move_elsewhere(id, member_id, member),
|
|
33
|
+
@invocation.in_project("remove-member", id, member_id)]
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# member, as show-principle prints it, with its repairs as repair_with when broken, which the controller says
|
|
37
|
+
# of a member an audit would refuse (#272).
|
|
38
|
+
#: (String, Hash[String, untyped], broken: bool) -> Hash[String, untyped]
|
|
39
|
+
def beside(id, member, broken:)
|
|
40
|
+
return member unless broken
|
|
41
|
+
|
|
42
|
+
member.merge("repair_with" => commands(id, member))
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
private
|
|
46
|
+
|
|
47
|
+
#: (String, String, Hash[String, untyped]) -> String
|
|
48
|
+
def move(id, member_id, member)
|
|
49
|
+
if file_unreadable?(member)
|
|
50
|
+
kept = flags(member, FLAGS.keys)
|
|
51
|
+
return @invocation.in_project("move-member", id, member_id, options: kept, usage: "--path NEW_PATH")
|
|
52
|
+
end
|
|
53
|
+
return @invocation.in_project("move-member", id, member_id, usage: "--query QUERY") if member["query"]
|
|
54
|
+
|
|
55
|
+
@invocation.in_project("move-member", id, member_id, options: flags(member, %w[starting_at ending_at]),
|
|
56
|
+
usage: "--section HEADING")
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# A section or passage lost from a file that is still there may have moved into another file (#378).
|
|
60
|
+
#: (String, String, Hash[String, untyped]) -> Array[String]
|
|
61
|
+
def move_elsewhere(id, member_id, member)
|
|
62
|
+
return [] if member["query"] || file_unreadable?(member)
|
|
63
|
+
|
|
64
|
+
anchors = flags(member, %w[starting_at ending_at])
|
|
65
|
+
[@invocation.in_project("move-member", id, member_id, options: anchors,
|
|
66
|
+
usage: "--path NEW_PATH --section HEADING")]
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# Whether member's file cannot be read, by the refusal it carries.
|
|
70
|
+
#: (Hash[String, untyped]) -> bool
|
|
71
|
+
def file_unreadable?(member)
|
|
72
|
+
(member["code"] || member.dig("error", "code")) == "unreadable_file"
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# The flags, with their values, of the locator fields named in keys that member has.
|
|
76
|
+
#: (Hash[String, untyped], Array[String]) -> Array[String]
|
|
77
|
+
def flags(member, keys)
|
|
78
|
+
keys.select { |key| member[key] }.flat_map { |key| [FLAGS.fetch(key), member.fetch(key)] }
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# typed: strict
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require "json"
|
|
5
|
+
require_relative "invocation"
|
|
6
|
+
require_relative "problem_lines"
|
|
7
|
+
require_relative "prompts"
|
|
8
|
+
require_relative "visible_text"
|
|
9
|
+
|
|
10
|
+
module Principles
|
|
11
|
+
# What this tool prints, from plain values a controller hands it. views/CLAUDE.md owns the boundary.
|
|
12
|
+
module Views
|
|
13
|
+
# list-member-problems --commits-after COMMIT --hook-event EVENT: the whole JSON the plugin's after-commit hook
|
|
14
|
+
# prints for Claude Code, which puts its additionalContext beside the Bash call's result (D73), or nothing at all.
|
|
15
|
+
# Claude Code asks for that text to state facts, not to give orders, so it says what the commits changed and
|
|
16
|
+
# which command shows more.
|
|
17
|
+
class MembersACommitChanged
|
|
18
|
+
NOTHING = Lines.new(stdout: "", stderr: "", status: 0).freeze #: Lines
|
|
19
|
+
|
|
20
|
+
#: (Invocation) -> void
|
|
21
|
+
def initialize(invocation)
|
|
22
|
+
@invocation = invocation
|
|
23
|
+
freeze
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# changed is each member the commits changed, as list-member-problems lists it; others is how many other
|
|
27
|
+
# changed members it still lists.
|
|
28
|
+
#: (String, Array[Hash[String, untyped]], others: Integer) -> Lines
|
|
29
|
+
def changed(event, changed, others:)
|
|
30
|
+
rows = changed.map { |member| ProblemLines.new(@invocation).row(member) }
|
|
31
|
+
reported(event, [Prompts.text("report-after-a-commit/the-commits-changed-these-members"), *rows,
|
|
32
|
+
*still_listed(others), Prompts.text("report-after-a-commit/this-command-shows-each-one"),
|
|
33
|
+
command])
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# A refusal with code, which the commits could have caused.
|
|
37
|
+
#: (String, String) -> Lines
|
|
38
|
+
def refused(event, code)
|
|
39
|
+
reported(event, [Prompts.text("report-after-a-commit/it-refused-after-the-commits-touched-the-maps",
|
|
40
|
+
code: VisibleText.new(code).to_s), command])
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
private
|
|
44
|
+
|
|
45
|
+
# The line saying how many other changed members list-member-problems still lists, or none when it lists none.
|
|
46
|
+
#: (Integer) -> Array[String]
|
|
47
|
+
def still_listed(others)
|
|
48
|
+
return [] if others.zero?
|
|
49
|
+
|
|
50
|
+
[Prompts.text("report-after-a-commit/others-are-still-listed",
|
|
51
|
+
count: others.to_s, members: others == 1 ? "member is" : "members are")]
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
#: () -> String
|
|
55
|
+
def command = @invocation.in_project("list-member-problems")
|
|
56
|
+
|
|
57
|
+
# The hook's JSON. Each field from a project file or commit is written through VisibleText already, so an
|
|
58
|
+
# invisible character reaches the model as \uXXXX, not hidden in the text it reads (#227).
|
|
59
|
+
#: (String, Array[String]) -> Lines
|
|
60
|
+
def reported(event, lines)
|
|
61
|
+
output = { "hookSpecificOutput" => { "hookEventName" => event, "additionalContext" => lines.join("\n") } }
|
|
62
|
+
Lines.new(stdout: "#{JSON.generate(output)}\n", stderr: "", status: 0)
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# typed: strict
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require_relative "../prose_list"
|
|
5
|
+
|
|
6
|
+
module Principles
|
|
7
|
+
# What this tool prints, from plain values a controller hands it. views/CLAUDE.md owns the boundary.
|
|
8
|
+
module Views
|
|
9
|
+
# One principle's members with no baseline, as list-member-problems' next_action says what gives them one:
|
|
10
|
+
# outside git a completed audit, and in git committing the files that hold them (#564).
|
|
11
|
+
class MembersWithNoBaseline
|
|
12
|
+
# because is "outside_git" or "not_committed"; audit is the start-audit command to run outside git, and
|
|
13
|
+
# files the map and member files to commit in git.
|
|
14
|
+
#: (id: String, count: Integer, because: String, audit: String, files: Array[String]) -> void
|
|
15
|
+
def initialize(id:, count:, because:, audit:, files:)
|
|
16
|
+
@id = id
|
|
17
|
+
@count = count
|
|
18
|
+
@because = because
|
|
19
|
+
@audit = audit
|
|
20
|
+
@files = files
|
|
21
|
+
freeze
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
#: () -> String
|
|
25
|
+
def to_s
|
|
26
|
+
"#{@count} member#{"s" unless one?} of #{@id} #{one? ? "has" : "have"} no baseline, so whether " \
|
|
27
|
+
"#{one? ? "it" : "they"} changed is not yet known.#{remedy}"
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
private
|
|
31
|
+
|
|
32
|
+
#: () -> bool
|
|
33
|
+
def one? = @count == 1
|
|
34
|
+
|
|
35
|
+
# What gives the members a baseline: a completed audit outside git, or in git committing the files that
|
|
36
|
+
# differ from HEAD, or an audit again when none does, since every file is committed already (#710 X3). The
|
|
37
|
+
# audit command starts a line of its own, after its purpose.
|
|
38
|
+
#: () -> String
|
|
39
|
+
def remedy
|
|
40
|
+
return " Committing #{ProseList.new(@files)} #{gives}." if @because == "not_committed" && !@files.empty?
|
|
41
|
+
|
|
42
|
+
"#{all_committed if @because == "not_committed"}\nA completed audit #{gives}: #{@audit}"
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
#: () -> String
|
|
46
|
+
def gives = "gives #{one? ? "it" : "each"} one"
|
|
47
|
+
|
|
48
|
+
#: () -> String
|
|
49
|
+
def all_committed
|
|
50
|
+
them, their, were = one? ? %w[it its was] : %w[them their were]
|
|
51
|
+
" Every file holding #{them} is already committed, but no commit held #{them} where #{their} map places " \
|
|
52
|
+
"#{them} when #{one? ? "it" : "they"} #{were} mapped."
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# typed: strict
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require_relative "prompts"
|
|
5
|
+
|
|
6
|
+
module Principles
|
|
7
|
+
# What this tool prints, from plain values a controller hands it. views/CLAUDE.md owns the boundary.
|
|
8
|
+
module Views
|
|
9
|
+
# The passage setup proposes for every entry file, as the agent pastes it, its lines kept: one or two lines,
|
|
10
|
+
# worded for a reader who may not have principles installed (D68, D71).
|
|
11
|
+
class MetaPrinciplePassage
|
|
12
|
+
#: (heading: String) -> void
|
|
13
|
+
def initialize(heading:)
|
|
14
|
+
@heading = heading
|
|
15
|
+
freeze
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# The passage, ending in a line break.
|
|
19
|
+
#: () -> String
|
|
20
|
+
def text = "#{Prompts.markdown("set-principles-up/entry-file-passage", heading: @heading)}\n"
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|