@aefree/pi-plastic 0.5.5 → 0.5.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +6 -0
- package/README.md +1 -1
- package/index.ts +24 -1
- package/package.json +3 -4
- package/skills/using-plastic/SKILL.md +1 -1
- package/src/plastic-core.ts +45 -0
- package/SECURITY.md +0 -31
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,12 @@ and this project follows semantic versioning for public package releases.
|
|
|
7
7
|
|
|
8
8
|
## Unreleased
|
|
9
9
|
|
|
10
|
+
## [0.5.6] - 2026-08-27
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
|
|
14
|
+
- Warn once per interactive Pi runtime when a configured `PI_PLASTIC_PATCH_EXECUTABLE` cannot launch or Windows lacks its required patch backend setting. Warnings redact configured paths; `plastic_patch` retains its existing tool-time validation.
|
|
15
|
+
|
|
10
16
|
## [0.5.5] - 2026-08-14
|
|
11
17
|
|
|
12
18
|
### Changed
|
package/README.md
CHANGED
|
@@ -143,7 +143,7 @@ Project-local installation protects only Pi processes that load those project se
|
|
|
143
143
|
- Pi 0.82.0 or newer; the current development and eval baseline is Pi 0.83
|
|
144
144
|
- Plastic SCM / Unity Version Control CLI (`cm`) available on `PATH`, or `PI_PLASTIC_CM_EXECUTABLE` set to its full executable path
|
|
145
145
|
- A GNU/POSIX-compatible text `diff` available on `PATH`, or `PI_PLASTIC_DIFF_EXECUTABLE` set to its full executable path (including paths containing spaces), for text-only diff tools. Pi invokes that resolved executable as-is and does not discover Git Bash paths automatically. On macOS, bare `diff` is PATH-dependent: it may be GNU Diffutils (often installed as `diff` ahead of system paths) or Apple’s BSD `/usr/bin/diff`; the package does not substitute one for the other. Configure the intended text executable explicitly when that distinction matters.
|
|
146
|
-
- Patch generation has a separate executable policy: `toolPath` is the one-call highest-priority override, followed by `PI_PLASTIC_PATCH_EXECUTABLE`. On Windows, set one to a verified patch-capable non-GUI executable such as Git's `diff.exe`; the package deliberately does not reuse `PI_PLASTIC_DIFF_EXECUTABLE`/GnuWin32 as a patch default. macOS validation with Plastic 11 found that Apple BSD `/usr/bin/diff` supports text-only diffs but rejects the `--binary` argument supplied by `cm patch`; configure a verified GNU Diffutils-compatible executable explicitly for `plastic_patch`. The non-Windows fallback to `PI_PLASTIC_DIFF_EXECUTABLE` or bare `diff` remains only for environments whose resolved executable satisfies that patch contract.
|
|
146
|
+
- Patch generation has a separate executable policy: `toolPath` is the one-call highest-priority override, followed by `PI_PLASTIC_PATCH_EXECUTABLE`. On Windows, set one to a verified patch-capable non-GUI executable such as Git's `diff.exe`; the package deliberately does not reuse `PI_PLASTIC_DIFF_EXECUTABLE`/GnuWin32 as a patch default. macOS validation with Plastic 11 found that Apple BSD `/usr/bin/diff` supports text-only diffs but rejects the `--binary` argument supplied by `cm patch`; configure a verified GNU Diffutils-compatible executable explicitly for `plastic_patch`. The non-Windows fallback to `PI_PLASTIC_DIFF_EXECUTABLE` or bare `diff` remains only for environments whose resolved executable satisfies that patch contract. In an interactive Pi session, an invalid configured patch override or missing Windows patch setting produces one package capability warning per Pi runtime; the warning omits configured paths, and `plastic_patch` retains its tool-time validation.
|
|
147
147
|
- A configured Plastic workspace for workspace-scoped operations. Text diffs require an ASCII-safe temporary directory; if the configured backend cannot accept Unicode paths, set `TEMP` and `TMP` to a writable ASCII-only location.
|
|
148
148
|
- `pi-file-discovery` is an optional independently loaded integration. When its `discover_candidate_files` tool is active, it receives the advisory Plastic ignore/cloak filter through the shared global capability protocol; when absent, `pi-plastic` loads without file-discovery filtering. The tarball does not embed linked sibling workspaces or `node_modules` paths.
|
|
149
149
|
|
package/index.ts
CHANGED
|
@@ -656,6 +656,28 @@ function metadataDescription(node: CoreSchemaNode): string {
|
|
|
656
656
|
return node.metadata?.description ?? "Allowed values.";
|
|
657
657
|
}
|
|
658
658
|
|
|
659
|
+
type CapabilityDiagnosticContext = {
|
|
660
|
+
hasUI?: boolean;
|
|
661
|
+
ui?: { notify?: (message: string, level: "warning") => void };
|
|
662
|
+
};
|
|
663
|
+
|
|
664
|
+
type PatchCapabilityWarningGetter = () => Promise<string | undefined>;
|
|
665
|
+
|
|
666
|
+
export const __plasticCapabilityDiagnosticInternals = {
|
|
667
|
+
createPatchCapabilityWarningNotifier(getWarning: PatchCapabilityWarningGetter = () => core.getPatchBackendCapabilityWarning()) {
|
|
668
|
+
let emitted = false;
|
|
669
|
+
return async (ctx: CapabilityDiagnosticContext): Promise<void> => {
|
|
670
|
+
if (emitted || !ctx.hasUI || typeof ctx.ui?.notify !== "function") return;
|
|
671
|
+
const warning = await getWarning();
|
|
672
|
+
if (!warning) return;
|
|
673
|
+
emitted = true;
|
|
674
|
+
ctx.ui.notify(warning, "warning");
|
|
675
|
+
};
|
|
676
|
+
},
|
|
677
|
+
};
|
|
678
|
+
|
|
679
|
+
const notifyPatchCapabilityWarning = __plasticCapabilityDiagnosticInternals.createPatchCapabilityWarningNotifier();
|
|
680
|
+
|
|
659
681
|
function buildParameters(args: Record<string, unknown> | undefined): TSchema {
|
|
660
682
|
if (!args || Object.keys(args).length === 0) {
|
|
661
683
|
return EMPTY_PARAMETERS;
|
|
@@ -770,7 +792,8 @@ export default function plasticTools(pi: ExtensionAPI) {
|
|
|
770
792
|
},
|
|
771
793
|
});
|
|
772
794
|
|
|
773
|
-
pi.on("session_start", (_event, ctx) => {
|
|
795
|
+
pi.on("session_start", async (_event, ctx) => {
|
|
796
|
+
await notifyPatchCapabilityWarning(ctx as CapabilityDiagnosticContext);
|
|
774
797
|
const ownership = getEffectivePlasticToolOwnership(pi.getAllTools(), EXTENSION_SOURCE_PATH);
|
|
775
798
|
const active = pi.getActiveTools();
|
|
776
799
|
const mode = getPlasticToolLoadingMode();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aefree/pi-plastic",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.6",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": ">=22.19.0"
|
|
@@ -18,8 +18,7 @@
|
|
|
18
18
|
"skills/",
|
|
19
19
|
"CHANGELOG.md",
|
|
20
20
|
"LICENSE",
|
|
21
|
-
"README.md"
|
|
22
|
-
"SECURITY.md"
|
|
21
|
+
"README.md"
|
|
23
22
|
],
|
|
24
23
|
"pi": {
|
|
25
24
|
"extensions": [
|
|
@@ -34,7 +33,7 @@
|
|
|
34
33
|
]
|
|
35
34
|
},
|
|
36
35
|
"scripts": {
|
|
37
|
-
"test": "npx --yes tsx tests/plastic-tool-validation.ts && npx --yes tsx tests/plastic-status-machine-readable.test.ts && npx --yes tsx tests/plastic-checkin-path-resolution.ts && npx --yes tsx tests/plastic-diff-workflow.test.ts && npx --yes tsx tests/plastic-workspace-diff.test.ts && npx --yes tsx tests/plastic-process-lifecycle.test.ts && npx --yes tsx tests/plastic-patch-command.test.ts && npx --yes tsx tests/plastic-extension-registration.test.ts && npx --yes tsx tests/plastic-dynamic-tool-loading.test.ts && npx --yes tsx tests/plastic-tool-rendering.test.ts && npx --yes tsx tests/plastic-branch-query.test.ts && npx --yes tsx tests/plastic-workspace.test.ts && npx --yes tsx tests/plastic-mutation-execution.test.ts && npx --yes tsx tests/file-discovery-filter.test.ts && npx --yes tsx tests/file-discovery-filter-registration.test.ts && npx --yes tsx tests/packed-copy-owner-conflict.test.ts && npx --yes tsx tests/plastic-branch-status.test.ts && npx --yes tsx tests/plastic-constrained-sampling.test.ts && npx --yes tsx tests/bash-cm-diff-guard-validation.ts",
|
|
36
|
+
"test": "npx --yes tsx tests/plastic-tool-validation.ts && npx --yes tsx tests/plastic-status-machine-readable.test.ts && npx --yes tsx tests/plastic-checkin-path-resolution.ts && npx --yes tsx tests/plastic-diff-workflow.test.ts && npx --yes tsx tests/plastic-workspace-diff.test.ts && npx --yes tsx tests/plastic-process-lifecycle.test.ts && npx --yes tsx tests/plastic-patch-command.test.ts && npx --yes tsx tests/plastic-capability-diagnostics.test.ts && npx --yes tsx tests/plastic-extension-registration.test.ts && npx --yes tsx tests/plastic-dynamic-tool-loading.test.ts && npx --yes tsx tests/plastic-tool-rendering.test.ts && npx --yes tsx tests/plastic-branch-query.test.ts && npx --yes tsx tests/plastic-workspace.test.ts && npx --yes tsx tests/plastic-mutation-execution.test.ts && npx --yes tsx tests/file-discovery-filter.test.ts && npx --yes tsx tests/file-discovery-filter-registration.test.ts && npx --yes tsx tests/packed-copy-owner-conflict.test.ts && npx --yes tsx tests/plastic-branch-status.test.ts && npx --yes tsx tests/plastic-constrained-sampling.test.ts && npx --yes tsx tests/bash-cm-diff-guard-validation.ts",
|
|
38
37
|
"test:live": "npx --yes tsx tests/plastic-live-smoke.test.ts",
|
|
39
38
|
"test:live:branch-create": "npx --yes tsx tests/plastic-branch-create-live.test.ts",
|
|
40
39
|
"eval:tool-loading": "npx --yes tsx evals/tool-loading/run-eval.ts"
|
|
@@ -22,7 +22,7 @@ Plastic merges are workspace- and branch-oriented, not Git fast-forwards: the me
|
|
|
22
22
|
|
|
23
23
|
`plastic_workspaceDiff` requires selected paths or explicit `allPending=true`, runs status once, has small default file/per-file/combined-output bounds, and returns per-file outcomes without aborting when one file is unavailable. Selected private paths are included; whole-workspace private review additionally requires `includePrivate=true`. Keep `maxChars` small unless more output is intentional. Text-diff selection and patch-backend selection are distinct: text tools use `PI_PLASTIC_DIFF_EXECUTABLE` or bare PATH `diff`. On macOS, bare `diff` can resolve either to GNU Diffutils or Apple’s BSD `/usr/bin/diff`; Pi uses the resolved executable and does not auto-select `gdiff`.
|
|
24
24
|
|
|
25
|
-
Use `plastic_patch` for review patch generation with `clean` and `integration` filters; it is generation-only and does not apply patches. `toolPath` is its highest-priority one-call patch-backend override, followed by `PI_PLASTIC_PATCH_EXECUTABLE`. On Windows, configure one to a verified patch-capable non-GUI executable such as Git's `diff.exe`: patch generation deliberately does not reuse `PI_PLASTIC_DIFF_EXECUTABLE`/GnuWin32. On macOS with Plastic 11, Apple BSD `/usr/bin/diff` works for text-only `plastic_diffFile` but rejects the `--binary` argument used by `cm patch`; set the patch-specific policy to a verified GNU Diffutils-compatible non-GUI executable. The non-Windows fallback to the text setting or bare `diff` is only valid when that executable accepts the local Plastic patch arguments. Unqualified `br:/...` patch selectors are qualified only from the current workspace's exact selector repository; otherwise pass `br:/<branch>@<repository>@<server>`. For a large patch, pass an intentional new `output` path: the package stages and atomically publishes it, never overwriting an existing path. Do not use `cm cat --raw`: it is unsupported for this workflow. Typed retrieval owns cleanup; the low-level byte-preserving fallback is `cm cat --file` only when a typed tool cannot represent the case. Plastic/server output may represent moves as moves or delete/add records, so inspect generated patches rather than assuming a move-aware encoding.
|
|
25
|
+
Use `plastic_patch` for review patch generation with `clean` and `integration` filters; it is generation-only and does not apply patches. `toolPath` is its highest-priority one-call patch-backend override, followed by `PI_PLASTIC_PATCH_EXECUTABLE`. On Windows, configure one to a verified patch-capable non-GUI executable such as Git's `diff.exe`: patch generation deliberately does not reuse `PI_PLASTIC_DIFF_EXECUTABLE`/GnuWin32. On macOS with Plastic 11, Apple BSD `/usr/bin/diff` works for text-only `plastic_diffFile` but rejects the `--binary` argument used by `cm patch`; set the patch-specific policy to a verified GNU Diffutils-compatible non-GUI executable. The non-Windows fallback to the text setting or bare `diff` is only valid when that executable accepts the local Plastic patch arguments. Interactive Pi sessions issue one path-redacted package capability warning per runtime for an invalid configured patch override or missing Windows setting; fix `PI_PLASTIC_PATCH_EXECUTABLE` and retry, while headless sessions retain `plastic_patch` tool-time validation. Unqualified `br:/...` patch selectors are qualified only from the current workspace's exact selector repository; otherwise pass `br:/<branch>@<repository>@<server>`. For a large patch, pass an intentional new `output` path: the package stages and atomically publishes it, never overwriting an existing path. Do not use `cm cat --raw`: it is unsupported for this workflow. Typed retrieval owns cleanup; the low-level byte-preserving fallback is `cm cat --file` only when a typed tool cannot represent the case. Plastic/server output may represent moves as moves or delete/add records, so inspect generated patches rather than assuming a move-aware encoding.
|
|
26
26
|
|
|
27
27
|
Prefer runtime `plastic_*` tools first. Keep `cm` shell commands as manual fallback.
|
|
28
28
|
|
package/src/plastic-core.ts
CHANGED
|
@@ -32,6 +32,7 @@ const getCmExecutable = (): string => resolveExecutable(process.env, "PI_PLASTIC
|
|
|
32
32
|
// Keep the executable name configurable rather than assuming a .exe suffix or package-manager path.
|
|
33
33
|
const getDiffExecutable = (): string => resolveExecutable(process.env, "PI_PLASTIC_DIFF_EXECUTABLE", "diff");
|
|
34
34
|
const PLASTIC_PATCH_EXECUTABLE_ENV = "PI_PLASTIC_PATCH_EXECUTABLE";
|
|
35
|
+
type PatchExecutableProbe = (command: string) => Promise<boolean>;
|
|
35
36
|
// Plastic's server/backend determines whether a moved item is encoded as a
|
|
36
37
|
// move or as delete/add records. Do not claim either without a live fixture.
|
|
37
38
|
const PATCH_MOVE_REPRESENTATION = "backend-determined" as const;
|
|
@@ -1228,6 +1229,49 @@ const assertNonBlankPatchValue = (name: keyof PatchCommandArgs, value: string |
|
|
|
1228
1229
|
}
|
|
1229
1230
|
};
|
|
1230
1231
|
|
|
1232
|
+
const probePatchExecutable = async (command: string): Promise<boolean> =>
|
|
1233
|
+
{
|
|
1234
|
+
try
|
|
1235
|
+
{
|
|
1236
|
+
// This establishes only that the configured executable can launch.
|
|
1237
|
+
// `cm patch` remains the authoritative verifier for its --binary contract.
|
|
1238
|
+
const result = await spawnAndCollect(command, ["--version"], process.cwd(), undefined, AbortSignal.timeout(3000), {
|
|
1239
|
+
abortKillDelayMs: 100,
|
|
1240
|
+
outputLimitChars: 1024,
|
|
1241
|
+
});
|
|
1242
|
+
return !result.aborted;
|
|
1243
|
+
}
|
|
1244
|
+
catch
|
|
1245
|
+
{
|
|
1246
|
+
return false;
|
|
1247
|
+
}
|
|
1248
|
+
};
|
|
1249
|
+
|
|
1250
|
+
export const getPatchBackendCapabilityWarning = async (
|
|
1251
|
+
environment: ExecutableEnvironment = process.env,
|
|
1252
|
+
platform: NodeJS.Platform = process.platform,
|
|
1253
|
+
probe: PatchExecutableProbe = probePatchExecutable,
|
|
1254
|
+
): Promise<string | undefined> =>
|
|
1255
|
+
{
|
|
1256
|
+
const configuredPatchExecutable = environment[PLASTIC_PATCH_EXECUTABLE_ENV]?.trim();
|
|
1257
|
+
if (configuredPatchExecutable)
|
|
1258
|
+
{
|
|
1259
|
+
if (await probe(configuredPatchExecutable))
|
|
1260
|
+
{
|
|
1261
|
+
return undefined;
|
|
1262
|
+
}
|
|
1263
|
+
|
|
1264
|
+
return "Pi Plastic capability warning: the configured PI_PLASTIC_PATCH_EXECUTABLE could not be launched. Set it to a verified patch-capable non-GUI diff executable, or remove the override to use this platform's documented fallback. The configured path is not shown for privacy.";
|
|
1265
|
+
}
|
|
1266
|
+
|
|
1267
|
+
if (platform === "win32")
|
|
1268
|
+
{
|
|
1269
|
+
return "Pi Plastic capability warning: plastic_patch requires PI_PLASTIC_PATCH_EXECUTABLE on Windows. Set it to a verified patch-capable non-GUI diff executable (for example Git's diff.exe). PI_PLASTIC_DIFF_EXECUTABLE is only for text diffs.";
|
|
1270
|
+
}
|
|
1271
|
+
|
|
1272
|
+
return undefined;
|
|
1273
|
+
};
|
|
1274
|
+
|
|
1231
1275
|
const resolvePatchToolPath = (
|
|
1232
1276
|
toolPath?: string,
|
|
1233
1277
|
environment: ExecutableEnvironment = process.env,
|
|
@@ -1491,6 +1535,7 @@ export const __plasticProcessInternals = {
|
|
|
1491
1535
|
export const __plasticPatchInternals = {
|
|
1492
1536
|
buildPatchCommandArgs,
|
|
1493
1537
|
resolvePatchToolPath,
|
|
1538
|
+
getPatchBackendCapabilityWarning,
|
|
1494
1539
|
qualifyPatchBranchSpec,
|
|
1495
1540
|
resolvePatchBranchSpecs,
|
|
1496
1541
|
createPatchOutputStaging,
|
package/SECURITY.md
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
# Security Policy
|
|
2
|
-
|
|
3
|
-
## Supported versions
|
|
4
|
-
|
|
5
|
-
Security fixes are provided for the latest tagged release. Upgrade to the newest release before reporting an issue that may already be fixed.
|
|
6
|
-
|
|
7
|
-
## Reporting a vulnerability
|
|
8
|
-
|
|
9
|
-
Do not open a public issue for a suspected vulnerability, credential exposure, or unsafe command-execution path.
|
|
10
|
-
|
|
11
|
-
Use GitHub's private vulnerability reporting for this repository:
|
|
12
|
-
|
|
13
|
-
<https://github.com/aefreedman/pi-plastic/security/advisories/new>
|
|
14
|
-
|
|
15
|
-
Include:
|
|
16
|
-
|
|
17
|
-
- the affected package version or commit;
|
|
18
|
-
- the Pi, Node.js, Git, and Plastic CLI versions;
|
|
19
|
-
- the operating system;
|
|
20
|
-
- reproduction steps and expected versus observed behavior;
|
|
21
|
-
- the affected tool or extension;
|
|
22
|
-
- impact and any known mitigations;
|
|
23
|
-
- whether credentials, repository content, or remote Plastic objects may have been exposed or changed.
|
|
24
|
-
|
|
25
|
-
Avoid including real credentials or sensitive repository content. Use a disposable Plastic workspace when a reproduction requires mutation.
|
|
26
|
-
|
|
27
|
-
You should receive an acknowledgement within seven days. Release timing depends on severity, reproducibility, and coordination needs.
|
|
28
|
-
|
|
29
|
-
## Scope
|
|
30
|
-
|
|
31
|
-
Security-sensitive areas include command construction, executable-path overrides, workspace/path targeting, destructive Plastic operations, provider payload capture, dynamic tool ownership, and package-install behavior. General support questions and ordinary bugs belong in the public issue tracker.
|