aipctl 2026.10.3 → 2026.10.5

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.
@@ -56,7 +56,7 @@
56
56
  | P1-AUTO-01 | automation | `aipctl automation list`, `get`, `create`, `update`, `delete`, `enable`, `disable`, `history`, `triggers` | `listAutomations`, `getAutomation`, `createAutomation`, `updateAutomation`, `deleteAutomation`, `updateAutomationStatus`, `listAutomationHistories`, `getTriggerProviderMetadata` | api | `GET`, `POST`, `PUT`, `DELETE`, `PATCH` | `/api/cli/v1/organizations/{organizationSlug}/automations`; `/{automationId}`; `/{automationId}/status`; `/{automationId}/history`; `/triggers?type=...` | one-based pageNumber/pageSize (1..100); status `{ status }`; exactly one matching trigger branch; metadata retains required accountId/folderId/serviceType input | existing list/history domain DTOs; dedicated `GetCliAutomationResponse` and ID DTO; webhook detail only serviceType/boolean secretConfigured | `resource/oas/modules/backend/cli/openapi.yaml` → `v1_automations*.yaml`; request/list/history aliases reuse Automation user schemas | `backend/api/.../cli/generated/api/CliAutomationApi.kt` | `generated-ready` | `P1` | `migrate` | owner=`CLI Automation adapter`; Schedule/Webhook/My Drive management enabled; external account provider metadata/mutations return 403 before provider side effects; stored external detail never enriches remotely or fabricates account/folder validity | `AI-6344`; external lifecycle gate `AI-6380`; large pagination gate `AI-6413` | `src/core/automation-contract.test.ts`, `src/core/api.test.ts`, Automation command tests, `redaction.test.ts`, Backend safe-read/controller/audit tests, Gateway parity; real mise servers + production CLI CRUD/ownership/pagination/quota/DB/audit |
57
57
  | P1-AUTO-02 | automation-execution | `aipctl automation run`, `cancel`, `webhook-regen` (GA-CANDIDATE, production gated) | `runAutomation`, `cancelAutomationHistory`, `regenerateWebhookUrl` | api | `POST`, `DELETE`, `POST` | legacy `/api/web/organizations/slug/{organizationSlug}/automations/{automationId}/run`; `/histories/{seq}`; `/webhook-url/regen` | existing domain input | existing execution/history/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` | `legacy-exception` | owner=`Automation execution domain`; requires execution quota, idempotency/cancel lifetime, webhook secret rotation and safe output verification before customer enablement | `AI-6380` | existing legacy path/command tests; production availability keeps all three hidden |
58
58
  | CHAT-01 | chat-readonly | `aipctl chat list`, `aipctl chat get`, `aipctl chat messages` | `listConversations`, `getConversation`, `listMessages` | chat | `GET` | `/api/cli/v1/organizations/{orgSlug}/chats`; `/chats/{conversationId}`; `/chats/{conversationId}/messages` | list sends optional cursor; server fixes bounded `updatedAt desc` page size; detail/messages preserve organization and user ownership | local `ListConversationsResponse`, `ConversationDetail`, `ChatMessage[]` | `chat/packages/chat/src/modules/cli-chat/interface/cli-chat-read-v1.interface.controller.ts` | code-first controller contract with `operationId`/quota/capability extensions; no generated backend artifact | `oas-source-only` | `P0` | `migrate` | none; `CliChatReadInterfaceService` reuses the existing conversation/message ownership services and returns CLI-safe fields only | `AI-6344` | updated `src/core/api.test.ts`, Chat read service spec, Gateway registry/contract parity; local CLI/Chat verification covers cursor and no legacy fallback |
59
- | 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
+ | 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` with optional count/cursor/parentId (default count200), `/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) |
60
60
  | 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 |
61
61
  | 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` | read operations use `/api/cli/v1/organizations/{organizationSlug}/integrations`; `/admin/integrations/available`; `/admin/integrations/{integrationId}`; `/tools`; mutations/test remain legacy candidate paths | read responses use dedicated CLI DTOs; admin detail maps only metadata and configured boolean, never property descriptors or credential values; update/delete/test remain unchanged | local `Integration`, `IntegrationDetail`, `IntegrationToolsResponse`, `ConfigurableIntegration[]` | `resource/oas/modules/backend/cli/openapi.yaml` → `v1_integrations*.yaml` | `backend/api/.../cli/generated/api/CliIntegrationApi.kt`; generated `Cli*Integration*` models | `generated-ready` | `P1` | `migrate` | owner=`backend CLI integration adapter`; rationale=`read-only operations now have a stable v1 contract while external test and mutations retain candidate gates`; removal condition=`dedicated test/mutation contracts pass timeout, redaction and idempotency gates`; incorporation plan=`follow AI-6380 candidate work` | `AI-6344` | updated `src/core/api.test.ts`, Backend adapter/security tests, Gateway registry/contract parity; local CLI read verification and legacy mutation path regression |
