aipctl 2026.9.9 → 2026.9.10

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/build/index.cjs CHANGED
@@ -89670,7 +89670,7 @@ const injectedBuildEnv = "dev".length > 0 ? "dev" : "local";
89670
89670
  if (!isBuildEnv(injectedBuildEnv)) {
89671
89671
  throw new Error(`Invalid AIPCTL_BUILD_ENV: ${injectedBuildEnv}`);
89672
89672
  }
89673
- const VERSION = "2026.9.9".length > 0 ? "2026.9.9" : "0.0.0";
89673
+ const VERSION = "2026.9.10".length > 0 ? "2026.9.10" : "0.0.0";
89674
89674
  const BUILD_ENV = injectedBuildEnv;
89675
89675
  const INCLUDE_NATIVE_LOGS = BUILD_ENV !== "prod";
89676
89676
 
@@ -89819,7 +89819,25 @@ const implementedCommandOperationIds = /* @__PURE__ */ new Set([
89819
89819
  "listCliOrganizationMembers",
89820
89820
  "listCliModels",
89821
89821
  "listCliModelExecModels",
89822
- "createCliModelChatExecution"
89822
+ "createCliModelChatExecution",
89823
+ "listCliSkills",
89824
+ "getCliSkill",
89825
+ "deleteCliSkill",
89826
+ "listCliSkillLibrary",
89827
+ "createCliSkillClones",
89828
+ "listCliBuiltInSkills",
89829
+ "createCliBuiltInSkillClones",
89830
+ "listCliAdminSkills",
89831
+ "getCliAdminSkill",
89832
+ "deleteCliAdminSkill",
89833
+ "updateCliAdminSkill",
89834
+ "listCliAdminBuiltInSkills",
89835
+ "createCliAdminBuiltInSkillClones",
89836
+ "listCliDriveEntries",
89837
+ "getCliDriveUsage",
89838
+ "createCliDriveFolder",
89839
+ "updateCliDriveEntryName",
89840
+ "deleteCliDriveEntries"
89823
89841
  ]);
