@mhingston5/lasso 0.1.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 (124) hide show
  1. package/README.md +707 -0
  2. package/docs/agent-wrangling.png +0 -0
  3. package/package.json +26 -0
  4. package/src/capabilities/matcher.ts +25 -0
  5. package/src/capabilities/registry.ts +103 -0
  6. package/src/capabilities/types.ts +15 -0
  7. package/src/cir/lower.ts +253 -0
  8. package/src/cir/optimize.ts +251 -0
  9. package/src/cir/types.ts +131 -0
  10. package/src/cir/validate.ts +265 -0
  11. package/src/compiler/compile.ts +601 -0
  12. package/src/compiler/feedback.ts +471 -0
  13. package/src/compiler/runtime-helpers.ts +455 -0
  14. package/src/composition/chain.ts +58 -0
  15. package/src/composition/conditional.ts +76 -0
  16. package/src/composition/parallel.ts +75 -0
  17. package/src/composition/types.ts +105 -0
  18. package/src/environment/analyzer.ts +56 -0
  19. package/src/environment/discovery.ts +179 -0
  20. package/src/environment/types.ts +68 -0
  21. package/src/failures/classifiers.ts +134 -0
  22. package/src/failures/generator.ts +421 -0
  23. package/src/failures/map-reference-failures.ts +23 -0
  24. package/src/failures/ontology.ts +210 -0
  25. package/src/failures/recovery.ts +214 -0
  26. package/src/failures/types.ts +14 -0
  27. package/src/index.ts +67 -0
  28. package/src/memory/advisor.ts +132 -0
  29. package/src/memory/extractor.ts +166 -0
  30. package/src/memory/store.ts +107 -0
  31. package/src/memory/types.ts +53 -0
  32. package/src/metaharness/engine.ts +256 -0
  33. package/src/metaharness/predictor.ts +168 -0
  34. package/src/metaharness/types.ts +40 -0
  35. package/src/mutation/derive.ts +308 -0
  36. package/src/mutation/diff.ts +52 -0
  37. package/src/mutation/engine.ts +256 -0
  38. package/src/mutation/types.ts +84 -0
  39. package/src/pi/command-input.ts +209 -0
  40. package/src/pi/commands.ts +351 -0
  41. package/src/pi/extension.ts +16 -0
  42. package/src/planner/synthesize.ts +83 -0
  43. package/src/planner/template-rules.ts +183 -0
  44. package/src/planner/types.ts +42 -0
  45. package/src/reference/catalog.ts +128 -0
  46. package/src/reference/patch-validation-strategies.ts +170 -0
  47. package/src/reference/patch-validation.ts +174 -0
  48. package/src/reference/pr-review-merge.ts +155 -0
  49. package/src/reference/strategies.ts +126 -0
  50. package/src/reference/types.ts +33 -0
  51. package/src/replanner/risk-rules.ts +161 -0
  52. package/src/replanner/runtime.ts +308 -0
  53. package/src/replanner/synthesize.ts +619 -0
  54. package/src/replanner/types.ts +73 -0
  55. package/src/spec/schema.ts +254 -0
  56. package/src/spec/types.ts +319 -0
  57. package/src/spec/validate.ts +296 -0
  58. package/src/state/snapshots.ts +43 -0
  59. package/src/state/types.ts +12 -0
  60. package/src/synthesis/graph-builder.ts +267 -0
  61. package/src/synthesis/harness-builder.ts +113 -0
  62. package/src/synthesis/intent-ir.ts +63 -0
  63. package/src/synthesis/policy-builder.ts +320 -0
  64. package/src/synthesis/risk-analyzer.ts +182 -0
  65. package/src/synthesis/skill-parser.ts +441 -0
  66. package/src/verification/engine.ts +230 -0
  67. package/src/versioning/file-store.ts +103 -0
  68. package/src/versioning/history.ts +43 -0
  69. package/src/versioning/store.ts +16 -0
  70. package/src/versioning/types.ts +31 -0
  71. package/test/capabilities/matcher.test.ts +67 -0
  72. package/test/capabilities/registry.test.ts +136 -0
  73. package/test/capabilities/synthesis.test.ts +264 -0
  74. package/test/cir/lower.test.ts +417 -0
  75. package/test/cir/optimize.test.ts +266 -0
  76. package/test/cir/validate.test.ts +368 -0
  77. package/test/compiler/adaptive-runtime.test.ts +157 -0
  78. package/test/compiler/compile.test.ts +1198 -0
  79. package/test/compiler/feedback.test.ts +784 -0
  80. package/test/compiler/guardrails.test.ts +191 -0
  81. package/test/compiler/trace.test.ts +404 -0
  82. package/test/composition/chain.test.ts +328 -0
  83. package/test/composition/conditional.test.ts +241 -0
  84. package/test/composition/parallel.test.ts +215 -0
  85. package/test/environment/analyzer.test.ts +204 -0
  86. package/test/environment/discovery.test.ts +149 -0
  87. package/test/failures/classifiers.test.ts +287 -0
  88. package/test/failures/generator.test.ts +203 -0
  89. package/test/failures/ontology.test.ts +439 -0
  90. package/test/failures/recovery.test.ts +300 -0
  91. package/test/helpers/createFixtureRepo.ts +84 -0
  92. package/test/helpers/createPatchValidationFixture.ts +144 -0
  93. package/test/helpers/runCompiledWorkflow.ts +208 -0
  94. package/test/memory/advisor.test.ts +332 -0
  95. package/test/memory/extractor.test.ts +295 -0
  96. package/test/memory/store.test.ts +244 -0
  97. package/test/metaharness/engine.test.ts +575 -0
  98. package/test/metaharness/predictor.test.ts +436 -0
  99. package/test/mutation/derive-failure.test.ts +209 -0
  100. package/test/mutation/engine.test.ts +622 -0
  101. package/test/package-smoke.test.ts +29 -0
  102. package/test/pi/command-input.test.ts +153 -0
  103. package/test/pi/commands.test.ts +623 -0
  104. package/test/planner/classify-template.test.ts +32 -0
  105. package/test/planner/synthesize.test.ts +901 -0
  106. package/test/reference/PatchValidation.failures.test.ts +137 -0
  107. package/test/reference/PatchValidation.test.ts +326 -0
  108. package/test/reference/PrReviewMerge.failures.test.ts +121 -0
  109. package/test/reference/PrReviewMerge.test.ts +55 -0
  110. package/test/reference/catalog-open.test.ts +70 -0
  111. package/test/replanner/runtime.test.ts +207 -0
  112. package/test/replanner/synthesize.test.ts +303 -0
  113. package/test/spec/validate.test.ts +1056 -0
  114. package/test/state/snapshots.test.ts +264 -0
  115. package/test/synthesis/custom-workflow.test.ts +264 -0
  116. package/test/synthesis/graph-builder.test.ts +370 -0
  117. package/test/synthesis/harness-builder.test.ts +128 -0
  118. package/test/synthesis/policy-builder.test.ts +149 -0
  119. package/test/synthesis/risk-analyzer.test.ts +230 -0
  120. package/test/synthesis/skill-parser.test.ts +796 -0
  121. package/test/verification/engine.test.ts +509 -0
  122. package/test/versioning/history.test.ts +144 -0
  123. package/test/versioning/store.test.ts +254 -0
  124. package/vitest.config.ts +9 -0
