@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.
- package/README.md +3 -5
- package/assets/plugin_contract.json +33 -8
- package/bin/morit.js +0 -0
- package/package.json +1 -1
- package/src/cli.js +5 -0
- package/src/preview.js +254 -17
- package/src/workspace.js +218 -19
- package/assets/docs/README.md +0 -107
- package/assets/docs/ai-response-and-timeline.md +0 -203
- package/assets/docs/ai-skill-and-docx-workflow.md +0 -83
- package/assets/docs/app-builder.md +0 -56
- package/assets/docs/authentication.md +0 -140
- package/assets/docs/components.md +0 -216
- package/assets/docs/design-tokens-responsive.md +0 -171
- package/assets/docs/docs-index.json +0 -94
- package/assets/docs/examples-notion.md +0 -83
- package/assets/docs/examples-school-life.md +0 -79
- package/assets/docs/getting-started.md +0 -132
- package/assets/docs/information-hierarchy.md +0 -81
- package/assets/docs/instances-and-connectors.md +0 -93
- package/assets/docs/lifecycle-and-api.md +0 -169
- package/assets/docs/local-cli.md +0 -125
- package/assets/docs/manifest.md +0 -234
- package/assets/docs/packaging-and-testing.md +0 -121
- package/assets/docs/permissions-and-data.md +0 -149
- package/assets/docs/platform-compatibility.md +0 -62
- package/assets/docs/plugin-storage.md +0 -175
- package/assets/docs/project-structure.md +0 -102
- package/assets/docs/remote-mcp.md +0 -158
- package/assets/docs/school-life-privacy.md +0 -55
- package/assets/docs/screens-layout-navigation.md +0 -95
- package/assets/docs/sdk-and-mcp.md +0 -199
- package/assets/docs/tool-and-skill.md +0 -172
- package/assets/docs/troubleshooting.md +0 -121
- package/assets/docs/ui-extensions.md +0 -75
- package/assets/docs/ui-runtime-v2.md +0 -343
- package/assets/docs/verification.md +0 -133
|
@@ -1,175 +0,0 @@
|
|
|
1
|
-
# Plugin Local Storage와 AI 접근
|
|
2
|
-
|
|
3
|
-
Plugin Local Storage는 Host가 관리하는 영구 JSON 저장소입니다. 데이터는 `user_id + installation_id +
|
|
4
|
-
instance_id + namespace + key`로 분리되며 플러그인 코드가 파일 경로나 DB에 직접 접근하지 않습니다.
|
|
5
|
-
UI, Tool, Skill, Background는 같은 Instance 저장소를 사용합니다.
|
|
6
|
-
|
|
7
|
-
## Manifest 선언
|
|
8
|
-
|
|
9
|
-
```json
|
|
10
|
-
{
|
|
11
|
-
"schema_version": 2,
|
|
12
|
-
"permissions": ["storage", "ai_storage"],
|
|
13
|
-
"data_policy": "retain",
|
|
14
|
-
"storage": {
|
|
15
|
-
"version": 2,
|
|
16
|
-
"namespaces": [
|
|
17
|
-
{"id": "default", "max_bytes": 131072, "ai_access": "read"},
|
|
18
|
-
{"id": "tasks", "max_bytes": 262144, "ai_access": "read_write"}
|
|
19
|
-
],
|
|
20
|
-
"migrations": [
|
|
21
|
-
{
|
|
22
|
-
"from": 1,
|
|
23
|
-
"to": 2,
|
|
24
|
-
"namespace": "tasks",
|
|
25
|
-
"rename": {"today": "today_tasks"},
|
|
26
|
-
"delete": ["legacy_filter"]
|
|
27
|
-
}
|
|
28
|
-
]
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
- `storage` 선언에는 schema 2와 `storage` 권한이 필요합니다.
|
|
34
|
-
- namespace는 1~16개, ID는 안전한 plugin identifier입니다.
|
|
35
|
-
- `max_bytes`는 1~256 KiB이고 전체 Installation은 512 KiB 이하입니다.
|
|
36
|
-
- namespace마다 최대 256개 key, key는 최대 80자, 값 하나는 UTF-8 JSON 32 KiB 이하입니다.
|
|
37
|
-
- migration 선언은 최대 64개이며 version은 1부터 1000까지 한 단계씩 증가합니다.
|
|
38
|
-
- 값은 문자열, 유한한 숫자, boolean, `null`, JSON 객체·목록을 사용할 수 있습니다.
|
|
39
|
-
- `ai_access`는 `none`, `read`, `read_write`입니다. 하나라도 AI에 공개하면 Manifest에
|
|
40
|
-
`ai_storage` 권한도 선언해야 합니다.
|
|
41
|
-
|
|
42
|
-
schema 1 플러그인이 기존 `storage` 권한만 요청한 경우 Host는 호환용 `default` namespace(version 1,
|
|
43
|
-
128 KiB)를 제공합니다. 새 플러그인은 명시적 schema 2 선언을 사용하세요.
|
|
44
|
-
|
|
45
|
-
## 표준 Storage Tool
|
|
46
|
-
|
|
47
|
-
Host는 저장소를 선언한 각 Instance에 다음 capability를 제공합니다.
|
|
48
|
-
|
|
49
|
-
| Tool | arguments | 동작 |
|
|
50
|
-
|---|---|---|
|
|
51
|
-
| `morit.storage.list` | `namespace`, 선택 `query`, 선택 `limit` | key와 값 검색·목록 |
|
|
52
|
-
| `morit.storage.get` | `namespace`, `key` | 단일 항목 조회 |
|
|
53
|
-
| `morit.storage.create` | `namespace`, `key`, `value` | 없는 key 생성 |
|
|
54
|
-
| `morit.storage.update` | `namespace`, `key`, `value`, `revision` | revision 일치 시 수정 |
|
|
55
|
-
| `morit.storage.delete` | `namespace`, `key`, `revision` | revision 일치 시 삭제 |
|
|
56
|
-
|
|
57
|
-
`namespace`를 생략하면 `default`, 없으면 첫 namespace를 사용합니다. `list.limit`은 1~100이고
|
|
58
|
-
응답 크기 때문에 일부만 반환하면 `data.has_more`가 `true`입니다. create는 같은 key를 덮어쓰지
|
|
59
|
-
않으며 update/delete는 직전에 읽은 양의 정수 `revision`을 요구합니다.
|
|
60
|
-
|
|
61
|
-
모든 결과는 공통 `ExtensionResult` 형태입니다.
|
|
62
|
-
|
|
63
|
-
```json
|
|
64
|
-
{
|
|
65
|
-
"summary": "task-42 항목을 수정했어요.",
|
|
66
|
-
"data": {
|
|
67
|
-
"namespace": "tasks",
|
|
68
|
-
"item": {
|
|
69
|
-
"key": "task-42",
|
|
70
|
-
"value": {"title": "과학 보고서", "done": true},
|
|
71
|
-
"revision": 3,
|
|
72
|
-
"created_at": "2026-08-17T01:00:00+00:00",
|
|
73
|
-
"updated_at": "2026-08-17T02:00:00+00:00"
|
|
74
|
-
}
|
|
75
|
-
},
|
|
76
|
-
"evidence": [
|
|
77
|
-
{"type": "plugin_storage", "instance_id": "...", "namespace": "tasks", "key": "task-42", "revision": 3}
|
|
78
|
-
]
|
|
79
|
-
}
|
|
80
|
-
```
|
|
81
|
-
|
|
82
|
-
## Saved Entity
|
|
83
|
-
|
|
84
|
-
AI에서 저장·즐겨찾기한 Plugin 항목은 별도 DB 사본을 만들지 않고 같은 Local Storage의
|
|
85
|
-
`saved_entities` namespace를 source of truth로 사용합니다. UI, Tool, Skill과 AI 표준 Storage Tool이
|
|
86
|
-
같은 key·revision을 읽고 쓰므로 한 경로의 변경이 다른 경로에도 즉시 반영됩니다.
|
|
87
|
-
|
|
88
|
-
```json
|
|
89
|
-
{
|
|
90
|
-
"type": "school.assignment",
|
|
91
|
-
"title": "과학 보고서",
|
|
92
|
-
"subtitle": "금요일까지",
|
|
93
|
-
"description": "실험 결과 정리",
|
|
94
|
-
"url": "https://school.example/assignments/42",
|
|
95
|
-
"image_url": "https://school.example/images/42.png",
|
|
96
|
-
"favorite": true,
|
|
97
|
-
"data": {"due": "2026-08-21"},
|
|
98
|
-
"source_capability": "school_life.assignments"
|
|
99
|
-
}
|
|
100
|
-
```
|
|
101
|
-
|
|
102
|
-
`type`과 `title`은 필수입니다. 선택 필드는 `subtitle`, `description`, HTTPS `url`/`image_url`,
|
|
103
|
-
boolean `favorite`, bounded JSON `data`, 안전한 identifier `source_capability`뿐입니다. CRUD는
|
|
104
|
-
`morit.storage.list/get/create/update/delete`를 그대로 사용하며 기존 namespace 권한, quota,
|
|
105
|
-
revision, generation, credential 차단 검사가 동일하게 적용됩니다.
|
|
106
|
-
|
|
107
|
-
## UI binding과 갱신
|
|
108
|
-
|
|
109
|
-
UI Runtime v2 data source에서 표준 Tool을 그대로 사용합니다.
|
|
110
|
-
|
|
111
|
-
```json
|
|
112
|
-
{
|
|
113
|
-
"id": "saved_tasks",
|
|
114
|
-
"capability": "morit.storage.list",
|
|
115
|
-
"trigger": "load",
|
|
116
|
-
"query": "",
|
|
117
|
-
"arguments": {"namespace": "tasks", "limit": 20}
|
|
118
|
-
}
|
|
119
|
-
```
|
|
120
|
-
|
|
121
|
-
표시는 `data.saved_tasks.data.items`를 source로 사용하는 `list`, 단일 값은
|
|
122
|
-
`{{data.saved_task.data.item.value.title}}`처럼 binding합니다. UI가 Storage create/update/delete를
|
|
123
|
-
완료하거나 AI 응답이 끝나면 Host가 storage revision을 갱신해 Storage data source만 다시 읽습니다.
|
|
124
|
-
앱 재개 시에도 갱신합니다. 일반 Tool 결과 data source는 불필요하게 재실행하지 않습니다.
|
|
125
|
-
서버 Background가 화면과 무관하게 값을 바꾸는 namespace는 source에 `refresh_seconds: 30` 이상을
|
|
126
|
-
선언해 화면이 열린 동안에도 주기적으로 맞춥니다.
|
|
127
|
-
|
|
128
|
-
Tool·Skill·Background capability는 `storage` 권한을 선언하면 동일 Instance의 `plugin_storage`
|
|
129
|
-
snapshot을 읽고, 결과의 `data.host_actions`에 `plugin_storage_set` 또는
|
|
130
|
-
`plugin_storage_delete`를 반환해 같은 canonical 저장소를 원자적으로 변경할 수 있습니다.
|
|
131
|
-
`namespace`를 명시하면 해당 namespace를 사용합니다.
|
|
132
|
-
|
|
133
|
-
## AI 권한과 보안 경계
|
|
134
|
-
|
|
135
|
-
설치 또는 설정에서 사용자가 `ai_storage`를 한 번 허용하면 Morit AI는 매 CRUD마다 다시 승인받지
|
|
136
|
-
않습니다. 하지만 다음 검사는 항상 적용됩니다.
|
|
137
|
-
|
|
138
|
-
- 현재 사용자에게 속하고 활성화된 Instance만 선택
|
|
139
|
-
- 해당 Installation·Instance·namespace와 package generation 일치
|
|
140
|
-
- `ai_access: read`는 list/get만, `read_write`만 mutation 허용
|
|
141
|
-
- 다른 사용자, 다른 Plugin/Instance, 선언하지 않은 namespace 접근 차단
|
|
142
|
-
- key 이름에 credential, password, secret, token, access token, refresh token, API key,
|
|
143
|
-
private key 계열을 저장하지 못하도록 차단
|
|
144
|
-
- 실행 코드·파일 경로·DB 접근은 제공하지 않음
|
|
145
|
-
|
|
146
|
-
Host가 AI에 노출하는 tool handle은 Instance와 capability를 해시한 불투명 ID입니다. AI는 임의
|
|
147
|
-
`instance_id`를 arguments로 넘겨 scope를 바꿀 수 없습니다.
|
|
148
|
-
|
|
149
|
-
## 오류 구분
|
|
150
|
-
|
|
151
|
-
| code | 의미 | 처리 |
|
|
152
|
-
|---|---|---|
|
|
153
|
-
| `PLUGIN_STORAGE_PERMISSION_DENIED` | 권한·namespace·AI access 부족 | 설정과 manifest 확인 |
|
|
154
|
-
| `PLUGIN_STORAGE_NOT_FOUND` | key 없음 | create 여부를 사용자 의도에 따라 결정 |
|
|
155
|
-
| `PLUGIN_STORAGE_QUOTA_EXCEEDED` | 값·namespace·Installation 한도 초과 | 데이터를 줄이거나 정리 |
|
|
156
|
-
| `PLUGIN_STORAGE_CONFLICT` | 중복 create, stale revision/generation | list/get 후 최신 revision으로 재시도 |
|
|
157
|
-
| `PLUGIN_STORAGE_INVALID` | key, JSON, query, arguments 형식 오류 | 입력 수정 |
|
|
158
|
-
|
|
159
|
-
오류를 not-found나 빈 목록으로 바꾸지 마세요. 특히 conflict에서 revision 검사를 제거하면 동시에
|
|
160
|
-
수정한 사용자 데이터를 잃을 수 있습니다.
|
|
161
|
-
|
|
162
|
-
## 업데이트, migration, 삭제, 초기화
|
|
163
|
-
|
|
164
|
-
- 업데이트: 같은 Installation/Instance의 데이터는 유지되고 설치 transaction 안에서 version을
|
|
165
|
-
한 단계씩 올립니다. 각 `(from, namespace)` migration은 한 번만 선언하며 rename 대상 충돌 시
|
|
166
|
-
업데이트 전체가 실패해 이전 package와 데이터가 유지됩니다.
|
|
167
|
-
- `data_policy: purge`: uninstall 때 Plugin Local Storage를 삭제합니다.
|
|
168
|
-
- `data_policy: retain`: uninstall 뒤 같은 사용자·Plugin Installation ID로 재설치할 때 복구합니다.
|
|
169
|
-
- credential, OAuth state, pending action은 retain과 무관하게 별도 보안 수명주기로 정리됩니다.
|
|
170
|
-
- 사용자가 설정의 **저장 데이터 초기화**를 누르면 해당 Instance 데이터만 삭제합니다. HTTP API는
|
|
171
|
-
`DELETE /v1/plugin-instances/{instance_id}/storage`이며 다른 Instance에는 영향이 없습니다.
|
|
172
|
-
- disable은 데이터를 삭제하지 않지만 읽기·쓰기를 모두 막습니다.
|
|
173
|
-
|
|
174
|
-
배포 전에는 두 사용자와 둘 이상의 Instance로 격리, read-only AI mutation 차단, quota,
|
|
175
|
-
stale revision/generation, purge/retain, migration 충돌과 재시작 복원을 검증하세요.
|
|
@@ -1,102 +0,0 @@
|
|
|
1
|
-
# 프로젝트 구조와 fragment
|
|
2
|
-
|
|
3
|
-
## 권장 디렉터리
|
|
4
|
-
|
|
5
|
-
```text
|
|
6
|
-
my-plugin/
|
|
7
|
-
├─ manifest.json
|
|
8
|
-
├─ README.md
|
|
9
|
-
├─ tools/*.json
|
|
10
|
-
├─ skills/*.json
|
|
11
|
-
├─ search/*.json
|
|
12
|
-
├─ notifications/*.json
|
|
13
|
-
├─ background/*.json
|
|
14
|
-
├─ ui/*.json
|
|
15
|
-
├─ credentials/*.json
|
|
16
|
-
├─ slash_commands/*.json
|
|
17
|
-
├─ src/**/*.py
|
|
18
|
-
├─ assets/*.{json,md,txt,png,jpg,jpeg,gif,webp}
|
|
19
|
-
├─ children/*.mplg
|
|
20
|
-
├─ morit-plugin.json
|
|
21
|
-
└─ dist/
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
`morit-plugin.json`과 `dist/`는 개발 상태와 산출물이므로 설치 패키지의 기능 계약이 아닙니다.
|
|
25
|
-
비밀 값도 두 위치에 저장하지 않습니다.
|
|
26
|
-
|
|
27
|
-
## fragment 병합 규칙
|
|
28
|
-
|
|
29
|
-
각 fragment 파일은 UTF-8 JSON 객체 하나입니다. 빌드할 때 파일명을 정렬한 순서로 다음 manifest
|
|
30
|
-
배열에 추가합니다.
|
|
31
|
-
|
|
32
|
-
| 디렉터리 | 대상 배열 | 자동으로 채우는 값 |
|
|
33
|
-
|---|---|---|
|
|
34
|
-
| `capabilities/` | `capabilities` | 없음 |
|
|
35
|
-
| `tools/` | `capabilities` | `kind: "tool"` |
|
|
36
|
-
| `skills/` | `capabilities` | `kind: "skill"` |
|
|
37
|
-
| `search/` | `capabilities` | `kind: "provider"`, `runtime.role: "search"` |
|
|
38
|
-
| `notifications/` | `capabilities` | `kind: "notification"` |
|
|
39
|
-
| `background/` | `capabilities` | `kind: "background"` |
|
|
40
|
-
| `ui/` | `ui_extensions` | 없음 |
|
|
41
|
-
| `credentials/` | `credentials` | 없음 |
|
|
42
|
-
| `slash_commands/` | `slash_commands` | 없음 |
|
|
43
|
-
|
|
44
|
-
같은 값이 fragment에 이미 있으면서 자동 값과 다르면 빌드가 실패합니다. manifest 배열과 fragment
|
|
45
|
-
배열은 합쳐지므로 ID는 전체에서 유일해야 합니다.
|
|
46
|
-
|
|
47
|
-
## source와 패키지에 들어가는 파일
|
|
48
|
-
|
|
49
|
-
검증은 프로젝트의 안전한 상대 POSIX 경로만 읽습니다. 절대 경로, `..`, 역슬래시, Windows 예약명,
|
|
50
|
-
심볼릭 링크는 사용할 수 없습니다. 프로젝트 전체 한도는 1 MiB, 파일 수는 64개, 파일 하나는
|
|
51
|
-
512 KiB입니다. 최종 `.mplg`는 2 MiB 이하입니다.
|
|
52
|
-
|
|
53
|
-
빌드가 설치 패키지에 포함하는 항목은 다음뿐입니다.
|
|
54
|
-
|
|
55
|
-
- fragment를 병합해 만든 `manifest.json`
|
|
56
|
-
- 선택적 `README.md`
|
|
57
|
-
- 선언된 `sandbox_python` entrypoint와 연결된 `src/**/*.py`
|
|
58
|
-
- 허용 확장자의 `assets/`
|
|
59
|
-
- dependency와 정확히 일치하는 `children/*.mplg`
|
|
60
|
-
- `signature.json`
|
|
61
|
-
|
|
62
|
-
fragment 원본은 compiled manifest에 병합되므로 `.mplg` 안에 중복해 넣지 않습니다. `src/*.py`는
|
|
63
|
-
각각 정확히 한 `sandbox_python` capability가 entrypoint로 선언해야 하며, 선언되지 않은 Python
|
|
64
|
-
파일이나 여러 capability가 공유하는 entrypoint는 거부됩니다.
|
|
65
|
-
|
|
66
|
-
## 텍스트와 바이너리
|
|
67
|
-
|
|
68
|
-
JSON, Markdown, 텍스트, Python은 엄격한 UTF-8입니다. PNG/JPEG/WebP/GIF와 child `.mplg`는
|
|
69
|
-
바이너리 그대로 보존됩니다. Cloud sync의 JSON 경계를 지날 때만 바이너리 envelope로 변환되며,
|
|
70
|
-
pull·source ZIP·build 결과에서는 원래 바이트로 복원됩니다.
|
|
71
|
-
|
|
72
|
-
UI에서 참조하는 package 이미지는 최대 512 KiB이고 가로·세로가 각각 4096 px 이하여야 합니다.
|
|
73
|
-
정적 이미지는 1 frame, GIF/WebP 애니메이션은 최대 128 frame이며 `width × height × frame 수`로
|
|
74
|
-
계산한 frame 합산 pixel은 최대 16,000,000입니다. 확장자·MIME에 대응하는 magic byte와 실제 이미지
|
|
75
|
-
포맷도 일치해야 합니다.
|
|
76
|
-
|
|
77
|
-
### 웹 프로젝트에서 아이콘 올리기
|
|
78
|
-
|
|
79
|
-
developers.moring.co의 **플러그인 프로젝트 관리 → 정보 → 앱 아이콘**에서는 PNG, JPEG, WebP
|
|
80
|
-
파일을 직접 선택하거나 끌어 놓을 수 있습니다. 업로드가 완료되면 이미지는
|
|
81
|
-
`assets/plugin-icon.*`에 저장되고 `manifest.icon`도 같은 revision에서 함께 갱신됩니다. 기존에 이
|
|
82
|
-
화면에서 올린 아이콘을 교체하거나 제거할 때도 파일과 manifest가 원자적으로 함께 반영됩니다.
|
|
83
|
-
|
|
84
|
-
아이콘은 512 KiB 이하, 가로·세로 각각 4096 px 이하, 전체 16,000,000 pixel 이하만 허용됩니다.
|
|
85
|
-
확장자만 바꾼 파일이나 실제 포맷이 다른 이미지는 서버 검증에서 거부됩니다. MCP가 바이너리 파일을
|
|
86
|
-
직접 전송하지 못하더라도 이 화면에서 한 번 올린 아이콘은 프로젝트 source에 포함되므로 이후 MCP,
|
|
87
|
-
CLI pull·build에서도 원래 이미지 바이트와 `manifest.icon` 경로가 그대로 유지됩니다.
|
|
88
|
-
|
|
89
|
-
## 파일별 책임
|
|
90
|
-
|
|
91
|
-
- `manifest.json`: 패키지 신원, 버전, 전역 권한, 연결과 데이터 정책
|
|
92
|
-
- capability fragment: AI나 UI가 실행할 한 가지 작업
|
|
93
|
-
- UI fragment: Host가 표시할 화면과 capability 참조
|
|
94
|
-
- credential/connector: 사용자 계정 또는 Cloud 비밀 값과 외부 endpoint의 연결
|
|
95
|
-
- `src/`: 검증되고 격리된 Python 작업만 포함
|
|
96
|
-
- `assets/`: 아이콘·정적 데이터·설명 자료
|
|
97
|
-
- `children/`: 함께 설치할 별도 서명 플러그인
|
|
98
|
-
|
|
99
|
-
화면 문구, 외부 endpoint, 비밀 값, 사용자 설정을 한 JSON에 섞지 마세요. 바뀌는 주기와 접근 권한이
|
|
100
|
-
다른 정보는 각각 UI, Connector, Secret, settings에 둡니다.
|
|
101
|
-
|
|
102
|
-
다음은 [Manifest 레퍼런스](manifest.md)입니다.
|
|
@@ -1,158 +0,0 @@
|
|
|
1
|
-
# 원격 Plugin MCP
|
|
2
|
-
|
|
3
|
-
Remote Plugin MCP는 파일시스템이 없는 AI client가 Morit 조직의 Cloud Project를 만들고 검증·배포할
|
|
4
|
-
수 있게 하는 OAuth 보호 Streamable HTTP 서비스입니다.
|
|
5
|
-
|
|
6
|
-
```text
|
|
7
|
-
https://morit-api.moring.co/mcp
|
|
8
|
-
```
|
|
9
|
-
|
|
10
|
-
인증 전 응답은 `401`과 RFC 9728 protected-resource metadata 위치를 반환합니다. Morit SSO의
|
|
11
|
-
authorization code + PKCE 흐름으로 로그인하며 승인된 scope와 사용자 RLS를 모든 Tool에 적용합니다.
|
|
12
|
-
|
|
13
|
-
## 연결
|
|
14
|
-
|
|
15
|
-
Codex:
|
|
16
|
-
|
|
17
|
-
```bash
|
|
18
|
-
codex mcp add morit-plugin-remote --url https://morit-api.moring.co/mcp
|
|
19
|
-
codex mcp login morit-plugin-remote
|
|
20
|
-
```
|
|
21
|
-
|
|
22
|
-
Claude Code:
|
|
23
|
-
|
|
24
|
-
```bash
|
|
25
|
-
claude mcp add --transport http --scope user \
|
|
26
|
-
morit-plugin-remote https://morit-api.moring.co/mcp
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
## Tool 목록
|
|
30
|
-
|
|
31
|
-
### 계약과 문서
|
|
32
|
-
|
|
33
|
-
| Tool | 목적 |
|
|
34
|
-
|---|---|
|
|
35
|
-
| `morit_sdk_contract` | SDK 1.7.8 Theme·Storage·UI/Host capability contract 전체 반환 |
|
|
36
|
-
| `morit_docs_search` | bundled 공식 문서 검색 |
|
|
37
|
-
| `morit_docs_get` | 검색 결과의 Markdown 한 파일 읽기 |
|
|
38
|
-
|
|
39
|
-
### 조직과 Project
|
|
40
|
-
|
|
41
|
-
| Tool | 목적 |
|
|
42
|
-
|---|---|
|
|
43
|
-
| `morit_organization_list` | 접근 가능한 조직과 role 조회 |
|
|
44
|
-
| `morit_project_list` | 조직의 Cloud Project 목록 |
|
|
45
|
-
| `morit_project_create` | 표준 source를 가진 Project 생성 |
|
|
46
|
-
| `morit_project_files_get` | 최신 revision과 source snapshot 읽기 |
|
|
47
|
-
| `morit_project_files_put` | revision 보호를 적용한 파일 생성·수정·삭제 |
|
|
48
|
-
| `morit_project_metadata_update` | Marketplace 표시 metadata 변경 |
|
|
49
|
-
| `morit_project_delete` | 활성 Deployment가 없는 Project 삭제 |
|
|
50
|
-
|
|
51
|
-
### 검증과 artifact
|
|
52
|
-
|
|
53
|
-
| Tool | 목적 |
|
|
54
|
-
|---|---|
|
|
55
|
-
| `morit_project_validate` | 현재 revision의 source 계약 검사 |
|
|
56
|
-
| `morit_project_preview` | light/dark 토글을 포함한 script-free private HTML preview 생성 |
|
|
57
|
-
| `morit_project_source_download` | 편집 가능한 source ZIP 생성 |
|
|
58
|
-
| `morit_build_start` | immutable build/Deployment 시작 |
|
|
59
|
-
| `morit_build_status` | build state와 package artifact 조회 |
|
|
60
|
-
| `morit_artifact_download` | owned artifact의 짧은 수명 download URL 생성 |
|
|
61
|
-
|
|
62
|
-
### Deployment
|
|
63
|
-
|
|
64
|
-
| Tool | 목적 |
|
|
65
|
-
|---|---|
|
|
66
|
-
| `morit_deployment_list` | Project의 immutable Deployment history |
|
|
67
|
-
| `morit_deployment_get` | build 결과, hash, logs, visibility 조회 |
|
|
68
|
-
| `morit_deployment_publish` | completed Deployment를 private/public current로 설정 |
|
|
69
|
-
|
|
70
|
-
### Secret과 Connection
|
|
71
|
-
|
|
72
|
-
| Tool | 목적 |
|
|
73
|
-
|---|---|
|
|
74
|
-
| `morit_project_secret_list` | Secret ID와 masked metadata 조회 |
|
|
75
|
-
| `morit_project_secret_put` | encrypted Secret 생성·rotation |
|
|
76
|
-
| `morit_project_secret_delete` | 참조되지 않는 Secret 삭제 |
|
|
77
|
-
| `morit_project_connection_list` | OAuth/API Connection 선언 조회 |
|
|
78
|
-
| `morit_project_connection_put` | Connection 생성·수정 |
|
|
79
|
-
| `morit_project_connection_delete` | Connection 선언 삭제 |
|
|
80
|
-
|
|
81
|
-
Secret Tool은 평문을 반환하지 않습니다. source, log, Tool 응답에 Secret 값을 복사하지 마세요.
|
|
82
|
-
|
|
83
|
-
## ID와 경로
|
|
84
|
-
|
|
85
|
-
- organization, Project, Deployment, artifact ID는 `format: uuid`입니다.
|
|
86
|
-
- Manifest plugin ID는 소문자 reverse-domain ID입니다.
|
|
87
|
-
- source path는 상대 POSIX 형식입니다.
|
|
88
|
-
- `..`, 역슬래시, 절대 경로, Windows 예약명, symlink는 거부합니다.
|
|
89
|
-
- `manifest.json`은 삭제할 수 없습니다.
|
|
90
|
-
- 한 파일 512 KiB, source 최대 64개 파일·1 MiB입니다.
|
|
91
|
-
- 한 `files_put` 변경은 최대 64개입니다.
|
|
92
|
-
|
|
93
|
-
AI가 UUID나 경로를 추측하지 않고 list/create/get 결과를 그대로 다음 Tool에 전달해야 합니다.
|
|
94
|
-
|
|
95
|
-
## Revision과 파일 변경
|
|
96
|
-
|
|
97
|
-
```json
|
|
98
|
-
{
|
|
99
|
-
"project_id": "00000000-0000-4000-8000-000000000000",
|
|
100
|
-
"revision": 3,
|
|
101
|
-
"files": {
|
|
102
|
-
"ui/home.json": "{...}\n",
|
|
103
|
-
"ui/old.json": null
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
```
|
|
107
|
-
|
|
108
|
-
`null`은 파일 삭제입니다. revision이 오래되면 전체 요청을 거부하고 최신 source를 반환하므로
|
|
109
|
-
`files_get` → 변경 병합 → `files_put`을 반복합니다. conflict를 `force`로 숨기지 않습니다.
|
|
110
|
-
|
|
111
|
-
이미지 asset과 child `.mplg`는 `morit-base64-v1:<canonical-base64>` binary envelope로만 JSON
|
|
112
|
-
경계를 지나며 MIME magic과 경로를 검증합니다. 최종 source ZIP과
|
|
113
|
-
package에서는 원래 바이트로 복원됩니다.
|
|
114
|
-
|
|
115
|
-
Theme/Storage를 생성·수정할 때는 contract의 `ui_runtime.theme_*`, `storage_tools`,
|
|
116
|
-
`storage_ai_access`, `storage_limits`를 기준으로 Manifest와 UI fragment를 함께 변경합니다. Remote
|
|
117
|
-
MCP validation은 Host와 같은 잘못된 token, 확정적으로 보이지 않는 색 조합, namespace/permission,
|
|
118
|
-
migration과 binding 오류를 거부하고 정적으로 확정하기 어려운 대비는 warning으로 반환합니다.
|
|
119
|
-
|
|
120
|
-
## Build와 다운로드
|
|
121
|
-
|
|
122
|
-
```text
|
|
123
|
-
morit_build_start
|
|
124
|
-
→ job_id와 deployment_id
|
|
125
|
-
morit_build_status 반복
|
|
126
|
-
→ completed + artifact_id + size + sha256
|
|
127
|
-
morit_deployment_get
|
|
128
|
-
→ exact artifact hash와 visibility
|
|
129
|
-
morit_artifact_download
|
|
130
|
-
→ 짧은 수명 URL
|
|
131
|
-
```
|
|
132
|
-
|
|
133
|
-
같은 요청을 재시도할 때 새 build가 생성될 수 있으므로 반환된 ID를 섞지 않습니다. status가
|
|
134
|
-
`failed`이면 logs의 공개 진단을 source에 반영하고 새 build를 시작합니다. `processing`을 완료로
|
|
135
|
-
간주하지 않습니다.
|
|
136
|
-
|
|
137
|
-
## Protocol compatibility
|
|
138
|
-
|
|
139
|
-
서비스는 직접 `tools/list`/`tools/call`을 보내는 최신 handshake-free client와
|
|
140
|
-
initialize → initialized → Tool 호출 방식의 client를 모두 지원합니다. `MCP-Protocol-Version`과
|
|
141
|
-
`Mcp-Method`/`Mcp-Name` 같은 routing header는 서버가 협상한 값과 맞춰야 합니다. 지원 protocol
|
|
142
|
-
date는 서비스 응답을 사용하며 client가 임의로 고정하지 않습니다.
|
|
143
|
-
|
|
144
|
-
## 복구
|
|
145
|
-
|
|
146
|
-
| 오류 | 대응 |
|
|
147
|
-
|---|---|
|
|
148
|
-
| `401` | OAuth metadata를 따라 로그인 |
|
|
149
|
-
| scope 부족 | 필요한 scope를 사용자에게 명시하고 재승인 |
|
|
150
|
-
| Project 없음 | 현재 조직과 Project ID 확인 |
|
|
151
|
-
| revision conflict | 최신 source를 읽고 병합 |
|
|
152
|
-
| validation 오류 | 반환된 정확한 field/reference 진단 수정 |
|
|
153
|
-
| build timeout | status로 기존 build 확인 후 필요한 경우 새 build |
|
|
154
|
-
| artifact 만료 | 같은 artifact ID로 새 download URL 발급 |
|
|
155
|
-
| Secret 참조 중 | Connection 참조를 먼저 정리 |
|
|
156
|
-
|
|
157
|
-
로컬 파일을 직접 편집해야 하면 [Local MCP](sdk-and-mcp.md)를 사용합니다. Remote 서비스에 local
|
|
158
|
-
absolute path나 publisher private key를 전달하지 않습니다.
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
# 학교 생활 플러그인 개인정보 처리 안내
|
|
2
|
-
|
|
3
|
-
최종 수정일: 2026-08-17
|
|
4
|
-
|
|
5
|
-
학교 생활 플러그인은 학생이 선택한 학교, 학년, 반을 기준으로 시간표·급식·학사일정을
|
|
6
|
-
보여 주고 기기 안에서 알림과 아침 브리핑을 구성합니다. 플러그인 설치 전에 아래 데이터
|
|
7
|
-
사용 범위를 확인할 수 있으며, 설치 후 설정에서 언제든 초기화하거나 삭제할 수 있습니다.
|
|
8
|
-
|
|
9
|
-
## 사용하는 정보
|
|
10
|
-
|
|
11
|
-
- 사용자가 직접 선택한 학교 코드, 교육청 코드, 학년, 반
|
|
12
|
-
- 알레르기 필터, 알림 사용 여부와 알림 시간
|
|
13
|
-
- 중복 알림을 막기 위한 마지막 실행 날짜
|
|
14
|
-
- 사용자가 Morit AI에 추가·수정·완료·삭제를 요청한 학교 할 일
|
|
15
|
-
- 교육부 NEIS 공개 API가 제공하는 시간표, 급식, 학사일정
|
|
16
|
-
|
|
17
|
-
이 플러그인은 이름, 주민등록번호, 학생 번호, 성적, 연락처, 계정 비밀번호를 요청하거나
|
|
18
|
-
수집하지 않습니다. 별도의 OAuth 계정이나 API key도 요구하지 않습니다.
|
|
19
|
-
|
|
20
|
-
## 처리 목적과 저장 위치
|
|
21
|
-
|
|
22
|
-
학교·학년·반 설정은 사용자가 요청한 학교 정보를 반복 입력하지 않도록 해당 Morit
|
|
23
|
-
사용자의 Plugin Instance 저장소에만 보관합니다. 조회한 공개 학교 정보는 화면 표시와
|
|
24
|
-
알림 생성에만 사용합니다. 다른 사용자나 다른 Instance와 공유하지 않습니다.
|
|
25
|
-
|
|
26
|
-
학교 할 일은 `tasks` namespace에 저장됩니다. 사용자가 설치/설정에서 `ai_storage` 권한을 허용하면
|
|
27
|
-
Morit AI가 이 namespace를 별도 매 작업 승인 없이 읽고 변경할 수 있습니다. Host는 현재 사용자와
|
|
28
|
-
활성 Instance를 고정하고 다른 namespace·사용자·플러그인 접근을 차단합니다.
|
|
29
|
-
|
|
30
|
-
외부 요청은 선언된 NEIS HTTPS endpoint로만 제한되며 Morit의 SSRF filtering proxy를
|
|
31
|
-
통과합니다. 플러그인 코드에는 운영 credential이나 사용자 token이 포함되지 않습니다.
|
|
32
|
-
|
|
33
|
-
## 보관과 삭제
|
|
34
|
-
|
|
35
|
-
Manifest의 data policy는 `purge`입니다. 사용자가 Plugin Instance 또는 플러그인을
|
|
36
|
-
삭제하면 해당 Instance의 설정, 조회 cache, 알림 상태를 함께 삭제합니다. 앱 데이터
|
|
37
|
-
초기화 후 서버에 남은 개인 Plugin Instance도 계정의 플러그인 관리 화면에서 삭제할 수
|
|
38
|
-
있습니다.
|
|
39
|
-
|
|
40
|
-
## 권한
|
|
41
|
-
|
|
42
|
-
- 네트워크: NEIS 공개 학교 정보 조회
|
|
43
|
-
- 저장소: 학교·학년·반과 사용자 설정 저장
|
|
44
|
-
- AI 저장소: 사용자가 허용한 경우 학교 할 일 목록의 조회·추가·수정·삭제
|
|
45
|
-
- 알림: 사용자가 켠 경우 다음 학교 일정과 아침 브리핑 알림 예약
|
|
46
|
-
- 백그라운드: 사용자가 켠 경우 공개 학교 정보 갱신과 브리핑 준비
|
|
47
|
-
|
|
48
|
-
권한이 꺼져 있거나 네트워크가 실패하면 해당 기능만 사용할 수 없다는 상태를 표시하며,
|
|
49
|
-
오류를 숨기거나 임의의 학교 정보를 생성하지 않습니다.
|
|
50
|
-
|
|
51
|
-
## 문의와 변경
|
|
52
|
-
|
|
53
|
-
플러그인 기능과 구현은 [학교 생활 예제 문서](examples-school-life.md)에서 확인할 수
|
|
54
|
-
있습니다. 처리 항목이나 외부 제공 범위가 바뀌면 새 Plugin version과 이 문서를 함께
|
|
55
|
-
갱신하며, 권한이 추가되는 경우 사용자가 설치 전에 다시 확인할 수 있게 표시합니다.
|
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
# 화면, 레이아웃, 내비게이션
|
|
2
|
-
|
|
3
|
-
플러그인 UI는 “어디에 나타나는가”를 정하는 extension point와 “무엇을 그리는가”를 정하는 Runtime
|
|
4
|
-
tree로 나뉩니다. 먼저 사용자 흐름을 화면 단위로 나눈 뒤 각 화면의 JSON을 작성하세요.
|
|
5
|
-
|
|
6
|
-
## 화면 역할부터 정하기
|
|
7
|
-
|
|
8
|
-
| 사용자 목적 | extension point | 권장 내용 |
|
|
9
|
-
|---|---|---|
|
|
10
|
-
| 홈에서 상태를 빠르게 확인 | `card` | 핵심 상태 1~3개와 명확한 다음 행동 |
|
|
11
|
-
| 홈에서 즉시 실행 | `action` | 짧은 라벨의 단일 행동 |
|
|
12
|
-
| 플러그인의 주 작업 | `screen` | 목록, 상세, 편집 등 독립 화면 |
|
|
13
|
-
| 홈 메뉴 진입점 | `menu` | 자주 찾지만 상시 노출할 필요 없는 화면 |
|
|
14
|
-
| 플러그인 설정 | `settings` | 권한, 알림, 표시 옵션, 계정 진입 |
|
|
15
|
-
| AI와 함께 작업 | `workspace` | 대화 맥락과 함께 보는 도구 화면 |
|
|
16
|
-
| AI 실행 결과 | `response` | 해당 AI 메시지에 붙는 읽기 중심 결과 |
|
|
17
|
-
|
|
18
|
-
`surface`는 기존 패키지 호환용 일반 화면 point입니다. 새 독립 화면에는 역할이 더 명확한
|
|
19
|
-
`screen`을 사용합니다.
|
|
20
|
-
|
|
21
|
-
## 권장 화면 흐름
|
|
22
|
-
|
|
23
|
-
```text
|
|
24
|
-
Home card/action
|
|
25
|
-
→ Overview screen
|
|
26
|
-
├─ List/filter state
|
|
27
|
-
├─ Detail screen
|
|
28
|
-
└─ Edit dialog 또는 sheet
|
|
29
|
-
|
|
30
|
-
Plugin detail
|
|
31
|
-
→ Settings screen
|
|
32
|
-
├─ Account connections
|
|
33
|
-
├─ Notifications
|
|
34
|
-
└─ Display preferences
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
첫 화면은 사용자가 현재 상태와 다음 행동을 5초 안에 파악할 수 있어야 합니다. 원시 JSON,
|
|
38
|
-
capability ID, package ID, 디버그 상태는 사용자 화면에 두지 않습니다.
|
|
39
|
-
|
|
40
|
-
## 레이아웃 선택
|
|
41
|
-
|
|
42
|
-
- `column`: 기본 읽기 흐름. 모바일에서 가장 안전한 시작점입니다.
|
|
43
|
-
- `row`: 짧은 상태와 행동을 나란히 놓을 때 사용합니다. 좁은 폭에서는 `stack_at`으로 세로 전환합니다.
|
|
44
|
-
- `wrap`: chip이나 짧은 필터처럼 항목 너비가 다른 반복 요소에 사용합니다.
|
|
45
|
-
- `grid`: 같은 중요도의 카드·metric을 반복할 때 사용합니다. `min_item_width`로 열 수를 줄입니다.
|
|
46
|
-
- `section`: 제목이 있는 정보 그룹입니다. 한 화면에 section이 너무 많아지면 화면을 분리합니다.
|
|
47
|
-
- `card`: 배경과 경계가 필요한 독립 정보나 누를 수 있는 요약에 사용합니다.
|
|
48
|
-
|
|
49
|
-
중첩 card와 section을 장식 목적으로 반복하지 마세요. 부모 하나로 관계가 설명되면 추가 surface는
|
|
50
|
-
정보 계층을 흐립니다.
|
|
51
|
-
|
|
52
|
-
## 내비게이션
|
|
53
|
-
|
|
54
|
-
같은 플러그인의 다른 UI extension으로 이동할 때 `navigate`를 사용합니다.
|
|
55
|
-
|
|
56
|
-
```json
|
|
57
|
-
{
|
|
58
|
-
"type": "button",
|
|
59
|
-
"props": {"label": "전체 시간표 보기", "style": "tonal"},
|
|
60
|
-
"action": {"type": "navigate", "target": "school_life.week"}
|
|
61
|
-
}
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
`target`은 같은 manifest에 선언된 UI extension ID여야 합니다. 현재 화면을 닫고 이전 Host 화면으로
|
|
65
|
-
돌아갈 때는 `back`을 사용합니다.
|
|
66
|
-
|
|
67
|
-
```json
|
|
68
|
-
{"type": "back"}
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
탭처럼 보여야 하는 단순 필터는 새 화면을 만들지 말고 `chip`과 `set_state`로 처리합니다. 반대로
|
|
72
|
-
목록과 상세처럼 제목, 스크롤 위치, 뒤로가기 의미가 달라지는 정보는 별도 `screen`으로 나눕니다.
|
|
73
|
-
|
|
74
|
-
## 상단 메뉴와 설정
|
|
75
|
-
|
|
76
|
-
Host가 화면 제목, 뒤로가기, 플러그인 메뉴를 담당합니다. JSON tree에서 별도 앱 바를 흉내 내지
|
|
77
|
-
않습니다. 화면의 overflow 메뉴는 해당 화면에서 자주 쓰지 않는 보조 행동만 담습니다. 계정 연결은
|
|
78
|
-
settings 화면의 Connection 관리로 제공하며 동일 패키지 root Instance를 복제하는 “계정 추가”
|
|
79
|
-
동작을 만들지 않습니다.
|
|
80
|
-
|
|
81
|
-
## 상태별 화면
|
|
82
|
-
|
|
83
|
-
한 data source에는 적어도 다음 상태를 고려합니다.
|
|
84
|
-
|
|
85
|
-
| 상태 | 화면 동작 |
|
|
86
|
-
|---|---|
|
|
87
|
-
| 첫 로딩 | 기존 레이아웃 크기를 유지하는 진행 표시 |
|
|
88
|
-
| 데이터 없음 | 무엇이 비었는지와 시작 행동을 설명하는 `empty` |
|
|
89
|
-
| 재시도 가능 오류 | 원인 요약과 `refresh` 행동 |
|
|
90
|
-
| 권한·연결 필요 | 필요한 권한/계정과 설정 진입 |
|
|
91
|
-
| 갱신 실패 + 기존 데이터 | 기존 내용을 유지하고 작은 상태 안내 |
|
|
92
|
-
|
|
93
|
-
전체 화면을 한 data source의 오류로 교체하지 않습니다. 오류는 영향을 받은 section에 격리합니다.
|
|
94
|
-
|
|
95
|
-
다음은 [기본·커스텀 컴포넌트](components.md)입니다.
|