@takagaki/cortex-decisions-viewer 0.4.11 → 0.4.12
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/dist/build.js +7 -0
- package/dist/cli.js +6 -0
- package/dist/render.js +108 -15
- package/package.json +1 -1
package/dist/build.js
CHANGED
|
@@ -875,6 +875,13 @@ async function build(opts) {
|
|
|
875
875
|
graph,
|
|
876
876
|
categories,
|
|
877
877
|
months,
|
|
878
|
+
intake: opts.intakeUrl && opts.projectKey
|
|
879
|
+
? {
|
|
880
|
+
url: opts.intakeUrl,
|
|
881
|
+
token: opts.intakeToken ?? "",
|
|
882
|
+
projectKey: opts.projectKey,
|
|
883
|
+
}
|
|
884
|
+
: undefined,
|
|
878
885
|
};
|
|
879
886
|
// サムネイル(デザイン画面等)をサイトに同梱し、ノードのパスをサイト内相対に書き換える
|
|
880
887
|
await node_fs_1.promises.mkdir(outAbs, { recursive: true });
|
package/dist/cli.js
CHANGED
|
@@ -16,6 +16,9 @@ program
|
|
|
16
16
|
.option("--repo-url <url>", "GitHubリポジトリURL(未指定なら git remote から解決)")
|
|
17
17
|
.option("--branch <branch>", "編集リンクが指すブランチ(既定: main / 環境変数 AWS_BRANCH)")
|
|
18
18
|
.option("--exclude <files...>", "一覧から除外する追加ファイル名(既定で README.md / template.md は除外)", [])
|
|
19
|
+
.option("--intake-url <url>", "投入フォームのLambda URL(環境変数 INTAKE_URL でも可)")
|
|
20
|
+
.option("--intake-token <token>", "投入フォームの共有秘密トークン(環境変数 INTAKE_TOKEN でも可)")
|
|
21
|
+
.option("--project-key <key>", "案件キー(投入フォームのルーティングキー)")
|
|
19
22
|
.action(async (dir, opts) => {
|
|
20
23
|
try {
|
|
21
24
|
const result = await (0, build_1.build)({
|
|
@@ -26,6 +29,9 @@ program
|
|
|
26
29
|
branch: opts.branch,
|
|
27
30
|
exclude: opts.exclude ?? [],
|
|
28
31
|
generatedAt: new Date().toISOString().replace("T", " ").slice(0, 16) + " UTC",
|
|
32
|
+
intakeUrl: opts.intakeUrl ?? process.env.INTAKE_URL,
|
|
33
|
+
intakeToken: opts.intakeToken ?? process.env.INTAKE_TOKEN,
|
|
34
|
+
projectKey: opts.projectKey,
|
|
29
35
|
});
|
|
30
36
|
console.log(`✓ ${result.count} 件のレコードを ${result.outDir} にビルドしました`);
|
|
31
37
|
}
|
package/dist/render.js
CHANGED
|
@@ -14,13 +14,7 @@ function renderSite(site) {
|
|
|
14
14
|
? `https://claude.ai/code?repo=${repoSlug}&prompt=${encodeURIComponent(prompt)}`
|
|
15
15
|
: "https://claude.ai/code/";
|
|
16
16
|
const askUrl = codeUrl("このプロジェクトの概要について教えてください。");
|
|
17
|
-
//
|
|
18
|
-
if (repoSlug) {
|
|
19
|
-
site.intake = {
|
|
20
|
-
transcript: codeUrl("会議の文字起こしを取り込みます。まず 会議/README.md(無ければ MTG/README.md 等の会議ディレクトリのREADME)と 会議/templates/minute-template.md を読んでください。次のメッセージで、ダウンロードした文字起こしファイル(.txt / .docx 等)を添付するので、その内容を読み、テンプレートの様式に従って議事録を生成し、文字起こし原本と議事録を会議ディレクトリの規約どおりの場所にコミットしてください。/post-meeting や /create-minute スラッシュコマンドが使えるならそれを使ってよいですが、使えなくても手動で作成して構いません。議事録に frontmatter は付けないでください。"),
|
|
21
|
-
material: codeUrl("共有資料を取り込みます。まず 共有資料/README.md を読んでください。次のメッセージで資料(テキストまたはファイル)を渡すので、それを Markdown 化して 共有資料/{資料名}/{資料名}.md に配置し、元ファイルも同じディレクトリに残してコミットしてください(PDF・PPT は中身を読み、図表も文章で説明して Markdown 化する)。/sync-materials スラッシュコマンドが使えるならそれを使ってよいですが、使えなくても手動で構いません。frontmatter は付けないでください。"),
|
|
22
|
-
};
|
|
23
|
-
}
|
|
17
|
+
// ※ 投入フォーム設定 site.intake は build.ts が --intake-url/--intake-token/--project-key から付与する。
|
|
24
18
|
const dataJson = JSON.stringify(site).replace(/</g, "\\u003c");
|
|
25
19
|
const safeTitle = escapeHtml(site.title);
|
|
26
20
|
const githubBtn = site.repoBaseUrl
|
|
@@ -347,6 +341,35 @@ a:hover { text-decoration: underline; }
|
|
|
347
341
|
background: var(--accent); color: #fff; font-size: 13px; font-weight: 600;
|
|
348
342
|
}
|
|
349
343
|
.ops-card-btn:hover { background: #1d4ed8; text-decoration: none; }
|
|
344
|
+
button.ops-card-btn { cursor: pointer; }
|
|
345
|
+
button.ops-card-btn:disabled { opacity: .6; cursor: default; }
|
|
346
|
+
/* ---- 投入モーダル ---- */
|
|
347
|
+
.modal-overlay {
|
|
348
|
+
position: fixed; inset: 0; z-index: 100; display: flex; align-items: center; justify-content: center;
|
|
349
|
+
background: rgba(16,24,40,0.45); padding: 20px;
|
|
350
|
+
-webkit-backdrop-filter: blur(2px); backdrop-filter: blur(2px);
|
|
351
|
+
}
|
|
352
|
+
.modal {
|
|
353
|
+
background: var(--surface); border: 1px solid var(--border); border-radius: 14px;
|
|
354
|
+
box-shadow: 0 12px 40px rgba(16,24,40,0.25); width: 100%; max-width: 480px;
|
|
355
|
+
max-height: 90vh; overflow-y: auto; padding: 22px; display: flex; flex-direction: column; gap: 12px;
|
|
356
|
+
}
|
|
357
|
+
.modal-title { font-size: 17px; font-weight: 700; margin: 0; color: var(--text); }
|
|
358
|
+
.modal-desc { font-size: 13px; color: var(--muted); line-height: 1.7; margin: 0; }
|
|
359
|
+
.modal-field { display: flex; flex-direction: column; gap: 4px; }
|
|
360
|
+
.modal-field-label { font-size: 12px; font-weight: 600; color: var(--muted); }
|
|
361
|
+
.modal-file, .modal-name, .modal-text {
|
|
362
|
+
border: 1px solid var(--border); border-radius: 8px; padding: 8px 10px; font-size: 14px; color: var(--text);
|
|
363
|
+
background: var(--bg); width: 100%; box-sizing: border-box;
|
|
364
|
+
}
|
|
365
|
+
.modal-text { resize: vertical; min-height: 90px; }
|
|
366
|
+
.modal-status { font-size: 13px; color: var(--muted); min-height: 18px; line-height: 1.6; }
|
|
367
|
+
.modal-actions { display: flex; justify-content: flex-end; gap: 8px; margin-top: 4px; }
|
|
368
|
+
.modal-cancel {
|
|
369
|
+
padding: 8px 16px; border-radius: 999px; border: 1px solid var(--border);
|
|
370
|
+
background: var(--surface); color: var(--muted); font-size: 13px; font-weight: 600; cursor: pointer;
|
|
371
|
+
}
|
|
372
|
+
.modal-cancel:hover { background: var(--bg); }
|
|
350
373
|
.summary-box { background: var(--accent-weak); border: 1px solid #dce6fb; border-radius: var(--radius); padding: 12px 16px; color: #1e3a8a; }
|
|
351
374
|
.deciders { display: flex; flex-wrap: wrap; gap: 8px; }
|
|
352
375
|
.refs { margin: 0; padding-left: 18px; }
|
|
@@ -602,27 +625,97 @@ const CLIENT_JS = `
|
|
|
602
625
|
|
|
603
626
|
// ---------- 操作タブ(Cortex自体への操作。まずは取り込み。今後この受け皿に機能を足す) ----------
|
|
604
627
|
function renderOps() {
|
|
605
|
-
|
|
606
|
-
app.appendChild(el("p", { class: "ops-intro", text: "Cortex にコンテキストを取り込む操作です。ボタンを押すと Claude Code Web がこの案件のリポジトリで開くので、内容を貼る/渡すと議事録化・Markdown化してコミットまで行います。" }));
|
|
628
|
+
app.appendChild(el("p", { class: "ops-intro", text: "Cortex にコンテキストを取り込む操作です。ファイルを選ぶかテキストを貼って送信すると、自動で取り込まれます(数分で反映)。" }));
|
|
607
629
|
app.appendChild(el("div", { class: "section-label", text: "取り込み" }));
|
|
608
630
|
var grid = el("div", { class: "ops-grid" });
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
grid.appendChild(opsCard("📎", "共有資料を追加", "提案書・仕様書・議事メモなどの資料を渡して Markdown 化し、共有資料に取り込みます。", intake.material, "資料を追加"));
|
|
612
|
-
}
|
|
631
|
+
grid.appendChild(opsCard("🗒️", "会議の文字起こしを追加", "顧客主催の会議など、自動取り込みできない会議の文字起こしファイル(.txt / .docx 等)から議事録を生成します。", "transcript", "文字起こしを追加"));
|
|
632
|
+
grid.appendChild(opsCard("📎", "共有資料を追加", "提案書・仕様書・議事メモなどの資料を Markdown 化して 共有資料 に取り込みます。", "material", "資料を追加"));
|
|
613
633
|
app.appendChild(grid);
|
|
614
634
|
}
|
|
615
|
-
function opsCard(icon, title, desc,
|
|
635
|
+
function opsCard(icon, title, desc, kind, btnLabel) {
|
|
636
|
+
var btn = el("button", { class: "ops-card-btn", text: "+ " + btnLabel });
|
|
637
|
+
btn.addEventListener("click", function () { openIntakeModal(kind); });
|
|
616
638
|
return el("div", { class: "ops-card" }, [
|
|
617
639
|
el("div", { class: "ops-card-head" }, [
|
|
618
640
|
el("span", { class: "ops-card-icon", text: icon }),
|
|
619
641
|
el("h3", { class: "ops-card-title", text: title }),
|
|
620
642
|
]),
|
|
621
643
|
el("p", { class: "ops-card-desc", text: desc }),
|
|
622
|
-
|
|
644
|
+
btn,
|
|
623
645
|
]);
|
|
624
646
|
}
|
|
625
647
|
|
|
648
|
+
// 投入モーダル(ファイル選択+自由テキスト+お名前 → presign→S3 PUT→submit)
|
|
649
|
+
function fieldRow(label, control) {
|
|
650
|
+
return el("label", { class: "modal-field" }, [
|
|
651
|
+
el("span", { class: "modal-field-label", text: label }),
|
|
652
|
+
control,
|
|
653
|
+
]);
|
|
654
|
+
}
|
|
655
|
+
function openIntakeModal(kind) {
|
|
656
|
+
var intake = SITE.intake;
|
|
657
|
+
if (!intake) return;
|
|
658
|
+
var isT = kind === "transcript";
|
|
659
|
+
var overlay = el("div", { class: "modal-overlay" });
|
|
660
|
+
var modal = el("div", { class: "modal" });
|
|
661
|
+
modal.appendChild(el("h2", { class: "modal-title", text: isT ? "会議の文字起こしを追加" : "共有資料を追加" }));
|
|
662
|
+
modal.appendChild(el("p", { class: "modal-desc", text: isT
|
|
663
|
+
? "文字起こしファイル(.txt / .docx 等)を選ぶか、下のテキスト欄に貼り付けてください。送信すると議事録を自動生成します。"
|
|
664
|
+
: "資料ファイル(PDF / PPT / Excel 等)を選ぶか、下のテキスト欄に内容を貼り付けてください。送信すると Markdown 化して取り込みます。" }));
|
|
665
|
+
var fileInput = el("input", { type: "file", multiple: "multiple", class: "modal-file" });
|
|
666
|
+
var nameInput = el("input", { type: "text", class: "modal-name", placeholder: "お名前(任意・投入者として記録されます)" });
|
|
667
|
+
var textArea = el("textarea", { class: "modal-text", rows: "5", placeholder: isT ? "(任意)文字起こしテキストを直接貼り付け" : "(任意)テキスト内容やメモを直接入力" });
|
|
668
|
+
modal.appendChild(fieldRow("ファイル", fileInput));
|
|
669
|
+
modal.appendChild(fieldRow("お名前", nameInput));
|
|
670
|
+
modal.appendChild(fieldRow("テキスト(自由入力)", textArea));
|
|
671
|
+
var status = el("div", { class: "modal-status" });
|
|
672
|
+
var cancelBtn = el("button", { class: "modal-cancel", text: "閉じる" });
|
|
673
|
+
var submitBtn = el("button", { class: "ops-card-btn", text: "送信" });
|
|
674
|
+
modal.appendChild(status);
|
|
675
|
+
modal.appendChild(el("div", { class: "modal-actions" }, [cancelBtn, submitBtn]));
|
|
676
|
+
overlay.appendChild(modal);
|
|
677
|
+
document.body.appendChild(overlay);
|
|
678
|
+
function close() { if (overlay.parentNode) document.body.removeChild(overlay); }
|
|
679
|
+
cancelBtn.addEventListener("click", close);
|
|
680
|
+
overlay.addEventListener("click", function (e) { if (e.target === overlay) close(); });
|
|
681
|
+
submitBtn.addEventListener("click", function () {
|
|
682
|
+
submitIntake(kind, fileInput.files, textArea.value, nameInput.value, status, submitBtn);
|
|
683
|
+
});
|
|
684
|
+
}
|
|
685
|
+
async function submitIntake(kind, fileList, text, submitter, status, submitBtn) {
|
|
686
|
+
var intake = SITE.intake;
|
|
687
|
+
var files = fileList ? Array.prototype.slice.call(fileList) : [];
|
|
688
|
+
if (!files.length && !(text && text.trim())) { status.textContent = "ファイルかテキストを入力してください。"; return; }
|
|
689
|
+
submitBtn.disabled = true;
|
|
690
|
+
var pfx = intake.url + (intake.url.indexOf("?") === -1 ? "?" : "&");
|
|
691
|
+
try {
|
|
692
|
+
var uploaded = [];
|
|
693
|
+
for (var i = 0; i < files.length; i++) {
|
|
694
|
+
var f = files[i];
|
|
695
|
+
status.textContent = "アップロード中… (" + (i + 1) + "/" + files.length + ") " + f.name;
|
|
696
|
+
var pres = await fetch(pfx + "op=presign&t=" + encodeURIComponent(intake.token), {
|
|
697
|
+
method: "POST", headers: { "content-type": "application/json" },
|
|
698
|
+
body: JSON.stringify({ projectKey: intake.projectKey, filename: f.name, contentType: f.type || "application/octet-stream" }),
|
|
699
|
+
}).then(function (r) { return r.json(); });
|
|
700
|
+
if (!pres.url) throw new Error(pres.message || "アップロードURLの取得に失敗しました");
|
|
701
|
+
var put = await fetch(pres.url, { method: "PUT", headers: { "content-type": f.type || "application/octet-stream" }, body: f });
|
|
702
|
+
if (!put.ok) throw new Error("アップロードに失敗しました (" + put.status + ")");
|
|
703
|
+
uploaded.push({ key: pres.key, filename: f.name });
|
|
704
|
+
}
|
|
705
|
+
status.textContent = "取り込み中…";
|
|
706
|
+
var sub = await fetch(pfx + "op=submit&t=" + encodeURIComponent(intake.token), {
|
|
707
|
+
method: "POST", headers: { "content-type": "application/json" },
|
|
708
|
+
body: JSON.stringify({ projectKey: intake.projectKey, kind: kind, files: uploaded, text: text || "", submitter: submitter || "" }),
|
|
709
|
+
}).then(function (r) { return r.json().then(function (j) { return { ok: r.ok, j: j }; }); });
|
|
710
|
+
if (!sub.ok) throw new Error((sub.j && sub.j.message) || "取り込みに失敗しました");
|
|
711
|
+
status.textContent = "✓ 送信しました。数分後に" + (kind === "transcript" ? "議事録" : "資料") + "が反映されます。";
|
|
712
|
+
submitBtn.textContent = "完了";
|
|
713
|
+
} catch (e) {
|
|
714
|
+
status.textContent = "✗ " + (e && e.message ? e.message : "エラーが発生しました");
|
|
715
|
+
submitBtn.disabled = false;
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
|
|
626
719
|
// ---------- Decisions一覧(フィルタ付き) ----------
|
|
627
720
|
function renderDecisionList() {
|
|
628
721
|
// 既存案件・移行案件は導入前/移行前の意思決定が揃わないため、その旨を最初に注記する
|
package/package.json
CHANGED