thinkwork-cli 0.12.7 → 0.12.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/cli.js +288 -174
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -2041,9 +2041,9 @@ function registerInitCommand(program2) {
2041
2041
  printError("Stage name is required. Pass -s <name> or re-run in an interactive terminal.");
2042
2042
  process.exit(1);
2043
2043
  }
2044
- const { input: input20 } = await import("@inquirer/prompts");
2044
+ const { input: input21 } = await import("@inquirer/prompts");
2045
2045
  try {
2046
- stage = await input20({
2046
+ stage = await input21({
2047
2047
  message: "Stage name (e.g. dev, staging, prod):",
2048
2048
  validate: (v) => validateStage(v).error ?? true
2049
2049
  });
@@ -2657,10 +2657,10 @@ async function getTenant(client, id) {
2657
2657
  async function getTenantBySlug(client, slug) {
2658
2658
  return client.fetch(`/api/tenants/by-slug/${encodeURIComponent(slug)}`);
2659
2659
  }
2660
- async function updateTenant(client, id, input20) {
2660
+ async function updateTenant(client, id, input21) {
2661
2661
  return client.fetch(`/api/tenants/${encodeURIComponent(id)}`, {
2662
2662
  method: "PUT",
2663
- body: JSON.stringify(input20)
2663
+ body: JSON.stringify(input21)
2664
2664
  });
2665
2665
  }
2666
2666
 
@@ -2671,12 +2671,12 @@ __export(admin_keys_exports, {
2671
2671
  listAdminKeys: () => listAdminKeys,
2672
2672
  revokeAdminKey: () => revokeAdminKey
2673
2673
  });
2674
- async function createAdminKey(client, tenantIdOrSlug, input20 = {}) {
2674
+ async function createAdminKey(client, tenantIdOrSlug, input21 = {}) {
2675
2675
  return client.fetch(
2676
2676
  `/api/tenants/${encodeURIComponent(tenantIdOrSlug)}/mcp-admin-keys`,
2677
2677
  {
2678
2678
  method: "POST",
2679
- body: JSON.stringify(input20)
2679
+ body: JSON.stringify(input21)
2680
2680
  }
2681
2681
  );
2682
2682
  }
@@ -2937,7 +2937,7 @@ Examples:
2937
2937
  ).action(
2938
2938
  async (nameArg, opts) => {
2939
2939
  try {
2940
- const { input: input20 } = await import("@inquirer/prompts");
2940
+ const { input: input21 } = await import("@inquirer/prompts");
2941
2941
  const { stage, api, tenant } = await resolveMcpContext(opts);
2942
2942
  let name = nameArg;
2943
2943
  if (!name) {
@@ -2945,7 +2945,7 @@ Examples:
2945
2945
  printError("Name is required. Pass it as a positional arg.");
2946
2946
  process.exit(1);
2947
2947
  }
2948
- name = await input20({ message: "Server name:" });
2948
+ name = await input21({ message: "Server name:" });
2949
2949
  }
2950
2950
  let url = opts.url;
2951
2951
  if (!url) {
@@ -2953,7 +2953,7 @@ Examples:
2953
2953
  printError("--url is required. Pass it as a flag.");
2954
2954
  process.exit(1);
2955
2955
  }
2956
- url = await input20({
2956
+ url = await input21({
2957
2957
  message: "MCP server URL:",
2958
2958
  validate: (v) => v.startsWith("http://") || v.startsWith("https://") ? true : "URL must start with http:// or https://"
2959
2959
  });
@@ -3113,7 +3113,7 @@ Examples:
3113
3113
  ).option("-s, --stage <name>", "Deployment stage").option("-t, --tenant <slug>", "Tenant slug").option("--agent <id>", "Agent ID").action(
3114
3114
  async (mcpServerArg, opts) => {
3115
3115
  try {
3116
- const { input: input20 } = await import("@inquirer/prompts");
3116
+ const { input: input21 } = await import("@inquirer/prompts");
3117
3117
  const { api, tenant } = await resolveMcpContext(opts);
3118
3118
  const server = await resolveServer(mcpServerArg, api, tenant.slug);
3119
3119
  let agent = opts.agent;
@@ -3122,7 +3122,7 @@ Examples:
3122
3122
  printError("--agent is required. Pass it as a flag.");
3123
3123
  process.exit(1);
3124
3124
  }
3125
- agent = await input20({ message: "Agent ID:" });
3125
+ agent = await input21({ message: "Agent ID:" });
3126
3126
  }
3127
3127
  const result = await apiFetch(
3128
3128
  api.apiUrl,
@@ -3145,7 +3145,7 @@ Examples:
3145
3145
  ).option("-s, --stage <name>", "Deployment stage").option("-t, --tenant <slug>", "Tenant slug").option("--agent <id>", "Agent ID").action(
3146
3146
  async (mcpServerArg, opts) => {
3147
3147
  try {
3148
- const { input: input20 } = await import("@inquirer/prompts");
3148
+ const { input: input21 } = await import("@inquirer/prompts");
3149
3149
  const { api, tenant } = await resolveMcpContext(opts);
3150
3150
  const server = await resolveServer(mcpServerArg, api, tenant.slug);
3151
3151
  let agent = opts.agent;
@@ -3154,7 +3154,7 @@ Examples:
3154
3154
  printError("--agent is required. Pass it as a flag.");
3155
3155
  process.exit(1);
3156
3156
  }
3157
- agent = await input20({ message: "Agent ID:" });
3157
+ agent = await input21({ message: "Agent ID:" });
3158
3158
  }
3159
3159
  await apiFetch(
3160
3160
  api.apiUrl,
@@ -4341,6 +4341,8 @@ var CliUpdateScheduledJobDocument = { "kind": "Document", "definitions": [{ "kin
4341
4341
  var CliSchedJobTenantBySlugDocument = { "kind": "Document", "definitions": [{ "kind": "OperationDefinition", "operation": "query", "name": { "kind": "Name", "value": "CliSchedJobTenantBySlug" }, "variableDefinitions": [{ "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "slug" } }, "type": { "kind": "NonNullType", "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "String" } } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "tenantBySlug" }, "arguments": [{ "kind": "Argument", "name": { "kind": "Name", "value": "slug" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "slug" } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }] } }] } }] };
4342
4342
  var CliSkillCatalogDocument = { "kind": "Document", "definitions": [{ "kind": "OperationDefinition", "operation": "query", "name": { "kind": "Name", "value": "CliSkillCatalog" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "skillCatalog" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "skillId" } }, { "kind": "Field", "name": { "kind": "Name", "value": "displayName" } }, { "kind": "Field", "name": { "kind": "Name", "value": "description" } }, { "kind": "Field", "name": { "kind": "Name", "value": "category" } }, { "kind": "Field", "name": { "kind": "Name", "value": "icon" } }, { "kind": "Field", "name": { "kind": "Name", "value": "source" } }, { "kind": "Field", "name": { "kind": "Name", "value": "enabled" } }] } }] } }] };
4343
4343
  var CliSkillTenantBySlugDocument = { "kind": "Document", "definitions": [{ "kind": "OperationDefinition", "operation": "query", "name": { "kind": "Name", "value": "CliSkillTenantBySlug" }, "variableDefinitions": [{ "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "slug" } }, "type": { "kind": "NonNullType", "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "String" } } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "tenantBySlug" }, "arguments": [{ "kind": "Argument", "name": { "kind": "Name", "value": "slug" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "slug" } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }] } }] } }] };
