@aiwg/cli 2026.9.1 → 2026.9.3

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 (71) hide show
  1. package/agentic/code/providers/antigravity/provider-contract.v1.json +121 -0
  2. package/agentic/code/providers/capability-matrix.yaml +88 -2
  3. package/agentic/code/providers/model-capabilities.v1.json +42 -0
  4. package/agentic/code/providers/model-catalog.v1.json +37 -0
  5. package/agentic/code/providers/omp/README.md +58 -0
  6. package/agentic/code/providers/omp/aiwg-bridge.ts +52 -0
  7. package/agentic/code/providers/pi/aiwg-bridge.ts +26 -0
  8. package/dist/src/agents/agent-deployer.js +18 -0
  9. package/dist/src/agents/agent-packager.js +25 -0
  10. package/dist/src/artifacts/backends/sqlite-backend.js +18 -10
  11. package/dist/src/artifacts/query-engine.js +30 -0
  12. package/dist/src/auth/credential-store.js +6 -0
  13. package/dist/src/cli/agent-spawn.js +13 -2
  14. package/dist/src/cli/handlers/help.js +3 -1
  15. package/dist/src/cli/handlers/init.js +2 -0
  16. package/dist/src/cli/handlers/models.js +1 -1
  17. package/dist/src/cli/handlers/runtime-info.js +8 -1
  18. package/dist/src/cli/handlers/session.js +5 -4
  19. package/dist/src/cli/handlers/sessions.js +54 -19
  20. package/dist/src/cli/handlers/setup.js +9 -2
  21. package/dist/src/cli/handlers/steward.js +13 -2
  22. package/dist/src/cli/handlers/subcommands.js +11 -0
  23. package/dist/src/cli/handlers/team.js +68 -7
  24. package/dist/src/cli/handlers/use.js +121 -9
  25. package/dist/src/cli/scope-resolver.js +7 -0
  26. package/dist/src/config/aiwg-config.js +1 -0
  27. package/dist/src/dataset/fortemi-live-qualification.d.ts +53 -0
  28. package/dist/src/dataset/fortemi-live-qualification.js +297 -0
  29. package/dist/src/dataset/index.d.ts +1 -0
  30. package/dist/src/dataset/index.js +1 -0
  31. package/dist/src/mcp/cli.mjs +30 -1
  32. package/dist/src/mcp/omp-config.mjs +128 -0
  33. package/dist/src/mcp/registry.js +45 -5
  34. package/dist/src/mcp/registry.mjs +29 -6
  35. package/dist/src/models/model-capabilities.v1.json +42 -0
  36. package/dist/src/models/model-catalog.v1.json +37 -0
  37. package/dist/src/models/model-discovery.js +78 -5
  38. package/dist/src/models/provider-policy.js +6 -3
  39. package/dist/src/plugin/skill-command-translator.js +2 -0
  40. package/dist/src/providers/capability-matrix.yaml +88 -2
  41. package/dist/src/providers/omp-agent.mjs +40 -0
  42. package/dist/src/providers/omp-diagnostics.mjs +15 -0
  43. package/dist/src/providers/omp-paths.mjs +38 -0
  44. package/dist/src/providers/provider-definitions.js +83 -0
  45. package/dist/src/providers/provider-definitions.mjs +25 -1
  46. package/dist/src/providers/provider-inventory.js +2 -0
  47. package/dist/src/sessions/adapters/omp.js +203 -0
  48. package/dist/src/sessions/adapters/pi.js +141 -0
  49. package/dist/src/sessions/batch-import.js +7 -0
  50. package/dist/src/sessions/contracts.js +1 -1
  51. package/dist/src/sessions/importer.js +4 -3
  52. package/dist/src/sessions/index.js +2 -0
  53. package/dist/src/sessions/readers.js +4 -3
  54. package/dist/src/sessions/workspace-discovery.js +22 -2
  55. package/dist/src/skills/deployer.js +21 -1
  56. package/dist/src/smiths/agentsmith/generator.js +1 -0
  57. package/dist/src/smiths/context-pipeline/parallelism-section.js +2 -0
  58. package/dist/src/smiths/context-pipeline/provider-policy.js +2 -2
  59. package/dist/src/smiths/context-pipeline/workspace-context.js +2 -2
  60. package/dist/src/storage/backends/fortemi.js +142 -17
  61. package/dist/src/storage/fortemi-qualification-receipt.js +206 -0
  62. package/dist/src/storage/fortemi-qualification.js +67 -6
  63. package/dist/src/storage/index.js +1 -0
  64. package/package.json +2 -1
  65. package/schemas/dataset/fortemi-live-qualification-receipt.v1.schema.json +132 -0
  66. package/tools/agents/deploy-agents.mjs +6 -3
  67. package/tools/agents/providers/antigravity.mjs +147 -0
  68. package/tools/agents/providers/omp.d.mts +4 -0
  69. package/tools/agents/providers/omp.mjs +256 -0
  70. package/tools/agents/providers/pi.mjs +13 -1
  71. package/tools/providers/antigravity-transport.mjs +124 -0
