@ssobig/writer-cli 0.2.2 → 0.3.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 (39) hide show
  1. package/README.md +19 -0
  2. package/asset-repository.js +7 -2
  3. package/config.js +2 -1
  4. package/package.json +1 -1
  5. package/templates/mystery-v1/authoring-view-preference.js +22 -5
  6. package/templates/mystery-v1/character-perspective-preview.js +3 -3
  7. package/templates/mystery-v1/codemirror6-runtime.min.js +28 -0
  8. package/templates/mystery-v1/component-asset-operations.js +19 -6
  9. package/templates/mystery-v1/component-catalog-contract.js +26 -35
  10. package/templates/mystery-v1/component-draft-operations.js +19 -8
  11. package/templates/mystery-v1/component-field-contracts.js +127 -51
  12. package/templates/mystery-v1/component-id-policy.js +1 -1
  13. package/templates/mystery-v1/component-manager.js +21 -11
  14. package/templates/mystery-v1/component-navigation-counts.js +9 -9
  15. package/templates/mystery-v1/component-registry.js +11 -5
  16. package/templates/mystery-v1/component-renderers.js +12 -8
  17. package/templates/mystery-v1/component-storage-contract.js +28 -9
  18. package/templates/mystery-v1/markdown-document-model.js +444 -0
  19. package/templates/mystery-v1/markdown-image-editor.js +320 -0
  20. package/templates/mystery-v1/markdown-live-editor.js +1224 -0
  21. package/templates/mystery-v1/page-header.js +2 -1
  22. package/templates/mystery-v1/timeline-model.js +235 -0
  23. package/tools/writer-cli/package-lock.json +2 -2
  24. package/tools/writer-cli/package.json +1 -1
  25. package/tools/writer-cli/skills/ssobig-writer-cli/SKILL.md +13 -14
  26. package/tools/writer-cli/skills/ssobig-writer-cli/references/assets-checkpoints.md +5 -1
  27. package/tools/writer-cli/skills/ssobig-writer-cli/references/errors.md +4 -1
  28. package/tools/writer-cli/skills/ssobig-writer-cli/references/install-auth.md +3 -3
  29. package/tools/writer-cli/skills/ssobig-writer-cli/references/investigation-board.md +9 -0
  30. package/tools/writer-cli/skills/ssobig-writer-cli/references/layout-spec.md +130 -0
  31. package/tools/writer-cli/skills/ssobig-writer-cli/references/projects-components.md +8 -2
  32. package/tools/writer-cli/skills/ssobig-writer-cli/references/read-search.md +12 -2
  33. package/tools/writer-cli/src/agent-service.cjs +3 -1
  34. package/tools/writer-cli/src/command-registry.cjs +24 -20
  35. package/tools/writer-cli/src/commands.cjs +106 -3
  36. package/tools/writer-cli/src/domain.cjs +296 -1
  37. package/tools/writer-cli/src/gateway.cjs +14 -0
  38. package/tools/writer-cli/src/mutations.cjs +167 -1
  39. package/tools/writer-cli/src/project-import.cjs +27 -22
package/README.md CHANGED
@@ -17,12 +17,27 @@ ssobig-writer project list
17
17
 
18
18
  CLI는 stdout에 JSON 문서 하나를 출력한다. 원고 변경은 `plan -> 사람 검토 -> apply -> authoritative read-back` 절차만 사용하며, 범용 SQL이나 직접 table update를 제공하지 않는다.
19
19
 
20
+ 작품 구성 화면의 등록된 선택 Component 추가·사용 여부와 선택 속성도 같은 절차로 변경할 수 있다.
21
+
22
+ ```bash
23
+ ssobig-writer component plan-add --project <slug> --template ssobig.timeline --out .ssobig-writer/component-add.plan.json
24
+ ssobig-writer apply .ssobig-writer/component-add.plan.json --receipt .ssobig-writer/component-add.receipt.json
25
+
26
+ ssobig-writer component plan-set-active --project <slug> --instance timeline --active false --out .ssobig-writer/component-archive.plan.json
27
+ ssobig-writer component plan-set-field --project <slug> --instance clues --field image --enabled false --out .ssobig-writer/field.plan.json
28
+ ```
29
+
30
+ patch·spec·plan·receipt는 기밀 원고를 포함할 수 있으므로 ignored `.ssobig-writer/` 또는 private 경로에 보관하고 커밋하지 않는다.
31
+
32
+ plan에서 대상, 보존할 data, 생성·제거될 View·binding 또는 `enabledOptionalFields` 변경을 먼저 검토해야 한다. 사용 안 함은 data를 삭제하지 않고 보관하며, 필수·내부·미등록 Component와 필수·미등록 속성 및 임의 구성 변경은 허용하지 않는다.
33
+
20
34
  ## 업데이트와 제거
