@invarn/cli 0.2.1 → 0.2.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.
- package/README.md +4 -0
- package/dist/invarn.cjs +7 -7
- package/dist/sdk.mjs +56 -14
- package/package.json +1 -1
package/dist/sdk.mjs
CHANGED
|
@@ -6995,10 +6995,11 @@ async function cancelBuild(buildId) {
|
|
|
6995
6995
|
body: "{}"
|
|
6996
6996
|
});
|
|
6997
6997
|
}
|
|
6998
|
-
async function registerAgent({ name, type, description, repository, commands, overwrite }) {
|
|
6998
|
+
async function registerAgent({ name, type, description, repository, commands, overwrite, triggers }) {
|
|
6999
6999
|
const body = { name, type, description, commands };
|
|
7000
7000
|
if (repository) body.repository = repository;
|
|
7001
7001
|
if (overwrite) body.overwrite = true;
|
|
7002
|
+
if (Array.isArray(triggers) && triggers.length > 0) body.triggers = triggers;
|
|
7002
7003
|
const res = await request("/agent/register", {
|
|
7003
7004
|
method: "POST",
|
|
7004
7005
|
body: JSON.stringify(body)
|
|
@@ -7090,17 +7091,19 @@ async function getAgentBuildResult(sessionToken, buildId, { wait } = {}) {
|
|
|
7090
7091
|
}
|
|
7091
7092
|
return res.json();
|
|
7092
7093
|
}
|
|
7093
|
-
async function listSecrets({ pipelineId, kind } = {}) {
|
|
7094
|
+
async function listSecrets({ pipelineId, agentId, kind } = {}) {
|
|
7094
7095
|
const url = new URL("/secrets", "http://placeholder");
|
|
7095
7096
|
if (pipelineId) url.searchParams.set("pipeline", pipelineId);
|
|
7097
|
+
if (agentId) url.searchParams.set("agent", agentId);
|
|
7096
7098
|
if (kind) url.searchParams.set("kind", kind);
|
|
7097
7099
|
const res = await request(`${url.pathname}${url.search}`);
|
|
7098
7100
|
const body = await res.json();
|
|
7099
7101
|
return body.entries || [];
|
|
7100
7102
|
}
|
|
7101
|
-
async function createSecret({ scope, pipelineId, kind, key, value }) {
|
|
7103
|
+
async function createSecret({ scope, pipelineId, agentId, kind, key, value }) {
|
|
7102
7104
|
const body = { scope, kind, key, value };
|
|
7103
7105
|
if (pipelineId) body.pipelineId = pipelineId;
|
|
7106
|
+
if (agentId) body.agentId = agentId;
|
|
7104
7107
|
const res = await request("/secrets", {
|
|
7105
7108
|
method: "POST",
|
|
7106
7109
|
body: JSON.stringify(body)
|
|
@@ -8820,7 +8823,8 @@ async function handleAgentRegister(args) {
|
|
|
8820
8823
|
description: args.description,
|
|
8821
8824
|
repository: args.repository,
|
|
8822
8825
|
commands,
|
|
8823
|
-
overwrite: args.overwrite
|
|
8826
|
+
overwrite: args.overwrite,
|
|
8827
|
+
triggers: args.triggers
|
|
8824
8828
|
});
|
|
8825
8829
|
if (result.pipelinePath && result.yamlContent) {
|
|
8826
8830
|
try {
|
|
@@ -8969,12 +8973,19 @@ ${lines.join("\n")}`;
|
|
|
8969
8973
|
}
|
|
8970
8974
|
async function handleSecretsList(args) {
|
|
8971
8975
|
try {
|
|
8976
|
+
if (args.pipeline_id && args.agent_id) {
|
|
8977
|
+
return {
|
|
8978
|
+
content: [{ type: "text", text: "Error: pass either pipeline_id or agent_id, not both." }],
|
|
8979
|
+
isError: true
|
|
8980
|
+
};
|
|
8981
|
+
}
|
|
8972
8982
|
const entries = await listSecrets({
|
|
8973
8983
|
pipelineId: args.pipeline_id || void 0,
|
|
8984
|
+
agentId: args.agent_id || void 0,
|
|
8974
8985
|
kind: args.kind
|
|
8975
8986
|
});
|
|
8976
8987
|
if (entries.length === 0) {
|
|
8977
|
-
const scope = args.pipeline_id ? "pipeline" : "org";
|
|
8988
|
+
const scope = args.pipeline_id || args.agent_id ? "pipeline" : "org";
|
|
8978
8989
|
return {
|
|
8979
8990
|
content: [
|
|
8980
8991
|
{ type: "text", text: `No ${args.kind?.toLowerCase() ?? "entries"} at ${scope} scope.` }
|
|
@@ -8994,12 +9005,19 @@ ${lines.join("\n")}` }] };
|
|
|
8994
9005
|
}
|
|
8995
9006
|
async function handleSecretsSet(args) {
|
|
8996
9007
|
try {
|
|
9008
|
+
if (args.pipeline_id && args.agent_id) {
|
|
9009
|
+
return {
|
|
9010
|
+
content: [{ type: "text", text: "Error: pass either pipeline_id or agent_id, not both." }],
|
|
9011
|
+
isError: true
|
|
9012
|
+
};
|
|
9013
|
+
}
|
|
8997
9014
|
const kind = args.kind === "VARIABLE" ? "VARIABLE" : "SECRET";
|
|
8998
|
-
const scope = args.pipeline_id ? "PIPELINE" : "ORG";
|
|
9015
|
+
const scope = args.pipeline_id || args.agent_id ? "PIPELINE" : "ORG";
|
|
8999
9016
|
try {
|
|
9000
9017
|
await createSecret({
|
|
9001
9018
|
scope,
|
|
9002
9019
|
pipelineId: args.pipeline_id,
|
|
9020
|
+
agentId: args.agent_id,
|
|
9003
9021
|
kind,
|
|
9004
9022
|
key: args.key,
|
|
9005
9023
|
value: args.value
|
|
@@ -9014,7 +9032,11 @@ async function handleSecretsSet(args) {
|
|
|
9014
9032
|
};
|
|
9015
9033
|
} catch (err) {
|
|
9016
9034
|
if (err.statusCode !== 409) throw err;
|
|
9017
|
-
const existing = (await listSecrets({
|
|
9035
|
+
const existing = (await listSecrets({
|
|
9036
|
+
pipelineId: args.pipeline_id,
|
|
9037
|
+
agentId: args.agent_id,
|
|
9038
|
+
kind
|
|
9039
|
+
})).find((e) => e.key === args.key);
|
|
9018
9040
|
if (!existing) throw err;
|
|
9019
9041
|
await updateSecretValue(existing.id, args.value);
|
|
9020
9042
|
return {
|
|
@@ -9144,7 +9166,13 @@ var TOOL_SPECS = [
|
|
|
9144
9166
|
name: z2.string().describe('Command name (e.g. "compile")'),
|
|
9145
9167
|
run: z2.string().describe('Shell command to execute (e.g. "./gradlew assembleDebug")')
|
|
9146
9168
|
})).describe("List of commands this agent can run"),
|
|
9147
|
-
overwrite: z2.boolean().optional().describe("Set true to replace a pipeline file that already exists at .ci/pipelines/agent-<name>.yml in the repo. Use this when re-registering an agent \u2014 e.g. the same repo is connected under another org, or a prior registration was deleted without cleaning up the committed file. Do NOT set this when the existing file is hand-authored YAML unrelated to a prior agent.")
|
|
9169
|
+
overwrite: z2.boolean().optional().describe("Set true to replace a pipeline file that already exists at .ci/pipelines/agent-<name>.yml in the repo. Use this when re-registering an agent \u2014 e.g. the same repo is connected under another org, or a prior registration was deleted without cleaning up the committed file. Do NOT set this when the existing file is hand-authored YAML unrelated to a prior agent."),
|
|
9170
|
+
triggers: z2.array(z2.object({
|
|
9171
|
+
push_branch: z2.string().optional().describe('Match push events where the pushed branch matches this pattern (glob). Use "*" for any branch.'),
|
|
9172
|
+
pull_request_source_branch: z2.string().optional().describe("Match PR events where the source (head) branch matches this pattern."),
|
|
9173
|
+
pull_request_target_branch: z2.string().optional().describe("Match PR events where the target (base) branch matches this pattern."),
|
|
9174
|
+
workflow: z2.string().describe('Workflow to run on match \u2014 must be one of the command names, or the combined "a-and-b-and-c" workflow when multiple commands exist.')
|
|
9175
|
+
})).optional().describe("Events that should trigger this agent automatically. Each rule mirrors cibuild.yml trigger_map entries. Omit to keep the agent manual-only (runnable only via invarn_agent_run). See docs/AGENTS-ROADMAP.md item #2.")
|
|
9148
9176
|
},
|
|
9149
9177
|
handler: async (args) => handleAgentRegister(args)
|
|
9150
9178
|
},
|
|
@@ -9183,16 +9211,17 @@ var TOOL_SPECS = [
|
|
|
9183
9211
|
},
|
|
9184
9212
|
{
|
|
9185
9213
|
name: "invarn_secrets_list",
|
|
9186
|
-
description: "List secret and variable metadata for the organization or a specific pipeline. Returns keys, kinds, scopes, and timestamps \u2014 NEVER values. Use this to check whether a secret exists before calling invarn_agent_run.",
|
|
9214
|
+
description: "List secret and variable metadata for the organization or a specific pipeline. Returns keys, kinds, scopes, and timestamps \u2014 NEVER values. Use this to check whether a secret exists before calling invarn_agent_run. To scope to an agent's pipeline, pass agent_id \u2014 simpler than looking up pipeline_id.",
|
|
9187
9215
|
inputSchema: {
|
|
9188
|
-
pipeline_id: z2.string().optional().describe("Pipeline ID. Omit for org-scoped entries."),
|
|
9216
|
+
pipeline_id: z2.string().optional().describe("Pipeline ID. Omit for org-scoped entries. Mutually exclusive with agent_id."),
|
|
9217
|
+
agent_id: z2.string().optional().describe("Agent ID \u2014 resolves to the agent's owned pipeline server-side. Mutually exclusive with pipeline_id."),
|
|
9189
9218
|
kind: z2.enum(["SECRET", "VARIABLE"]).optional().describe("Filter to a specific kind.")
|
|
9190
9219
|
},
|
|
9191
9220
|
handler: async (args) => handleSecretsList(args ?? {})
|
|
9192
9221
|
},
|
|
9193
9222
|
{
|
|
9194
9223
|
name: "invarn_secrets_set",
|
|
9195
|
-
description: "Create or update a secret or variable. Idempotent \u2014 if the key already exists at this scope, the value is replaced. Requires a human (inv_human_\u2026) token with OWNER or ADMIN role in the org; agent tokens receive 403. There is no read tool \u2014 values cannot be retrieved via MCP.",
|
|
9224
|
+
description: "Create or update a secret or variable. Idempotent \u2014 if the key already exists at this scope, the value is replaced. Requires a human (inv_human_\u2026) token with OWNER or ADMIN role in the org; agent tokens receive 403. There is no read tool \u2014 values cannot be retrieved via MCP. To target an agent's pipeline, pass agent_id instead of pipeline_id.",
|
|
9196
9225
|
inputSchema: {
|
|
9197
9226
|
key: z2.string().describe(
|
|
9198
9227
|
"Uppercase env-var-safe key (/^[A-Z_][A-Z0-9_]{0,63}$/, not starting with INVARN_)."
|
|
@@ -9201,7 +9230,8 @@ var TOOL_SPECS = [
|
|
|
9201
9230
|
kind: z2.enum(["SECRET", "VARIABLE"]).describe(
|
|
9202
9231
|
"SECRET: encrypted at rest, redacted from build logs. VARIABLE: plaintext, visible in dashboard and logs when echoed."
|
|
9203
9232
|
),
|
|
9204
|
-
pipeline_id: z2.string().optional().describe("Pipeline ID for a pipeline-scoped entry. Omit for org scope.")
|
|
9233
|
+
pipeline_id: z2.string().optional().describe("Pipeline ID for a pipeline-scoped entry. Omit for org scope. Mutually exclusive with agent_id."),
|
|
9234
|
+
agent_id: z2.string().optional().describe("Agent ID \u2014 resolves to the agent's owned pipeline server-side. Mutually exclusive with pipeline_id. Omit both for org scope.")
|
|
9205
9235
|
},
|
|
9206
9236
|
handler: async (args) => handleSecretsSet(args)
|
|
9207
9237
|
}
|
|
@@ -9311,19 +9341,27 @@ function buildHandlers(ctx, getSession) {
|
|
|
9311
9341
|
return result;
|
|
9312
9342
|
},
|
|
9313
9343
|
invarn_secrets_list: async (args) => {
|
|
9344
|
+
if (args.pipeline_id && args.agent_id) {
|
|
9345
|
+
throw new Error("pass either pipeline_id or agent_id, not both");
|
|
9346
|
+
}
|
|
9314
9347
|
const entries = await listSecrets({
|
|
9315
9348
|
pipelineId: args.pipeline_id || void 0,
|
|
9349
|
+
agentId: args.agent_id || void 0,
|
|
9316
9350
|
kind: args.kind
|
|
9317
9351
|
});
|
|
9318
9352
|
return { entries };
|
|
9319
9353
|
},
|
|
9320
9354
|
invarn_secrets_set: async (args) => {
|
|
9355
|
+
if (args.pipeline_id && args.agent_id) {
|
|
9356
|
+
throw new Error("pass either pipeline_id or agent_id, not both");
|
|
9357
|
+
}
|
|
9321
9358
|
const kind = args.kind === "VARIABLE" ? "VARIABLE" : "SECRET";
|
|
9322
|
-
const scope = args.pipeline_id ? "PIPELINE" : "ORG";
|
|
9359
|
+
const scope = args.pipeline_id || args.agent_id ? "PIPELINE" : "ORG";
|
|
9323
9360
|
try {
|
|
9324
9361
|
await createSecret({
|
|
9325
9362
|
scope,
|
|
9326
9363
|
pipelineId: args.pipeline_id,
|
|
9364
|
+
agentId: args.agent_id,
|
|
9327
9365
|
kind,
|
|
9328
9366
|
key: args.key,
|
|
9329
9367
|
value: args.value
|
|
@@ -9331,7 +9369,11 @@ function buildHandlers(ctx, getSession) {
|
|
|
9331
9369
|
return { action: "created", key: args.key, kind, scope: scope.toLowerCase() };
|
|
9332
9370
|
} catch (err) {
|
|
9333
9371
|
if (err.statusCode !== 409) throw err;
|
|
9334
|
-
const existing = (await listSecrets({
|
|
9372
|
+
const existing = (await listSecrets({
|
|
9373
|
+
pipelineId: args.pipeline_id,
|
|
9374
|
+
agentId: args.agent_id,
|
|
9375
|
+
kind
|
|
9376
|
+
})).find((e) => e.key === args.key);
|
|
9335
9377
|
if (!existing) throw err;
|
|
9336
9378
|
await updateSecretValue(existing.id, args.value);
|
|
9337
9379
|
return { action: "updated", key: args.key, kind, scope: scope.toLowerCase() };
|