@aefree/pi-plastic 0.4.0

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 (61) hide show
  1. package/CHANGELOG.md +109 -0
  2. package/CONTRIBUTING.md +88 -0
  3. package/LICENSE +21 -0
  4. package/README.md +181 -0
  5. package/SECURITY.md +31 -0
  6. package/evals/tool-loading/README.md +38 -0
  7. package/evals/tool-loading/RESULTS.md +57 -0
  8. package/evals/tool-loading/baseline.json +34 -0
  9. package/evals/tool-loading/cases.json +70 -0
  10. package/evals/tool-loading/config.json +19 -0
  11. package/evals/tool-loading/mutation-guard.ts +30 -0
  12. package/evals/tool-loading/provider-capture.ts +22 -0
  13. package/evals/tool-loading/results/.gitignore +3 -0
  14. package/evals/tool-loading/run-eval.ts +372 -0
  15. package/extensions/bash-cm-diff-guard.ts +49 -0
  16. package/extensions/bash-cm-merge-guard.ts +53 -0
  17. package/extensions/plastic-branch-status.ts +285 -0
  18. package/extensions/repository-search-provider.ts +66 -0
  19. package/extensions/shared/bash-command-guards.ts +67 -0
  20. package/index.ts +777 -0
  21. package/package.json +76 -0
  22. package/skills/_shared/references/conventional-commits.md +198 -0
  23. package/skills/using-plastic/SKILL.md +50 -0
  24. package/skills/using-plastic/references/branch-management.md +78 -0
  25. package/skills/using-plastic/references/changeset-operations.md +96 -0
  26. package/skills/using-plastic/references/code-review-creation.md +30 -0
  27. package/skills/using-plastic/references/integration.md +47 -0
  28. package/skills/using-plastic/references/quick-reference.md +32 -0
  29. package/skills/using-plastic/references/resources.md +7 -0
  30. package/skills/using-plastic/references/reviewing-changes.md +71 -0
  31. package/skills/using-plastic/references/shelving.md +25 -0
  32. package/skills/using-plastic/references/troubleshooting.md +115 -0
  33. package/skills/using-plastic/references/workspaces.md +33 -0
  34. package/src/pi-tool-compat.ts +56 -0
  35. package/src/plastic-core.ts +4204 -0
  36. package/src/plastic-tool-loading.ts +234 -0
  37. package/src/plastic-workspace.ts +176 -0
  38. package/src/repository-search-provider.ts +64 -0
  39. package/tests/bash-cm-diff-guard-validation.ts +55 -0
  40. package/tests/fixtures/plastic.selector +3 -0
  41. package/tests/fixtures/status-compact.txt +1 -0
  42. package/tests/fixtures/status-normal.txt +1 -0
  43. package/tests/packed-copy-owner-conflict.test.ts +28 -0
  44. package/tests/pi-tool-harness.ts +116 -0
  45. package/tests/plastic-branch-create-live.test.ts +78 -0
  46. package/tests/plastic-branch-query.test.ts +26 -0
  47. package/tests/plastic-branch-status.test.ts +241 -0
  48. package/tests/plastic-checkin-path-resolution.ts +219 -0
  49. package/tests/plastic-constrained-sampling.test.ts +77 -0
  50. package/tests/plastic-diff-workflow.test.ts +86 -0
  51. package/tests/plastic-dynamic-tool-loading.test.ts +224 -0
  52. package/tests/plastic-extension-registration.test.ts +34 -0
  53. package/tests/plastic-live-smoke.test.ts +37 -0
  54. package/tests/plastic-mutation-execution.test.ts +61 -0
  55. package/tests/plastic-patch-command.test.ts +118 -0
  56. package/tests/plastic-process-lifecycle.test.ts +148 -0
  57. package/tests/plastic-tool-rendering.test.ts +16 -0
  58. package/tests/plastic-tool-validation.ts +153 -0
  59. package/tests/plastic-workspace.test.ts +62 -0
  60. package/tests/repository-search-provider-registration.test.ts +37 -0
  61. package/tests/repository-search-provider.test.ts +27 -0