4344
+ var CliInstallSkillDocument = { "kind": "Document", "definitions": [{ "kind": "OperationDefinition", "operation": "mutation", "name": { "kind": "Name", "value": "CliInstallSkill" }, "variableDefinitions": [{ "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "input" } }, "type": { "kind": "NonNullType", "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "InstallSkillInput" } } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "installSkill" }, "arguments": [{ "kind": "Argument", "name": { "kind": "Name", "value": "input" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "input" } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "tenantId" } }, { "kind": "Field", "name": { "kind": "Name", "value": "skillId" } }, { "kind": "Field", "name": { "kind": "Name", "value": "source" } }, { "kind": "Field", "name": { "kind": "Name", "value": "version" } }, { "kind": "Field", "name": { "kind": "Name", "value": "catalogVersion" } }, { "kind": "Field", "name": { "kind": "Name", "value": "enabled" } }, { "kind": "Field", "name": { "kind": "Name", "value": "installedAt" } }, { "kind": "Field", "name": { "kind": "Name", "value": "updatedAt" } }] } }] } }] };
4345
+ var CliUninstallSkillDocument = { "kind": "Document", "definitions": [{ "kind": "OperationDefinition", "operation": "mutation", "name": { "kind": "Name", "value": "CliUninstallSkill" }, "variableDefinitions": [{ "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "tenantId" } }, "type": { "kind": "NonNullType", "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "ID" } } } }, { "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "skillId" } }, "type": { "kind": "NonNullType", "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "String" } } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "uninstallSkill" }, "arguments": [{ "kind": "Argument", "name": { "kind": "Name", "value": "tenantId" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "tenantId" } } }, { "kind": "Argument", "name": { "kind": "Name", "value": "skillId" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "skillId" } } }] }] } }] };
4344
4346
  var CliTeamsDocument = { "kind": "Document", "definitions": [{ "kind": "OperationDefinition", "operation": "query", "name": { "kind": "Name", "value": "CliTeams" }, "variableDefinitions": [{ "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "tenantId" } }, "type": { "kind": "NonNullType", "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "ID" } } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "teams" }, "arguments": [{ "kind": "Argument", "name": { "kind": "Name", "value": "tenantId" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "tenantId" } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "name" } }, { "kind": "Field", "name": { "kind": "Name", "value": "slug" } }, { "kind": "Field", "name": { "kind": "Name", "value": "type" } }, { "kind": "Field", "name": { "kind": "Name", "value": "status" } }, { "kind": "Field", "name": { "kind": "Name", "value": "budgetMonthlyCents" } }, { "kind": "Field", "name": { "kind": "Name", "value": "createdAt" } }] } }] } }] };
4345
4347
  var CliTeamDocument = { "kind": "Document", "definitions": [{ "kind": "OperationDefinition", "operation": "query", "name": { "kind": "Name", "value": "CliTeam" }, "variableDefinitions": [{ "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "id" } }, "type": { "kind": "NonNullType", "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "ID" } } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "team" }, "arguments": [{ "kind": "Argument", "name": { "kind": "Name", "value": "id" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "id" } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "name" } }, { "kind": "Field", "name": { "kind": "Name", "value": "slug" } }, { "kind": "Field", "name": { "kind": "Name", "value": "description" } }, { "kind": "Field", "name": { "kind": "Name", "value": "type" } }, { "kind": "Field", "name": { "kind": "Name", "value": "status" } }, { "kind": "Field", "name": { "kind": "Name", "value": "budgetMonthlyCents" } }, { "kind": "Field", "name": { "kind": "Name", "value": "createdAt" } }, { "kind": "Field", "name": { "kind": "Name", "value": "updatedAt" } }, { "kind": "Field", "name": { "kind": "Name", "value": "agents" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "agentId" } }, { "kind": "Field", "name": { "kind": "Name", "value": "role" } }, { "kind": "Field", "name": { "kind": "Name", "value": "joinedAt" } }] } }, { "kind": "Field", "name": { "kind": "Name", "value": "users" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "userId" } }, { "kind": "Field", "name": { "kind": "Name", "value": "role" } }, { "kind": "Field", "name": { "kind": "Name", "value": "joinedAt" } }] } }] } }] } }] };
4346
4348
  var CliCreateTeamDocument = { "kind": "Document", "definitions": [{ "kind": "OperationDefinition", "operation": "mutation", "name": { "kind": "Name", "value": "CliCreateTeam" }, "variableDefinitions": [{ "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "input" } }, "type": { "kind": "NonNullType", "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "CreateTeamInput" } } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "createTeam" }, "arguments": [{ "kind": "Argument", "name": { "kind": "Name", "value": "input" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "input" } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "name" } }, { "kind": "Field", "name": { "kind": "Name", "value": "type" } }, { "kind": "Field", "name": { "kind": "Name", "value": "status" } }] } }] } }] };
