@aefree/pi-plastic 0.7.6 → 0.8.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.
Files changed (148) hide show
  1. package/CHANGELOG.md +43 -0
  2. package/README.md +48 -174
  3. package/docs/2026-10-06-development.md +101 -0
  4. package/docs/2026-10-06-diffs-and-patches.md +136 -0
  5. package/docs/2026-10-06-discovery.md +135 -0
  6. package/docs/2026-10-06-integrations.md +49 -0
  7. package/docs/2026-10-06-merging.md +153 -0
  8. package/docs/2026-10-06-safety-and-receipts.md +95 -0
  9. package/docs/2026-10-06-setup.md +101 -0
  10. package/docs/2026-10-06-shelvesets-and-reviews.md +113 -0
  11. package/docs/2026-10-06-status.md +130 -0
  12. package/docs/2026-10-06-tools-and-loading.md +64 -0
  13. package/docs/2026-10-06-workspace-operations.md +142 -0
  14. package/docs/README.md +65 -0
  15. package/extensions/bash-cm-diff-guard.ts +1 -1
  16. package/index.ts +4 -687
  17. package/package.json +10 -4
  18. package/skills/using-plastic/SKILL.md +11 -5
  19. package/skills/using-plastic/references/branch-management.md +5 -1
  20. package/skills/using-plastic/references/changeset-operations.md +9 -8
  21. package/skills/using-plastic/references/code-review-creation.md +25 -18
  22. package/skills/using-plastic/references/integration.md +9 -5
  23. package/skills/using-plastic/references/quick-reference.md +4 -4
  24. package/skills/using-plastic/references/reviewing-changes.md +10 -10
  25. package/skills/using-plastic/references/shelving.md +26 -11
  26. package/skills/using-plastic/references/troubleshooting.md +4 -4
  27. package/src/diff/local-snapshot.ts +74 -0
  28. package/src/diff/text.ts +187 -0
  29. package/src/domain/add-contract.ts +24 -0
  30. package/src/domain/branch-create-contract.ts +38 -0
  31. package/src/domain/branch-delete-contract.ts +15 -0
  32. package/src/domain/branches.ts +263 -0
  33. package/src/domain/checkin-contract.ts +70 -0
  34. package/src/domain/closeout-contract.ts +30 -0
  35. package/src/domain/copied-merge.ts +42 -0
  36. package/src/domain/diff-base-xml.ts +65 -0
  37. package/src/domain/diff-pending-xml.ts +34 -0
  38. package/src/domain/merge-output.ts +327 -0
  39. package/src/domain/paths.ts +253 -0
  40. package/src/domain/pending.ts +499 -0
  41. package/src/domain/removal-contract.ts +25 -0
  42. package/src/domain/revisions.ts +301 -0
  43. package/src/domain/server-merge-contract.ts +45 -0
  44. package/src/domain/server-merge-resolutions.ts +61 -0
  45. package/src/domain/status-xml.ts +122 -0
  46. package/src/domain/switch-contract.ts +60 -0
  47. package/src/domain/switch-policy.ts +95 -0
  48. package/src/domain/undo-contract.ts +24 -0
  49. package/src/domain/update-contract.ts +16 -0
  50. package/src/domain/workspace-merge-contract.ts +41 -0
  51. package/src/execution/add-command.ts +118 -0
  52. package/src/execution/branch-create-command.ts +118 -0
  53. package/src/execution/branch-list-command.ts +75 -0
  54. package/src/execution/checkin-command.ts +116 -0
  55. package/src/execution/cli-version.ts +31 -0
  56. package/src/execution/cm.ts +59 -0
  57. package/src/execution/code-review-find-command.ts +75 -0
  58. package/src/execution/context.ts +20 -0
  59. package/src/execution/diff-revisions-command.ts +74 -0
  60. package/src/execution/process.ts +260 -0
  61. package/src/execution/removal-command.ts +118 -0
  62. package/src/execution/server-merge-command.ts +92 -0
  63. package/src/execution/shelveset-list-command.ts +75 -0
  64. package/src/execution/status-command.ts +29 -0
  65. package/src/execution/status-xml-command.ts +72 -0
  66. package/src/execution/status-xml-limits.ts +1 -0
  67. package/src/execution/switch-command.ts +118 -0
  68. package/src/execution/test-seams.ts +10 -0
  69. package/src/execution/undo-command.ts +118 -0
  70. package/src/execution/update-command.ts +118 -0
  71. package/src/execution/workspace-list-command.ts +75 -0
  72. package/src/execution/workspace-merge-command.ts +118 -0
  73. package/src/operations/add-receipt.ts +37 -0
  74. package/src/operations/arguments.ts +3 -0
  75. package/src/operations/branch-create.ts +74 -0
  76. package/src/operations/branch-delete-receipt.ts +25 -0
  77. package/src/operations/branch-list.ts +94 -0
  78. package/src/operations/branch-reads.ts +94 -0
  79. package/src/operations/branches.ts +111 -0
  80. package/src/operations/checkin-receipt.ts +140 -0
  81. package/src/operations/checkin.ts +102 -0
  82. package/src/operations/closeout-receipt.ts +74 -0
  83. package/src/operations/closeout.ts +19 -0
  84. package/src/operations/code-review-find.ts +97 -0
  85. package/src/operations/consolidated-diff.ts +144 -0
  86. package/src/operations/diff-revisions.ts +157 -0
  87. package/src/operations/diff.ts +53 -0
  88. package/src/operations/merge.ts +26 -0
  89. package/src/operations/object-delete-receipt.ts +21 -0
  90. package/src/operations/object-write-receipt.ts +105 -0
  91. package/src/operations/patch-receipt.ts +96 -0
  92. package/src/operations/patch-support.ts +375 -0
  93. package/src/operations/patch.ts +25 -0
  94. package/src/operations/removal-receipt.ts +42 -0
  95. package/src/operations/reviews.ts +90 -0
  96. package/src/operations/server-merge.ts +130 -0
  97. package/src/operations/shelveset-list.ts +90 -0
  98. package/src/operations/shelvesets.ts +90 -0
  99. package/src/operations/status.ts +129 -0
  100. package/src/operations/switch-receipt.ts +85 -0
  101. package/src/operations/switch.ts +25 -0
  102. package/src/operations/undo-receipt.ts +37 -0
  103. package/src/operations/update-receipt.ts +35 -0
  104. package/src/operations/workspace-list.ts +92 -0
  105. package/src/operations/workspace-merge-receipt.ts +50 -0
  106. package/src/operations/workspace.ts +120 -0
  107. package/src/pi/add-output.ts +52 -0
  108. package/src/pi/arguments.ts +298 -0
  109. package/src/pi/branch-create-output.ts +83 -0
  110. package/src/pi/branch-delete-output.ts +46 -0
  111. package/src/pi/branch-list-output.ts +59 -0
  112. package/src/pi/branch-output.ts +63 -0
  113. package/src/pi/capability-diagnostics.ts +23 -0
  114. package/src/pi/checkin-output.ts +68 -0
  115. package/src/pi/closeout-output.ts +87 -0
  116. package/src/pi/code-review-find-output.ts +50 -0
  117. package/src/pi/diff-output.ts +66 -0
  118. package/src/pi/diff-revisions-output.ts +55 -0
  119. package/src/pi/object-delete-output.ts +15 -0
  120. package/src/pi/object-write-output.ts +54 -0
  121. package/src/pi/patch-output.ts +69 -0
  122. package/src/pi/register.ts +188 -0
  123. package/src/pi/removal-output.ts +59 -0
  124. package/src/pi/schemas.ts +146 -0
  125. package/src/pi/server-merge-output.ts +83 -0
  126. package/src/pi/shelveset-list-output.ts +50 -0
  127. package/src/pi/status-output.ts +204 -0
  128. package/src/pi/switch-output.ts +80 -0
  129. package/src/pi/tool-registry.ts +72 -0
  130. package/src/pi/undo-output.ts +52 -0
  131. package/src/pi/update-output.ts +48 -0
  132. package/src/pi/workspace-list-output.ts +53 -0
  133. package/src/pi/workspace-merge-output.ts +46 -0
  134. package/src/plastic-core.ts +14 -5775
  135. package/src/plastic-renderers.ts +102 -22
  136. package/src/plastic-tool-loading.ts +7 -12
  137. package/src/presentation/add-results.ts +5 -0
  138. package/src/presentation/branch-create.ts +7 -0
  139. package/src/presentation/branch-delete-results.ts +7 -0
  140. package/src/presentation/checkin-results.ts +14 -0
  141. package/src/presentation/closeout-results.ts +2 -0
  142. package/src/presentation/diff-results.ts +237 -0
  143. package/src/presentation/removal-results.ts +7 -0
  144. package/src/presentation/results.ts +84 -0
  145. package/src/presentation/switch-results.ts +7 -0
  146. package/src/presentation/undo-results.ts +5 -0
  147. package/src/presentation/update-results.ts +5 -0
  148. package/src/presentation/workspace-merge-results.ts +6 -0