@@ -0,0 +1,206 @@
1
+ import { createHash } from "node:crypto";
2
+ import { link, mkdir, unlink, writeFile } from "node:fs/promises";
3
+ import { dirname } from "node:path";
4
+ import { execFileSync } from "node:child_process";
5
+ export const FORTEMI_QUALIFICATION_RECEIPT = "aiwg.fortemi-live-qualification-receipt/v1";
6
+ const DIGEST = /^sha256:[0-9a-f]{64}$/;
7
+ const COMMIT = /^[0-9a-f]{40}$/;
8
+ const REF = /^(?:refs\/(?:heads|tags)\/[A-Za-z0-9._/-]+|[0-9a-f]{40})$/;
9
+ const SHORT_REF = /^[A-Za-z0-9._/-]+$/;
10
+ const SAFE = /^[A-Za-z0-9._:/-]+$/;
11
+ const NAMESPACE = /^aiwg-qualification-[0-9a-f-]{36}$/;
12
+ const REQUIRED_OPERATIONS = new Set([
13
+ "read",
14
+ "write",
15
+ "update",
16
+ "list",
17
+ "query",
18
+ ]);
19
+ function hasCompleteOperationInventory(operations) {
20
+ const names = operations.map((operation) => operation.operation);
21
+ return (names.length === REQUIRED_OPERATIONS.size &&
22
+ new Set(names).size === REQUIRED_OPERATIONS.size &&
23
+ names.every((name) => REQUIRED_OPERATIONS.has(name)));
24
+ }
25
+ export function resolveFortemiQualificationSource(env = process.env, cwd = process.cwd()) {
26
+ const git = (...args) => execFileSync("git", args, {
27
+ cwd,
28
+ encoding: "utf8",
29
+ stdio: ["ignore", "pipe", "ignore"],
30
+ }).trim();
31
+ const aiwgCommit = env.AIWG_STORAGE_QUALIFICATION_COMMIT || git("rev-parse", "HEAD");
32
+ const configuredRef = env.AIWG_STORAGE_QUALIFICATION_BRANCH;
33
+ const aiwgRef = configuredRef
34
+ ? REF.test(configuredRef)
35
+ ? configuredRef
36
+ : SHORT_REF.test(configuredRef) && !configuredRef.includes("..")
37
+ ? `refs/heads/${configuredRef}`
38
+ : configuredRef
39
+ : (() => {
40
+ try {
41
+ return git("symbolic-ref", "-q", "HEAD");
42
+ }
43
+ catch {
44
+ return aiwgCommit;
45
+ }
46
+ })();
47
+ if (!COMMIT.test(aiwgCommit))
48
+ throw new Error("FORTEMI_RECEIPT_INVALID_COMMIT");
49
+ if (!REF.test(aiwgRef) || aiwgRef.includes(".."))
50
+ throw new Error("FORTEMI_RECEIPT_INVALID_REF");
51
+ return { aiwgCommit, aiwgRef };
52
+ }
53
+ function canonical(value) {
54
+ if (Array.isArray(value))
55
+ return `[${value.map(canonical).join(",")}]`;
56
+ if (value && typeof value === "object")
57
+ return `{${Object.entries(value)
58
+ .sort(([a], [b]) => a.localeCompare(b))
59
+ .map(([key, item]) => `${JSON.stringify(key)}:${canonical(item)}`)
60
+ .join(",")}}`;
61
+ return JSON.stringify(value);
62
+ }
63
+ export function fortemiReceiptDigest(value) {
64
+ return `sha256:${createHash("sha256").update(canonical(value)).digest("hex")}`;
65
+ }
66
+ export function endpointFingerprint(rawUrl) {
67
+ const url = new URL(rawUrl);
68
+ url.username = "";
69
+ url.password = "";
70
+ url.hash = "";
71
+ return fortemiReceiptDigest(url.toString());
72
+ }
73
+ function receiptMaterial(receipt) {
74
+ const { receiptDigest: _digest, ...material } = receipt;
75
+ return material;
76
+ }
77
+ export function createFortemiQualificationReceipt(input) {
78
+ if (!COMMIT.test(input.aiwgCommit))
79
+ throw new Error("FORTEMI_RECEIPT_INVALID_COMMIT");
80
+ if (!REF.test(input.aiwgRef) || input.aiwgRef.includes(".."))
81
+ throw new Error("FORTEMI_RECEIPT_INVALID_REF");
82
+ if (!input.report.server.name || !SAFE.test(input.report.server.name))
83
+ throw new Error("FORTEMI_RECEIPT_INVALID_SERVER_NAME");
84
+ if (!input.report.server.version || !SAFE.test(input.report.server.version))
85
+ throw new Error("FORTEMI_RECEIPT_INVALID_SERVER_VERSION");
86
+ if (!SAFE.test(input.contractRevision))
87
+ throw new Error("FORTEMI_RECEIPT_INVALID_CONTRACT_REVISION");
88
+ if (!NAMESPACE.test(input.report.namespace))
89
+ throw new Error("FORTEMI_RECEIPT_INVALID_NAMESPACE");
90
+ if (input.report.mutationAttempted !== Boolean(input.mutationObjectId))
91
+ throw new Error("FORTEMI_RECEIPT_MUTATION_BINDING_MISMATCH");
92
+ if (input.mutationObjectId && !SAFE.test(input.mutationObjectId))
93
+ throw new Error("FORTEMI_RECEIPT_INVALID_OBJECT_ID");
94
+ const start = Date.parse(input.startedAt);
95
+ const end = Date.parse(input.endedAt);
96
+ if (!Number.isFinite(start) || !Number.isFinite(end) || end < start)
97
+ throw new Error("FORTEMI_RECEIPT_INVALID_TIMESTAMPS");
98
+ if (!Number.isInteger(input.timeoutMs) ||
99
+ input.timeoutMs < 250 ||
100
+ input.timeoutMs > 30_000 ||
101
+ !Number.isInteger(input.networkAttempts) ||
102
+ input.networkAttempts < 0)
103
+ throw new Error("FORTEMI_RECEIPT_INVALID_RESOURCES");
104
+ const operations = input.report.operations.map(({ operation, tool, compatible, code }) => {
105
+ if (![operation, tool, code].every((value) => SAFE.test(value)))
106
+ throw new Error("FORTEMI_RECEIPT_UNSAFE_OPERATION");
107
+ return { operation, tool, compatible, code };
108
+ });
109
+ if (!hasCompleteOperationInventory(operations))
110
+ throw new Error("FORTEMI_RECEIPT_OPERATION_INVENTORY_INVALID");
111
+ const material = {
112
+ contract: FORTEMI_QUALIFICATION_RECEIPT,
113
+ outcome: input.report.compatible ? "passed" : "failed",
114
+ bindings: {
115
+ aiwgCommit: input.aiwgCommit,
116
+ aiwgRef: input.aiwgRef,
117
+ endpointFingerprint: endpointFingerprint(input.endpointUrl),
118
+ toolSchemaDigest: fortemiReceiptDigest(input.toolSchemas),
119
+ },
120
+ observed: {
121
+ serverName: input.report.server.name,
122
+ serverVersion: input.report.server.version,
123
+ contractRevision: input.contractRevision,
124
+ },
125
+ namespace: input.report.namespace,
126
+ operations,
127
+ mutation: {
128
+ attempted: input.report.mutationAttempted,
129
+ ...(input.mutationObjectId ? { objectId: input.mutationObjectId } : {}),
130
+ },
131
+ startedAt: new Date(start).toISOString(),
132
+ endedAt: new Date(end).toISOString(),
133
+ resources: {
134
+ timeoutMs: input.timeoutMs,
135
+ durationMs: end - start,
136
+ networkAttempts: input.networkAttempts,
137
+ toolCount: operations.length,
138
+ },
139
+ };
140
+ return { ...material, receiptDigest: fortemiReceiptDigest(material) };
141
+ }
142
+ export function verifyFortemiQualificationReceipt(receipt) {
143
+ const errors = [];
144
+ if (receipt.contract !== FORTEMI_QUALIFICATION_RECEIPT)
145
+ errors.push("FORTEMI_RECEIPT_CONTRACT_MISMATCH");
146
+ if (!["passed", "failed"].includes(receipt.outcome) ||
147
+ receipt.outcome !==
148
+ (receipt.operations.every((operation) => operation.compatible)
149
+ ? "passed"
150
+ : "failed"))
151
+ errors.push("FORTEMI_RECEIPT_OUTCOME_INVALID");
152
+ if (!DIGEST.test(receipt.receiptDigest) ||
153
+ receipt.receiptDigest !== fortemiReceiptDigest(receiptMaterial(receipt)))
154
+ errors.push("FORTEMI_RECEIPT_DIGEST_MISMATCH");
155
+ if (!DIGEST.test(receipt.bindings.endpointFingerprint) ||
156
+ !DIGEST.test(receipt.bindings.toolSchemaDigest))
157
+ errors.push("FORTEMI_RECEIPT_BINDING_INVALID");
158
+ if (!COMMIT.test(receipt.bindings.aiwgCommit) ||
159
+ !REF.test(receipt.bindings.aiwgRef))
160
+ errors.push("FORTEMI_RECEIPT_SOURCE_INVALID");
161
+ if (!SAFE.test(receipt.observed.serverName) ||
162
+ !SAFE.test(receipt.observed.serverVersion) ||
163
+ !SAFE.test(receipt.observed.contractRevision) ||
164
+ !NAMESPACE.test(receipt.namespace))
165
+ errors.push("FORTEMI_RECEIPT_OBSERVATION_INVALID");
166
+ if (receipt.operations.some((item) => !SAFE.test(item.operation) ||
167
+ !SAFE.test(item.tool) ||
168
+ !SAFE.test(item.code)))
169
+ errors.push("FORTEMI_RECEIPT_OPERATION_INVALID");
170
+ if (!hasCompleteOperationInventory(receipt.operations))
171
+ errors.push("FORTEMI_RECEIPT_OPERATION_INVENTORY_INVALID");
172
+ if (receipt.mutation.attempted !== Boolean(receipt.mutation.objectId) ||
173
+ (receipt.mutation.objectId && !SAFE.test(receipt.mutation.objectId)))
174
+ errors.push("FORTEMI_RECEIPT_MUTATION_INVALID");
175
+ if (Date.parse(receipt.endedAt) < Date.parse(receipt.startedAt) ||
176
+ receipt.resources.durationMs !==
177
+ Date.parse(receipt.endedAt) - Date.parse(receipt.startedAt))
178
+ errors.push("FORTEMI_RECEIPT_TIME_INVALID");
179
+ if (!Number.isInteger(receipt.resources.timeoutMs) ||
180
+ receipt.resources.timeoutMs < 250 ||
181
+ receipt.resources.timeoutMs > 30_000 ||
182
+ !Number.isInteger(receipt.resources.networkAttempts) ||
183
+ receipt.resources.networkAttempts < 0 ||
184
+ receipt.resources.toolCount !== receipt.operations.length)
185
+ errors.push("FORTEMI_RECEIPT_RESOURCES_INVALID");
186
+ return errors;
187
+ }
188
+ export async function writeFortemiQualificationReceipt(path, receipt) {
189
+ const errors = verifyFortemiQualificationReceipt(receipt);
190
+ if (errors.length)
191
+ throw new Error(errors.join(","));
192
+ await mkdir(dirname(path), { recursive: true });
193
+ const temporary = `${path}.tmp-${process.pid}`;
194
+ await writeFile(temporary, `${JSON.stringify(receipt, null, 2)}\n`, {
195
+ encoding: "utf8",
196
+ mode: 0o600,
197
+ flag: "wx",
198
+ });
199
+ try {
200
+ await link(temporary, path);
201
+ }
202
+ finally {
203
+ await unlink(temporary).catch(() => undefined);
204
+ }
205
+ }
206
+ //# sourceMappingURL=fortemi-qualification-receipt.js.map
@@ -1,7 +1,7 @@
1
1
  import { randomUUID } from "node:crypto";
