@opensoftware/contracts 2.5.0 → 2.6.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.
- package/README.md +19 -1
- package/dist/cli.js +3 -6
- package/dist/cli.js.map +1 -1
- package/dist/formats.js +1 -0
- package/dist/formats.js.map +1 -1
- package/dist/generated/types.d.ts +85 -1
- package/dist/index.d.ts +13 -0
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -1
- package/dist/sandbox.d.ts +17 -0
- package/dist/sandbox.js +23 -0
- package/dist/sandbox.js.map +1 -0
- package/factory-definition/factory-definition.schema.json +1 -1
- package/factory-lock/factory-lock.schema.json +32 -0
- package/openapi/openapi.json +206 -2
- package/package.json +2 -2
- package/skill-catalog/skill-catalog.schema.json +177 -0
- package/typespec/factory-definition.tsp +4 -1
- package/typespec/factory-lock.tsp +23 -0
- package/typespec/main.tsp +1 -0
- package/typespec/skill-catalog.tsp +94 -0
package/README.md
CHANGED
|
@@ -28,6 +28,13 @@ const problems = validate("factory-definition", document); // [] when valid, els
|
|
|
28
28
|
`runSpans(record)` reads a run record as runlog writes it: each span with its decoded resource and attributes, or
|
|
29
29
|
`undefined` when the value is no OTLP/JSON trace export request ([ADR 0041](../docs/decisions/0041-run-record-reader.md)).
|
|
30
30
|
|
|
31
|
+
`readDocument(format, file)` reads a YAML or JSON file and gives `{ document, problems }`, the problems as
|
|
32
|
+
`validate` gives them; a file that cannot be read or parsed throws. The sandbox port's command line has two values
|
|
33
|
+
of its own ([ADR 0147](../docs/decisions/0147-sandbox-egress-is-the-egress-proxy.md)): `copyEnds(from, to)` gives the
|
|
34
|
+
ends of `copy <from> <to>`, `{ id, inSandbox, local, into }` with a relative path below `SANDBOX_WORKSPACE`
|
|
35
|
+
(`/workspace`), or `{ problem }` when not exactly one side is `<ID>:<path>`. Each gives a problem and throws no
|
|
36
|
+
usage error: the adapter turns it into its own.
|
|
37
|
+
|
|
31
38
|
The schema files are exported at the paths in the table below, for example
|
|
32
39
|
`@opensoftware/contracts/work-item/work-item.schema.json`, along with `events/asyncapi.yaml`, `openapi/*` and `typespec/*`.
|
|
33
40
|
|
|
@@ -44,8 +51,9 @@ Each format has one schema, generated from `typespec/`, and fixtures that CONTRA
|
|
|
44
51
|
| score | `score/score.schema.json` | `Score` | Subset of Langfuse's create-score request; factory fields in `metadata`. |
|
|
45
52
|
| gate record | `gate-record/gate-record.schema.json` | `GateRecord` | gatekeeper's signed approval record (ADR 0047). |
|
|
46
53
|
| sandbox spec | `sandbox-spec/sandbox-spec.schema.json` | `SandboxSpec` | The input of a sandbox adapter's `create` (ADR 0054). Closed objects: an unknown field is an error. |
|
|
47
|
-
| factory lock | `factory-lock/factory-lock.schema.json` | `FactoryLock` | `factory.lock` next to `factory.yaml`: the registry MCP servers and the
|
|
54
|
+
| factory lock | `factory-lock/factory-lock.schema.json` | `FactoryLock` | `factory.lock` next to `factory.yaml`: the registry MCP servers, the adapters and the skills of other Git repositories that `factory plan` pinned, a skill with its commit and the hash of its files (ADR 0020, ADR 0125, ADR 0146). factory-spec writes it, the foreman reads the adapter pins and the skill pins. |
|
|
48
55
|
| access | `access/access.schema.json` | `Access` | `access.yaml` next to `factory.yaml`: the people who may sign in to the factory UI, each by email with one role, `member`, `factory-engineer` or `admin` (ADR 0134). The console reads it at each request. |
|
|
56
|
+
| skill catalog | `skill-catalog/skill-catalog.schema.json` | `SkillCatalog` | What `factory skills` prints: every skill the factory's agents use, with its needs, its agents and what each lacks, its files, the Markdown of its `SKILL.md` and its problems, and for a skill of another Git repository its URL and commit (ADR 0141, ADR 0143, ADR 0146). factory-spec writes it, the console reads it for `/skills`. |
|
|
49
57
|
| events | `events/<event>/<event>.schema.json`, `events/asyncapi.yaml` | `WorkReceived`, `WorkRetryRequested`, `RunStarted`, `RunCompleted`, `RunBlocked`, `DoctorPing` … `IssueLabeled` | CloudEvents 1.0, structured JSON. |
|
|
50
58
|
|
|
51
59
|
## HTTP APIs
|
|
@@ -158,3 +166,13 @@ None. The CLI reads no environment variables.
|
|
|
158
166
|
| SCN-CTR-012 | implemented | A factory definition with an unknown effort is rejected with the allowed levels |
|
|
159
167
|
| SCN-CTR-013 | implemented | An access file with an admin and a member validates |
|
|
160
168
|
| SCN-CTR-014 | implemented | An access file with an unknown role is rejected with the roles it allows |
|
|
169
|
+
| SCN-CTR-015 | implemented | A skill catalog with a skill that one agent lacks the secret of validates |
|
|
170
|
+
| SCN-CTR-016 | implemented | A skill catalog whose skill has no body is rejected with its path |
|
|
171
|
+
| SCN-CTR-017 | implemented | readDocument gives a file's document and each problem with its path |
|
|
172
|
+
| SCN-CTR-018 | implemented | A copy into a sandbox names a path below its working folder |
|
|
173
|
+
| SCN-CTR-019 | implemented | A copy out of a sandbox keeps an absolute path |
|
|
174
|
+
| SCN-CTR-020 | implemented | A copy that names a sandbox on both sides gives its problem |
|
|
175
|
+
| SCN-CTR-021 | implemented | A factory lock with a pinned skill of another repository validates |
|
|
176
|
+
| SCN-CTR-022 | implemented | A pinned skill with a short commit is rejected with its path |
|
|
177
|
+
| SCN-CTR-023 | implemented | The pins of skills in factory.lock are no breaking change |
|
|
178
|
+
| SCN-CTR-024 | implemented | A skill catalog with a skill of another repository at its commit validates |
|
package/dist/cli.js
CHANGED
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
// osf-contracts: validate documents against the shared formats, check schema compatibility with the last release,
|
|
3
3
|
// and round-trip the fixtures through the generated clients.
|
|
4
|
-
import { readFileSync } from "node:fs";
|
|
5
|
-
import { parse } from "yaml";
|
|
6
4
|
import { breaking } from "./breaking.js";
|
|
7
5
|
import { FORMATS, formatNamed } from "./formats.js";
|
|
8
|
-
import {
|
|
6
|
+
import { readDocument } from "./index.js";
|
|
9
7
|
import { CLIENTS, roundtrip } from "./roundtrip.js";
|
|
10
8
|
const USAGE = `Usage: osf-contracts <command>
|
|
11
9
|
|
|
@@ -45,15 +43,14 @@ function validateCommand([name, file]) {
|
|
|
45
43
|
const format = name ? formatNamed(name) : undefined;
|
|
46
44
|
if (!format || !file)
|
|
47
45
|
return usage(name && !format ? `Unknown format: ${name}` : "Give a format and a file");
|
|
48
|
-
let
|
|
46
|
+
let problems;
|
|
49
47
|
try {
|
|
50
|
-
|
|
48
|
+
({ problems } = readDocument(format, file));
|
|
51
49
|
}
|
|
52
50
|
catch (error) {
|
|
53
51
|
process.stdout.write(`${file}: not readable as YAML or JSON: ${error.message}\n`);
|
|
54
52
|
return 1;
|
|
55
53
|
}
|
|
56
|
-
const problems = validate(format, document);
|
|
57
54
|
for (const problem of problems)
|
|
58
55
|
process.stdout.write(`${file} ${problem.path}: ${problem.message}\n`);
|
|
59
56
|
if (problems.length > 0)
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,kHAAkH;AAClH,6DAA6D;AAC7D,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,kHAAkH;AAClH,6DAA6D;AAC7D,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,EAAgB,YAAY,EAAE,MAAM,YAAY,CAAC;AACxD,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAEpD,MAAM,KAAK,GAAG;;2EAE6D,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;;;;yEAIjD,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC;CAC1F,CAAC;AAEF,SAAS,IAAI,CAAC,IAAc;IAC1B,MAAM,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC;IAChC,QAAQ,OAAO,EAAE,CAAC;QAChB,KAAK,UAAU;YACb,OAAO,eAAe,CAAC,IAAI,CAAC,CAAC;QAC/B,KAAK,UAAU,CAAC,CAAC,CAAC;YAChB,MAAM,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;YAClC,OAAO,QAAQ,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC;QACxD,CAAC;QACD,KAAK,WAAW,CAAC,CAAC,CAAC;YACjB,MAAM,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;YACpC,MAAM,MAAM,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;YACpD,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,CAAC,KAAK,KAAK,EAAE,IAAI,KAAK,KAAK,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,WAAW,CAAC;YAC1F,IAAI,CAAC,MAAM,IAAI,CAAE,OAA6B,CAAC,QAAQ,CAAC,MAAM,CAAC;gBAC7D,OAAO,KAAK,CAAC,kBAAkB,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YACvD,OAAO,SAAS,CAAC,MAAkC,EAAE,GAAG,CAAC,CAAC;QAC5D,CAAC;QACD,KAAK,SAAS,CAAC;QACf,KAAK,MAAM,CAAC;QACZ,KAAK,QAAQ;YACX,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;YAC5B,OAAO,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACvC;YACE,OAAO,KAAK,CAAC,oBAAoB,OAAO,EAAE,CAAC,CAAC;IAChD,CAAC;AACH,CAAC;AAED,SAAS,eAAe,CAAC,CAAC,IAAI,EAAE,IAAI,CAAW;IAC7C,MAAM,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IACpD,IAAI,CAAC,MAAM,IAAI,CAAC,IAAI;QAAE,OAAO,KAAK,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,mBAAmB,IAAI,EAAE,CAAC,CAAC,CAAC,0BAA0B,CAAC,CAAC;IAC7G,IAAI,QAAmB,CAAC;IACxB,IAAI,CAAC;QACH,CAAC,EAAE,QAAQ,EAAE,GAAG,YAAY,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC;IAC9C,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,IAAI,mCAAoC,KAAe,CAAC,OAAO,IAAI,CAAC,CAAC;QAC7F,OAAO,CAAC,CAAC;IACX,CAAC;IACD,KAAK,MAAM,OAAO,IAAI,QAAQ;QAAE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,IAAI,IAAI,OAAO,CAAC,IAAI,KAAK,OAAO,CAAC,OAAO,IAAI,CAAC,CAAC;IACtG,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,CAAC,CAAC;IAClC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,IAAI,WAAW,MAAM,CAAC,IAAI,IAAI,CAAC,CAAC;IACxD,OAAO,CAAC,CAAC;AACX,CAAC;AAED,SAAS,KAAK,CAAC,OAAe;IAC5B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,OAAO,OAAO,KAAK,EAAE,CAAC,CAAC;IAC/C,OAAO,CAAC,CAAC;AACX,CAAC;AAED,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC"}
|
package/dist/formats.js
CHANGED
|
@@ -10,6 +10,7 @@ export const FORMATS = [
|
|
|
10
10
|
format("sandbox-spec", "SandboxSpec"),
|
|
11
11
|
format("factory-lock", "FactoryLock"),
|
|
12
12
|
format("access", "Access"),
|
|
13
|
+
format("skill-catalog", "SkillCatalog"),
|
|
13
14
|
format("events/work-received", "WorkReceived"),
|
|
14
15
|
format("events/work-retry-requested", "WorkRetryRequested"),
|
|
15
16
|
format("events/run-started", "RunStarted"),
|
package/dist/formats.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"formats.js","sourceRoot":"","sources":["../src/formats.ts"],"names":[],"mappings":"AAAA,2GAA2G;AAW3G,MAAM,MAAM,GAAG,CAAC,IAAY,EAAE,KAAa,EAAU,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAY,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;AAEjH,MAAM,CAAC,MAAM,OAAO,GAAsB;IACxC,MAAM,CAAC,oBAAoB,EAAE,mBAAmB,CAAC;IACjD,MAAM,CAAC,WAAW,EAAE,UAAU,CAAC;IAC/B,MAAM,CAAC,YAAY,EAAE,WAAW,CAAC;IACjC,MAAM,CAAC,iBAAiB,EAAE,kBAAkB,CAAC;IAC7C,MAAM,CAAC,OAAO,EAAE,OAAO,CAAC;IACxB,MAAM,CAAC,aAAa,EAAE,YAAY,CAAC;IACnC,MAAM,CAAC,cAAc,EAAE,aAAa,CAAC;IACrC,MAAM,CAAC,cAAc,EAAE,aAAa,CAAC;IACrC,MAAM,CAAC,QAAQ,EAAE,QAAQ,CAAC;IAC1B,MAAM,CAAC,sBAAsB,EAAE,cAAc,CAAC;IAC9C,MAAM,CAAC,6BAA6B,EAAE,oBAAoB,CAAC;IAC3D,MAAM,CAAC,oBAAoB,EAAE,YAAY,CAAC;IAC1C,MAAM,CAAC,sBAAsB,EAAE,cAAc,CAAC;IAC9C,MAAM,CAAC,oBAAoB,EAAE,YAAY,CAAC;IAC1C,MAAM,CAAC,oBAAoB,EAAE,YAAY,CAAC;IAC1C,MAAM,CAAC,uBAAuB,EAAE,eAAe,CAAC;IAChD,MAAM,CAAC,qBAAqB,EAAE,aAAa,CAAC;IAC5C,MAAM,CAAC,uBAAuB,EAAE,eAAe,CAAC;IAChD,MAAM,CAAC,kBAAkB,EAAE,UAAU,CAAC;IACtC,MAAM,CAAC,oBAAoB,EAAE,YAAY,CAAC;IAC1C,MAAM,CAAC,kBAAkB,EAAE,UAAU,CAAC;IACtC,MAAM,CAAC,sBAAsB,EAAE,cAAc,CAAC;CAC/C,CAAC;AAEF,MAAM,UAAU,WAAW,CAAC,IAAY;IACtC,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;AAC9D,CAAC"}
|
|
1
|
+
{"version":3,"file":"formats.js","sourceRoot":"","sources":["../src/formats.ts"],"names":[],"mappings":"AAAA,2GAA2G;AAW3G,MAAM,MAAM,GAAG,CAAC,IAAY,EAAE,KAAa,EAAU,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAY,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;AAEjH,MAAM,CAAC,MAAM,OAAO,GAAsB;IACxC,MAAM,CAAC,oBAAoB,EAAE,mBAAmB,CAAC;IACjD,MAAM,CAAC,WAAW,EAAE,UAAU,CAAC;IAC/B,MAAM,CAAC,YAAY,EAAE,WAAW,CAAC;IACjC,MAAM,CAAC,iBAAiB,EAAE,kBAAkB,CAAC;IAC7C,MAAM,CAAC,OAAO,EAAE,OAAO,CAAC;IACxB,MAAM,CAAC,aAAa,EAAE,YAAY,CAAC;IACnC,MAAM,CAAC,cAAc,EAAE,aAAa,CAAC;IACrC,MAAM,CAAC,cAAc,EAAE,aAAa,CAAC;IACrC,MAAM,CAAC,QAAQ,EAAE,QAAQ,CAAC;IAC1B,MAAM,CAAC,eAAe,EAAE,cAAc,CAAC;IACvC,MAAM,CAAC,sBAAsB,EAAE,cAAc,CAAC;IAC9C,MAAM,CAAC,6BAA6B,EAAE,oBAAoB,CAAC;IAC3D,MAAM,CAAC,oBAAoB,EAAE,YAAY,CAAC;IAC1C,MAAM,CAAC,sBAAsB,EAAE,cAAc,CAAC;IAC9C,MAAM,CAAC,oBAAoB,EAAE,YAAY,CAAC;IAC1C,MAAM,CAAC,oBAAoB,EAAE,YAAY,CAAC;IAC1C,MAAM,CAAC,uBAAuB,EAAE,eAAe,CAAC;IAChD,MAAM,CAAC,qBAAqB,EAAE,aAAa,CAAC;IAC5C,MAAM,CAAC,uBAAuB,EAAE,eAAe,CAAC;IAChD,MAAM,CAAC,kBAAkB,EAAE,UAAU,CAAC;IACtC,MAAM,CAAC,oBAAoB,EAAE,YAAY,CAAC;IAC1C,MAAM,CAAC,kBAAkB,EAAE,UAAU,CAAC;IACtC,MAAM,CAAC,sBAAsB,EAAE,cAAc,CAAC;CAC/C,CAAC;AAEF,MAAM,UAAU,WAAW,CAAC,IAAY;IACtC,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;AAC9D,CAAC"}
|
|
@@ -294,7 +294,10 @@ export type components = {
|
|
|
294
294
|
repositories?: string[];
|
|
295
295
|
/** @description MCP servers: `registry:<name>@<version>` or `<name>@<version>`. */
|
|
296
296
|
mcp?: string[];
|
|
297
|
-
/**
|
|
297
|
+
/**
|
|
298
|
+
* @description The agent's skills: each a path to a skill folder, or a folder of another Git repository at a ref,
|
|
299
|
+
* `git+<url>#<ref>:<path>`, which `factory plan` pins in factory.lock (ADR 0146).
|
|
300
|
+
*/
|
|
298
301
|
skills?: string[];
|
|
299
302
|
secrets?: components["schemas"]["SecretReference"][];
|
|
300
303
|
/** @description Runtime of the agent. */
|
|
@@ -344,6 +347,53 @@ export type components = {
|
|
|
344
347
|
BlockedOn: "checks";
|
|
345
348
|
/** @description A path inside the bundle: relative, forward slashes, no "..". */
|
|
346
349
|
BundlePath: string;
|
|
350
|
+
/** @description One skill, also one that lint refuses: then `problems` names why. */
|
|
351
|
+
CatalogSkill: {
|
|
352
|
+
/** @description The last segment of the skill's folder. */
|
|
353
|
+
name: string;
|
|
354
|
+
/** @description The description of its front matter; null without one. */
|
|
355
|
+
description: string | null;
|
|
356
|
+
/** @description Where the skill comes from. */
|
|
357
|
+
source: components["schemas"]["CatalogSkillSource"];
|
|
358
|
+
/** @description What it needs, from the `metadata` of its front matter. */
|
|
359
|
+
needs: components["schemas"]["SkillNeeds"];
|
|
360
|
+
/** @description Each agent that uses it, sorted by name. */
|
|
361
|
+
agents: components["schemas"]["CatalogSkillAgent"][];
|
|
362
|
+
/** @description The files of its folder, by their path below it, sorted. */
|
|
363
|
+
files: string[];
|
|
364
|
+
/**
|
|
365
|
+
* @description The text of SKILL.md below the line that ends its front matter, all of it without front matter; null without a
|
|
366
|
+
* SKILL.md that is UTF-8 text.
|
|
367
|
+
*/
|
|
368
|
+
body: string | null;
|
|
369
|
+
/**
|
|
370
|
+
* @description The problems of its own files as `factory lint` prints them, relative to the folder of factory.yaml, and a folder
|
|
371
|
+
* without a SKILL.md.
|
|
372
|
+
*/
|
|
373
|
+
problems: string[];
|
|
374
|
+
};
|
|
375
|
+
/** @description An agent that uses a skill. */
|
|
376
|
+
CatalogSkillAgent: {
|
|
377
|
+
name: string;
|
|
378
|
+
/** @description The agent's reference whose variable is each secret the skill needs, by the variable. */
|
|
379
|
+
secrets: {
|
|
380
|
+
[key: string]: components["schemas"]["SecretReference"];
|
|
381
|
+
};
|
|
382
|
+
/** @description Each needed secret the agent does not declare, and each needed host its sandbox does not allow. */
|
|
383
|
+
lacks: components["schemas"]["SkillNeeds"];
|
|
384
|
+
};
|
|
385
|
+
/**
|
|
386
|
+
* @description A folder of the factory's repository, relative to the folder of factory.yaml, like "skills/release-notes"; or, for a
|
|
387
|
+
* skill of another Git repository, its folder there with the repository's URL and the commit factory.lock pins
|
|
388
|
+
* (ADR 0146).
|
|
389
|
+
*/
|
|
390
|
+
CatalogSkillSource: {
|
|
391
|
+
folder: string;
|
|
392
|
+
/** @description The URL of the other Git repository, as the entry `git+<url>#<ref>:<path>` names it. */
|
|
393
|
+
repository?: string;
|
|
394
|
+
/** @description The commit of the other repository that factory.lock pins; none while factory.lock has no pin. */
|
|
395
|
+
commit?: string;
|
|
396
|
+
};
|
|
347
397
|
/** @description The name of a check on the forge: a commit status context. */
|
|
348
398
|
CheckName: string;
|
|
349
399
|
/**
|
|
@@ -487,6 +537,14 @@ export type components = {
|
|
|
487
537
|
[key: string]: components["schemas"]["FactoryLockAdapterPin"];
|
|
488
538
|
};
|
|
489
539
|
};
|
|
540
|
+
/**
|
|
541
|
+
* @description The skills of other Git repositories that `factory plan` pinned, by the skill's name (ADR 0146). A pin counts only
|
|
542
|
+
* while its `source` is the entry factory.yaml declares; the foreman and `factory render` fetch its commit and check
|
|
543
|
+
* its hash.
|
|
544
|
+
*/
|
|
545
|
+
skills?: {
|
|
546
|
+
[key: string]: components["schemas"]["FactoryLockSkillPin"];
|
|
547
|
+
};
|
|
490
548
|
};
|
|
491
549
|
/** @description One adapter's npm package `@opensoftware/<port>-<name>` at the newest version inside its range. */
|
|
492
550
|
FactoryLockAdapterPin: {
|
|
@@ -510,6 +568,15 @@ export type components = {
|
|
|
510
568
|
url: string;
|
|
511
569
|
};
|
|
512
570
|
};
|
|
571
|
+
/** @description One skill of another Git repository at the commit its ref had when `factory plan` pinned it. */
|
|
572
|
+
FactoryLockSkillPin: {
|
|
573
|
+
/** @description The entry of `skills` in factory.yaml that the pin was resolved from, `git+<url>#<ref>:<path>`. */
|
|
574
|
+
source: string;
|
|
575
|
+
/** @description The full commit, 40 hexadecimal characters, or 64 in a repository of SHA-256. */
|
|
576
|
+
commit: string;
|
|
577
|
+
/** @description The hash of the skill folder's files in the form of Go's modules: "h1:" and the base64 of a SHA-256. */
|
|
578
|
+
hash: string;
|
|
579
|
+
};
|
|
513
580
|
/**
|
|
514
581
|
* @description The version of a format inside its documents. Only 1 exists; a new major version of a format adds the next.
|
|
515
582
|
* @constant
|
|
@@ -1304,6 +1371,23 @@ export type components = {
|
|
|
1304
1371
|
/** @description A reference to a secret, resolved at the egress proxy, never in the sandbox: "ref:<provider>/<name>". */
|
|
1305
1372
|
SecretReference: string;
|
|
1306
1373
|
Sha256: string;
|
|
1374
|
+
/**
|
|
1375
|
+
* @description What `factory skills` of factory-spec prints (ADR 0141, ADR 0143): every skill the factory's agents use, read with
|
|
1376
|
+
* the rules of `factory lint` (ADR 0140), sorted by name. The console reads it for its pages `/skills` and
|
|
1377
|
+
* `/skills/<name>`, so it never parses a SKILL.md itself.
|
|
1378
|
+
*/
|
|
1379
|
+
SkillCatalog: {
|
|
1380
|
+
skills: components["schemas"]["CatalogSkill"][];
|
|
1381
|
+
};
|
|
1382
|
+
/** @description A host as an entry of `sandbox.egress`, like "api.linear.app". */
|
|
1383
|
+
SkillHost: string;
|
|
1384
|
+
/** @description The secrets a skill needs, by the variable that holds each in a sandbox, and the hosts it reaches (ADR 0140). */
|
|
1385
|
+
SkillNeeds: {
|
|
1386
|
+
secrets: components["schemas"]["SkillSecretName"][];
|
|
1387
|
+
hosts: components["schemas"]["SkillHost"][];
|
|
1388
|
+
};
|
|
1389
|
+
/** @description The variable of a secret in a sandbox (ADR 0068), like "LINEAR_TOKEN". */
|
|
1390
|
+
SkillSecretName: string;
|
|
1307
1391
|
Stage: {
|
|
1308
1392
|
stage: components["schemas"]["Name"];
|
|
1309
1393
|
/** @description Agent that runs the stage. Defaults to the agent with the stage's name. */
|
package/dist/index.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ export { diff as breakingChanges, type Schema } from "./breaking.ts";
|
|
|
4
4
|
export { FORMATS, type Format, formatNamed } from "./formats.ts";
|
|
5
5
|
export type { components, paths } from "./generated/types.ts";
|
|
6
6
|
export { type AttributeValue, type RunSpan, runSpans, type SpanAttributes } from "./run-record.ts";
|
|
7
|
+
export { type CopyEnds, copyEnds, SANDBOX_WORKSPACE } from "./sandbox.ts";
|
|
7
8
|
type Schemas = components["schemas"];
|
|
8
9
|
export type FactoryDefinition = Schemas["FactoryDefinition"];
|
|
9
10
|
export type WorkItem = Schemas["WorkItem"];
|
|
@@ -45,6 +46,10 @@ export type FactoryLock = Schemas["FactoryLock"];
|
|
|
45
46
|
export type Access = Schemas["Access"];
|
|
46
47
|
export type AccessPerson = Schemas["AccessPerson"];
|
|
47
48
|
export type AccessRole = Schemas["AccessRole"];
|
|
49
|
+
export type SkillCatalog = Schemas["SkillCatalog"];
|
|
50
|
+
export type CatalogSkill = Schemas["CatalogSkill"];
|
|
51
|
+
export type CatalogSkillAgent = Schemas["CatalogSkillAgent"];
|
|
52
|
+
export type SkillNeeds = Schemas["SkillNeeds"];
|
|
48
53
|
export type Health = Schemas["Health"];
|
|
49
54
|
export type HealthCheck = Schemas["HealthCheck"];
|
|
50
55
|
/** One reason a document does not match its format. `path` is a JSON Pointer into the document. */
|
|
@@ -56,5 +61,13 @@ export interface Problem {
|
|
|
56
61
|
export declare function schemaOf(format: Format | string): Record<string, unknown>;
|
|
57
62
|
/** Every problem of the document; empty when it matches the format. */
|
|
58
63
|
export declare function validate(format: Format | string, document: unknown): Problem[];
|
|
64
|
+
/**
|
|
65
|
+
* The document of a YAML or JSON file and every problem of it against the format; JSON is YAML. A file that cannot
|
|
66
|
+
* be read or parsed throws.
|
|
67
|
+
*/
|
|
68
|
+
export declare function readDocument<T = unknown>(format: Format | string, file: string): {
|
|
69
|
+
document: T;
|
|
70
|
+
problems: Problem[];
|
|
71
|
+
};
|
|
59
72
|
/** True when the document matches the format, with its type narrowed. */
|
|
60
73
|
export declare function isValid<T>(format: Format | string, document: unknown): document is T;
|
package/dist/index.js
CHANGED
|
@@ -4,10 +4,12 @@ import { dirname, join } from "node:path";
|
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
5
|
import Ajv2020, {} from "ajv/dist/2020.js";
|
|
6
6
|
import addFormats from "ajv-formats";
|
|
7
|
+
import { parse } from "yaml";
|
|
7
8
|
import { formatNamed } from "./formats.js";
|
|
8
9
|
export { diff as breakingChanges } from "./breaking.js";
|
|
9
10
|
export { FORMATS, formatNamed } from "./formats.js";
|
|
10
11
|
export { runSpans } from "./run-record.js";
|
|
12
|
+
export { copyEnds, SANDBOX_WORKSPACE } from "./sandbox.js";
|
|
11
13
|
/** The package root: dist/ and src/ both sit one level below it, next to the schema folders. */
|
|
12
14
|
const ROOT = join(dirname(fileURLToPath(import.meta.url)), "..");
|
|
13
15
|
const validators = new Map();
|
|
@@ -31,6 +33,14 @@ export function validate(format, document) {
|
|
|
31
33
|
}
|
|
32
34
|
return check(document) ? [] : problems(check.errors ?? []);
|
|
33
35
|
}
|
|
36
|
+
/**
|
|
37
|
+
* The document of a YAML or JSON file and every problem of it against the format; JSON is YAML. A file that cannot
|
|
38
|
+
* be read or parsed throws.
|
|
39
|
+
*/
|
|
40
|
+
export function readDocument(format, file) {
|
|
41
|
+
const document = parse(readFileSync(file, "utf8"));
|
|
42
|
+
return { document, problems: validate(format, document) };
|
|
43
|
+
}
|
|
34
44
|
/** True when the document matches the format, with its type narrowed. */
|
|
35
45
|
export function isValid(format, document) {
|
|
36
46
|
return validate(format, document).length === 0;
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,oHAAoH;AACpH,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,OAAO,EAAE,EAA2C,MAAM,kBAAkB,CAAC;AACpF,OAAO,UAAU,MAAM,aAAa,CAAC;AACrC,OAAO,EAAe,WAAW,EAAE,MAAM,cAAc,CAAC;AAGxD,OAAO,EAAE,IAAI,IAAI,eAAe,EAAe,MAAM,eAAe,CAAC;AACrE,OAAO,EAAE,OAAO,EAAe,WAAW,EAAE,MAAM,cAAc,CAAC;AAEjE,OAAO,EAAqC,QAAQ,EAAuB,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/** The working folder of every command in a sandbox. */
|
|
2
|
+
export declare const SANDBOX_WORKSPACE = "/workspace";
|
|
3
|
+
/** The two ends of a copy. */
|
|
4
|
+
export interface CopyEnds {
|
|
5
|
+
/** The sandbox's ID. */
|
|
6
|
+
id: string;
|
|
7
|
+
/** The absolute path in the sandbox; a relative path is below the working folder. */
|
|
8
|
+
inSandbox: string;
|
|
9
|
+
/** The path on the client's side, as given. */
|
|
10
|
+
local: string;
|
|
11
|
+
/** Whether the copy goes into the sandbox. */
|
|
12
|
+
into: boolean;
|
|
13
|
+
}
|
|
14
|
+
/** The ends of `copy <from> <to>`, or the problem when not exactly one side names a sandbox. */
|
|
15
|
+
export declare function copyEnds(from: string | undefined, to: string | undefined): CopyEnds | {
|
|
16
|
+
problem: string;
|
|
17
|
+
};
|
package/dist/sandbox.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
// The sandbox port's command line as its adapters and clients share it (ADR 0054, ADR 0147): the working folder of
|
|
2
|
+
// every sandbox, and the two ends of `copy <from> <to>`, whose sandbox side is `<ID>:<path>`.
|
|
3
|
+
import { posix } from "node:path";
|
|
4
|
+
/** The working folder of every command in a sandbox. */
|
|
5
|
+
export const SANDBOX_WORKSPACE = "/workspace";
|
|
6
|
+
const IN_SANDBOX = /^([0-9a-f]{12}):(.+)$/;
|
|
7
|
+
/** The ends of `copy <from> <to>`, or the problem when not exactly one side names a sandbox. */
|
|
8
|
+
export function copyEnds(from, to) {
|
|
9
|
+
if (!from || !to)
|
|
10
|
+
return { problem: "name what to copy and where to, like copy notes.md <ID>:notes.md" };
|
|
11
|
+
const source = IN_SANDBOX.exec(from);
|
|
12
|
+
const target = IN_SANDBOX.exec(to);
|
|
13
|
+
if (Boolean(source) === Boolean(target))
|
|
14
|
+
return { problem: "name the sandbox on one side only, as <ID>:<path>" };
|
|
15
|
+
const [, id, path] = (source ?? target);
|
|
16
|
+
return {
|
|
17
|
+
id: id,
|
|
18
|
+
inSandbox: posix.resolve(SANDBOX_WORKSPACE, path),
|
|
19
|
+
local: source ? to : from,
|
|
20
|
+
into: !source,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=sandbox.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sandbox.js","sourceRoot":"","sources":["../src/sandbox.ts"],"names":[],"mappings":"AAAA,mHAAmH;AACnH,8FAA8F;AAC9F,OAAO,EAAE,KAAK,EAAE,MAAM,WAAW,CAAC;AAElC,wDAAwD;AACxD,MAAM,CAAC,MAAM,iBAAiB,GAAG,YAAY,CAAC;AAc9C,MAAM,UAAU,GAAG,uBAAuB,CAAC;AAE3C,gGAAgG;AAChG,MAAM,UAAU,QAAQ,CAAC,IAAwB,EAAE,EAAsB;IACvE,IAAI,CAAC,IAAI,IAAI,CAAC,EAAE;QAAE,OAAO,EAAE,OAAO,EAAE,kEAAkE,EAAE,CAAC;IACzG,MAAM,MAAM,GAAG,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACrC,MAAM,MAAM,GAAG,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACnC,IAAI,OAAO,CAAC,MAAM,CAAC,KAAK,OAAO,CAAC,MAAM,CAAC;QAAE,OAAO,EAAE,OAAO,EAAE,mDAAmD,EAAE,CAAC;IACjH,MAAM,CAAC,EAAE,EAAE,EAAE,IAAI,CAAC,GAAG,CAAC,MAAM,IAAI,MAAM,CAAoB,CAAC;IAC3D,OAAO;QACL,EAAE,EAAE,EAAY;QAChB,SAAS,EAAE,KAAK,CAAC,OAAO,CAAC,iBAAiB,EAAE,IAAc,CAAC;QAC3D,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI;QACzB,IAAI,EAAE,CAAC,MAAM;KACd,CAAC;AACJ,CAAC"}
|
|
@@ -186,7 +186,7 @@
|
|
|
186
186
|
"items": {
|
|
187
187
|
"type": "string"
|
|
188
188
|
},
|
|
189
|
-
"description": "
|
|
189
|
+
"description": "The agent's skills: each a path to a skill folder, or a folder of another Git repository at a ref,\n`git+<url>#<ref>:<path>`, which `factory plan` pins in factory.lock (ADR 0146)."
|
|
190
190
|
},
|
|
191
191
|
"secrets": {
|
|
192
192
|
"type": "array",
|
|
@@ -101,6 +101,38 @@
|
|
|
101
101
|
}
|
|
102
102
|
},
|
|
103
103
|
"description": "The adapters under `providers` that `factory plan --adapters` pinned, per port and adapter name (ADR 0125). A pin\ncounts only while its `range` is the range factory.yaml declares."
|
|
104
|
+
},
|
|
105
|
+
"skills": {
|
|
106
|
+
"type": "object",
|
|
107
|
+
"properties": {},
|
|
108
|
+
"unevaluatedProperties": {
|
|
109
|
+
"type": "object",
|
|
110
|
+
"properties": {
|
|
111
|
+
"source": {
|
|
112
|
+
"type": "string",
|
|
113
|
+
"pattern": "^git\\+.+#[^:]+:.+$",
|
|
114
|
+
"description": "The entry of `skills` in factory.yaml that the pin was resolved from, `git+<url>#<ref>:<path>`."
|
|
115
|
+
},
|
|
116
|
+
"commit": {
|
|
117
|
+
"type": "string",
|
|
118
|
+
"pattern": "^([0-9a-f]{40}|[0-9a-f]{64})$",
|
|
119
|
+
"description": "The full commit, 40 hexadecimal characters, or 64 in a repository of SHA-256."
|
|
120
|
+
},
|
|
121
|
+
"hash": {
|
|
122
|
+
"type": "string",
|
|
123
|
+
"pattern": "^h1:[A-Za-z0-9+/]{43}=$",
|
|
124
|
+
"description": "The hash of the skill folder's files in the form of Go's modules: \"h1:\" and the base64 of a SHA-256."
|
|
125
|
+
}
|
|
126
|
+
},
|
|
127
|
+
"required": [
|
|
128
|
+
"source",
|
|
129
|
+
"commit",
|
|
130
|
+
"hash"
|
|
131
|
+
],
|
|
132
|
+
"description": "One skill of another Git repository at the commit its ref had when `factory plan` pinned it.",
|
|
133
|
+
"additionalProperties": false
|
|
134
|
+
},
|
|
135
|
+
"description": "The skills of other Git repositories that `factory plan` pinned, by the skill's name (ADR 0146). A pin counts only\nwhile its `source` is the entry factory.yaml declares; the foreman and `factory render` fetch its commit and check\nits hash."
|
|
104
136
|
}
|
|
105
137
|
},
|
|
106
138
|
"required": [
|
package/openapi/openapi.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"openapi": "3.1.0",
|
|
3
3
|
"info": {
|
|
4
4
|
"title": "Open Software Factory contracts",
|
|
5
|
-
"version": "2.
|
|
5
|
+
"version": "2.6.0",
|
|
6
6
|
"description": "The shared formats as named models, and the HTTP APIs of the modules. Generated by `pnpm build` in contracts/ from typespec/. Do not edit.",
|
|
7
7
|
"license": {
|
|
8
8
|
"name": "Apache-2.0",
|
|
@@ -1042,7 +1042,7 @@
|
|
|
1042
1042
|
"items": {
|
|
1043
1043
|
"type": "string"
|
|
1044
1044
|
},
|
|
1045
|
-
"description": "
|
|
1045
|
+
"description": "The agent's skills: each a path to a skill folder, or a folder of another Git repository at a ref,\n`git+<url>#<ref>:<path>`, which `factory plan` pins in factory.lock (ADR 0146)."
|
|
1046
1046
|
},
|
|
1047
1047
|
"secrets": {
|
|
1048
1048
|
"type": "array",
|
|
@@ -1203,6 +1203,128 @@
|
|
|
1203
1203
|
"pattern": "^(?!/)(?!.*(^|/)\\.\\.(/|$))[^\\\\]+$",
|
|
1204
1204
|
"description": "A path inside the bundle: relative, forward slashes, no \"..\"."
|
|
1205
1205
|
},
|
|
1206
|
+
"CatalogSkill": {
|
|
1207
|
+
"type": "object",
|
|
1208
|
+
"properties": {
|
|
1209
|
+
"name": {
|
|
1210
|
+
"type": "string",
|
|
1211
|
+
"minLength": 1,
|
|
1212
|
+
"description": "The last segment of the skill's folder."
|
|
1213
|
+
},
|
|
1214
|
+
"description": {
|
|
1215
|
+
"anyOf": [
|
|
1216
|
+
{
|
|
1217
|
+
"type": "string"
|
|
1218
|
+
},
|
|
1219
|
+
{
|
|
1220
|
+
"type": "null"
|
|
1221
|
+
}
|
|
1222
|
+
],
|
|
1223
|
+
"description": "The description of its front matter; null without one."
|
|
1224
|
+
},
|
|
1225
|
+
"source": {
|
|
1226
|
+
"$ref": "#/components/schemas/CatalogSkillSource",
|
|
1227
|
+
"description": "Where the skill comes from."
|
|
1228
|
+
},
|
|
1229
|
+
"needs": {
|
|
1230
|
+
"$ref": "#/components/schemas/SkillNeeds",
|
|
1231
|
+
"description": "What it needs, from the `metadata` of its front matter."
|
|
1232
|
+
},
|
|
1233
|
+
"agents": {
|
|
1234
|
+
"type": "array",
|
|
1235
|
+
"items": {
|
|
1236
|
+
"$ref": "#/components/schemas/CatalogSkillAgent"
|
|
1237
|
+
},
|
|
1238
|
+
"description": "Each agent that uses it, sorted by name."
|
|
1239
|
+
},
|
|
1240
|
+
"files": {
|
|
1241
|
+
"type": "array",
|
|
1242
|
+
"items": {
|
|
1243
|
+
"type": "string"
|
|
1244
|
+
},
|
|
1245
|
+
"description": "The files of its folder, by their path below it, sorted."
|
|
1246
|
+
},
|
|
1247
|
+
"body": {
|
|
1248
|
+
"anyOf": [
|
|
1249
|
+
{
|
|
1250
|
+
"type": "string"
|
|
1251
|
+
},
|
|
1252
|
+
{
|
|
1253
|
+
"type": "null"
|
|
1254
|
+
}
|
|
1255
|
+
],
|
|
1256
|
+
"description": "The text of SKILL.md below the line that ends its front matter, all of it without front matter; null without a\nSKILL.md that is UTF-8 text."
|
|
1257
|
+
},
|
|
1258
|
+
"problems": {
|
|
1259
|
+
"type": "array",
|
|
1260
|
+
"items": {
|
|
1261
|
+
"type": "string"
|
|
1262
|
+
},
|
|
1263
|
+
"description": "The problems of its own files as `factory lint` prints them, relative to the folder of factory.yaml, and a folder\nwithout a SKILL.md."
|
|
1264
|
+
}
|
|
1265
|
+
},
|
|
1266
|
+
"required": [
|
|
1267
|
+
"name",
|
|
1268
|
+
"description",
|
|
1269
|
+
"source",
|
|
1270
|
+
"needs",
|
|
1271
|
+
"agents",
|
|
1272
|
+
"files",
|
|
1273
|
+
"body",
|
|
1274
|
+
"problems"
|
|
1275
|
+
],
|
|
1276
|
+
"description": "One skill, also one that lint refuses: then `problems` names why."
|
|
1277
|
+
},
|
|
1278
|
+
"CatalogSkillAgent": {
|
|
1279
|
+
"type": "object",
|
|
1280
|
+
"properties": {
|
|
1281
|
+
"name": {
|
|
1282
|
+
"type": "string",
|
|
1283
|
+
"minLength": 1
|
|
1284
|
+
},
|
|
1285
|
+
"secrets": {
|
|
1286
|
+
"type": "object",
|
|
1287
|
+
"properties": {},
|
|
1288
|
+
"unevaluatedProperties": {
|
|
1289
|
+
"$ref": "#/components/schemas/SecretReference"
|
|
1290
|
+
},
|
|
1291
|
+
"description": "The agent's reference whose variable is each secret the skill needs, by the variable."
|
|
1292
|
+
},
|
|
1293
|
+
"lacks": {
|
|
1294
|
+
"$ref": "#/components/schemas/SkillNeeds",
|
|
1295
|
+
"description": "Each needed secret the agent does not declare, and each needed host its sandbox does not allow."
|
|
1296
|
+
}
|
|
1297
|
+
},
|
|
1298
|
+
"required": [
|
|
1299
|
+
"name",
|
|
1300
|
+
"secrets",
|
|
1301
|
+
"lacks"
|
|
1302
|
+
],
|
|
1303
|
+
"description": "An agent that uses a skill."
|
|
1304
|
+
},
|
|
1305
|
+
"CatalogSkillSource": {
|
|
1306
|
+
"type": "object",
|
|
1307
|
+
"properties": {
|
|
1308
|
+
"folder": {
|
|
1309
|
+
"type": "string",
|
|
1310
|
+
"minLength": 1
|
|
1311
|
+
},
|
|
1312
|
+
"repository": {
|
|
1313
|
+
"type": "string",
|
|
1314
|
+
"minLength": 1,
|
|
1315
|
+
"description": "The URL of the other Git repository, as the entry `git+<url>#<ref>:<path>` names it."
|
|
1316
|
+
},
|
|
1317
|
+
"commit": {
|
|
1318
|
+
"type": "string",
|
|
1319
|
+
"pattern": "^([0-9a-f]{40}|[0-9a-f]{64})$",
|
|
1320
|
+
"description": "The commit of the other repository that factory.lock pins; none while factory.lock has no pin."
|
|
1321
|
+
}
|
|
1322
|
+
},
|
|
1323
|
+
"required": [
|
|
1324
|
+
"folder"
|
|
1325
|
+
],
|
|
1326
|
+
"description": "A folder of the factory's repository, relative to the folder of factory.yaml, like \"skills/release-notes\"; or, for a\nskill of another Git repository, its folder there with the repository's URL and the commit factory.lock pins\n(ADR 0146)."
|
|
1327
|
+
},
|
|
1206
1328
|
"CheckName": {
|
|
1207
1329
|
"type": "string",
|
|
1208
1330
|
"minLength": 1,
|
|
@@ -1513,6 +1635,14 @@
|
|
|
1513
1635
|
}
|
|
1514
1636
|
},
|
|
1515
1637
|
"description": "The adapters under `providers` that `factory plan --adapters` pinned, per port and adapter name (ADR 0125). A pin\ncounts only while its `range` is the range factory.yaml declares."
|
|
1638
|
+
},
|
|
1639
|
+
"skills": {
|
|
1640
|
+
"type": "object",
|
|
1641
|
+
"properties": {},
|
|
1642
|
+
"unevaluatedProperties": {
|
|
1643
|
+
"$ref": "#/components/schemas/FactoryLockSkillPin"
|
|
1644
|
+
},
|
|
1645
|
+
"description": "The skills of other Git repositories that `factory plan` pinned, by the skill's name (ADR 0146). A pin counts only\nwhile its `source` is the entry factory.yaml declares; the foreman and `factory render` fetch its commit and check\nits hash."
|
|
1516
1646
|
}
|
|
1517
1647
|
},
|
|
1518
1648
|
"required": [
|
|
@@ -1599,6 +1729,33 @@
|
|
|
1599
1729
|
],
|
|
1600
1730
|
"description": "One registry MCP server at its exact version, with the npm package or the remote it starts."
|
|
1601
1731
|
},
|
|
1732
|
+
"FactoryLockSkillPin": {
|
|
1733
|
+
"type": "object",
|
|
1734
|
+
"properties": {
|
|
1735
|
+
"source": {
|
|
1736
|
+
"type": "string",
|
|
1737
|
+
"pattern": "^git\\+.+#[^:]+:.+$",
|
|
1738
|
+
"description": "The entry of `skills` in factory.yaml that the pin was resolved from, `git+<url>#<ref>:<path>`."
|
|
1739
|
+
},
|
|
1740
|
+
"commit": {
|
|
1741
|
+
"type": "string",
|
|
1742
|
+
"pattern": "^([0-9a-f]{40}|[0-9a-f]{64})$",
|
|
1743
|
+
"description": "The full commit, 40 hexadecimal characters, or 64 in a repository of SHA-256."
|
|
1744
|
+
},
|
|
1745
|
+
"hash": {
|
|
1746
|
+
"type": "string",
|
|
1747
|
+
"pattern": "^h1:[A-Za-z0-9+/]{43}=$",
|
|
1748
|
+
"description": "The hash of the skill folder's files in the form of Go's modules: \"h1:\" and the base64 of a SHA-256."
|
|
1749
|
+
}
|
|
1750
|
+
},
|
|
1751
|
+
"required": [
|
|
1752
|
+
"source",
|
|
1753
|
+
"commit",
|
|
1754
|
+
"hash"
|
|
1755
|
+
],
|
|
1756
|
+
"description": "One skill of another Git repository at the commit its ref had when `factory plan` pinned it.",
|
|
1757
|
+
"additionalProperties": false
|
|
1758
|
+
},
|
|
1602
1759
|
"FormatVersion": {
|
|
1603
1760
|
"type": "integer",
|
|
1604
1761
|
"minimum": 1,
|
|
@@ -3707,6 +3864,53 @@
|
|
|
3707
3864
|
"type": "string",
|
|
3708
3865
|
"pattern": "^[0-9a-f]{64}$"
|
|
3709
3866
|
},
|
|
3867
|
+
"SkillCatalog": {
|
|
3868
|
+
"type": "object",
|
|
3869
|
+
"properties": {
|
|
3870
|
+
"skills": {
|
|
3871
|
+
"type": "array",
|
|
3872
|
+
"items": {
|
|
3873
|
+
"$ref": "#/components/schemas/CatalogSkill"
|
|
3874
|
+
}
|
|
3875
|
+
}
|
|
3876
|
+
},
|
|
3877
|
+
"required": [
|
|
3878
|
+
"skills"
|
|
3879
|
+
],
|
|
3880
|
+
"description": "What `factory skills` of factory-spec prints (ADR 0141, ADR 0143): every skill the factory's agents use, read with\nthe rules of `factory lint` (ADR 0140), sorted by name. The console reads it for its pages `/skills` and\n`/skills/<name>`, so it never parses a SKILL.md itself."
|
|
3881
|
+
},
|
|
3882
|
+
"SkillHost": {
|
|
3883
|
+
"type": "string",
|
|
3884
|
+
"pattern": "^[a-z0-9-]+(\\.[a-z0-9-]+)*$",
|
|
3885
|
+
"description": "A host as an entry of `sandbox.egress`, like \"api.linear.app\"."
|
|
3886
|
+
},
|
|
3887
|
+
"SkillNeeds": {
|
|
3888
|
+
"type": "object",
|
|
3889
|
+
"properties": {
|
|
3890
|
+
"secrets": {
|
|
3891
|
+
"type": "array",
|
|
3892
|
+
"items": {
|
|
3893
|
+
"$ref": "#/components/schemas/SkillSecretName"
|
|
3894
|
+
}
|
|
3895
|
+
},
|
|
3896
|
+
"hosts": {
|
|
3897
|
+
"type": "array",
|
|
3898
|
+
"items": {
|
|
3899
|
+
"$ref": "#/components/schemas/SkillHost"
|
|
3900
|
+
}
|
|
3901
|
+
}
|
|
3902
|
+
},
|
|
3903
|
+
"required": [
|
|
3904
|
+
"secrets",
|
|
3905
|
+
"hosts"
|
|
3906
|
+
],
|
|
3907
|
+
"description": "The secrets a skill needs, by the variable that holds each in a sandbox, and the hosts it reaches (ADR 0140)."
|
|
3908
|
+
},
|
|
3909
|
+
"SkillSecretName": {
|
|
3910
|
+
"type": "string",
|
|
3911
|
+
"pattern": "^[A-Z0-9_]+$",
|
|
3912
|
+
"description": "The variable of a secret in a sandbox (ADR 0068), like \"LINEAR_TOKEN\"."
|
|
3913
|
+
},
|
|
3710
3914
|
"Stage": {
|
|
3711
3915
|
"type": "object",
|
|
3712
3916
|
"properties": {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@opensoftware/contracts",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.6.0",
|
|
4
4
|
"description": "The shared formats of the open software factory: JSON Schemas, TypeScript types and the osf-contracts CLI.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
"@typespec/openapi": "1.17.0",
|
|
45
45
|
"@typespec/openapi3": "1.17.0",
|
|
46
46
|
"openapi-typescript": "7.13.0",
|
|
47
|
-
"@opensoftware/testkit": "0.
|
|
47
|
+
"@opensoftware/testkit": "0.39.0"
|
|
48
48
|
},
|
|
49
49
|
"scripts": {
|
|
50
50
|
"build": "node scripts/build.ts",
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://raw.githubusercontent.com/sesigl/open-software-factory/main/contracts/skill-catalog/skill-catalog.schema.json",
|
|
4
|
+
"title": "SkillCatalog",
|
|
5
|
+
"$comment": "Generated by `pnpm build` in contracts/ from typespec/. Do not edit.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"properties": {
|
|
8
|
+
"skills": {
|
|
9
|
+
"type": "array",
|
|
10
|
+
"items": {
|
|
11
|
+
"type": "object",
|
|
12
|
+
"properties": {
|
|
13
|
+
"name": {
|
|
14
|
+
"type": "string",
|
|
15
|
+
"minLength": 1,
|
|
16
|
+
"description": "The last segment of the skill's folder."
|
|
17
|
+
},
|
|
18
|
+
"description": {
|
|
19
|
+
"anyOf": [
|
|
20
|
+
{
|
|
21
|
+
"type": "string"
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"type": "null"
|
|
25
|
+
}
|
|
26
|
+
],
|
|
27
|
+
"description": "The description of its front matter; null without one."
|
|
28
|
+
},
|
|
29
|
+
"source": {
|
|
30
|
+
"type": "object",
|
|
31
|
+
"properties": {
|
|
32
|
+
"folder": {
|
|
33
|
+
"type": "string",
|
|
34
|
+
"minLength": 1
|
|
35
|
+
},
|
|
36
|
+
"repository": {
|
|
37
|
+
"type": "string",
|
|
38
|
+
"minLength": 1,
|
|
39
|
+
"description": "The URL of the other Git repository, as the entry `git+<url>#<ref>:<path>` names it."
|
|
40
|
+
},
|
|
41
|
+
"commit": {
|
|
42
|
+
"type": "string",
|
|
43
|
+
"pattern": "^([0-9a-f]{40}|[0-9a-f]{64})$",
|
|
44
|
+
"description": "The commit of the other repository that factory.lock pins; none while factory.lock has no pin."
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
"required": [
|
|
48
|
+
"folder"
|
|
49
|
+
],
|
|
50
|
+
"description": "Where the skill comes from."
|
|
51
|
+
},
|
|
52
|
+
"needs": {
|
|
53
|
+
"type": "object",
|
|
54
|
+
"properties": {
|
|
55
|
+
"secrets": {
|
|
56
|
+
"type": "array",
|
|
57
|
+
"items": {
|
|
58
|
+
"type": "string",
|
|
59
|
+
"pattern": "^[A-Z0-9_]+$",
|
|
60
|
+
"description": "The variable of a secret in a sandbox (ADR 0068), like \"LINEAR_TOKEN\"."
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
"hosts": {
|
|
64
|
+
"type": "array",
|
|
65
|
+
"items": {
|
|
66
|
+
"type": "string",
|
|
67
|
+
"pattern": "^[a-z0-9-]+(\\.[a-z0-9-]+)*$",
|
|
68
|
+
"description": "A host as an entry of `sandbox.egress`, like \"api.linear.app\"."
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
"required": [
|
|
73
|
+
"secrets",
|
|
74
|
+
"hosts"
|
|
75
|
+
],
|
|
76
|
+
"description": "What it needs, from the `metadata` of its front matter."
|
|
77
|
+
},
|
|
78
|
+
"agents": {
|
|
79
|
+
"type": "array",
|
|
80
|
+
"items": {
|
|
81
|
+
"type": "object",
|
|
82
|
+
"properties": {
|
|
83
|
+
"name": {
|
|
84
|
+
"type": "string",
|
|
85
|
+
"minLength": 1
|
|
86
|
+
},
|
|
87
|
+
"secrets": {
|
|
88
|
+
"type": "object",
|
|
89
|
+
"properties": {},
|
|
90
|
+
"unevaluatedProperties": {
|
|
91
|
+
"type": "string",
|
|
92
|
+
"pattern": "^ref:[a-z][a-z0-9-]*/[A-Za-z0-9_./-]+$",
|
|
93
|
+
"description": "A reference to a secret, resolved at the egress proxy, never in the sandbox: \"ref:<provider>/<name>\"."
|
|
94
|
+
},
|
|
95
|
+
"description": "The agent's reference whose variable is each secret the skill needs, by the variable."
|
|
96
|
+
},
|
|
97
|
+
"lacks": {
|
|
98
|
+
"type": "object",
|
|
99
|
+
"properties": {
|
|
100
|
+
"secrets": {
|
|
101
|
+
"type": "array",
|
|
102
|
+
"items": {
|
|
103
|
+
"type": "string",
|
|
104
|
+
"pattern": "^[A-Z0-9_]+$",
|
|
105
|
+
"description": "The variable of a secret in a sandbox (ADR 0068), like \"LINEAR_TOKEN\"."
|
|
106
|
+
}
|
|
107
|
+
},
|
|
108
|
+
"hosts": {
|
|
109
|
+
"type": "array",
|
|
110
|
+
"items": {
|
|
111
|
+
"type": "string",
|
|
112
|
+
"pattern": "^[a-z0-9-]+(\\.[a-z0-9-]+)*$",
|
|
113
|
+
"description": "A host as an entry of `sandbox.egress`, like \"api.linear.app\"."
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
},
|
|
117
|
+
"required": [
|
|
118
|
+
"secrets",
|
|
119
|
+
"hosts"
|
|
120
|
+
],
|
|
121
|
+
"description": "Each needed secret the agent does not declare, and each needed host its sandbox does not allow."
|
|
122
|
+
}
|
|
123
|
+
},
|
|
124
|
+
"required": [
|
|
125
|
+
"name",
|
|
126
|
+
"secrets",
|
|
127
|
+
"lacks"
|
|
128
|
+
],
|
|
129
|
+
"description": "An agent that uses a skill."
|
|
130
|
+
},
|
|
131
|
+
"description": "Each agent that uses it, sorted by name."
|
|
132
|
+
},
|
|
133
|
+
"files": {
|
|
134
|
+
"type": "array",
|
|
135
|
+
"items": {
|
|
136
|
+
"type": "string"
|
|
137
|
+
},
|
|
138
|
+
"description": "The files of its folder, by their path below it, sorted."
|
|
139
|
+
},
|
|
140
|
+
"body": {
|
|
141
|
+
"anyOf": [
|
|
142
|
+
{
|
|
143
|
+
"type": "string"
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
"type": "null"
|
|
147
|
+
}
|
|
148
|
+
],
|
|
149
|
+
"description": "The text of SKILL.md below the line that ends its front matter, all of it without front matter; null without a\nSKILL.md that is UTF-8 text."
|
|
150
|
+
},
|
|
151
|
+
"problems": {
|
|
152
|
+
"type": "array",
|
|
153
|
+
"items": {
|
|
154
|
+
"type": "string"
|
|
155
|
+
},
|
|
156
|
+
"description": "The problems of its own files as `factory lint` prints them, relative to the folder of factory.yaml, and a folder\nwithout a SKILL.md."
|
|
157
|
+
}
|
|
158
|
+
},
|
|
159
|
+
"required": [
|
|
160
|
+
"name",
|
|
161
|
+
"description",
|
|
162
|
+
"source",
|
|
163
|
+
"needs",
|
|
164
|
+
"agents",
|
|
165
|
+
"files",
|
|
166
|
+
"body",
|
|
167
|
+
"problems"
|
|
168
|
+
],
|
|
169
|
+
"description": "One skill, also one that lint refuses: then `problems` names why."
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
},
|
|
173
|
+
"required": [
|
|
174
|
+
"skills"
|
|
175
|
+
],
|
|
176
|
+
"description": "What `factory skills` of factory-spec prints (ADR 0141, ADR 0143): every skill the factory's agents use, read with\nthe rules of `factory lint` (ADR 0140), sorted by name. The console reads it for its pages `/skills` and\n`/skills/<name>`, so it never parses a SKILL.md itself."
|
|
177
|
+
}
|
|
@@ -110,7 +110,10 @@ model Agent {
|
|
|
110
110
|
/** MCP servers: `registry:<name>@<version>` or `<name>@<version>`. */
|
|
111
111
|
mcp?: string[];
|
|
112
112
|
|
|
113
|
-
/**
|
|
113
|
+
/**
|
|
114
|
+
* The agent's skills: each a path to a skill folder, or a folder of another Git repository at a ref,
|
|
115
|
+
* `git+<url>#<ref>:<path>`, which `factory plan` pins in factory.lock (ADR 0146).
|
|
116
|
+
*/
|
|
114
117
|
skills?: string[];
|
|
115
118
|
|
|
116
119
|
secrets?: SecretReference[];
|
|
@@ -21,6 +21,29 @@ model FactoryLock {
|
|
|
21
21
|
* counts only while its `range` is the range factory.yaml declares.
|
|
22
22
|
*/
|
|
23
23
|
adapters?: Record<Record<FactoryLockAdapterPin>>;
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* The skills of other Git repositories that `factory plan` pinned, by the skill's name (ADR 0146). A pin counts only
|
|
27
|
+
* while its `source` is the entry factory.yaml declares; the foreman and `factory render` fetch its commit and check
|
|
28
|
+
* its hash.
|
|
29
|
+
*/
|
|
30
|
+
skills?: Record<FactoryLockSkillPin>;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** One skill of another Git repository at the commit its ref had when `factory plan` pinned it. */
|
|
34
|
+
@extension("additionalProperties", Json<false>)
|
|
35
|
+
model FactoryLockSkillPin {
|
|
36
|
+
/** The entry of `skills` in factory.yaml that the pin was resolved from, `git+<url>#<ref>:<path>`. */
|
|
37
|
+
@pattern("^git\\+.+#[^:]+:.+$")
|
|
38
|
+
source: string;
|
|
39
|
+
|
|
40
|
+
/** The full commit, 40 hexadecimal characters, or 64 in a repository of SHA-256. */
|
|
41
|
+
@pattern("^([0-9a-f]{40}|[0-9a-f]{64})$")
|
|
42
|
+
commit: string;
|
|
43
|
+
|
|
44
|
+
/** The hash of the skill folder's files in the form of Go's modules: "h1:" and the base64 of a SHA-256. */
|
|
45
|
+
@pattern("^h1:[A-Za-z0-9+/]{43}=$")
|
|
46
|
+
hash: string;
|
|
24
47
|
}
|
|
25
48
|
|
|
26
49
|
/** One registry MCP server at its exact version, with the npm package or the remote it starts. */
|
package/typespec/main.tsp
CHANGED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import "@typespec/json-schema";
|
|
2
|
+
import "./common.tsp";
|
|
3
|
+
import "./factory-definition.tsp";
|
|
4
|
+
|
|
5
|
+
using TypeSpec.JsonSchema;
|
|
6
|
+
|
|
7
|
+
namespace Osf.Contracts;
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* What `factory skills` of factory-spec prints (ADR 0141, ADR 0143): every skill the factory's agents use, read with
|
|
11
|
+
* the rules of `factory lint` (ADR 0140), sorted by name. The console reads it for its pages `/skills` and
|
|
12
|
+
* `/skills/<name>`, so it never parses a SKILL.md itself.
|
|
13
|
+
*/
|
|
14
|
+
model SkillCatalog {
|
|
15
|
+
skills: CatalogSkill[];
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/** One skill, also one that lint refuses: then `problems` names why. */
|
|
19
|
+
model CatalogSkill {
|
|
20
|
+
/** The last segment of the skill's folder. */
|
|
21
|
+
@minLength(1)
|
|
22
|
+
name: string;
|
|
23
|
+
|
|
24
|
+
/** The description of its front matter; null without one. */
|
|
25
|
+
description: string | null;
|
|
26
|
+
|
|
27
|
+
/** Where the skill comes from. */
|
|
28
|
+
source: CatalogSkillSource;
|
|
29
|
+
|
|
30
|
+
/** What it needs, from the `metadata` of its front matter. */
|
|
31
|
+
needs: SkillNeeds;
|
|
32
|
+
|
|
33
|
+
/** Each agent that uses it, sorted by name. */
|
|
34
|
+
agents: CatalogSkillAgent[];
|
|
35
|
+
|
|
36
|
+
/** The files of its folder, by their path below it, sorted. */
|
|
37
|
+
files: string[];
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* The text of SKILL.md below the line that ends its front matter, all of it without front matter; null without a
|
|
41
|
+
* SKILL.md that is UTF-8 text.
|
|
42
|
+
*/
|
|
43
|
+
body: string | null;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* The problems of its own files as `factory lint` prints them, relative to the folder of factory.yaml, and a folder
|
|
47
|
+
* without a SKILL.md.
|
|
48
|
+
*/
|
|
49
|
+
problems: string[];
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* A folder of the factory's repository, relative to the folder of factory.yaml, like "skills/release-notes"; or, for a
|
|
54
|
+
* skill of another Git repository, its folder there with the repository's URL and the commit factory.lock pins
|
|
55
|
+
* (ADR 0146).
|
|
56
|
+
*/
|
|
57
|
+
model CatalogSkillSource {
|
|
58
|
+
@minLength(1)
|
|
59
|
+
folder: string;
|
|
60
|
+
|
|
61
|
+
/** The URL of the other Git repository, as the entry `git+<url>#<ref>:<path>` names it. */
|
|
62
|
+
@minLength(1)
|
|
63
|
+
repository?: string;
|
|
64
|
+
|
|
65
|
+
/** The commit of the other repository that factory.lock pins; none while factory.lock has no pin. */
|
|
66
|
+
@pattern("^([0-9a-f]{40}|[0-9a-f]{64})$")
|
|
67
|
+
commit?: string;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/** The secrets a skill needs, by the variable that holds each in a sandbox, and the hosts it reaches (ADR 0140). */
|
|
71
|
+
model SkillNeeds {
|
|
72
|
+
secrets: SkillSecretName[];
|
|
73
|
+
hosts: SkillHost[];
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/** An agent that uses a skill. */
|
|
77
|
+
model CatalogSkillAgent {
|
|
78
|
+
@minLength(1)
|
|
79
|
+
name: string;
|
|
80
|
+
|
|
81
|
+
/** The agent's reference whose variable is each secret the skill needs, by the variable. */
|
|
82
|
+
secrets: Record<SecretReference>;
|
|
83
|
+
|
|
84
|
+
/** Each needed secret the agent does not declare, and each needed host its sandbox does not allow. */
|
|
85
|
+
lacks: SkillNeeds;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/** The variable of a secret in a sandbox (ADR 0068), like "LINEAR_TOKEN". */
|
|
89
|
+
@pattern("^[A-Z0-9_]+$")
|
|
90
|
+
scalar SkillSecretName extends string;
|
|
91
|
+
|
|
92
|
+
/** A host as an entry of `sandbox.egress`, like "api.linear.app". */
|
|
93
|
+
@pattern("^[a-z0-9-]+(\\.[a-z0-9-]+)*$")
|
|
94
|
+
scalar SkillHost extends string;
|