@awebai/oats 0.22.0 → 0.22.2

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 (60) hide show
  1. package/README.md +40 -50
  2. package/bin/oats.mjs +242 -22
  3. package/capabilities/oats-authoring/LICENSE +21 -0
  4. package/capabilities/oats-authoring/oats-package.json +11 -0
  5. package/capabilities/oats-authoring/oats.json +4 -4
  6. package/capabilities/oats-authoring/skills/integration-authoring/SKILL.md +63 -0
  7. package/capabilities/oats-authoring/skills/skill-craft/SKILL.md +109 -0
  8. package/capabilities/oats-authoring/skills/soul-craft/SKILL.md +109 -0
  9. package/capabilities/oats-aweb/injects/aweb.md +4 -3
  10. package/capabilities/oats-aweb/oats.json +7 -7
  11. package/capabilities/oats-aweb/skills/LICENSE +21 -0
  12. package/capabilities/oats-aweb/skills/VENDORED.md +26 -0
  13. package/capabilities/oats-aweb/skills/aweb-identity/SKILL.md +201 -0
  14. package/capabilities/oats-aweb/skills/aweb-messaging/SKILL.md +161 -0
  15. package/capabilities/oats-aweb/skills/aweb-messaging/references/messaging-scenarios.md +61 -0
  16. package/capabilities/oats-aweb/skills/aweb-team-membership/SKILL.md +328 -0
  17. package/capabilities/oats-aweb/skills/aweb-team-membership/references/team-membership-reference.md +74 -0
  18. package/capabilities/oats-jira/oats.json +1 -1
  19. package/capabilities/oats-linear/oats.json +1 -1
  20. package/capabilities/oats-okf/agents/{memory-harvest.md → memory-harvest/AGENTS.md} +3 -1
  21. package/capabilities/oats-okf/agents/memory-harvest/soul.yaml +6 -0
  22. package/capabilities/oats-okf/bin/oats-okf.mjs +201 -54
  23. package/capabilities/oats-okf/injects/okf.md +7 -0
  24. package/capabilities/oats-okf/oats.json +5 -2
  25. package/capabilities/oats-okf/skills/memory-harvest/SKILL.md +42 -1
  26. package/capabilities/oats-review/oats.json +1 -1
  27. package/docs/2026-09-03-architecture-proposal.md +642 -0
  28. package/docs/execution-targets.md +181 -0
  29. package/docs/first-team-demo.md +87 -0
  30. package/docs/first-team.md +179 -0
  31. package/docs/implementation.md +14 -1
  32. package/docs/integrations.md +83 -65
  33. package/docs/layers.md +356 -80
  34. package/docs/migration-from-oas.md +80 -116
  35. package/docs/oats-config.schema.json +1 -0
  36. package/docs/operating-team-migration.md +217 -0
  37. package/docs/release-notes/v0.22.1.md +106 -0
  38. package/docs/release-notes/v0.22.2.md +69 -0
  39. package/docs/servers.md +94 -0
  40. package/docs/souls-and-instances.md +30 -3
  41. package/lib/core.mjs +626 -415
  42. package/lib/herdr.mjs +95 -0
  43. package/lib/servers.mjs +436 -0
  44. package/lib/session-input.mjs +78 -0
  45. package/lib/session-viewer.mjs +51 -0
  46. package/package-catalog.json +2 -2
  47. package/package.json +1 -1
  48. package/packages/record/README.md +76 -16
  49. package/packages/record/bin/capture.mjs +59 -3
  50. package/packages/record/bin/recall.mjs +67 -1
  51. package/packages/record/docs/turn-record-sot.md +1 -1
  52. package/packages/record/lib/sessions-for-home.mjs +130 -0
  53. package/packages/record/lib/store.mjs +207 -43
  54. package/skills/oats/SKILL.md +6 -2
  55. package/capabilities/oats-aweb/package.json +0 -20
  56. package/capabilities/oats-jira/package.json +0 -25
  57. package/capabilities/oats-linear/README.md +0 -234
  58. package/capabilities/oats-linear/package.json +0 -29
  59. package/capabilities/oats-linear/test/oats-linear.test.mjs +0 -168
  60. package/capabilities/oats-okf/package.json +0 -22
