aipctl 2026.6.2 → 2026.6.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dispatcher.cjs +17 -0
- package/main.cjs +23 -0
- package/package.json +23 -22
- package/README.md +0 -60
- package/build/index.cjs +0 -100071
- package/docs/api-contract-inventory.md +0 -91
- package/docs/architecture.md +0 -75
- package/docs/desktop-cli-go-coding-guidelines.md +0 -22
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
# AIP CLI API contract inventory
|
|
2
|
-
|
|
3
|
-
## 목적
|
|
4
|
-
|
|
5
|
-
`desktop/packages/cli` public command가 어떤 network contract를 호출하는지 한 곳에 묶는다. 이 문서는 AIP-PUB-04/PUB-05 실행 입력이다.
|
|
6
|
-
|
|
7
|
-
## Source of truth policy
|
|
8
|
-
|
|
9
|
-
- Path 기준: OAS/generated/doc path는 repo-root 기준입니다. `src/...`는 `desktop/packages/cli/src/...` package-relative shorthand입니다.
|
|
10
|
-
- Runtime source of truth → `desktop/packages/cli/src/index.ts`, `src/commands/**`, `src/core/api.ts`, `src/core/oauth.ts`.
|
|
11
|
-
- Contract source of truth 우선순위 → current OAS source (`resource/oas/**`) → package-local DTO/parser (`src/core/api.ts`, `src/core/oauth.ts`) → generated reference path recorded in this inventory.
|
|
12
|
-
- CLI source/build/test/lint는 frontend `packages/*` workspace package에 의존하지 않는다. Runtime fetch/client는 계속 `src/core/api.ts`가 소유한다.
|
|
13
|
-
- Public beta policy → public command는 이 inventory에 network owner, path, DTO source, regression test를 함께 기록한다.
|
|
14
|
-
- Generated reference path는 contract 추적용 링크이며 CLI package dependency가 아니다.
|
|
15
|
-
|
|
16
|
-
## Status legend
|
|
17
|
-
|
|
18
|
-
- `generated-ready` → current OAS module + generated reference가 있고 CLI path/DTO가 맞음
|
|
19
|
-
- `oas-source-only` → current OAS source는 있으나 current generated output file/config가 tree에 없음
|
|
20
|
-
- `legacy-generated` → current module output 대신 legacy/top-level generated reference만 있음
|
|
21
|
-
- `mismatch` → CLI path/method/DTO가 최신 OAS/generated reference와 다름
|
|
22
|
-
- `oas-missing` → 대응 OAS path를 못 찾음
|
|
23
|
-
- `stream-exception` → endpoint path는 있으나 stream event contract를 CLI가 local parse 함
|
|
24
|
-
- `external-presigned` → first-party API 뒤에 presigned external URL 사용
|
|
25
|
-
- `local-only` → network 없음
|
|
26
|
-
|
|
27
|
-
## Excluded local-only commands
|
|
28
|
-
|
|
29
|
-
| Public command(s) | Reason | Status |
|
|
30
|
-
| --- | --- | --- |
|
|
31
|
-
| `aipctl config set`, `aipctl config status` | local config read/write only | `local-only` |
|
|
32
|
-
| `aipctl auth logout`, `aipctl auth status` | credential file/session inspection only | `local-only` |
|
|
33
|
-
| `aipctl org current` | selected org from local config only | `local-only` |
|
|
34
|
-
|
|
35
|
-
## Inventory
|
|
36
|
-
|
|
37
|
-
| ID | Domain | Public command(s) | ApiService method / non-ApiService network owner | Base service | HTTP method | CLI path | Request DTO / local shape | Response DTO / local shape | OAS source file | Generated reference file/export | Status | Priority | Public beta action | Legacy exception: owner, rationale, removal condition, contract incorporation plan | Follow-up task | Existing / needed regression test |
|
|
38
|
-
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
|
|
39
|
-
| AUTH-01 | auth | `aipctl auth login` | `src/core/oauth.ts`: `discoverOAuthMetadata` → `registerCliOAuthClient` → `exchangeAuthorizationCode` | api + external browser | `GET /.well-known` → `POST /oauth2/register` → browser `GET /oauth2/authorize` → `POST /oauth2/token` | `/.well-known/oauth-authorization-server`, `/oauth2/register`, `/oauth2/authorize`, `/oauth2/token` | PKCE state/challenge, dynamic client registration body, auth code exchange form | `OAuthMetadata`, `OAuthClientRegistration`, `OAuthTokenResponse` → local `Credentials` | not found in current `resource/oas` for `oauth-authorization-server` / `/oauth2/register` / `/oauth2/token` | none | `oas-missing` | N/A | `legacy-exception` | owner=`backend/api OAuth server`; rationale=`login is required public auth flow but OAuth authorization-server/DCR/token contract is not in current OAS`; removal condition=`official OAuth server contract exists in resource/oas and independent generated contract`; incorporation plan=`add OAuth server metadata/register/token paths or dedicated auth contract fixture, then bind CLI parser/tests` | `AIP-PUB-05` | existing auth tests cover login helpers; needed contract snapshot for OAuth metadata/register/token paths |
|
|
40
|
-
| AUTH-02 | auth | `aipctl auth refresh` | `ApiService.refreshToken` → `refreshAccessToken` → `src/core/oauth.ts#refreshOAuthToken` | api | `POST` | `/oauth2/token` | refresh token form body | refreshed local `Credentials` | not found in current `resource/oas` for `/oauth2/token` | none | `oas-missing` | N/A | `legacy-exception` | owner=`backend/api OAuth server`; rationale=`token refresh is required for session continuity but token endpoint is outside current OAS`; removal condition=`official OAuth token contract exists in resource/oas and independent generated contract`; incorporation plan=`same OAuth server contract as AUTH-01, plus refresh fixture` | `AIP-PUB-05` | existing `src/core/oauth.test.ts`, `src/core/api.test.ts`; needed token refresh path snapshot |
|
|
41
|
-
| AUTH-03 | auth | `aipctl auth whoami` | `ApiService.getMe` | api | `GET` | `/api/web/me` | none | local `UserProfile` | `resource/oas/duplo-web.yaml` | `frontend/packages/api/src/out/user-types.ts#paths["/api/web/me"]` | `legacy-generated` | N/A | `keep` | none | N/A | existing `commands/auth/auth.test.ts`; needed user-types ref note only |
|
|
42
|
-
| ORG-01 | org | `aipctl org list`, `aipctl org use` | `listOrganizations`, `getOrganization` | api | `GET` | `/api/web/organizations`; CLI `use` filters locally by slug after list call | none | local `Organization[]` / `Organization` | `resource/oas/duplo-web.yaml` | `frontend/packages/api/src/out/user-types.ts#paths["/api/web/organizations"]`, `#paths["/api/web/organizations/slug/{organizationSlug}"]` | `legacy-generated` | N/A | `keep` | none | N/A | existing `commands/org/org.test.ts`; needed slug lookup contract snapshot |
|
|
43
|
-
| ORG-02 | org | `aipctl org capabilities`, `aipctl org settings`, `aipctl org exit` | `getOrgCapabilities`, `getUserSettings`, `exitOrg` | api | `GET`, `GET`, `POST` | `/api/web/organizations/slug/{organizationSlug}/capabilities`; `/api/web/user/settings`; `/api/web/organizations/slug/{organizationSlug}/exit` | none | local `OrgCapabilities`, `UserSettings`, `void` | capabilities: `resource/oas/modules/backend/organization/openapi.yaml`; settings/exit: `resource/oas/duplo-web.yaml` | capabilities `frontend/packages/api/src/out/modules/organization-types.ts#paths["/api/web/organizations/slug/{organizationSlug}/capabilities"]`; settings/exit legacy `frontend/packages/api/src/out/user-types.ts#paths[...]` | `legacy-generated` | N/A | `keep` | none | N/A | existing org tests partial; needed capability/settings/exit smoke coverage |
|
|
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` | `/api/web/organizations/slug/{organizationSlug}/members/detail`; `/invite`; `/members` | list uses detail status shape; invite body `{ emails, role: 'owner' | 'admin' | 'aiOperator' | 'member' }`; remove/update bodies `{ members: [{ email, status, userId? }] }` + update `role` | local `ListMembersResponse`, `InviteOrgMembersResponse`, `void`; mutation commands preload `listOrgMembers` for selection UX | latest role enum source: `resource/oas/modules/backend/_/components/schemas/OrganizationRoleEnum.yaml`; member status source: `resource/oas/modules/backend/organization/openapi.yaml`; legacy member list/mutation paths: `resource/oas/duplo-web.yaml` | latest refs: `frontend/packages/api/src/out/modules/backend-common-types.ts#OrganizationRoleEnum`, `frontend/packages/api/src/out/modules/organization-types.ts#paths["/api/web/organizations/slug/{organizationSlug}/members/status"]`; legacy refs: `frontend/packages/api/src/out/user-types.ts#paths["/api/web/organizations/slug/{organizationSlug}/invite"]`, `#paths["/api/web/organizations/slug/{organizationSlug}/members"]`, `#paths["/api/web/organizations/slug/{organizationSlug}/members/detail"]` | `legacy-generated` | `P0` | `legacy-exception` | owner=`backend app Organization API / duplo-web legacy OAS`; rationale=`public member list/admin flow kept for beta; role/status now align with current enum/status source while invite/remove/update still rely on legacy duplo-web member mutation contract`; removal condition=`independent contract includes member detail list plus invite/remove/update member mutations`; incorporation plan=`add resource/oas-based organization member admin contract, then remove legacy duplo-web refs and local fallback mapping` | `AIP-PUB-05` | updated `src/core/api.test.ts`, `commands/org/members.test.ts`, `commands/org/org-member.test.ts`; covers detail path, lower-case role enum, failedInvitations, member mutation body |
|
|
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 |
|
|
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 |
|
|
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
|
-
| 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
|
-
| P0-AGENT-01 | agent-user | `aipctl agent list`, `aipctl agent get` | `listInstalledAgents`, `getInstalledAgent` | api | `GET`, `GET` | `/api/web/organizations/slug/{organizationSlug}/installed-agents`; `/installed-agents/{installedAgentId}` | legacy implemented endpoint maps `list`/`installedAgentId` into CLI `data`/`id`; detail wraps legacy response in `{ data }` and maps `installedIntegrationList` fallback | local `ListInstalledAgentsResponse`, `{ data: InstalledAgentDetail }` | implemented: `resource/oas/duplo.yaml`; future v2 source: `resource/oas/modules/backend/agent/user/openapi.yaml` | legacy `frontend/packages/api/src/out/user-types.ts#paths["/api/web/organizations/slug/{organizationSlug}/installed-agents"]`, `#paths["/api/web/organizations/slug/{organizationSlug}/installed-agents/{installedAgentId}"]` | `legacy-generated` | `P0` | `keep legacy` | owner=`backend app AgentsApiController`; rationale=`agent v2 controllers currently throw NotImplementedError in this repo, so public beta must call implemented legacy endpoints`; removal condition=`AgentUserApiController v2 methods are implemented and deployed`; incorporation plan=`switch to agent v2 OAS/generated contract only after backend implementation lands` | `AIP-PUB-05` | updated `src/core/api.test.ts`, `commands/agent/agent.test.ts`; covers implemented legacy list/detail path and response mapping |
|
|
53
|
-
| P0-AGENT-02 | agent-admin | `aipctl admin agent create`, `update`, `delete`, `export`, `share`, `templates`; `aipctl agent enable`, `disable` | `createInstalledAgent`, `updateInstalledAgent`, `deleteInstalledAgent`, `exportInstalledAgent`, `getInstalledAgentShare`, `listAgentTemplates`, `updateInstalledAgentStatus` | api | `POST`, `PATCH`, `DELETE`, `GET`, `GET`, `GET`, `PATCH` | `/api/web/admin/organizations/slug/{organizationSlug}/installed-agents`; `/{installedAgentId}`; `/export`; `/share`; `/agents`; `/{installedAgentId}/status` | create/update bodies follow implemented legacy admin request (`custom.iconKeyOrUrl`, `knowledgeBundleIdList`); templates map legacy `agentId`/`label`/`categoryList`; status body `{ status }` | create/update return plain `{ id }`; local admin agent DTOs + `Buffer` export | implemented: `resource/oas/duplo.yaml`; future v2 source: `resource/oas/modules/backend/agent/admin/openapi.yaml` | legacy `frontend/packages/api/src/out/user-types.ts#paths["/api/web/admin/organizations/slug/{organizationSlug}/installed-agents"]`, `#paths["/api/web/admin/organizations/slug/{organizationSlug}/installed-agents/{installedAgentId}"]`, `#paths["/api/web/admin/organizations/slug/{organizationSlug}/agents"]` | `legacy-generated` | `P0` | `keep legacy` | owner=`backend app AgentsApiController`; rationale=`agent v2 admin controllers currently throw NotImplementedError in this repo, so public beta must call implemented legacy endpoints`; removal condition=`AgentAdminApiController v2 methods are implemented and deployed`; incorporation plan=`switch to agent v2 OAS/generated contract only after backend implementation lands` | `AIP-PUB-05` | updated `src/core/api.test.ts`, `commands/agent/agent.test.ts`; covers implemented legacy CRUD/status/template path/body and plain response mapping |
|
|
54
|
-
| 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 |
|
|
55
|
-
| 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 |
|
|
56
|
-
| 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 query `{ cursor,pageSize,sortBy,sortDirection }` | 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` | none | N/A | existing `commands/chat/chat.test.ts`; needed independent chat contract generation later |
|
|
57
|
-
| 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-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 |
|
|
59
|
-
| 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 |
|
|
60
|
-
| P0-MODEL-01 | model | `aipctl model list` | `listModels` | chat | `GET` | `/api/{orgSlug}/models` | none | CLI maps official `{ models: string[], defaultModel? }` into `Model[]` with optional `isDefault` | `resource/oas/chat.yaml` | `frontend/packages/api/src/out/chat-types.ts#paths["/api/{orgSlug}/models"]` | `legacy-generated` | `P0` | `migrate` | none | `AIP-PUB-05` | updated `src/core/api.test.ts`, `commands/model/model.test.ts`; covers official path and string-array response mapping |
|
|
61
|
-
| USAGE-01 | usage | `aipctl admin usage credit`, `top-users`, `daily-graph`, `daily-users`, `mcp-top` | `getCreditStatistics`, `getCreditTopUsers`, `getCreditDailyGraph`, `getCreditDailyUsers`, `getMcpTopTools` | api | `GET` | `/api/web/admin/organizations/slug/{organizationSlug}/usage/...` | query `{ startDt,endDt,limit,pageNumber,pageSize,userId }` | local usage DTOs, `DailyUsageDetailsResponse.pagination { page,pageSize,total }` | `resource/oas/modules/backend/usage/openapi.yaml` | `frontend/packages/api/src/out/modules/usage-types.ts#paths[...]` | `generated-ready` | N/A | `keep` | none | N/A | existing `commands/usage/usage.test.ts`; needed generated path snapshots |
|
|
62
|
-
| AUDIT-01 | audit | `aipctl admin audit list`, `types` | `listAuditLogs`, `listAuditEventTypes` | api | `GET` | `/api/web/audit/organization/slug/{organizationSlug}`; `/api/web/audit/event/types` | query `{ eventType,page,pageSize }` | local `ListAuditResponse`, `AuditEventType[]` | `resource/oas/modules/backend/audit/openapi.yaml` | `frontend/packages/api/src/out/modules/backend-audit-types.ts#paths[...]` | `generated-ready` | N/A | `keep` | none | N/A | existing `commands/audit/audit.test.ts`; needed generated path snapshots |
|
|
63
|
-
| TUNNEL-01 | tunnel | `aipctl admin tunnel status`, `config`, `token` | `getTunnelStatus`, `getTunnelConfig`, `createTunnelToken` | api | `GET`, `GET`, `POST` | `/api/web/edge-tunnel/v2/organizations/slug/{organizationSlug}/status`; `/config`; `/token` | none | local `TunnelStatus`, `TunnelConfig`, `void` | `resource/oas/modules/backend/tunnel/openapi.yaml` | `frontend/packages/api/src/out/modules/tunnel-types.ts#paths[...]` | `generated-ready` | N/A | `keep` | none | N/A | existing `commands/tunnel/tunnel.test.ts`; needed v2 path snapshot |
|
|
64
|
-
| P1-PRESET-01 | preset | `aipctl admin preset list`, `get`, `create`, `update`, `rename`, `delete`, `set-default`, `unset-default`, `regen-key`, `regen-static-key` | `listPresets`, `getPreset`, `createPreset`, `updatePreset`, `renamePreset`, `deletePreset`, `setPresetAsDefault`, `unsetPresetAsDefault`, `regenPresetKey`, `regenPresetStaticKey` | api | `GET`, `POST`, `PUT`, `PATCH`, `DELETE` mix | `/api/web/presets/v2`; `/api/web/presets/{presetId}`; `/key`; `/static-key`; `/default` | legacy preset API kept, root how-to/docs switched to `aipctl admin preset ...`, and contract tests pin list/detail/default/key/static-key paths | local preset DTOs with installation/json command fields | `resource/oas/duplo-web.yaml` | `frontend/packages/api/src/out/user-types.ts#paths["/api/web/presets/v2"]`, `#paths["/api/web/presets/{presetId}"]`, `#paths["/api/web/presets/{presetId}/default"]` | `legacy-generated` | `P1` | `keep` | none | N/A | updated `src/core/api.test.ts`, `commands/preset/preset.test.ts`, `../docs/how-to/aip-cli-usage.md`; covers admin namespace docs plus `/v2`, `/{id}`, `/default`, `/key`, `/static-key` paths |
|
|
65
|
-
|
|
66
|
-
## Queue IDs for follow-up
|
|
67
|
-
|
|
68
|
-
### P0 queue
|
|
69
|
-
|
|
70
|
-
- `P0-ORG-01` org member list/mutation legacy-exception aligned (done in `AIP-PUB-04`, independent contract follow-up remains)
|
|
71
|
-
- `P0-ORG-02` org invite-link trio hidden from public beta (done in `AIP-PUB-04`)
|
|
72
|
-
- `P0-AGENT-01` user agent remains on implemented legacy endpoints until v2 backend lands
|
|
73
|
-
- `P0-AGENT-02` admin agent remains on implemented legacy endpoints until v2 backend lands
|
|
74
|
-
- `P0-DRIVE-01` drive list/download/delete/mkdir/rename/usage contract migration (done in `AIP-PUB-04`)
|
|
75
|
-
- `P0-DRIVE-02` drive upload contract migration (done in `AIP-PUB-04`)
|
|
76
|
-
- `P0-MODEL-01` model list path/DTO migration (done in `AIP-PUB-04`)
|
|
77
|
-
|
|
78
|
-
### P1 queue
|
|
79
|
-
|
|
80
|
-
- `P1-INT-01` integration legacy-exception documented; current/legacy path+DTO tests added
|
|
81
|
-
- `P1-AUTO-01` automation pagination/trigger metadata alignment done
|
|
82
|
-
- `P1-PRESET-01` preset admin namespace/docs + legacy path tests done
|
|
83
|
-
- `P1-SKILL-01` skill JSON/help/docs field sync done
|
|
84
|
-
- `P1-CHAT-01` chat SSE fixture tests added for final/fallback/error cases
|
|
85
|
-
|
|
86
|
-
## Manual notes
|
|
87
|
-
|
|
88
|
-
- Generated reference files under `frontend/packages/api/src/out/**` are inventory links only. They are not imported by CLI source/build/test/lint.
|
|
89
|
-
- `agent-user` / `agent-admin` modern OAS files exist under `resource/oas/modules/backend/agent/**`, but current backend v2 controllers throw `NotImplementedError`; current CLI intentionally uses implemented `AgentsApiController` endpoints until v2 implementation lands.
|
|
90
|
-
- OAuth authorization-server metadata, dynamic client registration, authorize, and token endpoints used by `src/core/oauth.ts` were not found in current `resource/oas`; they need owner-backed contractization.
|
|
91
|
-
- `config` commands intentionally excluded. local config surface has no network owner.
|
package/docs/architecture.md
DELETED
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
# aipctl 통합 CLI 구조
|
|
2
|
-
|
|
3
|
-
`desktop/packages/cli`는 npm package `aipctl`의 source of truth입니다.
|
|
4
|
-
|
|
5
|
-
- public bin: `aipctl`
|
|
6
|
-
- entrypoint: `build/index.cjs`
|
|
7
|
-
- root CLI: TypeScript/Effect (`src/`)
|
|
8
|
-
- native MCP commands: Go (`go/`), `install`/`run`/`tunnel`/`logs`
|
|
9
|
-
- platform optional package resolver: `binary.cjs`
|
|
10
|
-
|
|
11
|
-
## Source tree
|
|
12
|
-
|
|
13
|
-
```text
|
|
14
|
-
desktop/packages/cli/
|
|
15
|
-
├── src/
|
|
16
|
-
│ ├── index.ts # composition root, help pre-hooks, Command.run(name: aipctl)
|
|
17
|
-
│ ├── command-tree.ts # AIP commands + native top-level commands
|
|
18
|
-
│ ├── build-info.ts # AIPCTL_VERSION / AIPCTL_BUILD_ENV
|
|
19
|
-
│ ├── native/ # Go binary bridge, user-facing namespace 아님
|
|
20
|
-
│ ├── commands/ # AIP command handlers
|
|
21
|
-
│ │ └── admin/ # admin-only command namespaces 포함
|
|
22
|
-
│ ├── core/ # config/credentials/OAuth/API/rate-limit
|
|
23
|
-
│ └── help/ # custom group help renderer
|
|
24
|
-
├── go/ # 기존 Go MCP CLI source
|
|
25
|
-
├── scripts/ # publish and smoke helpers
|
|
26
|
-
├── binary.cjs
|
|
27
|
-
├── platforms.json
|
|
28
|
-
└── package.json
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
## Runtime flow
|
|
32
|
-
|
|
33
|
-
```text
|
|
34
|
-
사용자
|
|
35
|
-
└─ aipctl (build/index.cjs)
|
|
36
|
-
├─ AIP command → Effect command handler → core ApiService/Config/Credential
|
|
37
|
-
└─ native command → src/native bridge → binary.cjs lazy resolve → Go aipctl binary
|
|
38
|
-
```
|
|
39
|
-
|
|
40
|
-
## Native bridge rules
|
|
41
|
-
|
|
42
|
-
- `AIPCTL_NATIVE_BINARY`가 있으면 그 경로를 우선 사용합니다.
|
|
43
|
-
- 없으면 `build/index.cjs` 기준 `../binary.cjs`를 lazy require해 optional platform package를 찾습니다.
|
|
44
|
-
- native command 실행 시점에만 binary resolver를 호출합니다.
|
|
45
|
-
- `stdio: "inherit"`, `env: process.env` 정책을 유지합니다.
|
|
46
|
-
- `run --help`, `tunnel --help`, `tunnel link --help`는 Effect help보다 먼저 Go help로 위임합니다.
|
|
47
|
-
- `prod` build에서는 `logs`를 command tree와 native help hook에서 제외합니다.
|
|
48
|
-
|
|
49
|
-
## Command ownership
|
|
50
|
-
|
|
51
|
-
- TypeScript root command: `aipctl`
|
|
52
|
-
- AIP user workflows: `auth`, `config`, `org`, `skill`, `agent`, `automation`, `chat`, `drive`, `integration`, `model`
|
|
53
|
-
- AIP admin workflows: `admin org|agent|integration|skill|preset|usage|audit|tunnel`
|
|
54
|
-
- Go native workflows: `install`, `run`, `tunnel`, `logs` (`prod` 제외)
|
|
55
|
-
|
|
56
|
-
`aipctl admin tunnel ...`은 AIP admin command입니다. `aipctl tunnel ...`은 native Go MCP command입니다.
|
|
57
|
-
|
|
58
|
-
## Build/version
|
|
59
|
-
|
|
60
|
-
- package base version: `0.0.0`
|
|
61
|
-
- publish-time CalVer가 `AIPCTL_VERSION`으로 TS bundle과 Go ldflags에 주입됩니다.
|
|
62
|
-
- `AIPCTL_BUILD_ENV`는 `local|dev|stage|prod|test` 중 하나이며 `logs` gating에 사용됩니다.
|
|
63
|
-
|
|
64
|
-
## Dependency direction
|
|
65
|
-
|
|
66
|
-
```text
|
|
67
|
-
src/index.ts
|
|
68
|
-
→ command-tree.ts
|
|
69
|
-
→ commands/*
|
|
70
|
-
→ core/*
|
|
71
|
-
→ native/*
|
|
72
|
-
→ binary.cjs (lazy runtime only)
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
`core/`는 command를 몰라야 합니다. native bridge는 user-facing namespace가 아니라 Go binary adapter입니다.
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
# Desktop CLI Go 코딩 가이드라인
|
|
2
|
-
|
|
3
|
-
`desktop/packages/cli/go` 작업 시 적용하는 로컬 Go 코딩 규칙.
|
|
4
|
-
|
|
5
|
-
공통 규칙은 중앙 문서를 따른다.
|
|
6
|
-
|
|
7
|
-
- [docs/rules/go-coding-guidelines.md](/Users/evan/Desktop/Work/duplo/docs/rules/go-coding-guidelines.md)
|
|
8
|
-
|
|
9
|
-
## `desktop`에서 특히 중요한 규칙
|
|
10
|
-
|
|
11
|
-
- `desktop`은 다음 경계가 성능 민감 포인트다:
|
|
12
|
-
- SSE bridge
|
|
13
|
-
- stdio bridge
|
|
14
|
-
- tunnel stream handler
|
|
15
|
-
- terminal output buffer
|
|
16
|
-
- filesystem search / read
|
|
17
|
-
|
|
18
|
-
- 따라서 다음을 특히 엄격히 본다:
|
|
19
|
-
- `stdin/stdout` 전체 버퍼링
|
|
20
|
-
- 로그/출력 문자열 반복 생성
|
|
21
|
-
- stream relay에서의 불필요한 복사
|
|
22
|
-
- `io.Copy` 직접 사용
|