2
- import { FortemiAdapter } from "./backends/fortemi.js";
2
+ import { FortemiAdapter, fortemiStableNoteId, } from "./backends/fortemi.js";
3
3
  export const FORTEMI_QUALIFICATION_VERSION = "aiwg.fortemi-live-qualification/v1";
4
- const EXPECTED = {
4
+ const LEGACY_EXPECTED = {
5
5
  read: { tool: "get_note", required: ["note_id"], properties: ["note_id"] },
6
6
  write: {
7
7
  tool: "capture_knowledge",
@@ -20,6 +20,37 @@ const EXPECTED = {
20
20
  properties: ["query", "id_prefix"],
21
21
  },
22
22
  };
23
+ const SOURCE_ADDRESSED_EXPECTED = {
24
+ read: { tool: "get_note", required: ["id"], properties: ["id"] },
25
+ write: {
26
+ tool: "upsert_external_notes",
27
+ required: [
28
+ "source_namespace",
29
+ "source_schema_version",
30
+ "import_run_id",
31
+ "items",
32
+ ],
33
+ properties: [
34
+ "source_namespace",
35
+ "source_schema_version",
36
+ "import_run_id",
37
+ "batch_id",
38
+ "policy",
39
+ "items",
40
+ ],
41
+ },
42
+ update: {
43
+ tool: "update_note",
44
+ required: ["id"],
45
+ properties: ["id", "content", "archived"],
46
+ },
47
+ list: { tool: "list_notes", required: [], properties: ["limit", "offset"] },
48
+ query: {
49
+ tool: "search",
50
+ required: ["action"],
51
+ properties: ["action", "query", "limit"],
52
+ },
53
+ };
23
54
  function bounded(work, timeoutMs, label) {
24
55
  let timer;
25
56
  return Promise.race([
@@ -50,8 +81,19 @@ export async function qualifyLiveFortemi(client, options = {}) {
50
81
  if (!client.listTools)
51
82
  throw new Error("FORTEMI_TOOL_DISCOVERY_UNAVAILABLE");
52
83
  const discovered = await bounded(client.listTools(), timeoutMs, "tools/list");
84
+ options.onToolSchemas?.(discovered.tools ?? []);
53
85
  const tools = new Map((discovered.tools ?? []).map((tool) => [tool.name, tool]));
54
- for (const [operation, expected] of Object.entries(EXPECTED)) {
86
+ const getProperties = tools.get("get_note")?.inputSchema?.properties;
87
+ const profile = tools.has("upsert_external_notes") &&
88
+ getProperties &&
89
+ typeof getProperties === "object" &&
90
+ "id" in getProperties
91
+ ? "source-addressed-v1"
92
+ : "legacy-note-id";
93
+ const expectedOperations = profile === "source-addressed-v1"
94
+ ? SOURCE_ADDRESSED_EXPECTED
95
+ : LEGACY_EXPECTED;
96
+ for (const [operation, expected] of Object.entries(expectedOperations)) {
55
97
  const tool = tools.get(expected.tool);
56
98
  const schema = tool?.inputSchema;
57
99
  const properties = schema?.properties && typeof schema.properties === "object"
@@ -62,9 +104,23 @@ export async function qualifyLiveFortemi(client, options = {}) {
62
104
  : [];
63
105
  const missing = expected.properties.filter((name) => !(name in properties));
64
106
  const missingRequired = expected.required.filter((name) => !required.includes(name));
107
+ const itemProperties = operation === "write" && profile === "source-addressed-v1"
108
+ ? (properties.items?.items?.properties ?? {})
109
+ : {};
110
+ const missingItemProperties = operation === "write" && profile === "source-addressed-v1"
111
+ ? [
112
+ "external_id",
113
+ "content",
114
+ "content_digest",
115
+ "caller_stable_id",
116
+ "metadata",
117
+ "policy",
118
+ ].filter((name) => !(name in itemProperties))
119
+ : [];
65
120
  const compatible = Boolean(tool && schema) &&
66
121
  missing.length === 0 &&
67
- missingRequired.length === 0;
122
+ missingRequired.length === 0 &&
123
+ missingItemProperties.length === 0;
68
124
  report.operations.push({
69
125
  operation,
70
126
  tool: expected.tool,
@@ -76,7 +132,7 @@ export async function qualifyLiveFortemi(client, options = {}) {
76
132
  : "FORTEMI_TOOL_MISSING",
77
133
  detail: compatible
78
134
  ? "expected adapter arguments are accepted"
79
- : `missing properties: ${missing.join(", ") || "none"}; not required: ${missingRequired.join(", ") || "none"}`,
135
+ : `missing properties: ${missing.join(", ") || "none"}; not required: ${missingRequired.join(", ") || "none"}; missing item properties: ${missingItemProperties.join(", ") || "none"}`,
80
136
  });
81
137
  }
82
138
  report.compatible = report.operations.every((item) => item.compatible);
@@ -93,7 +149,12 @@ export async function qualifyLiveFortemi(client, options = {}) {
93
149
  await bounded(adapter.query(`aiwg qualification ${namespace}`), timeoutMs, "adapter query");
94
150
  if (options.allowMutation) {
95
151
  report.mutationAttempted = true;
96
- await bounded(adapter.write(randomUUID(), `AIWG live qualification ${namespace}`, {
152
+ const mutationPath = randomUUID();
153
+ report.mutationObjectId =
154
+ profile === "source-addressed-v1"
155
+ ? fortemiStableNoteId(namespace, mutationPath)
156
+ : `${namespace}:${mutationPath}`;
157
+ await bounded(adapter.write(mutationPath, `AIWG live qualification ${namespace}`, {
97
158
  contentType: "text/plain",
98
159
  }), timeoutMs, "adapter write");
99
160
  }
@@ -22,6 +22,7 @@ export { ObsidianAdapter } from './backends/obsidian.js';
22
22
  export { LogseqAdapter } from './backends/logseq.js';
23
23
  export { FortemiAdapter } from './backends/fortemi.js';
24
24
  export { qualifyLiveFortemi, FORTEMI_QUALIFICATION_VERSION, } from './fortemi-qualification.js';
25
+ export { createFortemiQualificationReceipt, endpointFingerprint, fortemiReceiptDigest, verifyFortemiQualificationReceipt, writeFortemiQualificationReceipt, FORTEMI_QUALIFICATION_RECEIPT, } from './fortemi-qualification-receipt.js';
25
26
  export { STORAGE_BACKEND_CONTRACT, STORAGE_BACKEND_MATRIX, StorageCapabilityError, negotiateStorageCapabilities, } from './backend-contract.js';
26
27
  export { STORAGE_MIGRATION_PROTOCOL, MigrationProtocolError, StorageMigrationCoordinator, approvalDigest, digestRecordChunks, digestRecords, validateManifest, } from './migration-protocol.js';
27
28
  export { PostgresStorageBackend, PostgresBackendError, } from './backends/postgres.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aiwg/cli",
3
- "version": "2026.9.1",
3
+ "version": "2026.9.3",
4
4
  "description": "Lightweight AIWG CLI for signed, versioned web-backed resources.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -39,6 +39,7 @@
39
39
  "tools/_resolve-impl.mjs",
40
40
  "tools/agents/deploy-agents.mjs",
41
41
  "tools/agents/providers/",
42
+ "tools/providers/antigravity-transport.mjs",
42
43
  "tools/commands/deploy-prompts-codex.mjs",
43
44
  "tools/plugin/package-plugins.mjs",
44
45
  "tools/skills/deploy-skills-codex.mjs",
@@ -0,0 +1,132 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://aiwg.io/schemas/dataset/fortemi-live-qualification-receipt.v1.schema.json",
4
+ "title": "AIWG Fortemi Dataset Live Qualification Receipt v1",
5
+ "type": "object",
6
+ "additionalProperties": false,
7
+ "required": [
8
+ "contract",
9
+ "outcome",
10
+ "diagnostic",
11
+ "receiptDigest",
12
+ "bindings",
13
+ "observed",
14
+ "namespace",
15
+ "operations",
16
+ "mutation",
17
+ "resources",
18
+ "startedAt",
19
+ "endedAt"
20
+ ],
21
+ "properties": {
22
+ "contract": { "const": "aiwg.fortemi-dataset-live-qualification/v1" },
23
+ "outcome": { "enum": ["pending", "supported"] },
24
+ "diagnostic": {
25
+ "enum": [
26
+ "CONFORMANCE_FORTEMI_DATASET_CONTRACT_UNAVAILABLE",
27
+ "CONFORMANCE_FORTEMI_DATASET_PREFLIGHT_SUPPORTED"
28
+ ]
29
+ },
30
+ "receiptDigest": { "$ref": "#/$defs/digest" },
31
+ "bindings": {
32
+ "type": "object",
33
+ "additionalProperties": false,
34
+ "required": ["aiwgCommit", "endpointFingerprint", "toolSchemaDigest"],
35
+ "properties": {
36
+ "aiwgCommit": { "type": "string", "pattern": "^[0-9a-f]{40}$" },
37
+ "endpointFingerprint": { "$ref": "#/$defs/digest" },
38
+ "toolSchemaDigest": { "$ref": "#/$defs/digest" }
39
+ }
40
+ },
41
+ "observed": {
42
+ "type": "object",
43
+ "additionalProperties": false,
44
+ "required": ["serverName", "serverVersion"],
45
+ "properties": {
46
+ "serverName": { "$ref": "#/$defs/safe" },
47
+ "serverVersion": { "$ref": "#/$defs/safe" }
48
+ }
49
+ },
50
+ "namespace": {
51
+ "type": "string",
52
+ "pattern": "^aiwg-dataset-qualification-[0-9a-f-]{36}$"
53
+ },
54
+ "operations": {
55
+ "type": "array",
56
+ "minItems": 2,
57
+ "maxItems": 2,
58
+ "items": {
59
+ "type": "object",
60
+ "additionalProperties": false,
61
+ "required": ["tool", "compatible", "code"],
62
+ "properties": {
63
+ "tool": { "enum": ["dataset_capabilities", "dataset_execute"] },
64
+ "compatible": { "type": "boolean" },
65
+ "code": {
66
+ "enum": [
67
+ "FORTEMI_DATASET_TOOL_SCHEMA_COMPATIBLE",
68
+ "FORTEMI_DATASET_TOOL_SCHEMA_DRIFT",
69
+ "FORTEMI_DATASET_TOOL_MISSING"
70
+ ]
71
+ }
72
+ }
73
+ }
74
+ },
75
+ "mutation": {
76
+ "type": "object",
77
+ "additionalProperties": false,
78
+ "required": ["authorized", "attempted"],
79
+ "properties": {
80
+ "authorized": { "const": false },
81
+ "attempted": { "const": false }
82
+ }
83
+ },
84
+ "resources": {
85
+ "type": "object",
86
+ "additionalProperties": false,
87
+ "required": [
88
+ "maxDurationMs",
89
+ "durationMs",
90
+ "maxToolCount",
91
+ "observedToolCount",
92
+ "maxSchemaBytes",
93
+ "observedSchemaBytes",
94
+ "networkAttempts",
95
+ "toolCalls"
96
+ ],
97
+ "properties": {
98
+ "maxDurationMs": {
99
+ "type": "integer",
100
+ "minimum": 250,
101
+ "maximum": 30000
102
+ },
103
+ "durationMs": { "type": "integer", "minimum": 0 },
104
+ "maxToolCount": { "const": 256 },
105
+ "observedToolCount": {
106
+ "type": "integer",
107
+ "minimum": 0,
108
+ "maximum": 256
109
+ },
110
+ "maxSchemaBytes": { "const": 1048576 },
111
+ "observedSchemaBytes": {
112
+ "type": "integer",
113
+ "minimum": 0,
114
+ "maximum": 1048576
115
+ },
116
+ "networkAttempts": { "const": 1 },
117
+ "toolCalls": { "const": 0 }
118
+ }
119
+ },
120
+ "startedAt": { "$ref": "#/$defs/time" },
121
+ "endedAt": { "$ref": "#/$defs/time" }
122
+ },
123
+ "$defs": {
124
+ "digest": { "type": "string", "pattern": "^sha256:[0-9a-f]{64}$" },
125
+ "safe": {
126
+ "type": "string",
127
+ "minLength": 1,
128
+ "pattern": "^[A-Za-z0-9._:/-]+$"
129
+ },
130
+ "time": { "type": "string", "format": "date-time", "pattern": "Z$" }
131
+ }
132
+ }
@@ -20,7 +20,7 @@
20
20
  * --rules-only Deploy only rules (skip agents)
21
21
  * --dry-run Show what would be deployed without writing
22
22
  * --force Overwrite existing files
23
- * --provider <name> Target provider: claude (default), openai, codex, cursor, opencode, copilot, factory, pi, warp, devin, hermes, or openclaw
23
+ * --provider <name> Target provider: antigravity (agy), claude (default), openai, codex, cursor, opencode, copilot, factory, pi, omp, warp, devin, hermes, or openclaw
24
24
  * --model <name> Override model for all tiers (blanket)
25
25
  * --reasoning-model <name> Override model for reasoning tasks
26
26
  * --coding-model <name> Override model for coding tasks
@@ -53,6 +53,7 @@
53
53
  * windsurf - Deprecated alias for devin
54
54
  * openclaw - OpenClaw - ~/.openclaw/agents/, ~/.openclaw/commands/, ~/.openclaw/skills/, ~/.openclaw/rules/, ~/.openclaw/behaviors/
55
55
  * pi - Pi Coding Agent - .agents/skills/, .pi/skills/, .pi/prompts/, AGENTS.md
56
+ * omp - Oh My Pi - .omp/agents/, .omp/prompts/, .agents/skills/, .omp/AGENTS.md
56
57
  *
57
58
  * Defaults:
58
59
  * --source resolves relative to this script's repo root (../..)
@@ -104,15 +105,17 @@ function getDeployVersion(srcRoot) {
104
105
  // ============================================================================
105
106
 
106
107
  const PROVIDER_ALIASES = {
108
+ agy: 'antigravity',
107
109
  'openai': 'codex',
108
110
  'devin': 'windsurf',
109
111
  'devin-desktop': 'windsurf',
110
112
  'devin-local': 'windsurf',
111
113
  'cascade': 'windsurf',
112
114
  'pi-coding-agent': 'pi',
115
+ 'oh-my-pi': 'omp',
113
116
  };
114
117
 
115
- const AVAILABLE_PROVIDERS = ['claude', 'factory', 'codex', 'opencode', 'copilot', 'cursor', 'pi', 'warp', 'windsurf', 'hermes', 'openclaw', 'openhuman'];
118
+ const AVAILABLE_PROVIDERS = ['antigravity', 'claude', 'factory', 'codex', 'opencode', 'copilot', 'cursor', 'pi', 'omp', 'warp', 'windsurf', 'hermes', 'openclaw', 'openhuman'];
116
119
 
117
120
  const UNSUPPORTED_PROVIDER_HINTS = {
118
121
  'devin-cli': [
@@ -154,7 +157,7 @@ const MIRRORED_KERNEL_COMMAND_SKILLS = new Set([
154
157
  ]);
155
158
 
156
159
  function providerUsesSkillsNatively(providerName) {
157
- return ['claude', 'cursor', 'hermes', 'openhuman', 'pi'].includes(providerName);
160
+ return ['antigravity', 'claude', 'cursor', 'hermes', 'openhuman', 'pi', 'omp'].includes(providerName);
158
161
  }
159
162
 
160
163
  function shouldMirrorStandardCommandSkill(skillName) {
@@ -0,0 +1,147 @@
1
+ /** Google Antigravity CLI project resource deployment, qualified against 1.1.26. */
2
+ import fs from 'node:fs';
3
+ import path from 'node:path';
4
+ import {
5
+ collectFrameworkArtifacts,
6
+ createAgentsMdFromTemplate,
7
+ deployFiles,
8
+ deploySkillsWithKernelRouting,
9
+ ensureDir,
10
+ getAddonAgentFiles,
11
+ getAddonSkillDirs,
12
+ listMdFiles,
13
+ listSkillDirs,
14
+ normalizeDeploymentMode,
15
+ resolveAiwgRoot,
16
+ } from './base.mjs';
17
+
18
+ export const name = 'antigravity';
19
+ export const aliases = ['agy'];
20
+ export const paths = { agents: '.agents/agents', commands: '', skills: '.agents/skills', rules: '' };
21
+ export const kernelSkillsPath = '.agents/skills';
22
+ export const support = { agents: 'degraded', commands: 'unsupported', skills: 'native', rules: 'context' };
23
+ export const capabilities = {
24
+ skills: true,
25
+ rules: false,
26
+ yamlFormat: true,
27
+ aggregatedOutput: false,
28
+ homeDirectoryDeploy: false,
29
+ parallelCommandAndSkillSurfaces: false,
30
+ };
31
+
32
+ export const mapModel = model => model;
33
+
34
+ const ANTIGRAVITY_TOOL_MAP = new Map([
35
+ ['Read', 'view_file'],
36
+ ['Write', 'write_to_file'],
37
+ ['Edit', 'replace_file_content'],
38
+ ['Grep', 'grep_search'],
39
+ ['Bash', 'run_command'],
40
+ ]);
41
+
42
+ function mapTools(value) {
43
+ if (!value) return [];
44
+ return value
45
+ .replace(/^\[|\]$/g, '')
46
+ .split(',')
47
+ .map(tool => ANTIGRAVITY_TOOL_MAP.get(tool.trim()))
48
+ .filter(Boolean);
49
+ }
50
+
51
+ export function transformAgent(_source, content) {
52
+ const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n([\s\S]*)$/);
53
+ if (!match) return content;
54
+ const frontmatter = match[1];
55
+ const body = match[2].trim();
56
+ const name = frontmatter.match(/^name:\s*(.+)$/m)?.[1]?.trim();
57
+ const description = frontmatter.match(/^description:\s*(.+)$/m)?.[1]?.trim();
58
+ const tools = mapTools(frontmatter.match(/^tools:\s*(.+)$/m)?.[1]?.trim());
59
+ return [
60
+ '---',
61
+ ...(name ? [`name: ${name}`] : []),
62
+ ...(description ? [`description: ${description}`] : []),
63
+ ...(tools.length ? ['tools:', ...tools.map(tool => ` - ${tool}`)] : []),
64
+ '---',
65
+ '',
66
+ body,
67
+ '',
68
+ ].join('\n');
69
+ }
70
+
71
+ export function deployAgents(files, target, opts = {}) {
72
+ const destination = path.join(target, paths.agents);
73
+ ensureDir(destination, opts.dryRun);
74
+ return deployFiles(files, destination, { ...opts, provider: name }, transformAgent);
75
+ }
76
+
77
+ export function deploySkills(dirs, target, opts = {}) {
78
+ return deploySkillsWithKernelRouting(
79
+ dirs,
80
+ path.join(target, '.agents/.aiwg/skills'),
81
+ path.join(target, kernelSkillsPath),
82
+ { ...opts, provider: name, copyStandardSkills: opts.copyStandardSkills === true },
83
+ );
84
+ }
85
+
86
+ export function deployCommands() { return 0; }
87
+ export function deployRules() { return 0; }
88
+
89
+ export function createAgentsMd(target, srcRoot, dryRun) {
90
+ const root = resolveAiwgRoot(srcRoot) || srcRoot;
91
+ createAgentsMdFromTemplate(target, root, 'antigravity/AGENTS.md.aiwg-template', dryRun);
92
+ }
93
+
94
+ export async function postDeploy(target, opts) {
95
+ if (opts.global || opts.user || opts.scope === 'user') {
96
+ throw new Error('Antigravity global skill deployment is disabled: official 1.1.26 path documentation conflicts');
97
+ }
98
+ if (opts.createAgentsMd || (!opts.commandsOnly && !opts.skillsOnly && !opts.rulesOnly)) {
99
+ createAgentsMd(target, opts.srcRoot, opts.dryRun);
100
+ }
101
+ if (!opts.quiet) {
102
+ console.log('Antigravity resources are project scoped. Restart agy after resource changes; authenticate with the provider separately.');
103
+ }
104
+ }
105
+
106
+ export function getFileExtension() { return '.md'; }
107
+
108
+ export async function deploy(opts) {
109
+ if (opts.global || opts.user || opts.scope === 'user') {
110
+ throw new Error('Antigravity global skill deployment is disabled: official 1.1.26 path documentation conflicts');
111
+ }
112
+ const mode = normalizeDeploymentMode(opts.mode);
113
+ const agents = [];
114
+ const skills = [];
115
+ const directSource = ['agents', 'skills'].some(type => fs.existsSync(path.join(opts.srcRoot, type)));
116
+ if (directSource) {
117
+ agents.push(...listMdFiles(path.join(opts.srcRoot, 'agents')));
118
+ if (opts.deploySkills || opts.skillsOnly) skills.push(...listSkillDirs(path.join(opts.srcRoot, 'skills')));
119
+ } else if (['general', 'sdlc', 'both', 'all'].includes(mode)) {
120
+ agents.push(...getAddonAgentFiles(opts.srcRoot));
121
+ if (opts.deploySkills || opts.skillsOnly) skills.push(...getAddonSkillDirs(opts.srcRoot));
122
+ }
123
+ const framework = directSource ? { agents: [], skills: [] } : collectFrameworkArtifacts(opts.srcRoot, mode, {
124
+ includeAgents: true,
125
+ includeCommands: false,
126
+ includeSkills: opts.deploySkills || opts.skillsOnly,
127
+ includeRules: false,
128
+ });
129
+ agents.push(...framework.agents);
130
+ skills.push(...framework.skills);
131
+ let count = 0;
132
+ if (!opts.commandsOnly && !opts.skillsOnly && !opts.rulesOnly) {
133
+ count += deployAgents(agents, opts.target, opts).filter(action => action.type === 'deploy').length;
134
+ }
135
+ if ((opts.deploySkills || opts.skillsOnly) && !opts.commandsOnly && !opts.rulesOnly) {
136
+ const result = deploySkills(skills, opts.target, opts);
137
+ count += result.kernel + result.standardCopied;
138
+ }
139
+ await postDeploy(opts.target, opts);
140
+ return count;
141
+ }
142
+
143
+ export default {
144
+ name, aliases, paths, kernelSkillsPath, support, capabilities, mapModel,
145
+ transformAgent, deployAgents, deploySkills, deployCommands, deployRules,
146
+ createAgentsMd, postDeploy, getFileExtension, deploy,
147
+ };
@@ -0,0 +1,4 @@
1
+ export interface OmpUninstallOptions { dryRun?: boolean; scope?: 'user' | 'project'; home?: string; env?: NodeJS.ProcessEnv; quiet?: boolean }
2
+ export function uninstall(target: string, opts?: OmpUninstallOptions): number;
3
+
4
+ export function deploySkillSupportAsset(source: string, destination: string, opts?: { dryRun?: boolean; quiet?: boolean }): number;