62
62
  | 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 |
@@ -67,6 +67,75 @@
67
67
  | TUNNEL-01 | tunnel | `aipctl admin tunnel status`; `config`/`token` remain gated | `getTunnelStatus`; candidate `getTunnelConfig`, `createTunnelToken` | api | `GET`; candidate `GET`/`POST` | status `/api/cli/v1/organizations/{organizationSlug}/admin/tunnel/status`; candidates retain Web `/config`/`/token` | none | status `{ connected: boolean }` only | status `resource/oas/modules/backend/cli/openapi.yaml`; candidates Tunnel OAS | `backend/api/.../cli/generated/api/CliTunnelApi.kt#getCliTunnelStatus` | `generated-ready` | N/A | `migrate` | none for status; existing personal Tunnel service checks current user/org; token/config secret gates remain | `AI-6344`; sensitive gate `AI-6380` | status contract/adapter/registry tests; actual CLI + Go Tunnel server disconnected/Redis session connected/user isolation, token count unchanged; actual edge handshake not verified |
68
68
  | P1-PRESET-01 | preset | `aipctl admin preset list`, `get`, `create`, `update`, `rename`, `delete`, `set-default`, `unset-default`; key rotation commands remain gated | `listPresets`, `getPreset`, `createPreset`, `updatePreset`, `renamePreset`, `deletePreset`, `setPresetAsDefault`, `unsetPresetAsDefault` | api | list/get `GET`; create `POST`; update/default set `PUT`; rename `PATCH`; delete/default unset `DELETE` | `/api/cli/v1/organizations/{organizationSlug}/admin/presets`; `/{presetId}`; `/{presetId}/default` | bounded one-based page/pageSize 1..100; default pageSize 100; existing basic mutation bodies, explicit org in path | dedicated safe `CliPreset` metadata; no installation/json commands, auth, keys or MCP URL; list CLI JSON remains a page array; delete `void` | `resource/oas/modules/backend/cli/openapi.yaml` | `backend/api/.../cli/generated/api/CliPresetApi.kt`; `CliPreset` DTOs | `generated-ready` | `P1` | `migrate` | none for basic operations; user-owned resources require member+owner+org checks despite admin namespace; read service does not mint keys/enrich remotely; domain mutation/audit reused | `AI-6344`; key gate `AI-6380`; larger workload gate `AI-6413` | `src/core/remaining-direct-contract.test.ts`, Backend safe-read/controller tests, registry/manifest/help, trailing argv tests; actual production CLI eight-operation lifecycle, ownership/accessible integration/pagination/quota/key-count/DB/audit checks |
69
69
 