@@ -1,168 +0,0 @@
1
- import assert from "node:assert/strict";
2
- import { spawn } from "node:child_process";
3
- import { mkdtempSync, rmSync, writeFileSync } from "node:fs";
4
- import { createServer } from "node:http";
5
- import { tmpdir } from "node:os";
6
- import { join, resolve } from "node:path";
7
- import test from "node:test";
8
- import { fileURLToPath } from "node:url";
9
-
10
- const DIR = resolve(fileURLToPath(new URL("..", import.meta.url)));
11
- const CLI = join(DIR, "bin", "oats-linear.mjs");
12
- const HOOK = join(DIR, "bin", "oats-linear-hook.mjs");
13
-
14
- function run(script, args = [], env = {}) {
15
- return new Promise((done) => {
16
- const child = spawn(process.execPath, [script, ...args], {
17
- env: { ...process.env, ...env },
18
- stdio: ["ignore", "pipe", "pipe"],
19
- });
20
- let stdout = "";
21
- let stderr = "";
22
- child.stdout.on("data", (chunk) => { stdout += chunk; });
23
- child.stderr.on("data", (chunk) => { stderr += chunk; });
24
- child.on("close", (code) => done({ code, stdout, stderr }));
25
- });
26
- }
27
-
28
- async function mockApi(responder, fn) {
29
- const requests = [];
30
- const server = createServer(async (request, response) => {
31
- let body = "";
32
- for await (const chunk of request) body += chunk;
33
- const parsed = JSON.parse(body);
34
- requests.push({ headers: request.headers, ...parsed });
35
- const payload = await responder(parsed, requests);
36
- response.writeHead(payload.status || 200, { "content-type": "application/json" });
37
- response.end(JSON.stringify(payload.body || payload));
38
- });
39
- await new Promise((ready) => server.listen(0, "127.0.0.1", ready));
40
- const url = `http://127.0.0.1:${server.address().port}/graphql`;
41
- try { await fn({ url, requests }); }
42
- finally { await new Promise((closed) => server.close(closed)); }
43
- }
44
-
45
- const team = { id: "team-1", key: "ENG", name: "Engineering" };
46
- const issue = {
47
- id: "issue-1", identifier: "ENG-1", title: "Test issue", description: "body",
48
- url: "https://linear.app/issue/ENG-1", priority: 0, priorityLabel: "No priority",
49
- team, state: { id: "started-1", name: "In Progress", type: "started" },
50
- project: null, parent: null, assignee: { id: "human-1", name: "Human", email: "human@example.com" },
51
- labels: { nodes: [] },
52
- };
53
-
54
- function operation(query) { return query.match(/(?:query|mutation)\s+(\w+)/)?.[1]; }
55
-
56
- test("missing API key fails once with setup guidance", async () => {
57
- const result = await run(CLI, ["auth"], { LINEAR_API_KEY: "" });
58
- assert.equal(result.code, 1);
59
- assert.match(result.stderr, /LINEAR_API_KEY is not set/);
60
- assert.match(result.stderr, /Security & access/);
61
- });
62
-
63
- test("auth uses the personal-key Authorization header", async () => {
64
- await mockApi(() => ({ data: {
65
- viewer: { id: "user-1", name: "Human", email: "human@example.com" },
66
- organization: { id: "org-1", name: "Acme", urlKey: "acme" },
67
- } }), async ({ url, requests }) => {
68
- const result = await run(CLI, ["auth"], { LINEAR_API_KEY: "secret-key", LINEAR_API_URL: url });
69
- assert.equal(result.code, 0, result.stderr);
70
- assert.equal(JSON.parse(result.stdout).authenticated, true);
71
- assert.equal(requests[0].headers.authorization, "secret-key");
72
- assert.equal(operation(requests[0].query), "OatsLinearAuth");
73
- });
74
- });
75
-
76
- test("issue list builds an open agent/project filter", async () => {
77
- await mockApi(({ query }) => {
78
- if (operation(query) === "OatsLinearTeam") return { data: { teams: { nodes: [team] } } };
79
- if (operation(query) === "OatsLinearProjects") return { data: { projects: { nodes: [
80
- { id: "project-1", name: "Agent Platform", slugId: "agent-platform", status: { id: "ps-1", name: "Started", type: "started" }, teams: { nodes: [team] } },
81
- ] } } };
82
- if (operation(query) === "OatsLinearIssues") return { data: { issues: { nodes: [issue], pageInfo: { hasNextPage: false, endCursor: null } } } };
83
- throw new Error(`unexpected operation ${operation(query)}`);
84
- }, async ({ url, requests }) => {
85
- const result = await run(CLI, ["issue", "list", "--team", "ENG", "--agent", "worker-1", "--project", "Agent Platform"], {
86
- LINEAR_API_KEY: "key", LINEAR_API_URL: url,
87
- });
88
- assert.equal(result.code, 0, result.stderr);
89
- const listRequest = requests.find((request) => operation(request.query) === "OatsLinearIssues");
90
- assert.deepEqual(listRequest.variables.filter, {
91
- team: { id: { eq: "team-1" } },
92
- state: { type: { nin: ["completed", "canceled", "duplicate"] } },
93
- labels: { some: { name: { eqIgnoreCase: "agent-worker-1" } } },
94
- project: { id: { eq: "project-1" } },
95
- });
96
- });
97
- });
98
-
99
- test("issue create provisions the agent label and records identity", async () => {
100
- await mockApi(({ query, variables }) => {
101
- const op = operation(query);
102
- if (op === "OatsLinearTeam") return { data: { teams: { nodes: [team] } } };
103
- if (op === "OatsLinearLabels") return { data: { issueLabels: { nodes: [] } } };
104
- if (op === "OatsLinearCreateLabel") return { data: { issueLabelCreate: {
105
- success: true, issueLabel: { id: "label-1", name: variables.input.name, color: "#5E6AD2", team },
106
- } } };
107
- if (op === "OatsLinearIssueCreate") return { data: { issueCreate: { success: true, issue } } };
108
- throw new Error(`unexpected operation ${op}`);
109
- }, async ({ url, requests }) => {
110
- const result = await run(CLI, ["issue", "create", "--team", "ENG", "--title", "Bounded work", "--description", "Acceptance", "--agent", "worker-1"], {
111
- LINEAR_API_KEY: "key", LINEAR_API_URL: url,
112
- });
113
- assert.equal(result.code, 0, result.stderr);
114
- const create = requests.find((request) => operation(request.query) === "OatsLinearIssueCreate");
115
- assert.equal(create.variables.input.teamId, "team-1");
116
- assert.deepEqual(create.variables.input.labelIds, ["label-1"]);
117
- assert.match(create.variables.input.description, /Acceptance\n\n---\nAgent: worker-1/);
118
- });
119
- });
120
-
121
- test("terminal transitions require explicit authorization", async () => {
122
- await mockApi(({ query }) => {
123
- const op = operation(query);
124
- if (op === "OatsLinearIssue") return { data: { issue } };
125
- if (op === "OatsLinearStates") return { data: { team: { states: { nodes: [
126
- { id: "done-1", name: "Done", type: "completed", position: 1 },
127
- ] } } } };
128
- throw new Error(`unexpected operation ${op}`);
129
- }, async ({ url, requests }) => {
130
- const result = await run(CLI, ["issue", "update", "ENG-1", "--state", "Done"], {
131
- LINEAR_API_KEY: "key", LINEAR_API_URL: url,
132
- });
133
- assert.equal(result.code, 1);
134
- assert.match(result.stderr, /refusing terminal state/);
135
- assert.equal(requests.some((request) => operation(request.query) === "OatsLinearIssueUpdate"), false);
136
- });
137
- });
138
-
139
- test("comment accepts multiline markdown from a file", async () => {
140
- const temp = mkdtempSync(join(tmpdir(), "oats-linear-test-"));
141
- const bodyFile = join(temp, "comment.md");
142
- writeFileSync(bodyFile, "[worker-1] handoff: details\n\n- tests pass\n");
143
- try {
144
- await mockApi(({ query }) => {
145
- assert.equal(operation(query), "OatsLinearComment");
146
- return { data: { commentCreate: { success: true, comment: { id: "comment-1", body: "ok", createdAt: "2026-07-10", url: "https://linear.app/c/1", user: { id: "user-1", name: "Human" } } } } };
147
- }, async ({ url, requests }) => {
148
- const result = await run(CLI, ["issue", "comment", "ENG-1", "--body-file", bodyFile], {
149
- LINEAR_API_KEY: "key", LINEAR_API_URL: url,
150
- });
151
- assert.equal(result.code, 0, result.stderr);
152
- assert.equal(requests[0].variables.input.body, "[worker-1] handoff: details\n\n- tests pass");
153
- });
154
- } finally { rmSync(temp, { recursive: true, force: true }); }
155
- });
156
-
157
- test("spawn hook briefs settings and warns without auth", async () => {
158
- const result = await run(HOOK, ["spawn"], {
159
- OATS_EVENT: "spawn", OATS_INSTANCE: "worker-1",
160
- OATS_SETTINGS: JSON.stringify({ team: "ENG", project: "Agent Platform" }),
161
- LINEAR_API_KEY: "",
162
- });
163
- assert.equal(result.code, 0, result.stderr);
164
- const payload = JSON.parse(result.stdout);
165
- assert.deepEqual(payload.meta, { label: "agent-worker-1", team: "ENG", project: "Agent Platform" });
166
- assert.match(payload.brief, /team ENG, default project Agent Platform/);
167
- assert.match(payload.warning, /LINEAR_API_KEY/);
168
- });
@@ -1,22 +0,0 @@
1
- {
2
- "name": "@awebai/oats-okf",
3
- "version": "0.1.0",
4
- "description": "OATS knowledge provider: Open Knowledge Format (OKF) craft skill, bundle validator, and agents-md injection",
5
- "keywords": [
6
- "pi-package",
7
- "oats",
8
- "okf"
9
- ],
10
- "repository": {
11
- "type": "git",
12
- "url": "https://github.com/awebai/oats",
13
- "directory": "capabilities/oats-okf"
14
- },
15
- "license": "MIT",
16
- "type": "module",
17
- "pi": {
18
- "skills": [
19
- "./skills"
20
- ]
21
- }
22
- }