@@ -4522,6 +4524,8 @@ var documents = {
4522
4524
  "\n query CliSchedJobTenantBySlug($slug: String!) {\n tenantBySlug(slug: $slug) {\n id\n }\n }\n": CliSchedJobTenantBySlugDocument,
4523
4525
  "\n query CliSkillCatalog {\n skillCatalog {\n id\n skillId\n displayName\n description\n category\n icon\n source\n enabled\n }\n }\n": CliSkillCatalogDocument,
4524
4526
  "\n query CliSkillTenantBySlug($slug: String!) {\n tenantBySlug(slug: $slug) {\n id\n }\n }\n": CliSkillTenantBySlugDocument,
4527
+ "\n mutation CliInstallSkill($input: InstallSkillInput!) {\n installSkill(input: $input) {\n id\n tenantId\n skillId\n source\n version\n catalogVersion\n enabled\n installedAt\n updatedAt\n }\n }\n": CliInstallSkillDocument,
4528
+ "\n mutation CliUninstallSkill($tenantId: ID!, $skillId: String!) {\n uninstallSkill(tenantId: $tenantId, skillId: $skillId)\n }\n": CliUninstallSkillDocument,
4525
4529
  "\n query CliTeams($tenantId: ID!) {\n teams(tenantId: $tenantId) {\n id\n name\n slug\n type\n status\n budgetMonthlyCents\n createdAt\n }\n }\n": CliTeamsDocument,
4526
4530
  "\n query CliTeam($id: ID!) {\n team(id: $id) {\n id\n name\n slug\n description\n type\n status\n budgetMonthlyCents\n createdAt\n updatedAt\n agents {\n id\n agentId\n role\n joinedAt\n }\n users {\n id\n userId\n role\n joinedAt\n }\n }\n }\n": CliTeamDocument,
4527
4531
  "\n mutation CliCreateTeam($input: CreateTeamInput!) {\n createTeam(input: $input) {\n id\n name\n type\n status\n }\n }\n": CliCreateTeamDocument,
@@ -5038,15 +5042,15 @@ async function runThreadCreate(title, opts) {
5038
5042
  // src/commands/thread/update.ts
5039
5043
  async function runThreadUpdate(id, opts) {
5040
5044
  const ctx = await resolveThreadContext(opts);
5041
- const input20 = {};
5042
- if (opts.title !== void 0) input20.title = opts.title;
5043
- if (opts.assignee !== void 0) input20.assigneeId = opts.assignee;
5044
- if (opts.due !== void 0) input20.dueAt = opts.due;
5045
- if (Object.keys(input20).length === 0) {
5045
+ const input21 = {};
5046
+ if (opts.title !== void 0) input21.title = opts.title;
5047
+ if (opts.assignee !== void 0) input21.assigneeId = opts.assignee;
5048
+ if (opts.due !== void 0) input21.dueAt = opts.due;
5049
+ if (Object.keys(input21).length === 0) {
5046
5050
  printError("Nothing to update. Pass at least one of --title, --assignee, --due.");
5047
5051
  process.exit(1);
5048
5052
  }
5049
- const data = await gqlMutate(ctx.client, UpdateThreadDoc, { id, input: input20 });
5053
+ const data = await gqlMutate(ctx.client, UpdateThreadDoc, { id, input: input21 });
5050
5054
  const updated = data.updateThread;
5051
5055
  if (isJsonMode()) {
5052
5056
  printJson(updated);
@@ -5668,15 +5672,15 @@ async function runLabelCreate(name, opts) {
5668
5672
  }
5669
5673
  async function runLabelUpdate(id, opts) {
5670
5674
  const ctx = await resolveLabelContext(opts);
5671
- const input20 = {};
5672
- if (opts.name !== void 0) input20.name = opts.name;
5673
- if (opts.color !== void 0) input20.color = validateColor(opts.color);
5674
- if (opts.description !== void 0) input20.description = opts.description;
5675
- if (Object.keys(input20).length === 0) {
5675
+ const input21 = {};
5676
+ if (opts.name !== void 0) input21.name = opts.name;
5677
+ if (opts.color !== void 0) input21.color = validateColor(opts.color);
5678
+ if (opts.description !== void 0) input21.description = opts.description;
5679
+ if (Object.keys(input21).length === 0) {
5676
5680
  printError("Nothing to update. Pass at least one of --name, --color, --description.");
5677
5681
  process.exit(1);
5678
5682
  }
5679
- const data = await gqlMutate(ctx.client, UpdateThreadLabelDoc, { id, input: input20 });
5683
+ const data = await gqlMutate(ctx.client, UpdateThreadLabelDoc, { id, input: input21 });
5680
5684
  const updated = data.updateThreadLabel;
5681
5685
  if (isJsonMode()) {
5682
5686
  printJson(updated);
@@ -6714,19 +6718,19 @@ async function runAgentUpdate(id, opts) {
6714
6718
  if (!systemPrompt && opts.systemPromptFile) {
6715
6719
  systemPrompt = await readFile4(opts.systemPromptFile, "utf-8");
6716
6720
  }
6717
- const input20 = {};
6718
- if (opts.name !== void 0) input20.name = opts.name;
6719
- if (opts.role !== void 0) input20.role = opts.role;
6720
- if (opts.type !== void 0) input20.type = parseEnum(opts.type, TYPE_BY_NAME, "--type");
6721
- if (opts.parent !== void 0) input20.parentAgentId = opts.parent;
6722
- if (opts.reportsTo !== void 0) input20.reportsTo = opts.reportsTo;
6723
- if (systemPrompt !== void 0) input20.systemPrompt = systemPrompt;
6724
- if (opts.model !== void 0) input20.runtimeConfig = { model: opts.model };
6725
- if (Object.keys(input20).length === 0) {
6721
+ const input21 = {};
6722
+ if (opts.name !== void 0) input21.name = opts.name;
6723
+ if (opts.role !== void 0) input21.role = opts.role;
6724
+ if (opts.type !== void 0) input21.type = parseEnum(opts.type, TYPE_BY_NAME, "--type");
6725
+ if (opts.parent !== void 0) input21.parentAgentId = opts.parent;
6726
+ if (opts.reportsTo !== void 0) input21.reportsTo = opts.reportsTo;
6727
+ if (systemPrompt !== void 0) input21.systemPrompt = systemPrompt;
6728
+ if (opts.model !== void 0) input21.runtimeConfig = { model: opts.model };
6729
+ if (Object.keys(input21).length === 0) {
6726
6730
  printError("Nothing to update. Pass at least one field flag.");
6727
6731
  process.exit(1);
6728
6732
  }
6729
- const data = await gqlMutate(ctx.client, UpdateAgentDoc, { id, input: input20 });
6733
+ const data = await gqlMutate(ctx.client, UpdateAgentDoc, { id, input: input21 });
6730
6734
  if (isJsonMode()) {
6731
6735
  printJson(data.updateAgent);
6732
6736
  return;
@@ -7360,7 +7364,7 @@ function registerComputerCommand(program2) {
7360
7364
  const tenantId = resolveTenantId(opts);
7361
7365
  const computerId = resolveComputerId(opts);
7362
7366
  const taskType = resolveTaskType(opts);
7363
- const input20 = taskType === "workspace_file_write" ? { path: opts.path, content: opts.content } : void 0;
7367
+ const input21 = taskType === "workspace_file_write" ? { path: opts.path, content: opts.content } : void 0;
7364
7368
  if (!isJsonMode()) printHeader("computer task enqueue", stage);
7365
7369
  const response = await apiFetchRaw(
7366
7370
  api.apiUrl,
@@ -7372,7 +7376,7 @@ function registerComputerCommand(program2) {
7372
7376
  tenantId,
7373
7377
  computerId,
7374
7378
  taskType,
7375
- input: input20,
7379
+ input: input21,
7376
7380
  idempotencyKey: opts.idempotencyKey
7377
7381
  })
7378
7382
  }
@@ -7644,15 +7648,15 @@ async function runTemplateUpdate(id, opts) {
7644
7648
  "--system-prompt-file is not yet wired in the CLI \u2014 edit prompt files via the admin UI."
7645
7649
  );
7646
7650
  }
7647
- const input20 = {};
7648
- if (opts.name !== void 0) input20.name = opts.name;
7649
- if (opts.model !== void 0) input20.model = opts.model;
7650
- if (opts.description !== void 0) input20.description = opts.description;
7651
- if (Object.keys(input20).length === 0) {
7651
+ const input21 = {};
7652
+ if (opts.name !== void 0) input21.name = opts.name;
7653
+ if (opts.model !== void 0) input21.model = opts.model;
7654
+ if (opts.description !== void 0) input21.description = opts.description;
7655
+ if (Object.keys(input21).length === 0) {
7652
7656
  printError("Nothing to update. Pass at least one of --name, --model, --description.");
7653
7657
  process.exit(1);
7654
7658
  }
7655
- const data = await gqlMutate(ctx.client, UpdateAgentTemplateDoc, { id, input: input20 });
7659
+ const data = await gqlMutate(ctx.client, UpdateAgentTemplateDoc, { id, input: input21 });
7656
7660
  if (isJsonMode()) {
7657
7661
  printJson(data.updateAgentTemplate);
7658
7662
  return;
@@ -7974,15 +7978,15 @@ async function runTenantUpdate(id, opts) {
7974
7978
  printMissingApiSessionError(stage, false);
7975
7979
  process.exit(1);
7976
7980
  }
7977
- const input20 = {};
7978
- if (opts.name !== void 0) input20.name = opts.name;
7979
- if (opts.plan !== void 0) input20.plan = opts.plan;
7980
- if (opts.issuePrefix !== void 0) input20.issuePrefix = opts.issuePrefix;
7981
- if (Object.keys(input20).length === 0) {
7981
+ const input21 = {};
7982
+ if (opts.name !== void 0) input21.name = opts.name;
7983
+ if (opts.plan !== void 0) input21.plan = opts.plan;
7984
+ if (opts.issuePrefix !== void 0) input21.issuePrefix = opts.issuePrefix;
7985
+ if (Object.keys(input21).length === 0) {
7982
7986
  printError("Nothing to update. Pass at least one of --name, --plan, --issue-prefix.");
7983
7987
  process.exit(1);
7984
7988
  }
7985
- const data = await gqlMutate(client, UpdateTenantDoc, { id, input: input20 });
7989
+ const data = await gqlMutate(client, UpdateTenantDoc, { id, input: input21 });
7986
7990
  if (isJsonMode()) {
7987
7991
  printJson(data.updateTenant);
7988
7992
  return;
@@ -8020,18 +8024,18 @@ async function runTenantSettingsSet(tenantArg, opts) {
8020
8024
  stage: opts.stage,
8021
8025
  tenant: tenantArg
8022
8026
  });
8023
- const input20 = {};
8024
- if (opts.defaultModel !== void 0) input20.defaultModel = opts.defaultModel;
8027
+ const input21 = {};
8028
+ if (opts.defaultModel !== void 0) input21.defaultModel = opts.defaultModel;
8025
8029
  if (opts.monthlyBudgetUsd !== void 0) {
8026
- input20.budgetMonthlyCents = Math.round(Number.parseFloat(opts.monthlyBudgetUsd) * 100);
8030
+ input21.budgetMonthlyCents = Math.round(Number.parseFloat(opts.monthlyBudgetUsd) * 100);
8027
8031
  }
8028
- if (opts.maxAgents !== void 0) input20.maxAgents = Number.parseInt(opts.maxAgents, 10);
8032
+ if (opts.maxAgents !== void 0) input21.maxAgents = Number.parseInt(opts.maxAgents, 10);
8029
8033
  if (opts.autoCloseAfterDays !== void 0) {
8030
- input20.autoCloseThreadMinutes = Math.round(Number.parseFloat(opts.autoCloseAfterDays) * 60 * 24);
8034
+ input21.autoCloseThreadMinutes = Math.round(Number.parseFloat(opts.autoCloseAfterDays) * 60 * 24);
8031
8035
  }
8032
8036
  const features = parseFeatureFlags(opts.feature);
8033
- if (features !== void 0) input20.features = JSON.stringify(features);
8034
- if (Object.keys(input20).length === 0) {
8037
+ if (features !== void 0) input21.features = JSON.stringify(features);
8038
+ if (Object.keys(input21).length === 0) {
8035
8039
  printError(
8036
8040
  "Nothing to set. Pass at least one of --default-model, --monthly-budget-usd, --max-agents, --auto-close-after-days, --feature."
8037
8041
  );
@@ -8039,7 +8043,7 @@ async function runTenantSettingsSet(tenantArg, opts) {
8039
8043
  }
8040
8044
  const data = await gqlMutate(ctx.client, UpdateTenantSettingsDoc, {
8041
8045
  tenantId: ctx.tenantId,
8042
- input: input20
8046
+ input: input21
8043
8047
  });
8044
8048
  if (isJsonMode()) {
8045
8049
  printJson(data.updateTenantSettings);
@@ -8284,14 +8288,14 @@ async function runMemberInvite(email, opts) {
8284
8288
  }
8285
8289
  async function runMemberUpdate(memberId, opts) {
8286
8290
  const ctx = await resolveMemberContext(opts);
8287
- const input20 = {};
8288
- if (opts.role !== void 0) input20.role = opts.role;
8289
- if (opts.status !== void 0) input20.status = opts.status;
8290
- if (Object.keys(input20).length === 0) {
8291
+ const input21 = {};
8292
+ if (opts.role !== void 0) input21.role = opts.role;
8293
+ if (opts.status !== void 0) input21.status = opts.status;
8294
+ if (Object.keys(input21).length === 0) {
8291
8295
  printError("Nothing to update. Pass at least one of --role, --status.");
8292
8296
  process.exit(1);
8293
8297
  }
8294
- const data = await gqlMutate(ctx.client, UpdateTenantMemberDoc, { id: memberId, input: input20 });
8298
+ const data = await gqlMutate(ctx.client, UpdateTenantMemberDoc, { id: memberId, input: input21 });
8295
8299
  const updated = data.updateTenantMember;
8296
8300
  if (isJsonMode()) {
8297
8301
  printJson(updated);
@@ -8575,18 +8579,18 @@ async function runTeamCreate(name, opts) {
8575
8579
  }
8576
8580
  async function runTeamUpdate(id, opts) {
8577
8581
  const ctx = await resolveTeamContext(opts);
8578
- const input20 = {};
8579
- if (opts.name !== void 0) input20.name = opts.name;
8580
- if (opts.description !== void 0) input20.description = opts.description;
8581
- if (opts.status !== void 0) input20.status = opts.status;
8582
+ const input21 = {};
8583
+ if (opts.name !== void 0) input21.name = opts.name;
8584
+ if (opts.description !== void 0) input21.description = opts.description;
8585
+ if (opts.status !== void 0) input21.status = opts.status;
8582
8586
  if (opts.budgetUsd !== void 0) {
8583
- input20.budgetMonthlyCents = Math.round(Number.parseFloat(opts.budgetUsd) * 100);
8587
+ input21.budgetMonthlyCents = Math.round(Number.parseFloat(opts.budgetUsd) * 100);
8584
8588
  }
8585
- if (Object.keys(input20).length === 0) {
8589
+ if (Object.keys(input21).length === 0) {
8586
8590
  printError("Nothing to update. Pass at least one of --name, --description, --status, --budget-usd.");
8587
8591
  process.exit(1);
8588
8592
  }
8589
- const data = await gqlMutate(ctx.client, UpdateTeamDoc, { id, input: input20 });
8593
+ const data = await gqlMutate(ctx.client, UpdateTeamDoc, { id, input: input21 });
8590
8594
  if (isJsonMode()) {
8591
8595
  printJson(data.updateTeam);
8592
8596
  return;
@@ -8910,14 +8914,14 @@ async function runKbCreate(name, opts) {
8910
8914
  }
8911
8915
  async function runKbUpdate(id, opts) {
8912
8916
  const ctx = await resolveKbContext(opts);
8913
- const input20 = {};
8914
- if (opts.name !== void 0) input20.name = opts.name;
8915
- if (opts.description !== void 0) input20.description = opts.description;
8916
- if (Object.keys(input20).length === 0) {
8917
+ const input21 = {};
8918
+ if (opts.name !== void 0) input21.name = opts.name;
8919
+ if (opts.description !== void 0) input21.description = opts.description;
8920
+ if (Object.keys(input21).length === 0) {
8917
8921
  printError("Nothing to update. Pass at least one of --name, --description.");
8918
8922
  process.exit(1);
8919
8923
  }
8920
- const data = await gqlMutate(ctx.client, UpdateKBDoc, { id, input: input20 });
8924
+ const data = await gqlMutate(ctx.client, UpdateKBDoc, { id, input: input21 });
8921
8925
  if (isJsonMode()) {
8922
8926
  printJson(data.updateKnowledgeBase);
8923
8927
  return;
@@ -9366,12 +9370,12 @@ async function runRoutineCreate(name, opts) {
9366
9370
  }
9367
9371
  async function runRoutineUpdate(id, opts) {
9368
9372
  const ctx = await resolveRoutineContext(opts);
9369
- const input20 = {};
9370
- if (opts.name !== void 0) input20.name = opts.name;
9371
- if (opts.status !== void 0) input20.status = opts.status;
9372
- if (opts.agent !== void 0) input20.agentId = opts.agent;
9373
- if (opts.team !== void 0) input20.teamId = opts.team;
9374
- if (Object.keys(input20).length === 0) {
9373
+ const input21 = {};
9374
+ if (opts.name !== void 0) input21.name = opts.name;
9375
+ if (opts.status !== void 0) input21.status = opts.status;
9376
+ if (opts.agent !== void 0) input21.agentId = opts.agent;
9377
+ if (opts.team !== void 0) input21.teamId = opts.team;
9378
+ if (Object.keys(input21).length === 0) {
9375
9379
  printError("Nothing to update.");
9376
9380
  process.exit(1);
9377
9381
  }
@@ -9381,7 +9385,7 @@ async function runRoutineUpdate(id, opts) {
9381
9385
  );
9382
9386
  process.exit(1);
9383
9387
  }
9384
- const data = await gqlMutate(ctx.client, UpdateRoutineDoc, { id, input: input20 });
9388
+ const data = await gqlMutate(ctx.client, UpdateRoutineDoc, { id, input: input21 });
9385
9389
  if (isJsonMode()) {
9386
9390
  printJson(data.updateRoutine);
9387
9391
  return;
@@ -9861,18 +9865,18 @@ async function runSchedDelete(id, opts) {
9861
9865
  }
9862
9866
  async function runSchedUpdate(id, opts) {
9863
9867
  const ctx = await resolveSchedContext(opts);
9864
- const input20 = {};
9865
- if (opts.name !== void 0) input20.name = opts.name;
9866
- if (opts.description !== void 0) input20.description = opts.description;
9867
- if (opts.prompt !== void 0) input20.prompt = opts.prompt;
9868
+ const input21 = {};
9869
+ if (opts.name !== void 0) input21.name = opts.name;
9870
+ if (opts.description !== void 0) input21.description = opts.description;
9871
+ if (opts.prompt !== void 0) input21.prompt = opts.prompt;
9868
9872
  if (opts.schedule !== void 0) {
9869
- input20.scheduleExpression = opts.schedule;
9870
- input20.scheduleType = opts.schedule.trim().startsWith("cron(") ? "cron" : "rate";
9873
+ input21.scheduleExpression = opts.schedule;
9874
+ input21.scheduleType = opts.schedule.trim().startsWith("cron(") ? "cron" : "rate";
9871
9875
  }
9872
- if (opts.timezone !== void 0) input20.timezone = opts.timezone;
9876
+ if (opts.timezone !== void 0) input21.timezone = opts.timezone;
9873
9877
  if (opts.payload !== void 0) {
9874
9878
  try {
9875
- input20.config = JSON.stringify(JSON.parse(opts.payload));
9879
+ input21.config = JSON.stringify(JSON.parse(opts.payload));
9876
9880
  } catch (err) {
9877
9881
  printError(`--payload is not valid JSON: ${err.message}`);
9878
9882
  process.exit(1);
@@ -9882,9 +9886,9 @@ async function runSchedUpdate(id, opts) {
9882
9886
  printError("--enable and --disable are mutually exclusive.");
9883
9887
  process.exit(1);
9884
9888
  }
9885
- if (opts.enable) input20.enabled = true;
9886
- if (opts.disable) input20.enabled = false;
9887
- if (Object.keys(input20).length === 0) {
9889
+ if (opts.enable) input21.enabled = true;
9890
+ if (opts.disable) input21.enabled = false;
9891
+ if (Object.keys(input21).length === 0) {
9888
9892
  printError(
9889
9893
  "Nothing to update. Pass at least one of --schedule, --timezone, --payload, --enable/--disable, --name, --description, --prompt."
9890
9894
  );
@@ -9892,7 +9896,7 @@ async function runSchedUpdate(id, opts) {
9892
9896
  }
9893
9897
  const data = await gqlMutate(ctx.client, UpdateScheduledJobDoc, {
9894
9898
  id,
9895
- input: input20
9899
+ input: input21
9896
9900
  });
9897
9901
  if (isJsonMode()) {
9898
9902
  printJson(data.updateScheduledJob);
@@ -10603,25 +10607,25 @@ async function runWebhookCreate(name, opts) {
10603
10607
  }
10604
10608
  async function runWebhookUpdate(id, opts) {
10605
10609
  const ctx = await resolveWebhookContext(opts);
10606
- const input20 = {};
10607
- if (opts.targetType !== void 0) input20.targetType = opts.targetType.toUpperCase();
10610
+ const input21 = {};
10611
+ if (opts.targetType !== void 0) input21.targetType = opts.targetType.toUpperCase();
10608
10612
  if (opts.targetId !== void 0) {
10609
10613
  const tt = (opts.targetType ?? "").toUpperCase();
10610
- if (tt === "AGENT") input20.agentId = opts.targetId;
10611
- else if (tt === "ROUTINE") input20.routineId = opts.targetId;
10614
+ if (tt === "AGENT") input21.agentId = opts.targetId;
10615
+ else if (tt === "ROUTINE") input21.routineId = opts.targetId;
10612
10616
  else {
10613
10617
  printError("--target-id requires --target-type <AGENT|ROUTINE> on the same call.");
10614
10618
  process.exit(1);
10615
10619
  }
10616
10620
  }
10617
- if (opts.rateLimit !== void 0) input20.rateLimit = Number.parseInt(opts.rateLimit, 10);
10618
- if (opts.enable) input20.enabled = true;
10619
- if (opts.disable) input20.enabled = false;
10620
- if (Object.keys(input20).length === 0) {
10621
+ if (opts.rateLimit !== void 0) input21.rateLimit = Number.parseInt(opts.rateLimit, 10);
10622
+ if (opts.enable) input21.enabled = true;
10623
+ if (opts.disable) input21.enabled = false;
10624
+ if (Object.keys(input21).length === 0) {
10621
10625
  printError("Nothing to update.");
10622
10626
  process.exit(1);
10623
10627
  }
10624
- const data = await gqlMutate(ctx.client, UpdateWebhookDoc, { id, input: input20 });
10628
+ const data = await gqlMutate(ctx.client, UpdateWebhookDoc, { id, input: input21 });
10625
10629
  if (isJsonMode()) {
10626
10630
  printJson(data.updateWebhook);
10627
10631
  return;
@@ -10786,6 +10790,9 @@ Examples:
10786
10790
  ).option("-s, --stage <name>", "Deployment stage").option("-t, --tenant <slug>", "Tenant slug").option("--limit <n>", "Max rows (1-500)", "25").action(runWebhookDeliveries);
10787
10791
  }
10788
10792
 
10793
+ // src/commands/skill.ts
10794
+ import { input as input18 } from "@inquirer/prompts";
10795
+
10789
10796
  // src/lib/plugin-zip.ts
10790
10797
  import { createReadStream, promises as fsp, statSync } from "fs";
10791
10798
  import { basename, join as join5, relative, resolve as resolve3, sep } from "path";
@@ -10926,12 +10933,12 @@ function hasParentSegment(relPath) {
10926
10933
  }
10927
10934
 
10928
10935
  // src/lib/plugin-push.ts
10929
- async function pushPluginZip(input20) {
10930
- const base = input20.apiUrl.replace(/\/+$/, "");
10936
+ async function pushPluginZip(input21) {
10937
+ const base = input21.apiUrl.replace(/\/+$/, "");
10931
10938
  const presignRes = await fetch(`${base}/api/plugins/presign`, {
10932
10939
  method: "POST",
10933
- headers: withJson(input20.headers),
10934
- body: JSON.stringify({ fileName: input20.fileName })
10940
+ headers: withJson(input21.headers),
10941
+ body: JSON.stringify({ fileName: input21.fileName })
10935
10942
  });
10936
10943
  if (!presignRes.ok) {
10937
10944
  throw new Error(`presign failed: ${await describeHttpError(presignRes)}`);
@@ -10945,14 +10952,14 @@ async function pushPluginZip(input20) {
10945
10952
  const putRes = await fetch(presign.uploadUrl, {
10946
10953
  method: "PUT",
10947
10954
  headers: { "Content-Type": "application/zip" },
10948
- body: new Uint8Array(input20.zipBuffer)
10955
+ body: new Uint8Array(input21.zipBuffer)
10949
10956
  });
10950
10957
  if (!putRes.ok) {
10951
10958
  throw new Error(`S3 PUT failed: HTTP ${putRes.status}`);
10952
10959
  }
10953
10960
  const installRes = await fetch(`${base}/api/plugins/upload`, {
10954
10961
  method: "POST",
10955
- headers: withJson(input20.headers),
10962
+ headers: withJson(input21.headers),
10956
10963
  body: JSON.stringify({ s3Key: presign.s3Key })
10957
10964
  });
10958
10965
  const installBody = await installRes.json().catch(() => ({}));
@@ -11015,14 +11022,59 @@ var SkillTenantBySlugDoc = graphql(`
11015
11022
  }
11016
11023
  }
11017
11024
  `);
11025
+ var InstallSkillDoc = graphql(`
11026
+ mutation CliInstallSkill($input: InstallSkillInput!) {
11027
+ installSkill(input: $input) {
11028
+ id
11029
+ tenantId
11030
+ skillId
11031
+ source
11032
+ version
11033
+ catalogVersion
11034
+ enabled
11035
+ installedAt
11036
+ updatedAt
11037
+ }
11038
+ }
11039
+ `);
11040
+ var UninstallSkillDoc = graphql(`
11041
+ mutation CliUninstallSkill($tenantId: ID!, $skillId: String!) {
11042
+ uninstallSkill(tenantId: $tenantId, skillId: $skillId)
11043
+ }
11044
+ `);
11018
11045
  async function resolveSkillContext(opts) {
11019
11046
  const region = opts.region ?? "us-east-1";
11020
11047
  const stage = await resolveStage({ flag: opts.stage, region });
11021
11048
  const session = loadStageSession(stage);
11022
- const { client } = await getGqlClient({ stage, region });
11049
+ const { client, tenantSlug: ctxSlug } = await getGqlClient({ stage, region });
11023
11050
  if (!session) {
11024
11051
  }
11025
- return { stage, region, client };
11052
+ return { stage, region, client, session, ctxSlug };
11053
+ }
11054
+ async function resolveTenantIdForSkill(ctx, tenantOpt) {
11055
+ const flagOrEnv = tenantOpt ?? process.env.THINKWORK_TENANT;
11056
+ if (flagOrEnv) {
11057
+ if (ctx.session?.tenantSlug === flagOrEnv && ctx.session.tenantId) {
11058
+ return ctx.session.tenantId;
11059
+ }
11060
+ const data = await gqlQuery(ctx.client, SkillTenantBySlugDoc, {
11061
+ slug: flagOrEnv
11062
+ });
11063
+ if (!data.tenantBySlug) {
11064
+ printError(`Tenant "${flagOrEnv}" not found.`);
11065
+ process.exit(1);
11066
+ }
11067
+ return data.tenantBySlug.id;
11068
+ }
11069
+ if (ctx.session?.tenantId) return ctx.session.tenantId;
11070
+ if (ctx.ctxSlug) {
11071
+ const data = await gqlQuery(ctx.client, SkillTenantBySlugDoc, {
11072
+ slug: ctx.ctxSlug
11073
+ });
11074
+ if (data.tenantBySlug) return data.tenantBySlug.id;
11075
+ }
11076
+ printMissingApiSessionError(ctx.stage, ctx.session !== null);
11077
+ process.exit(1);
11026
11078
  }
11027
11079
  async function runSkillCatalog(opts) {
11028
11080
  const ctx = await resolveSkillContext(opts);
@@ -11087,13 +11139,59 @@ async function runSkillList(opts) {
11087
11139
  ]
11088
11140
  );
11089
11141
  }
11090
- function notYetImplementedAtApi(verb) {
11142
+ async function runSkillInstall(slug, opts) {
11143
+ const ctx = await resolveSkillContext(opts);
11144
+ const tenantId = await resolveTenantIdForSkill(ctx, opts.tenant);
11145
+ const data = await gqlMutate(ctx.client, InstallSkillDoc, {
11146
+ input: { tenantId, skillId: slug, version: opts.version ?? null }
11147
+ });
11148
+ if (isJsonMode()) {
11149
+ printJson(data.installSkill);
11150
+ return;
11151
+ }
11152
+ printSuccess(
11153
+ `Installed skill ${data.installSkill.skillId} (source=${data.installSkill.source}, version=${data.installSkill.version ?? "\u2014"}).`
11154
+ );
11155
+ }
11156
+ async function runSkillDelete(slug, opts) {
11157
+ const ctx = await resolveSkillContext(opts);
11158
+ const tenantId = await resolveTenantIdForSkill(ctx, opts.tenant);
11159
+ if (!opts.yes) {
11160
+ if (!isInteractive()) {
11161
+ printError(
11162
+ "Refusing to uninstall without --yes in non-interactive mode."
11163
+ );
11164
+ process.exit(1);
11165
+ }
11166
+ requireTty("confirmation");
11167
+ const answer = await promptOrExit(
11168
+ () => input18({
11169
+ message: `Uninstall skill "${slug}" from this tenant? Type "uninstall" to confirm:`
11170
+ })
11171
+ );
11172
+ if (answer.trim() !== "uninstall") {
11173
+ console.log(" Cancelled.");
11174
+ return;
11175
+ }
11176
+ }
11177
+ const data = await gqlMutate(ctx.client, UninstallSkillDoc, {
11178
+ tenantId,
11179
+ skillId: slug
11180
+ });
11181
+ if (isJsonMode()) {
11182
+ printJson({ skillId: slug, uninstalled: data.uninstallSkill });
11183
+ return;
11184
+ }
11185
+ if (data.uninstallSkill) {
11186
+ printSuccess(`Uninstalled skill ${slug} from tenant.`);
11187
+ } else {
11188
+ console.log(` Skill "${slug}" was not installed (no-op).`);
11189
+ }
11190
+ }
11191
+ function retiredVerb(verb, hint) {
11091
11192
  printError(
11092
- `\`skill ${verb}\` is not yet implemented at the GraphQL API.
11093
- The current schema exposes skillCatalog (read), per-computer enableSkill/disableSkill,
11094
- and the REST \`skill push\` upload path. Tenant-scoped install/upgrade/create/update/delete
11095
- is tracked as a Phase-3 follow-up. Use \`thinkwork skill push <folder>\` to upload custom
11096
- plugins; toggle catalog skills per-agent via \`thinkwork agent skills set\` for now.`
11193
+ `\`skill ${verb}\` was retired: ${hint}
11194
+ See \`thinkwork skill --help\` for the supported verbs.`
11097
11195
  );
11098
11196
  process.exit(2);
11099
11197
  }
@@ -11103,11 +11201,27 @@ function registerSkillCommand(program2) {
11103
11201
  );
11104
11202
  skill.command("catalog").description("Browse the skill catalog. Client-side filters --search and --tag are applied locally.").option("-s, --stage <name>", "Deployment stage").option("-t, --tenant <slug>", "Tenant slug").option("--search <q>", "Filter by keyword").option("--tag <t>", "Filter by category").action(runSkillCatalog);
11105
11203
  skill.command("list").alias("ls").description("List skills available to the tenant.").option("-s, --stage <name>", "Deployment stage").option("-t, --tenant <slug>", "Tenant slug").option("--custom-only", "Only show tenant-owned custom skills (source=tenant)").action(runSkillList);
11106
- skill.command("install <slug>").description("Install a public skill. (API surface pending \u2014 toggle per-agent via `agent skills set`.)").option("-s, --stage <name>", "Deployment stage").option("-t, --tenant <slug>", "Tenant slug").option("--version <v>", "Pin to a specific version").action(() => notYetImplementedAtApi("install"));
11107
- skill.command("upgrade <slug>").description("Upgrade an installed skill. (API surface pending.)").option("-s, --stage <name>", "Deployment stage").option("-t, --tenant <slug>", "Tenant slug").action(() => notYetImplementedAtApi("upgrade"));
11108
- skill.command("create [slug]").description("Publish a custom tenant-scoped skill. (Use `skill push <folder>` for now.)").option("-s, --stage <name>", "Deployment stage").option("-t, --tenant <slug>", "Tenant slug").option("--name <n>").option("--description <text>").option("--manifest-file <path>", "Path to the MCP server manifest JSON").option("--endpoint <url>", "MCP server HTTP/SSE endpoint").action(() => notYetImplementedAtApi("create"));
11109
- skill.command("update <slug>").description("Update a custom skill. (API surface pending.)").option("-s, --stage <name>", "Deployment stage").option("-t, --tenant <slug>", "Tenant slug").option("--name <n>").option("--description <text>").option("--manifest-file <path>").option("--endpoint <url>").action(() => notYetImplementedAtApi("update"));
11110
- skill.command("delete <slug>").description("Delete a custom skill. (API surface pending.)").option("-s, --stage <name>", "Deployment stage").option("-t, --tenant <slug>", "Tenant slug").option("-y, --yes", "Skip confirmation").action(() => notYetImplementedAtApi("delete"));
11204
+ skill.command("install <slug>").description(
11205
+ "Install a catalog skill into the tenant (upserts tenant_skills). Idempotent \u2014 re-running bumps the version. Per-agent assignment still goes through `agent skills set`."
11206
+ ).option("-s, --stage <name>", "Deployment stage").option("-t, --tenant <slug>", "Tenant slug").option("--version <v>", "Pin to a specific version (defaults to catalog's current)").action(runSkillInstall);
11207
+ skill.command("upgrade <slug>").description(
11208
+ "Upgrade an installed skill to the catalog's current version (or to --version). Same mutation as `install`."
11209
+ ).option("-s, --stage <name>", "Deployment stage").option("-t, --tenant <slug>", "Tenant slug").option("--version <v>", "Pin to a specific version").action(runSkillInstall);
11210
+ skill.command("create [slug]").description("Retired \u2014 use `thinkwork skill push <folder>` to publish a custom skill.").action(
11211
+ () => retiredVerb(
11212
+ "create",
11213
+ "custom-skill authoring is done by uploading a folder via `thinkwork skill push <folder>`."
11214
+ )
11215
+ );
11216
+ skill.command("update <slug>").description("Retired \u2014 re-push the skill folder with `thinkwork skill push <folder>` to update.").action(
11217
+ () => retiredVerb(
11218
+ "update",
11219
+ "updates are done by re-pushing the skill folder via `thinkwork skill push <folder>`."
11220
+ )
11221
+ );
11222
+ skill.command("delete <slug>").description(
11223
+ "Uninstall a skill from the tenant (deletes the tenant_skills row). Confirms unless --yes."
11224
+ ).option("-s, --stage <name>", "Deployment stage").option("-t, --tenant <slug>", "Tenant slug").option("-y, --yes", "Skip confirmation").action(runSkillDelete);
11111
11225
  skill.command("push <folder>").description(
11112
11226
  "Zip a local plugin folder and upload it to the tenant as a pending plugin."
11113
11227
  ).option("-s, --stage <name>", "Deployment stage").option("--region <name>", "AWS region", "us-east-1").addHelpText(
@@ -11471,7 +11585,7 @@ function registerMemoryCommand(program2) {
11471
11585
  }
11472
11586
 
11473
11587
  // src/commands/recipe.ts
11474
- import { confirm as confirm15, input as input18 } from "@inquirer/prompts";
11588
+ import { confirm as confirm15, input as input19 } from "@inquirer/prompts";
11475
11589
  var RecipesDoc = graphql(`
11476
11590
  query CliRecipes($tenantId: ID!, $threadId: ID, $agentId: ID, $limit: Int, $cursor: String) {
11477
11591
  recipes(tenantId: $tenantId, threadId: $threadId, agentId: $agentId, limit: $limit, cursor: $cursor) {
@@ -11627,7 +11741,7 @@ async function runRecipeCreate(name, opts) {
11627
11741
  process.exit(1);
11628
11742
  }
11629
11743
  requireTty("Recipe name");
11630
- title = await promptOrExit(() => input18({ message: "Recipe title:" }));
11744
+ title = await promptOrExit(() => input19({ message: "Recipe title:" }));
11631
11745
  }
11632
11746
  if (!opts.tool) {
11633
11747
  printError("--tool <server/tool> is required.");
@@ -11668,22 +11782,22 @@ async function runRecipeCreate(name, opts) {
11668
11782
  }
11669
11783
  async function runRecipeUpdate(id, opts) {
11670
11784
  const ctx = await resolveRecipeContext(opts);
11671
- const input20 = {};
11672
- if (opts.title !== void 0) input20.title = opts.title;
11673
- if (opts.summary !== void 0) input20.summary = opts.summary;
11785
+ const input21 = {};
11786
+ if (opts.title !== void 0) input21.title = opts.title;
11787
+ if (opts.summary !== void 0) input21.summary = opts.summary;
11674
11788
  if (opts.params !== void 0) {
11675
11789
  try {
11676
- input20.params = JSON.parse(opts.params);
11790
+ input21.params = JSON.parse(opts.params);
11677
11791
  } catch (err) {
11678
11792
  printError(`--params is not valid JSON: ${err.message}`);
11679
11793
  process.exit(1);
11680
11794
  }
11681
11795
  }
11682
- if (Object.keys(input20).length === 0) {
11796
+ if (Object.keys(input21).length === 0) {
11683
11797
  printError("Nothing to update.");
11684
11798
  process.exit(1);
11685
11799
  }
11686
- const data = await gqlMutate(ctx.client, UpdateRecipeDoc, { id, input: input20 });
11800
+ const data = await gqlMutate(ctx.client, UpdateRecipeDoc, { id, input: input21 });
11687
11801
  if (isJsonMode()) {
11688
11802
  printJson(data.updateRecipe);
11689
11803
  return;
@@ -13264,7 +13378,7 @@ async function runEvalTestCaseGet(id, opts) {
13264
13378
 
13265
13379
  // src/commands/eval/test-case/create.ts
13266
13380
  import { readFileSync as readFileSync4 } from "fs";
13267
- import { input as input19, select as select8, checkbox as checkbox2 } from "@inquirer/prompts";
13381
+ import { input as input20, select as select8, checkbox as checkbox2 } from "@inquirer/prompts";
13268
13382
  var DEFAULT_EVALUATORS = [
13269
13383
  "Builtin.Helpfulness",
13270
13384
  "Builtin.Correctness",
@@ -13294,17 +13408,17 @@ async function runEvalTestCaseCreate(opts) {
13294
13408
  if (!name) {
13295
13409
  requireTty("Name");
13296
13410
  name = await promptOrExit(
13297
- () => input19({ message: "Test case name?", validate: (v) => v.trim().length > 0 || "Required" })
13411
+ () => input20({ message: "Test case name?", validate: (v) => v.trim().length > 0 || "Required" })
13298
13412
  );
13299
13413
  }
13300
13414
  if (!category) {
13301
13415
  category = await promptOrExit(
13302
- () => input19({ message: "Category (free-form label)?", validate: (v) => v.trim().length > 0 || "Required" })
13416
+ () => input20({ message: "Category (free-form label)?", validate: (v) => v.trim().length > 0 || "Required" })
13303
13417
  );
13304
13418
  }
13305
13419
  if (!query) {
13306
13420
  query = await promptOrExit(
13307
- () => input19({ message: "Query the agent under test will receive?", validate: (v) => v.trim().length > 0 || "Required" })
13421
+ () => input20({ message: "Query the agent under test will receive?", validate: (v) => v.trim().length > 0 || "Required" })
13308
13422
  );
13309
13423
  }
13310
13424
  if (interactive && agentTemplateId === null) {
@@ -13370,28 +13484,28 @@ async function runEvalTestCaseCreate(opts) {
13370
13484
  import { readFileSync as readFileSync5 } from "fs";
13371
13485
  async function runEvalTestCaseUpdate(id, opts) {
13372
13486
  const ctx = await resolveEvalContext(opts);
13373
- const input20 = {};
13374
- if (opts.name !== void 0) input20.name = opts.name;
13375
- if (opts.category !== void 0) input20.category = opts.category;
13376
- if (opts.query !== void 0) input20.query = opts.query;
13377
- if (opts.systemPrompt !== void 0) input20.systemPrompt = opts.systemPrompt;
13378
- if (opts.agentTemplate !== void 0) input20.agentTemplateId = opts.agentTemplate;
13379
- if (opts.evaluator !== void 0) input20.agentcoreEvaluatorIds = opts.evaluator;
13380
- if (opts.tag !== void 0) input20.tags = opts.tag;
13381
- if (opts.enabled !== void 0) input20.enabled = opts.enabled;
13487
+ const input21 = {};
13488
+ if (opts.name !== void 0) input21.name = opts.name;
13489
+ if (opts.category !== void 0) input21.category = opts.category;
13490
+ if (opts.query !== void 0) input21.query = opts.query;
13491
+ if (opts.systemPrompt !== void 0) input21.systemPrompt = opts.systemPrompt;
13492
+ if (opts.agentTemplate !== void 0) input21.agentTemplateId = opts.agentTemplate;
13493
+ if (opts.evaluator !== void 0) input21.agentcoreEvaluatorIds = opts.evaluator;
13494
+ if (opts.tag !== void 0) input21.tags = opts.tag;
13495
+ if (opts.enabled !== void 0) input21.enabled = opts.enabled;
13382
13496
  if (opts.assertionsFile) {
13383
13497
  const parsed = JSON.parse(readFileSync5(opts.assertionsFile, "utf8"));
13384
13498
  if (!Array.isArray(parsed)) {
13385
13499
  printError(`--assertions-file must contain a JSON array.`);
13386
13500
  process.exit(1);
13387
13501
  }
13388
- input20.assertions = parsed;
13502
+ input21.assertions = parsed;
13389
13503
  }
13390
- if (Object.keys(input20).length === 0) {
13504
+ if (Object.keys(input21).length === 0) {
13391
13505
  printError("No fields to update. Pass at least one --<field>.");
13392
13506
  process.exit(1);
13393
13507
  }
13394
- const res = await gqlMutate(ctx.client, UpdateEvalTestCaseDoc, { id, input: input20 });
13508
+ const res = await gqlMutate(ctx.client, UpdateEvalTestCaseDoc, { id, input: input21 });
13395
13509
  if (isJsonMode()) {
13396
13510
  printJson(res.updateEvalTestCase);
13397
13511
  return;
@@ -14852,12 +14966,12 @@ function awsOk(args) {
14852
14966
 
14853
14967
  // src/commands/enterprise/github.ts
14854
14968
  import { execFileSync as execFileSync2 } from "child_process";
14855
- function parseGitHubRepository(input20) {
14856
- const trimmed = input20.trim();
14969
+ function parseGitHubRepository(input21) {
14970
+ const trimmed = input21.trim();
14857
14971
  const match = /^([A-Za-z0-9_.-]+)\/([A-Za-z0-9_.-]+)$/.exec(trimmed);
14858
14972
  if (!match) {
14859
14973
  throw new Error(
14860
- `Invalid GitHub repository "${input20}". Use owner/name, for example acme/thinkwork-deploy.`
14974
+ `Invalid GitHub repository "${input21}". Use owner/name, for example acme/thinkwork-deploy.`
14861
14975
  );
14862
14976
  }
14863
14977
  return {
@@ -15222,16 +15336,16 @@ async function resolveCustomerSlug(flag) {
15222
15336
  if (!process.stdin.isTTY) {
15223
15337
  throw new Error("Customer slug is required. Pass --customer <slug>.");
15224
15338
  }
15225
- const { input: input20 } = await import("@inquirer/prompts");
15226
- return input20({ message: "Customer slug:" });
15339
+ const { input: input21 } = await import("@inquirer/prompts");
15340
+ return input21({ message: "Customer slug:" });
15227
15341
  }
15228
15342
  async function resolveRepository(flag) {
15229
15343
  if (flag) return flag;
15230
15344
  if (!process.stdin.isTTY) {
15231
15345
  throw new Error("GitHub repository is required. Pass --repo <owner/name>.");
15232
15346
  }
15233
- const { input: input20 } = await import("@inquirer/prompts");
15234
- return input20({ message: "GitHub deployment repo (owner/name):" });
15347
+ const { input: input21 } = await import("@inquirer/prompts");
15348
+ return input21({ message: "GitHub deployment repo (owner/name):" });
15235
15349
  }
15236
15350
  function printBootstrapSummary(result) {
15237
15351
  console.log("");
@@ -15485,7 +15599,7 @@ async function applyEnterpriseOverlay(plan, client) {
15485
15599
  skipped: 0
15486
15600
  };
15487
15601
  for (const testCase of operation.testCases) {
15488
- const input20 = withOverlayTags(
15602
+ const input21 = withOverlayTags(
15489
15603
  operation.pack,
15490
15604
  testCase,
15491
15605
  client.targetAgentTemplateId
@@ -15494,16 +15608,16 @@ async function applyEnterpriseOverlay(plan, client) {
15494
15608
  overlayKeyTag(operation.pack, testCase)
15495
15609
  );
15496
15610
  if (existingCase) {
15497
- if (sameEval(existingCase, input20)) {
15611
+ if (sameEval(existingCase, input21)) {
15498
15612
  result.evals.skipped++;
15499
15613
  packResult.skipped++;
15500
15614
  } else {
15501
- await client.updateEvalTestCase(existingCase.id, input20);
15615
+ await client.updateEvalTestCase(existingCase.id, input21);
15502
15616
  result.evals.updated++;
15503
15617
  packResult.updated++;
15504
15618
  }
15505
15619
  } else {
15506
- await client.createEvalTestCase(input20);
15620
+ await client.createEvalTestCase(input21);
15507
15621
  result.evals.inserted++;
15508
15622
  packResult.inserted++;
15509
15623
  }
@@ -15673,19 +15787,19 @@ async function createOverlayApiClient(plan, opts) {
15673
15787
  });
15674
15788
  return data.evalTestCases;
15675
15789
  },
15676
- async createEvalTestCase(input20) {
15790
+ async createEvalTestCase(input21) {
15677
15791
  await gqlMutate(ctx.client, CreateEvalTestCaseDoc, {
15678
15792
  tenantId: ctx.tenantId,
15679
- input: evalInput(input20)
15793
+ input: evalInput(input21)
15680
15794
  });
15681
15795
  },
15682
- async updateEvalTestCase(id, input20) {
15796
+ async updateEvalTestCase(id, input21) {
15683
15797
  await gqlMutate(ctx.client, UpdateEvalTestCaseDoc, {
15684
15798
  id,
15685
- input: evalInput(input20)
15799
+ input: evalInput(input21)
15686
15800
  });
15687
15801
  },
15688
- async putWorkspaceFile(input20) {
15802
+ async putWorkspaceFile(input21) {
15689
15803
  const response = await fetch(
15690
15804
  `${apiUrl.replace(/\/+$/, "")}/api/workspaces/files`,
15691
15805
  {
@@ -15698,15 +15812,15 @@ async function createOverlayApiClient(plan, opts) {
15698
15812
  body: JSON.stringify({
15699
15813
  action: "put",
15700
15814
  templateId,
15701
- path: input20.path,
15702
- content: input20.content
15815
+ path: input21.path,
15816
+ content: input21.content
15703
15817
  })
15704
15818
  }
15705
15819
  );
15706
15820
  if (!response.ok) {
15707
15821
  const text = await response.text();
15708
15822
  throw new Error(
15709
- `PUT ${input20.path} failed: ${response.status} ${text || response.statusText}`
15823
+ `PUT ${input21.path} failed: ${response.status} ${text || response.statusText}`
15710
15824
  );
15711
15825
  }
15712
15826
  }
@@ -15724,17 +15838,17 @@ async function resolveTemplateId(client, tenantId, templateSlug) {
15724
15838
  }
15725
15839
  return template.id;
15726
15840
  }
15727
- function evalInput(input20) {
15841
+ function evalInput(input21) {
15728
15842
  return {
15729
- name: input20.name,
15730
- category: input20.category,
15731
- query: input20.query,
15732
- systemPrompt: input20.systemPrompt ?? null,
15733
- agentTemplateId: input20.agentTemplateId ?? null,
15734
- assertions: input20.assertions,
15735
- agentcoreEvaluatorIds: input20.agentcoreEvaluatorIds ?? [],
15736
- tags: input20.tags ?? [],
15737
- enabled: input20.enabled ?? true
15843
+ name: input21.name,
15844
+ category: input21.category,
15845
+ query: input21.query,
15846
+ systemPrompt: input21.systemPrompt ?? null,
15847
+ agentTemplateId: input21.agentTemplateId ?? null,
15848
+ assertions: input21.assertions,
15849
+ agentcoreEvaluatorIds: input21.agentcoreEvaluatorIds ?? [],
15850
+ tags: input21.tags ?? [],
15851
+ enabled: input21.enabled ?? true
15738
15852
  };
15739
15853
  }
15740
15854
  function publicPlan(plan) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "thinkwork-cli",
3
- "version": "0.12.7",
3
+ "version": "0.12.8",
4
4
  "description": "Thinkwork CLI — deploy, manage, and interact with your Thinkwork stack",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",