70
+ ## 본인 quota 진단 계약
71
+
72
+ `quota status [--org <slug>] [--json]`은 `ApiService.getMyCliQuota`에서
73
+ `GET /api/cli/v1/organizations/{organizationSlug}/quota`를 한 번 호출한다.
74
+ Source OAS는 `resource/oas/modules/backend/cli/paths/v1_quota.yaml`, generated owner는
75
+ `CliQuotaApi#getCliMyQuota`, CLI parser는 `src/core/quota-contract.ts`다.
76
+ Canonical operation은 `cli.quota.self.read`, capability는 `cli.quota.self`, quota class는
77
+ `control-read`다. 현재 인증 actor·active membership을 정책/사용량 조회보다 먼저 검증한다.
78
+ Gateway capability discovery와 동일한 user-global control-read bucket을 쓰며 workload policy
79
+ 조회나 metadata/text quota 소진에 의존하지 않는다. bucket은 유한하고 Redis 장애 시 503이다.
80
+
81
+ 응답은 `userLimits`, `organizationSharedLimits`, nullable 정책 version 2개, `usage`만 허용한다.
82
+ UTC 일일 text admissions, 미반납 active, unresolved 수는 PostgreSQL authoritative snapshot이다.
83
+ 정책 row가 없으면 version을 `null`로 포함한다. 사용량 실패는 `UNAVAILABLE`과 required-null
84
+ 사용량/reset 필드로 표시한다. 본인 사용량과 조직 공유 정책 수치는 반환하지만 조직 aggregate
85
+ 사용량·다른 사용자·raw policy·credit 잔액을 반환하지 않는다. HTTP 응답은 `Cache-Control: no-store`다.
86
+ 조회는 용량을 예약하거나 기존 permit을 반환하지 않는다. 테스트는 Backend
87
+ `CliQuotaApiControllerTest`, Gateway admission/registry, CLI quota parser/command/API tests다.
88
+ Source OAS의 429/503은 JSON `CliQuotaErrorResponse`와 공유 `CliQuotaErrorDetails`를 선언하며,
89
+ 200의 `Cache-Control: no-store`와 429의 조건부 positive-integer `Retry-After`도 포함한다.
90
+
91
+ ## 공통 CLI HTTP 수명과 작업량 상한
92
+
93
+ Skill list/library는 `--count 1..200`/`--cursor`/`--search`, built-in/admin built-in은
94
+ `--limit 1..100`/`--cursor`/`--search`, Drive list는 `--count 1..200`/`--cursor`/
95
+ `--parent-id`, Chat list는 `--cursor`를 기존 OAS query로 전달한다. `--json-page`는 서버의 한
96
+ 페이지 envelope와 nullable `nextCursor`를 반환한다. Admin skill list는 기존 page/page-size query와
97
+ `pagination` envelope를 제공한다. 기존 Skill/Chat/admin Skill `--json` 배열은 유지하며
98
+ 다음 페이지가 있으면 stderr에 안내한다. 자동 전체 수집은 없다. `src/basic-behavior.test.ts`와
99
+ `src/core/api.test.ts`에서 root argv→API options→encoded query와 출력/오류를 검증한다.
100
+ 삭제·멤버 제거·조직 탈퇴의 확인 누락은 요청 전 `CLI_CONFIRMATION_REQUIRED`,
101
+ `outcome=not-dispatched`, exit 1이다. 공개 범위는 `command-manifest.ts`와 availability가 결정한다.
102
+
103
+ 인증 state snapshot/commit·logout·환경 변경·조직 선택 저장은 동일한 짧은 credentials lock을
104
+ 사용한다. refresh 전용 lock은 network 대기 중에도 logout/config 변경을 허용한다. 새 로그인·
105
+ logout·환경 변경은 persistent session revision을 바꾸며, refresh는 같은 session을 유지한다.
106
+ 늦은 refresh/login/org 결과는 폐기하고, HTTP admission 뒤 fetch 직전에 revision·bearer·App URL/
107
+ first-party destination을 다시 확인한다. 재로그인 후 과거 invalid_grant가 새 credentials를
108
+ 지우지 않는다. config/credentials JSON은 atomic rename으로 저장하고 config는 매번 다시 읽는다.
109
+ 실제 filesystem을 공유하는 독립 service instance 회귀는 `src/core/auth-session.test.ts`에 있다.
110
+ Refresh lock 획득은 metadata/token 각각 30초와 짧은 state lock을 고려해 최대 70초 기다린다.
111
+ 대기는 취소 가능하며 시간 초과는 `CLI_AUTH_REFRESH_WAIT_TIMEOUT`, `outcome=not-dispatched`다.
112
+ 취소된 대기자는 token을 재교환하지 않고, 갱신 소유자의 취소는 OAuth HTTP signal에도 전달한다.
113
+ 6초 지연된 정상 갱신에서도 독립 인스턴스가 token POST 한 번을 재사용하는 회귀를 유지한다.
114
+
115
+ `src/core/http-request.ts`가 로컬 admission, fetch, 전체 body 소비를 하나의 deadline으로 묶는다.
116
+ 일반 API는 120초·decoded 8 MiB, OAuth는 30초·8 MiB, transfer/export download는 600초·128 MiB,
117
+ external upload는 600초·응답 8 MiB, text execution은 서버 최대 600초에 응답 여유 10초를 더한다.
118
+ Content-Length 사전 검사와 chunked byte 검사를 모두 적용한다. 로컬 lease는 headers 뒤에도
119
+ body 소비 종료까지 유지하고 timeout/cancel/실패 시 해당 lease만 반납한다. deadline 뒤 늦게
120
+ 획득된 lease도 요청을 전송하지 않고 반납한다.
121
+ Forced runtime teardown은 interrupt된 HTTP와 늦은 admission cleanup을 최대 5초 기다린 뒤 종료한다.
122
+
123
+ Mutation transport/invalid-body/timeout 실패는 전송 전 `not-dispatched`, 전송 후 `unknown`;
124
+ GET/HEAD 실패는 `read-failed`다. 알려진 server rejection은 기존 code/status를 유지한다.
125
+ 변경·유료 요청의 자동 retry나 legacy fallback은 없다. 개발 Agent stream의 terminal-envelope-only
126
+ 구독 재조회는 전체 600초·최대 3회로 제한하며 start/provider 요청은 재실행하지 않는다.
127
+ OAuth registration·authorization-code·refresh POST의 timeout/invalid JSON/잘못된 성공 payload도
128
+ `unknown`과 safe request ID를 로그인·갱신의 최종 오류 경계까지 전달한다. 인증 상태를 확인한 뒤
129
+ 재시도하도록 안내하며 자동 재전송 또는 결과가 불명인 응답으로 자격 증명 저장/삭제를 하지 않는다.
130
+ 확인된 `invalid_grant`/401 응답은 기존 session-expired 처리로 구분한다.
131
+ Ctrl+C는 보수적인 `CLI_COMMAND_INTERRUPTED`, `outcome=unknown`, exit 130을 출력하며 remote
132
+ rollback을 의미하지 않는다. API/auth/org 실패는 exit 1이고 `--json` stderr에 한 건만 기록한다.
133
+
134
+ Agent templates 전체 collector는 100페이지·10,000항목·합계 8 MiB·120초를 공유한다.
135
+ 반복 ID, total/pageSize 변경, 빈/짧은 중간 페이지와 상한 초과는 오류로 종료하며 부분 성공을
136
+ 반환하지 않는다. Snapshot cursor가 없는 동안 같은 크기의 동시 교체까지 검출한다고 보장하지
137
+ 않는다. DB/query·다른 endpoint pagination 및 대규모 tenant 측정은 AI-6413에 남아 있다.
138
+
70
139
  ## 공통 CLI request quota 오류 계약
