@unson/brainbase-mcp 0.39.0 → 0.40.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@unson/brainbase-mcp",
3
- "version": "0.39.0",
3
+ "version": "0.40.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",
@@ -481,5 +481,5 @@
481
481
  "engines": {
482
482
  "node": ">=20"
483
483
  },
484
- "gitHead": "f6631b4f6a088162dbd4a3d1fb974de3e599dc85"
484
+ "gitHead": "05c940b491a191339b9bc59ffb123579220714a3"
485
485
  }
@@ -834,6 +834,11 @@ export function buildCorrectionRequest(form) {
834
834
  const name = String(form.draft.name ?? '').trim();
835
835
  if (!name) return { ok: false, message: GRAPH_CORRECTION_ERROR_MESSAGES.correction_name_required };
836
836
  const entity = { type, name };
837
+ if (form.projects.length > 0) {
838
+ const projectCode = String(form.draft.projectCode ?? '');
839
+ if (!form.projects.some((project) => project.code === projectCode)) return { ok: false, message: '人を加えるプロジェクトを選んでください。' };
840
+ entity.projectCode = projectCode;
841
+ }
837
842
  const aliases = splitAliases(form.draft.aliases ?? '').filter((alias) => alias !== name);
838
843
  const summary = String(form.draft.summary ?? '').trim();
839
844
  if (aliases.length > 0) entity.aliases = aliases;
@@ -894,7 +899,11 @@ function readBackFields(form, payload) {
894
899
 
895
900
  /** What a new record is, as rows shown before its values. */
896
901
  function createdEntityRows(form, record) {
897
- return [['種類', form.typeNames[record?.type] ?? typeLabel(record?.type)]];
902
+ const project = form.projects.find((candidate) => candidate.code === form.draft.projectCode);
903
+ return [
904
+ ['種類', form.typeNames[record?.type] ?? typeLabel(record?.type)],
905
+ ...(project ? [['関わるプロジェクト', project.name ?? project.code]] : []),
906
+ ];
898
907
  }
899
908
 
900
909
  /** What a new relation connects, as rows shown before its values. */
@@ -1059,10 +1068,36 @@ function renderCreateEntityFields(doc, form, callbacks) {
1059
1068
  onChange: (value) => callbacks.onInput('type', value),
1060
1069
  }));
1061
1070
  }
1071
+ if (form.projects.length > 0) {
1072
+ group.append(selectControl(doc, {
1073
+ id: `${form.formId}-project`,
1074
+ name: 'projectCode',
1075
+ label: '関わるプロジェクト',
1076
+ value: String(form.draft.projectCode ?? ''),
1077
+ options: [
1078
+ { value: '', label: 'プロジェクトを選んでください' },
1079
+ ...form.projects.map((project) => ({ value: project.code, label: project.name ?? project.code })),
1080
+ ],
1081
+ onChange: (value) => callbacks.onInput('projectCode', value),
1082
+ }));
1083
+ group.append(notice(doc, 'muted', '人はこのプロジェクトの関係者として記録されます。会社への所属は、作った後に加えてください。'));
1084
+ }
1062
1085
  for (const field of form.fields) group.append(fieldControl(doc, form, field, callbacks));
1063
1086
  return group;
1064
1087
  }
1065
1088
 
1089
+ /** The projects a host offers for a new person, as `{ code, name }`, without duplicates. */
1090
+ function creationProjects(projects) {
1091
+ const seen = new Set();
1092
+ return (Array.isArray(projects) ? projects : []).flatMap((project) => {
1093
+ const code = typeof project?.code === 'string' ? project.code.trim() : '';
1094
+ if (!code || seen.has(code)) return [];
1095
+ seen.add(code);
1096
+ const name = typeof project.name === 'string' && project.name.trim() ? project.name.trim() : null;
1097
+ return [{ code, name }];
1098
+ });
1099
+ }
1100
+
1066
1101
  /**
1067
1102
  * The correction panel. `form` is the state held by `createGraphCorrection`;
1068
1103
  * callbacks are the controller's handlers.
@@ -1360,7 +1395,7 @@ export function createGraphCorrection({ client, rerender, onSaved, onConflict, n
1360
1395
  * `person` and `org` are created; others are dropped), `typeNames` their
1361
1396
  * labels. Null outside the scope.
1362
1397
  */
