@askdkc/kiokuko 0.1.2 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.ja.md +4 -0
- package/README.ko.md +4 -0
- package/README.md +7 -0
- package/README.zh-CN.md +4 -0
- package/dist/bin/kiokuko.js +11 -4
- package/dist/bin/kiokuko.js.map +1 -1
- package/dist/runtime-version.d.ts +5 -0
- package/dist/runtime-version.d.ts.map +1 -0
- package/dist/runtime-version.js +16 -0
- package/dist/runtime-version.js.map +1 -0
- package/dist/web/i18n.d.ts +83 -0
- package/dist/web/i18n.d.ts.map +1 -0
- package/dist/web/i18n.js +329 -0
- package/dist/web/i18n.js.map +1 -0
- package/dist/web/ui.d.ts.map +1 -1
- package/dist/web/ui.js +126 -60
- package/dist/web/ui.js.map +1 -1
- package/package.json +3 -3
package/README.ja.md
CHANGED
|
@@ -6,6 +6,8 @@ Kiokukoは、AIコーディングエージェント向けのモデル非依存
|
|
|
6
6
|
|
|
7
7
|
## グローバルへのインストールと有効化
|
|
8
8
|
|
|
9
|
+
Node.js 24以上が必要です。
|
|
10
|
+
|
|
9
11
|
```bash
|
|
10
12
|
npm install --global @askdkc/kiokuko
|
|
11
13
|
kiokuko setup
|
|
@@ -108,6 +110,8 @@ kiokuko web
|
|
|
108
110
|
# http://127.0.0.1:4173 を開く
|
|
109
111
|
```
|
|
110
112
|
|
|
113
|
+
UIは英語、日本語、簡体字中国語、韓国語に対応します。初回はブラウザの言語を使用し、明示的に選択した言語はブラウザに保存されます。`?lang=en`、`?lang=ja`、`?lang=zh-CN`、`?lang=ko`で上書きできます。
|
|
114
|
+
|
|
111
115
|
`--port 0`で空いているポートを自動選択でき、`--json`で選択されたURLをJSONとして出力できます。Web UIが非ループバックインターフェースへサーバーを公開することはありません。verifiedおよびsupersededエントリは読み取り専用です。candidateの編集には楽観的リビジョン検査が使われ、監査履歴が維持されます。
|
|
112
116
|
|
|
113
117
|
`bot:researcher`、`bot:builder`、`bot:reviewer`などのタグは、種類をまたいだフィルターとして使用できます。エントリまたはサイドバーのタグをクリックすると、記憶タイプに関係なく一致するすべてのエントリが表示されます。
|
package/README.ko.md
CHANGED
|
@@ -6,6 +6,8 @@ Kiokuko는 AI 코딩 에이전트를 위한 모델 독립적인 외부 메모리
|
|
|
6
6
|
|
|
7
7
|
## 전역 설치 및 활성화
|
|
8
8
|
|
|
9
|
+
Node.js 24 이상이 필요합니다.
|
|
10
|
+
|
|
9
11
|
```bash
|
|
10
12
|
npm install --global @askdkc/kiokuko
|
|
11
13
|
kiokuko setup
|
|
@@ -108,6 +110,8 @@ kiokuko web
|
|
|
108
110
|
# http://127.0.0.1:4173 열기
|
|
109
111
|
```
|
|
110
112
|
|
|
113
|
+
UI는 영어, 일본어, 중국어 간체 및 한국어를 지원합니다. 처음에는 브라우저 언어를 사용하고 명시적으로 선택한 언어는 브라우저에 저장합니다. `?lang=en`, `?lang=ja`, `?lang=zh-CN`, `?lang=ko`로 재정의할 수도 있습니다.
|
|
114
|
+
|
|
111
115
|
`--port 0`을 사용하면 사용 가능한 포트를 자동으로 선택하고, `--json`을 사용하면 선택된 URL을 JSON으로 출력합니다. Web UI는 루프백이 아닌 인터페이스에 서버를 노출하지 않습니다. verified 및 superseded 항목은 읽기 전용이며 candidate 편집에는 낙관적 리비전 검사를 사용하고 감사 기록을 유지합니다.
|
|
112
116
|
|
|
113
117
|
`bot:researcher`, `bot:builder`, `bot:reviewer` 같은 태그를 유형 간 필터로 사용할 수 있습니다. 항목 또는 사이드바의 태그를 클릭하면 메모리 유형과 관계없이 일치하는 모든 항목을 표시합니다.
|
package/README.md
CHANGED
|
@@ -13,6 +13,8 @@ storing memories.
|
|
|
13
13
|
|
|
14
14
|
## Install and enable globally
|
|
15
15
|
|
|
16
|
+
Node.js 24 or newer is required.
|
|
17
|
+
|
|
16
18
|
```bash
|
|
17
19
|
npm install --global @askdkc/kiokuko
|
|
18
20
|
kiokuko setup
|
|
@@ -152,6 +154,11 @@ kiokuko web
|
|
|
152
154
|
# open http://127.0.0.1:4173
|
|
153
155
|
```
|
|
154
156
|
|
|
157
|
+
The UI supports English, Japanese, Simplified Chinese, and Korean. It uses the
|
|
158
|
+
browser language on first use, persists an explicit language selection in the
|
|
159
|
+
browser, and accepts `?lang=en`, `?lang=ja`, `?lang=zh-CN`, or `?lang=ko` as an
|
|
160
|
+
override.
|
|
161
|
+
|
|
155
162
|
Use `--port 0` to select an available port, or `--json` to print the selected
|
|
156
163
|
URL as JSON. The web UI does not expose the server on non-loopback interfaces.
|
|
157
164
|
Verified and superseded entries are read-only; editing a candidate uses an
|
package/README.zh-CN.md
CHANGED
|
@@ -6,6 +6,8 @@ Kiokuko 是面向 AI 编程智能体、与模型无关的外部记忆工具。
|
|
|
6
6
|
|
|
7
7
|
## 全局安装与启用
|
|
8
8
|
|
|
9
|
+
需要Node.js 24或更高版本。
|
|
10
|
+
|
|
9
11
|
```bash
|
|
10
12
|
npm install --global @askdkc/kiokuko
|
|
11
13
|
kiokuko setup
|
|
@@ -108,6 +110,8 @@ kiokuko web
|
|
|
108
110
|
# 打开 http://127.0.0.1:4173
|
|
109
111
|
```
|
|
110
112
|
|
|
113
|
+
UI支持英语、日语、简体中文和韩语。首次使用时采用浏览器语言,明确选择的语言会保存在浏览器中;也可以使用`?lang=en`、`?lang=ja`、`?lang=zh-CN`或`?lang=ko`覆盖。
|
|
114
|
+
|
|
111
115
|
使用 `--port 0` 可自动选择可用端口,使用 `--json` 可将所选 URL 以 JSON 输出。Web UI 不会在非回环接口上公开服务器。verified 和 superseded 条目为只读;编辑 candidate 时会使用乐观修订检查,并保留审计记录。
|
|
112
116
|
|
|
113
117
|
`bot:researcher`、`bot:builder` 和 `bot:reviewer` 等标签可以作为跨类型筛选器。点击条目或侧边栏中的标签,会显示所有匹配条目,而不受记忆类型限制。
|
package/dist/bin/kiokuko.js
CHANGED
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
process.exitCode =
|
|
2
|
+
import { supportsNodeVersion, unsupportedNodeMessage } from '../runtime-version.js';
|
|
3
|
+
if (!supportsNodeVersion(process.versions.node)) {
|
|
4
|
+
process.stderr.write(`${unsupportedNodeMessage(process.versions.node)}\n`);
|
|
5
|
+
process.exitCode = 1;
|
|
6
|
+
}
|
|
7
|
+
else {
|
|
8
|
+
const { runCli } = await import('../cli.js');
|
|
9
|
+
const exitCode = await runCli();
|
|
10
|
+
if (exitCode !== 0)
|
|
11
|
+
process.exitCode = exitCode;
|
|
12
|
+
}
|
|
6
13
|
//# sourceMappingURL=kiokuko.js.map
|
package/dist/bin/kiokuko.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"kiokuko.js","sourceRoot":"","sources":["../../src/bin/kiokuko.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"kiokuko.js","sourceRoot":"","sources":["../../src/bin/kiokuko.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,mBAAmB,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAEpF,IAAI,CAAC,mBAAmB,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;IAChD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,sBAAsB,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC3E,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;AACvB,CAAC;KAAM,CAAC;IACN,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC,CAAC;IAC7C,MAAM,QAAQ,GAAG,MAAM,MAAM,EAAE,CAAC;IAChC,IAAI,QAAQ,KAAK,CAAC;QAAE,OAAO,CAAC,QAAQ,GAAG,QAAQ,CAAC;AAClD,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export declare const MINIMUM_NODE_MAJOR = 24;
|
|
2
|
+
export declare function nodeMajor(version: string): number | undefined;
|
|
3
|
+
export declare function supportsNodeVersion(version: string): boolean;
|
|
4
|
+
export declare function unsupportedNodeMessage(version: string): string;
|
|
5
|
+
//# sourceMappingURL=runtime-version.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime-version.d.ts","sourceRoot":"","sources":["../src/runtime-version.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,kBAAkB,KAAK,CAAC;AAErC,wBAAgB,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAK7D;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAG5D;AAED,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAE9D"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export const MINIMUM_NODE_MAJOR = 24;
|
|
2
|
+
export function nodeMajor(version) {
|
|
3
|
+
const match = /^(\d+)\./u.exec(version);
|
|
4
|
+
if (!match?.[1])
|
|
5
|
+
return undefined;
|
|
6
|
+
const major = Number(match[1]);
|
|
7
|
+
return Number.isSafeInteger(major) ? major : undefined;
|
|
8
|
+
}
|
|
9
|
+
export function supportsNodeVersion(version) {
|
|
10
|
+
const major = nodeMajor(version);
|
|
11
|
+
return major !== undefined && major >= MINIMUM_NODE_MAJOR;
|
|
12
|
+
}
|
|
13
|
+
export function unsupportedNodeMessage(version) {
|
|
14
|
+
return `Kiokuko requires Node.js ${MINIMUM_NODE_MAJOR} or newer; current runtime is Node.js ${version}.`;
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=runtime-version.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime-version.js","sourceRoot":"","sources":["../src/runtime-version.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,kBAAkB,GAAG,EAAE,CAAC;AAErC,MAAM,UAAU,SAAS,CAAC,OAAe;IACvC,MAAM,KAAK,GAAG,WAAW,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACxC,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;QAAE,OAAO,SAAS,CAAC;IAClC,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAC/B,OAAO,MAAM,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;AACzD,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,OAAe;IACjD,MAAM,KAAK,GAAG,SAAS,CAAC,OAAO,CAAC,CAAC;IACjC,OAAO,KAAK,KAAK,SAAS,IAAI,KAAK,IAAI,kBAAkB,CAAC;AAC5D,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,OAAe;IACpD,OAAO,4BAA4B,kBAAkB,yCAAyC,OAAO,GAAG,CAAC;AAC3G,CAAC"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
export declare const WEB_LOCALES: readonly ["en", "ja", "zh-CN", "ko"];
|
|
2
|
+
export type WebLocale = (typeof WEB_LOCALES)[number];
|
|
3
|
+
export declare const DEFAULT_WEB_LOCALE: WebLocale;
|
|
4
|
+
export declare const WEB_LOCALE_LABELS: Readonly<Record<WebLocale, string>>;
|
|
5
|
+
declare const englishMessages: {
|
|
6
|
+
readonly eyebrow: "Local memory console";
|
|
7
|
+
readonly subtitle: "Browse SQLite memory by bot role, memory type, and cross-cutting tags, and safely edit candidate entries.";
|
|
8
|
+
readonly workspaceLabel: "Workspace";
|
|
9
|
+
readonly languageLabel: "Language";
|
|
10
|
+
readonly searchPlaceholder: "Search memory…";
|
|
11
|
+
readonly refresh: "Refresh";
|
|
12
|
+
readonly filtersPanelTitle: "Bot role / tags";
|
|
13
|
+
readonly filtersNavLabel: "Filter by bot role, memory type, or tag";
|
|
14
|
+
readonly entriesTitle: "Memory";
|
|
15
|
+
readonly 'entryCount.one': "{count} item";
|
|
16
|
+
readonly 'entryCount.other': "{count} items";
|
|
17
|
+
readonly editorTitle: "Details";
|
|
18
|
+
readonly unselected: "Not selected";
|
|
19
|
+
readonly operatorTitle: "Agent run operator view";
|
|
20
|
+
readonly trustBadge: "stored data is untrusted / non-actionable";
|
|
21
|
+
readonly runSelectFull: "Select a run to view its intake, profile, timeline, delivery, feedback, and coverage.";
|
|
22
|
+
readonly 'kind.all': "All";
|
|
23
|
+
readonly 'kind.fact': "Fact";
|
|
24
|
+
readonly 'kind.decision': "Decision";
|
|
25
|
+
readonly 'kind.lesson': "Lesson";
|
|
26
|
+
readonly 'kind.preference': "Preference";
|
|
27
|
+
readonly 'kind.reference': "Reference";
|
|
28
|
+
readonly 'bot.common': "Common";
|
|
29
|
+
readonly 'bot.researcher': "Researcher";
|
|
30
|
+
readonly 'bot.builder': "Builder";
|
|
31
|
+
readonly 'bot.reviewer': "Reviewer";
|
|
32
|
+
readonly 'bot.devops': "DevOps";
|
|
33
|
+
readonly 'bot.writer': "Writer";
|
|
34
|
+
readonly 'bot.analyst': "Analyst";
|
|
35
|
+
readonly requestFailed: "The request failed.";
|
|
36
|
+
readonly botFilterTitle: "Bot roles (tags)";
|
|
37
|
+
readonly memoryTypeFilterTitle: "Memory type";
|
|
38
|
+
readonly crossTagFilterTitle: "Cross-cutting tags";
|
|
39
|
+
readonly noEntries: "No matching memory entries.";
|
|
40
|
+
readonly edit: "Edit";
|
|
41
|
+
readonly revision: "revision";
|
|
42
|
+
readonly selectMemory: "Select a memory entry on the left to edit its details.";
|
|
43
|
+
readonly memoryType: "Memory type";
|
|
44
|
+
readonly status: "Status";
|
|
45
|
+
readonly title: "Title";
|
|
46
|
+
readonly body: "Body";
|
|
47
|
+
readonly summary: "Summary";
|
|
48
|
+
readonly commaSeparatedTags: "Tags (comma-separated)";
|
|
49
|
+
readonly scopeJson: "scope JSON";
|
|
50
|
+
readonly provenanceJson: "provenance JSON";
|
|
51
|
+
readonly save: "Save";
|
|
52
|
+
readonly candidateNotice: "Candidate entries are updated only after checking the revision.";
|
|
53
|
+
readonly immutableNotice: "Verified / superseded entries cannot be overwritten directly. Replace them with the CLI to preserve history.";
|
|
54
|
+
readonly saved: "Saved.";
|
|
55
|
+
readonly runSelect: "Select a run to view its details.";
|
|
56
|
+
readonly contextWarning: "Stored context / recommendations: untrusted, non-actionable";
|
|
57
|
+
readonly detailRunIntake: "run / intake";
|
|
58
|
+
readonly detailInitialProfile: "initial profile (immutable view)";
|
|
59
|
+
readonly detailProjectedProfile: "projected profile (ledger revisions)";
|
|
60
|
+
readonly detailPolicySource: "policy / profile source";
|
|
61
|
+
readonly detailCoverageWarnings: "coverage / evidence warnings";
|
|
62
|
+
readonly detailTimelineEvidence: "timeline / evidence";
|
|
63
|
+
readonly detailDeliveriesReasons: "context deliveries / selection reasons";
|
|
64
|
+
readonly detailFeedback: "context / run / intake feedback";
|
|
65
|
+
readonly detailProposalLinks: "memory proposal links";
|
|
66
|
+
readonly noRuns: "No runs.";
|
|
67
|
+
readonly unknown: "unknown";
|
|
68
|
+
readonly untitled: "untitled";
|
|
69
|
+
readonly nextPage: "More results available (bounded cursor)";
|
|
70
|
+
readonly end: "End";
|
|
71
|
+
readonly 'displayedCount.one': "Showing {count} item";
|
|
72
|
+
readonly 'displayedCount.other': "Showing {count} items";
|
|
73
|
+
readonly noWorkspace: "No workspace is available. Run kiokuko use or record in the CLI.";
|
|
74
|
+
readonly 'status.candidate': "candidate";
|
|
75
|
+
readonly 'status.verified': "verified";
|
|
76
|
+
readonly 'status.superseded': "superseded";
|
|
77
|
+
};
|
|
78
|
+
export type WebMessageKey = keyof typeof englishMessages;
|
|
79
|
+
export declare const WEB_MESSAGES: Readonly<Record<WebLocale, Readonly<Record<WebMessageKey, string>>>>;
|
|
80
|
+
export declare function normalizeWebLocale(value: string | null | undefined): WebLocale | null;
|
|
81
|
+
export declare function resolveWebLocale(candidates: ReadonlyArray<string | null | undefined>): WebLocale;
|
|
82
|
+
export {};
|
|
83
|
+
//# sourceMappingURL=i18n.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"i18n.d.ts","sourceRoot":"","sources":["../../src/web/i18n.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,WAAW,sCAAuC,CAAC;AAChE,MAAM,MAAM,SAAS,GAAG,CAAC,OAAO,WAAW,CAAC,CAAC,MAAM,CAAC,CAAC;AAErD,eAAO,MAAM,kBAAkB,EAAE,SAAgB,CAAC;AAElD,eAAO,MAAM,iBAAiB,EAAE,QAAQ,CAAC,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,CAKjE,CAAC;AAEF,QAAA,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAwEX,CAAC;AAEX,MAAM,MAAM,aAAa,GAAG,MAAM,OAAO,eAAe,CAAC;AAgOzD,eAAO,MAAM,YAAY,EAAE,QAAQ,CAAC,MAAM,CAAC,SAAS,EAAE,QAAQ,CAAC,MAAM,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC,CAAC,CAK7F,CAAC;AAEF,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,SAAS,GAAG,IAAI,CASrF;AAED,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,aAAa,CAAC,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,GAAG,SAAS,CAMhG"}
|
package/dist/web/i18n.js
ADDED
|
@@ -0,0 +1,329 @@
|
|
|
1
|
+
export const WEB_LOCALES = ['en', 'ja', 'zh-CN', 'ko'];
|
|
2
|
+
export const DEFAULT_WEB_LOCALE = 'en';
|
|
3
|
+
export const WEB_LOCALE_LABELS = {
|
|
4
|
+
en: 'English',
|
|
5
|
+
ja: '日本語',
|
|
6
|
+
'zh-CN': '简体中文',
|
|
7
|
+
ko: '한국어',
|
|
8
|
+
};
|
|
9
|
+
const englishMessages = {
|
|
10
|
+
eyebrow: 'Local memory console',
|
|
11
|
+
subtitle: 'Browse SQLite memory by bot role, memory type, and cross-cutting tags, and safely edit candidate entries.',
|
|
12
|
+
workspaceLabel: 'Workspace',
|
|
13
|
+
languageLabel: 'Language',
|
|
14
|
+
searchPlaceholder: 'Search memory…',
|
|
15
|
+
refresh: 'Refresh',
|
|
16
|
+
filtersPanelTitle: 'Bot role / tags',
|
|
17
|
+
filtersNavLabel: 'Filter by bot role, memory type, or tag',
|
|
18
|
+
entriesTitle: 'Memory',
|
|
19
|
+
'entryCount.one': '{count} item',
|
|
20
|
+
'entryCount.other': '{count} items',
|
|
21
|
+
editorTitle: 'Details',
|
|
22
|
+
unselected: 'Not selected',
|
|
23
|
+
operatorTitle: 'Agent run operator view',
|
|
24
|
+
trustBadge: 'stored data is untrusted / non-actionable',
|
|
25
|
+
runSelectFull: 'Select a run to view its intake, profile, timeline, delivery, feedback, and coverage.',
|
|
26
|
+
'kind.all': 'All',
|
|
27
|
+
'kind.fact': 'Fact',
|
|
28
|
+
'kind.decision': 'Decision',
|
|
29
|
+
'kind.lesson': 'Lesson',
|
|
30
|
+
'kind.preference': 'Preference',
|
|
31
|
+
'kind.reference': 'Reference',
|
|
32
|
+
'bot.common': 'Common',
|
|
33
|
+
'bot.researcher': 'Researcher',
|
|
34
|
+
'bot.builder': 'Builder',
|
|
35
|
+
'bot.reviewer': 'Reviewer',
|
|
36
|
+
'bot.devops': 'DevOps',
|
|
37
|
+
'bot.writer': 'Writer',
|
|
38
|
+
'bot.analyst': 'Analyst',
|
|
39
|
+
requestFailed: 'The request failed.',
|
|
40
|
+
botFilterTitle: 'Bot roles (tags)',
|
|
41
|
+
memoryTypeFilterTitle: 'Memory type',
|
|
42
|
+
crossTagFilterTitle: 'Cross-cutting tags',
|
|
43
|
+
noEntries: 'No matching memory entries.',
|
|
44
|
+
edit: 'Edit',
|
|
45
|
+
revision: 'revision',
|
|
46
|
+
selectMemory: 'Select a memory entry on the left to edit its details.',
|
|
47
|
+
memoryType: 'Memory type',
|
|
48
|
+
status: 'Status',
|
|
49
|
+
title: 'Title',
|
|
50
|
+
body: 'Body',
|
|
51
|
+
summary: 'Summary',
|
|
52
|
+
commaSeparatedTags: 'Tags (comma-separated)',
|
|
53
|
+
scopeJson: 'scope JSON',
|
|
54
|
+
provenanceJson: 'provenance JSON',
|
|
55
|
+
save: 'Save',
|
|
56
|
+
candidateNotice: 'Candidate entries are updated only after checking the revision.',
|
|
57
|
+
immutableNotice: 'Verified / superseded entries cannot be overwritten directly. Replace them with the CLI to preserve history.',
|
|
58
|
+
saved: 'Saved.',
|
|
59
|
+
runSelect: 'Select a run to view its details.',
|
|
60
|
+
contextWarning: 'Stored context / recommendations: untrusted, non-actionable',
|
|
61
|
+
detailRunIntake: 'run / intake',
|
|
62
|
+
detailInitialProfile: 'initial profile (immutable view)',
|
|
63
|
+
detailProjectedProfile: 'projected profile (ledger revisions)',
|
|
64
|
+
detailPolicySource: 'policy / profile source',
|
|
65
|
+
detailCoverageWarnings: 'coverage / evidence warnings',
|
|
66
|
+
detailTimelineEvidence: 'timeline / evidence',
|
|
67
|
+
detailDeliveriesReasons: 'context deliveries / selection reasons',
|
|
68
|
+
detailFeedback: 'context / run / intake feedback',
|
|
69
|
+
detailProposalLinks: 'memory proposal links',
|
|
70
|
+
noRuns: 'No runs.',
|
|
71
|
+
unknown: 'unknown',
|
|
72
|
+
untitled: 'untitled',
|
|
73
|
+
nextPage: 'More results available (bounded cursor)',
|
|
74
|
+
end: 'End',
|
|
75
|
+
'displayedCount.one': 'Showing {count} item',
|
|
76
|
+
'displayedCount.other': 'Showing {count} items',
|
|
77
|
+
noWorkspace: 'No workspace is available. Run kiokuko use or record in the CLI.',
|
|
78
|
+
'status.candidate': 'candidate',
|
|
79
|
+
'status.verified': 'verified',
|
|
80
|
+
'status.superseded': 'superseded',
|
|
81
|
+
};
|
|
82
|
+
const japaneseMessages = {
|
|
83
|
+
eyebrow: 'ローカル記憶コンソール',
|
|
84
|
+
subtitle: 'Bot用途・記憶タイプ・横断タグからSQLiteの記憶を確認し、安全に候補エントリを編集します。',
|
|
85
|
+
workspaceLabel: 'ワークスペース',
|
|
86
|
+
languageLabel: '言語',
|
|
87
|
+
searchPlaceholder: '記憶を検索…',
|
|
88
|
+
refresh: '更新',
|
|
89
|
+
filtersPanelTitle: 'Bot用途 / タグ',
|
|
90
|
+
filtersNavLabel: 'Bot用途・記憶タイプ・タグで絞り込む',
|
|
91
|
+
entriesTitle: '記憶',
|
|
92
|
+
'entryCount.one': '{count}件',
|
|
93
|
+
'entryCount.other': '{count}件',
|
|
94
|
+
editorTitle: '内容',
|
|
95
|
+
unselected: '未選択',
|
|
96
|
+
operatorTitle: 'エージェント実行オペレータービュー',
|
|
97
|
+
trustBadge: '保存データは信頼できず、操作の根拠にはできません',
|
|
98
|
+
runSelectFull: 'runを選択すると intake、profile、timeline、delivery、feedback、coverage を表示します。',
|
|
99
|
+
'kind.all': 'すべて',
|
|
100
|
+
'kind.fact': '事実',
|
|
101
|
+
'kind.decision': '決定',
|
|
102
|
+
'kind.lesson': '教訓',
|
|
103
|
+
'kind.preference': '好み',
|
|
104
|
+
'kind.reference': '参照',
|
|
105
|
+
'bot.common': '共通',
|
|
106
|
+
'bot.researcher': 'リサーチャー',
|
|
107
|
+
'bot.builder': 'ビルダー',
|
|
108
|
+
'bot.reviewer': 'レビュアー',
|
|
109
|
+
'bot.devops': 'DevOps',
|
|
110
|
+
'bot.writer': 'ライター',
|
|
111
|
+
'bot.analyst': 'アナリスト',
|
|
112
|
+
requestFailed: 'リクエストに失敗しました。',
|
|
113
|
+
botFilterTitle: 'Bot用途(タグ)',
|
|
114
|
+
memoryTypeFilterTitle: '記憶タイプ',
|
|
115
|
+
crossTagFilterTitle: '横断タグ',
|
|
116
|
+
noEntries: '該当する記憶はありません。',
|
|
117
|
+
edit: '編集',
|
|
118
|
+
revision: 'リビジョン',
|
|
119
|
+
selectMemory: '左の記憶を選択すると内容を編集できます。',
|
|
120
|
+
memoryType: '記憶タイプ',
|
|
121
|
+
status: '状態',
|
|
122
|
+
title: 'タイトル',
|
|
123
|
+
body: '本文',
|
|
124
|
+
summary: '要約',
|
|
125
|
+
commaSeparatedTags: 'タグ(カンマ区切り)',
|
|
126
|
+
scopeJson: 'scope JSON',
|
|
127
|
+
provenanceJson: 'provenance JSON',
|
|
128
|
+
save: '保存',
|
|
129
|
+
candidateNotice: '候補エントリはリビジョンを確認して更新します。',
|
|
130
|
+
immutableNotice: 'verified / superseded は直接上書きできません。履歴を保つためCLIで置換してください。',
|
|
131
|
+
saved: '保存しました。',
|
|
132
|
+
runSelect: 'runを選択すると詳細を表示します。',
|
|
133
|
+
contextWarning: '保存されたコンテキスト / 推奨事項:信頼できず、操作の根拠にはできません',
|
|
134
|
+
detailRunIntake: 'run / intake',
|
|
135
|
+
detailInitialProfile: '初期profile(変更不可の表示)',
|
|
136
|
+
detailProjectedProfile: '投影profile(ledgerの改訂)',
|
|
137
|
+
detailPolicySource: 'policy / profileの出典',
|
|
138
|
+
detailCoverageWarnings: 'coverage / evidenceの警告',
|
|
139
|
+
detailTimelineEvidence: 'timeline / evidence',
|
|
140
|
+
detailDeliveriesReasons: 'context delivery / 選択理由',
|
|
141
|
+
detailFeedback: 'context / run / intakeのfeedback',
|
|
142
|
+
detailProposalLinks: '記憶提案のリンク',
|
|
143
|
+
noRuns: 'runはありません。',
|
|
144
|
+
unknown: '不明',
|
|
145
|
+
untitled: '無題',
|
|
146
|
+
nextPage: '次ページあり(bounded cursor)',
|
|
147
|
+
end: '末尾',
|
|
148
|
+
'displayedCount.one': '{count}件を表示中',
|
|
149
|
+
'displayedCount.other': '{count}件を表示中',
|
|
150
|
+
noWorkspace: 'workspaceがありません。CLIで kiokuko use または record を実行してください。',
|
|
151
|
+
'status.candidate': '候補',
|
|
152
|
+
'status.verified': '検証済み',
|
|
153
|
+
'status.superseded': '置換済み',
|
|
154
|
+
};
|
|
155
|
+
const simplifiedChineseMessages = {
|
|
156
|
+
eyebrow: '本地记忆控制台',
|
|
157
|
+
subtitle: '按机器人用途、记忆类型和跨类别标签浏览SQLite记忆,并安全地编辑候选条目。',
|
|
158
|
+
workspaceLabel: '工作区',
|
|
159
|
+
languageLabel: '语言',
|
|
160
|
+
searchPlaceholder: '搜索记忆…',
|
|
161
|
+
refresh: '刷新',
|
|
162
|
+
filtersPanelTitle: '机器人用途 / 标签',
|
|
163
|
+
filtersNavLabel: '按机器人用途、记忆类型或标签筛选',
|
|
164
|
+
entriesTitle: '记忆',
|
|
165
|
+
'entryCount.one': '{count}条',
|
|
166
|
+
'entryCount.other': '{count}条',
|
|
167
|
+
editorTitle: '内容',
|
|
168
|
+
unselected: '未选择',
|
|
169
|
+
operatorTitle: '智能体运行操作视图',
|
|
170
|
+
trustBadge: '存储的数据不可信,不能作为操作依据',
|
|
171
|
+
runSelectFull: '选择一次运行以查看其intake、profile、timeline、delivery、feedback和coverage。',
|
|
172
|
+
'kind.all': '全部',
|
|
173
|
+
'kind.fact': '事实',
|
|
174
|
+
'kind.decision': '决定',
|
|
175
|
+
'kind.lesson': '经验教训',
|
|
176
|
+
'kind.preference': '偏好',
|
|
177
|
+
'kind.reference': '参考',
|
|
178
|
+
'bot.common': '通用',
|
|
179
|
+
'bot.researcher': '研究员',
|
|
180
|
+
'bot.builder': '构建者',
|
|
181
|
+
'bot.reviewer': '审查员',
|
|
182
|
+
'bot.devops': 'DevOps',
|
|
183
|
+
'bot.writer': '写作者',
|
|
184
|
+
'bot.analyst': '分析师',
|
|
185
|
+
requestFailed: '请求失败。',
|
|
186
|
+
botFilterTitle: '机器人用途(标签)',
|
|
187
|
+
memoryTypeFilterTitle: '记忆类型',
|
|
188
|
+
crossTagFilterTitle: '跨类别标签',
|
|
189
|
+
noEntries: '没有匹配的记忆。',
|
|
190
|
+
edit: '编辑',
|
|
191
|
+
revision: '修订',
|
|
192
|
+
selectMemory: '选择左侧的记忆以编辑其内容。',
|
|
193
|
+
memoryType: '记忆类型',
|
|
194
|
+
status: '状态',
|
|
195
|
+
title: '标题',
|
|
196
|
+
body: '正文',
|
|
197
|
+
summary: '摘要',
|
|
198
|
+
commaSeparatedTags: '标签(用逗号分隔)',
|
|
199
|
+
scopeJson: 'scope JSON',
|
|
200
|
+
provenanceJson: 'provenance JSON',
|
|
201
|
+
save: '保存',
|
|
202
|
+
candidateNotice: '候选条目仅在确认修订版本后更新。',
|
|
203
|
+
immutableNotice: '不能直接覆盖verified / superseded条目。请使用CLI替换以保留历史记录。',
|
|
204
|
+
saved: '已保存。',
|
|
205
|
+
runSelect: '选择一次运行以查看详情。',
|
|
206
|
+
contextWarning: '存储的上下文 / 建议:不可信,不能作为操作依据',
|
|
207
|
+
detailRunIntake: '运行 / intake',
|
|
208
|
+
detailInitialProfile: '初始profile(不可变视图)',
|
|
209
|
+
detailProjectedProfile: '投影profile(ledger修订)',
|
|
210
|
+
detailPolicySource: 'policy / profile来源',
|
|
211
|
+
detailCoverageWarnings: 'coverage / evidence警告',
|
|
212
|
+
detailTimelineEvidence: 'timeline / evidence',
|
|
213
|
+
detailDeliveriesReasons: 'context delivery / 选择原因',
|
|
214
|
+
detailFeedback: 'context / run / intake反馈',
|
|
215
|
+
detailProposalLinks: '记忆提案链接',
|
|
216
|
+
noRuns: '没有运行记录。',
|
|
217
|
+
unknown: '未知',
|
|
218
|
+
untitled: '无标题',
|
|
219
|
+
nextPage: '还有更多结果(有界游标)',
|
|
220
|
+
end: '末尾',
|
|
221
|
+
'displayedCount.one': '正在显示{count}条',
|
|
222
|
+
'displayedCount.other': '正在显示{count}条',
|
|
223
|
+
noWorkspace: '没有可用的工作区。请在CLI中运行kiokuko use或record。',
|
|
224
|
+
'status.candidate': '候选',
|
|
225
|
+
'status.verified': '已验证',
|
|
226
|
+
'status.superseded': '已替代',
|
|
227
|
+
};
|
|
228
|
+
const koreanMessages = {
|
|
229
|
+
eyebrow: '로컬 메모리 콘솔',
|
|
230
|
+
subtitle: '봇 역할, 메모리 유형, 교차 태그로 SQLite 메모리를 확인하고 후보 항목을 안전하게 편집합니다.',
|
|
231
|
+
workspaceLabel: '워크스페이스',
|
|
232
|
+
languageLabel: '언어',
|
|
233
|
+
searchPlaceholder: '메모리 검색…',
|
|
234
|
+
refresh: '새로 고침',
|
|
235
|
+
filtersPanelTitle: '봇 역할 / 태그',
|
|
236
|
+
filtersNavLabel: '봇 역할, 메모리 유형 또는 태그로 필터링',
|
|
237
|
+
entriesTitle: '메모리',
|
|
238
|
+
'entryCount.one': '{count}개',
|
|
239
|
+
'entryCount.other': '{count}개',
|
|
240
|
+
editorTitle: '내용',
|
|
241
|
+
unselected: '선택 안 함',
|
|
242
|
+
operatorTitle: '에이전트 실행 운영자 보기',
|
|
243
|
+
trustBadge: '저장된 데이터는 신뢰할 수 없으며 작업 근거로 사용할 수 없습니다',
|
|
244
|
+
runSelectFull: '실행을 선택하면 intake, profile, timeline, delivery, feedback, coverage를 표시합니다.',
|
|
245
|
+
'kind.all': '전체',
|
|
246
|
+
'kind.fact': '사실',
|
|
247
|
+
'kind.decision': '결정',
|
|
248
|
+
'kind.lesson': '교훈',
|
|
249
|
+
'kind.preference': '선호',
|
|
250
|
+
'kind.reference': '참조',
|
|
251
|
+
'bot.common': '공통',
|
|
252
|
+
'bot.researcher': '리서처',
|
|
253
|
+
'bot.builder': '빌더',
|
|
254
|
+
'bot.reviewer': '리뷰어',
|
|
255
|
+
'bot.devops': 'DevOps',
|
|
256
|
+
'bot.writer': '라이터',
|
|
257
|
+
'bot.analyst': '애널리스트',
|
|
258
|
+
requestFailed: '요청에 실패했습니다.',
|
|
259
|
+
botFilterTitle: '봇 역할(태그)',
|
|
260
|
+
memoryTypeFilterTitle: '메모리 유형',
|
|
261
|
+
crossTagFilterTitle: '교차 태그',
|
|
262
|
+
noEntries: '일치하는 메모리가 없습니다.',
|
|
263
|
+
edit: '편집',
|
|
264
|
+
revision: '리비전',
|
|
265
|
+
selectMemory: '왼쪽에서 메모리를 선택하면 내용을 편집할 수 있습니다.',
|
|
266
|
+
memoryType: '메모리 유형',
|
|
267
|
+
status: '상태',
|
|
268
|
+
title: '제목',
|
|
269
|
+
body: '본문',
|
|
270
|
+
summary: '요약',
|
|
271
|
+
commaSeparatedTags: '태그(쉼표로 구분)',
|
|
272
|
+
scopeJson: 'scope JSON',
|
|
273
|
+
provenanceJson: 'provenance JSON',
|
|
274
|
+
save: '저장',
|
|
275
|
+
candidateNotice: '후보 항목은 리비전을 확인한 뒤 업데이트합니다.',
|
|
276
|
+
immutableNotice: 'verified / superseded 항목은 직접 덮어쓸 수 없습니다. 기록을 보존하려면 CLI에서 교체하세요.',
|
|
277
|
+
saved: '저장했습니다.',
|
|
278
|
+
runSelect: '실행을 선택하면 세부 정보를 표시합니다.',
|
|
279
|
+
contextWarning: '저장된 context / 권장 사항: 신뢰할 수 없으며 작업 근거로 사용할 수 없음',
|
|
280
|
+
detailRunIntake: '실행 / intake',
|
|
281
|
+
detailInitialProfile: '초기profile(변경 불가 보기)',
|
|
282
|
+
detailProjectedProfile: '투영profile(ledger 리비전)',
|
|
283
|
+
detailPolicySource: 'policy / profile 출처',
|
|
284
|
+
detailCoverageWarnings: 'coverage / evidence 경고',
|
|
285
|
+
detailTimelineEvidence: 'timeline / evidence',
|
|
286
|
+
detailDeliveriesReasons: 'context delivery / 선택 이유',
|
|
287
|
+
detailFeedback: 'context / run / intake feedback',
|
|
288
|
+
detailProposalLinks: '메모리 제안 링크',
|
|
289
|
+
noRuns: '실행 기록이 없습니다.',
|
|
290
|
+
unknown: '알 수 없음',
|
|
291
|
+
untitled: '제목 없음',
|
|
292
|
+
nextPage: '다음 페이지 있음(제한된 커서)',
|
|
293
|
+
end: '끝',
|
|
294
|
+
'displayedCount.one': '{count}개 표시 중',
|
|
295
|
+
'displayedCount.other': '{count}개 표시 중',
|
|
296
|
+
noWorkspace: '사용 가능한 워크스페이스가 없습니다. CLI에서 kiokuko use 또는 record를 실행하세요.',
|
|
297
|
+
'status.candidate': '후보',
|
|
298
|
+
'status.verified': '검증됨',
|
|
299
|
+
'status.superseded': '대체됨',
|
|
300
|
+
};
|
|
301
|
+
export const WEB_MESSAGES = {
|
|
302
|
+
en: englishMessages,
|
|
303
|
+
ja: japaneseMessages,
|
|
304
|
+
'zh-CN': simplifiedChineseMessages,
|
|
305
|
+
ko: koreanMessages,
|
|
306
|
+
};
|
|
307
|
+
export function normalizeWebLocale(value) {
|
|
308
|
+
if (typeof value !== 'string')
|
|
309
|
+
return null;
|
|
310
|
+
const normalized = value.trim().replaceAll('_', '-').toLowerCase();
|
|
311
|
+
if (!normalized)
|
|
312
|
+
return null;
|
|
313
|
+
const parts = normalized.split('-');
|
|
314
|
+
const language = parts[0];
|
|
315
|
+
if (language === 'en' || language === 'ja' || language === 'ko')
|
|
316
|
+
return language;
|
|
317
|
+
if (language === 'zh' && (parts.length === 1 || parts.includes('hans') || parts.includes('cn') || parts.includes('sg')))
|
|
318
|
+
return 'zh-CN';
|
|
319
|
+
return null;
|
|
320
|
+
}
|
|
321
|
+
export function resolveWebLocale(candidates) {
|
|
322
|
+
for (const candidate of candidates) {
|
|
323
|
+
const locale = normalizeWebLocale(candidate);
|
|
324
|
+
if (locale)
|
|
325
|
+
return locale;
|
|
326
|
+
}
|
|
327
|
+
return DEFAULT_WEB_LOCALE;
|
|
328
|
+
}
|
|
329
|
+
//# sourceMappingURL=i18n.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"i18n.js","sourceRoot":"","sources":["../../src/web/i18n.ts"],"names":[],"mappings":"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"}
|
package/dist/web/ui.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ui.d.ts","sourceRoot":"","sources":["../../src/web/ui.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ui.d.ts","sourceRoot":"","sources":["../../src/web/ui.ts"],"names":[],"mappings":"AAcA,eAAO,MAAM,QAAQ,QAmUb,CAAC"}
|
package/dist/web/ui.js
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
|
+
import { DEFAULT_WEB_LOCALE, WEB_LOCALE_LABELS, WEB_LOCALES, WEB_MESSAGES } from './i18n.js';
|
|
2
|
+
const WEB_I18N_CONFIG = JSON.stringify({
|
|
3
|
+
defaultLocale: DEFAULT_WEB_LOCALE,
|
|
4
|
+
localeLabels: WEB_LOCALE_LABELS,
|
|
5
|
+
locales: WEB_LOCALES,
|
|
6
|
+
messages: WEB_MESSAGES,
|
|
7
|
+
})
|
|
8
|
+
.replaceAll('&', '\\u0026')
|
|
9
|
+
.replaceAll('<', '\\u003c')
|
|
10
|
+
.replaceAll('>', '\\u003e')
|
|
11
|
+
.replaceAll('\u2028', '\\u2028')
|
|
12
|
+
.replaceAll('\u2029', '\\u2029');
|
|
1
13
|
export const WEB_HTML = String.raw `<!doctype html>
|
|
2
|
-
<html lang="
|
|
14
|
+
<html lang="en">
|
|
3
15
|
<head>
|
|
4
16
|
<meta charset="utf-8">
|
|
5
17
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
@@ -56,7 +68,7 @@ export const WEB_HTML = String.raw `<!doctype html>
|
|
|
56
68
|
.notice { border-radius:12px; padding:11px 12px; background:#fffbeb; color:var(--warn); font-size:13px; }
|
|
57
69
|
.notice.error { background:#fef2f2; color:var(--danger); }
|
|
58
70
|
.status { color:var(--muted); font-size:12px; min-height:18px; }
|
|
59
|
-
.operator-panel { grid-column:1 / -1; }
|
|
71
|
+
.operator-panel { grid-column:1 / -1; margin-top:16px; }
|
|
60
72
|
.operator-grid { display:grid; grid-template-columns:minmax(240px,.7fr) minmax(420px,1.3fr); gap:16px; }
|
|
61
73
|
.run-list { display:flex; flex-direction:column; gap:8px; max-height:360px; overflow:auto; }
|
|
62
74
|
.run-card { border:1px solid var(--line); border-radius:12px; padding:11px; background:var(--panel); text-align:left; }
|
|
@@ -73,56 +85,103 @@ export const WEB_HTML = String.raw `<!doctype html>
|
|
|
73
85
|
<main class="shell">
|
|
74
86
|
<header class="topbar">
|
|
75
87
|
<div>
|
|
76
|
-
<div class="eyebrow">Local memory console</div>
|
|
88
|
+
<div class="eyebrow" data-i18n="eyebrow">Local memory console</div>
|
|
77
89
|
<h1>Kiokuko Web</h1>
|
|
78
|
-
<p class="subtitle">
|
|
90
|
+
<p class="subtitle" data-i18n="subtitle">Browse SQLite memory by bot role, memory type, and cross-cutting tags, and safely edit candidate entries.</p>
|
|
79
91
|
</div>
|
|
80
92
|
<div class="toolbar">
|
|
81
|
-
<select id="
|
|
82
|
-
<
|
|
83
|
-
<
|
|
93
|
+
<select id="locale" class="control" aria-label="Language" data-i18n-aria-label="languageLabel"></select>
|
|
94
|
+
<select id="workspace" class="control" aria-label="Workspace" data-i18n-aria-label="workspaceLabel"></select>
|
|
95
|
+
<input id="search" class="search" type="search" placeholder="Search memory…" aria-label="Search memory…" data-i18n-placeholder="searchPlaceholder" data-i18n-aria-label="searchPlaceholder">
|
|
96
|
+
<button id="refresh" class="button" type="button" data-i18n="refresh">Refresh</button>
|
|
84
97
|
</div>
|
|
85
98
|
</header>
|
|
86
99
|
<div id="status" class="status" role="status"></div>
|
|
87
100
|
<section class="layout">
|
|
88
101
|
<aside class="panel genres-panel">
|
|
89
|
-
<div class="panel-head"><h2>Bot
|
|
90
|
-
<nav id="genres" class="genres" aria-label="
|
|
102
|
+
<div class="panel-head"><h2 data-i18n="filtersPanelTitle">Bot role / tags</h2></div>
|
|
103
|
+
<nav id="genres" class="genres" aria-label="Filter by bot role, memory type, or tag" data-i18n-aria-label="filtersNavLabel"></nav>
|
|
91
104
|
</aside>
|
|
92
105
|
<section class="panel list-panel">
|
|
93
|
-
<div class="panel-head"><h2 id="list-title"
|
|
106
|
+
<div class="panel-head"><h2 id="list-title">Memory</h2><span id="result-count" class="badge">0 items</span></div>
|
|
94
107
|
<div class="panel-body"><div id="entry-list" class="entry-list"></div></div>
|
|
95
108
|
</section>
|
|
96
109
|
<section class="panel editor-panel">
|
|
97
|
-
<div class="panel-head"><h2
|
|
110
|
+
<div class="panel-head"><h2 data-i18n="editorTitle">Details</h2><span id="editor-state" class="badge" data-i18n="unselected">Not selected</span></div>
|
|
98
111
|
<div class="panel-body"><div id="editor"></div></div>
|
|
99
112
|
</section>
|
|
100
113
|
</section>
|
|
101
114
|
<section class="panel operator-panel">
|
|
102
|
-
<div class="panel-head"><h2>Agent run operator view</h2><span class="badge">stored data is untrusted / non-actionable</span></div>
|
|
115
|
+
<div class="panel-head"><h2 data-i18n="operatorTitle">Agent run operator view</h2><span class="badge" data-i18n="trustBadge">stored data is untrusted / non-actionable</span></div>
|
|
103
116
|
<div class="panel-body operator-grid">
|
|
104
117
|
<div><div id="run-list" class="run-list"></div><div id="run-page" class="status"></div></div>
|
|
105
|
-
<div id="run-detail"><div class="editor-empty">run
|
|
118
|
+
<div id="run-detail"><div class="editor-empty" data-i18n="runSelectFull">Select a run to view its intake, profile, timeline, delivery, feedback, and coverage.</div></div>
|
|
106
119
|
</div>
|
|
107
120
|
</section>
|
|
108
121
|
</main>
|
|
109
122
|
<script>
|
|
123
|
+
const i18n = ${WEB_I18N_CONFIG};
|
|
124
|
+
const localeStorageKey = 'kiokuko.web.locale';
|
|
125
|
+
const normalizeLocale = (value) => {
|
|
126
|
+
if (typeof value !== 'string') return null;
|
|
127
|
+
const normalized = value.trim().replaceAll('_', '-').toLowerCase();
|
|
128
|
+
if (!normalized) return null;
|
|
129
|
+
const parts = normalized.split('-');
|
|
130
|
+
const language = parts[0];
|
|
131
|
+
if (language === 'en' || language === 'ja' || language === 'ko') return language;
|
|
132
|
+
if (language === 'zh' && (parts.length === 1 || parts.includes('hans') || parts.includes('cn') || parts.includes('sg'))) return 'zh-CN';
|
|
133
|
+
return null;
|
|
134
|
+
};
|
|
135
|
+
const readStoredLocale = () => { try { return localStorage.getItem(localeStorageKey); } catch { return null; } };
|
|
136
|
+
const browserLocales = Array.isArray(navigator.languages) ? navigator.languages : [navigator.language];
|
|
137
|
+
const localeCandidates = [new URLSearchParams(location.search).get('lang'), readStoredLocale(), ...browserLocales];
|
|
138
|
+
const initialLocale = localeCandidates.map(normalizeLocale).find(Boolean) || i18n.defaultLocale;
|
|
110
139
|
const kinds = [
|
|
111
|
-
['all', '
|
|
140
|
+
['all', 'kind.all'], ['fact', 'kind.fact'], ['decision', 'kind.decision'], ['lesson', 'kind.lesson'], ['preference', 'kind.preference'], ['reference', 'kind.reference']
|
|
112
141
|
];
|
|
113
142
|
const botModes = [
|
|
114
|
-
['bot:common', '
|
|
143
|
+
['bot:common', 'bot.common'], ['bot:researcher', 'bot.researcher'], ['bot:builder', 'bot.builder'], ['bot:reviewer', 'bot.reviewer'], ['bot:devops', 'bot.devops'], ['bot:writer', 'bot.writer'], ['bot:analyst', 'bot.analyst']
|
|
115
144
|
];
|
|
116
|
-
const state = { workspace: '', kind: 'all', tag: '', query: '', entries: [], tags: [], selected: null, runs: [], selectedRun: null };
|
|
145
|
+
const state = { locale: initialLocale, workspace: '', kind: 'all', tag: '', query: '', entries: [], tags: [], selected: null, runs: [], selectedRun: null, localizedStatus: null };
|
|
117
146
|
const $ = (id) => document.getElementById(id);
|
|
147
|
+
const t = (key, parameters = {}) => {
|
|
148
|
+
const template = i18n.messages[state.locale]?.[key] ?? i18n.messages[i18n.defaultLocale]?.[key] ?? key;
|
|
149
|
+
return template.replace(/\{([^}]+)\}/g, (_match, name) => Object.prototype.hasOwnProperty.call(parameters, name) ? String(parameters[name]) : '');
|
|
150
|
+
};
|
|
151
|
+
const tp = (key, count) => {
|
|
152
|
+
const category = new Intl.PluralRules(state.locale).select(count) === 'one' ? 'one' : 'other';
|
|
153
|
+
return t(key + '.' + category, { count });
|
|
154
|
+
};
|
|
155
|
+
const setI18nText = (element, key) => { element.dataset.i18n = key; element.textContent = t(key); return element; };
|
|
156
|
+
const labelForKind = (kind) => { const item = kinds.find(([value]) => value === kind); return item ? t(item[1]) : kind; };
|
|
157
|
+
const labelForStatus = (status) => i18n.messages[state.locale]?.['status.' + status] ?? status;
|
|
158
|
+
const updateEditorState = () => {
|
|
159
|
+
const element = $('editor-state');
|
|
160
|
+
if (state.selected) { delete element.dataset.i18n; element.dataset.i18nStatus = state.selected.status; element.textContent = labelForStatus(state.selected.status); }
|
|
161
|
+
else { delete element.dataset.i18nStatus; setI18nText(element, 'unselected'); }
|
|
162
|
+
};
|
|
163
|
+
const showStatus = (message, error = false) => { $('status').textContent = message; $('status').className = error ? 'status notice error' : 'status'; };
|
|
164
|
+
const setStatus = (message, error = false) => { state.localizedStatus = null; showStatus(message, error); };
|
|
165
|
+
const setLocalizedStatus = (key, parameters = {}, error = false) => { state.localizedStatus = { key, parameters, error }; showStatus(t(key, parameters), error); };
|
|
166
|
+
const setLocalizedCountStatus = (key, count, error = false) => { state.localizedStatus = { key, count, error, plural: true }; showStatus(tp(key, count), error); };
|
|
167
|
+
const applyTranslations = () => {
|
|
168
|
+
document.documentElement.lang = state.locale;
|
|
169
|
+
document.querySelectorAll('[data-i18n]').forEach((element) => { element.textContent = t(element.dataset.i18n); });
|
|
170
|
+
document.querySelectorAll('[data-i18n-aria-label]').forEach((element) => { element.setAttribute('aria-label', t(element.dataset.i18nAriaLabel)); });
|
|
171
|
+
document.querySelectorAll('[data-i18n-placeholder]').forEach((element) => { element.setAttribute('placeholder', t(element.dataset.i18nPlaceholder)); });
|
|
172
|
+
document.querySelectorAll('[data-i18n-status]').forEach((element) => {
|
|
173
|
+
const value = labelForStatus(element.dataset.i18nStatus);
|
|
174
|
+
if ('value' in element) element.value = value; else element.textContent = value;
|
|
175
|
+
});
|
|
176
|
+
$('locale').value = state.locale;
|
|
177
|
+
if (state.localizedStatus) showStatus(state.localizedStatus.plural ? tp(state.localizedStatus.key, state.localizedStatus.count) : t(state.localizedStatus.key, state.localizedStatus.parameters), state.localizedStatus.error);
|
|
178
|
+
};
|
|
118
179
|
const api = async (path, options) => {
|
|
119
180
|
const response = await fetch(path, options);
|
|
120
181
|
const value = await response.json();
|
|
121
|
-
if (!response.ok) throw new Error(value.error?.message || '
|
|
182
|
+
if (!response.ok) throw new Error(value.error?.message || t('requestFailed'));
|
|
122
183
|
return value;
|
|
123
184
|
};
|
|
124
|
-
const setStatus = (message, error = false) => { $('status').textContent = message; $('status').className = error ? 'status notice error' : 'status'; };
|
|
125
|
-
const labelForKind = (kind) => (kinds.find((item) => item[0] === kind) || [kind, kind])[1];
|
|
126
185
|
const escapeTags = (value) => value.split(',').map((item) => item.trim()).filter(Boolean);
|
|
127
186
|
|
|
128
187
|
function filterButton(key, label, count, active, onClick) {
|
|
@@ -145,32 +204,32 @@ export const WEB_HTML = String.raw `<!doctype html>
|
|
|
145
204
|
function renderFilters() {
|
|
146
205
|
const kindCounts = Object.fromEntries(kinds.map(([kind]) => [kind, kind === 'all' ? state.entries.length : state.entries.filter((entry) => entry.kind === kind).length]));
|
|
147
206
|
const tagCounts = Object.fromEntries(state.tags.map((item) => [item.tag, item.count]));
|
|
148
|
-
const botButtons = botModes.map(([tag, label]) => filterButton(tag, label, tagCounts[tag], state.tag === tag, () => { state.tag = tag; renderFilters(); loadEntries(); }));
|
|
149
|
-
const kindButtons = kinds.map(([kind, label]) => filterButton(kind, label, kindCounts[kind], state.kind === kind, () => { state.kind = kind; renderFilters(); loadEntries(); }));
|
|
207
|
+
const botButtons = botModes.map(([tag, label]) => filterButton(tag, t(label), tagCounts[tag], state.tag === tag, () => { state.tag = tag; renderFilters(); loadEntries(); }));
|
|
208
|
+
const kindButtons = kinds.map(([kind, label]) => filterButton(kind, t(label), kindCounts[kind], state.kind === kind, () => { state.kind = kind; renderFilters(); loadEntries(); }));
|
|
150
209
|
const tagButtons = state.tags
|
|
151
210
|
.filter((item) => !botModes.some(([tag]) => tag === item.tag))
|
|
152
211
|
.map((item) => filterButton(item.tag, '#' + item.tag, item.count, state.tag === item.tag, () => { state.tag = item.tag; renderFilters(); loadEntries(); }));
|
|
153
|
-
const root = $('genres'); root.replaceChildren(filterGroup('
|
|
154
|
-
if (tagButtons.length > 0) root.append(filterGroup('
|
|
212
|
+
const root = $('genres'); root.replaceChildren(filterGroup(t('botFilterTitle'), botButtons), filterGroup(t('memoryTypeFilterTitle'), kindButtons));
|
|
213
|
+
if (tagButtons.length > 0) root.append(filterGroup(t('crossTagFilterTitle'), tagButtons));
|
|
155
214
|
}
|
|
156
215
|
|
|
157
216
|
function renderEntries() {
|
|
158
|
-
$('result-count').textContent =
|
|
159
|
-
$('list-title').textContent = state.tag ? '#' + state.tag : (state.kind === 'all' ? '
|
|
217
|
+
$('result-count').textContent = tp('entryCount', state.entries.length);
|
|
218
|
+
$('list-title').textContent = state.tag ? '#' + state.tag : (state.kind === 'all' ? t('entriesTitle') : labelForKind(state.kind));
|
|
160
219
|
const list = $('entry-list');
|
|
161
220
|
if (!state.entries.length) {
|
|
162
|
-
const empty = document.createElement('div'); empty.className = 'editor-empty'; empty
|
|
221
|
+
const empty = document.createElement('div'); empty.className = 'editor-empty'; setI18nText(empty, 'noEntries'); list.replaceChildren(empty); return;
|
|
163
222
|
}
|
|
164
223
|
list.replaceChildren(...state.entries.map((entry) => {
|
|
165
224
|
const card = document.createElement('article'); card.className = 'entry-card ' + (state.selected?.id === entry.id ? 'selected' : '');
|
|
166
225
|
const meta = document.createElement('div'); meta.className = 'entry-meta';
|
|
167
226
|
const kind = document.createElement('span'); kind.className = 'badge'; kind.textContent = labelForKind(entry.kind);
|
|
168
|
-
const status = document.createElement('span'); status.className = 'badge ' + entry.status; status.textContent = entry.status;
|
|
169
|
-
const revision = document.createElement('span'); revision.textContent = 'revision ' + entry.revision; meta.append(kind, status, revision);
|
|
227
|
+
const status = document.createElement('span'); status.className = 'badge ' + entry.status; status.textContent = labelForStatus(entry.status);
|
|
228
|
+
const revision = document.createElement('span'); revision.textContent = t('revision') + ' ' + entry.revision; meta.append(kind, status, revision);
|
|
170
229
|
const title = document.createElement('h3'); title.textContent = entry.title;
|
|
171
230
|
const snippet = document.createElement('p'); snippet.className = 'snippet'; snippet.textContent = entry.summary || entry.body;
|
|
172
231
|
const tags = document.createElement('div'); tags.className = 'tags'; entry.tags.forEach((tag) => { const item = document.createElement('button'); item.type = 'button'; item.className = 'tag'; item.textContent = '#' + tag; item.addEventListener('click', (event) => { event.stopPropagation(); state.tag = tag; renderFilters(); loadEntries(); }); tags.append(item); });
|
|
173
|
-
const edit = document.createElement('button'); edit.type = 'button'; edit.className = 'button'; edit
|
|
232
|
+
const edit = document.createElement('button'); edit.type = 'button'; edit.className = 'button'; setI18nText(edit, 'edit'); edit.style.marginTop = '12px'; edit.addEventListener('click', (event) => { event.stopPropagation(); selectEntry(entry.id); });
|
|
174
233
|
card.append(meta, title, snippet, tags, edit); card.addEventListener('click', () => selectEntry(entry.id)); return card;
|
|
175
234
|
}));
|
|
176
235
|
}
|
|
@@ -178,27 +237,27 @@ export const WEB_HTML = String.raw `<!doctype html>
|
|
|
178
237
|
function renderEditor() {
|
|
179
238
|
const editor = $('editor');
|
|
180
239
|
const entry = state.selected;
|
|
181
|
-
|
|
182
|
-
if (!entry) { const empty = document.createElement('div'); empty.className = 'editor-empty'; empty
|
|
240
|
+
updateEditorState();
|
|
241
|
+
if (!entry) { const empty = document.createElement('div'); empty.className = 'editor-empty'; setI18nText(empty, 'selectMemory'); editor.replaceChildren(empty); return; }
|
|
183
242
|
const form = document.createElement('form'); form.className = 'form';
|
|
184
243
|
const row = document.createElement('div'); row.className = 'form-row';
|
|
185
|
-
const kindLabel = document.createElement('label');
|
|
186
|
-
const statusLabel = document.createElement('label');
|
|
187
|
-
const titleLabel = document.createElement('label');
|
|
188
|
-
const bodyLabel = document.createElement('label');
|
|
189
|
-
const summaryLabel = document.createElement('label');
|
|
190
|
-
const tagsLabel = document.createElement('label');
|
|
244
|
+
const kindLabel = document.createElement('label'); const kindLabelText = document.createElement('span'); setI18nText(kindLabelText, 'memoryType'); const kind = document.createElement('select'); kinds.filter(([value]) => value !== 'all').forEach(([value, label]) => { const option = document.createElement('option'); option.value = value; setI18nText(option, label); kind.append(option); }); kind.value = entry.kind; kindLabel.append(kindLabelText, kind);
|
|
245
|
+
const statusLabel = document.createElement('label'); const statusLabelText = document.createElement('span'); setI18nText(statusLabelText, 'status'); const status = document.createElement('input'); status.value = labelForStatus(entry.status); status.dataset.i18nStatus = entry.status; status.disabled = true; statusLabel.append(statusLabelText, status); row.append(kindLabel, statusLabel);
|
|
246
|
+
const titleLabel = document.createElement('label'); const titleLabelText = document.createElement('span'); setI18nText(titleLabelText, 'title'); const title = document.createElement('input'); title.value = entry.title; titleLabel.append(titleLabelText, title);
|
|
247
|
+
const bodyLabel = document.createElement('label'); const bodyLabelText = document.createElement('span'); setI18nText(bodyLabelText, 'body'); const body = document.createElement('textarea'); body.className = 'body'; body.value = entry.body; bodyLabel.append(bodyLabelText, body);
|
|
248
|
+
const summaryLabel = document.createElement('label'); const summaryLabelText = document.createElement('span'); setI18nText(summaryLabelText, 'summary'); const summary = document.createElement('textarea'); summary.value = entry.summary || ''; summaryLabel.append(summaryLabelText, summary);
|
|
249
|
+
const tagsLabel = document.createElement('label'); const tagsLabelText = document.createElement('span'); setI18nText(tagsLabelText, 'commaSeparatedTags'); const tags = document.createElement('input'); tags.value = entry.tags.join(', '); tagsLabel.append(tagsLabelText, tags);
|
|
191
250
|
const jsonRow = document.createElement('div'); jsonRow.className = 'form-row';
|
|
192
|
-
const scopeLabel = document.createElement('label');
|
|
193
|
-
const provenanceLabel = document.createElement('label');
|
|
251
|
+
const scopeLabel = document.createElement('label'); const scopeLabelText = document.createElement('span'); setI18nText(scopeLabelText, 'scopeJson'); const scope = document.createElement('textarea'); scope.value = JSON.stringify(entry.scope, null, 2); scopeLabel.append(scopeLabelText, scope);
|
|
252
|
+
const provenanceLabel = document.createElement('label'); const provenanceLabelText = document.createElement('span'); setI18nText(provenanceLabelText, 'provenanceJson'); const provenance = document.createElement('textarea'); provenance.value = JSON.stringify(entry.provenance, null, 2); provenanceLabel.append(provenanceLabelText, provenance); jsonRow.append(scopeLabel, provenanceLabel);
|
|
194
253
|
const actions = document.createElement('div'); actions.className = 'toolbar';
|
|
195
|
-
const save = document.createElement('button'); save.type = 'submit'; save.className = 'button primary'; save
|
|
196
|
-
const note = document.createElement('div'); note.className = entry.status === 'candidate' ? 'notice' : 'notice error'; note
|
|
254
|
+
const save = document.createElement('button'); save.type = 'submit'; save.className = 'button primary'; setI18nText(save, 'save');
|
|
255
|
+
const note = document.createElement('div'); note.className = entry.status === 'candidate' ? 'notice' : 'notice error'; setI18nText(note, entry.status === 'candidate' ? 'candidateNotice' : 'immutableNotice');
|
|
197
256
|
if (entry.status !== 'candidate') { save.disabled = true; [kind, title, body, summary, tags, scope, provenance].forEach((control) => { control.disabled = true; }); }
|
|
198
257
|
actions.append(save); form.append(row, titleLabel, bodyLabel, summaryLabel, tagsLabel, jsonRow, note, actions); form.addEventListener('submit', async (event) => { event.preventDefault(); if (save.disabled) return; try {
|
|
199
258
|
const payload = { expectedRevision: entry.revision, kind: kind.value, title: title.value, body: body.value, summary: summary.value || null, scope: JSON.parse(scope.value || '{}'), provenance: JSON.parse(provenance.value || '{}'), tags: escapeTags(tags.value) };
|
|
200
259
|
await api('/api/entries/' + encodeURIComponent(entry.id) + '?workspace=' + encodeURIComponent(state.workspace), { method: 'PUT', headers: { 'content-type': 'application/json' }, body: JSON.stringify(payload) });
|
|
201
|
-
|
|
260
|
+
setLocalizedStatus('saved'); await loadEntries(); await selectEntry(entry.id);
|
|
202
261
|
} catch (error) { setStatus(error.message, true); }
|
|
203
262
|
}); editor.replaceChildren(form);
|
|
204
263
|
}
|
|
@@ -213,37 +272,37 @@ export const WEB_HTML = String.raw `<!doctype html>
|
|
|
213
272
|
} catch (error) { setStatus(error.message, true); }
|
|
214
273
|
}
|
|
215
274
|
|
|
216
|
-
function detailBlock(
|
|
275
|
+
function detailBlock(titleKey, value) {
|
|
217
276
|
const block = document.createElement('section'); block.className = 'detail-block';
|
|
218
|
-
const heading = document.createElement('h3'); heading
|
|
277
|
+
const heading = document.createElement('h3'); setI18nText(heading, titleKey);
|
|
219
278
|
const text = document.createElement('div'); text.className = 'detail-text'; text.textContent = typeof value === 'string' ? value : JSON.stringify(value, null, 2);
|
|
220
279
|
block.append(heading, text); return block;
|
|
221
280
|
}
|
|
222
281
|
|
|
223
282
|
function renderRunDetail() {
|
|
224
283
|
const root = $('run-detail'); const detail = state.selectedRun;
|
|
225
|
-
if (!detail) { const empty = document.createElement('div'); empty.className = 'editor-empty'; empty
|
|
226
|
-
const heading = document.createElement('h3'); heading
|
|
284
|
+
if (!detail) { const empty = document.createElement('div'); empty.className = 'editor-empty'; setI18nText(empty, 'runSelect'); root.replaceChildren(empty); return; }
|
|
285
|
+
const heading = document.createElement('h3'); setI18nText(heading, 'contextWarning');
|
|
227
286
|
const blocks = [
|
|
228
|
-
detailBlock('
|
|
229
|
-
detailBlock('
|
|
230
|
-
detailBlock('
|
|
231
|
-
detailBlock('
|
|
232
|
-
detailBlock('
|
|
233
|
-
detailBlock('
|
|
234
|
-
detailBlock('
|
|
235
|
-
detailBlock('
|
|
236
|
-
detailBlock('
|
|
287
|
+
detailBlock('detailRunIntake', { run: detail.run, intake: detail.intake }),
|
|
288
|
+
detailBlock('detailInitialProfile', detail.profile.initial),
|
|
289
|
+
detailBlock('detailProjectedProfile', detail.profile.projected),
|
|
290
|
+
detailBlock('detailPolicySource', { policyVersion: detail.profile.policyVersion, source: detail.profile.source, initialProfileHash: detail.profile.initialProfileHash }),
|
|
291
|
+
detailBlock('detailCoverageWarnings', { coverage: detail.coverage, evidenceState: detail.evidenceState, warnings: detail.warnings }),
|
|
292
|
+
detailBlock('detailTimelineEvidence', { timeline: detail.timeline, evidence: detail.evidence }),
|
|
293
|
+
detailBlock('detailDeliveriesReasons', detail.deliveries),
|
|
294
|
+
detailBlock('detailFeedback', detail.feedback),
|
|
295
|
+
detailBlock('detailProposalLinks', { proposals: detail.proposals, links: detail.memoryLinks }),
|
|
237
296
|
];
|
|
238
297
|
root.replaceChildren(heading, ...blocks);
|
|
239
298
|
}
|
|
240
299
|
|
|
241
300
|
function renderRuns() {
|
|
242
301
|
const root = $('run-list');
|
|
243
|
-
if (!state.runs.length) { const empty = document.createElement('div'); empty.className = 'editor-empty'; empty
|
|
302
|
+
if (!state.runs.length) { const empty = document.createElement('div'); empty.className = 'editor-empty'; setI18nText(empty, 'noRuns'); root.replaceChildren(empty); return; }
|
|
244
303
|
root.replaceChildren(...state.runs.map((run) => {
|
|
245
304
|
const button = document.createElement('button'); button.type = 'button'; button.className = 'run-card' + (state.selectedRun?.run?.runId === run.runId ? ' selected' : '');
|
|
246
|
-
button.textContent = run.runId + ' / ' + (run.status || 'unknown') + ' / ' + (run.title || 'untitled');
|
|
305
|
+
button.textContent = run.runId + ' / ' + (run.status || t('unknown')) + ' / ' + (run.title || t('untitled'));
|
|
247
306
|
button.addEventListener('click', () => loadRunDetail(run.runId)); return button;
|
|
248
307
|
}));
|
|
249
308
|
}
|
|
@@ -252,18 +311,25 @@ export const WEB_HTML = String.raw `<!doctype html>
|
|
|
252
311
|
if (!state.workspace) return;
|
|
253
312
|
try {
|
|
254
313
|
const result = await api('/api/operator/runs?workspace=' + encodeURIComponent(state.workspace) + '&limit=50');
|
|
255
|
-
state.runs = result.items || []; renderRuns(); $('run-page')
|
|
314
|
+
state.runs = result.items || []; renderRuns(); setI18nText($('run-page'), result.nextCursor ? 'nextPage' : 'end');
|
|
256
315
|
if (!state.selectedRun && state.runs[0]) await loadRunDetail(state.runs[0].runId);
|
|
257
316
|
else renderRunDetail();
|
|
258
317
|
} catch (error) { setStatus(error.message, true); }
|
|
259
318
|
}
|
|
260
319
|
|
|
261
|
-
async function loadEntries() { if (!state.workspace) return; try { const params = new URLSearchParams({ workspace: state.workspace }); if (state.kind !== 'all') params.set('kind', state.kind); if (state.tag) params.set('tag', state.tag); if (state.query) params.set('q', state.query); const result = await api('/api/entries?' + params); state.entries = result.entries; if (state.selected && !state.entries.some((entry) => entry.id === state.selected.id)) state.selected = null; renderEntries(); renderFilters(); if (!state.selected && state.entries[0]) await selectEntry(state.entries[0].id); else renderEditor();
|
|
320
|
+
async function loadEntries() { if (!state.workspace) return; try { const params = new URLSearchParams({ workspace: state.workspace }); if (state.kind !== 'all') params.set('kind', state.kind); if (state.tag) params.set('tag', state.tag); if (state.query) params.set('q', state.query); const result = await api('/api/entries?' + params); state.entries = result.entries; if (state.selected && !state.entries.some((entry) => entry.id === state.selected.id)) state.selected = null; renderEntries(); renderFilters(); if (!state.selected && state.entries[0]) await selectEntry(state.entries[0].id); else renderEditor(); setLocalizedCountStatus('displayedCount', result.entries.length); } catch (error) { setStatus(error.message, true); } }
|
|
262
321
|
async function loadTags() { if (!state.workspace) return; try { const result = await api('/api/tags?workspace=' + encodeURIComponent(state.workspace)); state.tags = result.tags; renderFilters(); } catch (error) { setStatus(error.message, true); } }
|
|
263
|
-
async function loadWorkspaces() { try { const result = await api('/api/workspaces'); const select = $('workspace'); select.replaceChildren(...result.workspaces.map((item) => { const option = document.createElement('option'); option.value = item.workspace; option.textContent = (item.displayName || item.workspace) + ' (' + item.count + ')'; return option; })); if (!state.workspace && result.workspaces[0]) state.workspace = result.workspaces[0].workspace; select.value = state.workspace; if (state.workspace) { await loadTags(); await loadEntries(); await loadRuns(); } else
|
|
322
|
+
async function loadWorkspaces() { try { const result = await api('/api/workspaces'); const select = $('workspace'); select.replaceChildren(...result.workspaces.map((item) => { const option = document.createElement('option'); option.value = item.workspace; option.textContent = (item.displayName || item.workspace) + ' (' + item.count + ')'; return option; })); if (!state.workspace && result.workspaces[0]) state.workspace = result.workspaces[0].workspace; select.value = state.workspace; if (state.workspace) { await loadTags(); await loadEntries(); await loadRuns(); } else setLocalizedStatus('noWorkspace', {}, true); } catch (error) { setStatus(error.message, true); } }
|
|
323
|
+
$('locale').replaceChildren(...i18n.locales.map((locale) => { const option = document.createElement('option'); option.value = locale; option.lang = locale; option.textContent = i18n.localeLabels[locale]; return option; }));
|
|
324
|
+
$('locale').addEventListener('change', (event) => {
|
|
325
|
+
state.locale = normalizeLocale(event.target.value) || i18n.defaultLocale;
|
|
326
|
+
try { localStorage.setItem(localeStorageKey, state.locale); } catch {}
|
|
327
|
+
applyTranslations(); renderFilters(); renderEntries(); renderRuns(); renderRunDetail(); updateEditorState();
|
|
328
|
+
});
|
|
264
329
|
$('workspace').addEventListener('change', (event) => { state.workspace = event.target.value; state.selected = null; state.selectedRun = null; state.runs = []; state.tag = ''; loadTags().then(loadEntries).then(loadRuns); });
|
|
265
330
|
$('refresh').addEventListener('click', () => loadWorkspaces());
|
|
266
331
|
let searchTimer; $('search').addEventListener('input', (event) => { clearTimeout(searchTimer); state.query = event.target.value.trim(); searchTimer = setTimeout(() => loadEntries(), 180); });
|
|
332
|
+
applyTranslations();
|
|
267
333
|
loadWorkspaces();
|
|
268
334
|
</script>
|
|
269
335
|
</body>
|
package/dist/web/ui.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ui.js","sourceRoot":"","sources":["../../src/web/ui.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,QAAQ,GAAG,MAAM,CAAC,GAAG,CAAA
|
|
1
|
+
{"version":3,"file":"ui.js","sourceRoot":"","sources":["../../src/web/ui.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAE7F,MAAM,eAAe,GAAG,IAAI,CAAC,SAAS,CAAC;IACrC,aAAa,EAAE,kBAAkB;IACjC,YAAY,EAAE,iBAAiB;IAC/B,OAAO,EAAE,WAAW;IACpB,QAAQ,EAAE,YAAY;CACvB,CAAC;KACC,UAAU,CAAC,GAAG,EAAE,SAAS,CAAC;KAC1B,UAAU,CAAC,GAAG,EAAE,SAAS,CAAC;KAC1B,UAAU,CAAC,GAAG,EAAE,SAAS,CAAC;KAC1B,UAAU,CAAC,QAAQ,EAAE,SAAS,CAAC;KAC/B,UAAU,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;AAEnC,MAAM,CAAC,MAAM,QAAQ,GAAG,MAAM,CAAC,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;mBA8Gf,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAqN1B,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@askdkc/kiokuko",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"description": "Model-agnostic external memory for AI coding agents",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"kiokuko": "dist/bin/kiokuko.js"
|
|
8
8
|
},
|
|
9
9
|
"engines": {
|
|
10
|
-
"node": ">=
|
|
10
|
+
"node": ">=24.0.0"
|
|
11
11
|
},
|
|
12
12
|
"publishConfig": {
|
|
13
13
|
"access": "public"
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"zod": "^4.4.3"
|
|
39
39
|
},
|
|
40
40
|
"devDependencies": {
|
|
41
|
-
"@types/node": "^
|
|
41
|
+
"@types/node": "^24.0.0",
|
|
42
42
|
"tsx": "^4.20.3",
|
|
43
43
|
"typescript": "^5.9.2"
|
|
44
44
|
}
|