@pedyc/harness-core 1.1.1 → 1.2.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 (103) hide show
  1. package/README.md +34 -0
  2. package/dist/config/agents.d.ts +14 -0
  3. package/dist/config/agents.d.ts.map +1 -0
  4. package/dist/config/agents.js +39 -0
  5. package/dist/config/agents.js.map +1 -0
  6. package/dist/config/bundled.d.ts +14 -0
  7. package/dist/config/bundled.d.ts.map +1 -0
  8. package/dist/config/bundled.js +38 -0
  9. package/dist/config/bundled.js.map +1 -0
  10. package/dist/config/defaults.d.ts +19 -0
  11. package/dist/config/defaults.d.ts.map +1 -0
  12. package/dist/config/defaults.js +32 -0
  13. package/dist/config/defaults.js.map +1 -0
  14. package/dist/config/errors.d.ts +12 -0
  15. package/dist/config/errors.d.ts.map +1 -0
  16. package/dist/config/errors.js +11 -0
  17. package/dist/config/errors.js.map +1 -0
  18. package/dist/config/index.d.ts +15 -0
  19. package/dist/config/index.d.ts.map +1 -0
  20. package/dist/config/index.js +18 -0
  21. package/dist/config/index.js.map +1 -0
  22. package/dist/config/json.d.ts +14 -0
  23. package/dist/config/json.d.ts.map +1 -0
  24. package/dist/config/json.js +5 -0
  25. package/dist/config/json.js.map +1 -0
  26. package/dist/config/loader.d.ts +16 -0
  27. package/dist/config/loader.d.ts.map +1 -0
  28. package/dist/config/loader.js +221 -0
  29. package/dist/config/loader.js.map +1 -0
  30. package/dist/config/manifest.d.ts +22 -0
  31. package/dist/config/manifest.d.ts.map +1 -0
  32. package/dist/config/manifest.js +56 -0
  33. package/dist/config/manifest.js.map +1 -0
  34. package/dist/config/policy.d.ts +14 -0
  35. package/dist/config/policy.d.ts.map +1 -0
  36. package/dist/config/policy.js +35 -0
  37. package/dist/config/policy.js.map +1 -0
  38. package/dist/config/presets.d.ts +35 -0
  39. package/dist/config/presets.d.ts.map +1 -0
  40. package/dist/config/presets.js +187 -0
  41. package/dist/config/presets.js.map +1 -0
  42. package/dist/config/schema.d.ts +16 -0
  43. package/dist/config/schema.d.ts.map +1 -0
  44. package/dist/config/schema.js +24 -0
  45. package/dist/config/schema.js.map +1 -0
  46. package/dist/contracts/harness.d.ts +86 -0
  47. package/dist/contracts/harness.d.ts.map +1 -0
  48. package/dist/contracts/harness.js +2 -0
  49. package/dist/contracts/harness.js.map +1 -0
  50. package/dist/contracts/index.d.ts +3 -1
  51. package/dist/contracts/index.d.ts.map +1 -1
  52. package/dist/contracts/preset.d.ts +54 -20
  53. package/dist/contracts/preset.d.ts.map +1 -1
  54. package/dist/contracts/validator.d.ts +33 -0
  55. package/dist/contracts/validator.d.ts.map +1 -0
  56. package/dist/contracts/validator.js +23 -0
  57. package/dist/contracts/validator.js.map +1 -0
  58. package/dist/core/diff-inspector.d.ts.map +1 -1
  59. package/dist/core/diff-inspector.js +3 -6
  60. package/dist/core/diff-inspector.js.map +1 -1
  61. package/dist/index.d.ts +18 -17
  62. package/dist/index.d.ts.map +1 -1
  63. package/dist/index.js +10 -10
  64. package/dist/index.js.map +1 -1
  65. package/dist/runtime/agent.d.ts +22 -0
  66. package/dist/runtime/agent.d.ts.map +1 -0
  67. package/dist/runtime/agent.js +47 -0
  68. package/dist/runtime/agent.js.map +1 -0
  69. package/dist/runtime/approval-gate.d.ts +17 -0
  70. package/dist/runtime/approval-gate.d.ts.map +1 -0
  71. package/dist/runtime/approval-gate.js +18 -0
  72. package/dist/runtime/approval-gate.js.map +1 -0
  73. package/dist/runtime/command.d.ts +14 -0
  74. package/dist/runtime/command.d.ts.map +1 -0
  75. package/dist/runtime/command.js +33 -0
  76. package/dist/runtime/command.js.map +1 -0
  77. package/dist/runtime/diff-inspector.d.ts +7 -0
  78. package/dist/runtime/diff-inspector.d.ts.map +1 -0
  79. package/dist/runtime/diff-inspector.js +24 -0
  80. package/dist/runtime/diff-inspector.js.map +1 -0
  81. package/dist/runtime/executor.d.ts +21 -0
  82. package/dist/runtime/executor.d.ts.map +1 -0
  83. package/dist/runtime/executor.js +142 -0
  84. package/dist/runtime/executor.js.map +1 -0
  85. package/dist/runtime/intake.d.ts +11 -0
  86. package/dist/runtime/intake.d.ts.map +1 -0
  87. package/dist/runtime/intake.js +33 -0
  88. package/dist/runtime/intake.js.map +1 -0
  89. package/dist/runtime/package-manager.d.ts +14 -0
  90. package/dist/runtime/package-manager.d.ts.map +1 -0
  91. package/dist/runtime/package-manager.js +20 -0
  92. package/dist/runtime/package-manager.js.map +1 -0
  93. package/dist/runtime/policy-engine.d.ts +7 -0
  94. package/dist/runtime/policy-engine.d.ts.map +1 -0
  95. package/dist/runtime/policy-engine.js +8 -0
  96. package/dist/runtime/policy-engine.js.map +1 -0
  97. package/dist/runtime/provider-runner.d.ts +18 -0
  98. package/dist/runtime/provider-runner.d.ts.map +1 -0
  99. package/dist/runtime/provider-runner.js +45 -0
  100. package/dist/runtime/provider-runner.js.map +1 -0
  101. package/package.json +24 -19
  102. package/schemas/harness.schema.json +41 -0
  103. package/schemas/preset.schema.json +62 -0