@@ -0,0 +1,153 @@
1
+ import { afterEach, describe, expect, it } from "vitest";
2
+ import { mkdtemp, rm, writeFile } from "node:fs/promises";
3
+ import { tmpdir } from "node:os";
4
+ import { join } from "node:path";
5
+ import { parseCommandTarget } from "../../src/pi/command-input.js";
6
+
7
+ const tempDirs: string[] = [];
8
+
9
+ const patchRequest = {
10
+ workflow: "patch-validation" as const,
11
+ input: {
12
+ repoPath: "/tmp/repo",
13
+ baselineRef: "main",
14
+ candidateSource: { kind: "patchFile" as const, value: "/tmp/fix.patch" },
15
+ reproduceCommands: ["npm test -- --grep broken"],
16
+ verificationCommands: ["npm test"],
17
+ reviewInstructions: "Approve if the patch applies cleanly and verification passes.",
18
+ approvalRequired: false,
19
+ },
20
+ };
21
+
22
+ const customSpec = {
23
+ name: "custom-echo",
24
+ graph: {
25
+ entryNodeId: "echo",
26
+ nodes: [
27
+ {
28
+ id: "echo",
29
+ kind: "tool" as const,
30
+ tool: "bash",
31
+ args: ["-lc", "echo hello"],
32
+ },
33
+ ],
34
+ edges: [],
35
+ },
36
+ };
37
+
38
+ describe("parseCommandTarget", () => {
39
+ afterEach(async () => {
40
+ while (tempDirs.length > 0) {
41
+ const dir = tempDirs.pop();
42
+ if (dir) {
43
+ await rm(dir, { recursive: true, force: true });
44
+ }
45
+ }
46
+ });
47
+
48
+ it("parses a bundled workflow request as a reference target", async () => {
49
+ const target = await parseCommandTarget(JSON.stringify(patchRequest), "compile");
50
+
51
+ expect(target).toEqual({
52
+ kind: "reference",
53
+ request: patchRequest,
54
+ runtimeInput: {},
55
+ });
56
+ });
57
+
58
+ it("parses raw HarnessSpec JSON as a custom target with empty runtime input", async () => {
59
+ const target = await parseCommandTarget(JSON.stringify(customSpec), "compile");
60
+
61
+ expect(target).toEqual({
62
+ kind: "custom",
63
+ spec: customSpec,
64
+ runtimeInput: {},
65
+ });
66
+ });
67
+
68
+ it("parses a generic envelope with embedded spec and explicit runtime input", async () => {
69
+ const runtimeInput = { ticket: 42, dryRun: true };
70
+ const target = await parseCommandTarget(JSON.stringify({ spec: customSpec, input: runtimeInput }), "run");
71
+
72
+ expect(target).toEqual({
73
+ kind: "custom",
74
+ spec: customSpec,
75
+ runtimeInput,
76
+ });
77
+ });
78
+
79
+ it("loads a custom spec from specPath with explicit runtime input", async () => {
80
+ const specPath = await createSpecFile(JSON.stringify(customSpec, null, 2));
81
+ const runtimeInput = { branch: "feature/test" };
82
+
83
+ const target = await parseCommandTarget(JSON.stringify({ specPath, input: runtimeInput }), "run");
84
+
85
+ expect(target).toEqual({
86
+ kind: "custom",
87
+ spec: customSpec,
88
+ runtimeInput,
89
+ });
90
+ });
91
+
92
+ it("loads a direct absolute-path shorthand with empty runtime input", async () => {
93
+ const specPath = await createSpecFile(JSON.stringify(customSpec, null, 2));
94
+
95
+ const target = await parseCommandTarget(specPath, "run");
96
+
97
+ expect(target).toEqual({
98
+ kind: "custom",
99
+ spec: customSpec,
100
+ runtimeInput: {},
101
+ });
102
+ });
103
+
104
+ it("treats Windows-style absolute paths as file paths before JSON parsing", async () => {
105
+ await expect(parseCommandTarget("path:C:\\temp\\spec.json", "compile")).rejects.toThrow(
106
+ "Spec file not found: C:\\temp\\spec.json",
107
+ );
108
+
109
+ await expect(parseCommandTarget("C:\\temp\\spec.json", "compile")).rejects.toThrow(
110
+ "Spec file not found: C:\\temp\\spec.json",
111
+ );
112
+ });
113
+
114
+ it("rejects relative spec paths clearly", async () => {
115
+ await expect(parseCommandTarget("path:spec.json", "compile")).rejects.toThrow(
116
+ "Spec path must be an absolute path",
117
+ );
118
+
119
+ await expect(parseCommandTarget("spec.json", "compile")).rejects.toThrow(
120
+ "Spec path must be an absolute path",
121
+ );
122
+ });
123
+
124
+ it("rejects generic envelopes that contain both spec and specPath", async () => {
125
+ const specPath = await createSpecFile(JSON.stringify(customSpec, null, 2));
126
+
127
+ await expect(parseCommandTarget(JSON.stringify({ spec: customSpec, specPath }), "compile")).rejects.toThrow(
128
+ "Generic harness request must include exactly one of `spec` or `specPath`",
129
+ );
130
+ });
131
+
132
+ it("rejects string spec values and points operators to specPath", async () => {
133
+ await expect(parseCommandTarget(JSON.stringify({ spec: "/tmp/spec.json" }), "run")).rejects.toThrow(
134
+ "Generic harness request uses `specPath` for file paths, not `spec`",
135
+ );
136
+ });
137
+
138
+ it("rejects invalid JSON in a spec file with a file-specific error", async () => {
139
+ const specPath = await createSpecFile("{not-json");
140
+
141
+ await expect(parseCommandTarget(specPath, "compile")).rejects.toThrow(
142
+ `Spec file must contain valid JSON: ${specPath}`,
143
+ );
144
+ });
145
+ });
146
+
147
+ async function createSpecFile(contents: string): Promise<string> {
148
+ const dir = await mkdtemp(join(tmpdir(), "lasso-spec-"));
149
+ tempDirs.push(dir);
150
+ const specPath = join(dir, "custom-spec.json");
151
+ await writeFile(specPath, contents, "utf8");
152
+ return specPath;
153
+ }