1363
- openCreateEntity({ types = ['person', 'org'], type, typeNames = {}, title = '記録を加える', subject } = {}) {
1398
+ openCreateEntity({ types = ['person', 'org'], type, typeNames = {}, title = '記録を加える', subject, projects = [] } = {}) {
1364
1399
  const entityTypes = allowed.createEntities
1365
1400
  ? types.filter((candidate) => (candidate === 'person' || candidate === 'org') && allowed.entity(candidate))
1366
1401
  : [];
@@ -1372,8 +1407,9 @@ export function createGraphCorrection({ client, rerender, onSaved, onConflict, n
1372
1407
  entityTypes,
1373
1408
  typeNames,
1374
1409
  fields,
1410
+ projects: entityTypes.length === 1 && entityTypes[0] === 'person' ? creationProjects(projects) : [],
1375
1411
  original: Object.fromEntries(fields.map((field) => [field, ''])),
1376
- draft: { type: entityTypes.includes(type) ? type : entityTypes[0], name: '', aliases: '', summary: '', validFrom: '' },
1412
+ draft: { type: entityTypes.includes(type) ? type : entityTypes[0], name: '', aliases: '', summary: '', validFrom: '', projectCode: '' },
1377
1413
  });
1378
1414
  redraw();
1379
1415
  return form;
@@ -127,6 +127,8 @@ export function normalizePeopleAndCompanies(result) {
127
127
  && isIdList(person.companyIds) && Number.isInteger(person.projectCount) && Number.isInteger(person.accountableProjectCount)
128
128
  && (person.orgNote === undefined || isTextOrNull(person.orgNote)))) return INVALID;
129
129
  if (!Array.isArray(payload.companies) || !payload.companies.every(isCompanySummary)) return INVALID;
130
+ if (payload.personProjects !== undefined && !(Array.isArray(payload.personProjects) && payload.personProjects.every((project) => isRecord(project)
131
+ && typeof project.code === 'string' && project.code.trim() && isTextOrNull(project.name)))) return INVALID;
130
132
  if (payload.people.length === 0 && payload.companies.length === 0 && payload.absenceConfirmed !== true) return { state: 'unknown' };
131
133
  return { state: 'ok', payload };
132
134
  }
@@ -189,6 +191,9 @@ export function personOrgNote(person, ownCompanyId) {
189
191
  * With writes allowed, only these (see `graphCorrectionScope`): `createEntities: false` withholds
190
192
  * 人を加える・会社を加える, `createEdges: false` withholds 所属を付ける・所属する人を加える, `edges: false`
191
193
  * withholds 所属を終える, and `entityTypes` limits the kinds that may be created.
194
+ * A host that places people in projects lists the projects a new person may join as
195
+ * `personProjects` (`[{ code, name }]`) in its read; 人を加える then requires one and sends it as
196
+ * `entity.projectCode`. Without that list (the local host) no project is asked or sent.
192
197
  * @param {string} [options.token] Launch token sent with a correction.
193
198
  * @param {string} [options.tokenHeader] Header name for the token.
194
199
  */
@@ -297,11 +302,14 @@ export function createPeopleAndCompaniesView({
297
302
  }
298
303
 
299
304
  function openCreateEntity(type) {
305
+ // A host that places people in projects lists the ones a new person may join (`personProjects`).
306
+ const projects = type === 'person' && state.list.state === 'ok' ? state.list.payload.personProjects ?? [] : [];
300
307
  correction.openCreateEntity({
301
308
  types: [type],
302
309
  typeNames: { person: '人', org: '会社' },
303
310
  title: type === 'org' ? '会社を加える' : '人を加える',
304
311
  subject: type === 'org' ? 'Graphに会社の記録を作ります。' : 'Graphに人の記録を作ります。',
312
+ projects,
305
313
  });
306
314
  }
307
315