@morit/cli 1.3.0 → 1.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/README.md +3 -5
  2. package/assets/plugin_contract.json +33 -8
  3. package/bin/morit.js +0 -0
  4. package/package.json +1 -1
  5. package/src/cli.js +5 -0
  6. package/src/preview.js +254 -17
  7. package/src/workspace.js +218 -19
  8. package/assets/docs/README.md +0 -107
  9. package/assets/docs/ai-response-and-timeline.md +0 -203
  10. package/assets/docs/ai-skill-and-docx-workflow.md +0 -83
  11. package/assets/docs/app-builder.md +0 -56
  12. package/assets/docs/authentication.md +0 -140
  13. package/assets/docs/components.md +0 -216
  14. package/assets/docs/design-tokens-responsive.md +0 -171
  15. package/assets/docs/docs-index.json +0 -94
  16. package/assets/docs/examples-notion.md +0 -83
  17. package/assets/docs/examples-school-life.md +0 -79
  18. package/assets/docs/getting-started.md +0 -132
  19. package/assets/docs/information-hierarchy.md +0 -81
  20. package/assets/docs/instances-and-connectors.md +0 -93
  21. package/assets/docs/lifecycle-and-api.md +0 -169
  22. package/assets/docs/local-cli.md +0 -125
  23. package/assets/docs/manifest.md +0 -234
  24. package/assets/docs/packaging-and-testing.md +0 -121
  25. package/assets/docs/permissions-and-data.md +0 -149
  26. package/assets/docs/platform-compatibility.md +0 -62
  27. package/assets/docs/plugin-storage.md +0 -175
  28. package/assets/docs/project-structure.md +0 -102
  29. package/assets/docs/remote-mcp.md +0 -158
  30. package/assets/docs/school-life-privacy.md +0 -55
  31. package/assets/docs/screens-layout-navigation.md +0 -95
  32. package/assets/docs/sdk-and-mcp.md +0 -199
  33. package/assets/docs/tool-and-skill.md +0 -172
  34. package/assets/docs/troubleshooting.md +0 -121
  35. package/assets/docs/ui-extensions.md +0 -75
  36. package/assets/docs/ui-runtime-v2.md +0 -343
  37. package/assets/docs/verification.md +0 -133
