@takagaki/cortex-decisions-viewer 0.4.34 → 0.4.36
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 +1 -0
- package/dist/render.js +298 -32
- package/package.json +1 -1
package/dist/build.js
CHANGED
|
@@ -1022,6 +1022,7 @@ async function parseDecision(raw, fileName, repoRelDir, repoBaseUrl, branch) {
|
|
|
1022
1022
|
bodyHtml,
|
|
1023
1023
|
bodyRef: "",
|
|
1024
1024
|
searchText: toSearchText(content),
|
|
1025
|
+
rstatus: data.status != null ? String(data.status) : "",
|
|
1025
1026
|
fileName,
|
|
1026
1027
|
editUrl,
|
|
1027
1028
|
fm: sanitizeFm(data),
|
package/dist/render.js
CHANGED
|
@@ -197,12 +197,45 @@ function buildTutorialData(site, codeUrl, repoSlug) {
|
|
|
197
197
|
prompt: "直近2週間の主要な動き・論点・未解決事項を、議事録や決定記録を横断してまとめてください。",
|
|
198
198
|
},
|
|
199
199
|
];
|
|
200
|
-
//
|
|
200
|
+
// ここから先は「書き込み・外部連携」の体験。案件の構成に無い能力のチャレンジは出さない(表示条件つき)
|
|
201
|
+
const tools = site.tools ?? {};
|
|
202
|
+
const internals = site.internalSources ?? [];
|
|
203
|
+
const externals = site.externalSources ?? [];
|
|
204
|
+
// メンバーの自分のレコードを直す体験(Members セクションがある案件のみ出す)
|
|
201
205
|
if ((site.sections ?? []).some((s) => s.name === "Members" || s.name === "メンバー")) {
|
|
202
206
|
specs.push({
|
|
203
207
|
title: "自分の名前を変更してみよう",
|
|
204
208
|
desc: "メンバー一覧の自分のレコードをAIに直してもらう",
|
|
205
|
-
prompt:
|
|
209
|
+
prompt: TUT_MEMBER_PROMPT,
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
// Backlogに記票する体験(課題管理にBacklogを使う案件のみ出す)
|
|
213
|
+
const usesBacklog = tools["課題管理"] === "backlog" ||
|
|
214
|
+
internals.some((s) => s.kind === "課題管理" && s.tool === "backlog" && s.enabled !== false);
|
|
215
|
+
if (usesBacklog) {
|
|
216
|
+
specs.push({
|
|
217
|
+
title: "Backlogに記票してみよう",
|
|
218
|
+
desc: "AIから自分の名義で課題にコメントする",
|
|
219
|
+
prompt: TUT_BACKLOG_PROMPT,
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
// 画面インベントリを読む体験(デザインを同期している案件のみ出す)
|
|
223
|
+
const usesDesign = (tools["デザイン"] != null && tools["デザイン"] !== "none") ||
|
|
224
|
+
internals.some((s) => s.kind === "デザイン" && s.enabled !== false);
|
|
225
|
+
if (usesDesign) {
|
|
226
|
+
specs.push({
|
|
227
|
+
title: "デザインを読んでみよう",
|
|
228
|
+
desc: "画面インベントリから1画面を選んで理解する",
|
|
229
|
+
prompt: TUT_DESIGN_PROMPT,
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
// 完了をSlackに知らせる体験(チャットにSlackを宣言している案件のみ出す。最終チャレンジ)
|
|
233
|
+
const usesSlack = tools["チャット"] === "slack" || externals.some((s) => s.type === "slack");
|
|
234
|
+
if (usesSlack) {
|
|
235
|
+
specs.push({
|
|
236
|
+
title: "Slackに完了を知らせよう",
|
|
237
|
+
desc: "チュートリアルの完了を案件のチャンネルに投稿する",
|
|
238
|
+
prompt: TUT_SLACK_PROMPT,
|
|
206
239
|
});
|
|
207
240
|
}
|
|
208
241
|
return {
|
|
@@ -234,6 +267,92 @@ function tutorialChallenge4Prompt(decisions) {
|
|
|
234
267
|
return (`このプロジェクトの決定「${picked.title}」(${picked.id})について、なぜこの結論に至ったのか、` +
|
|
235
268
|
"根拠になった会議や課題まで遡って経緯を説明してください。関連する未解決の論点があれば併せて教えてください。");
|
|
236
269
|
}
|
|
270
|
+
/**
|
|
271
|
+
* 書き込み・外部連携をともなうチャレンジのプロンプト。
|
|
272
|
+
* リンク先はクラウド実行のセッションでエンジンのスキルがロードされないため、規約・手順を埋め込んで自己完結させる
|
|
273
|
+
* (AI導線ボタンのプロンプトと同じ方針)。スキルが使える環境ではそちらを優先させる旨を冒頭に添える。
|
|
274
|
+
*/
|
|
275
|
+
const TUT_MEMBER_PROMPT = [
|
|
276
|
+
"(update-member スキルが使える環境なら、そのスキルの手順を優先してください。使えない場合は以下に従ってください。)",
|
|
277
|
+
"",
|
|
278
|
+
"Cortex/Members/records/ にある、わたし自身のメンバーレコードの表示名(title)を変更してください。Gold層へ書き込む練習です。名簿にわたしのレコードが無ければ、新規登録として1ファイル作ってかまいません。",
|
|
279
|
+
"",
|
|
280
|
+
"前提:",
|
|
281
|
+
"- 名簿は更新型です。氏名・所属・役割が変わったら frontmatter・本文を直接更新してかまいません(変更履歴は git が持ちます)",
|
|
282
|
+
"- 新しい表記揺れ(文字起こしの誤変換・呼称)は新規ファイルを作らず aliases に追記します",
|
|
283
|
+
"- 本人やPMに確認が取れたら status: draft を active に上げます。確証が無い項目は推測で埋めず空のままにします",
|
|
284
|
+
"- 離任しても削除せず status: inactive にします(過去の議事録・決定の人名正規化の根拠として残すため)",
|
|
285
|
+
"",
|
|
286
|
+
"手順:",
|
|
287
|
+
"1. Cortex/Members/README.md(スキーマ)と、対象になるレコードを読む",
|
|
288
|
+
"2. わたしのレコードが無ければ、ファイル名 records/{氏名(スペース無し)}.md・id member:{氏名(スペース無し)} で新規に作る",
|
|
289
|
+
"3. frontmatter の必須は type: member / id(member:{氏名(スペース無し)}) / title / description / status。任意は yomi・aliases・org・side(cm | client | vendor)・role・email。README 定義以外のフィールドは追加しない",
|
|
290
|
+
"4. 名簿に書くのは氏名・所属・役割・表記揺れだけ。人の評価・人事・単価・工数は書かない",
|
|
291
|
+
"",
|
|
292
|
+
"共通ルール:",
|
|
293
|
+
"- 書き込む前に、作成・更新する内容を提示して承認を得てください",
|
|
294
|
+
"- 同じ人に複数ファイルを作らないよう、既存レコードとの重複を必ず確認してください",
|
|
295
|
+
"- relations の target にファイルパスは書かず、安定ID(member:{氏名} / 決定ID YYYYMMDD-NNN / 課題キー 等)で張ってください",
|
|
296
|
+
"- 売上・単価・工数・人事評価などの内部限定情報は書かないでください(このリポジトリは顧客も閲覧します)",
|
|
297
|
+
].join("\n");
|
|
298
|
+
const TUT_BACKLOG_PROMPT = [
|
|
299
|
+
"(backlog-push スキルが使える環境なら、そのスキルの手順を優先してください。使えない場合は以下に従ってください。)",
|
|
300
|
+
"",
|
|
301
|
+
"Backlogの課題に、わたしの名義でコメントを1件投稿してください。Backlogの画面を開かずにAIから記票する練習です。",
|
|
302
|
+
"",
|
|
303
|
+
"Backlogのつなぎ方(本人名義で投稿するには Backlog MCP の接続が必要です):",
|
|
304
|
+
"- 手元の Claude Code(CLI・デスクトップ)なら /mcp コマンドから backlog を選んで認証する",
|
|
305
|
+
"- クラウドのセッション(claude.ai/code)なら、セッションのコネクタ設定で Backlog を有効にする",
|
|
306
|
+
"",
|
|
307
|
+
"手順:",
|
|
308
|
+
"1. どの経路で書き込むかを次の優先順で判定し、判定結果とBacklog上の名義を最初に伝える",
|
|
309
|
+
" - mcp__backlog__ で始まるツールが使えるなら、それを使う(あなた本人の名義。手元にAPIキーは不要)",
|
|
310
|
+
" - 使えない場合、環境変数 DOMAIN / PROJECT_KEY / BACKLOG_API_KEY が参照できるなら Backlog REST API を直接呼ぶ(キーの持ち主の名義)",
|
|
311
|
+
" - どちらも無ければ 課題管理/backlog-proxy.json(url / projectKey / token)を読み、その中央プロキシ経由で投稿する(共有bot名義になるため、本文の冒頭に自分の名前を記名する)",
|
|
312
|
+
" - 3つとも無ければ、上記のつなぎ方を案内して止まる",
|
|
313
|
+
"2. 課題管理/issues/ からコメントする課題を1件選ぶ(候補を挙げて確認する)。課題キーは各ファイルの「基本情報 > 課題キー」にある",
|
|
314
|
+
"3. 投稿する課題キー・本文・使う経路・Backlog上の名義を提示して、承認を得る",
|
|
315
|
+
"4. 承認後に投稿し、投稿先のURLを報告する",
|
|
316
|
+
"",
|
|
317
|
+
"注意:",
|
|
318
|
+
"- 今回はコメントの追加だけです。課題の削除・クローズ・属性変更はしないでください",
|
|
319
|
+
"- 売上・単価・工数・人事評価などの内部限定情報は書かないでください(顧客も閲覧します)",
|
|
320
|
+
].join("\n");
|
|
321
|
+
const TUT_DESIGN_PROMPT = [
|
|
322
|
+
"デザイン/inventory/ の画面インベントリから画面を1つ選び、それがどんな画面なのかを説明してください。",
|
|
323
|
+
"",
|
|
324
|
+
"手順:",
|
|
325
|
+
"1. デザイン/inventory/ を一覧し、主要そうな画面を1つ選ぶ(1画面1ファイル。frontmatter に安定ID design:{fileKey}:{nodeId} とFigmaへのディープリンクがあります)",
|
|
326
|
+
"2. その画面のファイルを読み、画面の役割・主な要素・前後の画面とのつながりを、読み取れる範囲で説明する",
|
|
327
|
+
"3. 関連する決定(Cortex/Decisions/)・用語(Cortex/Glossary/)・課題(課題管理/issues/)があれば、安定IDをたどって補足する",
|
|
328
|
+
"4. 最後に、Figmaで実物を開くリンクを提示する",
|
|
329
|
+
"",
|
|
330
|
+
"注意:",
|
|
331
|
+
"- 読むだけです。ファイルの作成・更新はしないでください",
|
|
332
|
+
"- インベントリはFigmaからの同期で上書きされる生成物です。手で編集しないでください",
|
|
333
|
+
].join("\n");
|
|
334
|
+
const TUT_SLACK_PROMPT = [
|
|
335
|
+
"Cortex のチュートリアルを完了したことを、この案件の Slack チャンネルに投稿してください。最後のステップです。",
|
|
336
|
+
"",
|
|
337
|
+
"Slackのつなぎ方:",
|
|
338
|
+
"- 手元の Claude Code(CLI・デスクトップ)なら /mcp コマンドから slack を選んで認可する",
|
|
339
|
+
"- クラウドのセッション(claude.ai/code)なら、セッションのコネクタ設定で Slack を有効にする",
|
|
340
|
+
"- どちらもできない場合は、その旨とつなぎ方を案内して止まってください",
|
|
341
|
+
"",
|
|
342
|
+
"手順:",
|
|
343
|
+
"1. チャット/channels.json を読み、登録されているチャンネル(name / url / description)から投稿先を選ぶ。複数あれば description を見て判断し、迷ったら確認する",
|
|
344
|
+
"2. 次の雛形で本文を作る({名前} は Cortex/Members/records/ にあるわたしのレコードの表記に合わせる)",
|
|
345
|
+
"",
|
|
346
|
+
"🎉 {名前} さんが Cortex のチュートリアルを完了しました",
|
|
347
|
+
"できるようになったこと: Gold層から案件を把握する・自分の情報を更新する・Backlogに記票する・資料を投入する",
|
|
348
|
+
"使い方の質問はこのチャンネルへどうぞ",
|
|
349
|
+
"",
|
|
350
|
+
"3. 投稿先のチャンネルと本文をプレビューして、承認を得る",
|
|
351
|
+
"4. 承認後に投稿し、投稿したメッセージのリンクを報告する",
|
|
352
|
+
"",
|
|
353
|
+
"注意:",
|
|
354
|
+
"- 売上・単価・工数・人事評価などの内部限定情報は書かないでください",
|
|
355
|
+
].join("\n");
|
|
237
356
|
const CSS = `
|
|
238
357
|
:root {
|
|
239
358
|
--bg: #f6f7f9;
|
|
@@ -465,13 +584,9 @@ a:hover { text-decoration: underline; }
|
|
|
465
584
|
.badge.cat-インフラ { background: #efe9fb; color: #6d28d9; }
|
|
466
585
|
.badge.cat-ビジネス { background: #fde9ef; color: #be185d; }
|
|
467
586
|
.badge.cat-デザイン { background: #fce7f3; color: #a21caf; }
|
|
468
|
-
.badge.draft { background: #fef3c7; color: #92400e; border: 1px solid #fcd34d; }
|
|
469
587
|
.badge.error { background: #fee2e2; color: #b91c1c; border: 1px solid #fca5a5; }
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
background: #fffbeb; border: 1px solid #fcd34d; border-radius: 8px;
|
|
473
|
-
padding: 10px 14px; margin: 12px 0 4px; font-size: 13.5px; color: #92400e; line-height: 1.7;
|
|
474
|
-
}
|
|
588
|
+
/* 未確認(status: draft = AI生成・人間未確認)の印。ほとんどのレコードが該当しうるため色もアイコンも使わない */
|
|
589
|
+
.unverified { margin-left: 8px; font-size: 11.5px; font-weight: 400; color: var(--muted); white-space: nowrap; }
|
|
475
590
|
.adoption-note {
|
|
476
591
|
display: flex; gap: 8px; align-items: flex-start;
|
|
477
592
|
background: #eff6ff; border: 1px solid #bfdbfe; border-radius: 8px;
|
|
@@ -818,6 +933,16 @@ const CLIENT_JS = `
|
|
|
818
933
|
function catBadge(cat) {
|
|
819
934
|
return el("span", { class: "badge cat-" + cat, text: cat || "未分類" });
|
|
820
935
|
}
|
|
936
|
+
// 未確認(status: draft = AI生成・人間未確認)の印。タイトル脇に小さく添えるだけで、active・status無しには何も出さない
|
|
937
|
+
function unverifiedMark(rec) {
|
|
938
|
+
return rec && rec.rstatus === "draft" ? el("span", { class: "unverified", text: "未確認" }) : null;
|
|
939
|
+
}
|
|
940
|
+
// 未確認の絞り込み(フィルタのセレクトの選択肢は draft の1つだけ)
|
|
941
|
+
function statusLabel(v) { return v === "draft" ? "未確認のみ" : v; }
|
|
942
|
+
// 未確認が1件も無い一覧では絞り込みを出さない
|
|
943
|
+
function hasUnverified(items) {
|
|
944
|
+
return (items || []).some(function (r) { return r.rstatus === "draft"; });
|
|
945
|
+
}
|
|
821
946
|
|
|
822
947
|
// ---------- AI導線(Gold層への人間の書き込み口。claude.ai/code へのディープリンク) ----------
|
|
823
948
|
// ヘッダー「AIに聞く」と同じ方式。repoBaseUrl から slug を導出し、プロンプトを入力済みで Claude Code Web を開く。
|
|
@@ -835,13 +960,155 @@ const CLIENT_JS = `
|
|
|
835
960
|
var m = rec.editUrl.match(/\\/edit\\/[^/]+\\/(.+)$/);
|
|
836
961
|
return m ? decodeURIComponent(m[1]) : "";
|
|
837
962
|
}
|
|
838
|
-
// Gold型(ディレクトリ名)→
|
|
839
|
-
//
|
|
963
|
+
// Gold型(ディレクトリ名)→ 書き込みプロンプトの対応。決定事項/用語集/メンバー/ルールの4型のみ。
|
|
964
|
+
// レポート等スキルの無いディレクトリは対象外(ボタンを出さない)。
|
|
965
|
+
// リンク先はクラウド実行のセッションでエンジンのスキルがロードされないため、プロンプトには規約を埋め込んで自己完結させる。
|
|
966
|
+
// スキルが使える環境(手元のCLI・デスクトップ等)ではそちらを優先させる旨を冒頭に添える。
|
|
967
|
+
function aiHead(skill) {
|
|
968
|
+
return "(" + skill + " スキルが使える環境なら、そのスキルの手順を優先してください。使えない場合は以下に従ってください。)\\n\\n";
|
|
969
|
+
}
|
|
970
|
+
// 4型すべてに付ける共通の規律(承認・重複・安定ID・公開範囲)
|
|
971
|
+
var AI_COMMON = [
|
|
972
|
+
"",
|
|
973
|
+
"",
|
|
974
|
+
"共通ルール:",
|
|
975
|
+
"- 書き込む前に、作成・更新する内容を提示して承認を得てください",
|
|
976
|
+
"- 同じ対象に複数ファイルを作らないよう、既存レコードとの重複を必ず確認してください",
|
|
977
|
+
"- relations の target にファイルパスは書かず、安定ID(決定ID YYYYMMDD-NNN / term:{代表表記} / rule:{slug} / member:{氏名} / 課題キー / minute:{定例名}:{YYYYMMDD})で張ってください",
|
|
978
|
+
"- 売上・単価・工数・人事評価などの内部限定情報は書かないでください(このリポジトリは顧客も閲覧します)",
|
|
979
|
+
].join("\\n");
|
|
840
980
|
var GOLD_SKILL = {
|
|
841
|
-
"Decisions": {
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
981
|
+
"Decisions": {
|
|
982
|
+
skill: "update-decision",
|
|
983
|
+
noun: "決定",
|
|
984
|
+
add: [
|
|
985
|
+
"これから伝える決定事項を Cortex/Decisions/records/ に1決定1ファイルで記録してください。",
|
|
986
|
+
"",
|
|
987
|
+
"手順:",
|
|
988
|
+
"1. Cortex/Decisions/README.md(フィールド定義・カテゴリー一覧)と Cortex/Decisions/template.md を読む",
|
|
989
|
+
"2. 既存の records/ を一覧し、同じ決定が記録済みでないかと、決定日の連番の続きを確認する",
|
|
990
|
+
"3. ファイル名は YYYYMMDD-NNN-決定内容の要約.md(YYYYMMDD=決定日、NNN=同日内の連番)",
|
|
991
|
+
"4. frontmatter の必須は type: decision / id(YYYYMMDD-NNN) / title / date / sprint(スプリント運用が無ければフェーズ名) / category(ビジネス・技術選定・設計方針・運用ルール・インフラ・デザインから選ぶ) / deciders(Cortex/Members/records/ の正式表記に揃える。名簿に無い人名は「(要確認)」を付ける) / description(1文要約) / references(出典への人間向けリンク)。README 定義以外のフィールドは追加しない",
|
|
992
|
+
"5. 根拠がある場合は relations に rel: based_on で安定IDを張る(議事録は minute:{定例名}:{YYYYMMDD}、課題は課題キー)",
|
|
993
|
+
"6. 本文は「# タイトル」「## 背景」(なぜ必要になったか)「## 理由」(なぜその選択をしたか・他案との比較)",
|
|
994
|
+
"7. 過去の決定を変える内容なら、その記録は書き換えず新しい記録を作り、relations に rel: supersedes で元の決定IDを張る",
|
|
995
|
+
"8. 確定した決定だけを記録する(検討中・未確定の議論は記録しない)",
|
|
996
|
+
].join("\\n"),
|
|
997
|
+
edit: function (target) {
|
|
998
|
+
return [
|
|
999
|
+
target + "について、これから伝える変更を反映してください。",
|
|
1000
|
+
"",
|
|
1001
|
+
"重要: 決定の内容そのものが変わる場合、この記録は書き換えません。Cortex/Decisions/records/ に新しいファイル(YYYYMMDD-NNN-決定内容の要約.md。YYYYMMDD=新しい決定日、NNN=同日内の連番)を作り、frontmatter の relations に rel: supersedes / target: 元の決定ID を張って、背景・理由に変更の経緯を書いてください。誤字・リンク切れなど決定の中身が変わらない訂正だけ、その場で直してかまいません。",
|
|
1002
|
+
"",
|
|
1003
|
+
"手順:",
|
|
1004
|
+
"1. Cortex/Decisions/README.md(フィールド定義・カテゴリー一覧)と対象ファイルを読む",
|
|
1005
|
+
"2. 新しい記録を作る場合は、既存の records/ で連番の続きと重複を確認する",
|
|
1006
|
+
"3. frontmatter の必須は type: decision / id / title / date / sprint / category / deciders(Cortex/Members/records/ の正式表記に揃える) / description / references。README 定義以外のフィールドは追加しない",
|
|
1007
|
+
"4. 本文は「# タイトル」「## 背景」「## 理由」の構成を保つ",
|
|
1008
|
+
"5. あなた(人間)が内容を確認して編集したので、status が draft(AI生成・人間未確認)なら active に上げる。内容を確認せず表記・形式だけ直した場合は draft のままにする",
|
|
1009
|
+
].join("\\n");
|
|
1010
|
+
},
|
|
1011
|
+
},
|
|
1012
|
+
"Glossary": {
|
|
1013
|
+
skill: "update-glossary",
|
|
1014
|
+
noun: "用語",
|
|
1015
|
+
add: [
|
|
1016
|
+
"これから伝える用語を Cortex/Glossary/records/ に1用語1ファイルで登録してください。",
|
|
1017
|
+
"",
|
|
1018
|
+
"手順:",
|
|
1019
|
+
"1. Cortex/Glossary/README.md(スキーマ・除外用語リスト)と Cortex/Glossary/template.md を読む",
|
|
1020
|
+
"2. 既存 records/ の title と synonyms を確認する。既存用語の表記揺れなら新規ファイルを作らず、その用語の synonyms に追記する。除外用語リストに載っている語は登録しない",
|
|
1021
|
+
"3. ファイル名は records/{代表表記}.md、id は term:{代表表記}",
|
|
1022
|
+
"4. frontmatter の必須は type: term / id / title / description(1文要約) / scope(project=案件固有 | organization=全社共通) / status / date(登録日)。任意は synonyms(表記揺れ)・source(この案件での出典)・references。README 定義以外のフィールドは追加しない",
|
|
1023
|
+
"5. 案件固有語は社内の情報源(議事録・課題・資料)の記述だけを根拠に定義する(Web検索せず references も付けない)。Figma・OIDC のような一般公開のサービス・技術・規格は、Web で公式ドキュメント等の一次情報を確認してから定義し、そのURLを references に入れる。推測で書かない",
|
|
1024
|
+
"6. 定義を人間と確認できた場合のみ status: active。確証が持てなければ status: draft(AI生成・人間未確認の印)にする",
|
|
1025
|
+
"7. 本文にはこの案件における意味を1〜数段落で具体的に書く(一般的な意味に加え、この案件で特殊な使われ方があれば補足する)",
|
|
1026
|
+
].join("\\n"),
|
|
1027
|
+
edit: function (target) {
|
|
1028
|
+
return [
|
|
1029
|
+
target + "について、これから伝える修正を反映してください。",
|
|
1030
|
+
"",
|
|
1031
|
+
"前提:",
|
|
1032
|
+
"- 用語集は更新型です。定義が変わったら本文・frontmatter を直接更新してかまいません(変更履歴は git が持ちます)",
|
|
1033
|
+
"- 新しい表記揺れは新規ファイルを作らず synonyms に追記します",
|
|
1034
|
+
"- 定義を人間と確認できたら status: draft を active に上げます",
|
|
1035
|
+
"- 使われなくなった用語は削除せず status: superseded にします",
|
|
1036
|
+
"",
|
|
1037
|
+
"手順:",
|
|
1038
|
+
"1. Cortex/Glossary/README.md(スキーマ)と対象ファイルを読む",
|
|
1039
|
+
"2. frontmatter の必須は type: term / id(term:{代表表記}) / title / description / scope / status / date。README 定義以外のフィールドは追加しない",
|
|
1040
|
+
"3. 一般公開のサービス・技術・規格は Web で公式ドキュメント等の一次情報を確認してから定義を直し、references にそのURLを入れる。案件固有語は社内の情報源だけを根拠にし、推測で書かない",
|
|
1041
|
+
"4. あなた(人間)が内容を確認して編集したので、status が draft(AI生成・人間未確認)なら active に上げる。内容を確認せず表記・形式だけ直した場合は draft のままにする",
|
|
1042
|
+
].join("\\n");
|
|
1043
|
+
},
|
|
1044
|
+
},
|
|
1045
|
+
"Members": {
|
|
1046
|
+
skill: "update-member",
|
|
1047
|
+
noun: "メンバー",
|
|
1048
|
+
add: [
|
|
1049
|
+
"これから伝えるメンバーを Cortex/Members/records/ に1人1ファイルで登録してください。",
|
|
1050
|
+
"",
|
|
1051
|
+
"手順:",
|
|
1052
|
+
"1. Cortex/Members/README.md(スキーマ)と Cortex/Members/template.md を読む",
|
|
1053
|
+
"2. 既存 records/ の title・aliases・side を確認する。既存メンバーの表記揺れなら新規ファイルを作らず、その人の aliases に追記する(同一人物に複数ファイルを作らない)",
|
|
1054
|
+
"3. ファイル名は records/{氏名(スペース無し)}.md、id は member:{氏名(スペース無し)}",
|
|
1055
|
+
"4. frontmatter の必須は type: member / id / title(氏名の正式表記。スペースを含んでよい) / description(何者かの1文) / status(active=在籍 | inactive=離任 | draft=AI生成・人間未確認)。任意は yomi・aliases・org・side(cm=開発側 | client=顧客 | vendor=ベンダー)・role・email。README 定義以外のフィールドは追加しない",
|
|
1056
|
+
"5. 氏名・所属・side を推測で確定させない。確証が無い項目は空にし、確認が取れていないレコードは status: draft のままにする",
|
|
1057
|
+
"6. 本文にも何者かを1〜2文書く(Viewer の個別ページに表示されるため空にしない)",
|
|
1058
|
+
"7. 名簿に書くのは氏名・所属・役割・表記揺れだけ。人の評価・人事・単価・工数は書かない",
|
|
1059
|
+
].join("\\n"),
|
|
1060
|
+
edit: function (target) {
|
|
1061
|
+
return [
|
|
1062
|
+
target + "について、これから伝える修正を反映してください。",
|
|
1063
|
+
"",
|
|
1064
|
+
"前提:",
|
|
1065
|
+
"- 名簿は更新型です。氏名・所属・役割が変わったら frontmatter・本文を直接更新してかまいません(変更履歴は git が持ちます)",
|
|
1066
|
+
"- 新しい表記揺れ(文字起こしの誤変換・呼称)は新規ファイルを作らず aliases に追記します",
|
|
1067
|
+
"- 本人やPMに確認が取れたら status: draft を active に上げます。確証が無い項目は推測で埋めず空のままにします",
|
|
1068
|
+
"- 離任しても削除せず status: inactive にします(過去の議事録・決定の人名正規化の根拠として残すため)",
|
|
1069
|
+
"",
|
|
1070
|
+
"手順:",
|
|
1071
|
+
"1. Cortex/Members/README.md(スキーマ)と対象ファイルを読む",
|
|
1072
|
+
"2. frontmatter の必須は type: member / id(member:{氏名(スペース無し)}) / title / description / status。任意は yomi・aliases・org・side(cm | client | vendor)・role・email。README 定義以外のフィールドは追加しない",
|
|
1073
|
+
"3. 名簿に書くのは氏名・所属・役割・表記揺れだけ。人の評価・人事・単価・工数は書かない",
|
|
1074
|
+
"4. あなた(人間)が内容を確認して編集したので、status が draft(AI生成・人間未確認)なら active に上げる。内容を確認せず表記・形式だけ直した場合は draft のままにする",
|
|
1075
|
+
].join("\\n");
|
|
1076
|
+
},
|
|
1077
|
+
},
|
|
1078
|
+
"Rules": {
|
|
1079
|
+
skill: "update-rule",
|
|
1080
|
+
noun: "ルール",
|
|
1081
|
+
add: [
|
|
1082
|
+
"これから伝えるルール(案件で継続的に守る制約)を Cortex/Rules/records/ に1ルール1ファイルで登録してください。",
|
|
1083
|
+
"",
|
|
1084
|
+
"手順:",
|
|
1085
|
+
"1. Cortex/Rules/README.md(スキーマ・除外ルールリスト)と Cortex/Rules/template.md を読む",
|
|
1086
|
+
"2. Rule と Decision を判別する。Rule は「本番リリースは金曜禁止」のように今も効き続ける約束事だけ。一回きりの決定・単発のTODO・期限付きの依頼は Rule にしない(それは Cortex/Decisions/ の担当)",
|
|
1087
|
+
"3. 既存 records/ の title を確認して重複を避ける。README の除外ルールに載っている制約は起票しない(除外リストは読むだけで編集しない)",
|
|
1088
|
+
"4. ファイル名は records/{slug}.md、id は rule:{slug}(例: rule:本番リリース-金曜禁止)",
|
|
1089
|
+
"5. frontmatter の必須は type: rule / id / title(制約の1行表現) / description(1文要約) / status(draft=AI生成・人間未確認 | active=確認済み)。README 定義以外のフィールドは追加しない",
|
|
1090
|
+
"6. status は原則 draft。対話でユーザー本人が制約の内容に合意している場合だけ active にしてよい",
|
|
1091
|
+
"7. 元になった決定があれば relations に rel: derived_from / target: 決定ID(YYYYMMDD-NNN)を、議事録・課題が根拠なら rel: based_on で安定IDを張る",
|
|
1092
|
+
"8. 本文は「## 制約」「## 適用範囲」「## 違反するとどうなるか」「## 出典」で構成する",
|
|
1093
|
+
].join("\\n"),
|
|
1094
|
+
edit: function (target) {
|
|
1095
|
+
return [
|
|
1096
|
+
target + "について、これから伝える修正を反映してください。",
|
|
1097
|
+
"",
|
|
1098
|
+
"前提:",
|
|
1099
|
+
"- ルールは更新型です。制約の表現・適用範囲が変わったら frontmatter・本文を直接更新してかまいません(変更履歴は git が持ちます)",
|
|
1100
|
+
"- 内容を人間と確認できたら status: draft を active に上げます(本人の合意が無いものを勝手に active にしない)",
|
|
1101
|
+
"- 効かなくなったルールは削除せず、本文に失効を追記して元の決定から履歴をたどれるようにします",
|
|
1102
|
+
"- 継続的な制約でなくなる内容(一回きりの決定)は Rule ではなく Cortex/Decisions/ の担当です",
|
|
1103
|
+
"",
|
|
1104
|
+
"手順:",
|
|
1105
|
+
"1. Cortex/Rules/README.md(スキーマ・除外ルール)と対象ファイルを読む",
|
|
1106
|
+
"2. frontmatter の必須は type: rule / id(rule:{slug}) / title / description / status。README 定義以外のフィールドは追加しない",
|
|
1107
|
+
"3. 本文は「## 制約」「## 適用範囲」「## 違反するとどうなるか」「## 出典」の構成を保つ",
|
|
1108
|
+
"4. あなた(人間)が内容を確認して編集したので、status が draft(AI生成・人間未確認)なら active に上げる。内容を確認せず表記・形式だけ直した場合は draft のままにする",
|
|
1109
|
+
].join("\\n");
|
|
1110
|
+
},
|
|
1111
|
+
},
|
|
845
1112
|
};
|
|
846
1113
|
// ディレクトリ名が日本語の案件(用語集 等)でも同じ4型に解決できるよう、表示名(DIR_LABELS)→英語キーの別名も引く
|
|
847
1114
|
var GOLD_ALIAS = { "決定事項": "Decisions", "用語集": "Glossary", "メンバー": "Members", "ルール": "Rules" };
|
|
@@ -852,7 +1119,7 @@ const CLIENT_JS = `
|
|
|
852
1119
|
function aiAddBar(sectionName) {
|
|
853
1120
|
var g = goldSkill(sectionName);
|
|
854
1121
|
if (!g) return null;
|
|
855
|
-
var prompt = g.skill +
|
|
1122
|
+
var prompt = aiHead(g.skill) + g.add + AI_COMMON;
|
|
856
1123
|
return el("div", { class: "ai-add-bar" }, [
|
|
857
1124
|
el("a", { class: "ai-add-btn", href: codeUrl(prompt), target: "_blank", rel: "noopener", text: "+ AIで登録" }),
|
|
858
1125
|
]);
|
|
@@ -865,8 +1132,8 @@ const CLIENT_JS = `
|
|
|
865
1132
|
var target = pathRef
|
|
866
1133
|
? pathRef + " の" + g.noun + "「" + title + "」"
|
|
867
1134
|
: "この" + g.noun + "「" + title + "」(" + rec.id + ")";
|
|
868
|
-
var prompt = g.skill +
|
|
869
|
-
return el("a", { class: "ai-edit-btn", href: codeUrl(prompt), target: "_blank", rel: "noopener", text: "
|
|
1135
|
+
var prompt = aiHead(g.skill) + g.edit(target) + AI_COMMON;
|
|
1136
|
+
return el("a", { class: "ai-edit-btn", href: codeUrl(prompt), target: "_blank", rel: "noopener", text: "AIで編集" });
|
|
870
1137
|
}
|
|
871
1138
|
// 本文HTMLは bodies/<i>.html に外出しされている。詳細表示時にfetchして埋める(キャッシュ・失敗時フォールバック付き)
|
|
872
1139
|
var bodyCache = {};
|
|
@@ -894,7 +1161,7 @@ const CLIENT_JS = `
|
|
|
894
1161
|
window.scrollTo(0, 0);
|
|
895
1162
|
}
|
|
896
1163
|
|
|
897
|
-
var listState = { tab: DEFAULT_TAB, q: "", category: "", month: "", page: 1 };
|
|
1164
|
+
var listState = { tab: DEFAULT_TAB, q: "", category: "", month: "", status: "", page: 1 };
|
|
898
1165
|
|
|
899
1166
|
// 一覧のページネーション(描画コスト対策。1ページあたりの件数)
|
|
900
1167
|
var PAGE_SIZE = 30;
|
|
@@ -952,7 +1219,7 @@ const CLIENT_JS = `
|
|
|
952
1219
|
btnUrl: base ? base + "/actions/workflows/update-decision-log.yml" : null,
|
|
953
1220
|
},
|
|
954
1221
|
"dir:Glossary": {
|
|
955
|
-
text: "毎晩の自動走査が新しい用語を draft として直接追加します(update-glossary-auto)。AI
|
|
1222
|
+
text: "毎晩の自動走査が新しい用語を draft として直接追加します(update-glossary-auto)。AIが生成した定義は仮のものです。「未確認」の用語は内容を確認し、適切な定義に置き換えて status: active にしてください。",
|
|
956
1223
|
btnLabel: "実行履歴を確認 →",
|
|
957
1224
|
btnUrl: base ? base + "/actions/workflows/update-glossary.yml" : null,
|
|
958
1225
|
},
|
|
@@ -1484,6 +1751,9 @@ const CLIENT_JS = `
|
|
|
1484
1751
|
filters.appendChild(buildSelect("すべての期間", SITE.months, listState.month, function (v) { listState.month = v; listState.page = 1; drawCards(); }, monthLabel));
|
|
1485
1752
|
}
|
|
1486
1753
|
filters.appendChild(buildSelect("すべてのカテゴリー", SITE.categories, listState.category, function (v) { listState.category = v; listState.page = 1; drawCards(); }));
|
|
1754
|
+
if (hasUnverified(SITE.decisions)) {
|
|
1755
|
+
filters.appendChild(buildSelect("すべての状態", ["draft"], listState.status, function (v) { listState.status = v; listState.page = 1; drawCards(); }, statusLabel));
|
|
1756
|
+
}
|
|
1487
1757
|
app.appendChild(filters);
|
|
1488
1758
|
|
|
1489
1759
|
var addBarD = aiAddBar("Decisions");
|
|
@@ -1511,6 +1781,7 @@ const CLIENT_JS = `
|
|
|
1511
1781
|
var items = SITE.decisions.filter(function (d) {
|
|
1512
1782
|
if (listState.month && d.date.slice(0, 7) !== listState.month) return false;
|
|
1513
1783
|
if (listState.category && d.category !== listState.category) return false;
|
|
1784
|
+
if (listState.status && d.rstatus !== listState.status) return false;
|
|
1514
1785
|
if (q) {
|
|
1515
1786
|
var hay = (d.title + " " + d.summary + " " + d.searchText + " " + d.deciders.join(" ")).toLowerCase();
|
|
1516
1787
|
if (hay.indexOf(q) === -1) return false;
|
|
@@ -1545,7 +1816,7 @@ const CLIENT_JS = `
|
|
|
1545
1816
|
meta.appendChild(traceD);
|
|
1546
1817
|
var card = el("div", { class: "card" }, [
|
|
1547
1818
|
meta,
|
|
1548
|
-
el("div", { class: "card-title", text: d.title }),
|
|
1819
|
+
el("div", { class: "card-title", text: d.title }, [unverifiedMark(d)]),
|
|
1549
1820
|
d.summary ? el("p", { class: "card-summary", text: d.summary }) : null,
|
|
1550
1821
|
]);
|
|
1551
1822
|
card.addEventListener("click", function () { go(d.id); });
|
|
@@ -1566,6 +1837,9 @@ const CLIENT_JS = `
|
|
|
1566
1837
|
var search = el("input", { type: "search", placeholder: "キーワード検索" });
|
|
1567
1838
|
search.value = listState.q;
|
|
1568
1839
|
filters.appendChild(search);
|
|
1840
|
+
if (hasUnverified(items)) {
|
|
1841
|
+
filters.appendChild(buildSelect("すべての状態", ["draft"], listState.status, function (v) { listState.status = v; listState.page = 1; draw(); }, statusLabel));
|
|
1842
|
+
}
|
|
1569
1843
|
app.appendChild(filters);
|
|
1570
1844
|
|
|
1571
1845
|
var addBarG = aiAddBar(listState.tab.replace(/^dir:/, ""));
|
|
@@ -1577,6 +1851,7 @@ const CLIENT_JS = `
|
|
|
1577
1851
|
function draw() {
|
|
1578
1852
|
var q = listState.q.trim().toLowerCase();
|
|
1579
1853
|
var shown = items.filter(function (r) {
|
|
1854
|
+
if (listState.status && r.rstatus !== listState.status) return false;
|
|
1580
1855
|
if (!q) return true;
|
|
1581
1856
|
return (r.title + " " + r.summary + " " + r.searchText).toLowerCase().indexOf(q) !== -1;
|
|
1582
1857
|
});
|
|
@@ -1592,7 +1867,6 @@ const CLIENT_JS = `
|
|
|
1592
1867
|
(pg.pages > 1 ? "(" + pg.page + "/" + pg.pages + "ページ)" : "");
|
|
1593
1868
|
pg.slice.forEach(function (r) {
|
|
1594
1869
|
var meta = el("div", { class: "card-meta" }, [
|
|
1595
|
-
r.rstatus === "draft" ? el("span", { class: "badge draft", text: "AI生成・未確認" }) : null,
|
|
1596
1870
|
r.date ? el("span", { class: "mono", text: r.date }) : null,
|
|
1597
1871
|
el("span", { class: "mono", text: r.id }),
|
|
1598
1872
|
]);
|
|
@@ -1603,7 +1877,7 @@ const CLIENT_JS = `
|
|
|
1603
1877
|
meta.appendChild(traceR);
|
|
1604
1878
|
var card = el("div", { class: "card" }, [
|
|
1605
1879
|
meta,
|
|
1606
|
-
el("div", { class: "card-title", text: r.title }),
|
|
1880
|
+
el("div", { class: "card-title", text: r.title }, [unverifiedMark(r)]),
|
|
1607
1881
|
r.summary ? el("p", { class: "card-summary", text: r.summary }) : null,
|
|
1608
1882
|
]);
|
|
1609
1883
|
card.addEventListener("click", function () { go(r.id); });
|
|
@@ -1626,7 +1900,7 @@ const CLIENT_JS = `
|
|
|
1626
1900
|
app.appendChild(back);
|
|
1627
1901
|
|
|
1628
1902
|
var head = el("div", { class: "detail-head" });
|
|
1629
|
-
head.appendChild(el("div", {}, [ el("h1", { class: "detail-title", text: r.title }) ]));
|
|
1903
|
+
head.appendChild(el("div", {}, [ el("h1", { class: "detail-title", text: r.title }, [unverifiedMark(r)]) ]));
|
|
1630
1904
|
var traceBtn2 = el("a", { class: "edit-btn", href: "?tab=graph", text: "🕸 つながり" });
|
|
1631
1905
|
traceBtn2.addEventListener("click", function (ev) { ev.preventDefault(); openExplorerFor(r); });
|
|
1632
1906
|
head.appendChild(traceBtn2);
|
|
@@ -1638,7 +1912,6 @@ const CLIENT_JS = `
|
|
|
1638
1912
|
app.appendChild(head);
|
|
1639
1913
|
|
|
1640
1914
|
app.appendChild(el("div", { class: "detail-meta" }, [
|
|
1641
|
-
r.rstatus === "draft" ? el("span", { class: "badge draft", text: "AI生成・未確認" }) : null,
|
|
1642
1915
|
r.date ? el("span", { class: "mono", text: r.date }) : null,
|
|
1643
1916
|
el("span", { class: "mono", text: r.id }),
|
|
1644
1917
|
r.summary ? el("span", { text: r.summary }) : null,
|
|
@@ -1647,13 +1920,6 @@ const CLIENT_JS = `
|
|
|
1647
1920
|
var en2 = fmErrorNote(r);
|
|
1648
1921
|
if (en2) app.appendChild(en2);
|
|
1649
1922
|
|
|
1650
|
-
if (r.rstatus === "draft") {
|
|
1651
|
-
app.appendChild(el("div", { class: "draft-note" }, [
|
|
1652
|
-
el("span", { text: "⚠️" }),
|
|
1653
|
-
el("span", { text: "この定義はAIが自動生成したものです(人間未確認)。必ず内容を確認し、適切な定義に置き換えたうえで frontmatter の status を active に変更してください。" }),
|
|
1654
|
-
]));
|
|
1655
|
-
}
|
|
1656
|
-
|
|
1657
1923
|
var genBody = el("div", { class: "body" });
|
|
1658
1924
|
app.appendChild(genBody);
|
|
1659
1925
|
loadBody(r, genBody);
|
|
@@ -2282,7 +2548,7 @@ const CLIENT_JS = `
|
|
|
2282
2548
|
app.appendChild(back);
|
|
2283
2549
|
|
|
2284
2550
|
var head = el("div", { class: "detail-head" });
|
|
2285
|
-
var headLeft = el("div", {}, [ el("h1", { class: "detail-title", text: d.title }) ]);
|
|
2551
|
+
var headLeft = el("div", {}, [ el("h1", { class: "detail-title", text: d.title }, [unverifiedMark(d)]) ]);
|
|
2286
2552
|
head.appendChild(headLeft);
|
|
2287
2553
|
var traceBtn = el("a", { class: "edit-btn", href: "?tab=graph", text: "🕸 つながり" });
|
|
2288
2554
|
traceBtn.addEventListener("click", function (ev) { ev.preventDefault(); openExplorerFor(d); });
|
package/package.json
CHANGED