@@ -0,0 +1,22 @@
1
+ import type { HarnessConfigError, HarnessManifest } from '../contracts/index.js';
2
+ /** The repository-relative path of a project's manifest. */
3
+ export declare const manifestFile = ".harness/harness.json";
4
+ export declare const manifestPath: (root: string) => string;
5
+ /** The bundled schema a project manifest is validated against. */
6
+ export declare const manifestSchema = "harness.schema.json";
7
+ export type ManifestResult = {
8
+ ok: true;
9
+ manifest: HarnessManifest;
10
+ } | {
11
+ ok: false;
12
+ errors: HarnessConfigError[];
13
+ };
14
+ /**
15
+ * Reads and validates `.harness/harness.json`.
16
+ *
17
+ * Every failure is structured: a caller gets the document, the field and a
18
+ * stable code, which is what lets the CLI fail before execution with a message
19
+ * a human can act on.
20
+ */
21
+ export declare const readManifest: (root: string) => ManifestResult;
22
+ //# sourceMappingURL=manifest.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../../src/config/manifest.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAA;AAEhF,4DAA4D;AAC5D,eAAO,MAAM,YAAY,0BAA0B,CAAA;AAEnD,eAAO,MAAM,YAAY,GAAI,MAAM,MAAM,KAAG,MAAkC,CAAA;AAE9E,kEAAkE;AAClE,eAAO,MAAM,cAAc,wBAAwB,CAAA;AAEnD,MAAM,MAAM,cAAc,GACtB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,EAAE,eAAe,CAAA;CAAE,GACvC;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,kBAAkB,EAAE,CAAA;CAAE,CAAA;AAE/C;;;;;;GAMG;AACH,eAAO,MAAM,YAAY,GAAI,MAAM,MAAM,KAAG,cA4C3C,CAAA"}
@@ -0,0 +1,56 @@
1
+ import { readFileSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ import { bundledSchemaFile, bundledValidator, fieldOf } from './bundled.js';
4
+ import { configError } from './errors.js';
5
+ /** The repository-relative path of a project's manifest. */
6
+ export const manifestFile = '.harness/harness.json';
7
+ export const manifestPath = (root) => join(root, manifestFile);
8
+ /** The bundled schema a project manifest is validated against. */
9
+ export const manifestSchema = 'harness.schema.json';
10
+ /**
11
+ * Reads and validates `.harness/harness.json`.
12
+ *
13
+ * Every failure is structured: a caller gets the document, the field and a
14
+ * stable code, which is what lets the CLI fail before execution with a message
15
+ * a human can act on.
16
+ */
17
+ export const readManifest = (root) => {
18
+ let raw;
19
+ try {
20
+ raw = readFileSync(manifestPath(root), 'utf8');
21
+ }
22
+ catch (error) {
23
+ return {
24
+ ok: false,
25
+ errors: [configError('manifest_unreadable', manifestFile, `The manifest could not be read: ${error instanceof Error ? error.message : 'unknown error'}`)],
26
+ };
27
+ }
28
+ let document;
29
+ try {
30
+ document = JSON.parse(raw);
31
+ }
32
+ catch (error) {
33
+ return {
34
+ ok: false,
35
+ errors: [configError('manifest_invalid_json', manifestFile, `The manifest is not valid JSON: ${error instanceof Error ? error.message : 'unknown error'}`)],
36
+ };
37
+ }
38
+ let validate;
39
+ try {
40
+ validate = bundledValidator(manifestSchema);
41
+ }
42
+ catch (error) {
43
+ return {
44
+ ok: false,
45
+ errors: [configError('harness_schema_unreadable', bundledSchemaFile(manifestSchema), `The bundled manifest schema could not be loaded, so the installation is incomplete: ${error instanceof Error ? error.message : 'unknown error'}`)],
46
+ };
47
+ }
48
+ if (!validate(document)) {
49
+ return {
50
+ ok: false,
51
+ errors: (validate.errors ?? []).map((error) => configError('manifest_invalid', manifestFile, error.message ?? 'is invalid', fieldOf(error))),
52
+ };
53
+ }
54
+ return { ok: true, manifest: document };
55
+ };
56
+ //# sourceMappingURL=manifest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manifest.js","sourceRoot":"","sources":["../../src/config/manifest.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AACtC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAChC,OAAO,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAC3E,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAGzC,4DAA4D;AAC5D,MAAM,CAAC,MAAM,YAAY,GAAG,uBAAuB,CAAA;AAEnD,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,IAAY,EAAU,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,YAAY,CAAC,CAAA;AAE9E,kEAAkE;AAClE,MAAM,CAAC,MAAM,cAAc,GAAG,qBAAqB,CAAA;AAMnD;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,IAAY,EAAkB,EAAE;IAC3D,IAAI,GAAW,CAAA;IACf,IAAI,CAAC;QACH,GAAG,GAAG,YAAY,CAAC,YAAY,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,CAAA;IAChD,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO;YACL,EAAE,EAAE,KAAK;YACT,MAAM,EAAE,CAAC,WAAW,CAAC,qBAAqB,EAAE,YAAY,EAAE,mCAAmC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,EAAE,CAAC,CAAC;SAC1J,CAAA;IACH,CAAC;IAED,IAAI,QAAiB,CAAA;IACrB,IAAI,CAAC;QACH,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;IAC5B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO;YACL,EAAE,EAAE,KAAK;YACT,MAAM,EAAE,CAAC,WAAW,CAAC,uBAAuB,EAAE,YAAY,EAAE,mCAAmC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,EAAE,CAAC,CAAC;SAC5J,CAAA;IACH,CAAC;IAED,IAAI,QAA6C,CAAA;IACjD,IAAI,CAAC;QACH,QAAQ,GAAG,gBAAgB,CAAC,cAAc,CAAC,CAAA;IAC7C,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO;YACL,EAAE,EAAE,KAAK;YACT,MAAM,EAAE,CAAC,WAAW,CAClB,2BAA2B,EAC3B,iBAAiB,CAAC,cAAc,CAAC,EACjC,uFAAuF,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,EAAE,CAClJ,CAAC;SACH,CAAA;IACH,CAAC;IAED,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QACxB,OAAO;YACL,EAAE,EAAE,KAAK;YACT,MAAM,EAAE,CAAC,QAAQ,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAC5C,WAAW,CAAC,kBAAkB,EAAE,YAAY,EAAE,KAAK,CAAC,OAAO,IAAI,YAAY,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC;SAChG,CAAA;IACH,CAAC;IAED,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,QAA2B,EAAE,CAAA;AAC5D,CAAC,CAAA"}
@@ -0,0 +1,14 @@
1
+ import type { ConfigProblem } from './json.js';
2
+ /**
3
+ * Checks a policy document read from disk or declared inline in the manifest.
4
+ *
5
+ * The document is untrusted JSON, so this takes `unknown` and reports every
6
+ * problem it finds rather than throwing. Validation lives in the config layer
7
+ * because deciding whether a document is acceptable configuration is a
8
+ * different job from deciding whether a specific change is allowed; the latter
9
+ * stays in the runtime policy engine.
10
+ */
11
+ export declare const policyProblems: (policy: unknown) => ConfigProblem[];
12
+ /** The first problem, or `null` when the document may be treated as a `Policy`. */
13
+ export declare const validatePolicy: (policy: unknown) => string | null;
14
+ //# sourceMappingURL=policy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"policy.d.ts","sourceRoot":"","sources":["../../src/config/policy.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,WAAW,CAAA;AAE9C;;;;;;;;GAQG;AACH,eAAO,MAAM,cAAc,GAAI,QAAQ,OAAO,KAAG,aAAa,EAqB7D,CAAA;AAED,mFAAmF;AACnF,eAAO,MAAM,cAAc,GAAI,QAAQ,OAAO,KAAG,MAAM,GAAG,IACd,CAAA"}
@@ -0,0 +1,35 @@
1
+ import { asRecord } from './json.js';
2
+ /**
3
+ * Checks a policy document read from disk or declared inline in the manifest.
4
+ *
5
+ * The document is untrusted JSON, so this takes `unknown` and reports every
6
+ * problem it finds rather than throwing. Validation lives in the config layer
7
+ * because deciding whether a document is acceptable configuration is a
8
+ * different job from deciding whether a specific change is allowed; the latter
9
+ * stays in the runtime policy engine.
10
+ */
11
+ export const policyProblems = (policy) => {
12
+ const candidate = asRecord(policy);
13
+ if (!candidate)
14
+ return [{ message: 'Policy must be an object.' }];
15
+ const problems = [];
16
+ if (!Array.isArray(candidate.allowedProductPaths) || candidate.allowedProductPaths.length === 0) {
17
+ problems.push({
18
+ field: 'allowedProductPaths',
19
+ message: 'Harness policy must define at least one allowedProductPaths entry.',
20
+ });
21
+ }
22
+ if (!Number.isInteger(candidate.maxIterations) || candidate.maxIterations < 1) {
23
+ problems.push({ field: 'maxIterations', message: 'Harness policy maxIterations must be a positive integer.' });
24
+ }
25
+ if (!Array.isArray(candidate.protectedPaths)) {
26
+ problems.push({ field: 'protectedPaths', message: 'Harness policy protectedPaths must be an array.' });
27
+ }
28
+ if (!Array.isArray(candidate.requiredChecks)) {
29
+ problems.push({ field: 'requiredChecks', message: 'Harness policy requiredChecks must be an array.' });
30
+ }
31
+ return problems;
32
+ };
33
+ /** The first problem, or `null` when the document may be treated as a `Policy`. */
34
+ export const validatePolicy = (policy) => policyProblems(policy)[0]?.message ?? null;
35
+ //# sourceMappingURL=policy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"policy.js","sourceRoot":"","sources":["../../src/config/policy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAA;AAGpC;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,MAAe,EAAmB,EAAE;IACjE,MAAM,SAAS,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAA;IAClC,IAAI,CAAC,SAAS;QAAE,OAAO,CAAC,EAAE,OAAO,EAAE,2BAA2B,EAAE,CAAC,CAAA;IAEjE,MAAM,QAAQ,GAAoB,EAAE,CAAA;IACpC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,mBAAmB,CAAC,IAAI,SAAS,CAAC,mBAAmB,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAChG,QAAQ,CAAC,IAAI,CAAC;YACZ,KAAK,EAAE,qBAAqB;YAC5B,OAAO,EAAE,oEAAoE;SAC9E,CAAC,CAAA;IACJ,CAAC;IACD,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,SAAS,CAAC,aAAa,CAAC,IAAK,SAAS,CAAC,aAAwB,GAAG,CAAC,EAAE,CAAC;QAC1F,QAAQ,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,eAAe,EAAE,OAAO,EAAE,0DAA0D,EAAE,CAAC,CAAA;IAChH,CAAC;IACD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,cAAc,CAAC,EAAE,CAAC;QAC7C,QAAQ,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,gBAAgB,EAAE,OAAO,EAAE,iDAAiD,EAAE,CAAC,CAAA;IACxG,CAAC;IACD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,cAAc,CAAC,EAAE,CAAC;QAC7C,QAAQ,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,gBAAgB,EAAE,OAAO,EAAE,iDAAiD,EAAE,CAAC,CAAA;IACxG,CAAC;IACD,OAAO,QAAQ,CAAA;AACjB,CAAC,CAAA;AAED,mFAAmF;AACnF,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,MAAe,EAAiB,EAAE,CAC/D,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,OAAO,IAAI,IAAI,CAAA"}
@@ -0,0 +1,35 @@
1
+ import type { HarnessConfigError, ResolvedPreset } from '../contracts/index.js';
2
+ /** The document a preset package exposes so the resolver can find it. */
3
+ export declare const presetDocument = "preset.json";
4
+ /** The bundled schema every preset manifest is validated against. */
5
+ export declare const presetSchema = "preset.schema.json";
6
+ export type PresetsResult = {
7
+ ok: true;
8
+ presets: ResolvedPreset[];
9
+ } | {
10
+ ok: false;
11
+ errors: HarnessConfigError[];
12
+ };
13
+ /**
14
+ * Expands the short name a user types into a package name.
15
+ *
16
+ * `vue` means `@pedyc/harness-preset-vue`. The rule is what removes the CLI's
17
+ * hardcoded table: a name containing a slash is already a package name and is
18
+ * taken verbatim, so a team or third-party preset is usable the moment it is
19
+ * installed, without an entry in any list this repository ships.
20
+ */
21
+ export declare const presetPackageName: (name: string) => string;
22
+ /**
23
+ * Resolves preset packages and their inheritance into one ordered list.
24
+ *
25
+ * The walk is a depth-first post-order traversal, which gives three properties at
26
+ * once: a preset is loaded once no matter how many chains reach it, dependencies
27
+ * come before the presets that inherit from them, and re-entering a package that
28
+ * is still on the stack is a cycle rather than infinite recursion — the error
29
+ * then names the whole loop, because "A → B → A" is what tells a reader which
30
+ * `extends` to remove.
31
+ */
32
+ export declare const resolvePresets: (root: string, requested: string[]) => PresetsResult;
33
+ /** How a preset's document is named in an error or in `doctor`. */
34
+ export declare const presetFile: (preset: ResolvedPreset, path: string) => string;
35
+ //# sourceMappingURL=presets.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"presets.d.ts","sourceRoot":"","sources":["../../src/config/presets.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,kBAAkB,EAAkB,cAAc,EAAE,MAAM,uBAAuB,CAAA;AAE/F,yEAAyE;AACzE,eAAO,MAAM,cAAc,gBAAgB,CAAA;AAE3C,qEAAqE;AACrE,eAAO,MAAM,YAAY,uBAAuB,CAAA;AAWhD,MAAM,MAAM,aAAa,GACrB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,OAAO,EAAE,cAAc,EAAE,CAAA;CAAE,GACvC;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,kBAAkB,EAAE,CAAA;CAAE,CAAA;AAI/C;;;;;;;GAOG;AACH,eAAO,MAAM,iBAAiB,GAAI,MAAM,MAAM,KAAG,MACY,CAAA;AA2J7D;;;;;;;;;GASG;AACH,eAAO,MAAM,cAAc,GAAI,MAAM,MAAM,EAAE,WAAW,MAAM,EAAE,KAAG,aAiDlE,CAAA;AAED,mEAAmE;AACnE,eAAO,MAAM,UAAU,GAAI,QAAQ,cAAc,EAAE,MAAM,MAAM,KAAG,MACZ,CAAA"}
@@ -0,0 +1,187 @@
1
+ import { existsSync, readFileSync } from 'node:fs';
2
+ import { createRequire } from 'node:module';
3
+ import { dirname, isAbsolute, join, relative, resolve, sep } from 'node:path';
4
+ import { bundledSchemaFile, bundledValidator, fieldOf } from './bundled.js';
5
+ import { configError } from './errors.js';
6
+ /** The document a preset package exposes so the resolver can find it. */
7
+ export const presetDocument = 'preset.json';
8
+ /** The bundled schema every preset manifest is validated against. */
9
+ export const presetSchema = 'preset.schema.json';
10
+ /**
11
+ * The fields of a preset manifest that name a file inside the package.
12
+ *
13
+ * `entry` and `verification` are validated even though no runtime consumes them
14
+ * yet: a declared document that the package does not contain is a broken preset
15
+ * either way, and resolving it early keeps the failure next to the manifest.
16
+ */
17
+ const pathFields = ['policy', 'agents', 'instruction', 'entry', 'verification'];
18
+ const describe = (error) => (error instanceof Error ? error.message : 'unknown error');
19
+ /**
20
+ * Expands the short name a user types into a package name.
21
+ *
22
+ * `vue` means `@pedyc/harness-preset-vue`. The rule is what removes the CLI's
23
+ * hardcoded table: a name containing a slash is already a package name and is
24
+ * taken verbatim, so a team or third-party preset is usable the moment it is
25
+ * installed, without an entry in any list this repository ships.
26
+ */
27
+ export const presetPackageName = (name) => name.includes('/') ? name : `@pedyc/harness-preset-${name}`;
28
+ /**
29
+ * Resolves a path a preset declares inside its own package.
30
+ *
31
+ * Returns the POSIX path relative to the package, or `null` when it escapes.
32
+ * A preset is a dependency like any other, so it may only point at its own
33
+ * files: a committed package must not be able to read anything the process can.
34
+ */
35
+ const withinPackage = (directory, path) => {
36
+ if (isAbsolute(path))
37
+ return null;
38
+ const offset = relative(directory, resolve(directory, path));
39
+ if (!offset || offset.startsWith('..') || isAbsolute(offset))
40
+ return null;
41
+ return offset.split(sep).join('/');
42
+ };
43
+ /**
44
+ * Finds the directory an installed package occupies.
45
+ *
46
+ * Used only to explain a failed resolution: `require.resolve` is what decides
47
+ * whether a package can be loaded, but when it fails the caller needs to know
48
+ * whether the package is missing or merely does not expose `preset.json`.
49
+ */
50
+ const installedDirectory = (resolveFrom, root, packageName) => {
51
+ const bases = [...(resolveFrom.resolve.paths(packageName) ?? []), join(root, 'node_modules')];
52
+ for (const base of bases) {
53
+ const directory = join(base, packageName);
54
+ if (existsSync(join(directory, 'package.json')))
55
+ return directory;
56
+ }
57
+ return null;
58
+ };
59
+ const notInstalled = (packageName, requiredBy) => configError('preset_not_installed', packageName, `Preset ${packageName} is not installed${requiredBy ? `, but ${requiredBy} requires it` : ''}. ` +
60
+ `Install it with your package manager, for example: npm install --save-dev ${packageName}`);
61
+ /** Locates one preset package, reads its manifest and checks the paths it declares. */
62
+ const locate = (root, resolveFrom, packageName, requiredBy) => {
63
+ const file = `${packageName}/${presetDocument}`;
64
+ const specifier = `${packageName}/${presetDocument}`;
65
+ let path;
66
+ try {
67
+ path = resolveFrom.resolve(specifier);
68
+ }
69
+ catch {
70
+ return installedDirectory(resolveFrom, root, packageName)
71
+ ? {
72
+ errors: [configError('preset_manifest_unreadable', file, `${packageName} is installed but does not expose ${presetDocument}. Add "./${presetDocument}": "./${presetDocument}" to its package.json "exports", then reinstall it.`)],
73
+ }
74
+ : { errors: [notInstalled(packageName, requiredBy)] };
75
+ }
76
+ let raw;
77
+ try {
78
+ raw = readFileSync(path, 'utf8');
79
+ }
80
+ catch (error) {
81
+ return { errors: [configError('preset_manifest_unreadable', file, `${presetDocument} could not be read: ${describe(error)}`)] };
82
+ }
83
+ let document;
84
+ try {
85
+ document = JSON.parse(raw);
86
+ }
87
+ catch (error) {
88
+ return { errors: [configError('preset_manifest_invalid_json', file, `${presetDocument} is not valid JSON: ${describe(error)}`)] };
89
+ }
90
+ let validate;
91
+ try {
92
+ validate = bundledValidator(presetSchema);
93
+ }
94
+ catch (error) {
95
+ return {
96
+ errors: [configError('harness_schema_unreadable', bundledSchemaFile(presetSchema), `The bundled preset schema could not be loaded, so the installation is incomplete: ${describe(error)}`)],
97
+ };
98
+ }
99
+ if (!validate(document)) {
100
+ return {
101
+ errors: (validate.errors ?? []).map((error) => configError('preset_manifest_invalid', file, error.message ?? 'is invalid', fieldOf(error))),
102
+ };
103
+ }
104
+ const manifest = document;
105
+ if (manifest.name !== packageName) {
106
+ return {
107
+ errors: [configError('preset_manifest_invalid', file, `name is '${manifest.name}', but the package it was read from is '${packageName}'. They must match.`, 'name')],
108
+ };
109
+ }
110
+ const directory = dirname(path);
111
+ const errors = [];
112
+ const declared = [];
113
+ for (const field of pathFields) {
114
+ const value = manifest[field];
115
+ if (value !== undefined)
116
+ declared.push([field, value]);
117
+ }
118
+ for (const rule of manifest.rules ?? [])
119
+ declared.push(['rules', rule]);
120
+ for (const [field, value] of declared) {
121
+ const resolved = withinPackage(directory, value);
122
+ if (!resolved) {
123
+ errors.push(configError('preset_path_outside_package', file, `${field} must point at a file inside the preset package; '${value}' does not.`, field));
124
+ continue;
125
+ }
126
+ if (!existsSync(join(directory, resolved))) {
127
+ errors.push(configError('config_file_missing', file, `${field} points at '${value}', which the package does not contain.`, field));
128
+ }
129
+ }
130
+ return errors.length > 0 ? { errors } : { value: { directory, manifest } };
131
+ };
132
+ /**
133
+ * Resolves preset packages and their inheritance into one ordered list.
134
+ *
135
+ * The walk is a depth-first post-order traversal, which gives three properties at
136
+ * once: a preset is loaded once no matter how many chains reach it, dependencies
137
+ * come before the presets that inherit from them, and re-entering a package that
138
+ * is still on the stack is a cycle rather than infinite recursion — the error
139
+ * then names the whole loop, because "A → B → A" is what tells a reader which
140
+ * `extends` to remove.
141
+ */
142
+ export const resolvePresets = (root, requested) => {
143
+ if (requested.length === 0)
144
+ return { ok: true, presets: [] };
145
+ const resolveFrom = createRequire(join(root, 'package.json'));
146
+ const done = new Map();
147
+ const order = [];
148
+ const stack = [];
149
+ const visit = (packageName, requiredBy) => {
150
+ if (done.has(packageName))
151
+ return [];
152
+ const entered = stack.indexOf(packageName);
153
+ if (entered >= 0) {
154
+ const loop = [...stack.slice(entered), packageName].join(' → ');
155
+ return [configError('preset_cyclic', packageName, `Cyclic preset dependency: ${loop}. A preset cannot inherit from itself, directly or through another preset.`)];
156
+ }
157
+ const located = locate(root, resolveFrom, packageName, requiredBy);
158
+ if ('errors' in located)
159
+ return located.errors;
160
+ stack.push(packageName);
161
+ for (const parent of located.value.manifest.extends ?? []) {
162
+ const errors = visit(presetPackageName(parent), packageName);
163
+ if (errors.length > 0)
164
+ return errors;
165
+ }
166
+ stack.pop();
167
+ const preset = {
168
+ packageName,
169
+ name: located.value.manifest.name,
170
+ directory: located.value.directory,
171
+ extends: [...new Set((located.value.manifest.extends ?? []).map(presetPackageName))],
172
+ manifest: located.value.manifest,
173
+ };
174
+ done.set(packageName, preset);
175
+ order.push(preset);
176
+ return [];
177
+ };
178
+ for (const name of requested) {
179
+ const errors = visit(presetPackageName(name));
180
+ if (errors.length > 0)
181
+ return { ok: false, errors };
182
+ }
183
+ return { ok: true, presets: order };
184
+ };
185
+ /** How a preset's document is named in an error or in `doctor`. */
186
+ export const presetFile = (preset, path) => `${preset.packageName}/${path.split(sep).join('/')}`;
187
+ //# sourceMappingURL=presets.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"presets.js","sourceRoot":"","sources":["../../src/config/presets.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ import type { HarnessSchemas, HarnessValidators } from '../contracts/validator.js';
2
+ export { createAjv, createValidators, validationDetails } from '../contracts/validator.js';
3
+ export type { HarnessSchemas, HarnessValidators, ResponseValidator, SchemaErrorFormatter, } from '../contracts/validator.js';
4
+ /** Compiles one schema document with the settings every Harness schema expects. */
5
+ export declare const compileSchema: (schema: object) => HarnessValidators["input"];
6
+ /** Reads one JSON Schema document out of `.harness/`. */
7
+ export declare const readSchema: (root: string, name: string) => object;
8
+ /**
9
+ * Reads the three contracts every target project commits.
10
+ *
11
+ * The manifest schema is deliberately not part of this set: it only has to be
12
+ * present once a project has a `harness.json`, so loading it here would make a
13
+ * project that predates the manifest fail.
14
+ */
15
+ export declare const loadSchemas: (root: string) => HarnessSchemas;
16
+ //# sourceMappingURL=schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/config/schema.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAA;AAKlF,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAA;AAC1F,YAAY,EACV,cAAc,EACd,iBAAiB,EACjB,iBAAiB,EACjB,oBAAoB,GACrB,MAAM,2BAA2B,CAAA;AAElC,mFAAmF;AACnF,eAAO,MAAM,aAAa,GAAI,QAAQ,MAAM,KAAG,iBAAiB,CAAC,OAAO,CAC3C,CAAA;AAE7B,yDAAyD;AACzD,eAAO,MAAM,UAAU,GAAI,MAAM,MAAM,EAAE,MAAM,MAAM,KAAG,MACkB,CAAA;AAE1E;;;;;;GAMG;AACH,eAAO,MAAM,WAAW,GAAI,MAAM,MAAM,KAAG,cAIzC,CAAA"}
@@ -0,0 +1,24 @@
1
+ import { readFileSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ import { createAjv } from '../contracts/validator.js';
4
+ // Compiling a schema is pure, so it lives in `contracts/`; this module adds the
5
+ // file system access the config layer owns. Both halves are re-exported here so
6
+ // the public `./schema` subpath keeps the shape it had before the split.
7
+ export { createAjv, createValidators, validationDetails } from '../contracts/validator.js';
8
+ /** Compiles one schema document with the settings every Harness schema expects. */
9
+ export const compileSchema = (schema) => createAjv().compile(schema);
10
+ /** Reads one JSON Schema document out of `.harness/`. */
11
+ export const readSchema = (root, name) => JSON.parse(readFileSync(join(root, '.harness', name), 'utf8'));
12
+ /**
13
+ * Reads the three contracts every target project commits.
14
+ *
15
+ * The manifest schema is deliberately not part of this set: it only has to be
16
+ * present once a project has a `harness.json`, so loading it here would make a
17
+ * project that predates the manifest fail.
18
+ */
19
+ export const loadSchemas = (root) => ({
20
+ input: readSchema(root, 'input.schema.json'),
21
+ output: readSchema(root, 'output.schema.json'),
22
+ agentResponse: readSchema(root, 'agent-response.schema.json'),
23
+ });
24
+ //# sourceMappingURL=schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/config/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AACtC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAChC,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAA;AAGrD,gFAAgF;AAChF,gFAAgF;AAChF,yEAAyE;AACzE,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAA;AAQ1F,mFAAmF;AACnF,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,MAAc,EAA8B,EAAE,CAC1E,SAAS,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,CAAA;AAE7B,yDAAyD;AACzD,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,IAAY,EAAE,IAAY,EAAU,EAAE,CAC/D,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,EAAE,UAAU,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,CAAW,CAAA;AAE1E;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,IAAY,EAAkB,EAAE,CAAC,CAAC;IAC5D,KAAK,EAAE,UAAU,CAAC,IAAI,EAAE,mBAAmB,CAAC;IAC5C,MAAM,EAAE,UAAU,CAAC,IAAI,EAAE,oBAAoB,CAAC;IAC9C,aAAa,EAAE,UAAU,CAAC,IAAI,EAAE,4BAA4B,CAAC;CAC9D,CAAC,CAAA"}
@@ -0,0 +1,86 @@
1
+ import type { AgentsConfig } from './agent.js';
2
+ import type { Policy } from './policy.js';
3
+ import type { ResolvedPreset } from './preset.js';
4
+ /**
5
+ * The `.harness/harness.json` manifest.
6
+ *
7
+ * It is the entry point that answers "which configuration does this project
8
+ * load", not the whole configuration. A field that points at another document
9
+ * is a path relative to `.harness/`; the same field may also carry the document
10
+ * inline. `verification` and `rules` are accepted and reported, but no runtime
11
+ * consumes them yet.
12
+ */
13
+ export interface HarnessManifest {
14
+ version: number;
15
+ /** Preset package names. Versions belong to `package.json` and the lockfile. */
16
+ presets?: string[];
17
+ policy?: Policy | string;
18
+ agents?: AgentsConfig | string;
19
+ verification?: string;
20
+ rules?: string[];
21
+ }
22
+ /**
23
+ * Why a configuration document could not be turned into runtime input.
24
+ *
25
+ * The codes are stable so CI can branch on them without parsing prose.
26
+ */
27
+ export type ConfigErrorCode = 'harness_directory_missing' | 'harness_schema_unreadable' | 'manifest_invalid_json' | 'manifest_unreadable' | 'manifest_invalid' | 'config_file_missing' | 'config_file_unreadable' | 'config_file_invalid_json' | 'config_file_invalid' | 'config_path_outside_harness' | 'preset_not_installed' | 'preset_manifest_unreadable' | 'preset_manifest_invalid_json' | 'preset_manifest_invalid' | 'preset_cyclic' | 'preset_path_outside_package';
28
+ /**
29
+ * A configuration problem found before any stage runs.
30
+ *
31
+ * `file` and `field` are what make the error actionable: the acceptance rule is
32
+ * that a bad configuration names both the document and the field inside it.
33
+ */
34
+ export interface HarnessConfigError {
35
+ code: ConfigErrorCode;
36
+ /**
37
+ * Repository-relative path of the offending document, or a package-qualified
38
+ * path when the document lives in an installed package.
39
+ *
40
+ * A preset's documents are reported as `<package>/preset.json` and
41
+ * `<package>/policy.json`, because they are not part of this repository and a
42
+ * bare relative path would point at nothing a reader could open.
43
+ */
44
+ file: string;
45
+ /** Dot path inside that document, when a single field is at fault. */
46
+ field?: string;
47
+ message: string;
48
+ }
49
+ /** One document, or set of built-in defaults, that a value was read from. */
50
+ export interface ConfigSource {
51
+ kind: 'manifest' | 'policy' | 'agents' | 'preset' | 'verification' | 'rules';
52
+ /** Repository-relative path, or a description when no file backs the value. */
53
+ location: string;
54
+ /** False when the manifest declares the source but no runtime consumes it yet. */
55
+ active: boolean;
56
+ }
57
+ /** The configuration a run starts from, plus where each part came from. */
58
+ export interface LoadedHarnessConfig {
59
+ root: string;
60
+ manifest: HarnessManifest | null;
61
+ policy: Policy;
62
+ agents: AgentsConfig;
63
+ /**
64
+ * The presets that were resolved, dependencies first.
65
+ *
66
+ * Reported rather than kept private because a preset's inheritance is not
67
+ * visible anywhere else: a project can see which packages it declares in
68
+ * `harness.json`, but only the resolver knows what they pull in.
69
+ */
70
+ presets: ResolvedPreset[];
71
+ sources: ConfigSource[];
72
+ }
73
+ /**
74
+ * Config loading either yields a complete configuration or a list of problems.
75
+ *
76
+ * A partial result is never returned: the acceptance rule is that a bad
77
+ * configuration fails before execution rather than midway through a run.
78
+ */
79
+ export type LoadConfigResult = {
80
+ ok: true;
81
+ config: LoadedHarnessConfig;
82
+ } | {
83
+ ok: false;
84
+ errors: HarnessConfigError[];
85
+ };
86
+ //# sourceMappingURL=harness.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"harness.d.ts","sourceRoot":"","sources":["../../src/contracts/harness.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAC9C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACzC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAEjD;;;;;;;;GAQG;AACH,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAA;IACf,gFAAgF;IAChF,OAAO,CAAC,EAAE,MAAM,EAAE,CAAA;IAClB,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;IACxB,MAAM,CAAC,EAAE,YAAY,GAAG,MAAM,CAAA;IAC9B,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAA;CACjB;AAED;;;;GAIG;AACH,MAAM,MAAM,eAAe,GACvB,2BAA2B,GAC3B,2BAA2B,GAC3B,uBAAuB,GACvB,qBAAqB,GACrB,kBAAkB,GAClB,qBAAqB,GACrB,wBAAwB,GACxB,0BAA0B,GAC1B,qBAAqB,GACrB,6BAA6B,GAC7B,sBAAsB,GACtB,4BAA4B,GAC5B,8BAA8B,GAC9B,yBAAyB,GACzB,eAAe,GACf,6BAA6B,CAAA;AAEjC;;;;;GAKG;AACH,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,eAAe,CAAA;IACrB;;;;;;;OAOG;IACH,IAAI,EAAE,MAAM,CAAA;IACZ,sEAAsE;IACtE,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,OAAO,EAAE,MAAM,CAAA;CAChB;AAED,6EAA6E;AAC7E,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,UAAU,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,GAAG,cAAc,GAAG,OAAO,CAAA;IAC5E,+EAA+E;IAC/E,QAAQ,EAAE,MAAM,CAAA;IAChB,kFAAkF;IAClF,MAAM,EAAE,OAAO,CAAA;CAChB;AAED,2EAA2E;AAC3E,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,eAAe,GAAG,IAAI,CAAA;IAChC,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,YAAY,CAAA;IACpB;;;;;;OAMG;IACH,OAAO,EAAE,cAAc,EAAE,CAAA;IACzB,OAAO,EAAE,YAAY,EAAE,CAAA;CACxB;AAED;;;;;GAKG;AACH,MAAM,MAAM,gBAAgB,GACxB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,mBAAmB,CAAA;CAAE,GACzC;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,kBAAkB,EAAE,CAAA;CAAE,CAAA"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=harness.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"harness.js","sourceRoot":"","sources":["../../src/contracts/harness.ts"],"names":[],"mappings":""}
@@ -1,7 +1,9 @@
1
1
  export type { AgentMode, AgentRole, CommandPolicy, Policy } from './policy.js';
2
2
  export type { VerificationCheck } from './validation.js';
3
3
  export type { IntakeResult, NormalizedTask, RawTaskInput } from './task.js';
4
- export type { Preset, PresetDetection } from './preset.js';
4
+ export type { PresetManifest, ResolvedPreset } from './preset.js';
5
5
  export type { FileChange, OrchestrationResult, PhaseRecord, PhaseStatus, RunResult, RunStatus } from './run.js';
6
+ export type { ConfigErrorCode, ConfigSource, HarnessConfigError, HarnessManifest, LoadConfigResult, LoadedHarnessConfig, } from './harness.js';
6
7
  export type { AgentCallResult, AgentPayload, AgentRoleConfig, AgentsConfig, CoderRequest, PlannerRequest, ProviderConfig, ReviewerRequest, RunAgent, StageRequest, TesterRequest, } from './agent.js';
8
+ export type { HarnessSchemas, HarnessValidators, ResponseValidator, SchemaErrorFormatter, } from './validator.js';
7
9
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/contracts/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,SAAS,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAC9E,YAAY,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAA;AACxD,YAAY,EAAE,YAAY,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,WAAW,CAAA;AAC3E,YAAY,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAC1D,YAAY,EAAE,UAAU,EAAE,mBAAmB,EAAE,WAAW,EAAE,WAAW,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,UAAU,CAAA;AAC/G,YAAY,EACV,eAAe,EACf,YAAY,EACZ,eAAe,EACf,YAAY,EACZ,YAAY,EACZ,cAAc,EACd,cAAc,EACd,eAAe,EACf,QAAQ,EACR,YAAY,EACZ,aAAa,GACd,MAAM,YAAY,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/contracts/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,SAAS,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAC9E,YAAY,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAA;AACxD,YAAY,EAAE,YAAY,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,WAAW,CAAA;AAC3E,YAAY,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AACjE,YAAY,EAAE,UAAU,EAAE,mBAAmB,EAAE,WAAW,EAAE,WAAW,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,UAAU,CAAA;AAC/G,YAAY,EACV,eAAe,EACf,YAAY,EACZ,kBAAkB,EAClB,eAAe,EACf,gBAAgB,EAChB,mBAAmB,GACpB,MAAM,cAAc,CAAA;AACrB,YAAY,EACV,eAAe,EACf,YAAY,EACZ,eAAe,EACf,YAAY,EACZ,YAAY,EACZ,cAAc,EACd,cAAc,EACd,eAAe,EACf,QAAQ,EACR,YAAY,EACZ,aAAa,GACd,MAAM,YAAY,CAAA;AACnB,YAAY,EACV,cAAc,EACd,iBAAiB,EACjB,iBAAiB,EACjB,oBAAoB,GACrB,MAAM,gBAAgB,CAAA"}