21
35
 
22
36
  ```bash
23
37
  ssobig-writer version --check
24
38
  npm install --global @ssobig/writer-cli@latest
25
39
  ssobig-writer skills status --target <내-workspace>
40
+ # status가 missing이면 install, update-available이면 update, current이면 추가 작업 없음
26
41
  ssobig-writer skills update --target <내-workspace>
27
42
 
28
43
  ssobig-writer auth logout
@@ -39,3 +54,7 @@ CLI를 업데이트한 뒤에는 각 작업공간에서 `skills status`를 확
39
54
  `doctor`는 설치·최신 버전·credential session 존재·Auth health·실행 backend 버전을 읽기 전용으로 진단하고 token, 이메일, 원고 값을 출력하지 않는다. macOS 세션은 Keychain에 저장되고 private Unix daemon을 사용한다. Windows 세션은 현재 Windows 사용자만 해독할 수 있도록 DPAPI CurrentUser로 보호되며 CLI는 background daemon 대신 in-process backend를 자동 사용한다. 따라서 Windows에서는 `agent start`와 `agent stop`이 지원되지 않는다.
40
55
 
41
56
  상세 설치, 업데이트, 삭제 방법은 [SSOBIG WRITER 운영 가이드](https://writer.ssobig.com/)에서 확인한다.
57
+
58
+ ## 작업별 안내
59
+
60
+ 설치된 `ssobig-writer-cli` 스킬은 필요한 참조만 선택한다. 패키지 안에서도 [조회와 검색](tools/writer-cli/skills/ssobig-writer-cli/references/read-search.md), [변경 계획](tools/writer-cli/skills/ssobig-writer-cli/references/projects-components.md), [추리 보드와 spec](tools/writer-cli/skills/ssobig-writer-cli/references/investigation-board.md), [오류 복구](tools/writer-cli/skills/ssobig-writer-cli/references/errors.md)를 읽을 수 있다.
@@ -30,18 +30,23 @@
30
30
  if (typeof options.putLocalAsset !== "function") throw new TypeError("에셋 복원에는 putLocalAsset 함수가 필요합니다.");
31
31
  const queue = buildAssetRestorePlan(manifest);
32
32
  const restoredLocalAssetIds = [];
33
+ const retainedLocalAssetIds = [];
33
34
  const concurrency = Math.max(1, Number(options.concurrency || 6));
34
35
  const workers = Array.from({ length: Math.min(concurrency, queue.length) }, async () => {
35
36
  while (queue.length) {
36
37
  const entry = queue.shift();
38
+ if (typeof options.isLocalAssetCurrent === "function" && await options.isLocalAssetCurrent(entry)) {
39
+ retainedLocalAssetIds.push(entry.localAssetId);
40
+ continue;
41
+ }
37
42
  const blob = await options.downloadAsset(entry);
38
43
  if (!blob) continue;
39
- await options.putLocalAsset(entry.localAssetId, blob);
44
+ await options.putLocalAsset(entry.localAssetId, blob, entry);
40
45
  restoredLocalAssetIds.push(entry.localAssetId);
41
46
  }
42
47
  });
43
48
  await Promise.all(workers);
44
- return { clearLocalAssetIds: [], restoredLocalAssetIds };
49
+ return { clearLocalAssetIds: [], restoredLocalAssetIds, retainedLocalAssetIds };
45
50
  }
46
51
 
47
52
  async function defaultContentHash(blob) {
package/config.js CHANGED
@@ -9,6 +9,7 @@
9
9
  supabaseUrl: "https://tlyioijsopxeegzfjlqe.supabase.co",
10
10
  supabaseKey: "sb_publishable_AdEHgXPGJ2gKGVAjb7RYSg_YzUuT6jB",
11
11
  assetBucket: "ssobig-writer-assets",
12
- staffDomain: "ssobig.com"
12
+ staffDomain: "ssobig.com",
13
+ sentryDsn: "https://d9d4a549fafe2f35be1827e5097ea7e8@o4505765760204800.ingest.us.sentry.io/4511998281449472"
13
14
  });
14
15
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ssobig/writer-cli",
3
- "version": "0.2.2",
3
+ "version": "0.3.2",
4
4
  "description": "Official agent CLI for SSOBIG WRITER",
5
5
  "type": "commonjs",
6
6
  "license": "UNLICENSED",
@@ -8,6 +8,7 @@
8
8
  const STORAGE_KEY = "somi-workbench-authoring-view";
9
9
  const DEFAULT_VIEW = "preview";
10
10
  const VIEWS = Object.freeze(["input", "preview"]);
11
+ const STORAGE_VERSION = 1;
11
12
 
12
13
  function normalize(value) {
13
14
  return VIEWS.includes(value) ? value : DEFAULT_VIEW;
@@ -18,17 +19,33 @@
18
19
  catch (_) { return null; }
19
20
  }
20
21
 
21
- function read(storage = deviceStorage()) {
22
- try { return normalize(storage?.getItem(STORAGE_KEY)); }
22
+ function parseStoredValue(value) {
23
+ if (VIEWS.includes(value)) return { fallback: value, views: {} };
24
+ try {
25
+ const parsed = JSON.parse(value || "null");
26
+ if (parsed?.version !== STORAGE_VERSION || !parsed.views || typeof parsed.views !== "object" || Array.isArray(parsed.views)) return { fallback: DEFAULT_VIEW, views: {} };
27
+ return { fallback: normalize(parsed.fallback), views: { ...parsed.views } };
28
+ } catch (_) { return { fallback: DEFAULT_VIEW, views: {} }; }
29
+ }
30
+
31
+ function read(scope, storage = deviceStorage()) {
32
+ try {
33
+ const stored = parseStoredValue(storage?.getItem(STORAGE_KEY));
34
+ return normalize(stored.views[String(scope || "")] || stored.fallback);
35
+ }
23
36
  catch (_) { return DEFAULT_VIEW; }
24
37
  }
25
38
 
26
- function write(view, storage = deviceStorage()) {
39
+ function write(scope, view, storage = deviceStorage()) {
27
40
  const normalized = normalize(view);
28
- try { storage?.setItem(STORAGE_KEY, normalized); }
41
+ try {
42
+ const stored = parseStoredValue(storage?.getItem(STORAGE_KEY));
43
+ stored.views[String(scope || "")] = normalized;
44
+ storage?.setItem(STORAGE_KEY, JSON.stringify({ version: STORAGE_VERSION, fallback: stored.fallback, views: stored.views }));
45
+ }
29
46
  catch (_) { /* 기기 저장소를 사용할 수 없어도 현재 화면 전환은 유지한다. */ }
30
47
  return normalized;
31
48
  }
32
49
 
33
- return Object.freeze({ STORAGE_KEY, DEFAULT_VIEW, VIEWS, normalize, read, write });
50
+ return Object.freeze({ STORAGE_KEY, STORAGE_VERSION, DEFAULT_VIEW, VIEWS, normalize, read, write });
34
51
  });
@@ -6,9 +6,9 @@
6
6
  "use strict";
7
7
 
8
8
  const CARD_ORDER = Object.freeze([
9
- Object.freeze({ key: "progress", label: "진행", templateId: "ssobig.progress" }),
10
- Object.freeze({ key: "common", label: "공통정보", templateId: "ssobig.common" }),
11
- Object.freeze({ key: "character", label: "캐릭터", templateId: "ssobig.character" })
9
+ Object.freeze({ key: "progress", label: "진행 순서", templateId: "ssobig.progress" }),
10
+ Object.freeze({ key: "common", label: "공통 문서", templateId: "ssobig.common" }),
11
+ Object.freeze({ key: "character", label: "캐릭터별 문서", templateId: "ssobig.character" })
12
12
  ]);
13
13
 
14
14
  function characters(instance, data) {