@@ -1,199 +0,0 @@
1
- # CLI와 AI 에이전트 MCP
2
-
3
- Morit은 두 MCP 연결을 제공합니다.
4
-
5
- | 연결 | 실행 위치 | 적합한 작업 |
6
- |---|---|---|
7
- | Local `@morit/plugin-mcp` | 개발자 PC의 stdio process | 로컬 파일 직접 편집, 빠른 preview/build |
8
- | Remote `https://morit-api.moring.co/mcp` | Morit Cloud Streamable HTTP | 파일시스템 없는 AI client, 조직 Project·Secret·Deployment |
9
-
10
- 두 연결은 SDK 1.7.8의 `@morit/cli`와 Host Plugin contract를 사용합니다. 계약에는 mode별 Plugin
11
- Theme, Local Storage/AI access, 표준 Storage Tool, UI binding, A2UI Response catalog와 safe
12
- preview가 포함됩니다. Local source에 접근할 필요가 없으면 Remote를, 현재 저장소 파일을 직접
13
- 고쳐야 하면 Local을 선택합니다.
14
-
15
- ## 준비
16
-
17
- ```bash
18
- node --version
19
- npx -y @morit/cli login
20
- ```
21
-
22
- Node.js 20.12 이상이 필요합니다. Local MCP의 Cloud Tool을 쓸 때만 CLI 로그인이 필요합니다.
23
- MCP 설정이나 Project source에 access token을 직접 넣지 않습니다.
24
-
25
- ## Codex에 Local MCP 추가
26
-
27
- ```bash
28
- codex mcp add morit-plugin-local -- npx -y @morit/plugin-mcp
29
- codex mcp list
30
- ```
31
-
32
- 특정 workspace만 허용하려면 환경변수로 절대 경로를 전달합니다.
33
-
34
- ```bash
35
- codex mcp add morit-plugin-local \
36
- --env MORIT_PLUGIN_WORKSPACE=/absolute/development/path \
37
- -- npx -y @morit/plugin-mcp
38
- ```
39
-
40
- Codex CLI/IDE/Desktop의 현재 MCP 설정 방식은
41
- [공식 OpenAI MCP 문서](https://learn.chatgpt.com/docs/extend/mcp?surface=cli)를 참고하세요. Codex
42
- TUI에서는 `/mcp`로 활성 서버를 확인합니다.
43
-
44
- ## Codex에 Remote MCP 추가
45
-
46
- ```bash
47
- codex mcp add morit-plugin-remote --url https://morit-api.moring.co/mcp
48
- codex mcp login morit-plugin-remote
49
- codex mcp list
50
- ```
51
-
52
- 브라우저에서 Morit 계정으로 로그인하고 조직과 scope를 승인합니다. static bearer token을 config에
53
- 넣지 않습니다.
54
-
55
- ## Claude Code
56
-
57
- Local stdio:
58
-
59
- ```bash
60
- claude mcp add --scope user morit-plugin-local -- npx -y @morit/plugin-mcp
61
- ```
62
-
63
- Remote Streamable HTTP:
64
-
65
- ```bash
66
- claude mcp add --transport http --scope user \
67
- morit-plugin-remote https://morit-api.moring.co/mcp
68
- ```
69
-
70
- 클라이언트가 OAuth를 요청하면 Morit SSO 승인을 완료한 뒤 Tool 목록을 새로고침합니다. Claude
71
- Web/Desktop에서는 Custom Connector에 같은 Remote URL을 등록합니다. Local stdio는 로컬 process를
72
- 실행할 수 있는 client에서만 사용할 수 있습니다.
73
-
74
- ## ChatGPT와 기타 Remote MCP client
75
-
76
- ChatGPT에서 custom MCP app을 사용할 수 있는 계정·workspace라면 Apps의 custom connector 생성
77
- 화면에 다음 URL을 입력하고 Morit OAuth를 승인합니다.
78
-
79
- ```text
80
- https://morit-api.moring.co/mcp
81
- ```
82
-
83
- ChatGPT Web은 개발자 PC의 stdio process나 Codex `config.toml`을 읽지 않으므로 Local MCP 대신
84
- Remote MCP를 사용합니다. 조직 계정은 관리자가 custom app과 필요한 read/write scope를 허용해야
85
- 할 수 있습니다. Tool이 변경된 뒤에는 connector의 Tool schema를 새로고침하고 새 대화에서
86
- 확인합니다.
87
-
88
- stdio MCP를 지원하는 다른 desktop agent의 일반적인 설정은 다음 형태입니다. 실제 설정 파일 위치와
89
- key 이름은 해당 client 문서를 따릅니다.
90
-
91
- ```json
92
- {
93
- "mcpServers": {
94
- "morit-plugin-local": {
95
- "command": "npx",
96
- "args": ["-y", "@morit/plugin-mcp"],
97
- "env": {
98
- "MORIT_PLUGIN_WORKSPACE": "/absolute/development/path"
99
- }
100
- }
101
- }
102
- }
103
- ```
104
-
105
- Remote를 지원하는 client에는 command나 server Secret 대신 endpoint와 OAuth만 설정합니다. 연결 뒤
106
- Tool 목록에서 `morit_sdk_contract`, `morit_docs_search`, `morit_project_create`가 보이는지 확인합니다.
107
- [OpenAI의 Apps 안내](https://help.openai.com/en/articles/11487775-connectors-in-chatgpt)에서 현재 계정과
108
- workspace의 custom app 지원 범위를 확인할 수 있습니다.
109
-
110
- ## Local MCP 작업 순서
111
-
112
- ```text
113
- morit_sdk_contract
114
- → morit_docs_search / morit_docs_get
115
- → morit_project_create 또는 morit_project_open
116
- → morit_project_files_get
117
- → morit_project_files_put
118
- → morit_project_validate
119
- → UI가 있으면 morit_project_preview(light/dark 확인)
120
- → morit_build_start / morit_build_status
121
- → morit_artifact_download
122
- ```
123
-
124
- 주요 Local Tool:
125
-
126
- - 계약·문서: `morit_sdk_contract`, `morit_docs_search`, `morit_docs_get`
127
- - local project: `morit_project_create`, `morit_project_open`, `morit_project_files_get`,
128
- `morit_project_files_put`
129
- - 산출물: `morit_project_validate`, `morit_project_preview`, `morit_project_source_download`,
130
- `morit_build_start`, `morit_build_status`, `morit_artifact_download`
131
- - Cloud 상태·Project: `morit_cloud_status`, `morit_cloud_project_list`, `morit_cloud_project_get`,
132
- `morit_cloud_project_add`, `morit_cloud_project_sync`, `morit_cloud_project_delete`
133
- - Cloud Deployment: `morit_cloud_deployment_start`, `morit_cloud_deployment_list`,
134
- `morit_cloud_deployment_get`, `morit_cloud_deployment_publish`
135
- - Cloud Secret: `morit_cloud_secret_list`, `morit_cloud_secret_put`, `morit_cloud_secret_delete`
136
- - Cloud Connection: `morit_cloud_connection_list`, `morit_cloud_connection_put`,
137
- `morit_cloud_connection_delete`
138
-
139
- MCP가 반환한 project ID, revision, artifact ID를 다음 호출에 그대로 사용합니다. 경로를 추측하거나
140
- build 전에 완료했다고 보고하지 않습니다.
141
-
142
- PNG/JPEG/GIF/WebP icon·UI asset과 `children/*.mplg`는
143
- `morit-base64-v1:<canonical-base64>` 문자열로 `files_put`할 수 있습니다. text 경로에 envelope를
144
- 쓰거나 이미지 확장자와 magic byte가 다르면 Local/Remote MCP가 거부합니다. `files_get`도 같은
145
- envelope를 반환하므로 수정하지 않은 바이트는 그대로 다음 revision에 유지합니다.
146
-
147
- Storage 기능을 생성할 때는 먼저 `morit_sdk_contract`의 `permissions`, `storage_tools`,
148
- `storage_ai_access`, `storage_limits`를 읽고 Manifest `storage`와 UI data source를 함께 작성합니다.
149
- AI가 쓰는 namespace는 `ai_access: read_write`와 `ai_storage` 권한을 모두 선언합니다. MCP는 package
150
- runtime 데이터를 읽는 우회 경로가 아니며 개발 source와 artifact만 다룹니다.
151
-
152
- Response extension을 생성할 때는 `ai_response`와 `ui_runtime` 계약을 함께 읽습니다. MCP 에이전트는
153
- `point: "response"`, Runtime v2, `a2ui.version/description/schema`, 실제 capability data source를 한
154
- 단위로 작성해야 합니다. AI가 결과 JSON을 만들게 하지 말고 schema에는 표시 가능한 최소 데이터와
155
- empty 조건을 명시합니다. validate가 schema·권한·version을 거부하면 파일을 우회 패키징하지 않습니다.
156
-
157
- ## Remote MCP 작업 순서
158
-
159
- ```text
160
- morit_organization_list
161
- → morit_project_create 또는 morit_project_list
162
- → morit_project_files_get
163
- → morit_project_files_put(revision 포함)
164
- → morit_project_validate
165
- → morit_project_preview
166
- → morit_build_start
167
- → morit_build_status
168
- → morit_deployment_get
169
- → morit_artifact_download
170
- ```
171
-
172
- Secret과 Connection은 build 전에 별도 Tool로 설정합니다. Secret 조회는 ID와 masked metadata만
173
- 반환하며 평문 값을 다시 읽을 수 없습니다.
174
-
175
- ## 에이전트 완료 규칙
176
-
177
- AI 에이전트는 다음을 모두 확인한 뒤 완료를 보고합니다.
178
-
179
- - source를 다시 읽고 요청한 파일이 존재함
180
- - 최신 revision으로 validate 성공
181
- - UI가 있으면 preview artifact 생성
182
- - build state가 completed
183
- - `.mplg` artifact ID, 크기, SHA-256, MIME 확인
184
- - 다운로드한 package가 다시 열리고 signature가 유효함
185
- - 배포 요청이면 고유 Deployment와 visibility 확인
186
-
187
- ## 연결 문제
188
-
189
- | 증상 | 확인 |
190
- |---|---|
191
- | Local server가 보이지 않음 | Node 버전, `npx -y @morit/plugin-mcp`, client restart |
192
- | workspace 밖 경로 거부 | `MORIT_PLUGIN_WORKSPACE`와 project 상대 경로 |
193
- | Remote `401` | 정상 OAuth 시작 여부, `codex mcp login` |
194
- | Remote `404` | `/mcp` ingress route |
195
- | contract parse 오류 | server가 전체 JSON stdout을 반환하는지, stderr 혼합 여부 |
196
- | revision conflict | `files_get`으로 최신 revision을 읽고 변경을 합침 |
197
- | artifact 없음 | build status가 completed인지 확인 |
198
-
199
- Remote Tool의 전체 필드는 [원격 Plugin MCP](remote-mcp.md)에 있습니다.
@@ -1,172 +0,0 @@
1
- # Tool, Skill, Search, Slash Command
2
-
3
- Capability는 사용자가 실행할 수 있는 한 가지 작업과 그 실행 경계를 선언합니다. UI에서 버튼을
4
- 누르거나 AI가 Tool을 선택해도 같은 capability가 실행됩니다.
5
-
6
- ## Capability kind
7
-
8
- | kind | 목적 | 실행 방식 |
9
- |---|---|---|
10
- | `tool` | 명시적인 한 번의 작업 | UI, AI, Slash Command |
11
- | `skill` | 여러 입력을 해석하는 작업 | AI, UI, Slash Command |
12
- | `provider` | AI 검색 후보 제공 | Search discovery |
13
- | `background` | 일정 간격의 자동 작업 | Host scheduler |
14
- | `notification` | 알림 생성·취소 작업 | UI, AI 또는 background |
15
-
16
- `tool`과 `skill`은 runtime adapter가 필수입니다. `provider`는
17
- `runtime.role: "search"`가 필요합니다. background runtime을 선언하면
18
- `interval_minutes`는 15~10,080입니다.
19
-
20
- ## Runtime adapter
21
-
22
- | adapter | 용도 | 주요 설정·권한 |
23
- |---|---|---|
24
- | `text_stats` | 텍스트 통계 | 별도 권한 없음 |
25
- | `text_template` | 제한된 텍스트 template | `template` 최대 2,000자 |
26
- | `settings_search` | Instance settings의 검색 항목 | Search Provider용 |
27
- | `notification_template` | 검증된 알림 Host action 생성 | `notifications` |
28
- | `calendar_store` | 일정 저장·조회·reminder | `storage`, reminder는 `notifications` |
29
- | `http_json` | 공개 HTTPS JSON API | `network`, credential 사용 시 `credentials` |
30
- | `mcp_http` | Remote MCP Tool 호출 | `network`, 선택적 `credentials` |
31
- | `child_plugin` | dependency capability 호출 | 노출된 dependency와 capability |
32
- | `neis_school` | 학교 검색·시간표·급식·일정 | `network`, `storage`; reminder는 `notifications` |
33
- | `sandbox_python` | 격리된 Python 데이터 작업 | signed package와 고급 worker |
34
-
35
- ## 선언형 adapter 예
36
-
37
- ### Text template
38
-
39
- ```json
40
- {
41
- "adapter": "text_template",
42
- "template": "요청을 다음 형식으로 정리합니다: {query}"
43
- }
44
- ```
45
-
46
- 복잡한 표현식이나 코드를 template에 넣지 않습니다.
47
-
48
- ### Calendar store
49
-
50
- ```json
51
- {
52
- "adapter": "calendar_store",
53
- "operation": "reminder",
54
- "namespace": "study.schedule"
55
- }
56
- ```
57
-
58
- 일반 저장에는 `storage`, 알림 예약에는 `storage`와 `notifications`가 모두 필요합니다.
59
-
60
- ### HTTP JSON
61
-
62
- ```json
63
- {
64
- "adapter": "http_json",
65
- "connector_id": "notes_api",
66
- "method": "POST",
67
- "request_body": {"query": "{query}"},
68
- "response": {"summary_path": "message", "data_path": "data"}
69
- }
70
- ```
71
-
72
- GET과 POST만 지원하며 redirect를 따라가지 않습니다. endpoint는 공개 HTTPS이고 SSRF 보호 경계를
73
- 통과합니다. bearer token은 Host가 Connection에서 주입하며 fragment에 직접 쓰지 않습니다.
74
-
75
- ### Remote MCP
76
-
77
- Morit Host 1.7.8의 plugin outbound MCP adapter는 `mcp_http`입니다. 개발자용 Local/Remote Plugin
78
- MCP 서버와 이름이 비슷하지만, 설치된 플러그인이 선언한 외부 MCP Tool을 Host 경계에서 호출하는
79
- runtime입니다.
80
-
81
- ```json
82
- {
83
- "adapter": "mcp_http",
84
- "connector_id": "research_mcp",
85
- "tool_name": "search",
86
- "protocol_version": "2025-11-25",
87
- "argument_template": {"query": "{query}"}
88
- }
89
- ```
90
-
91
- Host가 initialize → initialized → `tools/call` session을 관리합니다. credential이 거부되면 지원되는
92
- 연결에서 한 번 갱신한 뒤 새 session으로 재시도합니다. MCP의 `isError: true`는 성공 결과로 바꾸지
93
- 않습니다.
94
-
95
- ### Sandbox Python
96
-
97
- ```json
98
- {
99
- "adapter": "sandbox_python",
100
- "entrypoint": "src/analyze.py"
101
- }
102
- ```
103
-
104
- entrypoint는 package 상대 POSIX 경로이고 각 `src/*.py` 파일과 정확히 1:1이어야 합니다. 코드는
105
- Archive API process에서 실행하지 않고 별도 rootless Docker + gVisor worker와 lease-fenced broker를
106
- 거칩니다. 결과는 다음 객체여야 합니다.
107
-
108
- ```json
109
- {
110
- "summary": "분석을 완료했습니다.",
111
- "data": {},
112
- "evidence": []
113
- }
114
- ```
115
-
116
- `summary` 없이 sandbox 경로나 내부 로그만 반환하면 완료된 결과가 아닙니다.
117
-
118
- ## UI와 AI 노출
119
-
120
- AI는 enabled 상태이고 사용자에게 허용된 capability만 발견합니다. 제목과 설명은 모델이 언제 이
121
- 기능을 선택할지 판단할 수 있게 동작과 입력을 구체적으로 씁니다.
122
-
123
- Slash Command나 UI extension은 선택적 진입점일 뿐 discovery 조건이 아닙니다. 활성 Plugin의 모든
124
- `tool`·`skill`은 매 AI turn의 actor-scoped capability catalog에 자동 포함됩니다. 설치·업데이트·
125
- enable/disable·권한 변경·Connection 생성/수정/삭제·OAuth 완료·삭제 뒤 Host는 Instance route cache를
126
- 즉시 비워 다음 turn과 실행이 새 generation을 사용하게 합니다.
127
-
128
- ```json
129
- {
130
- "id": "school_life.today",
131
- "kind": "tool",
132
- "title": "오늘 학교 생활 조회",
133
- "description": "연결한 학교의 오늘 시간표, 급식, 학사일정을 조회합니다.",
134
- "permissions": ["network", "storage"],
135
- "timeout_seconds": 10,
136
- "runtime": {"adapter": "neis_school", "operation": "overview"}
137
- }
138
- ```
139
-
140
- UI `invoke`가 capability를 참조할 때도 enabled, generation, permission, timeout을 다시 확인합니다.
141
- UI에 capability ID를 사용자용 라벨로 표시하지 않습니다.
142
-
143
- ## Slash Command
144
-
145
- Slash Command는 같은 package의 `tool` 또는 `skill`에 고정된 진입점입니다.
146
-
147
- ```json
148
- {
149
- "id": "school_life.today_command",
150
- "command": "school",
151
- "title": "오늘 학교 생활",
152
- "description": "오늘 시간표와 급식을 확인합니다.",
153
- "capability": "school_life.today",
154
- "argument_template": {}
155
- }
156
- ```
157
-
158
- Slash Command를 선언하지 않아도 Tool discovery는 유지됩니다. 여러 command가 같은 이름을 사용할 수
159
- 없고 `/`는 `command` 값에 포함하지 않습니다.
160
-
161
- ## 실패와 복구
162
-
163
- Capability는 권한 부족, 연결 필요, timeout, retryable network 오류, 잘못된 응답을 구분합니다.
164
- retry는 Connector에 선언한 bounded 정책만 사용합니다. Tool 하나가 실패했다고 AI 요청 전체를
165
- 즉시 포기하지 말고, 오케스트레이터가 대체 Tool·재연결·부분 결과를 선택할 수 있도록 공개 오류를
166
- 구체적으로 유지합니다.
167
-
168
- 실행 준비 상태의 대표 code는 `EXTENSION_NOT_FOUND`, `EXTENSION_PERMISSION_DENIED`,
169
- `EXTENSION_CONNECTION_REQUIRED`, `EXTENSION_DISABLED`, `EXTENSION_VERSION_MISMATCH`,
170
- `EXTENSION_DEPENDENCY_REQUIRED`입니다. 빈 Tool 목록이나 일반 실패 문구로 합치지 마세요.
171
-
172
- 권한과 알림은 [권한, 설정, 저장소, 알림](permissions-and-data.md)을 참고하세요.
@@ -1,121 +0,0 @@
1
- # 오류 해결
2
-
3
- 오류를 catch로 숨기기 전에 어느 경계에서 발생했는지 구분합니다.
4
-
5
- ## 빠른 진단 순서
6
-
7
- ```text
8
- source를 읽을 수 있는가
9
- → validate가 성공하는가
10
- → preview artifact가 생기는가
11
- → signed build와 reopen이 성공하는가
12
- → API 인증과 목록 조회가 성공하는가
13
- → 설치 상태가 active인가
14
- → Connection과 권한이 ready인가
15
- → capability가 실행되는가
16
- → UI가 결과를 렌더링하는가
17
- ```
18
-
19
- 앞 단계가 실패한 상태에서 다음 단계 오류를 우회하지 않습니다.
20
-
21
- ## Validate 오류
22
-
23
- | 증상 | 확인 항목 |
24
- |---|---|
25
- | unknown field | 문서에 없는 key 제거, v1/v2 필드 혼합 여부 |
26
- | duplicate ID | manifest 배열과 모든 fragment를 함께 검색 |
27
- | unknown permission | 지원 목록과 Manifest 전역 권한 확인 |
28
- | capability reference | UI, Slash Command, child dependency 대상 ID 확인 |
29
- | state/data binding | `initial_state`, `data_sources`, `item` scope 확인 |
30
- | source entrypoint | 각 `src/*.py`와 `sandbox_python` 1:1 확인 |
31
- | image asset | `assets/` 경로·확장자·실제 파일 확인 |
32
-
33
- 진단에 표시된 첫 오류부터 고치고 다시 validate합니다. 허용 필드를 늘리거나 unknown key를 무시하게
34
- 바꾸지 않습니다.
35
-
36
- ## Preview 오류
37
-
38
- preview 전에 validate가 실행됩니다. artifact가 없으면 출력 디렉터리 권한과 source size를 확인합니다.
39
- preview가 열려도 실제 앱의 typography, navigation, scroll, async state는 별도 검증 대상입니다.
40
-
41
- ## Build·signature 오류
42
-
43
- - output 확장자가 `.mplg`인지 확인합니다.
44
- - package가 2 MiB, 64 entry 한도 안인지 확인합니다.
45
- - private key 파일 권한과 publisher identity를 확인합니다.
46
- - source ZIP을 `.mplg`로 이름만 바꾸지 않았는지 확인합니다.
47
- - `verify`가 반환한 plugin ID, publisher, version, SHA-256을 기록합니다.
48
- - trusted publisher에 등록된 key와 embedded public key가 다른 경우 올바른 조직 key로 다시 build합니다.
49
-
50
- ## 목록 조회와 설치 오류
51
-
52
- `Not Found`는 URL 이동으로 해결하지 않습니다. API base URL, 배포 route, 인증 header, 사용자 RLS를
53
- 확인합니다. `401`은 endpoint가 없다는 뜻이 아니라 인증이 필요하다는 뜻입니다.
54
-
55
- 설치 뒤 목록 조회가 실패했다가 재시도에서 duplicate가 나오면 package file, Installation row,
56
- default Instance, cache가 하나의 atomic transaction으로 정리되는지 확인합니다. 앱 데이터 삭제만으로
57
- 서버 DB와 외부 저장소는 삭제되지 않습니다. 사용자별 API 목록과 서버 package store를 함께 확인합니다.
58
-
59
- 정상 duplicate는 같은 plugin ID·publisher·version 정책으로 판단하고 파일명만 사용하지 않습니다.
60
-
61
- ## Connection 오류
62
-
63
- | 상태 | 의미 | 사용자 동작 |
64
- |---|---|---|
65
- | `not_configured` | 필수 Connection/Secret 없음 | 계정 연결 또는 Developer Secret 설정 |
66
- | `unavailable` | provider·암호화·runtime 사용 불가 | 운영 설정 확인 |
67
- | credential rejected | token 만료·철회 | 한 번 refresh 후 다시 연결 |
68
- | rate limited | Connector 한도 초과 | 제한된 시간 뒤 재시도 |
69
-
70
- token을 로그에 출력해 진단하지 않습니다. 연결 metadata와 공개 오류 코드만 사용합니다.
71
-
72
- ## Capability 오류
73
-
74
- - permission required: Manifest와 capability 권한, 사용자 grant 확인
75
- - disabled/incompatible: Instance state와 Morit version 확인
76
- - timeout: capability timeout과 Connector timeout을 비교하고 작업을 작게 나눔
77
- - retryable network: Connector의 bounded retry만 사용
78
- - invalid response: `summary`, `data`, `evidence` 형태와 외부 response mapping 확인
79
- - code worker unavailable: broker/worker health와 lease 확인; Archive process에서 직접 실행하지 않음
80
-
81
- Tool 하나의 실패가 AI 요청 전체 실패를 뜻하지 않는 경우 대체 Tool·부분 결과·재연결을 시도하고
82
- 최종 답변에 남은 제한을 설명합니다.
83
-
84
- ## UI 오류
85
-
86
- - 해당 extension만 fallback되고 대화·앱 전체가 계속 동작하는지 확인합니다.
87
- - 없는 state/data/route를 참조하지 않는지 확인합니다.
88
- - list/timeline child가 정확히 하나인지 확인합니다.
89
- - `surface`가 children을 가지는지 확인합니다.
90
- - `positioned`는 `stack`, `expanded`는 `row`/`column` 안인지 확인합니다.
91
- - literal image URL 대신 capability result binding을 사용했는지 확인합니다.
92
- - 원격 이미지가 안 보이면 Manifest와 활성 Instance의 `network` 권한, public HTTPS 여부를 먼저
93
- 확인합니다. redirect, MIME/magic 불일치, 손상된 파일, 512 KiB 또는 가로·세로 4096 px 초과는
94
- Host가 의도적으로 차단합니다. 애니메이션은 최대 128 frame이고 `width × height × frame 수`로
95
- 계산한 frame 합산 pixel이 16,000,000 이하여야 합니다.
96
- - 원격 이미지 실패를 앱 직접 fetch나 임의 외부 URL widget으로 우회하지 않습니다.
97
- - Response UI가 원래 AI 메시지 안의 한 container에 붙는지 확인합니다.
98
- - Response UI가 안 보이면 `config.a2ui.version`이 `v0.9`인지, schema가 실제 완료 데이터와 맞는지,
99
- response의 data source가 실행 capability를 가리키는지, Instance 권한이 승인됐는지 확인합니다.
100
- - 빈 데이터·무관한 답변·중복 결과·Tool 실패에서 Response UI가 생기지 않는 것은 정상입니다. AI가
101
- catalog 항목을 선택하지 않은 경우에도 서버가 임의 fallback UI를 만들지 않고 텍스트만 남깁니다.
102
-
103
- ## MCP 오류
104
-
105
- Local MCP:
106
-
107
- ```bash
108
- node --version
109
- npx -y @morit/plugin-mcp
110
- codex mcp list
111
- ```
112
-
113
- Remote MCP:
114
-
115
- ```bash
116
- curl -i https://morit-api.moring.co/mcp
117
- ```
118
-
119
- 인증 전 `401`과 `WWW-Authenticate`는 정상 OAuth 시작 신호입니다. `404`는 ingress route, `5xx`는
120
- MCP service health와 server log를 확인합니다. Codex에서는 `codex mcp login <name>`, Tool 목록에서는
121
- `morit_sdk_contract`와 `morit_docs_search`를 먼저 확인합니다.
@@ -1,75 +0,0 @@
1
- # UI extension point
2
-
3
- UI extension은 Host의 노출 위치와 Runtime config를 연결합니다.
4
-
5
- ```json
6
- {
7
- "id": "school_life.home",
8
- "point": "screen",
9
- "title": "학교 생활",
10
- "order": 10,
11
- "permissions": ["network", "storage"],
12
- "config": {
13
- "ui_schema": 2,
14
- "view": {"type": "text", "props": {"text": "오늘 학교 생활"}}
15
- }
16
- }
17
- ```
18
-
19
- ## point 선택
20
-
21
- | point | 노출 위치 | 사용 기준 |
22
- |---|---|---|
23
- | `screen` | 독립 플러그인 화면 | 목록·상세·편집 등 주 작업 |
24
- | `surface` | 기존 일반 surface | 기존 패키지 호환; 새 화면은 `screen` 권장 |
25
- | `menu` | 홈 플러그인 메뉴 | 독립 화면으로 가는 보조 진입점 |
26
- | `action` | 홈 extension 영역 | 짧은 즉시 행동 또는 작은 embedded UI |
27
- | `card` | 홈 extension 영역 | 상태·진행·다음 행동 요약 |
28
- | `settings` | 플러그인 상세의 설정 영역 | 사용자 설정과 Connection 진입 |
29
- | `workspace` | Morit AI 작업 공간 선택기 | 대화와 함께 쓰는 독립 작업 surface |
30
- | `response` | capability를 실행한 AI 메시지 내부 | 읽기 중심 결과와 후속 행동 |
31
-
32
- 일반 Tool/Skill은 자동으로 `workspace`가 되지 않습니다. AI 작업 공간 UI가 필요할 때만 별도
33
- `workspace` extension을 선언합니다. Slash Command와 Tool discovery도 별도 계약입니다.
34
-
35
- `response`는 Runtime v2와 `config.a2ui`가 모두 필수입니다. 활성 Instance의 권한과 capability
36
- data source가 확인되면 Host가 `plugin.<extension-id>` 컴포넌트로 동적 등록하고, AI가 최종 답변에
37
- 필요하다고 명시적으로 선택한 경우에만 렌더링합니다. 다른 point에 `a2ui`를 선언하거나 기존
38
- Runtime v1 Response 형식을 사용하는 것은 오류입니다.
39
-
40
- ## Home placement
41
-
42
- Runtime v2의 `card`와 `action`은 고유 section을 만들 수 있습니다.
43
-
44
- ```json
45
- {
46
- "placement": {
47
- "section_id": "school_life.home",
48
- "section_title": "학교 생활",
49
- "section_order": 15,
50
- "layout": "grid",
51
- "show_header": true
52
- }
53
- }
54
- ```
55
-
56
- `layout`은 `stack`, `horizontal`, `grid`입니다. 같은 플러그인에서 같은 `section_id`를 사용한
57
- extension은 함께 배치됩니다. 다른 플러그인의 ID와 겹치지 않게 package namespace를 붙입니다.
58
- `placement`는 `card`와 `action`에서만 사용할 수 있습니다.
59
-
60
- ## 권한과 action
61
-
62
- UI `permissions`는 Manifest 전역 권한의 부분집합입니다. 화면이 참조하는 capability도 자신의 권한을
63
- 따로 가집니다. UI가 표시됐다는 사실만으로 capability 권한이 허용되는 것은 아닙니다. `invoke`는
64
- enabled, generation, granted permission, timeout을 Host 실행 경계에서 다시 확인합니다.
65
-
66
- ## Runtime v1 호환
67
-
68
- `ui_schema`가 없는 기존 extension은 `sections`, `actions`, `form`, shorthand `capability`/`label`을
69
- 사용하는 Runtime v1으로 읽힙니다. v1은 Response 이외의 기존 설치 호환용입니다. 새 서비스형
70
- 화면에는 state, data source, navigation, theme를 함께 사용할 수 있는 Runtime v2를 사용합니다.
71
-
72
- Runtime v1 action style은 `primary` 또는 `secondary`이고, form field는 `text`, `integer`,
73
- `select`만 지원합니다. v1 JSON에 v2 필드를 섞으면 오류입니다.
74
-
75
- 다음은 [UI Runtime v2 레퍼런스](ui-runtime-v2.md)입니다.