89824
89842
  const releaseEnabledCommandOperationIds = /* @__PURE__ */ new Set([
89825
89843
  "listCliAgents",
@@ -89836,7 +89854,25 @@ const releaseEnabledCommandOperationIds = /* @__PURE__ */ new Set([
89836
89854
  "getCliOrganizationCapabilities",
89837
89855
  "listCliOrganizationMembers",
89838
89856
  "listCliModels",
89839
- "listCliModelExecModels"
89857
+ "listCliModelExecModels",
89858
+ "listCliSkills",
89859
+ "getCliSkill",
89860
+ "deleteCliSkill",
89861
+ "listCliSkillLibrary",
89862
+ "createCliSkillClones",
89863
+ "listCliBuiltInSkills",
89864
+ "createCliBuiltInSkillClones",
89865
+ "listCliAdminSkills",
89866
+ "getCliAdminSkill",
89867
+ "deleteCliAdminSkill",
89868
+ "updateCliAdminSkill",
89869
+ "listCliAdminBuiltInSkills",
89870
+ "createCliAdminBuiltInSkillClones",
89871
+ "listCliDriveEntries",
89872
+ "getCliDriveUsage",
89873
+ "createCliDriveFolder",
89874
+ "updateCliDriveEntryName",
89875
+ "deleteCliDriveEntries"
89840
89876
  ]);
89841
89877
  const direct = (commands, operation) => commands.map((command) => ({
89842
89878
  command,
@@ -95046,11 +95082,12 @@ const makeApiServiceLive = (buildEnv) => effect$1(
95046
95082
  }),
95047
95083
  listSkills: (orgSlug, options) => gen(function* () {
95048
95084
  const token = yield* getAccessToken();
95085
+ yield* requireReleaseEnabledOperation("listCliSkills");
95049
95086
  const params = new URLSearchParams();
95050
95087
  params.set("count", String(options?.count ?? 50));
95051
95088
  if (options?.cursor) params.set("cursor", options.cursor);
95052
95089
  if (options?.search) params.set("search", options.search);
95053
- const path = `/api/web/organizations/slug/${encodeURIComponent(orgSlug)}/skills?${params.toString()}`;
95090
+ const path = `/api/cli/v1/organizations/${encodeURIComponent(orgSlug)}/skills?${params.toString()}`;
95054
95091
  const response = yield* makeRequest(baseUrl, path, token);
95055
95092
  return {
95056
95093
  ...response,
@@ -95067,11 +95104,12 @@ const makeApiServiceLive = (buildEnv) => effect$1(
95067
95104
  }),
95068
95105
  listAdminSkills: (orgSlug, options) => gen(function* () {
95069
95106
  const token = yield* getAccessToken();
95107
+ yield* requireReleaseEnabledOperation("listCliAdminSkills");
95070
95108
  const params = new URLSearchParams();
95071
95109
  params.set("pageNumber", String(options?.pageNumber ?? 1));
95072
95110
  params.set("pageSize", String(options?.pageSize ?? 20));
95073
95111
  if (options?.search) params.set("search", options.search);
95074
- const path = `/api/web/admin/organizations/slug/${encodeURIComponent(orgSlug)}/skills?${params.toString()}`;
95112
+ const path = `/api/cli/v1/organizations/${encodeURIComponent(orgSlug)}/admin/skills?${params.toString()}`;
95075
95113
  const response = yield* makeRequest(baseUrl, path, token);
95076
95114
  return {
95077
95115
  ...response,
@@ -95141,12 +95179,14 @@ const makeApiServiceLive = (buildEnv) => effect$1(
95141
95179
  }),
95142
95180
  deleteSkill: (orgSlug, skillId) => gen(function* () {
95143
95181
  const token = yield* getAccessToken();
95144
- const path = `/api/web/organizations/slug/${encodeURIComponent(orgSlug)}/skills/${encodeURIComponent(skillId)}`;
95182
+ yield* requireReleaseEnabledOperation("deleteCliSkill");
95183
+ const path = `/api/cli/v1/organizations/${encodeURIComponent(orgSlug)}/skills/${encodeURIComponent(skillId)}`;
95145
95184
  return yield* makeRequest(baseUrl, path, token, { method: "DELETE" });
95146
95185
  }),
95147
95186
  deleteAdminSkill: (orgSlug, skillId) => gen(function* () {
95148
95187
  const token = yield* getAccessToken();
95149
- const path = `/api/web/admin/organizations/slug/${encodeURIComponent(orgSlug)}/skills/${encodeURIComponent(skillId)}`;
95188
+ yield* requireReleaseEnabledOperation("deleteCliAdminSkill");
95189
+ const path = `/api/cli/v1/organizations/${encodeURIComponent(orgSlug)}/admin/skills/${encodeURIComponent(skillId)}`;
95150
95190
  return yield* makeRequest(baseUrl, path, token, { method: "DELETE" });
95151
95191
  }),
95152
95192
  getCurrentOrganization: () => gen(function* () {
@@ -95163,10 +95203,11 @@ const makeApiServiceLive = (buildEnv) => effect$1(
95163
95203
  // Phase 1: Skill detail/download/library/clone
95164
95204
  getSkill: (orgSlug, skillId, options) => gen(function* () {
95165
95205
  const token = yield* getAccessToken();
95206
+ yield* requireReleaseEnabledOperation("getCliSkill");
95166
95207
  const params = new URLSearchParams();
95167
95208
  if (options?.maxFiles) params.set("maxFiles", String(options.maxFiles));
95168
95209
  const qs = params.toString();
95169
- const path = `/api/web/organizations/slug/${encodeURIComponent(orgSlug)}/skills/${encodeURIComponent(skillId)}${qs ? `?${qs}` : ""}`;
95210
+ const path = `/api/cli/v1/organizations/${encodeURIComponent(orgSlug)}/skills/${encodeURIComponent(skillId)}${qs ? `?${qs}` : ""}`;
95170
95211
  const response = yield* makeRequest(baseUrl, path, token);
95171
95212
  return {
95172
95213
  ...response,
@@ -95178,10 +95219,11 @@ const makeApiServiceLive = (buildEnv) => effect$1(
95178
95219
  }),
95179
95220
  getAdminSkill: (orgSlug, skillId, options) => gen(function* () {
95180
95221
  const token = yield* getAccessToken();
95222
+ yield* requireReleaseEnabledOperation("getCliAdminSkill");
95181
95223
  const params = new URLSearchParams();
95182
95224
  if (options?.maxFiles) params.set("maxFiles", String(options.maxFiles));
95183
95225
  const qs = params.toString();
95184
- const path = `/api/web/admin/organizations/slug/${encodeURIComponent(orgSlug)}/skills/${encodeURIComponent(skillId)}${qs ? `?${qs}` : ""}`;
95226
+ const path = `/api/cli/v1/organizations/${encodeURIComponent(orgSlug)}/admin/skills/${encodeURIComponent(skillId)}${qs ? `?${qs}` : ""}`;
95185
95227
  const response = yield* makeRequest(baseUrl, path, token);
95186
95228
  return {
95187
95229
  ...response,
@@ -95193,7 +95235,8 @@ const makeApiServiceLive = (buildEnv) => effect$1(
95193
95235
  }),
95194
95236
  updateAdminSkill: (orgSlug, skillId, body) => gen(function* () {
95195
95237
  const token = yield* getAccessToken();
95196
- const path = `/api/web/admin/organizations/slug/${encodeURIComponent(orgSlug)}/skills/${encodeURIComponent(skillId)}`;
95238
+ yield* requireReleaseEnabledOperation("updateCliAdminSkill");
95239
+ const path = `/api/cli/v1/organizations/${encodeURIComponent(orgSlug)}/admin/skills/${encodeURIComponent(skillId)}`;
95197
95240
  return yield* makeRequest(baseUrl, path, token, {
95198
95241
  method: "PATCH",
95199
95242
  body
@@ -95253,16 +95296,18 @@ const makeApiServiceLive = (buildEnv) => effect$1(
95253
95296
  }),
95254
95297
  listLibrarySkills: (orgSlug, options) => gen(function* () {
95255
95298
  const token = yield* getAccessToken();
95299
+ yield* requireReleaseEnabledOperation("listCliSkillLibrary");
95256
95300
  const params = new URLSearchParams();
95257
95301
  params.set("count", String(options?.count ?? 50));
95258
95302
  if (options?.cursor) params.set("cursor", options.cursor);
95259
95303
  if (options?.search) params.set("search", options.search);
95260
- const path = `/api/web/organizations/slug/${encodeURIComponent(orgSlug)}/skills/library?${params.toString()}`;
95304
+ const path = `/api/cli/v1/organizations/${encodeURIComponent(orgSlug)}/skills/library?${params.toString()}`;
95261
95305
  return yield* makeRequest(baseUrl, path, token);
95262
95306
  }),
95263
95307
  cloneSkills: (orgSlug, sourceSkillIds) => gen(function* () {
95264
95308
  const token = yield* getAccessToken();
95265
- const path = `/api/web/organizations/slug/${encodeURIComponent(orgSlug)}/skills/library/clone`;
95309
+ yield* requireReleaseEnabledOperation("createCliSkillClones");
95310
+ const path = `/api/cli/v1/organizations/${encodeURIComponent(orgSlug)}/skills/library/clone`;
95266
95311
  return yield* makeRequest(baseUrl, path, token, {
95267
95312
  method: "POST",
95268
95313
  body: { sourceSkillIds }
@@ -95481,8 +95526,9 @@ const makeApiServiceLive = (buildEnv) => effect$1(
95481
95526
  // Phase 5: Drive/Integration
95482
95527
  listDriveEntries: (orgSlug) => gen(function* () {
95483
95528
  const token = yield* getAccessToken();
95529
+ yield* requireReleaseEnabledOperation("listCliDriveEntries");
95484
95530
  const params = new URLSearchParams({ count: "200" });
95485
- const path = `/api/web/organizations/slug/${encodeURIComponent(orgSlug)}/drive/entries?${params.toString()}`;
95531
+ const path = `/api/cli/v1/organizations/${encodeURIComponent(orgSlug)}/drive/entries?${params.toString()}`;
95486
95532
  return yield* makeRequest(baseUrl, path, token);
95487
95533
  }),
95488
95534
  getDriveDownloadUrl: (orgSlug, entryId) => gen(function* () {
@@ -95516,22 +95562,26 @@ const makeApiServiceLive = (buildEnv) => effect$1(
95516
95562
  }),
95517
95563
  deleteDriveEntries: (orgSlug, entryIds) => gen(function* () {
95518
95564
  const token = yield* getAccessToken();
95519
- const path = `/api/web/organizations/slug/${encodeURIComponent(orgSlug)}/drive/entries/delete`;
95565
+ yield* requireReleaseEnabledOperation("deleteCliDriveEntries");
95566
+ const path = `/api/cli/v1/organizations/${encodeURIComponent(orgSlug)}/drive/entries/delete`;
95520
95567
  return yield* makeRequest(baseUrl, path, token, { method: "POST", body: { entryIds } });
95521
95568
  }),
95522
95569
  createDriveFolder: (orgSlug, name) => gen(function* () {
95523
95570
  const token = yield* getAccessToken();
95524
- const path = `/api/web/organizations/slug/${encodeURIComponent(orgSlug)}/drive/entries`;
95571
+ yield* requireReleaseEnabledOperation("createCliDriveFolder");
95572
+ const path = `/api/cli/v1/organizations/${encodeURIComponent(orgSlug)}/drive/folders`;
95525
95573
  return yield* makeRequest(baseUrl, path, token, { method: "POST", body: { name } });
95526
95574
  }),
95527
95575
  renameDriveEntry: (orgSlug, entryId, newName) => gen(function* () {
95528
95576
  const token = yield* getAccessToken();
95529
- const path = `/api/web/organizations/slug/${encodeURIComponent(orgSlug)}/drive/entries/${encodeURIComponent(entryId)}`;
95577
+ yield* requireReleaseEnabledOperation("updateCliDriveEntryName");
95578
+ const path = `/api/cli/v1/organizations/${encodeURIComponent(orgSlug)}/drive/entries/${encodeURIComponent(entryId)}`;
95530
95579
  return yield* makeRequest(baseUrl, path, token, { method: "PATCH", body: { newName } });
95531
95580
  }),
95532
95581
  getDriveUsage: (orgSlug) => gen(function* () {
95533
95582
  const token = yield* getAccessToken();
95534
- const path = `/api/web/organizations/slug/${encodeURIComponent(orgSlug)}/drive/usage`;
95583
+ yield* requireReleaseEnabledOperation("getCliDriveUsage");
95584
+ const path = `/api/cli/v1/organizations/${encodeURIComponent(orgSlug)}/drive/usage`;
95535
95585
  return yield* makeRequest(baseUrl, path, token);
95536
95586
  }),
95537
95587
  listIntegrations: (orgSlug) => gen(function* () {
@@ -95671,16 +95721,37 @@ const makeApiServiceLive = (buildEnv) => effect$1(
95671
95721
  // Built-in skill library
95672
95722
  listBuiltInSkills: (orgSlug, options) => gen(function* () {
95673
95723
  const token = yield* getAccessToken();
95724
+ yield* requireReleaseEnabledOperation("listCliBuiltInSkills");
95674
95725
  const params = new URLSearchParams();
95675
95726
  params.set("limit", String(options?.limit ?? 50));
95676
95727
  if (options?.cursor) params.set("cursor", options.cursor);
95677
95728
  if (options?.search) params.set("search", options.search);
95678
- const path = `/api/web/admin/organizations/slug/${encodeURIComponent(orgSlug)}/skills/built-in-library?${params.toString()}`;
95729
+ const path = `/api/cli/v1/organizations/${encodeURIComponent(orgSlug)}/skills/built-in?${params.toString()}`;
95679
95730
  return yield* makeRequest(baseUrl, path, token);
95680
95731
  }),
95681
95732
  cloneBuiltInSkills: (orgSlug, sourceSkillIds) => gen(function* () {
95682
95733
  const token = yield* getAccessToken();
95683
- const path = `/api/web/admin/organizations/slug/${encodeURIComponent(orgSlug)}/skills/built-in-library/clone`;
95734
+ yield* requireReleaseEnabledOperation("createCliBuiltInSkillClones");
95735
+ const path = `/api/cli/v1/organizations/${encodeURIComponent(orgSlug)}/skills/built-in/clone`;
95736
+ return yield* makeRequest(baseUrl, path, token, {
95737
+ method: "POST",
95738
+ body: { sourceSkillIds }
95739
+ });
95740
+ }),
95741
+ listAdminBuiltInSkills: (orgSlug, options) => gen(function* () {
95742
+ const token = yield* getAccessToken();
95743
+ yield* requireReleaseEnabledOperation("listCliAdminBuiltInSkills");
95744
+ const params = new URLSearchParams();
95745
+ params.set("limit", String(options?.limit ?? 50));
95746
+ if (options?.cursor) params.set("cursor", options.cursor);
95747
+ if (options?.search) params.set("search", options.search);
95748
+ const path = `/api/cli/v1/organizations/${encodeURIComponent(orgSlug)}/admin/skills/built-in?${params.toString()}`;
95749
+ return yield* makeRequest(baseUrl, path, token);
95750
+ }),
95751
+ cloneAdminBuiltInSkills: (orgSlug, sourceSkillIds) => gen(function* () {
95752
+ const token = yield* getAccessToken();
95753
+ yield* requireReleaseEnabledOperation("createCliAdminBuiltInSkillClones");
95754
+ const path = `/api/cli/v1/organizations/${encodeURIComponent(orgSlug)}/admin/skills/built-in/clone`;
95684
95755
  return yield* makeRequest(baseUrl, path, token, {
95685
95756
  method: "POST",
95686
95757
  body: { sourceSkillIds }
@@ -97146,14 +97217,14 @@ const searchOption$3 = text("search").pipe(
97146
97217
  withDescription$3("Search built-in skills by name"),
97147
97218
  optional
97148
97219
  );
97149
- const builtInCommand = make$4(
97220
+ const makeBuiltInCommand = (listSkills = (api, orgSlug, options) => api.listBuiltInSkills(orgSlug, options), description = "List built-in skills from the library") => make$4(
97150
97221
  "built-in",
97151
97222
  { org: orgOption, search: searchOption$3 },
97152
97223
  ({ org, search }) => gen(function* () {
97153
97224
  const api = yield* ApiService;
97154
97225
  const orgSlug = yield* resolveOrgSlug(org, api);
97155
97226
  const searchValue = search._tag === "Some" ? search.value : void 0;
97156
- const result = yield* api.listBuiltInSkills(orgSlug, { search: searchValue }).pipe(
97227
+ const result = yield* listSkills(api, orgSlug, { search: searchValue }).pipe(
97157
97228
  catchTag(
97158
97229
  "NotLoggedInError",
97159
97230
  (e) => gen(function* () {
@@ -97191,7 +97262,8 @@ const builtInCommand = make$4(
97191
97262
  yield* log("(More built-in skills available.)");
97192
97263
  }
97193
97264
  })
97194
- ).pipe(withDescription("List built-in skills from the library"));
97265
+ ).pipe(withDescription(description));
97266
+ const builtInCommand = makeBuiltInCommand();
97195
97267
 
97196
97268
  const MAX_CLONE_SKILLS$1 = 5;
97197
97269
  const formatCloneBuiltInFailureMessage = maskSensitiveText;
@@ -97199,7 +97271,7 @@ const skillIdsArg$1 = text$2({ name: "id" }).pipe(
97199
97271
  withDescription$5(`Built-in skill ID(s) to clone (max ${MAX_CLONE_SKILLS$1})`),
97200
97272
  repeated
97201
97273
  );
97202
- const cloneBuiltInCommand = make$4(
97274
+ const makeCloneBuiltInCommand = (cloneSkills = (api, orgSlug, sourceSkillIds) => api.cloneBuiltInSkills(orgSlug, sourceSkillIds), description = "Clone built-in skills from the library to your organization") => make$4(
97203
97275
  "clone-built-in",
97204
97276
  { skillIds: skillIdsArg$1, org: orgOption },
97205
97277
  ({ skillIds, org }) => gen(function* () {
@@ -97215,7 +97287,7 @@ const cloneBuiltInCommand = make$4(
97215
97287
  return;
97216
97288
  }
97217
97289
  yield* log(`Cloning ${ids.length} built-in skill(s) to organization "${orgSlug}"...`);
97218
- const result = yield* api.cloneBuiltInSkills(orgSlug, ids).pipe(
97290
+ const result = yield* cloneSkills(api, orgSlug, ids).pipe(
97219
97291
  catchTag(
97220
97292
  "NotLoggedInError",
97221
97293
  (e) => gen(function* () {
@@ -97245,7 +97317,8 @@ const cloneBuiltInCommand = make$4(
97245
97317
  }
97246
97318
  }
97247
97319
  })
97248
- ).pipe(withDescription("Clone built-in skills from the library to your organization"));
97320
+ ).pipe(withDescription(description));
97321
+ const cloneBuiltInCommand = makeCloneBuiltInCommand();
97249
97322
 
97250
97323
  const skillIdArg$4 = text$2({ name: "id" }).pipe(withDescription$5("Skill ID to download"));
97251
97324
  const outputOption$2 = text("output").pipe(
@@ -97822,6 +97895,14 @@ const unpublishCommand = make$4(
97822
97895
  yield* log(`Organization skill "${skillId}" was removed from the shared library.`);
97823
97896
  })
97824
97897
  ).pipe(withDescription("Remove an organization skill from the shared library"));
97898
+ const adminBuiltInCommand = makeBuiltInCommand(
97899
+ (api, orgSlug, options) => api.listAdminBuiltInSkills(orgSlug, options),
97900
+ "List built-in skills available to an AI operator"
97901
+ );
97902
+ const adminCloneBuiltInCommand = makeCloneBuiltInCommand(
97903
+ (api, orgSlug, sourceSkillIds) => api.cloneAdminBuiltInSkills(orgSlug, sourceSkillIds),
97904
+ "Clone built-in skills as an AI operator"
97905
+ );
97825
97906
  const adminSkillCommandDescription = "Admin skill management (list, get, upload, download, delete, publish, unpublish, built-in, clone-built-in, github)";
97826
97907
  const adminSkillSubcommands = [
97827
97908
  listCommand$8,
@@ -97831,8 +97912,8 @@ const adminSkillSubcommands = [
97831
97912
  deleteCommand$3,
97832
97913
  publishCommand,
97833
97914
  unpublishCommand,
97834
- builtInCommand,
97835
- cloneBuiltInCommand,
97915
+ adminBuiltInCommand,
97916
+ adminCloneBuiltInCommand,
97836
97917
  githubSkillCommand
97837
97918
  ];
97838
97919
  const adminSkillCommand = make$4("skill", {}).pipe(
@@ -43,10 +43,10 @@
43
43
  | ORG-02 | org | `aipctl org capabilities`, `aipctl org settings`, `aipctl org exit` | `getOrgCapabilities`, `getUserSettings`, `exitOrg` | api | `GET`, `GET`, `POST` | organization v1 `/api/cli/v1/organizations/{organizationSlug}/capabilities`; user-global v1 `/api/cli/v1/me/settings`; legacy `/api/web/organizations/slug/{organizationSlug}/exit` | none | local `OrgCapabilities`, `UserSettings`, `void` | read paths: `resource/oas/modules/backend/cli/openapi.yaml`; exit: `resource/oas/duplo-web.yaml` | read generated `CliOrganizationApi`/`CliV1Api`; exit legacy generated | `legacy-generated` | N/A | `migrate` | owner=`backend`; rationale=`capabilities is organization-owned, settings remains user-global, and exit remains a Wave B mutation`; removal condition=`exit receives its dedicated v1 mutation contract`; incorporation plan=`preserve current membership authorization and non-replay behavior` | task 3.3 | `src/core/api.test.ts` verifies v1 read paths and settings ownership; org tests cover response/error behavior |
44
44
  | P0-ORG-01 | org-member | `aipctl org members`; `aipctl admin org invite`, `aipctl admin org remove-member`, `aipctl admin org update-member-role` | `listOrgMembers`, `inviteOrgMembers`, `removeOrgMembers`, `updateOrgMemberRoles` | api | `GET`, `POST`, `DELETE`, `PUT` | list v1 `/api/cli/v1/organizations/{organizationSlug}/members`; mutations remain legacy `/invite`; `/members` | list uses stable CLI member response; mutation bodies preserve `{ emails, role }` and `{ members, role? }` | local `ListMembersResponse`, `InviteOrgMembersResponse`, `void` | list: `resource/oas/modules/backend/cli/openapi.yaml`; mutation: `resource/oas/duplo-web.yaml` | list generated `CliOrganizationApi`; mutation legacy generated | `legacy-generated` | `P0` | `legacy-exception` | owner=`backend`; rationale=`member read is migrated while admin mutations remain Wave B`; removal condition=`invite/remove/role receive dedicated v1 contracts`; incorporation plan=`reuse current admin authorization, audit, stale target validation, and non-replay semantics` | task 3.3 | `src/core/api.test.ts`, `commands/org/members.test.ts`, `commands/org/org-member.test.ts`; covers v1 member read and legacy mutation bodies |
45
45
  | P0-ORG-02 | org-admin | hidden from public beta (`aipctl admin org invite-link`, `gen-invite-link`, `revoke-invite-link` removed from command tree) | removed from public surface | api | `GET`, `POST`, `DELETE` | previously `/api/web/organizations/slug/{organizationSlug}/invite/link` | none | hidden | latest: `resource/oas/modules/backend/organization/openapi.yaml` (`/invite/link/v2`); legacy: `resource/oas/duplo-web.yaml` (`/invite/link`) | latest `frontend/packages/api/src/out/modules/organization-types.ts#paths["/api/web/organizations/slug/{organizationSlug}/invite/link/v2"]`; legacy `frontend/packages/api/src/out/user-types.ts#paths["/api/web/organizations/slug/{organizationSlug}/invite/link"]` | `oas-source-only` | `P0` | `hide` | owner=`backend organization module`; rationale=`v2 exists but current CLI UX contract for GET/DELETE parity is not approved for public beta`; removal condition=`public beta continues hiding until a reviewed v2 CLI UX contract exists`; incorporation plan=`reintroduce only after independent organization contract/build and public UX review` | N/A | updated admin org help smoke + command-tree regression to ensure trio is absent |
46
- | SKILL-01 | skill | `aipctl skill list`, `aipctl skill get`, `aipctl skill delete` | `listSkills`, `getSkill`, `deleteSkill` | api | `GET`, `GET`, `DELETE` | `/api/web/organizations/slug/{organizationSlug}/skills`; `/skills/{skillId}` | query `{ count,cursor,search }`; detail query `{ maxFiles }` | local `ListSkillsResponse`, `SkillDetail`, `void` | `resource/oas/modules/backend/organization/skills/openapi.yaml` | `frontend/packages/api/src/out/modules/organization-skills-types.ts#paths["/api/web/organizations/slug/{organizationSlug}/skills"]`, `#paths["/api/web/organizations/slug/{organizationSlug}/skills/{skillId}"]` | `generated-ready` | N/A | `keep` | none | N/A | existing `commands/skill/*.test.ts`; needed path/type snapshot once independent generation exists |
46
+ | SKILL-01 | skill | `aipctl skill list`, `aipctl skill get`, `aipctl skill delete` | `listSkills`, `getSkill`, `deleteSkill` | api | `GET`, `GET`, `DELETE` | `/api/cli/v1/organizations/{organizationSlug}/skills`; `/api/cli/v1/organizations/{organizationSlug}/skills/{skillId}` | query `{ count,cursor,search }`; detail query `{ maxFiles }` | local `ListSkillsResponse`, `SkillDetail`, `void` | `resource/oas/modules/backend/cli/openapi.yaml` → `v1_skills*.yaml` (DTO aliases to organization Skills OAS) | `backend/api/.../cli/generated/api/CliSkillApi.kt`; domain DTOs remain `com.querypie.duplo.api.skills.generated.model.*` | `generated-ready` | `P0` | `migrate` | none; `CliSkillApiController` delegates to the existing member authorization/audit controller | `AI-6344` | `src/core/api.test.ts`, `CliSkillDriveApiControllerTest`, Gateway registry/contract parity; production CLI and local 403/404 checks (401/429 remain common gates) |
47
47
  | SKILL-02 | skill | `aipctl skill upload` | `createUploadUrl` → `uploadToS3` → `completeUpload` (`abortUpload` on failure) | api + external | `POST` → `PUT` → `POST` | `/skills/upload-url`; external presigned `uploadUrl`; `/skills/{skillId}/complete` | local upload request `{ filename,fileSize,mimeType }`, file buffer, complete body `{ overwrite }` | `CreateSkillUploadUrlResponse`, external `void`, `CompleteSkillUploadResponse` | `resource/oas/modules/backend/organization/skills/openapi.yaml` | `frontend/packages/api/src/out/modules/organization-skills-types.ts#paths["/api/web/organizations/slug/{organizationSlug}/skills/upload-url"]`, `#paths["/api/web/organizations/slug/{organizationSlug}/skills/{skillId}/complete"]` | `external-presigned` | N/A | `keep` | none | N/A | existing skill upload tests; needed presigned URL + complete path snapshot |
48
- | SKILL-03 | skill | `aipctl skill library`, `aipctl skill clone`, `aipctl skill built-in`, `aipctl skill clone-built-in`; `aipctl admin skill built-in`, `aipctl admin skill clone-built-in` | `listLibrarySkills`, `cloneSkills`, `listBuiltInSkills`, `cloneBuiltInSkills` | api | `GET`, `POST`, `GET`, `POST` | `/skills/library`; `/skills/library/clone`; `/admin/.../skills/built-in-library`; `/built-in-library/clone` | list query `{ count,cursor,search/limit }`; clone body `{ sourceSkillIds[] }` | local list/clone DTOs | `resource/oas/modules/backend/organization/skills/openapi.yaml` | `frontend/packages/api/src/out/modules/organization-skills-types.ts#paths["/api/web/organizations/slug/{organizationSlug}/skills/library"]`, `#paths["/api/web/organizations/slug/{organizationSlug}/skills/library/clone"]`, `#paths["/api/web/admin/organizations/slug/{organizationSlug}/skills/built-in-library"]`, `#paths["/api/web/admin/organizations/slug/{organizationSlug}/skills/built-in-library/clone"]` | `generated-ready` | N/A | `keep` | none | N/A | existing skill extended tests; needed built-in/library path snapshot |
49
- | SKILL-04 | skill-admin | `aipctl admin skill list`, `get`, `delete`, `publish`, `unpublish` | `listAdminSkills`, `getAdminSkill`, `deleteAdminSkill`, `updateAdminSkill` | api | `GET`, `GET`, `DELETE`, `PATCH` | `/api/web/admin/organizations/slug/{organizationSlug}/skills`; `/skills/{skillId}` | list query `{ pageNumber,pageSize,search }`; publish toggle body `{ availableInLibrary: boolean }` | local `ListAdminSkillsResponse`, `SkillDetail`, `void` | `resource/oas/modules/backend/organization/skills/openapi.yaml` | `frontend/packages/api/src/out/modules/organization-skills-types.ts#paths["/api/web/admin/organizations/slug/{organizationSlug}/skills"]`, `#paths["/api/web/admin/organizations/slug/{organizationSlug}/skills/{skillId}"]` | `generated-ready` | N/A | `keep` | none | N/A | existing `commands/admin/skill.test.ts`; needed admin list/detail/update path snapshot |
48
+ | SKILL-03 | skill | `aipctl skill library`, `aipctl skill clone`, `aipctl skill built-in`, `aipctl skill clone-built-in`; `aipctl admin skill built-in`, `aipctl admin skill clone-built-in` | `listLibrarySkills`, `cloneSkills`, `listBuiltInSkills`, `cloneBuiltInSkills`, `listAdminBuiltInSkills`, `cloneAdminBuiltInSkills` | api | `GET`, `POST`, `GET`, `POST`, `GET`, `POST` | `/api/cli/v1/organizations/{organizationSlug}/skills/library`; `/skills/library/clone`; `/skills/built-in`; `/skills/built-in/clone`; `/admin/skills/built-in`; `/admin/skills/built-in/clone` | list query `{ count,cursor,search/limit }`; clone body `{ sourceSkillIds[] }` | local list/clone DTOs | `resource/oas/modules/backend/cli/openapi.yaml` → `v1_skills_library*`, `v1_skills_built-in*`, `v1_admin_skills_built-in*` (aliases to organization Skills OAS) | `backend/api/.../cli/generated/api/CliSkillApi.kt`; domain DTOs remain `com.querypie.duplo.api.skills.generated.model.*` | `generated-ready` | `P0` | `migrate` | none; built-in execution reuses the existing AI-operator authorization owner while CLI API methods preserve general/admin operation identity | `AI-6344` | existing skill extended/admin tests, API path tests, adapter test, Gateway registry/contract parity and production CLI clone/list checks |
49
+ | SKILL-04 | skill-admin | `aipctl admin skill list`, `get`, `delete`, `publish`, `unpublish` | `listAdminSkills`, `getAdminSkill`, `deleteAdminSkill`, `updateAdminSkill` | api | `GET`, `GET`, `DELETE`, `PATCH` | `/api/cli/v1/organizations/{organizationSlug}/admin/skills`; `/admin/skills/{skillId}` | list query `{ pageNumber,pageSize,search }`; publish toggle body `{ availableInLibrary: boolean }` | local `ListAdminSkillsResponse`, `SkillDetail`, `void` | `resource/oas/modules/backend/cli/openapi.yaml` → `v1_admin_skills*.yaml` (DTO aliases to organization Skills OAS) | `backend/api/.../cli/generated/api/CliSkillApi.kt`; domain DTOs remain `com.querypie.duplo.api.skills.generated.model.*` | `generated-ready` | `P0` | `migrate` | none; `CliSkillApiController` delegates AI-operator authorization, workflow and audit owner | `AI-6344` | existing `commands/admin/skill.test.ts`, adapter test, Gateway parity; production admin list/publish/delete and 403/429 checks |
50
50
  | SKILL-05 | skill-admin | `aipctl skill download`; `aipctl admin skill upload`, `aipctl admin skill download`, `aipctl admin skill github inspect/import/sync/credentials set/clear` | `createAdminUploadUrl` → `uploadToS3` → `completeAdminUpload` (`abortAdminUpload` on failure); `getSkillDownloadUrl` → `downloadFromUrl`; `inspectGitHubSkillSource`, `prepareGitHubSkill`, `syncPrepareGitHubSkill`, `updateGitHubSkillCredentials` | api + external | `POST`/`PUT`/`POST`; `POST`/`GET`; `POST`, `POST`, `POST`, `PATCH` | `/admin/.../skills/upload-url`; `/admin/.../skills/download-url`; `/admin/.../skills/github-repo-inspect`; `/github-prepare`; `/{skillId}/sync-prepare`; `/{skillId}/github-credentials` | upload/download local bodies; GitHub inspect/prepare `{ url, pat? }`; credentials `{ pat or null }` | upload/download/GitHub admin skill DTOs | `resource/oas/modules/backend/organization/skills/openapi.yaml` | `frontend/packages/api/src/out/modules/organization-skills-types.ts#paths["/api/web/admin/organizations/slug/{organizationSlug}/skills/upload-url"]`, `#paths["/api/web/admin/organizations/slug/{organizationSlug}/skills/download-url"]`, `#paths["/api/web/admin/organizations/slug/{organizationSlug}/skills/github-repo-inspect"]`, `#paths["/api/web/admin/organizations/slug/{organizationSlug}/skills/github-prepare"]`, `#paths["/api/web/admin/organizations/slug/{organizationSlug}/skills/{skillId}/sync-prepare"]`, `#paths["/api/web/admin/organizations/slug/{organizationSlug}/skills/{skillId}/github-credentials"]` | `external-presigned` | N/A | `keep` | none | N/A | existing `commands/admin/skill.test.ts`, `commands/skill/skill-extended.test.ts`; needed GitHub admin skill contract fixtures |
51
51
  | P1-SKILL-01 | skill-docs | `aipctl skill get --json`, `aipctl admin skill get --json`, `aipctl admin skill github import/sync --json` | same owners as `SKILL-01`/`SKILL-05` | api | same as upstream rows | same as upstream rows | runtime/JSON/help/docs now align on `source`, `origin`, `updateAvailable`, `secretsAvailable`, GitHub metadata, `secretKeys`; stale `version` and file `size` removed | JSON/help/docs contract for skill objects | `resource/oas/modules/backend/organization/skills/openapi.yaml` | `frontend/packages/api/src/out/modules/organization-skills-types.ts#components[...]` | `generated-ready` | `P1` | `keep` | none | N/A | updated `src/core/api.test.ts`, `commands/skill/skill.test.ts`, `commands/skill/skill-extended.test.ts`, `commands/admin/skill.test.ts`, `commands/json-format.test.ts`, `../docs/how-to/aip-cli-usage.md`; covers JSON/help/docs field sync |
52
52
  | P0-AGENT-01 | agent-user | `aipctl agent list`, `aipctl agent get` | `listInstalledAgents`, `getInstalledAgent` | api | `GET`, `GET` | `/api/cli/v1/organizations/{organizationSlug}/agents`; `/{installedAgentId}` | preserves user read semantics and maps `list`/`installedAgentId` to local `data`/`id` | local `ListInstalledAgentsResponse`, `{ data: InstalledAgentDetail }` | `resource/oas/modules/backend/cli/openapi.yaml`; shared DTO refs from `resource/oas/duplo.yaml` | `backend/api/.../cli/generated/api/CliAgentApi.kt` | `generated-ready` | `P0` | `migrate` | none; dedicated adapter delegates to the working `AgentsApiController` bean | `AI-6344` | `src/core/api.test.ts`, `CliAgentApiControllerTest`, Gateway registry/admission parity; real local production CLI list/get JSON |
@@ -55,7 +55,7 @@
55
55
  | P1-CHAT-01 | agent-chat | `aipctl agent chat` | `agentNewChat`, `agentChat`, local `parseSseStream` | chat | `POST` + SSE | `/librechat/api/{orgSlug}/agent/new-chat`; `/librechat/api/{orgSlug}/agent/chat` | request body `{ agentInstallationId or conversationId, text, files: [] }` | local `AgentChatResult { text, conversationId }` parsed from SSE event fields `final`, `conversation.conversationId`, `responseMessage` | path source: `resource/oas/chat.yaml` | `frontend/packages/api/src/out/chat-types.ts#paths["/librechat/api/{orgSlug}/agent/new-chat"]`, `#paths["/librechat/api/{orgSlug}/agent/chat"]` | `stream-exception` | `P1` | `legacy-exception` | owner=`chat backend agent SSE stream contract`; rationale=`path exists in OpenAPI but final SSE event payload is still out-of-band`; removal condition=`official SSE event schema or versioned fixture is published with the chat contract`; incorporation plan=`bind CLI parser/tests to the published SSE fixture and drop local-only stream assumptions` | N/A | updated `src/core/api.test.ts`; covers content[] text, fallback text, malformed event skip, and no-final-event failure |
56
56
  | P1-AUTO-01 | automation | `aipctl automation list`, `get`, `create`, `update`, `delete`, `run`, `enable`, `disable`, `history`, `cancel`, `webhook-regen`, `triggers` | `listAutomations`, `getAutomation`, `createAutomation`, `updateAutomation`, `deleteAutomation`, `runAutomation`, `updateAutomationStatus`, `listAutomationHistories`, `cancelAutomationHistory`, `regenerateWebhookUrl`, `getTriggerProviderMetadata` | api | `GET`, `POST`, `PUT`, `DELETE` mix | `/api/web/organizations/slug/{organizationSlug}/automations...`; `/automation-trigger-providers/.../metadata` | automation pagination normalized to `{ page, pageSize, total }`; metadata calls now use provider-specific OAS paths and required args (`accountId`, `folderId`, `serviceType`) | local automation DTOs + webhook URL DTO | `resource/oas/modules/backend/automation/user/openapi.yaml` | `frontend/packages/api/src/out/modules/automation-user-types.ts#paths[...]` | `generated-ready` | `P1` | `keep` | none | N/A | updated `src/core/api.test.ts`, `commands/automation/automation.test.ts`, `commands/json-format.test.ts`; covers official pagination fields, provider-specific metadata routes, and unsupported-provider preflight failure |
57
57
  | CHAT-01 | chat-readonly | `aipctl chat list`, `aipctl chat get`, `aipctl chat messages` | `listConversations`, `getConversation`, `listMessages` | chat | `GET` | `/librechat/api/{orgSlug}/convos`; `/convos/{conversationId}`; `/messages/{conversationId}` | list sends no default query; optional cursor only (`?cursor=...`). `pageSize`/`sortBy`/`sortDirection` defaults removed due deployed Chat validation drift | local `ListConversationsResponse`, `ConversationDetail`, `ChatMessage[]` | `resource/oas/chat.yaml` | `frontend/packages/api/src/out/chat-types.ts#paths["/librechat/api/{orgSlug}/convos"]`, `#paths["/librechat/api/{orgSlug}/convos/{conversationId}"]`, `#paths["/librechat/api/{orgSlug}/messages/{conversationId}"]` | `legacy-generated` | N/A | `keep` | owner=`chat backend`; rationale=`PROD rejects CLI default pageSize/sort query while no-query and cursor-only read path are safe`; removal condition=`chat deployed contract publishes and accepts explicit pagination query for public CLI`; incorporation plan=`reintroduce explicit pagination only after OAS/source/deployed validation align` | N/A | updated `src/core/api.test.ts`, existing `commands/chat/chat.test.ts`; covers default no-query and cursor-only URL |
58
- | P0-DRIVE-01 | drive | `aipctl drive list`, `download`, `delete`, `mkdir`, `rename`, `usage` | `listDriveEntries`, `getDriveDownloadUrl`, `deleteDriveEntries`, `createDriveFolder`, `renameDriveEntry`, `getDriveUsage`, `downloadFromUrl` | api + external | `GET`, `POST`, `POST`, `POST`, `PATCH`, `GET`, external `GET` | `/drive/entries?count=200`; `/drive/entries/download-url`; `/drive/entries/delete`; `/drive/entries/{entryId}`; `/drive/usage` | official list `{ path, hasNext, nextCursor, items }`; delete body `{ entryIds[] }`; rename body `{ newName }`; download body `{ entryIds: [id] }` | official drive list/download DTOs + external file buffer | `resource/oas/modules/backend/organization/storage/openapi.yaml` | `frontend/packages/api/src/out/modules/organization-storage-types.ts#paths["/api/web/organizations/slug/{organizationSlug}/drive/entries"]`, `#paths["/api/web/organizations/slug/{organizationSlug}/drive/entries/download-url"]`, `#paths["/api/web/organizations/slug/{organizationSlug}/drive/entries/{entryId}"]`, `#paths["/api/web/organizations/slug/{organizationSlug}/drive/entries/delete"]`, `#paths["/api/web/organizations/slug/{organizationSlug}/drive/usage"]` | `generated-ready` | `P0` | `migrate` | none | `AIP-PUB-05` | updated `src/core/api.test.ts`, `commands/drive/drive.test.ts`; covers paged list shape, batch download-url request, DTO field rename (`sizeBytes`, `modifiedAt`) |
58
+ | P0-DRIVE-01 | drive | `aipctl drive list`, `download`, `delete`, `mkdir`, `rename`, `usage` | `listDriveEntries`, `getDriveDownloadUrl`, `deleteDriveEntries`, `createDriveFolder`, `renameDriveEntry`, `getDriveUsage`, `downloadFromUrl` | api + external | `GET`, `POST`, `POST`, `POST`, `PATCH`, `GET`, external `GET` | CLI-managed basic CRUD: `/api/cli/v1/organizations/{organizationSlug}/drive/entries?count=200`, `/drive/entries/delete`, `/drive/folders`, `/drive/entries/{entryId}`, `/drive/usage`; download/upload remain Web/presigned | official list `{ path, hasNext, nextCursor, items }`; delete body `{ entryIds[] }`; mkdir optional `parentId`; rename body `{ newName }`; download body `{ entryIds: [id] }` | official drive list/download DTOs + external file buffer | `resource/oas/modules/backend/cli/openapi.yaml` → `v1_drive_*.yaml` (DTO aliases to organization Storage OAS); download/upload remain `resource/oas/modules/backend/organization/storage/openapi.yaml` | `backend/api/.../cli/generated/api/CliDriveApi.kt`; domain DTOs remain `com.querypie.duplo.api.drive.controller.generated.model.*` | `generated-ready` | `P0` | `migrate` | none; `CliDriveApiController` delegates membership, capacity and audit owner | `AI-6344` | `src/core/api.test.ts`, `CliSkillDriveApiControllerTest`, Gateway registry/contract parity; production CRUD/usage and local 403/404 checks (401/429 remain common gates) |
59
59
  | P0-DRIVE-02 | drive | `aipctl drive upload` | `createDriveUploadUrl` → `uploadToS3` → `completeDriveUpload` | api + external | `POST` → `PUT` → `POST` | `/drive/entries/upload-url`; external presigned `uploadUrl`; `/drive/entries/{entryId}/complete` | official upload request `{ parentId: null, filename, fileSize, mimeType }` | official `CreateDriveUploadUrlResponse { id, filename, uploadUrl, headers }` then `void` | `resource/oas/modules/backend/organization/storage/openapi.yaml` | `frontend/packages/api/src/out/modules/organization-storage-types.ts#paths["/api/web/organizations/slug/{organizationSlug}/drive/entries/upload-url"]`, `#paths["/api/web/organizations/slug/{organizationSlug}/drive/entries/{entryId}/complete"]` | `generated-ready` | `P0` | `migrate` | none | `AIP-PUB-05` | updated `src/core/api.test.ts`, `commands/drive/drive.test.ts`; covers `parentId: null` request and response `id`/`filename` usage |
60
60
  | P1-INT-01 | integration | `aipctl integration list`, `test`; `aipctl admin integration get`, `update`, `delete`, `tools`, `available` | `listIntegrations`, `testIntegration`, `getIntegration`, `updateIntegration`, `deleteIntegration`, `listIntegrationTools`, `listConfigurableIntegrations` | api | `GET`, `POST`, `GET`, `PUT`, `DELETE`, `GET`, `GET` | `/api/web/integrations/v2`; `/api/web/integration/{integrationId}/test`; `/api/web/admin/organizations/slug/{organizationSlug}/integrations/{integrationId}`; `/{integrationId}/tools`; `/configurable-integrations` | top-level list/test and admin detail/available now follow current/legacy OAS path+body+DTO where available; admin update/delete still accept untyped legacy mutation body/path until admin mutation contract lands | local `Integration`, `IntegrationDetail`, `IntegrationToolsResponse`, `ConfigurableIntegration[]` | legacy admin paths: `resource/oas/duplo-web.yaml`; partial modern source: `resource/oas/modules/backend/integration/openapi.yaml` (does not cover these admin list/CRUD/tools paths) | legacy `frontend/packages/api/src/out/user-types.ts#paths["/api/web/admin/organizations/slug/{organizationSlug}/integrations"]`, `#paths["/api/web/admin/organizations/slug/{organizationSlug}/configurable-integrations"]`; partial current `frontend/packages/api/src/out/modules/integration-types.ts` lacks these admin list/CRUD/tools paths | `legacy-generated` | `P1` | `legacy-exception` | owner=`backend app Integrations / duplo-web legacy OAS`; rationale=`public beta keeps integration list/test/admin detail/tools/available, but admin update/delete still lack an approved current contract outside legacy duplo-web`; removal condition=`independent contract covers user list/test plus admin CRUD/tools/available`; incorporation plan=`extend integration module or independent contract for list/test/admin CRUD/tools/available, then retire legacy path/body mappings and delete/update exception` | N/A | updated `src/core/api.test.ts`, `commands/integration/integration.test.ts`; covers v2 list query, test body `{ organizationSlug }`, admin detail/tools DTO fields, configurable wrapper unwrap, and pinned update/delete legacy paths |
61
61
  | P0-MODEL-01 | model | `aipctl model list` | `listModels` | chat | `GET` | `/api/cli/v1/organizations/{orgSlug}/models` | none | `{ models: string[], defaultModel? }` is mapped into `Model[]` and preserves active standard, custom/BYOK, and `etc` catalog IDs | code-first OAS: `chat/packages/chat/src/modules/cli-model-exec/interface/cli-model-exec-v1.interface.controller.ts` | runtime Swagger contract; the existing Web model endpoint remains an independent compatibility reference | `oas-source-only` | `P0` | `migrate` | owner=`Chat CliModelExecV1InterfaceController/ModelInternalService`; rationale=`the dedicated route reuses the existing organization-authorized model domain catalog instead of the narrowed model-exec SharedModel catalog`; removal condition=`none for the CLI route; Web migration is a separate work item`; incorporation plan=`keep the CLI path and capability/registry parity tests aligned with the code-first Chat contract` | `AIP-PUB-05` | `src/core/api.test.ts` verifies the dedicated path, production capability gate, default mapping, and preservation of custom/BYOK and `etc` IDs; Chat service/controller tests verify domain delegation and Swagger extensions |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aipctl",
3
- "version": "2026.9.9",
3
+ "version": "2026.9.10",
4
4
  "description": "QueryPie AIP and MCP CLI tool",
5
5
  "author": "QueryPie",
6
6
  "license": "UNLICENSED",
@@ -22,8 +22,8 @@
22
22
  "node": ">=24.18.0"
23
23
  },
24
24
  "metadata": {
25
- "contentHash": "95bfb896d5e0e21910685b39eff86f3d35ee5c1b0ef28854912f78fdbc7bee58",
26
- "wrapperHash": "a4ef2565f44cb9eb4a3706246f59427bf40a5275dc7bea030fb30024be6f5ab8",
25
+ "contentHash": "347543a4b224c8b9c8ff935b76027e974cb8b4fe60194c8fa521914f08fd4547",
26
+ "wrapperHash": "78654f7e6577f5ff63efac889f31483bdd5bcd6f34f474784fd356a89dc46bdf",
27
27
  "nativeHash": "006b08c3e391f4571d9b7c0f12d684fe2448106259e7e0581b10f9be362452e9"
28
28
  },
29
29
  "optionalDependencies": {