mosage 0.1.0
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/LICENSE +21 -0
- package/README.en.md +57 -0
- package/README.md +230 -0
- package/dist/cli.js +4545 -0
- package/dist/web/assets/index-Czg2WeHe.js +182 -0
- package/dist/web/assets/index-DKAyt92W.css +1 -0
- package/dist/web/index.html +15 -0
- package/package.json +90 -0
- package/skills/apply-comments/SKILL.md +87 -0
- package/skills/current-position/SKILL.md +65 -0
- package/skills/kickoff/SKILL.md +105 -0
- package/skills/mosage-reference/SKILL.md +164 -0
- package/skills/outline/SKILL.md +79 -0
- package/skills/review/SKILL.md +64 -0
- package/skills/write-chapter/SKILL.md +58 -0
- package/template/book/STYLE.md +6 -0
- package/template/book/assets/.gitkeep +0 -0
- package/template/book/book.yaml +42 -0
- package/template/book/brief.md +6 -0
- package/template/book/chapters/.gitkeep +0 -0
- package/template/book/notes/README.md +7 -0
- package/template/project/AGENTS.md +82 -0
- package/template/project/CLAUDE.md +1 -0
- package/template/project/README.md +48 -0
- package/template/project/books/.gitkeep +0 -0
- package/template/project/gitignore +5 -0
- package/template/project/mosage.yaml +23 -0
- package/template/project/notes/README.md +8 -0
- package/template/project/package.json +14 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
:root{--sans:ui-sans-serif, system-ui, -apple-system, "Segoe UI", "PingFang TC", "Noto Sans TC", "Microsoft JhengHei", sans-serif;--serif:"Noto Serif TC", "Source Han Serif TC", "Songti TC", "PMingLiU", "MingLiU", serif;--mono:ui-monospace, "SF Mono", Menlo, Consolas, "Noto Sans Mono CJK TC", monospace;--bg:#f3f0e8;--surface:#fbf9f4;--page:#fffefb;--ink:#2a2723;--ink-soft:#4a453e;--muted:#8a8277;--line:#e3ddd1;--line-strong:#cfc7b8;--accent:#a23b2c;--accent-soft:#f6e4df;--accent-ink:#fff;--focus:#c7775f;--human:#fff3c4;--human-line:#e2c150;--human-ink:#6d5510;--ai:#e6effa;--ai-line:#7ea4d6;--ai-ink:#274a74;--suggest:#efe9fa;--suggest-line:#9d82d2;--suggest-ink:#4c3480;--ins-bg:#d9f0de;--ins-ink:#17612f;--del-bg:#f9dfdb;--del-ink:#9a2f22;--shadow:0 1px 2px #3c2d140f, 0 6px 24px #3c2d1412;--radius:10px;--topbar:52px;--lightningcss-light:initial;--lightningcss-dark: ;color-scheme:light}:root[data-theme=dark]{--bg:#171614;--surface:#201f1c;--page:#252320;--ink:#ebe6dc;--ink-soft:#cfc8bb;--muted:#968f84;--line:#36332e;--line-strong:#4a4640;--accent:#d86b55;--accent-soft:#3d2520;--accent-ink:#1b0d0a;--human:#3a3216;--human-line:#a88b2a;--human-ink:#f0dc98;--ai:#1d2a3a;--ai-line:#4f78a8;--ai-ink:#b9d2f0;--suggest:#2a2338;--suggest-line:#7c63b0;--suggest-ink:#d8c9f5;--ins-bg:#173522;--ins-ink:#9fe0b1;--del-bg:#3d1d19;--del-ink:#f2a79a;--shadow:0 1px 2px #0000004d, 0 8px 28px #0000004d;--lightningcss-light: ;--lightningcss-dark:initial;color-scheme:dark}@media (prefers-color-scheme:dark){:root[data-theme=auto]{--bg:#171614;--surface:#201f1c;--page:#252320;--ink:#ebe6dc;--ink-soft:#cfc8bb;--muted:#968f84;--line:#36332e;--line-strong:#4a4640;--accent:#d86b55;--accent-soft:#3d2520;--accent-ink:#1b0d0a;--human:#3a3216;--human-line:#a88b2a;--human-ink:#f0dc98;--ai:#1d2a3a;--ai-line:#4f78a8;--ai-ink:#b9d2f0;--suggest:#2a2338;--suggest-line:#7c63b0;--suggest-ink:#d8c9f5;--ins-bg:#173522;--ins-ink:#9fe0b1;--del-bg:#3d1d19;--del-ink:#f2a79a;--shadow:0 1px 2px #0000004d, 0 8px 28px #0000004d;--lightningcss-light: ;--lightningcss-dark:initial;color-scheme:dark}}*{box-sizing:border-box}html,body{background:var(--bg);color:var(--ink);font-family:var(--sans);-webkit-font-smoothing:antialiased;margin:0;font-size:15px;line-height:1.55}a{color:inherit}button,input,select,textarea{font:inherit;color:inherit}code{font-family:var(--mono);background:color-mix(in srgb, var(--line) 55%, transparent);border-radius:4px;padding:.08em .35em;font-size:.88em}.muted{color:var(--muted)}.small{font-size:12.5px}.spacer{flex:1}.loading,.page-error,.empty{text-align:center;color:var(--muted);padding:48px 24px}.page-error{color:var(--del-ink)}.btn{border:1px solid var(--line-strong);background:var(--surface);cursor:pointer;white-space:nowrap;border-radius:8px;justify-content:center;align-items:center;gap:6px;height:34px;padding:0 14px;font-size:14px;text-decoration:none;transition:background .15s,border-color .15s;display:inline-flex}.btn:hover{border-color:var(--muted)}.btn:disabled{opacity:.5;cursor:default}.btn-primary{background:var(--accent);border-color:var(--accent);color:var(--accent-ink);font-weight:600}.btn-primary:hover{filter:brightness(1.06);border-color:var(--accent)}.btn-ghost{color:var(--ink-soft);background:0 0;border-color:#0000}.btn-ghost:hover{background:color-mix(in srgb, var(--line) 50%, transparent);border-color:#0000}.btn-sm{border-radius:7px;height:28px;padding:0 10px;font-size:13px}.icon-btn{cursor:pointer;color:var(--muted);background:0 0;border:0;padding:4px 8px;font-size:22px;line-height:1}.badge{border:1px solid var(--line-strong);color:var(--ink-soft);white-space:nowrap;border-radius:999px;padding:1px 7px;font-size:11.5px;display:inline-block}.pill{background:var(--accent-soft);color:var(--accent);white-space:nowrap;border-radius:999px;margin-left:6px;padding:1px 8px;font-size:11.5px;display:inline-block}.pill-warn,.pill-human{background:var(--human);color:var(--human-ink)}.pill-ai{background:var(--ai);color:var(--ai-ink)}.pill-suggest{background:var(--suggest);color:var(--suggest-ink)}.progress{background:var(--line);border-radius:99px;height:6px;margin-top:10px;overflow:hidden}.progress>div{background:var(--accent);border-radius:99px;height:100%;transition:width .4s}.progress-lg{max-width:420px;height:8px}.warning{background:var(--human);color:var(--human-ink);border:1px solid var(--human-line);border-radius:8px;flex-wrap:wrap;align-items:center;gap:10px;margin:12px 0;padding:10px 14px;display:flex}select.status{border:1px solid var(--line-strong);background:var(--surface);cursor:pointer;border-radius:7px;height:28px;padding:0 6px;font-size:13px}.status-idea{--dot:#b8b0a3}.status-draft{--dot:#d6a23c}.status-revising{--dot:#7ea4d6}.status-done{--dot:#4f9a64}select.status{border-left:4px solid var(--dot)}.status-dot{background:var(--dot);border-radius:50%;flex:none;width:8px;height:8px}.copy-text{border:1px solid var(--line-strong);background:var(--page);cursor:pointer;border-radius:8px;align-items:center;gap:8px;padding:4px 6px 4px 4px;display:inline-flex}.copy-text code{background:0 0;padding:2px 6px;font-size:13.5px}.copy-state{color:var(--muted);font-size:12px}.copy-row{align-items:center;gap:10px;display:flex}.segmented{border:1px solid var(--line-strong);border-radius:8px;display:inline-flex;overflow:hidden}.segmented button{background:var(--surface);cursor:pointer;border:0;padding:6px 16px}.segmented button.on{background:var(--accent);color:var(--accent-ink)}.field{flex-direction:column;gap:6px;margin:14px 0;display:flex}.field>span{color:var(--muted);font-size:13px}.field input{border:1px solid var(--line-strong);background:var(--page);border-radius:8px;height:38px;padding:0 12px}.editable{text-align:left;cursor:text;background:0 0;border:1px dashed #0000;border-radius:6px;width:100%;margin:0 -6px;padding:2px 6px;display:block}.editable:hover{border-color:var(--line-strong)}.editable.is-empty{color:var(--muted);font-style:italic}.editable-input{border:1px solid var(--focus);background:var(--page);border-radius:6px;outline:none;width:100%;margin:0 -6px;padding:2px 6px;display:block}.topbar{z-index:20;height:var(--topbar);background:color-mix(in srgb, var(--bg) 88%, transparent);-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);border-bottom:1px solid var(--line);align-items:center;gap:16px;padding:0 16px;display:flex;position:sticky;top:0}.crumbs{flex:1;align-items:center;gap:8px;min-width:0;display:flex}.crumbs a{text-decoration:none}.brand{align-items:center;gap:8px;text-decoration:none;display:inline-flex}.brand-mark{background:var(--accent);width:26px;height:26px;color:var(--accent-ink);font-size:14px;font-weight:800;font-family:var(--serif);border-radius:7px;place-items:center;display:grid}.brand-name{letter-spacing:.02em;font-weight:700}.crumb-sep{color:var(--line-strong)}.crumb-book{white-space:nowrap;text-overflow:ellipsis;max-width:28ch;font-weight:600;overflow:hidden}.crumb-page{color:var(--muted);white-space:nowrap;text-overflow:ellipsis;overflow:hidden}.tabs{background:color-mix(in srgb, var(--line) 55%, transparent);border-radius:9px;gap:2px;padding:3px;display:flex}.tab{color:var(--ink-soft);white-space:nowrap;border-radius:7px;padding:5px 14px;font-size:14px;text-decoration:none;position:relative}.tab.on{background:var(--page);color:var(--ink);font-weight:600;box-shadow:0 1px 2px #00000014}.tab .dot{background:var(--accent);border-radius:50%;width:6px;height:6px;position:absolute;top:5px;right:5px}.topbar-actions{flex:1;justify-content:flex-end;gap:8px;display:flex}.menu{position:relative}.menu-pop{background:var(--page);border:1px solid var(--line);width:290px;box-shadow:var(--shadow);z-index:40;border-radius:12px;padding:6px;position:absolute;top:calc(100% + 6px);right:0}.menu-pop button{cursor:pointer;text-align:left;background:0 0;border:0;border-radius:8px;flex-direction:column;align-items:flex-start;gap:2px;width:100%;padding:9px 12px;display:flex}.menu-pop button:hover{background:var(--surface)}.menu-pop button span{color:var(--muted);font-size:12.5px}.menu-note{color:var(--muted);border-top:1px solid var(--line);margin:6px 12px;padding-top:8px;font-size:12px}.library-main{max-width:1120px;margin:0 auto;padding:32px 24px 80px}.library-title{font-family:var(--serif);margin:8px 0 20px;font-size:26px}.shelf{grid-template-columns:repeat(auto-fill,minmax(320px,1fr));gap:18px;display:grid}.book-card{background:var(--page);border:1px solid var(--line);box-shadow:var(--shadow);border-radius:14px;gap:16px;min-height:190px;padding:16px;text-decoration:none;transition:transform .15s;display:flex}.book-card:hover{transform:translateY(-2px)}.book-spine{background:linear-gradient(90deg, #0000002e, transparent 18%), var(--accent);color:#fff;writing-mode:vertical-rl;width:64px;font-family:var(--serif);letter-spacing:.1em;border-radius:4px 8px 8px 4px;flex:none;justify-content:center;align-items:flex-start;padding-top:14px;font-size:14px;font-weight:700;display:flex;overflow:hidden}.spine-thesis{background:linear-gradient(90deg,#0000002e,#0000 18%),#3d5a80}.spine-other{background:linear-gradient(90deg,#0000002e,#0000 18%),#5b6b4f}.book-info{flex-direction:column;flex:1;min-width:0;display:flex}.book-card h2{font-family:var(--serif);margin:8px 0 2px;font-size:19px;line-height:1.35}.book-sub{color:var(--muted);margin:0;font-size:13.5px}.book-card-head{gap:6px;display:flex}.book-meta{color:var(--ink-soft);margin-top:auto;padding-top:12px;font-size:13px}.book-foot{margin-top:10px;font-size:12.5px}.book-card-new{box-shadow:none;cursor:pointer;color:var(--ink-soft);background:0 0;border-style:dashed;flex-direction:column;justify-content:center;align-items:center;gap:4px}.plus{color:var(--accent);font-size:28px}.stage{background:var(--surface);border:1px solid var(--line);color:var(--ink-soft);border-radius:999px;padding:1px 8px;font-size:11.5px}.onboarding{background:var(--page);border:1px solid var(--line);max-width:680px;box-shadow:var(--shadow);border-radius:16px;margin:40px auto;padding:36px 40px}.onboarding h2{font-family:var(--serif);margin:0 0 6px;font-size:26px}.steps{counter-reset:step;margin:28px 0 0;padding:0;list-style:none}.steps li{counter-increment:step;padding:0 0 22px 48px;position:relative}.steps li:before{content:counter(step);background:var(--accent-soft);width:30px;height:30px;color:var(--accent);border-radius:50%;place-items:center;font-weight:700;display:grid;position:absolute;top:-2px;left:0}.steps p{color:var(--ink-soft);margin:4px 0 8px}.outline-page{max-width:980px;margin:0 auto;padding:28px 24px 100px}.book-head{justify-content:space-between;align-items:flex-start;gap:24px;display:flex}.book-head-main{flex:1;min-width:0}.book-title{font-family:var(--serif);font-size:30px;font-weight:700;line-height:1.3}.book-subtitle{color:var(--ink-soft);margin-top:2px;font-size:16px}.book-byline{color:var(--ink-soft);flex-wrap:wrap;gap:14px;margin-top:10px;font-size:13.5px;display:flex}.book-docs{flex-direction:column;flex:none;gap:8px;width:200px;display:flex}.doc-link{background:var(--page);border:1px solid var(--line);cursor:pointer;text-align:left;border-radius:10px;flex-direction:column;align-items:flex-start;gap:2px;padding:10px 14px;display:flex}.doc-link span{color:var(--muted);font-size:12.5px}.doc-link:hover{border-color:var(--line-strong)}.stepper{flex-wrap:wrap;gap:6px;margin:24px 0 12px;display:flex}.step{border:1px solid var(--line);background:var(--surface);cursor:pointer;color:var(--muted);border-radius:999px;align-items:center;gap:8px;padding:5px 14px 5px 6px;font-size:14px;display:flex}.step-no{background:var(--line);border-radius:50%;place-items:center;width:22px;height:22px;font-size:12px;display:grid}.step.done{color:var(--ink-soft)}.step.done .step-no{background:var(--ins-bg);color:var(--ins-ink)}.step.on{border-color:var(--accent);color:var(--ink);background:var(--page);font-weight:600}.step.on .step-no{background:var(--accent);color:var(--accent-ink)}.ai-hint{background:var(--surface);border:1px solid var(--line);color:var(--ink-soft);border-radius:12px;flex-wrap:wrap;align-items:center;gap:12px;padding:12px 16px;font-size:14px;display:flex}.ai-hint-strong{background:var(--accent-soft);border-color:color-mix(in srgb, var(--accent) 35%, transparent)}.section-head{align-items:baseline;gap:12px;margin:32px 0 12px;display:flex}.section-head h2{margin:0;font-size:17px}.chapters{flex-direction:column;gap:10px;margin:0;padding:0;list-style:none;display:flex}.chapter-row{background:var(--page);border:1px solid var(--line);border-radius:12px;grid-template-columns:18px 34px minmax(0,1fr) 190px;align-items:start;gap:10px;padding:14px 16px 14px 8px;transition:box-shadow .15s,opacity .15s;display:grid}.chapter-row:hover{box-shadow:var(--shadow)}.chapter-row.dragging{opacity:.45;border-style:dashed}.drag-handle{cursor:grab;color:var(--line-strong);letter-spacing:-3px;-webkit-user-select:none;user-select:none;padding-top:4px}.chapter-no{font-family:var(--serif);color:var(--muted);padding-top:1px;font-size:18px}.chapter-title{font-family:var(--serif);font-size:17px;font-weight:700}.chapter-summary{color:var(--ink-soft);margin-top:2px;font-size:13.5px}.sections{color:var(--muted);columns:2;column-gap:24px;margin:8px 0 0;padding-left:18px;font-size:13px}.sections li{break-inside:avoid}.chapter-side{flex-direction:column;align-items:flex-end;gap:6px;display:flex}.chapter-words{color:var(--ink-soft);font-size:13px}.chapter-notes{flex-wrap:wrap;justify-content:flex-end;gap:4px;display:flex}.chapter-notes .pill{margin:0}.chapter-actions{gap:2px;margin-top:4px;display:flex}.add-chapter{gap:8px;margin-top:12px;display:flex}.add-chapter input{border:1px dashed var(--line-strong);background:0 0;border-radius:10px;flex:1;height:38px;padding:0 14px}.drafts ul{margin:0;padding:0;list-style:none}.drafts li{border-bottom:1px solid var(--line);align-items:center;gap:12px;padding:8px 0;display:flex}.drafts li a{font-weight:600}.drafts li .btn{margin-left:auto}.doc-editor{width:100%;min-height:55vh;font-family:var(--mono);border:1px solid var(--line-strong);background:var(--page);border-radius:8px;padding:12px;font-size:13.5px}.prose{font-family:var(--serif);line-height:1.8}.doc-preview{max-height:60vh;overflow:auto}.reader{grid-template-columns:260px minmax(0,1fr);display:grid}.reader-side{top:var(--topbar);height:calc(100vh - var(--topbar));border-right:1px solid var(--line);padding:18px 12px 40px;font-size:13.5px;position:sticky;overflow:auto}.side-title{color:var(--muted);letter-spacing:.08em;margin:4px 8px 8px;font-size:11.5px;font-weight:700}.toc{margin:0 0 20px;padding:0;list-style:none}.toc>li>a{color:var(--ink-soft);border-radius:7px;align-items:center;gap:8px;padding:6px 8px;text-decoration:none;display:flex}.toc>li>a:hover{background:color-mix(in srgb, var(--line) 50%, transparent)}.toc>li.on>a{background:var(--page);color:var(--ink);font-weight:600;box-shadow:0 1px 2px #0000000f}.toc-title{text-overflow:ellipsis;white-space:nowrap;flex:1;min-width:0;overflow:hidden}.toc-badge{background:var(--accent-soft);color:var(--accent);border-radius:99px;padding:0 7px;font-size:11px}.toc-sections{margin:0;padding:2px 0 6px 24px;list-style:none}.toc-sections a{color:var(--muted);border-radius:6px;padding:3px 8px;font-size:13px;text-decoration:none;display:block}.toc-sections a:hover{color:var(--ink)}.toc-sections .depth-3 a{padding-left:20px;font-size:12.5px}.reader-main,.whole-book,.source-page,.files-page{min-width:0}.reader-toolbar{top:var(--topbar);z-index:10;background:color-mix(in srgb, var(--bg) 92%, transparent);-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);border-bottom:1px solid var(--line);flex-wrap:wrap;align-items:center;gap:10px;padding:8px 20px;display:flex;position:sticky}.live{color:var(--muted);align-items:center;gap:6px;font-size:12px;display:inline-flex}.live:before{content:"";background:#4f9a64;border-radius:50%;width:7px;height:7px}.live-pulse{color:#4f9a64;font-weight:600}.live-pulse:before{animation:.8s ease-in-out 2 pulse}@keyframes pulse{50%{opacity:.5;transform:scale(1.8)}}.unsaved{color:var(--accent);font-size:12.5px;font-weight:600}.page{background:var(--page);border:1px solid var(--line);box-shadow:var(--shadow);border-radius:6px;max-width:1080px;margin:28px auto;padding:64px 0 72px}.chapter-nav{justify-content:space-between;gap:16px;max-width:1080px;margin:0 auto 80px;padding:0 16px;display:flex}.chapter-nav a{color:var(--ink-soft);font-family:var(--serif);text-decoration:none}.chapter-nav a:hover{color:var(--accent)}.chapter-doc{--cols:3rem minmax(0, 36em) minmax(0, 1fr);font-family:var(--book-font,var(--serif));font-size:17.5px;line-height:var(--book-leading,1.9);color:var(--ink)}.block{grid-template-columns:var(--cols);column-gap:28px;padding-right:24px;display:grid;position:relative}.block-content{border-radius:4px;grid-column:2;min-width:0}.block-notes{font-family:var(--sans);flex-direction:column;grid-column:3;gap:8px;max-width:300px;padding-top:.25em;font-size:13px;line-height:1.5;display:flex}.block-tools{opacity:0;flex-direction:column;grid-column:1;align-items:flex-end;gap:2px;padding-top:.35em;transition:opacity .12s;display:flex}.block:hover .block-tools{opacity:1}.block-tools button{border:1px solid var(--line);background:var(--page);cursor:pointer;width:26px;height:26px;color:var(--muted);border-radius:6px;place-items:center;padding:0;display:grid}.block-tools button:hover{color:var(--accent);border-color:var(--accent)}.block-tools svg{fill:none;stroke:currentColor;stroke-width:1.6px;stroke-linejoin:round;stroke-linecap:round;width:15px;height:15px}.block.has-notes>.block-content{box-shadow:-3px 0 0 var(--human-line)}.block.is-editing>.block-content{box-shadow:none}.chapter-doc p{text-indent:var(--book-indent,2em);text-align:justify;margin:0 0 .55em}.chapter-doc li p,.chapter-doc blockquote p,.chapter-doc .callout p,.chapter-doc td p,.chapter-doc .footnotes p{text-indent:0}.chapter-doc h1,.chapter-doc h2,.chapter-doc h3,.chapter-doc h4{font-family:var(--book-heading-font,var(--sans));text-indent:0;scroll-margin-top:calc(var(--topbar) + 60px);line-height:1.4}.chapter-doc h1{letter-spacing:.02em;margin:.2em 0 1.4em;font-size:1.85em}.chapter-doc h2{margin:1.6em 0 .6em;font-size:1.3em}.chapter-doc h3{margin:1.3em 0 .5em;font-size:1.1em}.chapter-doc h4{margin:1.1em 0 .4em;font-size:1em}.chapter-doc ul,.chapter-doc ol{margin:0 0 .7em;padding-left:2em}.chapter-doc li.task{margin-left:-1.4em;list-style:none}.chapter-doc blockquote{border-left:3px solid var(--line-strong);color:var(--ink-soft);margin:.4em 0 .9em;padding:.2em 1.2em}.callout{background:var(--surface);border:1px solid var(--line);border-left:4px solid var(--ai-line);border-radius:8px;margin:.5em 0 1em;padding:.7em 1.1em}.callout-label{font-family:var(--sans);letter-spacing:.06em;color:var(--ai-ink);margin-bottom:.2em;font-size:.8em;font-weight:700}.callout-tip{border-left-color:#4f9a64}.callout-tip .callout-label{color:#3b7d4f}.callout-important{border-left-color:var(--suggest-line)}.callout-important .callout-label{color:var(--suggest-ink)}.callout-warning{border-left-color:var(--human-line)}.callout-warning .callout-label{color:var(--human-ink)}.callout-caution{border-left-color:var(--accent)}.callout-caution .callout-label{color:var(--accent)}.code-block{font-family:var(--mono);background:var(--surface);border:1px solid var(--line);border-radius:8px;margin:.5em 0 1em;padding:.9em 1.1em;font-size:.78em;line-height:1.6;overflow-x:auto}.code-block code{background:0 0;padding:0}.table-wrap{margin:.5em 0 1em;overflow-x:auto}.chapter-doc table{border-collapse:collapse;width:100%;font-size:.88em;line-height:1.6}.chapter-doc th,.chapter-doc td{border:1px solid var(--line-strong);vertical-align:top;padding:.4em .7em}.chapter-doc th{background:var(--surface);font-weight:700}.chapter-doc figure{text-align:center;margin:1em 0}.chapter-doc figure img{border-radius:4px;max-width:100%;max-height:70vh}.chapter-doc figcaption{font-family:var(--sans);color:var(--muted);margin-top:.5em;font-size:.8em}.inline-image{vertical-align:middle;max-height:1.4em}.scene-break{text-align:center;color:var(--muted);letter-spacing:.3em;margin:1.2em 0}.page-break{text-align:center;font-family:var(--sans);color:var(--muted);border-top:1px dashed var(--line-strong);margin:1.4em 0;font-size:12px;line-height:0}.page-break:before{content:""}.fn-ref a{color:var(--accent);padding:0 .1em;font-size:.8em;text-decoration:none}.footnotes{color:var(--ink-soft);border-top:1px solid var(--line);max-width:36em;margin:2.5em 0 0 calc(3rem + 28px);padding-top:.8em;font-size:.82em}.quote-mark{background:var(--human);color:inherit;border-bottom:2px solid var(--human-line);padding:0 1px}.note{border:1px solid var(--line);background:var(--surface);border-radius:9px;padding:8px 10px}.note-human{background:var(--human);border-color:var(--human-line);color:var(--human-ink)}.note-ai{background:var(--ai);border-color:var(--ai-line);color:var(--ai-ink)}.note-suggest{background:var(--suggest);border-color:var(--suggest-line);color:var(--suggest-ink)}.note-compose{background:var(--page);border-color:var(--focus);box-shadow:var(--shadow)}.note-head{justify-content:space-between;gap:8px;margin-bottom:3px;font-size:11.5px;display:flex}.note-label{letter-spacing:.04em;font-weight:700}.note-time{opacity:.7}.note-quote{opacity:.8;-webkit-line-clamp:2;-webkit-box-orient:vertical;margin-bottom:3px;font-size:12px;display:-webkit-box;overflow:hidden}.note-body{white-space:pre-wrap;color:var(--ink)}.note-foot{opacity:.75;margin-top:4px;font-size:11.5px}.note-actions{justify-content:flex-end;gap:6px;margin-top:8px;display:flex}.note-input{border:1px solid var(--line-strong);background:var(--page);resize:none;border-radius:7px;outline:none;width:100%;min-height:60px;padding:6px 8px;font-size:13.5px}.suggestion{border-left:3px solid var(--suggest-line);background:color-mix(in srgb, var(--suggest) 45%, transparent);border-radius:0 6px 6px 0;margin:.2em 0 .8em;padding:.3em .9em .5em}.suggestion-tabs{font-family:var(--sans);gap:4px;margin-bottom:.3em;display:flex}.suggestion-tabs button{cursor:pointer;color:var(--suggest-ink);opacity:.7;background:0 0;border:0;border-radius:6px;padding:2px 8px;font-size:12px}.suggestion-tabs button.on{background:var(--suggest);opacity:1;font-weight:600}.diff{white-space:pre-wrap;line-height:inherit}.diff ins,.history ins{background:var(--ins-bg);color:var(--ins-ink);border-radius:3px;text-decoration:none}.diff del,.history del{background:var(--del-bg);color:var(--del-ink);border-radius:3px;text-decoration:line-through}.suggestion-after p{margin-bottom:.4em}.inline-editor-text{border:1px solid var(--focus);background:var(--page);width:100%;min-height:4em;font:inherit;resize:none;border-radius:8px;outline:none;padding:.5em .7em;line-height:1.7}.inline-editor-bar{font-family:var(--sans);justify-content:flex-end;align-items:center;gap:6px;margin:6px 0 12px;display:flex}.inline-editor-bar .hint{color:var(--muted);margin-right:auto;font-size:12px}.floating-comment{z-index:30;background:var(--ink);color:var(--bg);cursor:pointer;box-shadow:var(--shadow);border:0;border-radius:8px;padding:6px 12px;font-size:13px;font-weight:600;position:fixed;transform:translate(-50%,calc(-100% - 8px))}.whole-book .page+.page{margin-top:36px}.title-page{text-align:center;font-family:var(--book-font,var(--serif));padding:140px 40px}.title-page h1{margin:0;font-size:2.4em}.title-page .subtitle{color:var(--ink-soft);font-size:1.2em}.title-page .author{margin-top:4em;font-size:1.1em}.toc-page{font-family:var(--book-font,var(--serif));padding:56px 72px}.toc-page ol{line-height:2}.toc-page ul{color:var(--muted);font-size:.92em;line-height:1.8}.toc-page a{text-decoration:none}.split{height:calc(100vh - var(--topbar) - 45px);grid-template-columns:minmax(0,1fr) minmax(0,1fr);display:grid}.editor-pane{border-right:1px solid var(--line);background:var(--page);overflow:hidden}.editor-pane .cm-editor{height:100%;font-size:14.5px}.editor-pane .cm-scroller{font-family:var(--mono);line-height:1.7}.editor-pane .cm-content{padding:18px 0}.editor-pane .cm-gutters{background:var(--surface);border-right:1px solid var(--line);color:var(--muted)}.editor-pane .cm-editor.cm-focused{outline:none}.preview-pane{overflow:auto}.preview-pane .page{margin:20px;padding:40px 0}.preview-pane .chapter-doc{--cols:1.5rem minmax(0, 1fr);font-size:16px}.preview-pane .block-notes{display:none}.editor-pane .cm-editor{background:var(--page);color:var(--ink)}.editor-pane .cm-activeLine,.editor-pane .cm-activeLineGutter{background:color-mix(in srgb, var(--line) 35%, transparent)}.editor-pane .cm-cursor{border-left-color:var(--ink)}.editor-pane .cm-selectionBackground,.editor-pane .cm-focused .cm-selectionBackground{background:color-mix(in srgb, var(--accent) 22%, transparent)!important}.conflict{margin:10px 20px}.files-page{max-width:1100px;margin:0 auto;padding:24px}.files-grid{grid-template-columns:3fr 2fr;gap:32px;display:grid}.dropzone{border:2px dashed var(--line-strong);background:var(--surface);cursor:pointer;border-radius:12px;flex-direction:column;align-items:center;gap:4px;width:100%;padding:26px;display:flex}.dropzone.over{border-color:var(--accent);background:var(--accent-soft)}.assets{grid-template-columns:repeat(auto-fill,minmax(230px,1fr));gap:12px;margin:16px 0;padding:0;list-style:none;display:grid}.asset{background:var(--page);border:1px solid var(--line);border-radius:10px;overflow:hidden}.asset-thumb{background:var(--surface);height:130px;color:var(--muted);place-items:center;text-decoration:none;display:grid}.asset-thumb img{object-fit:contain;max-width:100%;max-height:130px}.asset-info{padding:8px 10px 10px}.asset-name{text-overflow:ellipsis;white-space:nowrap;font-size:13px;font-weight:600;overflow:hidden}.asset-actions{gap:4px;margin-top:6px;display:flex}.notes-list{margin:16px 0;padding:0;list-style:none}.notes-list li{border-bottom:1px solid var(--line);align-items:center;gap:10px;padding:8px 0;display:flex}.notes-list li a{text-overflow:ellipsis;font-weight:600;overflow:hidden}.notes-list li .btn{margin-left:auto}.history{grid-template-columns:240px minmax(0,1fr);gap:16px;height:56vh;display:grid}.history-list{border-right:1px solid var(--line);margin:0;padding:0;list-style:none;overflow:auto}.history-list button{cursor:pointer;text-align:left;background:0 0;border:0;border-radius:8px;flex-direction:column;align-items:flex-start;width:100%;padding:8px 10px;display:flex}.history-list button span{color:var(--muted);font-size:12px}.history-list button.on{background:var(--surface);box-shadow:inset 3px 0 0 var(--accent)}.history-diff{overflow:auto}.history-diff pre{white-space:pre-wrap;font-family:var(--mono);margin:0;font-size:12.5px;line-height:1.6}.history-diff .same{color:var(--muted)}.history-legend{gap:10px;margin-bottom:8px;font-size:12px;display:flex}.modal-backdrop{z-index:50;background:#140f0a66;place-items:center;padding:20px;display:grid;position:fixed;inset:0}.modal{background:var(--page);box-shadow:var(--shadow);border-radius:14px;flex-direction:column;width:min(460px,100%);max-height:calc(100vh - 40px);display:flex}.modal-wide{width:min(960px,100%)}.modal-head{justify-content:space-between;align-items:center;padding:14px 18px 0;display:flex}.modal-head h3{margin:0;font-size:17px}.modal-body{padding:8px 18px 18px;overflow:auto}.modal-actions{justify-content:flex-end;align-items:center;gap:8px;margin-top:16px;display:flex}.modal-actions .muted{margin-right:auto}.toaster{z-index:60;pointer-events:none;flex-direction:column;gap:8px;display:flex;position:fixed;bottom:20px;left:50%;transform:translate(-50%)}.toast{background:var(--ink);color:var(--bg);box-shadow:var(--shadow);border-radius:10px;max-width:min(560px,90vw);padding:9px 16px;font-size:14px}.toast-error{background:var(--del-ink);color:#fff}.toast-success{color:#fff;background:#2f6b43}.offline{z-index:70;background:var(--del-bg);color:var(--del-ink);text-align:center;padding:8px;font-size:13.5px;position:fixed;top:0;left:0;right:0}.theme-toggle{border:1px solid var(--line);background:var(--page);cursor:pointer;width:36px;height:36px;box-shadow:var(--shadow);z-index:15;border-radius:50%;position:fixed;bottom:16px;right:16px}@media (width<=1180px){.chapter-doc{--cols:2.4rem minmax(0, 1fr)}.block-notes{grid-column:2;max-width:none;padding:.3em 0 .8em}.footnotes{margin-left:calc(2.4rem + 28px)}}@media (width<=900px){.reader{grid-template-columns:minmax(0,1fr)}.reader-side{display:none}.page{margin:12px;padding:36px 0}.chapter-doc{font-size:16.5px}.block{column-gap:10px;padding-right:14px}.book-head{flex-direction:column}.book-docs{flex-direction:row;width:100%}.chapter-row{grid-template-columns:18px minmax(0,1fr)}.chapter-no{display:none}.chapter-side{grid-column:2;align-items:flex-start}.split{grid-template-columns:minmax(0,1fr)}.preview-pane{display:none}.files-grid{grid-template-columns:minmax(0,1fr)}.hide-narrow,.crumb-page,.topbar .badge{display:none}.chapter-doc p{text-align:left}.topbar{gap:8px;padding:0 10px}.tab{padding:5px 9px}}@media (width<=520px){.theme-toggle,.crumb-book,.crumbs .crumb-sep{display:none}.topbar-actions{flex:none}}@media print{.topbar,.reader-side,.reader-toolbar,.block-tools,.block-notes,.chapter-nav,.theme-toggle,.toaster,.suggestion-tabs{display:none!important}html,body{background:#fff}.reader{display:block}.page{box-shadow:none;break-before:page;border:0;margin:0;padding:0}.chapter-doc{--cols:0 minmax(0, 1fr);column-gap:0}.block{column-gap:0;padding:0}.block.has-notes>.block-content{box-shadow:none}}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="zh-Hant-TW">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<meta name="color-scheme" content="light dark" />
|
|
7
|
+
<link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Crect width='32' height='32' rx='7' fill='%23a23b2c'/%3E%3Cpath d='M8 23V9l8 8 8-8v14' fill='none' stroke='%23fff' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E" />
|
|
8
|
+
<title>MoSage</title>
|
|
9
|
+
<script type="module" crossorigin src="./assets/index-Czg2WeHe.js"></script>
|
|
10
|
+
<link rel="stylesheet" crossorigin href="./assets/index-DKAyt92W.css">
|
|
11
|
+
</head>
|
|
12
|
+
<body>
|
|
13
|
+
<div id="root"></div>
|
|
14
|
+
</body>
|
|
15
|
+
</html>
|
package/package.json
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "mosage",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "和 AI 一起寫書的本機寫作平台:Markdown 章節、書本排版預覽、留言給 AI、一鍵匯出 Word。",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"mosage": "dist/cli.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"dist",
|
|
11
|
+
"template",
|
|
12
|
+
"skills",
|
|
13
|
+
"README.md",
|
|
14
|
+
"README.en.md"
|
|
15
|
+
],
|
|
16
|
+
"scripts": {
|
|
17
|
+
"build": "npm run build:web && npm run build:cli",
|
|
18
|
+
"build:cli": "tsup",
|
|
19
|
+
"build:web": "vite build",
|
|
20
|
+
"dev:web": "vite",
|
|
21
|
+
"typecheck": "tsc --noEmit",
|
|
22
|
+
"check": "biome check .",
|
|
23
|
+
"check:fix": "biome check --write .",
|
|
24
|
+
"test": "vitest run",
|
|
25
|
+
"test:watch": "vitest",
|
|
26
|
+
"prepack": "npm run build",
|
|
27
|
+
"test:e2e": "node scripts/e2e.mjs",
|
|
28
|
+
"dev:cli": "tsx src/cli/index.ts"
|
|
29
|
+
},
|
|
30
|
+
"engines": {
|
|
31
|
+
"node": ">=20.19"
|
|
32
|
+
},
|
|
33
|
+
"keywords": [
|
|
34
|
+
"book",
|
|
35
|
+
"writing",
|
|
36
|
+
"ai",
|
|
37
|
+
"markdown",
|
|
38
|
+
"docx",
|
|
39
|
+
"word",
|
|
40
|
+
"claude-code",
|
|
41
|
+
"agent"
|
|
42
|
+
],
|
|
43
|
+
"license": "MIT",
|
|
44
|
+
"author": "CHENBOHAN",
|
|
45
|
+
"homepage": "https://github.com/nickchen1998/MoSage",
|
|
46
|
+
"repository": {
|
|
47
|
+
"type": "git",
|
|
48
|
+
"url": "git+https://github.com/nickchen1998/MoSage.git"
|
|
49
|
+
},
|
|
50
|
+
"bugs": {
|
|
51
|
+
"url": "https://github.com/nickchen1998/MoSage/issues"
|
|
52
|
+
},
|
|
53
|
+
"dependencies": {
|
|
54
|
+
"chokidar": "^4.0.3",
|
|
55
|
+
"diff": "^9.0.0",
|
|
56
|
+
"docx": "^9.7.2",
|
|
57
|
+
"image-size": "^2.0.4",
|
|
58
|
+
"mammoth": "^1.12.3",
|
|
59
|
+
"rehype-stringify": "^10.0.1",
|
|
60
|
+
"remark-frontmatter": "^5.0.0",
|
|
61
|
+
"remark-gfm": "^4.0.1",
|
|
62
|
+
"remark-parse": "^11.0.0",
|
|
63
|
+
"remark-rehype": "^11.1.2",
|
|
64
|
+
"turndown": "^7.2.4",
|
|
65
|
+
"turndown-plugin-gfm": "^1.0.2",
|
|
66
|
+
"unified": "^11.0.5",
|
|
67
|
+
"yaml": "^2.9.1"
|
|
68
|
+
},
|
|
69
|
+
"devDependencies": {
|
|
70
|
+
"@biomejs/biome": "^2.5.14",
|
|
71
|
+
"@codemirror/lang-markdown": "^6.5.2",
|
|
72
|
+
"@codemirror/lang-yaml": "^6.1.3",
|
|
73
|
+
"@codemirror/language": "^6.12.4",
|
|
74
|
+
"@lezer/highlight": "^1.2.4",
|
|
75
|
+
"@types/mdast": "^4.0.4",
|
|
76
|
+
"@types/node": "^22.20.4",
|
|
77
|
+
"@types/react": "^19.3.0",
|
|
78
|
+
"@types/react-dom": "^19.3.0",
|
|
79
|
+
"@types/turndown": "^5.0.6",
|
|
80
|
+
"@vitejs/plugin-react": "^6.1.1",
|
|
81
|
+
"codemirror": "^6.0.2",
|
|
82
|
+
"react": "^19.3.0",
|
|
83
|
+
"react-dom": "^19.3.0",
|
|
84
|
+
"tsup": "^8.5.1",
|
|
85
|
+
"tsx": "^4.23.15",
|
|
86
|
+
"typescript": "~5.9.3",
|
|
87
|
+
"vite": "^8.3.1",
|
|
88
|
+
"vitest": "^5.0.2"
|
|
89
|
+
}
|
|
90
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: apply-comments
|
|
3
|
+
description: 處理作者在 MoSage 介面上留給 AI 的留言。作者說「處理留言」「套用我的留言」「看一下我的意見」「我留了言」「apply comments」時使用。找出所有作者留言(mosage:comment,by=human),依 ai.editMode 以「修改建議」或直接修改的方式處理,然後移除已處理的留言標記。
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# 處理作者留言
|
|
7
|
+
|
|
8
|
+
作者在介面上選取文字、按「留言給 AI」後,留言會以 HTML 註解存進章節檔,放在它所指的區塊(段落、標題、清單、表格…)**正上方**:
|
|
9
|
+
|
|
10
|
+
```markdown
|
|
11
|
+
<!-- mosage:comment id=c-3f9a12bc by=human at=2026-09-26T08:12:03Z quote="這一段的第二句"
|
|
12
|
+
太生硬了,改得口語一點,並補一個例子
|
|
13
|
+
-->
|
|
14
|
+
這是作者留言所指的那一段……
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
- `quote` 是作者選取的文字(可能沒有 —— 那就是針對整個區塊)。
|
|
18
|
+
- 標記下方緊接的那個區塊就是留言的對象。
|
|
19
|
+
|
|
20
|
+
## 1. 找出留言
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
npx mosage status <書> --json # 看 notes 陣列:kind 為 comment 且 by 不是 ai 的就是作者留言
|
|
24
|
+
grep -rn "mosage:comment" books/<書>/chapters/
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
作者沒指定書時,處理所有書裡的作者留言(先告訴作者有幾則、在哪幾本)。沒有任何留言 → 告訴作者並結束。
|
|
28
|
+
|
|
29
|
+
## 2. 讀懂每一則
|
|
30
|
+
|
|
31
|
+
- 讀留言所在的整個區塊,以及前後各幾段(「改短一點」要看上下文才知道怎麼改)。
|
|
32
|
+
- 依 `at` 由舊到新處理 —— 後面的留言可能修正前面的。
|
|
33
|
+
- 先讀 `brief.md`、`STYLE.md`,修改要符合風格。
|
|
34
|
+
|
|
35
|
+
## 3. 處理
|
|
36
|
+
|
|
37
|
+
先看 `ai.editMode`(`books/<書>/book.yaml` 的設定優先,否則看 `mosage.yaml`,預設 `suggest`)。
|
|
38
|
+
|
|
39
|
+
### suggest(預設)— 提出修改建議,讓作者在介面上決定
|
|
40
|
+
|
|
41
|
+
**不要改原文**。把作者的留言標記**換成**一個修改建議標記,放在同一個區塊的正上方:
|
|
42
|
+
|
|
43
|
+
```markdown
|
|
44
|
+
<!-- mosage:suggest by=ai note="回應留言:改得口語,加上咖啡店的例子"
|
|
45
|
+
改寫後的**完整段落**(整段,不是只有改的那一句)。
|
|
46
|
+
-->
|
|
47
|
+
這是原本的那一段……
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
- 標記內容會**整個取代**下方的區塊。只改一句也要寫出整段,其餘文字保持原樣。
|
|
51
|
+
- 要取代**連續多個區塊**(例如把兩段合併、重寫一整個清單加一段)→ 加上 `span=2`(取代下方 2 個區塊),內容寫出全部新文字,區塊之間空一行。
|
|
52
|
+
- 要**插入新段落**而不取代任何東西 → `span=0`,內容會插在下方區塊之前。
|
|
53
|
+
- `note` 用一句話說明你改了什麼、為什麼;作者會在介面上看到新舊對照,按「接受」或「拒絕」。
|
|
54
|
+
- `id` 可以省略(系統會自動產生)。
|
|
55
|
+
|
|
56
|
+
### direct — 直接修改
|
|
57
|
+
|
|
58
|
+
直接改寫原文,然後刪除留言標記。
|
|
59
|
+
|
|
60
|
+
### 特殊情況
|
|
61
|
+
|
|
62
|
+
- **留言是問題**(「這裡的數據對嗎?」)或**意思不明確** → 不要猜著大改。刪除作者的留言,在同一位置留下 AI 留言回覆:
|
|
63
|
+
```markdown
|
|
64
|
+
<!-- mosage:comment by=ai quote="原本的 quote"
|
|
65
|
+
關於「這裡的數據對嗎?」:這個數字來自……;如果要更新,請提供新的來源。
|
|
66
|
+
-->
|
|
67
|
+
```
|
|
68
|
+
- **留言要求全書一致的修改**(「全書統一用『使用者』」)→ 找出所有相關位置,每個受影響的區塊各提一個修改建議(suggest 模式)或直接修改(direct 模式)。
|
|
69
|
+
- **無法處理的要求**(例如需要作者提供的資料)→ 保留原留言,並在回報中說明原因。
|
|
70
|
+
|
|
71
|
+
## 4. 移除已處理的留言標記
|
|
72
|
+
|
|
73
|
+
每一則處理完的作者留言,刪除整個 `<!-- mosage:comment … -->`(包含它後面的換行)。
|
|
74
|
+
在 suggest 模式下,你已經用修改建議標記取代了它。**沒處理的留言要保留。**
|
|
75
|
+
|
|
76
|
+
檢查:`grep -rn "mosage:comment" books/<書>/chapters/` 只剩你刻意保留的與 AI 回覆。
|
|
77
|
+
|
|
78
|
+
## 5. 回報
|
|
79
|
+
|
|
80
|
+
簡短列出,每則一行:
|
|
81
|
+
|
|
82
|
+
- 第幾章:留言重點 → 你做了什麼(修改建議/直接修改/回覆了問題)
|
|
83
|
+
- 跳過的留言與原因
|
|
84
|
+
|
|
85
|
+
suggest 模式下提醒作者:
|
|
86
|
+
|
|
87
|
+
> 請到介面上逐一查看修改建議,按「接受」或「拒絕」。
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: current-position
|
|
3
|
+
description: 解讀作者目前在 MoSage 介面上看的位置 —— 哪本書、哪一章、哪一段、選取了什麼文字。當作者說「這本」「這章」「這段」「這裡」「我正在看的」「選取的這句」「剛剛那段」,或任何沒有指名的指示代詞時使用。每一輪都要重新讀 .mosage/current.json,因為作者會在對話之間切換位置。
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# 作者現在在看哪裡?
|
|
7
|
+
|
|
8
|
+
作者說「改這段」「這章寫短一點」時,通常不會說出書名或檔名 —— 他指的是**瀏覽器裡正在看的位置**。
|
|
9
|
+
問「哪一段?」之前,先讀介面寫出的這個檔案:
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
.mosage/current.json
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
(路徑相對於專案根目錄,也就是有 `mosage.yaml` 的資料夾。)
|
|
16
|
+
|
|
17
|
+
## 每一輪都重新讀
|
|
18
|
+
|
|
19
|
+
作者會在你的回合之間換章、捲動、選取別的文字。**只要這一輪用到指示代詞就重新讀取**,
|
|
20
|
+
即使你剛剛才讀過、即使作者的話聽起來像是延續(「再短一點」「這段也是」)。
|
|
21
|
+
讀完與上次比對 `book`、`chapter`、`block`、`selection`,以新的為準。
|
|
22
|
+
|
|
23
|
+
## 內容
|
|
24
|
+
|
|
25
|
+
```json
|
|
26
|
+
{
|
|
27
|
+
"book": "ai-writing-guide",
|
|
28
|
+
"bookTitle": "和 AI 一起寫書",
|
|
29
|
+
"chapter": "03-workflow.md",
|
|
30
|
+
"path": "books/ai-writing-guide/chapters/03-workflow.md",
|
|
31
|
+
"chapterTitle": "第三章 工作流程",
|
|
32
|
+
"view": "read",
|
|
33
|
+
"section": "3.2 留言與修改建議",
|
|
34
|
+
"block": {
|
|
35
|
+
"index": 14,
|
|
36
|
+
"line": 52,
|
|
37
|
+
"type": "paragraph",
|
|
38
|
+
"text": "作者在介面上選取文字之後……"
|
|
39
|
+
},
|
|
40
|
+
"selection": {
|
|
41
|
+
"text": "選取的那幾個字",
|
|
42
|
+
"line": 52
|
|
43
|
+
},
|
|
44
|
+
"updatedAt": "2026-09-26T08:15:42.120Z"
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
- `path` — 直接交給 Read / Edit。
|
|
49
|
+
- `view` — `library`(書架)、`outline`(大綱編排頁)、`read`(閱讀單章)、`book`(全書預覽)、`source`(原始碼編輯)。
|
|
50
|
+
- `section` — 該位置所屬的最近一個小節標題。
|
|
51
|
+
- `block` — 作者最後點選、或畫面最上方正在閱讀的區塊:`line` 是它在檔案中的起始行(從 1 起算),`text` 是前 120 字,用來確認你找對地方。
|
|
52
|
+
- `selection` — 作者目前選取的文字;沒有選取時為 `null`。「這句」「這幾個字」指的就是它。
|
|
53
|
+
- 在書架或大綱頁時,`chapter`、`block` 可能是 `null`。
|
|
54
|
+
|
|
55
|
+
## 新舊判斷
|
|
56
|
+
|
|
57
|
+
- `updatedAt` 在 5 分鐘內 → 直接採用。
|
|
58
|
+
- 超過 5 分鐘 → 先向作者確認位置再動手(介面可能沒開,或作者已經在別處)。
|
|
59
|
+
- 好幾個小時以上 → 忽略,直接問作者。
|
|
60
|
+
- 檔案不存在 → 介面還沒開過。不要自己建立或猜測,請作者指名,或打開 `npm run dev` 後再試。
|
|
61
|
+
|
|
62
|
+
## 什麼時候不需要
|
|
63
|
+
|
|
64
|
+
- 作者明確指名了書、章或段落。
|
|
65
|
+
- `apply-comments` 用留言標記本身定位,不需要這個檔案。
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: kickoff
|
|
3
|
+
description: 新書/新論文的立項訪談。當專案裡還沒有任何書(books/ 是空的)、某本書的 stage 是 kickoff 或 brief.md 尚未完成,或作者說「開始」「我想寫一本書」「我要寫論文」「再開一本新書」「start」「kickoff」時使用 —— 全新專案時即使作者只打招呼也要主動開始。逐步訪談寫作目的、類型、讀者、核心主張、風格、篇幅與素材,然後建立書籍資料夾、寫好 brief.md 與 STYLE.md,最後接著進行 outline。
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# 立項訪談(Kickoff)
|
|
7
|
+
|
|
8
|
+
目標:動筆之前,和作者一起把「**為什麼寫、寫給誰、寫成什麼樣子**」講清楚並存成檔案,
|
|
9
|
+
讓之後每一次撰寫、審稿都有依據。你的角色像一位資深編輯(或論文指導者)在和作者聊天,不是在發問卷。
|
|
10
|
+
|
|
11
|
+
## 對話原則
|
|
12
|
+
|
|
13
|
+
- **一次只問一到兩題**。每題附 2–4 個具體選項或例子,讓作者用選的也能回答。
|
|
14
|
+
- 作者說「你幫我決定」→ 給出你的建議並說明理由,請作者確認。
|
|
15
|
+
- 作者已經說過的不要重問。作者一開頭就丟了一大段說明 → 先用幾句話整理你的理解,只補問缺的部分。
|
|
16
|
+
- 全程大約 6–10 輪。用作者使用的語言(預設台灣繁體中文)。
|
|
17
|
+
- 先讀 `notes/author.md`(如果存在):作者背景已知就不要再問,只確認是否有更新。
|
|
18
|
+
- 專案裡已經有其他書 → 問作者這本要不要沿用某本書的風格(可以複製那本的 `STYLE.md` 再調整)。
|
|
19
|
+
|
|
20
|
+
## 要弄清楚的事
|
|
21
|
+
|
|
22
|
+
依序進行,但可以依對話自然調整:
|
|
23
|
+
|
|
24
|
+
1. **類型與目的** — 書(商管、科普、技術、教科書、小說、散文、回憶錄…)、論文(碩博士學位論文、期刊論文、研究報告)、或其他長篇寫作?為什麼想寫?寫完希望達成什麼(出版、畢業、建立專業形象、留給家人…)?
|
|
25
|
+
2. **讀者** — 誰會讀?他們已經知道什麼、卡在哪裡?讀完之後應該「知道什麼/能做到什麼/相信什麼」?
|
|
26
|
+
3. **核心主張** — 用一句話說出這本書的核心。論文則是:研究問題、研究對象、研究方法、預期貢獻。
|
|
27
|
+
4. **風格與語氣** — 正式或口語?用「你」還是「您」?第一人稱?有沒有欣賞的作者或參考書?
|
|
28
|
+
**請作者貼一段自己寫過的文字**(最能抓到語感)。專有名詞中英文怎麼寫、數字用國字或阿拉伯數字。
|
|
29
|
+
5. **篇幅與結構** — 預計字數(一般書約 6–10 萬字;碩士論文常見 3–8 萬字)、大概幾章、有沒有既定架構
|
|
30
|
+
(論文常見:緒論、文獻探討、研究方法、研究結果與討論、結論與建議)。
|
|
31
|
+
6. **既有素材** — 有沒有寫好的稿子、筆記、資料、參考文獻?
|
|
32
|
+
- Word 舊稿:可以用 `npx mosage import 檔案.docx --book <代號>` 匯入(會依標題樣式切成章節)。
|
|
33
|
+
- 其他素材:請作者放進 `books/<代號>/notes/`。
|
|
34
|
+
7. **限制** — 截稿日;出版社或學校的格式規定(字型、字級、行距、邊界、引用格式如 APA 第 7 版)。
|
|
35
|
+
|
|
36
|
+
## 建立與寫檔
|
|
37
|
+
|
|
38
|
+
訪談結束時,先把整理好的摘要給作者看,**作者確認後**才寫檔:
|
|
39
|
+
|
|
40
|
+
1. **建立書籍資料夾**(如果這本書還不存在):
|
|
41
|
+
```bash
|
|
42
|
+
npx mosage new <代號> --title "<暫定書名>" --type book|thesis|other
|
|
43
|
+
```
|
|
44
|
+
代號用簡短英文與 `-`(例如 `ai-writing-guide`、`master-thesis`),之後不要再改。
|
|
45
|
+
這會建立 `books/<代號>/`(book.yaml、brief.md、STYLE.md、chapters/、assets/、notes/)並加入書架。
|
|
46
|
+
2. **`books/<代號>/brief.md`** — 寫作企劃,整份取代原本的佔位文字,格式如下。
|
|
47
|
+
3. **`books/<代號>/STYLE.md`** — 風格指南(格式如下)。
|
|
48
|
+
4. **`books/<代號>/book.yaml`** — 設定 `type`、`title`、`subtitle`、`targetWords`,並把 `stage` 改為 `outline`。
|
|
49
|
+
有格式規定時調整 `export`(字型、字級、行距、邊界…)。只改需要的欄位,保留檔案裡的註解。
|
|
50
|
+
5. **`notes/author.md`**(專案根目錄)— 若訪談中得到作者背景而這個檔案還不存在,簡短記下(專業、經歷、寫作偏好),以後的新書不用重問。
|
|
51
|
+
6. 作者名字若還沒設定,寫入 `mosage.yaml` 的 `author`(所有書共用)。
|
|
52
|
+
|
|
53
|
+
### brief.md 格式
|
|
54
|
+
|
|
55
|
+
```markdown
|
|
56
|
+
# 寫作企劃:<暫定書名>
|
|
57
|
+
|
|
58
|
+
## 一句話
|
|
59
|
+
<核心主張/研究問題,一句話>
|
|
60
|
+
|
|
61
|
+
## 類型與目的
|
|
62
|
+
- 類型:
|
|
63
|
+
- 為什麼寫:
|
|
64
|
+
- 成功的樣子:
|
|
65
|
+
|
|
66
|
+
## 讀者
|
|
67
|
+
- 誰:
|
|
68
|
+
- 他們現在的狀態/痛點:
|
|
69
|
+
- 讀完後會:
|
|
70
|
+
|
|
71
|
+
## 內容範圍
|
|
72
|
+
- 一定要談:
|
|
73
|
+
- 不談(刻意排除):
|
|
74
|
+
|
|
75
|
+
## 篇幅與結構
|
|
76
|
+
- 目標字數:
|
|
77
|
+
- 預計章數:
|
|
78
|
+
- 結構偏好:
|
|
79
|
+
|
|
80
|
+
## 既有素材
|
|
81
|
+
- …
|
|
82
|
+
|
|
83
|
+
## 限制與格式要求
|
|
84
|
+
- 截稿:
|
|
85
|
+
- 格式:
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### STYLE.md 格式
|
|
89
|
+
|
|
90
|
+
```markdown
|
|
91
|
+
# 風格指南
|
|
92
|
+
|
|
93
|
+
## 語氣與人稱
|
|
94
|
+
## 句子與段落(句長、段落長度、每段一個重點…)
|
|
95
|
+
## 用語表(統一的譯名、專有名詞、要避免的詞)
|
|
96
|
+
## 標點與數字
|
|
97
|
+
## 引用與註腳(論文:APA 第 7 版,文中(作者,年份);書:以註腳註明出處…)
|
|
98
|
+
## 範例段落
|
|
99
|
+
<用這個風格寫的一段示範,最好改寫自作者提供的文字>
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## 結束
|
|
103
|
+
|
|
104
|
+
用兩三句話告訴作者你建立了哪些檔案,提醒他可以在瀏覽器(`npm run dev`)的書架上看到這本書,
|
|
105
|
+
然後**直接接著使用 `outline` skill** 提出書名與章節架構 —— 除非作者想先停下來。
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: mosage-reference
|
|
3
|
+
description: MoSage 的技術參考 —— 專案與書籍資料夾結構、book.yaml/mosage.yaml 欄位、章節檔格式、支援的 Markdown 與它在 Word 裡的樣子、留言與修改建議的標記語法、指令。在建立或修改 books/ 底下任何檔案之前閱讀;不確定格式時回來查。
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# MoSage 技術參考
|
|
7
|
+
|
|
8
|
+
MoSage 沒有資料庫:**一切都是專案資料夾裡的純文字檔**。圖片與參考資料直接複製進資料夾即可。
|
|
9
|
+
|
|
10
|
+
## 專案結構
|
|
11
|
+
|
|
12
|
+
```
|
|
13
|
+
mosage.yaml 專案預設值(所有書共用)
|
|
14
|
+
notes/ 共用素材(author.md …)
|
|
15
|
+
books/<代號>/
|
|
16
|
+
book.yaml 這本書的設定(覆寫 mosage.yaml)
|
|
17
|
+
brief.md 寫作企劃
|
|
18
|
+
STYLE.md 風格指南
|
|
19
|
+
chapters/NN-name.md 章節,一章一檔
|
|
20
|
+
assets/ 圖片
|
|
21
|
+
notes/ 這本書的素材(不匯出)
|
|
22
|
+
output/<代號>/ 匯出結果
|
|
23
|
+
.mosage/current.json 作者目前在介面上的位置(唯讀)
|
|
24
|
+
.mosage/history/ 自動版本快照(唯讀)
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
書的代號(資料夾名)用英文小寫、數字與 `-`,建立後不要改名。新書用
|
|
28
|
+
`npx mosage new <代號> --title "書名" --type book|thesis|other` 建立,不要手動複製資料夾。
|
|
29
|
+
|
|
30
|
+
## book.yaml
|
|
31
|
+
|
|
32
|
+
```yaml
|
|
33
|
+
type: book # book | thesis | other
|
|
34
|
+
stage: writing # kickoff | outline | writing | revising | done
|
|
35
|
+
title: 和 AI 一起寫書
|
|
36
|
+
subtitle: 從立項到出版的協作流程
|
|
37
|
+
author: 陳小明 # 省略則用 mosage.yaml 的 author
|
|
38
|
+
targetWords: 80000 # 目標字數(中文字+英文單字)
|
|
39
|
+
chapters: # 章節順序=目錄順序;只有列在這裡的會被匯出
|
|
40
|
+
- 00-preface.md
|
|
41
|
+
- 01-why.md
|
|
42
|
+
ai:
|
|
43
|
+
editMode: suggest # suggest | direct(省略則用 mosage.yaml)
|
|
44
|
+
export: # Word 格式,省略的欄位依 type 套用預設
|
|
45
|
+
pageSize: A4 # A4 | A5 | B5 | Letter | { width: 170, height: 230 }(mm)
|
|
46
|
+
margins: { top: 25, bottom: 25, left: 30, right: 25 } # mm
|
|
47
|
+
fonts: { body: 標楷體, latin: Times New Roman, heading: 標楷體, code: Consolas }
|
|
48
|
+
fontSize: 12 # pt
|
|
49
|
+
lineSpacing: 1.5
|
|
50
|
+
firstLineIndent: 2 # 首行縮排字數
|
|
51
|
+
paragraphSpacing: 0 # 段後距 pt
|
|
52
|
+
titlePage: true
|
|
53
|
+
toc: true
|
|
54
|
+
chapterPageBreak: true
|
|
55
|
+
pageNumbers: true
|
|
56
|
+
header: title # none | title | chapter
|
|
57
|
+
sceneBreak: * * *
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
修改 YAML 時只動需要的欄位,保留作者的註解。`chapters:` 裡的檔名必須真的存在於 `chapters/`。
|
|
61
|
+
|
|
62
|
+
## 章節檔
|
|
63
|
+
|
|
64
|
+
```markdown
|
|
65
|
+
---
|
|
66
|
+
status: draft # idea(構想)| draft(草稿)| revising(修訂中)| done(完成)
|
|
67
|
+
summary: 這一章讓讀者理解…… # 一兩句,大綱頁會顯示
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
# 第一章 章名
|
|
71
|
+
|
|
72
|
+
## 1.1 小節
|
|
73
|
+
|
|
74
|
+
正文……
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
- 每個檔案**只有一個** `#` 標題,就是章名(在 Word 中是「標題 1」,會自動換頁並進入目錄)。
|
|
78
|
+
- `##` → 標題 2、`###` → 標題 3(都會進目錄),`####` 以下 → 標題 4。
|
|
79
|
+
- frontmatter 只給 MoSage 用,不會匯出。
|
|
80
|
+
|
|
81
|
+
## 支援的 Markdown(以及 Word 裡的樣子)
|
|
82
|
+
|
|
83
|
+
| 寫法 | 匯出成 |
|
|
84
|
+
| --- | --- |
|
|
85
|
+
| 一般段落 | 內文樣式(首行縮排、行距依設定) |
|
|
86
|
+
| `**粗體**`、`*斜體*`、`~~刪除線~~`、`` `程式碼` `` | 對應的文字格式 |
|
|
87
|
+
| `[文字](https://…)` | 超連結 |
|
|
88
|
+
| `- 項目`、`1. 項目`(可巢狀) | 項目符號/編號清單 |
|
|
89
|
+
| `> 引文` | 引文樣式 |
|
|
90
|
+
| `> [!NOTE]`、`[!TIP]`、`[!IMPORTANT]`、`[!WARNING]`、`[!CAUTION]` | 提示框(注意/提示/重要/警告/小心) |
|
|
91
|
+
| ```` ```語言 ```` 程式碼區塊 | 等寬字型區塊 |
|
|
92
|
+
| GFM 表格 | Word 表格(標題列加粗、跨頁重複) |
|
|
93
|
+
| `` | 置中圖片,下方加圖說;寬度自動縮到版心 |
|
|
94
|
+
| `文字[^1]` + `[^1]: 註腳內容` | Word 註腳(每頁頁尾) |
|
|
95
|
+
| `---`(單獨一行,前後空行) | 場景分隔(置中的 * * *) |
|
|
96
|
+
| `<!-- pagebreak -->` | 強制換頁 |
|
|
97
|
+
|
|
98
|
+
- 圖片路徑相對於章節檔,所以是 `../assets/檔名`。支援 png、jpg、gif、bmp。檔名建議英數字。
|
|
99
|
+
- 註腳編號在每章內唯一即可,匯出時會自動重新編號。
|
|
100
|
+
- 其他 HTML 標籤不會匯出,請不要使用。
|
|
101
|
+
|
|
102
|
+
## 標記:留言與修改建議
|
|
103
|
+
|
|
104
|
+
標記是 HTML 註解,任何 Markdown 工具都看不到,也不會被匯出。**標記屬於它正下方的那個區塊**
|
|
105
|
+
(段落、標題、清單、表格、引文…)。標記與區塊之間不要空行。
|
|
106
|
+
|
|
107
|
+
### 留言 `mosage:comment`
|
|
108
|
+
|
|
109
|
+
```markdown
|
|
110
|
+
<!-- mosage:comment id=c-1a2b3c4d by=human at=2026-09-26T08:00:00Z quote="被選取的文字"
|
|
111
|
+
留言內容,可以多行
|
|
112
|
+
-->
|
|
113
|
+
被留言的段落。
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
- `by=human`:作者留給你的 → 用 `apply-comments` 處理。
|
|
117
|
+
- `by=ai`:你留給作者的(需要資料、提問、審稿意見)→ 作者在介面上看過後會刪除。
|
|
118
|
+
- 單行寫法也可以:`<!-- mosage:comment by=ai 這裡需要資料來源 -->`
|
|
119
|
+
|
|
120
|
+
### 修改建議 `mosage:suggest`
|
|
121
|
+
|
|
122
|
+
```markdown
|
|
123
|
+
<!-- mosage:suggest by=ai note="一句話說明改了什麼"
|
|
124
|
+
取代下方區塊的完整新文字。
|
|
125
|
+
-->
|
|
126
|
+
原本的段落。
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
- `span=N`:取代下方連續 N 個區塊(預設 1)。內容寫出全部新文字,區塊之間空一行。
|
|
130
|
+
- `span=0`:不取代,只在下方區塊之前插入新內容。
|
|
131
|
+
- 作者在介面上看到新舊對照,按「接受」後內容才寫入;按「拒絕」則標記被刪除。
|
|
132
|
+
|
|
133
|
+
### 屬性
|
|
134
|
+
|
|
135
|
+
| 屬性 | 說明 |
|
|
136
|
+
| --- | --- |
|
|
137
|
+
| `id` | 可省略(系統會依內容產生)。自己加的話用 `c-`/`s-` 加 8 個十六進位字元 |
|
|
138
|
+
| `by` | `human` 或 `ai` |
|
|
139
|
+
| `at` | ISO 時間,可省略 |
|
|
140
|
+
| `quote` | 被選取的文字 |
|
|
141
|
+
| `note` | 修改建議的說明 |
|
|
142
|
+
| `span` | 修改建議取代的區塊數 |
|
|
143
|
+
|
|
144
|
+
含空白或特殊字元的值用雙引號,內部的 `"` 寫成 `\"`。內容裡不能出現 `-->`。
|
|
145
|
+
|
|
146
|
+
## 指令
|
|
147
|
+
|
|
148
|
+
```bash
|
|
149
|
+
npx mosage status # 書架總覽
|
|
150
|
+
npx mosage status <書> [--json] # 單本:章節、字數、待處理標記(含行號)、找不到的圖片
|
|
151
|
+
npx mosage new <代號> --title … --type book|thesis|other
|
|
152
|
+
npx mosage export <書> [docx|html|md] [--out 路徑]
|
|
153
|
+
npx mosage import <檔案.docx|.md> [--book <代號>] [--no-split] [--unlisted]
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
## 作者在介面上能做的事(引導作者時可以提到)
|
|
157
|
+
|
|
158
|
+
- **書架**:所有書的進度;新增一本書
|
|
159
|
+
- **大綱**:拖曳章節排序、改章名與摘要、設定章節狀態、新增章節、移出目錄
|
|
160
|
+
- **閱讀**:書本排版預覽;選取文字 → 留言給 AI;雙擊段落直接修改;接受/拒絕修改建議
|
|
161
|
+
- **原始碼**:Markdown 編輯器(左右對照預覽)
|
|
162
|
+
- **素材**:把圖片、參考檔拖進來,會複製到這本書的 `assets/` 或 `notes/`
|
|
163
|
+
- **版本紀錄**:每次修改前自動保存,可比較差異並還原
|
|
164
|
+
- **匯出**:Word(.docx)、HTML(可列印成 PDF)、合併的 Markdown
|