71
140
 
72
141
  `GA-DIRECT` 업무 호출과 명시적 discovery/진단용 `GET /api/cli/v1/capabilities`는 각각 Gateway request-rate admission을 통과한다. production CLI는 업무마다 capability를 선조회하지 않는다. 로컬 release manifest는 artifact에 없는 명령을 차단하고, 실제 업무 endpoint의 Gateway registry가 최신 server release/rollout/quota를 authoritative하게 검사한다. Gateway-owned source 계약은 `resource/oas/modules/backend-gateway/me/components/schemas/CliQuotaErrorResponse.yaml`과 `CliQuotaErrorDetails.yaml`이다.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aipctl",
3
- "version": "2026.10.3",
3
+ "version": "2026.10.5",
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": "cd3e1d96a6c80cca1c9594573468ecac8876ea644f388d0d53950cc063451a72",
26
- "wrapperHash": "1f9932e5f826496deb9203873e0e543319d84afda6610a78305ffa034fd665c0",
25
+ "contentHash": "b82bf4ae40e40305cc43d0cc31315cd2d21cecfeddf32f03c9df603142cba6ad",
26
+ "wrapperHash": "b468cab0d6f5dbb8d14c3d3958f004ab0802fd32387d93938a78f71c59aed74d",
27
27
  "nativeHash": "006b08c3e391f4571d9b7c0f12d684fe2448106259e7e0581b10f9be362452e9"
28
28
  },
29
29
  "optionalDependencies": {