@@ -0,0 +1,37 @@
1
+ import assert from "node:assert/strict";
2
+ import { createPlasticRepositoryProviderExtension, isMissingRepoSearchRuntime } from "../extensions/repository-search-provider.ts";
3
+
4
+ const records = new WeakMap<object, Map<string, { token: { id: string; nonce: string }; policy: { id: string } }>>();
5
+ let nonce = 0;
6
+ const registry = {
7
+ register(scope: object, policy: { id: string }) {
8
+ const scoped = records.get(scope) ?? new Map();
9
+ if (scoped.has(policy.id)) throw new Error(`duplicate ${policy.id}`);
10
+ const token = { id: policy.id, nonce: String(++nonce) };
11
+ scoped.set(policy.id, { token, policy }); records.set(scope, scoped); return token;
12
+ },
13
+ unregister(token: { id: string; nonce: string }) {
14
+ for (const scoped of [records.get(scope)]) {
15
+ const current = scoped?.get(token.id);
16
+ if (current?.token.nonce === token.nonce) return scoped!.delete(token.id);
17
+ }
18
+ return false;
19
+ },
20
+ };
21
+ const runtime = { createRepositoryPolicyRegistryV1: () => registry };
22
+ const handlers = new Map<string, Array<(_event: unknown, ctx: any) => Promise<void> | void>>();
23
+ const pi = { on(event: string, handler: (_event: unknown, ctx: any) => Promise<void> | void) { handlers.set(event, [...(handlers.get(event) ?? []), handler]); } };
24
+ createPlasticRepositoryProviderExtension(async () => runtime as any)(pi as any);
25
+ const scope = {}; const ctx = { sessionManager: scope };
26
+ for (const handler of handlers.get("session_start") ?? []) await handler({}, ctx);
27
+ assert.deepEqual([...records.get(scope)!.keys()], ["plastic.ignore-files"]);
28
+ for (const handler of handlers.get("session_shutdown") ?? []) await handler({}, ctx);
29
+ assert.equal(records.get(scope)?.size ?? 0, 0);
30
+
31
+ const absentHandlers = new Map<string, Array<(_event: unknown, ctx: any) => Promise<void> | void>>();
32
+ createPlasticRepositoryProviderExtension(async () => { throw Object.assign(new Error("Cannot find package '@aefree/pi-repo-search'"), { code: "ERR_MODULE_NOT_FOUND" }); })({ on(event: string, handler: any) { absentHandlers.set(event, [...(absentHandlers.get(event) ?? []), handler]); } } as any);
33
+ for (const handler of absentHandlers.get("session_start") ?? []) await handler({}, ctx);
34
+ assert.equal(records.get(scope)?.size ?? 0, 0, "an absent optional package must leave pi-plastic usable without registration");
35
+ assert.equal(isMissingRepoSearchRuntime({ code: "ERR_MODULE_NOT_FOUND", message: "Cannot find package '@aefree/pi-repo-search'" }), true);
36
+ assert.equal(isMissingRepoSearchRuntime({ code: "ERR_MODULE_NOT_FOUND", message: "Cannot find package 'nested-defect'" }), false);
37
+ console.log("PASS: optional Plastic repository-search policy registration");
@@ -0,0 +1,27 @@
1
+ import assert from "node:assert/strict";
2
+ import { mkdtemp, mkdir, realpath, rm, writeFile } from "node:fs/promises";
3
+ import { join } from "node:path";
4
+ import { tmpdir } from "node:os";
5
+ import { createPlasticRepositorySearchPolicyV1, loadPlasticOwnerV1 } from "../src/repository-search-provider.ts";
6
+
7
+ const root = await mkdtemp(join(tmpdir(), "pi-plastic-repo-policy-"));
8
+ try {
9
+ const plastic = join(root, "plastic"); const source = join(plastic, "Assets", "Code"); const gitOnly = join(root, "git-only");
10
+ await mkdir(join(plastic, ".plastic"), { recursive: true }); await writeFile(join(plastic, ".plastic", "plastic.workspace"), "fixture");
11
+ await mkdir(source, { recursive: true }); await writeFile(join(plastic, "ignore.conf"), "ignored.txt\n"); await writeFile(join(plastic, "Assets", "cloaked.conf"), "cache/**\n");
12
+ await mkdir(join(gitOnly, ".git"), { recursive: true });
13
+ const owner = await loadPlasticOwnerV1(new URL("../extensions/repository-search-provider.ts", import.meta.url).href);
14
+ assert.equal(owner.packageVersion, "0.4.0");
15
+ assert.equal(owner.packageRoot, await realpath(join(import.meta.dirname, "..")));
16
+ const policy = createPlasticRepositorySearchPolicyV1(owner);
17
+ const result = await policy.evaluate({ cwd: root, signal: new AbortController().signal }, { workspaceRoot: root, roots: [source], includeHidden: false, signal: new AbortController().signal });
18
+ assert.equal(result.outcome, "applied");
19
+ if (result.outcome === "applied") {
20
+ assert.equal(result.roots[0]?.policyOwnedRoot, plastic);
21
+ assert.deepEqual(result.roots[0]?.ignoreFiles.map((file) => file.slice(plastic.length + 1).replaceAll("\\", "/")), ["ignore.conf", "Assets/cloaked.conf"]);
22
+ }
23
+
24
+ const nonApplicable = await policy.evaluate({ cwd: root, signal: new AbortController().signal }, { workspaceRoot: root, roots: [gitOnly], includeHidden: false, signal: new AbortController().signal });
25
+ assert.equal(nonApplicable.outcome, "not_applicable");
26
+ } finally { await rm(root, { recursive: true, force: true }); }
27
+ console.log("PASS: Plastic repository-search policy");