@unson/brainbase-mcp 0.29.0 → 0.31.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +1 -1
- package/dist/judgment-host.d.ts +2 -2
- package/dist/judgment-host.js +3 -29
- package/dist/judgment-resolution-contract.d.ts +14 -0
- package/dist/judgment-resolution-contract.js +53 -0
- package/package.json +6 -2
- package/ui/local-web-shell.js +12 -10
- package/ui/world/world-view.js +16 -8
package/dist/cli.js
CHANGED
|
@@ -1071,7 +1071,7 @@ async function webServe(parsed, io, command) {
|
|
|
1071
1071
|
const origin = `http://127.0.0.1:${actualPort}`;
|
|
1072
1072
|
write(io, [
|
|
1073
1073
|
`Brainbase: ${origin}/`,
|
|
1074
|
-
`-
|
|
1074
|
+
`- 判断の履歴: ${origin}/#value-proofs`,
|
|
1075
1075
|
`- 目的と現状: ${origin}/#objectives`,
|
|
1076
1076
|
`- プロジェクトと関係者: ${origin}/#projects`,
|
|
1077
1077
|
`- 情報と関係: ${origin}/#graph`,
|
package/dist/judgment-host.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type JudgmentAutonomyEvaluation, type JudgmentAutonomyResolver } from './judgment-autonomy.js';
|
|
2
|
+
import { canonicalJson } from './judgment-resolution-contract.js';
|
|
2
3
|
type Environment = Record<string, string | undefined>;
|
|
3
4
|
export interface ConversationMessage {
|
|
4
5
|
sequence?: number;
|
|
@@ -204,7 +205,7 @@ export interface JudgmentStopBlock {
|
|
|
204
205
|
block_kind?: 'autonomy_continue' | 'audit_repair';
|
|
205
206
|
reason: string;
|
|
206
207
|
}
|
|
207
|
-
export
|
|
208
|
+
export { canonicalJson };
|
|
208
209
|
export declare function buildJudgmentRequest(payload: JudgmentHookPayload, { env, trustedConversationMessages }?: {
|
|
209
210
|
env?: Environment;
|
|
210
211
|
trustedConversationMessages?: ConversationMessage[];
|
|
@@ -223,4 +224,3 @@ export declare function blockedJudgmentOutput(reason: string): {
|
|
|
223
224
|
suppressOutput: false;
|
|
224
225
|
stopReason: string;
|
|
225
226
|
};
|
|
226
|
-
export {};
|
package/dist/judgment-host.js
CHANGED
|
@@ -3,6 +3,7 @@ import { closeSync, constants as fsConstants, fsyncSync, linkSync, mkdirSync, op
|
|
|
3
3
|
import { homedir } from 'node:os';
|
|
4
4
|
import { basename, delimiter, dirname, isAbsolute, join, relative, resolve, sep } from 'node:path';
|
|
5
5
|
import { evaluateJudgmentAutonomy, renderJudgmentAutonomyContinuation } from './judgment-autonomy.js';
|
|
6
|
+
import { canonicalJson } from './judgment-resolution-contract.js';
|
|
6
7
|
const RUNTIME_VERSION = 'portable-judgment-runtime-1.0.0';
|
|
7
8
|
const ZERO_CALL_DISPLAY_LINE = '📚 Brainbase未参照: 必須参照なし・実呼び出し0回 ✓';
|
|
8
9
|
const PORTABLE_KNOWLEDGE_TOOLS = {
|
|
@@ -62,35 +63,8 @@ const DOMAIN_TERMS = [
|
|
|
62
63
|
];
|
|
63
64
|
const FOLLOW_UP_TERMS = ['that', 'it', 'continue', 'do that', 'それ', 'その形', 'これ', 'こちら', '続けて', 'もう一度', 'では', 'それでいい', 'そうして'];
|
|
64
65
|
const AUTHORITY_INTENTS = new Set(['implement', 'operate']);
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
return JSON.stringify(value);
|
|
68
|
-
if (typeof value === 'number') {
|
|
69
|
-
if (!Number.isFinite(value))
|
|
70
|
-
throw new TypeError('canonical JSON only supports finite numbers');
|
|
71
|
-
return JSON.stringify(value);
|
|
72
|
-
}
|
|
73
|
-
if (Array.isArray(value))
|
|
74
|
-
return `[${value.map((entry) => canonicalJson(entry)).join(',')}]`;
|
|
75
|
-
if (value && typeof value === 'object') {
|
|
76
|
-
return `{${Object.keys(value).sort(compareCodePoints).map((key) => {
|
|
77
|
-
const entry = value[key];
|
|
78
|
-
if (entry === undefined)
|
|
79
|
-
throw new TypeError('canonical JSON does not support undefined');
|
|
80
|
-
return `${JSON.stringify(key)}:${canonicalJson(entry)}`;
|
|
81
|
-
}).join(',')}}`;
|
|
82
|
-
}
|
|
83
|
-
throw new TypeError(`canonical JSON does not support ${typeof value}`);
|
|
84
|
-
}
|
|
85
|
-
function compareCodePoints(left, right) {
|
|
86
|
-
const a = Array.from(left, (value) => value.codePointAt(0));
|
|
87
|
-
const b = Array.from(right, (value) => value.codePointAt(0));
|
|
88
|
-
for (let index = 0; index < Math.min(a.length, b.length); index += 1) {
|
|
89
|
-
if (a[index] !== b[index])
|
|
90
|
-
return a[index] - b[index];
|
|
91
|
-
}
|
|
92
|
-
return a.length - b.length;
|
|
93
|
-
}
|
|
66
|
+
// canonicalJson is the shared judgment resolution contract; re-exported so existing importers keep working.
|
|
67
|
+
export { canonicalJson };
|
|
94
68
|
function sha256(value) {
|
|
95
69
|
return createHash('sha256').update(value).digest('hex');
|
|
96
70
|
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export declare function canonicalJson(value: unknown): string;
|
|
2
|
+
export declare function sha256Hex(value: string): string;
|
|
3
|
+
export declare function computeRequestDigest(rawInput: unknown): string;
|
|
4
|
+
export declare class JudgmentResolutionError extends Error {
|
|
5
|
+
readonly code: string;
|
|
6
|
+
readonly status: number;
|
|
7
|
+
constructor(code: string, message: string, status?: number);
|
|
8
|
+
toJSON(): {
|
|
9
|
+
name: string;
|
|
10
|
+
code: string;
|
|
11
|
+
status: number;
|
|
12
|
+
message: string;
|
|
13
|
+
};
|
|
14
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
// Shared contract between the judgment Host and the judgment resolver.
|
|
3
|
+
// The resolver's HTTP mount and its service must throw and recognize the
|
|
4
|
+
// same error class, and both sides must produce identical canonical bytes,
|
|
5
|
+
// so these live in one public module instead of being copied per caller.
|
|
6
|
+
function compareCodePoints(left, right) {
|
|
7
|
+
const a = Array.from(left, (value) => value.codePointAt(0));
|
|
8
|
+
const b = Array.from(right, (value) => value.codePointAt(0));
|
|
9
|
+
for (let index = 0; index < Math.min(a.length, b.length); index += 1) {
|
|
10
|
+
if (a[index] !== b[index])
|
|
11
|
+
return a[index] - b[index];
|
|
12
|
+
}
|
|
13
|
+
return a.length - b.length;
|
|
14
|
+
}
|
|
15
|
+
export function canonicalJson(value) {
|
|
16
|
+
if (value === null || typeof value === 'boolean' || typeof value === 'string')
|
|
17
|
+
return JSON.stringify(value);
|
|
18
|
+
if (typeof value === 'number') {
|
|
19
|
+
if (!Number.isFinite(value))
|
|
20
|
+
throw new TypeError('canonical JSON only supports finite numbers');
|
|
21
|
+
return JSON.stringify(value);
|
|
22
|
+
}
|
|
23
|
+
if (Array.isArray(value))
|
|
24
|
+
return `[${value.map((entry) => canonicalJson(entry)).join(',')}]`;
|
|
25
|
+
if (value && typeof value === 'object') {
|
|
26
|
+
return `{${Object.keys(value).sort(compareCodePoints).map((key) => {
|
|
27
|
+
const entry = value[key];
|
|
28
|
+
if (entry === undefined)
|
|
29
|
+
throw new TypeError('canonical JSON does not support undefined');
|
|
30
|
+
return `${JSON.stringify(key)}:${canonicalJson(entry)}`;
|
|
31
|
+
}).join(',')}}`;
|
|
32
|
+
}
|
|
33
|
+
throw new TypeError(`canonical JSON does not support ${typeof value}`);
|
|
34
|
+
}
|
|
35
|
+
export function sha256Hex(value) {
|
|
36
|
+
return createHash('sha256').update(value).digest('hex');
|
|
37
|
+
}
|
|
38
|
+
export function computeRequestDigest(rawInput) {
|
|
39
|
+
return sha256Hex(canonicalJson(rawInput));
|
|
40
|
+
}
|
|
41
|
+
export class JudgmentResolutionError extends Error {
|
|
42
|
+
code;
|
|
43
|
+
status;
|
|
44
|
+
constructor(code, message, status = 400) {
|
|
45
|
+
super(message);
|
|
46
|
+
this.name = 'JudgmentResolutionError';
|
|
47
|
+
this.code = code;
|
|
48
|
+
this.status = status;
|
|
49
|
+
}
|
|
50
|
+
toJSON() {
|
|
51
|
+
return { name: this.name, code: this.code, status: this.status, message: this.message };
|
|
52
|
+
}
|
|
53
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@unson/brainbase-mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.31.0",
|
|
4
4
|
"description": "Local-first Brainbase judgment OS that lets supported AI agents reuse a user's approved goals, priorities, decisions, and judgment criteria.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -183,6 +183,10 @@
|
|
|
183
183
|
"types": "./dist/knowledge-resolution-service.d.ts",
|
|
184
184
|
"import": "./dist/knowledge-resolution-service.js"
|
|
185
185
|
},
|
|
186
|
+
"./judgment-resolution-contract": {
|
|
187
|
+
"types": "./dist/judgment-resolution-contract.d.ts",
|
|
188
|
+
"import": "./dist/judgment-resolution-contract.js"
|
|
189
|
+
},
|
|
186
190
|
"./canonical-document-writer": {
|
|
187
191
|
"types": "./dist/canonical-document-writer.d.ts",
|
|
188
192
|
"import": "./dist/canonical-document-writer.js"
|
|
@@ -451,5 +455,5 @@
|
|
|
451
455
|
"engines": {
|
|
452
456
|
"node": ">=20"
|
|
453
457
|
},
|
|
454
|
-
"gitHead": "
|
|
458
|
+
"gitHead": "aeb8467e65eda4223dd092cc43d69b4ebd040f42"
|
|
455
459
|
}
|
package/ui/local-web-shell.js
CHANGED
|
@@ -42,7 +42,7 @@ const UNREADABLE_LABELS = Object.freeze({
|
|
|
42
42
|
|
|
43
43
|
// Stroke icons from the organization edition's sprite (apps/web/public/index.html).
|
|
44
44
|
const NAV_ICON_PATHS = Object.freeze({
|
|
45
|
-
|
|
45
|
+
'value-proofs': ['M5 20V10m7 10V4m7 16v-7'],
|
|
46
46
|
objectives: ['M12 4 3 20h18z', 'M12 9v5m0 3h.01'],
|
|
47
47
|
projects: ['M3 6.5h7l2 2h9v10H3z', 'M3 6.5v-2h7l2 2'],
|
|
48
48
|
graph: ['M10 13a5 5 0 0 0 7.5.5l2-2a5 5 0 0 0-7-7l-1.2 1.2', 'M14 11a5 5 0 0 0-7.5-.5l-2 2a5 5 0 0 0 7 7l1.2-1.2'],
|
|
@@ -53,7 +53,7 @@ const NAV_ICON_PATHS = Object.freeze({
|
|
|
53
53
|
const SVG_NS = 'http://www.w3.org/2000/svg';
|
|
54
54
|
|
|
55
55
|
function makeIcon(doc, id) {
|
|
56
|
-
const paths = NAV_ICON_PATHS[id] ?? NAV_ICON_PATHS
|
|
56
|
+
const paths = NAV_ICON_PATHS[id] ?? NAV_ICON_PATHS['value-proofs'];
|
|
57
57
|
const create = (tag) => (typeof doc.createElementNS === 'function' ? doc.createElementNS(SVG_NS, tag) : doc.createElement(tag));
|
|
58
58
|
const svg = create('svg');
|
|
59
59
|
svg.setAttribute('class', 'bb-shell-icon');
|
|
@@ -90,13 +90,15 @@ function isRecord(value) {
|
|
|
90
90
|
export function parseLocalWebTarget(target) {
|
|
91
91
|
const raw = typeof target === 'string' ? target.replace(/^#/, '') : '';
|
|
92
92
|
const separator = raw.indexOf('?');
|
|
93
|
-
const
|
|
94
|
-
if (!
|
|
93
|
+
const requested = separator < 0 ? raw : raw.slice(0, separator);
|
|
94
|
+
if (!requested) return { screenId: null, entityId: null };
|
|
95
|
+
// 判断の履歴 was called 今日 (`#today`) until 2026-10-11; old links still open it.
|
|
96
|
+
const screenId = requested === 'today' ? 'value-proofs' : requested;
|
|
95
97
|
const query = separator < 0 ? '' : raw.slice(separator + 1);
|
|
96
98
|
const params = new URLSearchParams(query);
|
|
97
|
-
//
|
|
99
|
+
// 判断の履歴 accepts one judgment to open (`decision` = decision_attempt_id) and
|
|
98
100
|
// プロジェクトと関係者 one project (`project` = Graph project id); other screens ignore them.
|
|
99
|
-
const decisionId = screenId === '
|
|
101
|
+
const decisionId = screenId === 'value-proofs' ? params.get('decision')?.trim() || null : null;
|
|
100
102
|
const projectId = screenId === 'projects' ? params.get('project')?.trim() || null : null;
|
|
101
103
|
return {
|
|
102
104
|
screenId,
|
|
@@ -250,7 +252,7 @@ function mountGraphScreen(screenId, createView) {
|
|
|
250
252
|
}
|
|
251
253
|
|
|
252
254
|
export const LOCAL_WEB_SCREENS = Object.freeze([
|
|
253
|
-
Object.freeze({ id: '
|
|
255
|
+
Object.freeze({ id: 'value-proofs', label: '判断の履歴', usesGraph: false, rail: true, source: '判断の記録', mount: mountToday }),
|
|
254
256
|
Object.freeze({ id: 'minutes', label: '議事録', usesGraph: false, rail: true, source: '正本の議事録', mount: mountMeetingMinutes }),
|
|
255
257
|
Object.freeze({ id: 'objectives', label: '目的と現状', usesGraph: true, rail: true, source: '手元のGraph', mount: mountObjectives }),
|
|
256
258
|
Object.freeze({ id: 'projects', label: 'プロジェクトと関係者', usesGraph: true, rail: true, source: '手元のGraph', mount: mountGraphScreen('projects', createGraphProjectsView) }),
|
|
@@ -419,7 +421,7 @@ export function createLocalWebShell({
|
|
|
419
421
|
if (mounted.has(screen.id)) {
|
|
420
422
|
const view = mounted.get(screen.id);
|
|
421
423
|
if (entityId && screen.id === 'graph' && typeof view?.openEntity === 'function') void view.openEntity(entityId);
|
|
422
|
-
if (entityId && screen.id === '
|
|
424
|
+
if (entityId && screen.id === 'value-proofs' && typeof view?.openDecision === 'function') view.openDecision(entityId);
|
|
423
425
|
if (entityId && screen.id === 'projects' && typeof view?.openProject === 'function') void view.openProject(entityId);
|
|
424
426
|
return;
|
|
425
427
|
}
|
|
@@ -434,7 +436,7 @@ export function createLocalWebShell({
|
|
|
434
436
|
const page = Object.freeze({ crumbs: Object.freeze(['あなたのBrainbase', screen.label]), source: screen.source ?? null });
|
|
435
437
|
const view = screen.mount(slot, Object.freeze({ ...context, rail, page, initialEntityId: entityId })) ?? true;
|
|
436
438
|
mounted.set(screen.id, view);
|
|
437
|
-
if (entityId && screen.id === '
|
|
439
|
+
if (entityId && screen.id === 'value-proofs' && typeof view?.openDecision === 'function') view.openDecision(entityId);
|
|
438
440
|
if (entityId && screen.id === 'projects' && typeof view?.openProject === 'function') void view.openProject(entityId);
|
|
439
441
|
updateRail();
|
|
440
442
|
}
|
|
@@ -447,7 +449,7 @@ export function createLocalWebShell({
|
|
|
447
449
|
const parsed = parseLocalWebTarget(target);
|
|
448
450
|
const screen = screens.find((candidate) => candidate.id === parsed.screenId) ?? screens[0];
|
|
449
451
|
pendingEntityIds.set(screen.id, screen.id === 'graph' ? parsed.entityId
|
|
450
|
-
: screen.id === '
|
|
452
|
+
: screen.id === 'value-proofs' ? parsed.decisionId ?? null
|
|
451
453
|
: screen.id === 'projects' ? parsed.projectId ?? null : null);
|
|
452
454
|
active = screen.id;
|
|
453
455
|
for (const [screenId, slot] of slots) slot.hidden = screenId !== screen.id;
|
package/ui/world/world-view.js
CHANGED
|
@@ -1450,6 +1450,9 @@ function addressSelection() {
|
|
|
1450
1450
|
* organization web passes its own route.
|
|
1451
1451
|
* @param {(site: { task_id: string }) => string | null} [options.taskHref] Where a work site's task opens in the
|
|
1452
1452
|
* host's task screen (to check or correct it). Without one the rail says it cannot be corrected here.
|
|
1453
|
+
* @param {(decisionAttemptId: string | null) => string} [options.judgmentHref] Where a judgment (or, with null,
|
|
1454
|
+
* the list) opens in the host's 判断の履歴. The local web opens `#value-proofs?decision=<id>`; an organization
|
|
1455
|
+
* web passes its own route.
|
|
1453
1456
|
* @param {'standard' | 'canvas'} [options.presentation] Canvas owns its accessible overlays and ignores the host rail.
|
|
1454
1457
|
* @param {{ read(): { business: string | null, site: string | null }, write(selection): void }} [options.selection]
|
|
1455
1458
|
* @param {(business: object) => (BusinessExitsAnswer | Promise<BusinessExitsAnswer>)} [options.businessExits] The tools
|
|
@@ -1460,7 +1463,12 @@ function addressSelection() {
|
|
|
1460
1463
|
* others are dropped and counted. Without it the world is drawn exactly as before.
|
|
1461
1464
|
* @typedef {{ status: string, read_at?: string, reason?: string, exits: object[] }} BusinessExitsAnswer
|
|
1462
1465
|
*/
|
|
1463
|
-
|
|
1466
|
+
/** 判断の履歴 in the local web (it was 今日, `#today`, until 2026-10-11; the shell still opens old links). */
|
|
1467
|
+
function defaultJudgmentHref(decisionAttemptId) {
|
|
1468
|
+
return decisionAttemptId ? `#value-proofs?decision=${encodeURIComponent(decisionAttemptId)}` : '#value-proofs';
|
|
1469
|
+
}
|
|
1470
|
+
|
|
1471
|
+
export function createWorldView({ root, rail, page, presentation = 'standard', document: explicitDocument, fetcher, projectHref = (project) => `#projects?project=${encodeURIComponent(project.id)}`, taskHref = null, judgmentHref = defaultJudgmentHref, selection = addressSelection(), businessExits = null }) {
|
|
1464
1472
|
const exitsEnabled = typeof businessExits === 'function';
|
|
1465
1473
|
const doc = explicitDocument ?? globalThis.document;
|
|
1466
1474
|
const reducedMotion = Boolean(globalThis.matchMedia?.('(prefers-reduced-motion: reduce)').matches);
|
|
@@ -1634,9 +1642,9 @@ export function createWorldView({ root, rail, page, presentation = 'standard', d
|
|
|
1634
1642
|
return `${textValue}${suffix}`;
|
|
1635
1643
|
}
|
|
1636
1644
|
|
|
1637
|
-
/** Descends to the same judgment in
|
|
1645
|
+
/** Descends to the same judgment in the host's 判断の履歴. */
|
|
1638
1646
|
function decisionLink(decisionAttemptId) {
|
|
1639
|
-
const link = el(doc, 'a', { className: 'bb-world-rail-link', text: '
|
|
1647
|
+
const link = el(doc, 'a', { className: 'bb-world-rail-link', text: '「判断の履歴」でこの判断を開く', attrs: { href: judgmentHref(decisionAttemptId) } });
|
|
1640
1648
|
return link;
|
|
1641
1649
|
}
|
|
1642
1650
|
|
|
@@ -2242,7 +2250,7 @@ export function createWorldView({ root, rail, page, presentation = 'standard', d
|
|
|
2242
2250
|
showRail([
|
|
2243
2251
|
workspaceRailHead(doc, { kicker: `${business.name} の判断所`, title: `判断 ${data.judgments.length}件`, lead: business.purpose ?? undefined }),
|
|
2244
2252
|
cityJudgmentBlock(business),
|
|
2245
|
-
workspaceRailBlock(doc, { title: '詳しく見る', content: workspaceButton(doc, { text: '
|
|
2253
|
+
workspaceRailBlock(doc, { title: '詳しく見る', content: workspaceButton(doc, { text: '「判断の履歴」で開く', variant: 'primary', onClick: () => { globalThis.location.hash = judgmentHref(null); } }) }),
|
|
2246
2254
|
]);
|
|
2247
2255
|
return;
|
|
2248
2256
|
}
|
|
@@ -2273,7 +2281,7 @@ export function createWorldView({ root, rail, page, presentation = 'standard', d
|
|
|
2273
2281
|
blocks.push(workspaceRailBlock(doc, { title: '判断(新しい順)', content: items.length ? ul : { text: '判断はありません' } }));
|
|
2274
2282
|
blocks.push(workspaceRailBlock(doc, {
|
|
2275
2283
|
title: '詳しく見る',
|
|
2276
|
-
content: workspaceButton(doc, { text: '
|
|
2284
|
+
content: workspaceButton(doc, { text: '「判断の履歴」で開く', variant: 'primary', onClick: () => { globalThis.location.hash = judgmentHref(null); } }),
|
|
2277
2285
|
}));
|
|
2278
2286
|
showRail(blocks);
|
|
2279
2287
|
return;
|
|
@@ -2295,7 +2303,7 @@ export function createWorldView({ root, rail, page, presentation = 'standard', d
|
|
|
2295
2303
|
if (withheld) {
|
|
2296
2304
|
blocks.push(workspaceRailBlock(doc, {
|
|
2297
2305
|
title: `この世界に出していない判断(${withheld}件)`,
|
|
2298
|
-
content: { text: '
|
|
2306
|
+
content: { text: 'この組織の事業で作業したと確かめられない判断です。ほかの会社の仕事が混ざるため、内容も作業場所も出しません。「判断の履歴」では見られます。' },
|
|
2299
2307
|
}));
|
|
2300
2308
|
}
|
|
2301
2309
|
showRail(blocks);
|
|
@@ -2368,11 +2376,11 @@ export function createWorldView({ root, rail, page, presentation = 'standard', d
|
|
|
2368
2376
|
const waiting = [...proofs.values()].filter(isWaiting).length;
|
|
2369
2377
|
const places = placesResult.ok && placesResult.data?.status === 'available' ? placesResult.data.places : null;
|
|
2370
2378
|
if (places) {
|
|
2371
|
-
// Only judgments the home lists are placed, so the world and
|
|
2379
|
+
// Only judgments the home lists are placed, so the world and 判断の履歴 count the same judgments.
|
|
2372
2380
|
const known = places.filter((place) => proofs.has(place.decision_attempt_id)).map((place) => ({ ...place, item: proofs.get(place.decision_attempt_id) }));
|
|
2373
2381
|
placement = groupJudgmentPlaces(known, businesses);
|
|
2374
2382
|
const placed = known.length - placement.unplaced.length;
|
|
2375
|
-
const kept = withheld ? `この組織の事業で作業したと確かめられない判断${withheld}
|
|
2383
|
+
const kept = withheld ? `この組織の事業で作業したと確かめられない判断${withheld}件は、この世界には出していません(「判断の履歴」で見られます)。` : '';
|
|
2376
2384
|
note('判断', `${home.delegation_map.judged}件のうち${placed}件を作業した事業の判断所に、${placement.unplaced.length}件は事業が分からないため広場に。${kept}今あなたを待っている判断${waiting}件${waiting ? '(光の柱)' : ''}。`, waiting ? 'attention' : 'info', waiting ? `あなたを待っている判断 ${waiting}件` : null);
|
|
2377
2385
|
} else {
|
|
2378
2386
|
note('判断', `${home.delegation_map.judged}件。作業した場所を読めないため、事業には置かず広場の種類別だけで描いています(${placesResult.ok ? placesResult.data?.reason ?? '理由不明' : placesResult.error})。今あなたを待っている判断${waiting}件。`, 'warning', '判断の作業場所:読めない');
|