@@ -0,0 +1,135 @@
1
+ # Branch, workspace, and object discovery
2
+
3
+ [Documentation index](README.md) · [Status](2026-10-06-status.md) · [Safety and receipts](2026-10-06-safety-and-receipts.md)
4
+
5
+ Use an explicit structured source when you need reusable rows. Native/custom tables remain presentation rather than parsed identity evidence. Query filters describe requested scope—not returned metadata or verified ordering.
6
+
7
+ ## Choose a source
8
+
9
+ | Tool | Default | Structured source | Row identity / scope |
10
+ |---|---|---|---|
11
+ | `plastic_currentBranch` | Direct branch resolution | No extra source selector | Exact unqualified branch path / workspace |
12
+ | `plastic_branchExists` | Leaf query plus full-path comparison | No extra source selector | Path existence / workspace repository |
13
+ | `plastic_branchList` | `source="native"` | `source="names"` | Unqualified branch paths / workspace repository |
14
+ | `plastic_workspaceList` | `source="native"` | `source="fields"` | Name/path/GUID / local client inventory, with ASCII prerequisite |
15
+ | `plastic_shelvesetList` | `source="native"` | `source="ids"` | Decimal ID and unqualified sh selector / workspace repository |
16
+ | `plastic_codeReviewFind` | `source="native"` | `source="ids"` | Decimal ID / workspace repository |
17
+
18
+ Structured list projections default to 100 rows and cap at 500. The optional CLI `limit` is separate; it does not prove repository totals or exhaustion. The entire captured structured response is validated before projection, including omitted rows.
19
+
20
+ ## currentBranch
21
+
22
+ `action="current-branch"` returns the exact observed unqualified branch and basis `status`, `compact_status`, or `changeset_lookup`. No repository/server selector is invented.
23
+
24
+ Resolution follows the existing supported ladder: status; compact status only when normal output lacks a branch; changeset query only when compact output observes one changeset. Failure, cancellation, truncated/ambiguous/lossy output never authorizes another step.
25
+
26
+ Delimited paths retain spaces. Unsupported embedded selectors fail rather than shorten at whitespace. Core string output remains available; `format` changes presentation only, with legacy JSON's cached version observation outside DTO provenance.
27
+
28
+ ## branchExists
29
+
30
+ `action="branch-exists"` returns exists, requestedBranch, comparisonBranch, and scope `workspace_repository`.
31
+
32
+ - The leaf query is not identity: exact full-path comparison prevents `/other/test` from proving `/main/test`.
33
+ - Valid empty query output means false in that scope. Malformed/skipped/duplicate/unexpected rows, stderr uncertainty, and failures are errors—not verified false.
34
+ - Existing comparison removes `br:` and normalizes backslashes; relative inputs are compared literally, not expanded.
35
+ - Qualified input still has `qualifierVerified=false`, even when exists=true. It proves path existence in the workspace repository, not existence in the requested foreign repository/server.
36
+ - Core output remains `"true"`/`"false"`; no format argument is added.
37
+
38
+ ### Scalar read bounds
39
+
40
+ Identities: 4,096 characters; compact DTO: 16,384 UTF-8 bytes. Invalid/lossy/oversized Unicode identities fail rather than clip. U+FFFD and Windows `?` substitutions are rejected. Deterministic UTF-8 transport handles valid Unicode, but general live Windows/OEM round-trip support remains unverified. No XML/encoding fallback is added; legacy raw presentation/capture is outside the DTO cap.
41
+
42
+ Scalar failures withhold data and use sanitized codes such as command_failed, aborted, capture_incomplete, invalid_identity, malformed_output, invalid_producer_data, output_overflow.
43
+
44
+ ## branchList
45
+
46
+ `source="names"` uses one `find branch … --nototal --format={name} --encoding=utf-8` response. Returned branches are exact unqualified hierarchical names; no metadata/version query or source fallback follows.
47
+
48
+ | Control or result | Meaning |
49
+ |---|---|
50
+ | `nameLike` | Filters the leaf, not full hierarchical identity |
51
+ | Parent/query qualifiers | Preserved request; not cross-repository verification |
52
+ | `descending` | Ignored without orderBy, preserving existing behavior |
53
+ | `includeHidden=true` | Rejected before execution for names; native retains the existing expression |
54
+ | Counts | Observed captured rows, returned/omitted projection, excluded=0 |
55
+
56
+ Names requires slash-rooted nonempty components and exact UTF-8, LF/CRLF, at most one terminal newline. Qualifiers, backslashes, controls, lone surrogates, U+FFFD, Windows `?`, blank/junk rows, duplicates and invalid identities fail the whole response. Paired emoji are retained. CLI collation/order is preserved without a stable tie-breaker.
57
+
58
+ The hidden-query restriction is based on anomalous installed-client source behavior; it is not repaired by rewriting the query. Installed CM disallows apostrophe/newline/CR in branch leaf names; unsupported query escaping is not substituted.
59
+
60
+ ```js
61
+ const dto = await tools.plastic_branchList({source: "names", nameLike: "feature%", maxItems: 20});
62
+ text(dto.ok && dto.data.mode === "names"
63
+ ? {branches: dto.data.rows.map(row => row.branch), counts: dto.data.counts}
64
+ : dto.ok ? {rowsUnavailable: true} : dto.error);
65
+ ```
66
+
67
+ Native/default preserves tables, predicates, ordering/limit and `(no output)`. Rows/counts are null, read/capture unknown, projection false; native table identities/counts are not parsed. `format="text"|"json"` is presentation, not source.
68
+
69
+ ## workspaceList
70
+
71
+ **Fields requires independently known ASCII-only original names and paths in the entire selected local client inventory.** ASCII-looking formatter output alone is insufficient: CM can best-fit unsupported originals into printable ASCII or replace them with question marks.
72
+
73
+ Use `source="fields"` only under that configuration prerequisite. The receipt records the prerequisite and lack of independent original verification; source acceptance is limited to the tested Windows CM 11 configuration.
74
+
75
+ Fields uses one `workspace list` response with wkname, machine, path and wkid separated by tabs. No encoding/XML flags, registry-read producer, second snapshot or per-workspace lookup.
76
+
77
+ - Publish exact name/absolute path/GUID spelling. The machine field is parse-checked but not published as verified metadata.
78
+ - Scope is local_client_inventory, not the current repository, all users, or machine-wide inventory.
79
+ - Paths are producer_absolute syntax, not filesystem/platform verification.
80
+ - Counts are observed records, not unique workspaces or inventory exhaustion.
81
+ - Exact repeated four-field records remain in order; duplicateRecords covers the whole response. Conflicting reuse of GUID/name/path, including different unpublished machine fields, rejects the read.
82
+
83
+ Non-ASCII bytes, `?` identity fields, controls/BOM, blank/junk/wrong-field records, nonabsolute paths, invalid GUIDs or overflow fail with no partial reusable rows.
84
+
85
+ `format` is an arbitrary native CLI template; `output="text"|"json"` selects presentation separately. Meaningful custom format conflicts with fields; empty format keeps its ignored meaning. Native JSON retains its legacy version cache/wrapper and presentation line counts, not canonical workspace counts.
86
+
87
+ ## shelvesetList
88
+
89
+ `source="ids"` uses one `find shelve … --nototal --format={shelveid} --encoding=utf-8` response.
90
+
91
+ Rows contain decimal string id and unqualified `sh:<id>` selector. Reuse only in the same workspace-repository context; qualifierVerified=false and no repository/server alias is inferred. Owner/comment/date are requested predicates, not returned metadata or Unicode-rendering guarantees.
92
+
93
+ Exact repeated IDs remain in order, with full-response duplicate diagnostics. Counts describe observed records, not unique shelvesets, repository totals, or exhaustion.
94
+
95
+ `format` and `dateFormat` are native CLI templates; `output` selects text/JSON independently. Meaningful templates conflict with ids; empty strings retain ignored behavior. Native rows/counts stay null and read/capture unknown rather than table-derived facts. Native text/error and `(no output)` behavior remain available; JSON contains the noncanonical native envelope without a new metadata query.
96
+
97
+ ## codeReviewFind
98
+
99
+ `source="ids"` uses one `find review … --nototal --format={id} --encoding=utf-8` response. IDs are decimal strings, not JS numbers; no GUID, invented prefix, qualification, target/title/status/owner/assignee is recovered. Reuse only within workspace_repository scope; qualifierVerified=false.
100
+
101
+ Existing filters, escaping, sort fields date/modifieddate/status, ascending/descending, CLI limit and aliases remain. Descending without an order field retains ignored behavior. Query fields record intent, not verified metadata or sort correctness.
102
+
103
+ Meaningful native `format`/`dateFormat` conflicts with ids; empty strings retain ignored behavior. `output` is independent presentation. Native JSON retains its fenced wrapper/cached first-version lookup and presentation-only resultCount; those are not canonical ID/count evidence. Canonical IDs JSON uses the same DTO without that metadata command.
104
+
105
+ ```js
106
+ const dto = await tools.plastic_codeReviewFind({source: "ids", assignee: "me", maxItems: 20});
107
+ text(dto.ok && dto.data.mode === "ids"
108
+ ? {ids: dto.data.rows.map(row => row.id), counts: dto.data.counts}
109
+ : dto.ok ? {rowsUnavailable: true} : dto.error);
110
+ ```
111
+
112
+ ## List grammar and bounds
113
+
114
+ Structured sources never infer empty rows from a failed command. Genuine accepted empty queries produce []/0; malformed/oversized sources return errors without reusable partial identities.
115
+
116
+ | Bound | names / fields / ids sources |
117
+ |---|---|
118
+ | Query strings/native templates and path/name identities | 4,096 UTF-16 code units |
119
+ | Decimal ID strings | 20 digits; canonical nonnegative grammar |
120
+ | Stdout / stderr | 1 MiB /64 KiB |
121
+ | Source records | 20,000 |
122
+ | Process timeout | 30 seconds; operation collector escalation applies |
123
+ | Returned rows | 100 default /500 max |
124
+ | Compact DTO | 131,072 UTF-8 bytes |
125
+ | Public error message | 256 characters max |
126
+
127
+ IDs accept LF/CRLF and one terminal newline without trimming. Foreign/header/blank/negative/fractional/leading-zero/non-ASCII/overlong records fail, including omitted rows. Exact repeats remain for IDs/fields; branch-name duplicates fail. Nonempty stderr, invalid bytes, cancellation, timeout and capture failure reject canonical source admission. Synchronous bounded parsing has boundary abort checks, not a hard JS deadline.
128
+
129
+ Native/custom routes retain legacy raw-presentation/capture limits; the structured table bounds above do not retroactively bound them. [Foreign hooks/RPC limits](2026-10-06-safety-and-receipts.md#evidence-and-transport-limits) also apply.
130
+
131
+ ## Validation scope
132
+
133
+ Branch-name original/raw/registered equality was live-verified for spaces and several Unicode forms on Windows CM 11.0.16.10371, from root and subdirectory. Workspace fields requires its ASCII prerequisite; scalar Windows Unicode is not generally established.
134
+
135
+ Shelf/review canonical-ID source live validation covered clean empty queries. Later creation/update/deletion fixtures and external title queries do **not** establish native populated-list equality for these tools. Deterministic tests cover positive rows, grammar, precision, bounds, projection and SDK consumers. No universal platform/client/populated-inventory proof is implied.
@@ -0,0 +1,49 @@
1
+ # Pi integrations
2
+
3
+ [Documentation index](README.md) · [Setup](2026-10-06-setup.md) · [Receipt semantics](2026-10-06-safety-and-receipts.md)
4
+
5
+ These integrations improve presentation and discovery. They don't change the underlying mutation result into a stronger guarantee.
6
+
7
+ ## Tool displays
8
+
9
+ Compact action headers appear inside Pi's standard tool boxes. They show workspace and the relevant branch/file/revision pair/query; command previews are labelled.
10
+
11
+ Collapsed results expose structured counts, comparison availability, patch artifacts, merge outcomes, blocked checkins, omitted results and unresolved effects. Plain CLI output stays neutral rather than implying verified mutation.
12
+
13
+ Expand with the configured Pi tool-expansion shortcut for request/workspace context, colored diff hunks and returned evidence. Rendering preserves JSON identifiers and numeric text, masks common credential assignments and removes terminal control sequences. It does not alter execution/model-facing output or scan arbitrary source for secrets.
14
+
15
+ In a checkout, `npm run preview:tools` provides offline examples. The preview uses plain colors and a test binding; live Pi supplies the theme, box and configured shortcut.
16
+
17
+ ## Plastic branch footer
18
+
19
+ Inside a Plastic workspace, Pi adds a themed `Plastic <branch>` footer status. It finds the nearest `.plastic/plastic.workspace` and reads smartbranch/br selector forms as the credential-free source. A bounded `cm status` is used only when the selector lacks a valid branch.
20
+
21
+ Selector changes and successful same-workspace Plastic tools refresh the status; sibling workspaces are ignored.
22
+
23
+ | State | Display |
24
+ |---|---|
25
+ | Observed branch | Plastic branch status |
26
+ | Plastic marker but no selector/CM branch | Plastic branch unavailable |
27
+ | No Plastic workspace | No Plastic status |
28
+
29
+ The extension owns only the plastic-branch status key. It does not replace Pi's footer or suppress Git status; both can appear in nested workspaces.
30
+
31
+ ## File-discovery filter
32
+
33
+ When independently loaded `@aefree/pi-file-discovery` is present, session startup registers the advisory plastic.ignore-files filter through the package-qualified capability-registry rendezvous key. Separate package module roots are supported; Plastic does not import a sibling package instance from its own root.
34
+
35
+ For each requested root, the filter reads ignore.conf/cloaked.conf only from its nearest Plastic workspace and supplies readable files as ripgrep ignores, without replacing native ripgrep/Git-ignore behavior.
36
+
37
+ - Effective records declare filterDecision applied, decision code plastic_ignore_files_applied, and the workspace filterBoundary.
38
+ - A root is emitted only with at least one readable ignore/cloak file.
39
+ - No-op roots are omitted from mixed requests; no effective records means not_applicable.
40
+ - Missing/malformed/unavailable data degrades to generic discovery. The discovery package owns execution hygiene/disclosure.
41
+ - No workflow guidance or Plastic readiness query is registered by this filter.
42
+
43
+ Without file discovery, Plastic tools and the skill still load; no filter registry is created. This advisory filter is not an access-control boundary or proof that excluded files are inaccessible.
44
+
45
+ ## Bash guards
46
+
47
+ The declared diff and merge guard extensions block GUI diff/differences and unsafe interactive merge commands. They apply only in Pi processes that actually load them, not arbitrary shells or children that resolve different project settings.
48
+
49
+ Use user-scope installation when children in arbitrary workspaces must inherit them. Restart processes after installation/source changes. Mutating Plastic tools still have operation-specific guards and [authorization/receipt requirements](2026-10-06-safety-and-receipts.md#mutation-authorization-and-preflight); presentation/guards are not a universal sandbox.
@@ -0,0 +1,153 @@
1
+ # Merging and closeout
2
+
3
+ [Documentation index](README.md) · [Safety and receipts](2026-10-06-safety-and-receipts.md) · [Workspace operations](2026-10-06-workspace-operations.md)
4
+
5
+ Plastic merges are workspace/branch operations, not Git fast-forwards. A merge checkin belongs to the loaded target branch; switching afterward does not move or integrate a source-branch checkin.
6
+
7
+ ## Choose a route
8
+
9
+ | Tool | Use | Boundary |
10
+ |---|---|---|
11
+ | `plastic_merge` | Apply a noninteractive merge to the loaded workspace | Applying completion and admitted readiness are separate |
12
+ | `plastic_finalizeMerge` | Explicitly finalize merge metadata under a reviewed policy | Not a guarantee of preserving manual resolution |
13
+ | `plastic_mergeToBranch` | Resolve target, switch/update/merge/check readiness/check in | Typed ordered ledger; unknown target/readiness stops before checkin |
14
+ | `plastic_mergeBranches` | Workspace-free server-side merge | Same exact requested repository/server; no workspace fallback |
15
+
16
+ Don't substitute one route for another after failure without a new authorized decision. Command-only preflight does not analyze conflicts; closeout preflight actually performs read-only discovery/pending work.
17
+
18
+ ## merge and finalizeMerge
19
+
20
+ The closed producer receipts distinguish applying-command completion from overall outcome/readiness. Core text/JSON derives from the same observation; no version/formatting reads.
21
+
22
+ | Control | Preserved behavior |
23
+ |---|---|
24
+ | Merge strategy | Default auto/try; source/destination preferences are explicit policies |
25
+ | Finalization | Default forced destination preference; not preserved-manual-edit/conflict-resolution proof |
26
+ | Source selectors | Exact branch/changeset/label/shelve spelling, qualified or unqualified |
27
+ | Preflight | Zero-command plan, not conflict/readiness analysis |
28
+
29
+ Strict bounded inputs reject source-as-option/stdin, unsafe Unicode and unknown controls. Source/workdir cap 4,096 code units; aliases keep canonical precedence.
30
+
31
+ At most one applying merge. Supported output can be followed by separately recorded short/full status reads. File-conflict records block. Exit 0 followed by failed/unsupported reads can retain commandCompleted=true with overall ok=false/uncertain and unknown readiness.
32
+
33
+ No swallowed read failure, raw diagnostic facts, retry, strategy switch, export/backup/version query or rollback. Possible-start failure never proves absent effects or safe replay. Unobserved source/workspace identity, pending items, finalized metadata and preservation stay null.
34
+
35
+ ### Admitted readiness profiles
36
+
37
+ Windows CM 11.0.16.10371 source admission is narrow:
38
+
39
+ - Exact nonce-framed STATUS/ALREADY_CONNECTED, FILE_CONFLICT, APPLY/ADD and paired DO_COPIED records.
40
+ - Empty profile: successful complete empty short status plus exact header-only standard status and no stderr.
41
+ - Copied-add profile: paired applying paths, CP-only pending records and machine/full-status correlation; up to 128 files under unchanged byte/frame limits and one merge changeset.
42
+
43
+ Unknown/mixed/malformed/empty applying output, other rich operations, unsupported localization, unrelated pending changes or merge links stop as unknown—not zero conflicts or rollback. Core rejection and independent closeout post-read gates prevent checkin on unknown readiness.
44
+
45
+ `supported-no-unresolved-signals` is point-in-time admitted evidence, not transaction finality, target-head/source-link/exclusivity/other-workspace/Xlink proof. The agent may inspect and choose a supported resolution; the tool doesn't force one.
46
+
47
+ ## mergeToBranch
48
+
49
+ ```text
50
+ plastic_mergeToBranch(source="/main/owned-feature", target="/main", message="Merge owned feature", preflight=true)
51
+ ```
52
+
53
+ The ordered ledger can include discovery, pending reads, switch, optional update, merge, readiness, checkin and final observations. Inspect stages, outcome, completeness and unattemptedStages before proceeding. Unattempted stages include deliberate omissions as well as stopped steps.
54
+
55
+ - Source defaults only from directly observed loaded workspace.
56
+ - Target defaults only from an admitted source-parent observation.
57
+ - Branch inputs are bounded hierarchical selectors; changeset/label/shelve/flag operands are not closeout branches.
58
+ - Exact qualified spelling is retained. Different repository/server spellings, including unverified aliases, stop before target mutation.
59
+ - Loaded target is independently checked before merge/checkin; final branch mismatch is an error. Unqualified targets can have name-only workspace-context verification, not globally qualified identity proof.
60
+ - No child text/fenced JSON is parsed, operation replayed, or raw diagnostic copied as facts.
61
+ - A checkin identity remains recorded if final target/pending evidence fails.
62
+
63
+ ### Parent discovery
64
+
65
+ The installed client filters `name` by leaf but emits full hierarchy in `{name}|{parent}`. One query uses leaf equality, branchname ordering and limit 2 before the optional exact repository clause.
66
+
67
+ Only one matching full-source/direct-parent row is admitted. Two rows mean ambiguity; empty rows are not proof of branch absence. Warning/failure/malformed/root/unrelated-parent output stops without alternate queries or lexical parent guessing. The discovered target still requires loaded-target verification.
68
+
69
+ ### Investigating unknown readiness
70
+
71
+ `unsupported_readiness` is not an applying-command failure or rollback receipt. Inspect `commandCompleted`, capture completeness, `protocol` and each stage admission. Diagnostics distinguish unsupported applying output, applying warnings, pending/path correlation and full-status correlation. Stop checkin and do not automatically reapply the merge. Use separately authorized read-only inspection to establish current pending/conflict state; retain sanitized producer evidence for unsupported-profile analysis and verify the package revision actually loaded by the process (a source checkout alone is not proof).
72
+
73
+ Copied-add admission does not admit mixed replace/delete profiles. A synthetic historical-shape regression proves the supported DO_COPIED/ADD/CP path, not historical recovery: unavailable historical producer bytes and uncertain/stale runtime loads remain unresolved.
74
+
75
+ ### Readiness and message admission
76
+
77
+ Independent readiness requires complete successful capture, empty stderr, and an admitted header-only standard snapshot or the strict copied profile. Copied admission uses machine pending instead of the first standalone short read, then correlates full pending-link/Added/copied sections with requested source, namespace, changeset/merge metadata and paths. Volatile size/time display is opaque. Unknown/mixed/directory/duplicate/out-of-workspace records remain unsupported; CP selection keeps its CP code while using added kind locally in checkin. Final pending observations are typed and admitted, never swallowed into zero.
78
+
79
+ Existing message/card trimming and explicit-message precedence remain. Derived messages must satisfy the checkin owner's text/4, 096-unit bounds before target mutation. A card-only default inserts newlines rejected by that owner; supply an admitted explicit message instead. This is a current restriction, not permission to widen checkin text admission or silently drop the card.
80
+
81
+ ### Defaults and bounds
82
+
83
+ | Setting / bound | Value |
84
+ |---|---|
85
+ | Strategy | auto |
86
+ | Update target | true |
87
+ | Include private | false |
88
+ | Pending switch policy | cancel |
89
+ | Source / target / workdir controls | 4,096 UTF-16 code units |
90
+ | Request | 32,768 UTF-8 bytes |
91
+ | Ledger | 16 stages; up to 5 full child receipts and 11 compact reads |
92
+ | DTO | 1 MiB UTF-8 bytes |
93
+
94
+ Preflight is read-only discovery/pending preview, not zero CLI or applying-readiness proof. Selected reads use 64 KiB stdout/16 KiB stderr and nominal 30+5+5-second retirement; child operation limits/recovery rules remain in force. No compound retry/undo/switch-back/strategy change, rollback/exclusivity or guaranteed aggregate deadline is added.
95
+
96
+ ## mergeBranches
97
+
98
+ This route has no workspace mutation/fallback. Supply distinct fully qualified source/target branches in the same exact requested repository/server. The default `mode="apply"` requires a nonempty message; `mode="analyze"` is read-only remote conflict discovery and rejects a message, resolution file or conflict policy.
99
+
100
+ ```text
101
+ plastic_mergeBranches(source="br:/main/source@Example Repository@example@unity", target="br:/main/target@Example Repository@example@unity", message="Merge source", preflight=true)
102
+ ```
103
+
104
+ Inputs allow unambiguous `br:/branch@repository@server`, including literal host or full cloud/unity server suffix. Each control caps 4,096 UTF-16 code units. Workdir, unknown controls, malformed Unicode, and `@` inside branch/repository are rejected. Absolute local resolution-input paths are preserved, not trimmed or rewritten.
105
+
106
+ | Outcome/evidence | Interpretation |
107
+ |---|---|
108
+ | Preflight | Zero CLI; validates supplied local inputs and renders command intent, not remote conflicts |
109
+ | Analyzed | Complete supported point-in-time remote output; no applying command or contributor export |
110
+ | Completed | Complete normal exit emitted exactly one matching branch/repository/root-mount changeset |
111
+ | No-op / ALREADY_CONNECTED | Classification with effect not-proven; not independently verified unchanged state |
112
+ | Conflict / unsupported / uncertain / failed | Stop; possible effects are not ruled out |
113
+
114
+ Applying performs one local help syntax check and at most one noninteractive server merge. Exact decimal ID/emitted server qualifier remain separate from requested server spelling; alias equivalence is unverified.
115
+
116
+ No source-link/head-exclusive/global/Xlink/rollback proof, retries, head unification or shelveset mode. Undetected server-side Xlink effects remain possible; accepting a full xlink conflict path does not verify linked-repository ownership or effects.
117
+
118
+ ### Agent conflict-resolution workflow
119
+
120
+ 1. **Inspect:** call `mode="analyze"` to execute `cm merge <source> --to=<target>` without `--merge`. Unlike `preflight`, this contacts the server. Read `conflictPaths`, parse/capture completeness and omission counts. Empty, malformed, unknown-operation (including directory-conflict), warning or failed output remains uncertain, not a clean merge. `analyzed` means a supported observation, not absence of conflicts.
121
+ 2. **Understand contributors:** independently inspect base/source/destination for each conflict. The exact destination conflict path is usable as a resolution key, not a workspace path. This tool does not retrieve content or assign meanings to the numeric FILE_CONFLICT fields. If needed, use a read-only `cm merge <qualified-source> --to=<qualified-target> --printcontributors` inspection, without `--merge`, to establish contributor identities. Use `plastic_diff(mode="revisions", ...)` for deliberate comparisons after verifying file/repository/server-qualified selectors. For full bytes unavailable through typed tools, follow the [historical export fallback](../skills/using-plastic/references/changeset-operations.md#historical-export-fallback): fresh external temporary destinations only, never canonical workspace files or guessed revision IDs. Writable xlinks need independently verified linked-repository identities; do not qualify their revision IDs against the root repository by assumption.
122
+ 3. **Resolve and validate:** write merged content into new local result files outside the workspace; preserve immutable contributor baselines. Review the result and run relevant validation before submission. Binary files may use `keep`, but choosing a side deliberately discards the other contributor's conflicting changes. Directory conflicts are not solved by this JSON feature; stop and choose a separately authorized workflow.
123
+ 4. **Submit:** create a UTF-8 JSON file as below and pass its absolute path as `fileConflictsResolutionsFile` with a merge message. Each `path` must exactly match its observed FILE_CONFLICT destination path, including any writable-xlink prefix. Each entry requires exactly one of `keep` (`source`/`destination`) or an absolute readable regular `resultFile`. Duplicate paths and unknown fields are rejected. Input validation caps JSON at 1 MiB / 500 entries and records its SHA-256 plus counts, not file contents. Applying rechecks the JSON hash and result-file readability after help, before dispatch.
124
+ 5. **Observe:** inspect the receipt and any emitted target changeset. Never automatically retry a conflict, timeout or uncertain applying result. Keep source/target heads and all input files unchanged between inspection, validation and submission; these calls do not provide a transaction, head lock, result-content hash or atomic input snapshot. If the inputs or heads change, reassess instead of reusing stale merged content. The CLI owns current-conflict matching; its documented invalid-resolution rejection happens before upload, but opaque failures do not establish rollback.
125
+
126
+ ```text
127
+ plastic_mergeBranches(source="br:/main/source@Example Repository@example@unity", target="br:/main@Example Repository@example@unity", mode="analyze")
128
+ plastic_mergeBranches(source="br:/main/source@Example Repository@example@unity", target="br:/main@Example Repository@example@unity", message="Integrate reviewed resolutions", fileConflictsResolutionsFile="/tmp/resolutions.json")
129
+ ```
130
+
131
+ ```json
132
+ {
133
+ "resolutions": [
134
+ { "path": "/src/Player.cs", "resultFile": "/tmp/merged/Player.cs" },
135
+ { "path": "/art/logo.png", "keep": "source" },
136
+ { "path": "/README.md", "keep": "destination" }
137
+ ]
138
+ }
139
+ ```
140
+
141
+ The paths above are POSIX examples; on Windows supply native absolute local input paths. The tool and `cm` never change/delete the caller's JSON or result files. The JSON takes precedence over an optional explicit `unlistedConflictPolicy="source"|"destination"`, which emits `--keepsource`/`--keepdestination` only for that intentional fallback. Omit it to keep the existing noninteractive behavior for unlisted conflicts; never select a fallback automatically. `--nointeractiveresolution` is always present, including analysis. The resolution flag is required in local help only when a file is supplied, so ordinary merges retain their existing capability requirements. Local CM 11.0.16.10468 help advertises this flag; deterministic tests cover contracts, not live server-side resolution effects. Shelve sources/results are not added by this feature.
142
+
143
+ ### Server merge bounds
144
+
145
+ Stdout 64 KiB/stderr 16 KiB, fatal UTF-8, nullable observed start/terminal/exit facts. Help: 3 second deadline and 32,768 decoded-unit stdout gate (the updated help exceeds the former 16 KiB limit); merge: 30 second deadline with bounded termination escalation. Capture uncertainty never implies cancellation or safe replay.
146
+
147
+ Classify full framing/records before one aggregate 100-reference projection budget. Unknown/contradictory/malformed/overlimit evidence cannot become success. DTO 131,072 UTF-8 bytes; presentation 24,000 units. Core text/fenced JSON and native text/JSON share one observation; failures return native isError with no diagnostic duplication.
148
+
149
+ ## Follow-up decisions
150
+
151
+ Inspect merge metadata and pending scope rather than assuming exit 0 permits checkin. Use finalization only with explicit policy intent, not as automatic conflict repair. Manual resolution and any later applying call remain agent/user decisions with their own scope.
152
+
153
+ For source/consumer/platform limits, see [receipt semantics](2026-10-06-safety-and-receipts.md#evidence-and-transport-limits) and [the workflow skill](../skills/using-plastic/SKILL.md).
@@ -0,0 +1,95 @@
1
+ # Safety and receipts
2
+
3
+ [Documentation index](README.md) · [Tool-specific contracts](README.md#look-up-a-tool)
4
+
5
+ **The tool reports observed facts and unknowns; the agent chooses the next authorized action.** A receipt is not a transaction, automatic resolution, or proof that every requested effect occurred.
6
+
7
+ ## What success means
8
+
9
+ | Evidence | What it supports | What it does not establish by itself |
10
+ |---|---|---|
11
+ | Complete command exit 0 | Command completion, if that tool admits the capture | Changed files, clean workspace, deletion, preservation, or requested review state |
12
+ | Admitted emitted ID | The exact creation identity emitted by that command | Requested/emitted server alias equivalence, target-head exclusivity, or unrelated repository effects |
13
+ | Complete scoped read | Facts in that source/query scope | Repository totals, unselected records, global absence, or an atomic snapshot |
14
+ | Separate resulting-byte/state observation | The inspected post-state at that time | Automatic rollback or a guarantee about concurrent activity |
15
+ | Timeout/abort/retirement | The observed lifecycle/capture uncertainty | That the process stopped, no effect occurred, or replay is safe |
16
+
17
+ Some tools can observe more than command completion—for example admitted checkin changesets or patch bytes. Others deliberately keep requested effects null/unverified. Read the relevant tool reference instead of applying one success rule to all operations.
18
+
19
+ ## Read a native result
20
+
21
+ All core tools declare an output schema. Registered results use producer-owned `structuredContent`, independently of text/JSON presentation. Codemode consumers receive that DTO when the host preserves it.
22
+
23
+ | Field or concept | How to use it |
24
+ |---|---|
25
+ | `schemaVersion`, `action` | Select the declared tool/schema route; versions and shapes differ by tool |
26
+ | `ok` and native `isError` | Distinguish admitted results from failures; also handle host-native rejection |
27
+ | `provenance` | Plastic external content, produced by this package—not trusted instructions |
28
+ | `completeness` | Inspect read, capture, and projection independently where declared |
29
+ | `scope`, limits, counts | Keep query scope and omitted/unattempted evidence visible |
30
+ | Attempt/stage/effect fields | Preserve earlier completed or possible effects after later failures |
31
+ | Requested versus observed identity | Never substitute caller intent for observed/resolved identity |
32
+
33
+ Not every schema has every field. A successful **partial read** can still have `ok:true`; that is not a complete clean workspace. Native/custom table routes can have null rows/counts and unknown completeness rather than parsed facts.
34
+
35
+ Mutation/diff receipts generally use empty `details`; some read adapters retain legacy presentation in `details.rawResult`. Don't use that presentation as a substitute for declared canonical fields.
36
+
37
+ ```js
38
+ const dto = await tools.plastic_status({source: "xml", maxItems: 20});
39
+ if (!dto.ok) {
40
+ text(dto.error);
41
+ } else {
42
+ text({
43
+ completeness: dto.completeness,
44
+ itemCount: dto.data.itemCount,
45
+ changedPaths: dto.data.items.filter(item => item.kind === "changed").map(item => item.path)
46
+ });
47
+ }
48
+ ```
49
+
50
+ The example emits observed paths plus completeness; it does not certify workspace cleanliness. See [status](2026-10-06-status.md) for source restrictions.
51
+
52
+ ## Mutation authorization and preflight
53
+
54
+ Direct tool calls do not require package-owned approval tokens or UI confirmation. The agent must have user authorization, inspect exact targets, and respect command/path/workspace guards.
55
+
56
+ Preflight is **not routine confirmation** and does not mean the same thing everywhere:
57
+
58
+ | Operation | Preflight behavior |
59
+ |---|---|
60
+ | Branch/object deletion, object writes, workspace merge/finalization, server merge | Command-only plan; zero CLI, no existence/conflict/permission proof |
61
+ | Patch | Command-only plan; may read local selector metadata; no staging, backend probe, or generation |
62
+ | Checkin | Reads pending scope once; no mutation |
63
+ | Switch | Two sequential local reads; not server switchability/conflict proof |
64
+ | Closeout | Read-only discovery/pending preview; not zero CLI or applying-readiness proof |
65
+ | Add, undo, update, branchCreate | No added preflight API; use the declared tool schema |
66
+
67
+ Shelveset `preview=true` is different: it actually dispatches CM and can prompt/fail on conflicts. Read [shelveset application](2026-10-06-shelvesets-and-reviews.md#shelvesetapply).
68
+
69
+ ## Respond to failure without inventing recovery
70
+
71
+ 1. Stop dependent actions on failed/unknown evidence. A failed checkin/readiness step must not become successful closeout.
72
+ 2. Retain earlier IDs, publication, completed commands, and possible effects recorded in the receipt.
73
+ 3. Inspect the exact affected scope when further investigation is authorized.
74
+ 4. Choose an explicit resolution or ask the user when ownership, permissions, interaction, or intent is unclear.
75
+
76
+ Single-command producers do not silently retry, switch backends/strategies, or compensate. Compound operations can have multiple declared steps. Checkin and switch retain narrowly admitted existing recovery paths; those exceptions are documented in [workspace operations](2026-10-06-workspace-operations.md), not general retry permission.
77
+
78
+ Parent/agent restoration is a separate action with its own scope and evidence. It is not producer rollback. Do not interpret null effects, empty stdout, or a no-op classification as globally verified absence.
79
+
80
+ ## Guards and limits of protection
81
+
82
+ - The loaded Bash guards block raw GUI `cm diff` / `cm differences` and unsafe interactive `cm merge --merge` use.
83
+ - Guards exist only in Pi processes that load the package. Prefer user-scope installation for children running elsewhere.
84
+ - Preserve selector spelling and qualifiers. Different server names are not automatically interchangeable.
85
+ - Operation-specific containment checks do not turn all directory/wildcard operands into exclusively contained mutations.
86
+ - `cm cat --file=<path>` writes and can overwrite that destination. Never treat it as a read-only selector or point an inspection export at canonical workspace files.
87
+ - A bounded collector may retire while a child/server action can still be running. Per-command deadlines are not atomic compound deadlines.
88
+
89
+ ## Evidence and transport limits
90
+
91
+ Source acceptance is deliberately tool/client-specific. Windows CM 11 fixtures are not universal cross-platform, Xlink, Unicode, head, source-link, alias, exclusivity, or rollback proof. Unsupported source profiles stop conservatively; the agent may investigate rather than forcing admission.
92
+
93
+ Real SDK-host tests use a deterministic local provider and synthetic CLI. They validate consumers/serialization, not actual backend effects. Ordinary transcript messages do not automatically persist the full DTO. Foreign result hooks can remove/replace structured output, causing text fallback; this package does not restore it or enforce bounds after foreign hooks. General RPC fidelity is not claimed.
94
+
95
+ See [development](2026-10-06-development.md) for testing and [the tool index](README.md#look-up-a-tool) for each source/capture contract.
@@ -0,0 +1,101 @@
1
+ # Setup
2
+
3
+ [Documentation index](README.md) · [Next: tools and loading](2026-10-06-tools-and-loading.md)
4
+
5
+ ## Requirements
6
+
7
+ | Component | Requirement |
8
+ |---|---|
9
+ | Node.js | 22.19.0 or newer |
10
+ | Pi | Latest stable release; older versions are not the supported baseline |
11
+ | Plastic CLI | Authenticated `cm` on PATH, or `PI_PLASTIC_CM_EXECUTABLE` set to its full executable path |
12
+ | Workspace | Configured Plastic workspace for workspace-scoped tools; server merge has a separate workspace-free contract |
13
+ | Text comparison | A compatible non-GUI GNU/POSIX `diff` |
14
+ | Patch generation | A separately verified patch-capable diff backend; see below |
15
+
16
+ The package does not install or authenticate Plastic for you. Authenticate using your own authorized account, and inspect the workspace you intend to operate on.
17
+
18
+ ## Choose an installation source
19
+
20
+ ### Published npm release
21
+
22
+ ```bash
23
+ pi install npm:@aefree/pi-plastic
24
+ ```
25
+
26
+ This is the published package, which can lag Git main. Install at user scope when sessions and child processes in arbitrary workspaces need the Bash guards.
27
+
28
+ ### Git main or a pinned release
29
+
30
+ ```bash
31
+ # Track the moving default branch, including unreleased work:
32
+ pi install https://github.com/aefreedman/pi-plastic
33
+
34
+ # Pin an existing release tag:
35
+ pi install git:github.com/aefreedman/pi-plastic@v0.8.0
36
+
37
+ # Equivalent SSH source:
38
+ pi install git:git@github.com/aefreedman/pi-plastic@v0.8.0
39
+ ```
40
+
41
+ A pinned Git tag/commit does not move to main when updated. Review third-party source before installing: extensions execute with host permissions.
42
+
43
+ ### Local checkout or project settings
44
+
45
+ ```bash
46
+ pi install ./path-to-pi-plastic
47
+ pi install -l ./path-to-pi-plastic
48
+ ```
49
+
50
+ Local sources load from their path without copying. Install checkout dependencies yourself; see [development](2026-10-06-development.md#checkout-setup). Relative local paths resolve from the settings file containing them.
51
+
52
+ `-l` writes project settings. Project packages are subject to Pi's project-trust rules. A project-local install protects only processes loading that project's settings, not children launched into other workspaces.
53
+
54
+ ## Update and reload
55
+
56
+ Use `pi list` to inspect configured sources. `pi update --extensions` reconciles installed packages; `pi update <source>` updates one source. Plain `pi update` updates Pi itself, not just this package.
57
+
58
+ Restart existing Pi processes after installation or source changes. For resource edits during development, Pi provides `/reload`; source files are not automatically watched. See [loading modes](2026-10-06-tools-and-loading.md#loading-modes) when an installed tool is inactive rather than missing.
59
+
60
+ ## Executable configuration
61
+
62
+ Set environment variables before starting Pi. Full executable paths may contain spaces; the package invokes the resolved executable as-is and does not discover Git Bash paths automatically.
63
+
64
+ | Variable | Purpose |
65
+ |---|---|
66
+ | `PI_PLASTIC_CM_EXECUTABLE` | Override `cm` |
67
+ | `PI_PLASTIC_DIFF_EXECUTABLE` | Backend for text-only comparisons |
68
+ | `PI_PLASTIC_PATCH_EXECUTABLE` | Separate default backend for `cm patch` |
69
+ | `PI_PLASTIC_TOOL_LOADING_MODE` | `balanced`, `loader-only`, or `all-active` |
70
+ | `TEMP` / `TMP` | Writable ASCII-safe temporary location when the diff backend cannot accept Unicode paths |
71
+
72
+ For example, in PowerShell, using a **verified local executable**:
73
+
74
+ ```powershell
75
+ $env:PI_PLASTIC_CM_EXECUTABLE = "C:/Tools/Plastic/cm.exe"
76
+ $env:PI_PLASTIC_DIFF_EXECUTABLE = "C:/Tools/Diff/diff.exe"
77
+ $env:PI_PLASTIC_PATCH_EXECUTABLE = "C:/Tools/Git/usr/bin/diff.exe"
78
+ pi
79
+ ```
80
+
81
+ These are fictional paths, not executable-discovery recommendations.
82
+
83
+ ## Diff and patch backends
84
+
85
+ Text comparison and patch generation have different compatibility requirements. The package does not silently switch backends or retry with another executable.
86
+
87
+ | Environment | Text comparison | Patch generation |
88
+ |---|---|---|
89
+ | Windows | Configure a compatible text diff explicitly if needed | Set `toolPath` for one call or `PI_PLASTIC_PATCH_EXECUTABLE`, for example a verified Git `diff.exe`; text/GnuWin32 configuration is not reused as the patch default |
90
+ | macOS | Apple BSD `/usr/bin/diff` has text-only evidence; PATH may instead resolve GNU diff | Tested Apple BSD diff rejects CM 11's `--binary` argument; configure a verified GNU Diffutils-compatible backend |
91
+ | Other non-Windows environments | Resolve PATH `diff` or the explicit text override | The text override/PATH fallback is usable only when that executable accepts the local CM patch arguments |
92
+
93
+ Patch precedence: one-call `toolPath`, then `PI_PLASTIC_PATCH_EXECUTABLE`, then the allowed non-Windows fallback. Windows requires explicit patch configuration.
94
+
95
+ Interactive Pi sessions issue one path-redacted capability warning per runtime for missing Windows patch configuration or an invalid configured override. The tool still validates configuration at call time. Fix configuration before a **new deliberate attempt**; after an uncertain applying operation, inspect state first.
96
+
97
+ See [diffs and patches](2026-10-06-diffs-and-patches.md) for comparison scopes, publication, cleanup, and bounds.
98
+
99
+ ## Optional file discovery
100
+
101
+ `@aefree/pi-file-discovery` is an independently loaded optional integration, not a bundled runtime requirement. Without it, Plastic tools and the skill still work; no discovery filter registry is created. See [integration behavior](2026-10-06-integrations.md#file-discovery-filter).