@gaia-ai/gaia 0.9.2 → 0.11.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/dist/src/host.js +2 -0
- package/dist/src/validate.d.ts +78 -0
- package/dist/src/validate.js +272 -0
- package/package.json +20 -18
package/dist/src/host.js
CHANGED
|
@@ -7,6 +7,7 @@ import { commands as uiCommands } from '@gaia-ai/ui/preset';
|
|
|
7
7
|
import { Command } from 'commander';
|
|
8
8
|
import { registerUpdate } from './update.js';
|
|
9
9
|
import { registerUpgrade } from './upgrade.js';
|
|
10
|
+
import { registerValidate } from './validate.js';
|
|
10
11
|
// GAIA-201: the `gaia` plugin HOST. The meta package `@gaia-ai/gaia` owns the
|
|
11
12
|
// CLI entrypoint (AC-1); ui / conductor / dropsh / deployment are declared,
|
|
12
13
|
// ESLint-style resolved, LAZILY mounted command plugins (AC-2). The host
|
|
@@ -163,6 +164,7 @@ export async function buildHostProgram(argv, opts = {}) {
|
|
|
163
164
|
});
|
|
164
165
|
registerUpgrade(program);
|
|
165
166
|
registerUpdate(program);
|
|
167
|
+
registerValidate(program);
|
|
166
168
|
const target = opts.forceTarget ?? scanTarget(argv, names);
|
|
167
169
|
for (const entry of commands) {
|
|
168
170
|
if (entry.name === target) {
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { type EmptyLoaderShape, type SkillContract, type StepContractErrorCode } from '@gaia-ai/core';
|
|
2
|
+
import type { Command } from 'commander';
|
|
3
|
+
/** A `SKILL.md` whose frontmatter is not a readable skill contract. */
|
|
4
|
+
export interface SkillReadFailure {
|
|
5
|
+
path: string;
|
|
6
|
+
reason: string;
|
|
7
|
+
}
|
|
8
|
+
/** What the skill scan found: the name index, plus what it could not read. */
|
|
9
|
+
export interface SkillIndex {
|
|
10
|
+
byName: Map<string, SkillContract>;
|
|
11
|
+
/** Paths that parsed, in scan order — for the green summary's count. */
|
|
12
|
+
indexed: string[];
|
|
13
|
+
/** A later `SKILL.md` re-declaring an already-indexed name (first wins). */
|
|
14
|
+
shadowed: {
|
|
15
|
+
name: string;
|
|
16
|
+
path: string;
|
|
17
|
+
}[];
|
|
18
|
+
failures: SkillReadFailure[];
|
|
19
|
+
}
|
|
20
|
+
/** The verdict: `ok`, or the first contract defect with its message. */
|
|
21
|
+
export interface ValidateReport {
|
|
22
|
+
ok: boolean;
|
|
23
|
+
workflowPath: string;
|
|
24
|
+
roots: string[];
|
|
25
|
+
index: SkillIndex;
|
|
26
|
+
/** Loaded leaf skills — owners plus helpers — when the load got that far. */
|
|
27
|
+
loaded?: {
|
|
28
|
+
owners: string[];
|
|
29
|
+
helpers: string[];
|
|
30
|
+
};
|
|
31
|
+
tripleCount?: number;
|
|
32
|
+
error?: string;
|
|
33
|
+
/**
|
|
34
|
+
* The contract defect's classification, when core tagged one. GAIA-436: this is
|
|
35
|
+
* the seam `formatReport` branches on — it replaced a regex over core's message
|
|
36
|
+
* text, which matched only one of the two throw sites that need a hint and would
|
|
37
|
+
* have broken silently the next time a message was reworded.
|
|
38
|
+
*/
|
|
39
|
+
errorCode?: StepContractErrorCode;
|
|
40
|
+
/** For `unresolved_skill`: the skill name the load could not resolve. */
|
|
41
|
+
unresolvedSkill?: string;
|
|
42
|
+
/**
|
|
43
|
+
* For `empty_loader`: what the `## Loaded skills` section actually holds. Core
|
|
44
|
+
* raises that code for three shapes and its message can only describe one of
|
|
45
|
+
* them, so the shape is measured here and `formatReport` prints the remedy that
|
|
46
|
+
* fits the document rather than the one that fits the common case.
|
|
47
|
+
*/
|
|
48
|
+
emptyLoader?: EmptyLoaderShape;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Index every skill reachable from `roots` by its declared `name` — the key a
|
|
52
|
+
* `WORKFLOW.md` bullet resolves on, whatever namespace prefix the bullet wears.
|
|
53
|
+
*
|
|
54
|
+
* A `SKILL.md` that is not a readable GAIA skill contract is RECORDED rather than
|
|
55
|
+
* thrown on: a project's skill tree legitimately holds third-party skills that
|
|
56
|
+
* declare no GAIA frontmatter, and failing the whole validation over one of them
|
|
57
|
+
* would make the command useless exactly where it is most needed. The record is
|
|
58
|
+
* printed only when a bullet then fails to resolve, where it is the likely cause.
|
|
59
|
+
*/
|
|
60
|
+
export declare function indexSkills(roots: string[]): SkillIndex;
|
|
61
|
+
export interface ValidateOptions {
|
|
62
|
+
/** A project directory, or a loader document (`WORKFLOW.md`) directly. */
|
|
63
|
+
path?: string | undefined;
|
|
64
|
+
/** Project root for default skill-root discovery; defaults from `path`. */
|
|
65
|
+
project?: string | undefined;
|
|
66
|
+
/** Extra skill roots, in precedence order before the defaults. */
|
|
67
|
+
skills?: string[] | undefined;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Validate a project's loader: read `WORKFLOW.md`, index the skills it can reach,
|
|
71
|
+
* expand the load, derive the project's triple set, and enforce the contract.
|
|
72
|
+
*
|
|
73
|
+
* Returns the verdict rather than throwing, so the caller owns the exit code.
|
|
74
|
+
*/
|
|
75
|
+
export declare function runValidate(options?: ValidateOptions): ValidateReport;
|
|
76
|
+
/** Render the report for a terminal. Returns the lines, so tests can read them. */
|
|
77
|
+
export declare function formatReport(report: ValidateReport): string[];
|
|
78
|
+
export declare function registerValidate(program: Command): void;
|
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
import { readdirSync, readFileSync, statSync } from 'node:fs';
|
|
2
|
+
import { dirname, isAbsolute, join, resolve } from 'node:path';
|
|
3
|
+
import { deriveProjectTriples, expandLoad, measureEmptyLoader, readSkillWhen, StepContractError, validateLoad, } from '@gaia-ai/core';
|
|
4
|
+
// GAIA-436: `gaia validate` is the step contract's ENTRY POINT.
|
|
5
|
+
//
|
|
6
|
+
// `@gaia-ai/core` has shipped `expandLoad` / `validateLoad` since GAIA-204, but
|
|
7
|
+
// nothing outside the contract test ever called them: the contract was enforced
|
|
8
|
+
// only where an agent happened to run it by hand, so a drifted `WORKFLOW.md`
|
|
9
|
+
// degraded in silence — on one consumer project, eleven overrides resolved to
|
|
10
|
+
// nothing for six weeks after a key rename, with no error anywhere.
|
|
11
|
+
//
|
|
12
|
+
// This command is deliberately thin. It discovers, delegates to core, and
|
|
13
|
+
// reports; every rule it enforces lives in `core/src/workflow/step-contract.ts`,
|
|
14
|
+
// so the CLI and the contract test can never drift apart. Enforcing the contract
|
|
15
|
+
// at conductor claim time was considered and rejected for this ticket — it needs
|
|
16
|
+
// its own rollout story, because it would start failing live claims.
|
|
17
|
+
/** Directory names never worth walking when hunting for `SKILL.md` files. */
|
|
18
|
+
const SKIP_DIRS = new Set([
|
|
19
|
+
'node_modules',
|
|
20
|
+
'.git',
|
|
21
|
+
'dist',
|
|
22
|
+
'vendor',
|
|
23
|
+
'.ddev',
|
|
24
|
+
'coverage',
|
|
25
|
+
]);
|
|
26
|
+
/** How deep below a skill root a `SKILL.md` may sit. `.claude/skills/<plugin>/skills/<name>/SKILL.md`
|
|
27
|
+
* is 3 directories below `.claude/skills`; a plugin cache adds a version segment. */
|
|
28
|
+
const MAX_SKILL_DEPTH = 5;
|
|
29
|
+
/** How many offending load sites the empty-loader report prints before eliding. */
|
|
30
|
+
const MAX_LISTED_LOAD_SITES = 5;
|
|
31
|
+
/**
|
|
32
|
+
* The in-repo skill roots discovered without being told — the obvious two.
|
|
33
|
+
*
|
|
34
|
+
* The Claude **plugin cache** is deliberately NOT here. It would let a project
|
|
35
|
+
* that does not vendor its skills validate with no `--skills`, but the cache holds
|
|
36
|
+
* every installed version side by side (`cache/gaia/gaia/{0.18.0,0.19.0,0.20.0}/`),
|
|
37
|
+
* so a scan would index whichever version it walked first and report `OK` against
|
|
38
|
+
* a skill set weeks out of date — the exact silent degradation this command exists
|
|
39
|
+
* to end. Resolving the cache needs a version choice made on purpose; until then a
|
|
40
|
+
* consumer project passes `--skills`, and `formatReport` says so when a bullet
|
|
41
|
+
* fails to resolve rather than letting a discovery gap wear a loader defect's
|
|
42
|
+
* message.
|
|
43
|
+
*/
|
|
44
|
+
const DEFAULT_SKILL_ROOTS = ['.claude/skills', '.agents/skills'];
|
|
45
|
+
/** Every `SKILL.md` under `root`, depth-capped, deterministic (name-sorted). */
|
|
46
|
+
function findSkillFiles(root, depth = 0) {
|
|
47
|
+
let entries;
|
|
48
|
+
try {
|
|
49
|
+
entries = readdirSync(root, { withFileTypes: true });
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
return []; // an absent or unreadable root is simply not a skill root
|
|
53
|
+
}
|
|
54
|
+
const found = [];
|
|
55
|
+
for (const entry of [...entries].sort((a, b) => a.name.localeCompare(b.name))) {
|
|
56
|
+
if (entry.isFile() && entry.name === 'SKILL.md') {
|
|
57
|
+
found.push(join(root, entry.name));
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
if (!entry.isDirectory())
|
|
61
|
+
continue;
|
|
62
|
+
if (SKIP_DIRS.has(entry.name) || depth >= MAX_SKILL_DEPTH)
|
|
63
|
+
continue;
|
|
64
|
+
found.push(...findSkillFiles(join(root, entry.name), depth + 1));
|
|
65
|
+
}
|
|
66
|
+
return found;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Index every skill reachable from `roots` by its declared `name` — the key a
|
|
70
|
+
* `WORKFLOW.md` bullet resolves on, whatever namespace prefix the bullet wears.
|
|
71
|
+
*
|
|
72
|
+
* A `SKILL.md` that is not a readable GAIA skill contract is RECORDED rather than
|
|
73
|
+
* thrown on: a project's skill tree legitimately holds third-party skills that
|
|
74
|
+
* declare no GAIA frontmatter, and failing the whole validation over one of them
|
|
75
|
+
* would make the command useless exactly where it is most needed. The record is
|
|
76
|
+
* printed only when a bullet then fails to resolve, where it is the likely cause.
|
|
77
|
+
*/
|
|
78
|
+
export function indexSkills(roots) {
|
|
79
|
+
const byName = new Map();
|
|
80
|
+
const indexed = [];
|
|
81
|
+
const shadowed = [];
|
|
82
|
+
const failures = [];
|
|
83
|
+
for (const root of roots) {
|
|
84
|
+
for (const path of findSkillFiles(root)) {
|
|
85
|
+
let contract;
|
|
86
|
+
try {
|
|
87
|
+
contract = readSkillWhen(readFileSync(path, 'utf8'));
|
|
88
|
+
}
|
|
89
|
+
catch (cause) {
|
|
90
|
+
failures.push({ path, reason: cause.message });
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
if (byName.has(contract.name)) {
|
|
94
|
+
shadowed.push({ name: contract.name, path });
|
|
95
|
+
continue; // first root wins, so the order of `roots` is the precedence
|
|
96
|
+
}
|
|
97
|
+
byName.set(contract.name, contract);
|
|
98
|
+
indexed.push(path);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return { byName, indexed, shadowed, failures };
|
|
102
|
+
}
|
|
103
|
+
/** Resolve `path` into the loader document and the project root to scan from. */
|
|
104
|
+
function resolveTargets(options) {
|
|
105
|
+
const raw = options.path ?? process.cwd();
|
|
106
|
+
const target = isAbsolute(raw) ? raw : resolve(process.cwd(), raw);
|
|
107
|
+
let isDir = false;
|
|
108
|
+
try {
|
|
109
|
+
isDir = statSync(target).isDirectory();
|
|
110
|
+
}
|
|
111
|
+
catch {
|
|
112
|
+
// Not there: treat a bare directory-looking path as a directory so the
|
|
113
|
+
// error names the WORKFLOW.md we went looking for.
|
|
114
|
+
isDir = !target.endsWith('.md');
|
|
115
|
+
}
|
|
116
|
+
const workflowPath = isDir ? join(target, 'WORKFLOW.md') : target;
|
|
117
|
+
const fallbackRoot = isDir ? target : dirname(target);
|
|
118
|
+
const projectRoot = options.project === undefined
|
|
119
|
+
? fallbackRoot
|
|
120
|
+
: resolve(process.cwd(), options.project);
|
|
121
|
+
return { workflowPath, projectRoot };
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Validate a project's loader: read `WORKFLOW.md`, index the skills it can reach,
|
|
125
|
+
* expand the load, derive the project's triple set, and enforce the contract.
|
|
126
|
+
*
|
|
127
|
+
* Returns the verdict rather than throwing, so the caller owns the exit code.
|
|
128
|
+
*/
|
|
129
|
+
export function runValidate(options = {}) {
|
|
130
|
+
const { workflowPath, projectRoot } = resolveTargets(options);
|
|
131
|
+
const roots = [
|
|
132
|
+
...(options.skills ?? []).map((d) => resolve(process.cwd(), d)),
|
|
133
|
+
...DEFAULT_SKILL_ROOTS.map((d) => join(projectRoot, d)),
|
|
134
|
+
];
|
|
135
|
+
const index = indexSkills(roots);
|
|
136
|
+
let workflowMd;
|
|
137
|
+
try {
|
|
138
|
+
workflowMd = readFileSync(workflowPath, 'utf8');
|
|
139
|
+
}
|
|
140
|
+
catch {
|
|
141
|
+
return {
|
|
142
|
+
ok: false,
|
|
143
|
+
workflowPath,
|
|
144
|
+
roots,
|
|
145
|
+
index,
|
|
146
|
+
error: `cannot read \`${workflowPath}\` — a GAIA project's loader lives at its repository root.`,
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
try {
|
|
150
|
+
const { skills, values } = expandLoad(workflowMd, index.byName);
|
|
151
|
+
const triples = deriveProjectTriples(skills);
|
|
152
|
+
validateLoad(skills, values, triples);
|
|
153
|
+
return {
|
|
154
|
+
ok: true,
|
|
155
|
+
workflowPath,
|
|
156
|
+
roots,
|
|
157
|
+
index,
|
|
158
|
+
loaded: {
|
|
159
|
+
owners: skills.filter((s) => s.when !== undefined).map((s) => s.name),
|
|
160
|
+
helpers: skills.filter((s) => s.when === undefined).map((s) => s.name),
|
|
161
|
+
},
|
|
162
|
+
tripleCount: triples.length,
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
catch (cause) {
|
|
166
|
+
// A StepContractError is the product of this command; anything else is a bug
|
|
167
|
+
// in it, and must not be dressed up as a contract defect.
|
|
168
|
+
if (!(cause instanceof StepContractError))
|
|
169
|
+
throw cause;
|
|
170
|
+
const report = {
|
|
171
|
+
ok: false,
|
|
172
|
+
workflowPath,
|
|
173
|
+
roots,
|
|
174
|
+
index,
|
|
175
|
+
error: cause.message,
|
|
176
|
+
};
|
|
177
|
+
// `exactOptionalPropertyTypes` is on: set these only when core supplied them.
|
|
178
|
+
if (cause.code !== undefined)
|
|
179
|
+
report.errorCode = cause.code;
|
|
180
|
+
if (cause.skill !== undefined)
|
|
181
|
+
report.unresolvedSkill = cause.skill;
|
|
182
|
+
// Measured here, where the document is still in hand, and only for the code
|
|
183
|
+
// that needs it — `formatReport` stays a pure function of the report.
|
|
184
|
+
if (cause.code === 'empty_loader') {
|
|
185
|
+
report.emptyLoader = measureEmptyLoader(workflowMd);
|
|
186
|
+
}
|
|
187
|
+
return report;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
/** Render the report for a terminal. Returns the lines, so tests can read them. */
|
|
191
|
+
export function formatReport(report) {
|
|
192
|
+
const lines = [`workflow: ${report.workflowPath}`];
|
|
193
|
+
lines.push(`skill roots: ${report.roots.join(', ')}`);
|
|
194
|
+
lines.push(`skills indexed: ${report.index.indexed.length}`);
|
|
195
|
+
if (report.ok) {
|
|
196
|
+
const owners = report.loaded?.owners ?? [];
|
|
197
|
+
const helpers = report.loaded?.helpers ?? [];
|
|
198
|
+
lines.push(`OK — ${owners.length} step owner(s)${helpers.length > 0 ? ` + ${helpers.length} helper(s)` : ''} cover all ${report.tripleCount} project triple(s), every override resolves.`);
|
|
199
|
+
lines.push(` owners: ${owners.join(', ')}`);
|
|
200
|
+
if (helpers.length > 0)
|
|
201
|
+
lines.push(` helpers: ${helpers.join(', ')}`);
|
|
202
|
+
for (const s of report.index.shadowed) {
|
|
203
|
+
lines.push(` note: \`${s.name}\` also declared at ${s.path} (ignored)`);
|
|
204
|
+
}
|
|
205
|
+
return lines;
|
|
206
|
+
}
|
|
207
|
+
lines.push(`FAILED: ${report.error}`);
|
|
208
|
+
// An unresolved name is ambiguous on its own: the bullet (or the bundle body)
|
|
209
|
+
// may name the wrong skill, or the skill may simply live somewhere this scan
|
|
210
|
+
// never looked. Say which, so a discovery gap stops wearing a loader defect's
|
|
211
|
+
// message.
|
|
212
|
+
//
|
|
213
|
+
// Branching on the CODE rather than on core's wording (GAIA-436 review) is what
|
|
214
|
+
// brings the bundle-member half of that defect in: it is raised by the same
|
|
215
|
+
// `walk()`, needs the same remedy, and the old message regex never matched it.
|
|
216
|
+
if (report.errorCode === 'unresolved_skill') {
|
|
217
|
+
lines.push(report.index.indexed.length === 0
|
|
218
|
+
? ` no \`SKILL.md\` was found under any scanned root, so nothing could resolve: pass \`--skills <dir>\` pointing at the skills this project loads.`
|
|
219
|
+
: ` \`${report.unresolvedSkill}\` is not among the ${report.index.indexed.length} skill(s) found under the roots above — either the bullet names the wrong skill, or that skill is not vendored here: pass \`--skills <dir>\`.`);
|
|
220
|
+
}
|
|
221
|
+
// The second code, and the reason it earns a branch (GAIA-436 review round 3).
|
|
222
|
+
// `empty_loader` is raised for three documents but carries ONE message, whose
|
|
223
|
+
// "an indented `- @…` line is read as value" fits only the first: a section
|
|
224
|
+
// written with a `*` marker, or one with no line at all, has nothing indented,
|
|
225
|
+
// and sending its author to look at whitespace is the same misdirection as the
|
|
226
|
+
// `coverage gap` this code was introduced to replace. The shape decides the
|
|
227
|
+
// remedy, and the offending lines are named — a report the message cannot give.
|
|
228
|
+
if (report.errorCode === 'empty_loader') {
|
|
229
|
+
const indented = report.emptyLoader?.indented ?? [];
|
|
230
|
+
const bodyLines = report.emptyLoader?.bodyLines ?? 0;
|
|
231
|
+
if (indented.length > 0) {
|
|
232
|
+
lines.push(` ${indented.length} address-shaped line(s) in that section sit below indent 0, so each was read as the preceding bullet's value — de-indent them to column 0:`);
|
|
233
|
+
for (const site of indented.slice(0, MAX_LISTED_LOAD_SITES)) {
|
|
234
|
+
lines.push(` line ${site.line} (indent ${site.indent}): ${site.text}`);
|
|
235
|
+
}
|
|
236
|
+
if (indented.length > MAX_LISTED_LOAD_SITES) {
|
|
237
|
+
lines.push(` … and ${indented.length - MAX_LISTED_LOAD_SITES} more indented line(s)`);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
else if (bodyLines > 0) {
|
|
241
|
+
lines.push(` indentation is NOT the defect here: the section's ${bodyLines} non-blank line(s) carry no \`- @…\` bullet at any indent. A load site is a \`-\`, one space, then \`@<namespace>/<skill-name>\` — a \`*\` marker, or a \`-@\` written without the space, is not one.`);
|
|
242
|
+
}
|
|
243
|
+
else {
|
|
244
|
+
lines.push(` that section is empty: it carries no line between its heading and the next \`##\`, so there is nothing to move — add one \`- @<namespace>/<skill-name>\` bullet per skill the project loads.`);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
// Only relevant on failure, and then usually the cause: a bullet that will not
|
|
248
|
+
// resolve is very often a `SKILL.md` this scan could not read.
|
|
249
|
+
for (const f of report.index.failures) {
|
|
250
|
+
lines.push(` unreadable skill: ${f.path} — ${f.reason}`);
|
|
251
|
+
}
|
|
252
|
+
return lines;
|
|
253
|
+
}
|
|
254
|
+
export function registerValidate(program) {
|
|
255
|
+
program
|
|
256
|
+
.command('validate')
|
|
257
|
+
.description("validate the project's WORKFLOW.md against the loaded skills' step contract")
|
|
258
|
+
.argument('[path]', 'project directory, or a WORKFLOW.md file directly (default: cwd)')
|
|
259
|
+
.option('--project <dir>', 'project root used to discover .claude/skills and .agents/skills')
|
|
260
|
+
.option('--skills <dir>', 'additional skill root to scan for SKILL.md (repeatable)', (value, previous = []) => [...previous, value])
|
|
261
|
+
.action((path, opts) => {
|
|
262
|
+
const report = runValidate({
|
|
263
|
+
path,
|
|
264
|
+
project: opts.project,
|
|
265
|
+
skills: opts.skills,
|
|
266
|
+
});
|
|
267
|
+
const out = report.ok ? process.stdout : process.stderr;
|
|
268
|
+
out.write(`${formatReport(report).join('\n')}\n`);
|
|
269
|
+
if (!report.ok)
|
|
270
|
+
process.exitCode = 1;
|
|
271
|
+
});
|
|
272
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gaia-ai/gaia",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.0",
|
|
4
4
|
"description": "GAIA meta package: the `gaia` plugin-host CLI + all runtime plugins. Global install target.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -38,23 +38,25 @@
|
|
|
38
38
|
"jsonapi"
|
|
39
39
|
],
|
|
40
40
|
"dependencies": {
|
|
41
|
-
"@gaia-ai/addon-auth-basic": "^0.
|
|
42
|
-
"@gaia-ai/addon-claude": "^0.
|
|
43
|
-
"@gaia-ai/addon-codex": "^0.
|
|
44
|
-
"@gaia-ai/addon-deployment": "^0.
|
|
45
|
-
"@gaia-ai/addon-dropsh": "^0.
|
|
46
|
-
"@gaia-ai/addon-essentials": "^0.
|
|
47
|
-
"@gaia-ai/addon-gaia-ui": "^0.
|
|
48
|
-
"@gaia-ai/addon-
|
|
49
|
-
"@gaia-ai/addon-
|
|
50
|
-
"@gaia-ai/addon-
|
|
51
|
-
"@gaia-ai/addon-
|
|
52
|
-
"@gaia-ai/addon-
|
|
53
|
-
"@gaia-ai/addon-
|
|
54
|
-
"@gaia-ai/addon-
|
|
55
|
-
"@gaia-ai/
|
|
56
|
-
"@gaia-ai/
|
|
57
|
-
"@gaia-ai/
|
|
41
|
+
"@gaia-ai/addon-auth-basic": "^0.11.0",
|
|
42
|
+
"@gaia-ai/addon-claude": "^0.11.0",
|
|
43
|
+
"@gaia-ai/addon-codex": "^0.11.0",
|
|
44
|
+
"@gaia-ai/addon-deployment": "^0.11.0",
|
|
45
|
+
"@gaia-ai/addon-dropsh": "^0.11.0",
|
|
46
|
+
"@gaia-ai/addon-essentials": "^0.11.0",
|
|
47
|
+
"@gaia-ai/addon-gaia-ui": "^0.11.0",
|
|
48
|
+
"@gaia-ai/addon-gaia-ui-artifacts": "^0.11.0",
|
|
49
|
+
"@gaia-ai/addon-grok": "^0.11.0",
|
|
50
|
+
"@gaia-ai/addon-herdr": "^0.11.0",
|
|
51
|
+
"@gaia-ai/addon-kimi": "^0.11.0",
|
|
52
|
+
"@gaia-ai/addon-opencode": "^0.11.0",
|
|
53
|
+
"@gaia-ai/addon-pi": "^0.11.0",
|
|
54
|
+
"@gaia-ai/addon-remote-drupal": "^0.11.0",
|
|
55
|
+
"@gaia-ai/addon-workspace": "^0.11.0",
|
|
56
|
+
"@gaia-ai/addon-workspace-git": "^0.11.0",
|
|
57
|
+
"@gaia-ai/conductor": "^0.11.0",
|
|
58
|
+
"@gaia-ai/core": "^0.11.0",
|
|
59
|
+
"@gaia-ai/ui": "^0.11.0",
|
|
58
60
|
"commander": "^12.1.0"
|
|
59
61
|
}
|
|
60
62
|
}
|