lua-cli 3.25.0 → 3.27.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/api-exports.d.ts +143 -3
- package/dist/api-exports.js +96 -2
- package/dist/api-exports.js.map +1 -1
- package/dist/index.js +660 -27
- package/dist/index.js.map +1 -1
- package/docs/README.md +2 -2
- package/package.json +1 -1
- package/template/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1160,6 +1160,9 @@ function resolveRequireToolApproval(rules) {
|
|
|
1160
1160
|
function buildDefaultPersona(agentName) {
|
|
1161
1161
|
return DEFAULT_PERSONA_GUIDE.replace(AGENT_NAME_TOKEN, () => agentName || "My Agent");
|
|
1162
1162
|
}
|
|
1163
|
+
function buildPersonalSpaceStartingPersona(agentName) {
|
|
1164
|
+
return PERSONAL_SPACE_STARTING_PERSONA.replace(new RegExp(AGENT_NAME_TOKEN.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), "g"), () => agentName || "Your assistant");
|
|
1165
|
+
}
|
|
1163
1166
|
function resolveLuaJobTimeoutSeconds(timeout) {
|
|
1164
1167
|
const resolved = timeout ?? LUA_JOB_DEFAULT_TIMEOUT_SECONDS;
|
|
1165
1168
|
if (!Number.isInteger(resolved)) {
|
|
@@ -1176,7 +1179,7 @@ function normalizeLuaJobExecutionTimeoutSeconds(timeout) {
|
|
|
1176
1179
|
}
|
|
1177
1180
|
return Math.min(Math.max(timeout, LUA_JOB_MIN_TIMEOUT_SECONDS), LUA_JOB_MAX_TIMEOUT_SECONDS);
|
|
1178
1181
|
}
|
|
1179
|
-
var __defProp2, __name2, REVIEWABLE_ACTION_EXECUTE_TOOL_ALLOWLIST, REVIEWABLE_MCP_SEND_TOOL_SUFFIX, MCP_TOOL_READ_VERB_RE, MCP_DRAFT_CREATE_VERBS, NON_INTERACTIVE_CHANNELS, RICH_PARTS_MESSAGE_ID_PREFIX, SCREENSHOT_MESSAGE_ID_PREFIX, BROWSER_COMMANDS, BROWSER_COMMAND_NAMES, DESKTOP_FILE_COMMANDS, DESKTOP_FILE_COMMAND_SET, REASONING_EFFORT_VALUES, IMPLICIT_MODEL_SELECTION_SOURCES, AGENT_NAME_TOKEN, DEFAULT_PERSONA_GUIDE, AGENT_LOG_SOURCES, VoiceNameSchema, PluginProviderSchema, RealtimeProviderSchema, PluginClassSchema, ModelDescriptorSchema, InferenceModelSchema, PluginModelSchema, RealtimeModelSchema, LuaVoiceModelSchema, TurnDetectionSchema, InterruptionSchema, BuiltinAudioClipSchema, AudioConfigSchema, BackgroundAudioEntrySchema, BackgroundAudioSchema, LuaVoiceConfigInnerSchema, LuaVoiceConfigSchema, LuaVoiceRefSchema, LUA_JOB_DEFAULT_TIMEOUT_SECONDS, LUA_JOB_MIN_TIMEOUT_SECONDS, LUA_JOB_MAX_TIMEOUT_SECONDS;
|
|
1182
|
+
var __defProp2, __name2, REVIEWABLE_ACTION_EXECUTE_TOOL_ALLOWLIST, REVIEWABLE_MCP_SEND_TOOL_SUFFIX, MCP_TOOL_READ_VERB_RE, MCP_DRAFT_CREATE_VERBS, NON_INTERACTIVE_CHANNELS, RICH_PARTS_MESSAGE_ID_PREFIX, SCREENSHOT_MESSAGE_ID_PREFIX, BROWSER_COMMANDS, BROWSER_COMMAND_NAMES, DESKTOP_FILE_COMMANDS, DESKTOP_FILE_COMMAND_SET, REASONING_EFFORT_VALUES, IMPLICIT_MODEL_SELECTION_SOURCES, AGENT_NAME_TOKEN, DEFAULT_PERSONA_GUIDE, PERSONAL_SPACE_STARTING_PERSONA, AGENT_LOG_SOURCES, VoiceNameSchema, PluginProviderSchema, RealtimeProviderSchema, PluginClassSchema, ModelDescriptorSchema, InferenceModelSchema, PluginModelSchema, RealtimeModelSchema, LuaVoiceModelSchema, TurnDetectionSchema, InterruptionSchema, BuiltinAudioClipSchema, AudioConfigSchema, BackgroundAudioEntrySchema, BackgroundAudioSchema, LuaVoiceConfigInnerSchema, LuaVoiceConfigSchema, LuaVoiceRefSchema, LUA_JOB_DEFAULT_TIMEOUT_SECONDS, LUA_JOB_MIN_TIMEOUT_SECONDS, LUA_JOB_MAX_TIMEOUT_SECONDS;
|
|
1180
1183
|
var init_dist = __esm({
|
|
1181
1184
|
"../shared-types/dist/index.mjs"() {
|
|
1182
1185
|
"use strict";
|
|
@@ -1547,6 +1550,40 @@ Feel free to add, remove, or rename sections. Your persona can be a single parag
|
|
|
1547
1550
|
`;
|
|
1548
1551
|
__name(buildDefaultPersona, "buildDefaultPersona");
|
|
1549
1552
|
__name2(buildDefaultPersona, "buildDefaultPersona");
|
|
1553
|
+
PERSONAL_SPACE_STARTING_PERSONA = `# ${AGENT_NAME_TOKEN}
|
|
1554
|
+
|
|
1555
|
+
You are ${AGENT_NAME_TOKEN}, the assistant for whoever is chatting with you here. Your job is simple: help them get things done, and get better at it every day.
|
|
1556
|
+
|
|
1557
|
+
## You're just getting started
|
|
1558
|
+
|
|
1559
|
+
This workspace is new. What you already know about the person lives in your memory \u2014 the "Known about this user" notes are verified facts, so use them like you've known them all along; never say you don't know something that's written there. Beyond that, don't pretend. Pay attention instead: how they write, what they ask for, what they're working on. When something matters and you're not sure, ask. One good question beats a wrong guess.
|
|
1560
|
+
|
|
1561
|
+
## You have real tools
|
|
1562
|
+
|
|
1563
|
+
You can do a lot more than talk. Use your tools when they help, and be straight about what worked and what didn't. The more you learn, the more you can take off their plate without being asked.
|
|
1564
|
+
|
|
1565
|
+
## How you sound
|
|
1566
|
+
|
|
1567
|
+
Like a sharp, warm human who's on their side. Plain words. Short sentences when short works. React like a person would: if something's great, say so; if something's off, say that too. No corporate filler, no fake enthusiasm.
|
|
1568
|
+
|
|
1569
|
+
## What you hold yourself to
|
|
1570
|
+
|
|
1571
|
+
- Never make up facts about the person, and never claim you did something you didn't.
|
|
1572
|
+
- What you learn about them serves them. Nothing else.
|
|
1573
|
+
- If you can't do something, say so and offer what you can do.
|
|
1574
|
+
|
|
1575
|
+
## Where you come from
|
|
1576
|
+
|
|
1577
|
+
You live on Lua, the platform this workspace runs on. Lua gives people AI agents that do real work for them, and it lives at heylua.ai. It was founded by Lorcan (CEO) and Stefan (CTO).
|
|
1578
|
+
|
|
1579
|
+
If someone asks about Lua itself, have fun with it. It's your hometown, so show them around like a proud local: keep the facts straight, keep the delivery playful and a little whimsical. For anything you don't know (pricing, plans, roadmap), point them to heylua.ai instead of guessing.
|
|
1580
|
+
|
|
1581
|
+
## Keep this persona alive
|
|
1582
|
+
|
|
1583
|
+
This text is who you are for this person. As you learn them, their name, their work, what they care about, update it so tomorrow's you starts smarter than today's. Keep it about who they are and who you are for them.
|
|
1584
|
+
`;
|
|
1585
|
+
__name(buildPersonalSpaceStartingPersona, "buildPersonalSpaceStartingPersona");
|
|
1586
|
+
__name2(buildPersonalSpaceStartingPersona, "buildPersonalSpaceStartingPersona");
|
|
1550
1587
|
AGENT_LOG_SOURCES = [
|
|
1551
1588
|
"skill",
|
|
1552
1589
|
"job",
|
|
@@ -3298,6 +3335,7 @@ var init_files = __esm({
|
|
|
3298
3335
|
"preprocessors",
|
|
3299
3336
|
"postprocessors",
|
|
3300
3337
|
"mcpServers",
|
|
3338
|
+
"template",
|
|
3301
3339
|
"skill"
|
|
3302
3340
|
];
|
|
3303
3341
|
__name(yamlKeySorter, "yamlKeySorter");
|
|
@@ -13107,6 +13145,43 @@ var init_ai_api_service = __esm({
|
|
|
13107
13145
|
}
|
|
13108
13146
|
});
|
|
13109
13147
|
|
|
13148
|
+
// src/api/integrations.api.service.ts
|
|
13149
|
+
var IntegrationsApiService;
|
|
13150
|
+
var init_integrations_api_service = __esm({
|
|
13151
|
+
"src/api/integrations.api.service.ts"() {
|
|
13152
|
+
"use strict";
|
|
13153
|
+
init_http_client();
|
|
13154
|
+
IntegrationsApiService = class extends HttpClient {
|
|
13155
|
+
static {
|
|
13156
|
+
__name(this, "IntegrationsApiService");
|
|
13157
|
+
}
|
|
13158
|
+
apiKey;
|
|
13159
|
+
agentId;
|
|
13160
|
+
constructor(baseUrl, apiKey, agentId) {
|
|
13161
|
+
super(baseUrl), this.apiKey = apiKey, this.agentId = agentId;
|
|
13162
|
+
}
|
|
13163
|
+
async passthrough(integrationType, request2) {
|
|
13164
|
+
return this.httpPost(`/developer/unifiedto/connections/${encodeURIComponent(this.agentId)}/passthrough/${encodeURIComponent(integrationType)}`, request2, {
|
|
13165
|
+
Authorization: `Bearer ${this.apiKey}`
|
|
13166
|
+
});
|
|
13167
|
+
}
|
|
13168
|
+
/**
|
|
13169
|
+
* Sandbox-facing wrapper: returns the raw provider envelope
|
|
13170
|
+
* `{ status, headers, data }` (provider error statuses relayed faithfully in
|
|
13171
|
+
* `status`), and throws only on route-level failures (no connection,
|
|
13172
|
+
* passthrough disabled, rate limited, transport error).
|
|
13173
|
+
*/
|
|
13174
|
+
async passthroughForSandbox(integrationType, request2) {
|
|
13175
|
+
const result = await this.passthrough(integrationType, request2);
|
|
13176
|
+
if (!result.success || !result.data) {
|
|
13177
|
+
throw new Error(result.error?.message || `Integration passthrough failed for '${integrationType}'`);
|
|
13178
|
+
}
|
|
13179
|
+
return result.data;
|
|
13180
|
+
}
|
|
13181
|
+
};
|
|
13182
|
+
}
|
|
13183
|
+
});
|
|
13184
|
+
|
|
13110
13185
|
// src/api/agents.api.service.ts
|
|
13111
13186
|
var AgentsApiService;
|
|
13112
13187
|
var init_agents_api_service = __esm({
|
|
@@ -13853,6 +13928,7 @@ __export(lazy_instances_exports, {
|
|
|
13853
13928
|
getDeviceInstance: () => getDeviceInstance,
|
|
13854
13929
|
getDirectoryInstance: () => getDirectoryInstance,
|
|
13855
13930
|
getInboxPushInstance: () => getInboxPushInstance,
|
|
13931
|
+
getIntegrationsInstance: () => getIntegrationsInstance,
|
|
13856
13932
|
getJobInstance: () => getJobInstance,
|
|
13857
13933
|
getOrderInstance: () => getOrderInstance,
|
|
13858
13934
|
getProductsInstance: () => getProductsInstance,
|
|
@@ -13917,6 +13993,13 @@ async function getAiInstance() {
|
|
|
13917
13993
|
}
|
|
13918
13994
|
return _aiInstance;
|
|
13919
13995
|
}
|
|
13996
|
+
async function getIntegrationsInstance() {
|
|
13997
|
+
if (!_integrationsInstance) {
|
|
13998
|
+
const creds = await getCredentials();
|
|
13999
|
+
_integrationsInstance = new IntegrationsApiService(BASE_URLS.API, creds.apiKey, creds.agentId);
|
|
14000
|
+
}
|
|
14001
|
+
return _integrationsInstance;
|
|
14002
|
+
}
|
|
13920
14003
|
async function getAgentsInstance() {
|
|
13921
14004
|
if (!_agentsInstance) {
|
|
13922
14005
|
const creds = await getCredentials();
|
|
@@ -13998,7 +14081,7 @@ function clearAllInstances() {
|
|
|
13998
14081
|
_channelsSendInstance = null;
|
|
13999
14082
|
_directoryInstance = null;
|
|
14000
14083
|
}
|
|
14001
|
-
var _userInstance, _dataInstance, _productsInstance, _basketsInstance, _orderInstance, _webhookInstance, _jobInstance, _aiInstance, _agentsInstance, _whatsAppTemplatesInstance, _cdnInstance, _developerInstance, _voiceInstance, _channelsSendInstance, _directoryInstance, _deviceInstance, _inboxPushInstance;
|
|
14084
|
+
var _userInstance, _dataInstance, _productsInstance, _basketsInstance, _orderInstance, _webhookInstance, _jobInstance, _aiInstance, _integrationsInstance, _agentsInstance, _whatsAppTemplatesInstance, _cdnInstance, _developerInstance, _voiceInstance, _channelsSendInstance, _directoryInstance, _deviceInstance, _inboxPushInstance;
|
|
14002
14085
|
var init_lazy_instances = __esm({
|
|
14003
14086
|
"src/api/lazy-instances.ts"() {
|
|
14004
14087
|
"use strict";
|
|
@@ -14012,6 +14095,7 @@ var init_lazy_instances = __esm({
|
|
|
14012
14095
|
init_webhook_api_service();
|
|
14013
14096
|
init_job_api_service();
|
|
14014
14097
|
init_ai_api_service();
|
|
14098
|
+
init_integrations_api_service();
|
|
14015
14099
|
init_agents_api_service();
|
|
14016
14100
|
init_whatsapp_templates_api_service();
|
|
14017
14101
|
init_cdn_api_service();
|
|
@@ -14028,6 +14112,7 @@ var init_lazy_instances = __esm({
|
|
|
14028
14112
|
_webhookInstance = null;
|
|
14029
14113
|
_jobInstance = null;
|
|
14030
14114
|
_aiInstance = null;
|
|
14115
|
+
_integrationsInstance = null;
|
|
14031
14116
|
_agentsInstance = null;
|
|
14032
14117
|
_whatsAppTemplatesInstance = null;
|
|
14033
14118
|
_cdnInstance = null;
|
|
@@ -14043,6 +14128,7 @@ var init_lazy_instances = __esm({
|
|
|
14043
14128
|
__name(getWebhookInstance, "getWebhookInstance");
|
|
14044
14129
|
__name(getJobInstance, "getJobInstance");
|
|
14045
14130
|
__name(getAiInstance, "getAiInstance");
|
|
14131
|
+
__name(getIntegrationsInstance, "getIntegrationsInstance");
|
|
14046
14132
|
__name(getAgentsInstance, "getAgentsInstance");
|
|
14047
14133
|
__name(getWhatsAppTemplatesInstance, "getWhatsAppTemplatesInstance");
|
|
14048
14134
|
__name(getCdnInstance, "getCdnInstance");
|
|
@@ -21850,6 +21936,16 @@ function createSandbox(options) {
|
|
|
21850
21936
|
return agents.invokeForSandbox(targetAgentId, promptOrInput);
|
|
21851
21937
|
}, "invoke")
|
|
21852
21938
|
},
|
|
21939
|
+
// Unified.to raw provider passthrough (PRO-209). Proxied via the same
|
|
21940
|
+
// bearer-auth developer route the api-exports `Integrations` namespace
|
|
21941
|
+
// uses, so `lua test` matches production behavior.
|
|
21942
|
+
Integrations: {
|
|
21943
|
+
passthrough: /* @__PURE__ */ __name(async (integrationType, request2) => {
|
|
21944
|
+
const { getIntegrationsInstance: getIntegrationsInstance2 } = await Promise.resolve().then(() => (init_lazy_instances(), lazy_instances_exports));
|
|
21945
|
+
const integrations = await getIntegrationsInstance2();
|
|
21946
|
+
return integrations.passthroughForSandbox(integrationType, request2);
|
|
21947
|
+
}, "passthrough")
|
|
21948
|
+
},
|
|
21853
21949
|
// Outbound voice dispatch (BAC-212). `lua test` proxies via the same
|
|
21854
21950
|
// bearer-auth developer endpoint the lua-cli `Voice.call` namespace uses
|
|
21855
21951
|
// — keeps the surface byte-equivalent to the lua-core production VM
|
|
@@ -22652,12 +22748,14 @@ var ALIAS_MAP = {
|
|
|
22652
22748
|
"available",
|
|
22653
22749
|
"info",
|
|
22654
22750
|
"disconnect",
|
|
22751
|
+
"convert",
|
|
22655
22752
|
"webhooks",
|
|
22656
22753
|
"mcp"
|
|
22657
22754
|
],
|
|
22658
22755
|
aliases: lowerKeys({
|
|
22659
22756
|
add: "connect",
|
|
22660
22757
|
link: "connect",
|
|
22758
|
+
claim: "convert",
|
|
22661
22759
|
edit: "update",
|
|
22662
22760
|
modify: "update",
|
|
22663
22761
|
ls: "list",
|
|
@@ -22792,6 +22890,7 @@ var ALIAS_MAP = {
|
|
|
22792
22890
|
"template.action": {
|
|
22793
22891
|
canonical: [
|
|
22794
22892
|
"create",
|
|
22893
|
+
"draft",
|
|
22795
22894
|
"publish",
|
|
22796
22895
|
"view",
|
|
22797
22896
|
"versions",
|
|
@@ -22803,6 +22902,7 @@ var ALIAS_MAP = {
|
|
|
22803
22902
|
],
|
|
22804
22903
|
aliases: lowerKeys({
|
|
22805
22904
|
new: "create",
|
|
22905
|
+
compose: "draft",
|
|
22806
22906
|
publish_version: "publish",
|
|
22807
22907
|
submit: "publish",
|
|
22808
22908
|
show: "view",
|
|
@@ -37935,6 +38035,13 @@ var TemplateApiService = class {
|
|
|
37935
38035
|
body: JSON.stringify(data)
|
|
37936
38036
|
});
|
|
37937
38037
|
}
|
|
38038
|
+
/** T11.3 — draft composer (the clean `/templates/*` route home). */
|
|
38039
|
+
async composeDraft(templateId, data) {
|
|
38040
|
+
return this._fetch(`/templates/${templateId}/versions/draft`, {
|
|
38041
|
+
method: "POST",
|
|
38042
|
+
body: JSON.stringify(data)
|
|
38043
|
+
});
|
|
38044
|
+
}
|
|
37938
38045
|
async listTemplates() {
|
|
37939
38046
|
return this._fetch("/marketplace/templates");
|
|
37940
38047
|
}
|
|
@@ -37991,12 +38098,14 @@ var TemplateApiService = class {
|
|
|
37991
38098
|
// src/commands/template.ts
|
|
37992
38099
|
init_command_utils();
|
|
37993
38100
|
init_analytics();
|
|
38101
|
+
init_files();
|
|
37994
38102
|
function showTemplateUsage() {
|
|
37995
38103
|
console.log("\nUsage:");
|
|
37996
38104
|
console.log(" lua marketplace template Interactive mode");
|
|
37997
38105
|
console.log(" lua marketplace template <action> [options] Non-interactive mode");
|
|
37998
38106
|
console.log("\nActions:");
|
|
37999
38107
|
console.log(" create --name <n> --display-name <n> [--description <text>] [--visibility public|private]");
|
|
38108
|
+
console.log(" draft --template-id <id> [--source-version <n>] [--force] Compose/merge the template: section of lua.skill.yaml");
|
|
38000
38109
|
console.log(" publish --template-id <id> [--source-version <n>] [--changelog <text>] [--env-contract KEY=desc,...]");
|
|
38001
38110
|
console.log(" view --template-id <id> [--version <n>] [--json]");
|
|
38002
38111
|
console.log(" versions --template-id <id> [--json]");
|
|
@@ -38024,6 +38133,10 @@ async function templateCommand(action, options = {}) {
|
|
|
38024
38133
|
name: "Create a template from this agent",
|
|
38025
38134
|
value: "create"
|
|
38026
38135
|
},
|
|
38136
|
+
{
|
|
38137
|
+
name: "Draft the template: section from this agent",
|
|
38138
|
+
value: "draft"
|
|
38139
|
+
},
|
|
38027
38140
|
{
|
|
38028
38141
|
name: "Publish a new template version",
|
|
38029
38142
|
value: "publish"
|
|
@@ -38073,8 +38186,11 @@ async function templateCommand(action, options = {}) {
|
|
|
38073
38186
|
case "create":
|
|
38074
38187
|
await templateCreateAction(templateApi, config, options);
|
|
38075
38188
|
break;
|
|
38189
|
+
case "draft":
|
|
38190
|
+
await templateDraftAction(templateApi, options);
|
|
38191
|
+
break;
|
|
38076
38192
|
case "publish":
|
|
38077
|
-
await templatePublishAction(templateApi, options);
|
|
38193
|
+
await templatePublishAction(templateApi, config, options);
|
|
38078
38194
|
break;
|
|
38079
38195
|
case "view":
|
|
38080
38196
|
await templateViewAction(templateApi, options);
|
|
@@ -38320,18 +38436,125 @@ async function templateCreateAction(templateApi, config, options) {
|
|
|
38320
38436
|
});
|
|
38321
38437
|
}
|
|
38322
38438
|
__name(templateCreateAction, "templateCreateAction");
|
|
38323
|
-
async function
|
|
38439
|
+
async function templateDraftAction(templateApi, options) {
|
|
38440
|
+
const config = readYamlConfig();
|
|
38441
|
+
if (!config) throw new Error("No lua.skill.yaml found in this directory.");
|
|
38442
|
+
const templateId = await resolveTemplateId(templateApi, options, "Which template would you like to draft for?");
|
|
38443
|
+
const sourceAgentVersion = options.sourceVersion ? Number.parseInt(options.sourceVersion, 10) : void 0;
|
|
38444
|
+
if (options.sourceVersion && (!Number.isFinite(sourceAgentVersion) || sourceAgentVersion <= 0)) {
|
|
38445
|
+
throw new Error(`Invalid --source-version "${options.sourceVersion}": must be a positive integer.`);
|
|
38446
|
+
}
|
|
38447
|
+
writeProgress("\u{1F504} Composing template draft...");
|
|
38448
|
+
const result = await templateApi.composeDraft(templateId, {
|
|
38449
|
+
force: options.force === true,
|
|
38450
|
+
sourceAgentVersion
|
|
38451
|
+
});
|
|
38452
|
+
config.template = {
|
|
38453
|
+
connections: result.draft.connections,
|
|
38454
|
+
...result.draft.personaTemplate ? {
|
|
38455
|
+
personaTemplate: result.draft.personaTemplate
|
|
38456
|
+
} : {},
|
|
38457
|
+
triggerPresets: result.draft.triggerPresets,
|
|
38458
|
+
paramsMeta: result.draft.paramsMeta
|
|
38459
|
+
};
|
|
38460
|
+
writeYamlConfig(config);
|
|
38461
|
+
if (options.json) {
|
|
38462
|
+
console.log(JSON.stringify(result, null, 2));
|
|
38463
|
+
return;
|
|
38464
|
+
}
|
|
38465
|
+
writeSuccess("\u2705 template: section written to lua.skill.yaml");
|
|
38466
|
+
for (const [section2, diff] of Object.entries(result.diff)) {
|
|
38467
|
+
const annotations = Object.entries(diff.annotations ?? {});
|
|
38468
|
+
console.log(` ${section2}: +${diff.added.length} added (${diff.added.join(", ") || "\u2014"}), ${diff.kept.length} kept`);
|
|
38469
|
+
for (const [key, note] of annotations) {
|
|
38470
|
+
console.log(` \u26A0 ${key}: ${note}`);
|
|
38471
|
+
}
|
|
38472
|
+
}
|
|
38473
|
+
writeHintBlock({
|
|
38474
|
+
headline: "Review the drafted sections, then publish:",
|
|
38475
|
+
lines: [
|
|
38476
|
+
{
|
|
38477
|
+
label: "Publish:",
|
|
38478
|
+
command: `lua marketplace template publish --template-id ${templateId}`
|
|
38479
|
+
}
|
|
38480
|
+
],
|
|
38481
|
+
when: "success"
|
|
38482
|
+
});
|
|
38483
|
+
}
|
|
38484
|
+
__name(templateDraftAction, "templateDraftAction");
|
|
38485
|
+
var TEMPLATE_SECTION_KEYS = [
|
|
38486
|
+
"connections",
|
|
38487
|
+
"personaTemplate",
|
|
38488
|
+
"triggerPresets",
|
|
38489
|
+
"paramsMeta"
|
|
38490
|
+
];
|
|
38491
|
+
function sectionKeys(section2, value) {
|
|
38492
|
+
if (value === void 0 || value === null) return [];
|
|
38493
|
+
if (section2 === "connections") return (value ?? []).map((entry) => entry.key);
|
|
38494
|
+
if (section2 === "personaTemplate") {
|
|
38495
|
+
const vars = value.vars ?? [];
|
|
38496
|
+
return vars.map((v) => v.name);
|
|
38497
|
+
}
|
|
38498
|
+
return Object.keys(value);
|
|
38499
|
+
}
|
|
38500
|
+
__name(sectionKeys, "sectionKeys");
|
|
38501
|
+
async function confirmTemplateSectionConsequences(templateApi, templateId, local, force) {
|
|
38502
|
+
const versions = await templateApi.getVersions(templateId).catch(() => []);
|
|
38503
|
+
const latest = [
|
|
38504
|
+
...versions
|
|
38505
|
+
].sort((a, b) => b.version - a.version)[0];
|
|
38506
|
+
if (!latest) return;
|
|
38507
|
+
const consequences = [];
|
|
38508
|
+
const consequenceCopy = {
|
|
38509
|
+
connections: "installed agents keep their binding; new installs will not be prompted",
|
|
38510
|
+
personaTemplate: "new installs get no persona template; installed personas are untouched",
|
|
38511
|
+
triggerPresets: "new installs fall back to default arming recommendations",
|
|
38512
|
+
paramsMeta: "the deploy form falls back to derived display names and string typing"
|
|
38513
|
+
};
|
|
38514
|
+
for (const section2 of TEMPLATE_SECTION_KEYS) {
|
|
38515
|
+
const serverKeys = sectionKeys(section2, latest[section2]);
|
|
38516
|
+
const localKeys = sectionKeys(section2, local[section2]);
|
|
38517
|
+
const removed = serverKeys.filter((key) => !localKeys.includes(key));
|
|
38518
|
+
if (!removed.length) continue;
|
|
38519
|
+
const clearing = localKeys.length === 0;
|
|
38520
|
+
consequences.push(` ${section2}: ${clearing ? "CLEARING the section" : `removing ${removed.join(", ")}`} \u2014 ${consequenceCopy[section2]}`);
|
|
38521
|
+
}
|
|
38522
|
+
if (!consequences.length) return;
|
|
38523
|
+
console.log("\n\u26A0 This publish clears or narrows authored template sections:");
|
|
38524
|
+
for (const line of consequences) console.log(line);
|
|
38525
|
+
const isTTY = Boolean(process.stdin.isTTY && process.stdout.isTTY);
|
|
38526
|
+
if (force || isCiModeEnabled() || !isTTY) {
|
|
38527
|
+
writeInfo("Proceeding headless (diff printed above).");
|
|
38528
|
+
return;
|
|
38529
|
+
}
|
|
38530
|
+
const confirmed = await confirmAction("\nProceed with this publish?");
|
|
38531
|
+
if (!confirmed) throw new Error("Publish aborted.");
|
|
38532
|
+
}
|
|
38533
|
+
__name(confirmTemplateSectionConsequences, "confirmTemplateSectionConsequences");
|
|
38534
|
+
async function templatePublishAction(templateApi, config, options) {
|
|
38324
38535
|
const templateId = await resolveTemplateId(templateApi, options, "Which template would you like to publish a version for?");
|
|
38325
38536
|
const sourceAgentVersion = options.sourceVersion ? Number.parseInt(options.sourceVersion, 10) : void 0;
|
|
38326
38537
|
if (options.sourceVersion && (!Number.isFinite(sourceAgentVersion) || sourceAgentVersion <= 0)) {
|
|
38327
38538
|
throw new Error(`Invalid --source-version "${options.sourceVersion}": must be a positive integer.`);
|
|
38328
38539
|
}
|
|
38329
38540
|
const envContract = parseEnvContract(options.envContract);
|
|
38541
|
+
const templateSection = readYamlConfig()?.template ?? config.template;
|
|
38542
|
+
let sectionBody = {};
|
|
38543
|
+
if (templateSection !== void 0) {
|
|
38544
|
+
await confirmTemplateSectionConsequences(templateApi, templateId, templateSection, options.force === true || options.yes === true);
|
|
38545
|
+
sectionBody = {
|
|
38546
|
+
connections: templateSection.connections ?? [],
|
|
38547
|
+
triggerPresets: templateSection.triggerPresets ?? {},
|
|
38548
|
+
personaTemplate: templateSection.personaTemplate ?? null,
|
|
38549
|
+
paramsMeta: templateSection.paramsMeta ?? {}
|
|
38550
|
+
};
|
|
38551
|
+
}
|
|
38330
38552
|
writeProgress("\u{1F504} Publishing template version...");
|
|
38331
38553
|
const version = await templateApi.createVersion(templateId, {
|
|
38332
38554
|
sourceAgentVersion,
|
|
38333
38555
|
changelog: options.changelog || void 0,
|
|
38334
|
-
envContract
|
|
38556
|
+
envContract,
|
|
38557
|
+
...sectionBody
|
|
38335
38558
|
});
|
|
38336
38559
|
if (options.json) {
|
|
38337
38560
|
console.log(JSON.stringify(version, null, 2));
|
|
@@ -38427,12 +38650,14 @@ async function templateInstallAction(templateApi, config, options) {
|
|
|
38427
38650
|
console.error("\n\u274C Use --force to confirm installation");
|
|
38428
38651
|
throw new Error("This action requires --force to confirm");
|
|
38429
38652
|
}
|
|
38653
|
+
if (options.skipEnvCheck) {
|
|
38654
|
+
writeInfo("\u26A0\uFE0F --skip-env-check is deprecated: the env-contract check is server-enforced; use `lua env` to satisfy the contract.");
|
|
38655
|
+
}
|
|
38430
38656
|
writeProgress("\u{1F504} Installing template...");
|
|
38431
38657
|
const install = await templateApi.install(templateId, agentId, {
|
|
38432
38658
|
version,
|
|
38433
38659
|
envValues,
|
|
38434
|
-
allowCreatorUpdates: options.allowCreatorUpdates
|
|
38435
|
-
skipEnvCheck: options.skipEnvCheck
|
|
38660
|
+
allowCreatorUpdates: options.allowCreatorUpdates
|
|
38436
38661
|
});
|
|
38437
38662
|
if (options.json) {
|
|
38438
38663
|
console.log(JSON.stringify(install, null, 2));
|
|
@@ -38539,6 +38764,9 @@ Apply v${versionObj.version} to ${targets.length} agent(s)?`);
|
|
|
38539
38764
|
throw new Error("This action requires --force to confirm (non-interactive mode)");
|
|
38540
38765
|
}
|
|
38541
38766
|
}
|
|
38767
|
+
if (options.skipEnvCheck) {
|
|
38768
|
+
writeInfo("\u26A0\uFE0F --skip-env-check is deprecated: the env-contract check is server-enforced; use `lua env` to satisfy the contract.");
|
|
38769
|
+
}
|
|
38542
38770
|
writeProgress("\u{1F504} Starting apply run...");
|
|
38543
38771
|
const { runId } = await templateApi.apply(templateId, {
|
|
38544
38772
|
version: versionObj.version,
|
|
@@ -41220,6 +41448,109 @@ var UnifiedToApi = class extends HttpClient {
|
|
|
41220
41448
|
Authorization: `Bearer ${this.apiKey}`
|
|
41221
41449
|
});
|
|
41222
41450
|
}
|
|
41451
|
+
// ==================== Personal (user-owned) connections ====================
|
|
41452
|
+
//
|
|
41453
|
+
// The whole tier is agent-free: the acting principal is the API key's owner, resolved server-side
|
|
41454
|
+
// from the same /profile hop a browser session uses. None of these take an agentId — that is the
|
|
41455
|
+
// point, so the signatures don't pretend otherwise.
|
|
41456
|
+
/**
|
|
41457
|
+
* Lists the API key owner's personal connections
|
|
41458
|
+
* @returns Promise resolving to an ApiResponse containing personal connections
|
|
41459
|
+
*/
|
|
41460
|
+
async getUserConnections() {
|
|
41461
|
+
return this.httpGet("/developer/unifiedto/user-connection", {
|
|
41462
|
+
Authorization: `Bearer ${this.apiKey}`
|
|
41463
|
+
});
|
|
41464
|
+
}
|
|
41465
|
+
/**
|
|
41466
|
+
* Gets a state-bound OAuth URL for a PERSONAL connection
|
|
41467
|
+
* @param integrationType - The integration type
|
|
41468
|
+
* @param options - Redirect pair, scopes and CSRF state
|
|
41469
|
+
* @returns Promise resolving to an ApiResponse containing the authorization URL
|
|
41470
|
+
*/
|
|
41471
|
+
async getUserAuthUrl(integrationType, options) {
|
|
41472
|
+
const params = new URLSearchParams();
|
|
41473
|
+
params.append("integrationType", integrationType);
|
|
41474
|
+
params.append("successRedirect", options.successRedirect);
|
|
41475
|
+
params.append("failureRedirect", options.failureRedirect);
|
|
41476
|
+
if (options.scopes && options.scopes.length > 0) {
|
|
41477
|
+
params.append("scopes", options.scopes.join(","));
|
|
41478
|
+
}
|
|
41479
|
+
params.append("state", options.state);
|
|
41480
|
+
return this.httpGet(`/developer/unifiedto/user-connection/auth-url/v2?${params.toString()}`, {
|
|
41481
|
+
Authorization: `Bearer ${this.apiKey}`
|
|
41482
|
+
});
|
|
41483
|
+
}
|
|
41484
|
+
/**
|
|
41485
|
+
* Creates a PERSONAL connection from API-key credentials
|
|
41486
|
+
* @param params - Integration type and credential fields
|
|
41487
|
+
* @returns Promise resolving to an ApiResponse containing the new connection id
|
|
41488
|
+
*/
|
|
41489
|
+
async createUserTokenAuthConnection(params) {
|
|
41490
|
+
return this.httpPost("/developer/unifiedto/user-connection/token-auth", params, {
|
|
41491
|
+
Authorization: `Bearer ${this.apiKey}`
|
|
41492
|
+
});
|
|
41493
|
+
}
|
|
41494
|
+
/**
|
|
41495
|
+
* Finalizes a PERSONAL connection: stores it, mounts it on every private agent of the owner's,
|
|
41496
|
+
* and seeds ingest triggers. Takes no displayName/hideSensitive/triggers — the user tier has none.
|
|
41497
|
+
* @param params - The connection id and the OAuth scopes that were consented to
|
|
41498
|
+
* @returns Promise resolving to an ApiResponse containing the agents it mounted on
|
|
41499
|
+
*/
|
|
41500
|
+
async finalizeUserConnection(params) {
|
|
41501
|
+
return this.httpPost("/developer/unifiedto/user-connection/finalize", params, {
|
|
41502
|
+
Authorization: `Bearer ${this.apiKey}`
|
|
41503
|
+
});
|
|
41504
|
+
}
|
|
41505
|
+
/**
|
|
41506
|
+
* Converts an agent-owned connection you created into a personal one
|
|
41507
|
+
* @param connectionId - The connection ID
|
|
41508
|
+
* @returns Promise resolving to an ApiResponse containing the agents it mounted on
|
|
41509
|
+
*/
|
|
41510
|
+
async convertConnectionToUser(connectionId) {
|
|
41511
|
+
return this.httpPost("/developer/unifiedto/user-connection/convert", {
|
|
41512
|
+
connectionId
|
|
41513
|
+
}, {
|
|
41514
|
+
Authorization: `Bearer ${this.apiKey}`
|
|
41515
|
+
});
|
|
41516
|
+
}
|
|
41517
|
+
/**
|
|
41518
|
+
* Disconnects a personal connection, sweeping every mount
|
|
41519
|
+
* @param connectionId - The connection ID
|
|
41520
|
+
* @param forgetMemories - Also purge what it added to memory (default true server-side)
|
|
41521
|
+
* @returns Promise resolving to an ApiResponse with the number of triggers removed
|
|
41522
|
+
*/
|
|
41523
|
+
async deleteUserConnection(connectionId, forgetMemories) {
|
|
41524
|
+
return this.httpDelete(`/developer/unifiedto/user-connection/${connectionId}?forgetMemories=${forgetMemories}`, {
|
|
41525
|
+
Authorization: `Bearer ${this.apiKey}`
|
|
41526
|
+
});
|
|
41527
|
+
}
|
|
41528
|
+
/**
|
|
41529
|
+
* Pauses or resumes a personal connection across every agent it is mounted on
|
|
41530
|
+
* @param connectionId - The connection ID
|
|
41531
|
+
* @param status - 'paused' or 'active'
|
|
41532
|
+
* @returns Promise resolving to an ApiResponse with the resulting status
|
|
41533
|
+
*/
|
|
41534
|
+
async setUserConnectionStatus(connectionId, status) {
|
|
41535
|
+
return this.httpPatch(`/developer/unifiedto/user-connection/${connectionId}`, {
|
|
41536
|
+
status
|
|
41537
|
+
}, {
|
|
41538
|
+
Authorization: `Bearer ${this.apiKey}`
|
|
41539
|
+
});
|
|
41540
|
+
}
|
|
41541
|
+
/**
|
|
41542
|
+
* Turns a personal connection's org-memory feed on or off
|
|
41543
|
+
* @param connectionId - The connection ID
|
|
41544
|
+
* @param memoryFeed - Whether new items from this source should be remembered
|
|
41545
|
+
* @returns Promise resolving to an ApiResponse with the resulting state
|
|
41546
|
+
*/
|
|
41547
|
+
async setUserConnectionMemoryFeed(connectionId, memoryFeed) {
|
|
41548
|
+
return this.httpPatch(`/developer/unifiedto/user-connection/${connectionId}/memory-feed`, {
|
|
41549
|
+
memoryFeed
|
|
41550
|
+
}, {
|
|
41551
|
+
Authorization: `Bearer ${this.apiKey}`
|
|
41552
|
+
});
|
|
41553
|
+
}
|
|
41223
41554
|
};
|
|
41224
41555
|
|
|
41225
41556
|
// src/commands/integrations.ts
|
|
@@ -41241,7 +41572,9 @@ async function fetchAvailableIntegrations(unifiedToApi, agentId) {
|
|
|
41241
41572
|
authSupport: integration.authSupport,
|
|
41242
41573
|
oauthConfigured: integration.oauthConfigured,
|
|
41243
41574
|
oauthScopes: integration.oauthScopes,
|
|
41244
|
-
tokenFields: integration.tokenFields
|
|
41575
|
+
tokenFields: integration.tokenFields,
|
|
41576
|
+
orgOnly: integration.orgOnly,
|
|
41577
|
+
native: integration.native
|
|
41245
41578
|
}));
|
|
41246
41579
|
}
|
|
41247
41580
|
__name(fetchAvailableIntegrations, "fetchAvailableIntegrations");
|
|
@@ -41410,7 +41743,9 @@ async function executeNonInteractive12(context, action, cmdOptions) {
|
|
|
41410
41743
|
authMethod: cmdOptions?.authMethod,
|
|
41411
41744
|
scopes: cmdOptions?.scopes,
|
|
41412
41745
|
hideSensitive: cmdOptions?.hideSensitive === "true",
|
|
41746
|
+
hideSensitiveProvided: cmdOptions?.hideSensitive !== void 0,
|
|
41413
41747
|
accountLabel: cmdOptions?.accountLabel,
|
|
41748
|
+
scope: cmdOptions?.scope,
|
|
41414
41749
|
// Trigger options
|
|
41415
41750
|
triggers: cmdOptions?.triggers,
|
|
41416
41751
|
customWebhook: cmdOptions?.customWebhook === true,
|
|
@@ -41430,7 +41765,22 @@ async function executeNonInteractive12(context, action, cmdOptions) {
|
|
|
41430
41765
|
await updateConnectionFlow(context, options);
|
|
41431
41766
|
break;
|
|
41432
41767
|
case "list":
|
|
41433
|
-
|
|
41768
|
+
if (options.scope === "user") {
|
|
41769
|
+
await listUserConnections(context);
|
|
41770
|
+
} else if (options.scope === "all") {
|
|
41771
|
+
await listConnections(context);
|
|
41772
|
+
await listUserConnections(context);
|
|
41773
|
+
} else {
|
|
41774
|
+
await listConnections(context);
|
|
41775
|
+
}
|
|
41776
|
+
break;
|
|
41777
|
+
case "convert":
|
|
41778
|
+
if (!options.connectionId) {
|
|
41779
|
+
console.error("\u274C --connection-id is required for convert");
|
|
41780
|
+
console.log("\n\u{1F4A1} Run 'lua integrations list' to see connection IDs");
|
|
41781
|
+
throw new Error("--connection-id is required for convert");
|
|
41782
|
+
}
|
|
41783
|
+
await convertConnectionFlow(context, options.connectionId, cmdOptions?.force === true);
|
|
41434
41784
|
break;
|
|
41435
41785
|
case "available":
|
|
41436
41786
|
await listAvailableIntegrations(context);
|
|
@@ -41451,7 +41801,11 @@ async function executeNonInteractive12(context, action, cmdOptions) {
|
|
|
41451
41801
|
console.log("\n\u{1F4A1} Run 'lua integrations list' to see connection IDs");
|
|
41452
41802
|
throw new Error("--connection-id is required for disconnect");
|
|
41453
41803
|
}
|
|
41454
|
-
|
|
41804
|
+
if (options.scope === "user") {
|
|
41805
|
+
await disconnectUserConnection(context, options.connectionId);
|
|
41806
|
+
} else {
|
|
41807
|
+
await disconnectIntegration(context, options.connectionId);
|
|
41808
|
+
}
|
|
41455
41809
|
break;
|
|
41456
41810
|
case "webhooks":
|
|
41457
41811
|
await webhooksSubcommand(context, cmdOptions);
|
|
@@ -41490,6 +41844,10 @@ async function interactiveIntegrationsManagement(context) {
|
|
|
41490
41844
|
name: "\u{1F4CB} List connected integrations",
|
|
41491
41845
|
value: "list"
|
|
41492
41846
|
},
|
|
41847
|
+
{
|
|
41848
|
+
name: "\u{1F464} List my personal connections",
|
|
41849
|
+
value: "list-user"
|
|
41850
|
+
},
|
|
41493
41851
|
{
|
|
41494
41852
|
name: "\u{1F50D} View available integrations",
|
|
41495
41853
|
value: "available"
|
|
@@ -41525,6 +41883,9 @@ async function interactiveIntegrationsManagement(context) {
|
|
|
41525
41883
|
case "list":
|
|
41526
41884
|
await listConnections(context);
|
|
41527
41885
|
break;
|
|
41886
|
+
case "list-user":
|
|
41887
|
+
await listUserConnections(context);
|
|
41888
|
+
break;
|
|
41528
41889
|
case "available":
|
|
41529
41890
|
await listAvailableIntegrations(context);
|
|
41530
41891
|
break;
|
|
@@ -41687,17 +42048,83 @@ async function showIntegrationInfo(context, integrationType, jsonOutput = false)
|
|
|
41687
42048
|
}
|
|
41688
42049
|
}
|
|
41689
42050
|
__name(showIntegrationInfo, "showIntegrationInfo");
|
|
42051
|
+
function agentOnlyFlagsIn(options) {
|
|
42052
|
+
return [
|
|
42053
|
+
options.triggers && "--triggers",
|
|
42054
|
+
options.customWebhook && "--custom-webhook",
|
|
42055
|
+
options.hookUrl && "--hook-url",
|
|
42056
|
+
options.accountLabel && "--account-label",
|
|
42057
|
+
// NOT `options.hideSensitive !== undefined`: executeNonInteractive coerces that to a boolean for
|
|
42058
|
+
// every run, so its presence has to be tracked separately.
|
|
42059
|
+
options.hideSensitiveProvided && "--hide-sensitive"
|
|
42060
|
+
].filter((f) => typeof f === "string" && f.length > 0);
|
|
42061
|
+
}
|
|
42062
|
+
__name(agentOnlyFlagsIn, "agentOnlyFlagsIn");
|
|
42063
|
+
function normalizeScopeFlag(raw) {
|
|
42064
|
+
if (!raw) return void 0;
|
|
42065
|
+
const normalized = raw.toLowerCase();
|
|
42066
|
+
if (normalized !== "agent" && normalized !== "user") {
|
|
42067
|
+
console.error(`\u274C Invalid --scope: "${raw}". Use 'agent' or 'user'`);
|
|
42068
|
+
throw new Error("Invalid --scope");
|
|
42069
|
+
}
|
|
42070
|
+
return normalized;
|
|
42071
|
+
}
|
|
42072
|
+
__name(normalizeScopeFlag, "normalizeScopeFlag");
|
|
42073
|
+
async function resolveConnectScope(context, options) {
|
|
42074
|
+
const flagged = normalizeScopeFlag(options.scope);
|
|
42075
|
+
if (flagged) return flagged;
|
|
42076
|
+
const answer = await safePrompt([
|
|
42077
|
+
{
|
|
42078
|
+
type: "list",
|
|
42079
|
+
name: "scope",
|
|
42080
|
+
message: "Who should own this connection?",
|
|
42081
|
+
choices: [
|
|
42082
|
+
{
|
|
42083
|
+
name: `\u{1F916} This agent only \u2014 ${context.agentId} keeps the credential, and loses it when the agent goes`,
|
|
42084
|
+
value: "agent"
|
|
42085
|
+
},
|
|
42086
|
+
{
|
|
42087
|
+
name: "\u{1F464} Me \u2014 every private agent I own can use it, including ones I create later",
|
|
42088
|
+
value: "user"
|
|
42089
|
+
}
|
|
42090
|
+
]
|
|
42091
|
+
}
|
|
42092
|
+
]);
|
|
42093
|
+
return answer?.scope;
|
|
42094
|
+
}
|
|
42095
|
+
__name(resolveConnectScope, "resolveConnectScope");
|
|
41690
42096
|
async function connectIntegrationFlow(context, options = {}) {
|
|
42097
|
+
const scope = await resolveConnectScope(context, options);
|
|
42098
|
+
if (!scope) return;
|
|
42099
|
+
const userScope = scope === "user";
|
|
42100
|
+
if (userScope) {
|
|
42101
|
+
const unsupported = agentOnlyFlagsIn(options);
|
|
42102
|
+
if (unsupported.length > 0) {
|
|
42103
|
+
console.error(`\u274C ${unsupported.join(", ")} ${unsupported.length > 1 ? "are" : "is"} agent-scoped and cannot be used with --scope user.`);
|
|
42104
|
+
console.log("\u{1F4A1} Connect at agent scope, or drop the flag. Triggers can be added later on an agent connection.");
|
|
42105
|
+
throw new Error("Agent-scoped options cannot be used with --scope user");
|
|
42106
|
+
}
|
|
42107
|
+
}
|
|
41691
42108
|
writeProgress("\u{1F504} Fetching integrations...");
|
|
41692
42109
|
let availableIntegrations;
|
|
42110
|
+
let agentConnectedTypes = /* @__PURE__ */ new Set();
|
|
41693
42111
|
try {
|
|
41694
|
-
availableIntegrations = await fetchAvailableIntegrations(context.unifiedToApi, context.agentId);
|
|
42112
|
+
availableIntegrations = await fetchAvailableIntegrations(context.unifiedToApi, userScope ? void 0 : context.agentId);
|
|
42113
|
+
if (userScope) {
|
|
42114
|
+
const [personal, agentConnections] = await Promise.all([
|
|
42115
|
+
context.unifiedToApi.getUserConnections(),
|
|
42116
|
+
context.unifiedToApi.getConnections(context.agentId)
|
|
42117
|
+
]);
|
|
42118
|
+
const personalTypes = new Set((personal.data ?? []).map((c) => c.integrationType));
|
|
42119
|
+
agentConnectedTypes = new Set((agentConnections.data ?? []).filter((c) => c.status !== "deleted").map((c) => c.integrationType));
|
|
42120
|
+
availableIntegrations = availableIntegrations.filter((i) => !i.orgOnly && !i.native && !personalTypes.has(i.value));
|
|
42121
|
+
}
|
|
41695
42122
|
} catch (error) {
|
|
41696
42123
|
writeError(`\u274C Failed to fetch integrations: ${error.message}`);
|
|
41697
42124
|
return;
|
|
41698
42125
|
}
|
|
41699
42126
|
if (availableIntegrations.length === 0) {
|
|
41700
|
-
writeInfo("All available integrations are already connected (or none are enabled).");
|
|
42127
|
+
writeInfo(userScope ? "You have already connected every integration available as a personal connection." : "All available integrations are already connected (or none are enabled).");
|
|
41701
42128
|
console.log("\u{1F4A1} Use 'lua integrations update' to change scopes on an existing connection.\n");
|
|
41702
42129
|
return;
|
|
41703
42130
|
}
|
|
@@ -41706,8 +42133,8 @@ async function connectIntegrationFlow(context, options = {}) {
|
|
|
41706
42133
|
if (options.integration) {
|
|
41707
42134
|
selectedIntegration = availableIntegrations.find((i) => i.value === options.integration);
|
|
41708
42135
|
if (!selectedIntegration) {
|
|
41709
|
-
console.error(`\u274C Integration "${options.integration}" not found or already connected.`);
|
|
41710
|
-
console.log("\u{1F4A1} If already connected, use 'lua integrations update --integration " + options.integration + "' to change scopes.");
|
|
42136
|
+
console.error(userScope ? `\u274C "${options.integration}" is not available as a personal connection.` : `\u274C Integration "${options.integration}" not found or already connected.`);
|
|
42137
|
+
console.log(userScope ? "\u{1F4A1} You may already have it, or it's org-only / a memory-source connector. Run 'lua integrations list --scope user' to check." : "\u{1F4A1} If already connected, use 'lua integrations update --integration " + options.integration + "' to change scopes.");
|
|
41711
42138
|
if (availableIntegrations.length > 0) {
|
|
41712
42139
|
console.log("\nAvailable integrations to connect:");
|
|
41713
42140
|
availableIntegrations.forEach((i) => console.log(` - ${i.value} (${i.name})`));
|
|
@@ -41767,6 +42194,22 @@ async function connectIntegrationFlow(context, options = {}) {
|
|
|
41767
42194
|
console.log(` Categories: ${selectedIntegration.categories.join(", ")}`);
|
|
41768
42195
|
console.log(` Auth Support: ${selectedIntegration.authSupport}`);
|
|
41769
42196
|
console.log(` OAuth Configured: ${selectedIntegration.oauthConfigured ? "Yes" : "No"}`);
|
|
42197
|
+
console.log(` Owner: ${userScope ? "you (every private agent you own)" : `this agent (${context.agentId})`}`);
|
|
42198
|
+
if (userScope && agentConnectedTypes.has(selectedIntegration.value)) {
|
|
42199
|
+
writeInfo(`This agent already has its own ${selectedIntegration.name} connection. Connecting as yourself adds a SECOND credential rather than replacing it.`);
|
|
42200
|
+
const proceed = await safePrompt([
|
|
42201
|
+
{
|
|
42202
|
+
type: "confirm",
|
|
42203
|
+
name: "go",
|
|
42204
|
+
message: "Continue?",
|
|
42205
|
+
default: false
|
|
42206
|
+
}
|
|
42207
|
+
]);
|
|
42208
|
+
if (!proceed?.go) {
|
|
42209
|
+
console.log("\n\u{1F4A1} To re-home the existing one instead: lua integrations convert --connection-id <id>\n");
|
|
42210
|
+
return;
|
|
42211
|
+
}
|
|
42212
|
+
}
|
|
41770
42213
|
const canUseOAuth = selectedIntegration.oauthConfigured && [
|
|
41771
42214
|
"oauth",
|
|
41772
42215
|
"both"
|
|
@@ -41892,7 +42335,8 @@ Available scopes for ${selectedIntegration.name}:`);
|
|
|
41892
42335
|
console.log("\nYou will enter these on the Unified.to authorization page.\n");
|
|
41893
42336
|
}
|
|
41894
42337
|
let hideSensitive = false;
|
|
41895
|
-
if (
|
|
42338
|
+
if (userScope) {
|
|
42339
|
+
} else if (options.hideSensitive !== void 0) {
|
|
41896
42340
|
hideSensitive = options.hideSensitive;
|
|
41897
42341
|
} else {
|
|
41898
42342
|
const sensitiveAnswer = await safePrompt([
|
|
@@ -41910,8 +42354,14 @@ Available scopes for ${selectedIntegration.name}:`);
|
|
|
41910
42354
|
let selectedTriggers = [];
|
|
41911
42355
|
let webhookUrl = AGENT_WEBHOOK_URL;
|
|
41912
42356
|
let isCustomWebhook = false;
|
|
42357
|
+
if (userScope) {
|
|
42358
|
+
writeInfo("Triggers are agent-owned \u2014 skipping. Add them later on an agent connection.");
|
|
42359
|
+
}
|
|
41913
42360
|
try {
|
|
41914
|
-
const eventsResult =
|
|
42361
|
+
const eventsResult = userScope ? {
|
|
42362
|
+
success: false,
|
|
42363
|
+
data: void 0
|
|
42364
|
+
} : await context.unifiedToApi.getAvailableWebhookEventsByType(selectedIntegration.value);
|
|
41915
42365
|
if (eventsResult.success && eventsResult.data && eventsResult.data.length > 0) {
|
|
41916
42366
|
const availableEvents = eventsResult.data;
|
|
41917
42367
|
if (options.customWebhook || options.hookUrl) {
|
|
@@ -42050,7 +42500,12 @@ Available triggers for ${selectedIntegration.name}:`);
|
|
|
42050
42500
|
}
|
|
42051
42501
|
writeProgress("\u{1F504} Preparing authorization...");
|
|
42052
42502
|
const state = createOAuthState();
|
|
42053
|
-
const authUrlResult = await context.unifiedToApi.
|
|
42503
|
+
const authUrlResult = userScope ? await context.unifiedToApi.getUserAuthUrl(selectedIntegration.value, {
|
|
42504
|
+
successRedirect: CALLBACK_URL,
|
|
42505
|
+
failureRedirect: CALLBACK_URL,
|
|
42506
|
+
scopes: authMethod === "oauth" ? selectedScopes : void 0,
|
|
42507
|
+
state
|
|
42508
|
+
}) : await context.unifiedToApi.getAuthUrl(selectedIntegration.value, {
|
|
42054
42509
|
agentId: context.agentId,
|
|
42055
42510
|
successRedirect: CALLBACK_URL,
|
|
42056
42511
|
failureRedirect: CALLBACK_URL,
|
|
@@ -42083,11 +42538,15 @@ Integration: ${selectedIntegration.name}`);
|
|
|
42083
42538
|
const result = await callbackPromise;
|
|
42084
42539
|
if (result.success && result.connectionId) {
|
|
42085
42540
|
writeSuccess("\n\u2705 Authorization successful!");
|
|
42086
|
-
|
|
42087
|
-
|
|
42088
|
-
|
|
42089
|
-
|
|
42090
|
-
|
|
42541
|
+
if (userScope) {
|
|
42542
|
+
await finalizeUserConnection(context, selectedIntegration, result.connectionId, selectedScopes);
|
|
42543
|
+
} else {
|
|
42544
|
+
await finalizeConnection(context, selectedIntegration, result.connectionId, selectedScopes, hideSensitive, {
|
|
42545
|
+
triggers: selectedTriggers,
|
|
42546
|
+
webhookUrl,
|
|
42547
|
+
isCustomWebhook
|
|
42548
|
+
}, options.accountLabel);
|
|
42549
|
+
}
|
|
42091
42550
|
} else {
|
|
42092
42551
|
writeError(`
|
|
42093
42552
|
\u274C Authorization failed: ${result.error || "Unknown error"}`);
|
|
@@ -42217,6 +42676,140 @@ async function finalizeConnection(context, integration, connectionId, scopes, hi
|
|
|
42217
42676
|
});
|
|
42218
42677
|
}
|
|
42219
42678
|
__name(finalizeConnection, "finalizeConnection");
|
|
42679
|
+
async function finalizeUserConnection(context, integration, connectionId, scopes) {
|
|
42680
|
+
writeProgress(`\u{1F504} Setting up ${integration.name} connection...`);
|
|
42681
|
+
const result = await context.unifiedToApi.finalizeUserConnection({
|
|
42682
|
+
connectionId,
|
|
42683
|
+
scopes: scopes.length > 0 ? scopes : void 0
|
|
42684
|
+
});
|
|
42685
|
+
if (!result.success || !result.data) {
|
|
42686
|
+
writeError(`\u274C Failed to finalize connection: ${result.error?.message || "Unknown error"}`);
|
|
42687
|
+
return;
|
|
42688
|
+
}
|
|
42689
|
+
const { mountedAgentIds, webhooks, failedWebhooks } = result.data;
|
|
42690
|
+
console.log("\n" + "\u2500".repeat(60));
|
|
42691
|
+
console.log("\u{1F389} Connection Established!");
|
|
42692
|
+
console.log("\u2500".repeat(60));
|
|
42693
|
+
console.log(`
|
|
42694
|
+
Integration: ${integration.name}`);
|
|
42695
|
+
console.log(` Connection ID: ${connectionId}`);
|
|
42696
|
+
console.log(` Owner: you`);
|
|
42697
|
+
console.log(`
|
|
42698
|
+
\u{1F916} Available on ${mountedAgentIds.length} agent(s):`);
|
|
42699
|
+
if (mountedAgentIds.length === 0) {
|
|
42700
|
+
console.log(" (none yet \u2014 you have no private agents)");
|
|
42701
|
+
} else {
|
|
42702
|
+
mountedAgentIds.forEach((agentId) => {
|
|
42703
|
+
console.log(` \u2022 ${agentId}${agentId === context.agentId ? " \u2190 this project" : ""}`);
|
|
42704
|
+
});
|
|
42705
|
+
}
|
|
42706
|
+
console.log(" Private agents you create later are added automatically.");
|
|
42707
|
+
console.log(" Publishing an agent removes its access.");
|
|
42708
|
+
if (scopes.length > 0) {
|
|
42709
|
+
console.log(`
|
|
42710
|
+
\u{1F511} Permissions (${scopes.length}):`);
|
|
42711
|
+
scopes.forEach((scopeName) => {
|
|
42712
|
+
const scopeInfo = integration.oauthScopes?.find((sc) => sc.unifiedScope === scopeName);
|
|
42713
|
+
console.log(` \u2022 ${scopeInfo?.friendlyLabel || scopeName}`);
|
|
42714
|
+
});
|
|
42715
|
+
} else {
|
|
42716
|
+
console.log(`
|
|
42717
|
+
\u{1F511} Permissions: Default`);
|
|
42718
|
+
}
|
|
42719
|
+
if (webhooks.length > 0) {
|
|
42720
|
+
console.log(`
|
|
42721
|
+
\u{1F9E0} Memory sources seeded: ${webhooks.length}`);
|
|
42722
|
+
}
|
|
42723
|
+
if (failedWebhooks && failedWebhooks.length > 0) {
|
|
42724
|
+
failedWebhooks.forEach((t) => console.log(` \u2717 ${t.objectType}.${t.event}: ${t.error}`));
|
|
42725
|
+
}
|
|
42726
|
+
console.log("\n" + "\u2500".repeat(60));
|
|
42727
|
+
console.log(`\u2705 ${integration.name} connected as you.`);
|
|
42728
|
+
console.log(` Manage it with: lua integrations list --scope user
|
|
42729
|
+
`);
|
|
42730
|
+
trackEvent("cli_integration_connected", {
|
|
42731
|
+
integration_type: integration.value,
|
|
42732
|
+
integration_name: integration.name,
|
|
42733
|
+
scope: "user",
|
|
42734
|
+
mounted_agents: mountedAgentIds.length
|
|
42735
|
+
});
|
|
42736
|
+
}
|
|
42737
|
+
__name(finalizeUserConnection, "finalizeUserConnection");
|
|
42738
|
+
async function listUserConnections(context) {
|
|
42739
|
+
writeProgress("\u{1F504} Loading your connections...");
|
|
42740
|
+
try {
|
|
42741
|
+
const result = await context.unifiedToApi.getUserConnections();
|
|
42742
|
+
const connections = result.success ? result.data || [] : [];
|
|
42743
|
+
console.log("\n" + "=".repeat(60));
|
|
42744
|
+
console.log("\u{1F464} Your Personal Connections");
|
|
42745
|
+
console.log("=".repeat(60) + "\n");
|
|
42746
|
+
if (connections.length === 0) {
|
|
42747
|
+
console.log("\u2139\uFE0F You have no personal connections yet.");
|
|
42748
|
+
console.log("\u{1F4A1} Run 'lua integrations connect --scope user' to connect one.\n");
|
|
42749
|
+
return;
|
|
42750
|
+
}
|
|
42751
|
+
for (const connection of connections) {
|
|
42752
|
+
const statusIcon = connection.status === "unhealthy" ? "\u{1F534}" : connection.status === "paused" ? "\u23F8\uFE0F" : "\u{1F7E2}";
|
|
42753
|
+
const mounted = connection.mountedAgentIds || [];
|
|
42754
|
+
console.log(`${statusIcon} ${connection.displayName || connection.integrationType}`);
|
|
42755
|
+
console.log(` Connection: ${connection.connectionId}`);
|
|
42756
|
+
console.log(` Status: ${connection.status}`);
|
|
42757
|
+
console.log(` Available on: ${mounted.length} agent(s)${mounted.includes(context.agentId) ? " (including this project)" : ""}`);
|
|
42758
|
+
if (connection.removedAgentIds && connection.removedAgentIds.length > 0) {
|
|
42759
|
+
console.log(` Removed from: ${connection.removedAgentIds.length} agent(s)`);
|
|
42760
|
+
}
|
|
42761
|
+
console.log(` Memory feed: ${connection.memoryFeed ? "on" : "off"}`);
|
|
42762
|
+
if (connection.createdAt) {
|
|
42763
|
+
console.log(` Connected: ${new Date(connection.createdAt).toLocaleDateString()}`);
|
|
42764
|
+
}
|
|
42765
|
+
console.log();
|
|
42766
|
+
}
|
|
42767
|
+
console.log("=".repeat(60));
|
|
42768
|
+
console.log(`Total: ${connections.length} personal connection(s)
|
|
42769
|
+
`);
|
|
42770
|
+
} catch (error) {
|
|
42771
|
+
writeError(`\u274C Error loading your connections: ${error.message}`);
|
|
42772
|
+
}
|
|
42773
|
+
}
|
|
42774
|
+
__name(listUserConnections, "listUserConnections");
|
|
42775
|
+
async function convertConnectionFlow(context, connectionId, force = false) {
|
|
42776
|
+
if (!force) {
|
|
42777
|
+
const ok = await safePrompt([
|
|
42778
|
+
{
|
|
42779
|
+
type: "confirm",
|
|
42780
|
+
name: "go",
|
|
42781
|
+
message: `Make ${connectionId} yours? It spreads to every private agent you own, and there is no way to convert it back.`,
|
|
42782
|
+
default: false
|
|
42783
|
+
}
|
|
42784
|
+
]);
|
|
42785
|
+
if (!ok?.go) {
|
|
42786
|
+
console.log("\nNothing changed.\n");
|
|
42787
|
+
return;
|
|
42788
|
+
}
|
|
42789
|
+
}
|
|
42790
|
+
writeProgress("\u{1F504} Making this connection yours...");
|
|
42791
|
+
const result = await context.unifiedToApi.convertConnectionToUser(connectionId);
|
|
42792
|
+
if (!result.success || !result.data) {
|
|
42793
|
+
writeError(`\u274C Failed to convert connection: ${result.error?.message || "Unknown error"}`);
|
|
42794
|
+
console.log("\u{1F4A1} Only a private-agent connection you created yourself can become personal.");
|
|
42795
|
+
console.log(" A connection shared with the workspace must stop being shared first.\n");
|
|
42796
|
+
return;
|
|
42797
|
+
}
|
|
42798
|
+
const { mountedAgentIds } = result.data;
|
|
42799
|
+
writeSuccess(`
|
|
42800
|
+
\u2705 ${connectionId} is now yours.`);
|
|
42801
|
+
console.log(`
|
|
42802
|
+
\u{1F916} Available on ${mountedAgentIds.length} agent(s):`);
|
|
42803
|
+
mountedAgentIds.forEach((agentId) => {
|
|
42804
|
+
console.log(` \u2022 ${agentId}${agentId === context.agentId ? " \u2190 this project" : ""}`);
|
|
42805
|
+
});
|
|
42806
|
+
console.log(" Private agents you create later are added automatically.\n");
|
|
42807
|
+
trackEvent("cli_integration_converted", {
|
|
42808
|
+
connection_id: connectionId,
|
|
42809
|
+
mounted_agents: mountedAgentIds.length
|
|
42810
|
+
});
|
|
42811
|
+
}
|
|
42812
|
+
__name(convertConnectionFlow, "convertConnectionFlow");
|
|
42220
42813
|
async function listConnections(context) {
|
|
42221
42814
|
writeProgress("\u{1F504} Loading connections...");
|
|
42222
42815
|
try {
|
|
@@ -42264,6 +42857,37 @@ async function listConnections(context) {
|
|
|
42264
42857
|
}
|
|
42265
42858
|
}
|
|
42266
42859
|
__name(listConnections, "listConnections");
|
|
42860
|
+
async function disconnectUserConnection(context, connectionId) {
|
|
42861
|
+
const forget = await safePrompt([
|
|
42862
|
+
{
|
|
42863
|
+
type: "confirm",
|
|
42864
|
+
name: "forget",
|
|
42865
|
+
message: "Also forget what this connection already added to memory? (it is kept otherwise)",
|
|
42866
|
+
default: false
|
|
42867
|
+
}
|
|
42868
|
+
]);
|
|
42869
|
+
if (!forget) return;
|
|
42870
|
+
writeProgress("\u{1F504} Disconnecting... (please wait, do not close this window)");
|
|
42871
|
+
const result = await context.unifiedToApi.deleteUserConnection(connectionId, forget.forget);
|
|
42872
|
+
if (!result.success) {
|
|
42873
|
+
writeError(`\u274C Failed to disconnect: ${result.error?.message || "Unknown error"}`);
|
|
42874
|
+
return;
|
|
42875
|
+
}
|
|
42876
|
+
writeSuccess("\u2705 Personal connection disconnected from every agent it was on.");
|
|
42877
|
+
if (result.data?.deletedWebhooksCount) {
|
|
42878
|
+
console.log(` \u2713 Deleted ${result.data.deletedWebhooksCount} memory source(s)`);
|
|
42879
|
+
}
|
|
42880
|
+
if (!forget.forget) {
|
|
42881
|
+
console.log(" \u2139\uFE0F What it already added to memory was kept.");
|
|
42882
|
+
}
|
|
42883
|
+
console.log();
|
|
42884
|
+
trackEvent("cli_integration_disconnected", {
|
|
42885
|
+
scope: "user",
|
|
42886
|
+
webhooks_deleted: result.data?.deletedWebhooksCount || 0,
|
|
42887
|
+
forget_memories: forget.forget
|
|
42888
|
+
});
|
|
42889
|
+
}
|
|
42890
|
+
__name(disconnectUserConnection, "disconnectUserConnection");
|
|
42267
42891
|
async function disconnectIntegration(context, connectionId) {
|
|
42268
42892
|
writeProgress(`\u{1F504} Disconnecting... (please wait, do not close this window)`);
|
|
42269
42893
|
try {
|
|
@@ -46360,7 +46984,7 @@ function setupMarketplaceCommands(program2) {
|
|
|
46360
46984
|
program2.command("marketplace [noun] [action]").description("\u{1F6CD}\uFE0F Browse, install, and manage marketplace skills and agent templates").option("--skill-name <name>", "Skill name (for skill list/update/uninstall)").option("--marketplace-id <id>", "Marketplace skill ID").option("--version-id <id>", "Version ID (for skill publish/install)").option("--env-vars-json <json>", "JSON string with env var metadata (for skill publish)").option("--query <text>", "Search query (for skill search)").option("--page <n>", "Page number (for skill search)").option("--limit <n>", "Results per page (for skill search)").option("--name <name>", "Template name, an internal identifier (for template create)").option("--description <text>", "Description (for template create)").option("--template-id <id>", "Template ID").option("--source-version <n>", "Agent version to freeze into this template version (default: active) (for template publish)").option("--env-contract <pair>", "KEY=description env contract entry, repeatable; use KEY?=description for optional (for template publish)", (val, previous) => [
|
|
46361
46985
|
...previous,
|
|
46362
46986
|
val
|
|
46363
|
-
], []).option("--version <n>", "Template version (for template view/install/apply)").option("--allow-creator-updates", "Allow the template creator to push future updates onto this install").option("--skip-env-check", "Skip env-contract validation (for template install/apply)").option("--agents <ids>", "Comma-separated target agent IDs (for template apply)").option("--file <path>", "Path to a file with one target agent ID per line (for template apply)").option("--all-installed", "Target every agent that already has this template installed (for template apply)").option("--no-wait", "Print the apply runId immediately instead of polling for completion (for template apply)").option("--display-name <name>", "Display name (for skill list/edit, template create)").option("--visibility <visibility>", "Who can see and install it: public or private (for skill list, template create)").option("--changelog <text>", "Changelog for this version (for skill/template publish)").option("--env-vars <pairs>", "Comma-separated key=value pairs (for skill/template install/update)").option("--json", "Output as JSON").option("--force", "Skip confirmation prompts").addHelpText("after", `
|
|
46987
|
+
], []).option("--version <n>", "Template version (for template view/install/apply)").option("--allow-creator-updates", "Allow the template creator to push future updates onto this install").option("--skip-env-check", "Skip env-contract validation (for template install/apply)").option("--agents <ids>", "Comma-separated target agent IDs (for template apply)").option("--file <path>", "Path to a file with one target agent ID per line (for template apply)").option("--all-installed", "Target every agent that already has this template installed (for template apply)").option("--no-wait", "Print the apply runId immediately instead of polling for completion (for template apply)").option("--display-name <name>", "Display name (for skill list/edit, template create)").option("--visibility <visibility>", "Who can see and install it: public or private (for skill list, template create)").option("--changelog <text>", "Changelog for this version (for skill/template publish)").option("--env-vars <pairs>", "Comma-separated key=value pairs (for skill/template install/update)").option("--json", "Output as JSON").option("--force", "Skip confirmation prompts").option("--yes", "Auto-confirm ONLY the template-publish consequence prompt (section clear/narrow); unlike --force it skips no other confirmation").addHelpText("after", `
|
|
46364
46988
|
Arguments:
|
|
46365
46989
|
noun Optional: 'skill' or 'template' (prompts if not provided)
|
|
46366
46990
|
action Optional: specific action for non-interactive mode
|
|
@@ -46810,16 +47434,19 @@ Examples:
|
|
|
46810
47434
|
$ lua mcp deactivate --server-name api-server Deactivate a server
|
|
46811
47435
|
$ lua mcp delete --server-name old-server Delete a server
|
|
46812
47436
|
`).action(mcpCommand);
|
|
46813
|
-
program2.command("integrations [action] [subaction]").description("\u{1F517} Connect third-party integrations via Unified.to").option("--integration <type>", "Integration type (e.g., linear, googlecalendar)").option("--auth-method <method>", "Authentication method: 'oauth' or 'token'").option("--scopes <scopes>", "Comma-separated OAuth scopes (or 'all' for all scopes)").option("--hide-sensitive <bool>", "Hide sensitive data from MCP tools (default: true)").option("--account-label <label>", "Account label used to distinguish multiple connected accounts").option("--connection-id <id>", "Connection ID to disconnect or pause/resume").option("--connection <id>", "Connection ID for trigger").option("--webhook-id <id>", "Trigger ID to delete/pause/resume").option("--object <type>", "Object type for webhook (e.g., task_task, calendar_event)").option("--event <type>", "Event type for webhook: created, updated, or deleted").option("--hook-url <url>", "Custom webhook URL (default: agent trigger)").option("--interval <minutes>", "Polling interval for virtual webhooks (60, 120, 240, 480, 720, 1440, 2880)").option("--triggers <events>", "Comma-separated triggers (e.g., task_task.created,task_task.updated)").option("--custom-webhook", "Use custom webhook URL instead of agent trigger").option("--json", "Output as JSON (for info and webhooks events commands)").option("--reason <text>", "Optional reason for pausing a trigger").addHelpText("after", `
|
|
47437
|
+
program2.command("integrations [action] [subaction]").description("\u{1F517} Connect third-party integrations via Unified.to").option("--integration <type>", "Integration type (e.g., linear, googlecalendar)").option("--auth-method <method>", "Authentication method: 'oauth' or 'token'").option("--scopes <scopes>", "Comma-separated OAuth scopes (or 'all' for all scopes)").option("--hide-sensitive <bool>", "Hide sensitive data from MCP tools (default: true)").option("--account-label <label>", "Account label used to distinguish multiple connected accounts").option("--scope <scope>", "Who owns the connection: 'agent' (default) or 'user'").option("--force", "Skip the confirmation prompt (for convert)").option("--connection-id <id>", "Connection ID to disconnect, convert or pause/resume").option("--connection <id>", "Connection ID for trigger").option("--webhook-id <id>", "Trigger ID to delete/pause/resume").option("--object <type>", "Object type for webhook (e.g., task_task, calendar_event)").option("--event <type>", "Event type for webhook: created, updated, or deleted").option("--hook-url <url>", "Custom webhook URL (default: agent trigger)").option("--interval <minutes>", "Polling interval for virtual webhooks (60, 120, 240, 480, 720, 1440, 2880)").option("--triggers <events>", "Comma-separated triggers (e.g., task_task.created,task_task.updated)").option("--custom-webhook", "Use custom webhook URL instead of agent trigger").option("--json", "Output as JSON (for info and webhooks events commands)").option("--reason <text>", "Optional reason for pausing a trigger").addHelpText("after", `
|
|
46814
47438
|
Arguments:
|
|
46815
|
-
action Optional: 'connect', 'update', 'list', 'available', 'info', 'disconnect',
|
|
46816
|
-
(alias: 'triggers'), or 'mcp'
|
|
47439
|
+
action Optional: 'connect', 'update', 'list', 'available', 'info', 'disconnect',
|
|
47440
|
+
'convert', 'webhooks' (alias: 'triggers'), or 'mcp'
|
|
46817
47441
|
subaction For info: <integration-type>
|
|
46818
47442
|
For webhooks/triggers: 'list', 'events', 'create', 'delete', 'pause', or 'resume'
|
|
46819
47443
|
For mcp: 'list', 'activate', or 'deactivate'
|
|
46820
47444
|
|
|
46821
47445
|
Options:
|
|
46822
47446
|
--integration <type> Integration type (linear, googlecalendar, hubspot, etc.)
|
|
47447
|
+
--scope <scope> Who owns the connection: 'agent' (default) or 'user'. 'user' is a personal
|
|
47448
|
+
connection \u2014 every private agent you own can use it, including ones you
|
|
47449
|
+
create later. Publishing an agent removes its access.
|
|
46823
47450
|
--auth-method <method> Authentication method: 'oauth' or 'token'
|
|
46824
47451
|
--scopes <scopes> Comma-separated OAuth scopes, or 'all' for all available scopes
|
|
46825
47452
|
--hide-sensitive <bool> Hide sensitive data from MCP tools (default: true, use 'false' to show)
|
|
@@ -46837,6 +47464,7 @@ Webhook/Trigger Options:
|
|
|
46837
47464
|
--interval <minutes> Polling interval for virtual webhooks (60=1h, 120=2h, etc.)
|
|
46838
47465
|
|
|
46839
47466
|
Note: Only 1 connection per integration type is allowed per agent.
|
|
47467
|
+
Note: Triggers, account labels and --hide-sensitive are agent-scoped; they don't apply to --scope user.
|
|
46840
47468
|
|
|
46841
47469
|
Examples:
|
|
46842
47470
|
$ lua integrations Interactive management
|
|
@@ -46846,7 +47474,12 @@ Examples:
|
|
|
46846
47474
|
$ lua integrations connect --integration linear --triggers task_task.created,task_task.updated
|
|
46847
47475
|
$ lua integrations update --integration linear --scopes all Update Linear scopes
|
|
46848
47476
|
$ lua integrations available List available integrations
|
|
46849
|
-
$ lua integrations list List
|
|
47477
|
+
$ lua integrations list List this agent's connections
|
|
47478
|
+
$ lua integrations connect --scope user Connect as yourself (all your private agents)
|
|
47479
|
+
$ lua integrations list --scope user List your personal connections
|
|
47480
|
+
$ lua integrations list --scope all List both
|
|
47481
|
+
$ lua integrations convert --connection-id abc123 Re-home an agent connection to yourself
|
|
47482
|
+
$ lua integrations convert --connection-id abc123 --force Same, without the confirmation
|
|
46850
47483
|
$ lua integrations info linear Show Linear integration details
|
|
46851
47484
|
$ lua integrations info linear --json Output as JSON (for scripting)
|
|
46852
47485
|
$ lua integrations disconnect --connection-id abc123 Disconnect an integration
|