@ai-matrx/associations 0.10.7 → 0.11.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/CHANGELOG.md +20 -0
- package/dist/{CommentThread-DobuYuwz.d.cts → CommentThread-ZWiJVDpI.d.cts} +57 -21
- package/dist/{CommentThread-DobuYuwz.d.ts → CommentThread-ZWiJVDpI.d.ts} +57 -21
- package/dist/index.cjs +4 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +18 -1
- package/dist/index.d.ts +18 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/react/index.cjs +135 -38
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.d.cts +2 -2
- package/dist/react/index.d.ts +2 -2
- package/dist/react/index.js +135 -38
- package/dist/react/index.js.map +1 -1
- package/dist/react/lazy/index.d.cts +1 -1
- package/dist/react/lazy/index.d.ts +1 -1
- package/package.json +2 -2
package/dist/react/index.cjs
CHANGED
|
@@ -46,6 +46,7 @@ __export(react_exports, {
|
|
|
46
46
|
UnresolvedRef: () => UnresolvedRef,
|
|
47
47
|
attachedKey: () => attachedKey,
|
|
48
48
|
buildCommentTree: () => buildCommentTree,
|
|
49
|
+
containerLinksArgs: () => containerLinksArgs,
|
|
49
50
|
getContentRoleMeta: () => getContentRoleMeta,
|
|
50
51
|
lazyPickerOverride: () => lazyPickerOverride,
|
|
51
52
|
lazyWindowShell: () => lazyWindowShell,
|
|
@@ -1254,6 +1255,73 @@ var useEntityRelationships = useAssociations;
|
|
|
1254
1255
|
|
|
1255
1256
|
// src/react/hooks/useContainerLinks.ts
|
|
1256
1257
|
var import_react3 = require("react");
|
|
1258
|
+
|
|
1259
|
+
// src/edges.ts
|
|
1260
|
+
var ASSOCIATION_TARGET_TYPES = [
|
|
1261
|
+
"organization",
|
|
1262
|
+
// an org — the top-level container resources attach into
|
|
1263
|
+
"scope",
|
|
1264
|
+
"scope_type",
|
|
1265
|
+
"project",
|
|
1266
|
+
"task",
|
|
1267
|
+
"context_item",
|
|
1268
|
+
"thread",
|
|
1269
|
+
"war_room",
|
|
1270
|
+
"category",
|
|
1271
|
+
"conversation",
|
|
1272
|
+
// a chat conversation a working_document is attached to
|
|
1273
|
+
"fc_set",
|
|
1274
|
+
// a flashcard set (card→set membership)
|
|
1275
|
+
"fc_card",
|
|
1276
|
+
// a flashcard (card→card hierarchy, quiz→card)
|
|
1277
|
+
"study_media",
|
|
1278
|
+
// a study-media artifact (summary/mind_map) — converter lineage target
|
|
1279
|
+
"assessment",
|
|
1280
|
+
// a quiz / practice test — a converter lineage target + origin (assessment→artifact 'source')
|
|
1281
|
+
"note",
|
|
1282
|
+
// a note — the origin a converted study artifact links back to (artifact→note 'source' lineage, P4)
|
|
1283
|
+
"file",
|
|
1284
|
+
// a file (card→file media + source lineage)
|
|
1285
|
+
"quiz_session",
|
|
1286
|
+
// a quiz a card is used in
|
|
1287
|
+
"agent",
|
|
1288
|
+
// an orchestrator agent — the container an Orchestra's member agents attach into (role 'member'); an 'orchestra' self-edge marks the orchestrator
|
|
1289
|
+
"agent_term_list",
|
|
1290
|
+
// a term list — durable file attachments target its vocabulary resource
|
|
1291
|
+
"research_tag",
|
|
1292
|
+
// a research tag a source is filed under (rs_source_tag M2M collapsed into associations)
|
|
1293
|
+
"skill",
|
|
1294
|
+
// a skill — projects link to it (skill→project, role 'member'); code_files attach as resources (code_file→skill, role 'resource')
|
|
1295
|
+
"surface",
|
|
1296
|
+
// a UI surface — agents bind here (agent→surface); context menu reads via agent.menu_surface
|
|
1297
|
+
"plan_entity",
|
|
1298
|
+
// a Content Planning source/media citation — plan_node role edges (about/cites/embeds) target it
|
|
1299
|
+
"plan_node",
|
|
1300
|
+
// a planned page — research topics/tags attach here and follow realization into web_page
|
|
1301
|
+
"web_site",
|
|
1302
|
+
// a web.site — parties attach onto a site's roster (party→web_site role 'writes_for')
|
|
1303
|
+
"seo_topic",
|
|
1304
|
+
// a taxonomy topic — plan_node/plan_entity tag into it (role 'topic')
|
|
1305
|
+
"seo_keyword",
|
|
1306
|
+
// a keyword — plan_node attaches secondaries (role 'secondary_keyword'; the primary is an FK, never an edge)
|
|
1307
|
+
"web_page",
|
|
1308
|
+
// a canonical page — the page workspace attaches notes/tasks/files/keywords onto it (keyword edges: role 'primary'|'supporting')
|
|
1309
|
+
"web_screenshot",
|
|
1310
|
+
// a page capture — per-image attachments on the page workspace
|
|
1311
|
+
"party",
|
|
1312
|
+
// a CRM person/company (crm.party) — the record page attaches tasks/files/notes onto it
|
|
1313
|
+
"crm_outreach_list",
|
|
1314
|
+
// a CRM outreach list (a worked send/dial queue) — parties and resources attach into it
|
|
1315
|
+
"crm_deal",
|
|
1316
|
+
// a CRM deal (crm.deal) — people on it (role 'deal_contact'), tasks/files attach onto it
|
|
1317
|
+
"rulebook"
|
|
1318
|
+
// a Masterwork Rulebook — its Scout interviews attach here (conversation→rulebook, role 'interview')
|
|
1319
|
+
];
|
|
1320
|
+
function isAssociationTargetType(value) {
|
|
1321
|
+
return typeof value === "string" && ASSOCIATION_TARGET_TYPES.includes(value);
|
|
1322
|
+
}
|
|
1323
|
+
|
|
1324
|
+
// src/react/hooks/useContainerLinks.ts
|
|
1257
1325
|
function metadataRecord(metadata) {
|
|
1258
1326
|
if (metadata === null || typeof metadata !== "object" || Array.isArray(metadata)) {
|
|
1259
1327
|
return metadata == null ? {} : null;
|
|
@@ -1262,6 +1330,7 @@ function metadataRecord(metadata) {
|
|
|
1262
1330
|
}
|
|
1263
1331
|
function useContainerLinks(args) {
|
|
1264
1332
|
const { containerType, containerId, orgId } = args;
|
|
1333
|
+
const outgoing = args.direction === "outgoing";
|
|
1265
1334
|
const store = useAssociationsStore();
|
|
1266
1335
|
const {
|
|
1267
1336
|
edges,
|
|
@@ -1272,7 +1341,7 @@ function useContainerLinks(args) {
|
|
|
1272
1341
|
type: containerType,
|
|
1273
1342
|
id: containerId
|
|
1274
1343
|
});
|
|
1275
|
-
const conversationKey = containerType === "conversation" && containerId ? `conversation:${containerId}` : null;
|
|
1344
|
+
const conversationKey = !outgoing && containerType === "conversation" && containerId ? `conversation:${containerId}` : null;
|
|
1276
1345
|
const activeConversationKey = (0, import_react3.useRef)(conversationKey);
|
|
1277
1346
|
const conversationGeneration = (0, import_react3.useRef)(0);
|
|
1278
1347
|
const [conversationResult, setConversationResult] = (0, import_react3.useState)(null);
|
|
@@ -1328,9 +1397,9 @@ function useContainerLinks(args) {
|
|
|
1328
1397
|
}, [loadConversationFiles]);
|
|
1329
1398
|
const conversationFiles = conversationResult?.key === conversationKey ? conversationResult.files : [];
|
|
1330
1399
|
const conversationFileError = conversationResult?.key === conversationKey ? conversationResult.error : null;
|
|
1331
|
-
const conversationFileStatus = containerType !== "conversation" ? "idle" : conversationResult?.key !== conversationKey ? "loading" : conversationResult.loading ? "loading" : conversationFileError ? "error" : "ready";
|
|
1400
|
+
const conversationFileStatus = outgoing || containerType !== "conversation" ? "idle" : conversationResult?.key !== conversationKey ? "loading" : conversationResult.loading ? "loading" : conversationFileError ? "error" : "ready";
|
|
1332
1401
|
const incomingGeneric = edges.filter(
|
|
1333
|
-
(edge) => edge.direction === "incoming" && !(containerType === "conversation" && edge.otherType === "file")
|
|
1402
|
+
(edge) => outgoing ? edge.direction === "outgoing" : edge.direction === "incoming" && !(containerType === "conversation" && edge.otherType === "file")
|
|
1334
1403
|
).map((edge) => ({
|
|
1335
1404
|
edgeId: edge.id,
|
|
1336
1405
|
resourceId: edge.otherId,
|
|
@@ -1339,7 +1408,29 @@ function useContainerLinks(args) {
|
|
|
1339
1408
|
label: edge.label ?? null,
|
|
1340
1409
|
metadata: edge.metadata ?? {}
|
|
1341
1410
|
}));
|
|
1342
|
-
const incoming = containerType === "conversation" ? [...incomingGeneric, ...conversationFiles] : incomingGeneric;
|
|
1411
|
+
const incoming = !outgoing && containerType === "conversation" ? [...incomingGeneric, ...conversationFiles] : incomingGeneric;
|
|
1412
|
+
const endpoints = (token, resourceId) => {
|
|
1413
|
+
if (!containerId) return { error: "Missing container id" };
|
|
1414
|
+
if (outgoing) {
|
|
1415
|
+
if (!isAssociationTargetType(token)) {
|
|
1416
|
+
return {
|
|
1417
|
+
error: `A ${token.replace(/_/g, " ")} cannot be filed under: it is not a container type.`
|
|
1418
|
+
};
|
|
1419
|
+
}
|
|
1420
|
+
return {
|
|
1421
|
+
sourceType: containerType,
|
|
1422
|
+
sourceId: containerId,
|
|
1423
|
+
targetType: token,
|
|
1424
|
+
targetId: resourceId
|
|
1425
|
+
};
|
|
1426
|
+
}
|
|
1427
|
+
return {
|
|
1428
|
+
sourceType: token,
|
|
1429
|
+
sourceId: resourceId,
|
|
1430
|
+
targetType: containerType,
|
|
1431
|
+
targetId: containerId
|
|
1432
|
+
};
|
|
1433
|
+
};
|
|
1343
1434
|
const linksFor = (token) => incoming.filter((link) => link.token === token);
|
|
1344
1435
|
const countFor = (token) => incoming.reduce((n, link) => link.token === token ? n + 1 : n, 0);
|
|
1345
1436
|
const attachedIdsFor = (token) => {
|
|
@@ -1350,39 +1441,36 @@ function useContainerLinks(args) {
|
|
|
1350
1441
|
return set;
|
|
1351
1442
|
};
|
|
1352
1443
|
const attach = async (token, resourceId, label, metadata, options) => {
|
|
1353
|
-
|
|
1444
|
+
const ends = endpoints(token, resourceId);
|
|
1445
|
+
if ("error" in ends) return { ok: false, error: ends.error };
|
|
1354
1446
|
const result = await store.add({
|
|
1355
|
-
|
|
1356
|
-
sourceId: resourceId,
|
|
1357
|
-
targetType: containerType,
|
|
1358
|
-
targetId: containerId,
|
|
1447
|
+
...ends,
|
|
1359
1448
|
...orgId != null ? { orgId } : {},
|
|
1360
1449
|
...label !== void 0 ? { label } : {},
|
|
1361
1450
|
...metadata !== void 0 ? { metadata } : {},
|
|
1362
1451
|
...options?.role !== void 0 ? { role: options.role } : {},
|
|
1363
1452
|
...options?.replaceMetadata !== void 0 ? { replaceMetadata: options.replaceMetadata } : {}
|
|
1364
1453
|
});
|
|
1365
|
-
if (result.ok && containerType === "conversation" && token === "file") {
|
|
1454
|
+
if (result.ok && !outgoing && containerType === "conversation" && token === "file") {
|
|
1366
1455
|
await loadConversationFiles();
|
|
1367
1456
|
}
|
|
1368
1457
|
return result;
|
|
1369
1458
|
};
|
|
1370
1459
|
const detach = async (token, resourceId, role) => {
|
|
1371
|
-
|
|
1460
|
+
const ends = endpoints(token, resourceId);
|
|
1461
|
+
if ("error" in ends) return { ok: false, error: ends.error };
|
|
1372
1462
|
const result = await store.remove({
|
|
1373
|
-
|
|
1374
|
-
sourceId: resourceId,
|
|
1375
|
-
targetType: containerType,
|
|
1376
|
-
targetId: containerId,
|
|
1463
|
+
...ends,
|
|
1377
1464
|
...role !== void 0 ? { role } : {}
|
|
1378
1465
|
});
|
|
1379
|
-
if (result.ok && containerType === "conversation" && token === "file") {
|
|
1466
|
+
if (result.ok && !outgoing && containerType === "conversation" && token === "file") {
|
|
1380
1467
|
await loadConversationFiles();
|
|
1381
1468
|
}
|
|
1382
1469
|
return result;
|
|
1383
1470
|
};
|
|
1384
1471
|
const setPinned = async (token, resourceId, pinned, role) => {
|
|
1385
|
-
|
|
1472
|
+
const ends = endpoints(token, resourceId);
|
|
1473
|
+
if ("error" in ends) return { ok: false, error: ends.error };
|
|
1386
1474
|
const exactRole = role ?? null;
|
|
1387
1475
|
const link = incoming.find(
|
|
1388
1476
|
(candidate) => candidate.token === token && candidate.resourceId === resourceId && candidate.role === exactRole
|
|
@@ -1396,10 +1484,7 @@ function useContainerLinks(args) {
|
|
|
1396
1484
|
};
|
|
1397
1485
|
}
|
|
1398
1486
|
return store.add({
|
|
1399
|
-
|
|
1400
|
-
sourceId: resourceId,
|
|
1401
|
-
targetType: containerType,
|
|
1402
|
-
targetId: containerId,
|
|
1487
|
+
...ends,
|
|
1403
1488
|
...orgId != null ? { orgId } : {},
|
|
1404
1489
|
...link.label != null ? { label: link.label } : {},
|
|
1405
1490
|
...role !== void 0 ? { role } : {},
|
|
@@ -1409,10 +1494,10 @@ function useContainerLinks(args) {
|
|
|
1409
1494
|
const reload = async () => {
|
|
1410
1495
|
await Promise.all([
|
|
1411
1496
|
reloadGeneric(),
|
|
1412
|
-
containerType === "conversation" ? loadConversationFiles() : Promise.resolve()
|
|
1497
|
+
!outgoing && containerType === "conversation" ? loadConversationFiles() : Promise.resolve()
|
|
1413
1498
|
]);
|
|
1414
1499
|
};
|
|
1415
|
-
const status = !containerId ? genericStatus : conversationFileStatus === "error" ? "error" : containerType === "conversation" && (conversationFileStatus === "idle" || conversationFileStatus === "loading") ? "loading" : genericStatus;
|
|
1500
|
+
const status = !containerId ? genericStatus : conversationFileStatus === "error" ? "error" : !outgoing && containerType === "conversation" && (conversationFileStatus === "idle" || conversationFileStatus === "loading") ? "loading" : genericStatus;
|
|
1416
1501
|
const error = conversationFileError ?? genericError;
|
|
1417
1502
|
return {
|
|
1418
1503
|
status,
|
|
@@ -1427,6 +1512,21 @@ function useContainerLinks(args) {
|
|
|
1427
1512
|
setPinned
|
|
1428
1513
|
};
|
|
1429
1514
|
}
|
|
1515
|
+
function containerLinksArgs(container) {
|
|
1516
|
+
if (container?.direction === "outgoing") {
|
|
1517
|
+
return {
|
|
1518
|
+
containerType: container.type,
|
|
1519
|
+
containerId: container.id,
|
|
1520
|
+
orgId: container.orgId ?? null,
|
|
1521
|
+
direction: "outgoing"
|
|
1522
|
+
};
|
|
1523
|
+
}
|
|
1524
|
+
return {
|
|
1525
|
+
containerType: container?.type ?? "organization",
|
|
1526
|
+
containerId: container?.id ?? null,
|
|
1527
|
+
orgId: container?.orgId ?? null
|
|
1528
|
+
};
|
|
1529
|
+
}
|
|
1430
1530
|
|
|
1431
1531
|
// src/react/hooks/useEntityTitles.ts
|
|
1432
1532
|
var import_react4 = require("react");
|
|
@@ -2261,7 +2361,7 @@ function AssociationPicker(props) {
|
|
|
2261
2361
|
const Override = pickerOverrides?.[props.token];
|
|
2262
2362
|
if (Override) return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Override, { ...props });
|
|
2263
2363
|
const title = `Add ${info.labelPlural}`;
|
|
2264
|
-
const subtitle = props.containerLabel ? `Attach to ${props.containerLabel}` : "Click an item to attach or detach it";
|
|
2364
|
+
const subtitle = props.filing ? `File ${props.containerLabel ?? "this"} under a ${info.label.toLowerCase()}` : props.containerLabel ? `Attach to ${props.containerLabel}` : "Click an item to attach or detach it";
|
|
2265
2365
|
if (!props.open) return null;
|
|
2266
2366
|
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2267
2367
|
AssociationWindow,
|
|
@@ -2878,8 +2978,9 @@ function AttachedItemsSheet(props) {
|
|
|
2878
2978
|
const Icon = info.Icon ?? DefaultEntityIcon;
|
|
2879
2979
|
const title = info.labelPlural;
|
|
2880
2980
|
const containerName = props.container?.label ?? props.containerLabel;
|
|
2981
|
+
const filing = props.container?.direction === "outgoing";
|
|
2881
2982
|
const subtitle = props.container ? /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("span", { className: "inline-flex min-w-0 max-w-full items-center gap-1", children: [
|
|
2882
|
-
"Attached to",
|
|
2983
|
+
filing ? "What this is filed under:" : "Attached to",
|
|
2883
2984
|
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
2884
2985
|
DoorRef,
|
|
2885
2986
|
{
|
|
@@ -3155,11 +3256,7 @@ function AssociationCard({
|
|
|
3155
3256
|
attach,
|
|
3156
3257
|
detach,
|
|
3157
3258
|
setPinned
|
|
3158
|
-
} = useContainerLinks(
|
|
3159
|
-
containerType: container?.type ?? "organization",
|
|
3160
|
-
containerId: container?.id ?? null,
|
|
3161
|
-
orgId: container?.orgId ?? null
|
|
3162
|
-
});
|
|
3259
|
+
} = useContainerLinks(containerLinksArgs(container));
|
|
3163
3260
|
if (!container) {
|
|
3164
3261
|
store.errorSink({
|
|
3165
3262
|
code: "association_card_no_container",
|
|
@@ -3170,7 +3267,8 @@ function AssociationCard({
|
|
|
3170
3267
|
}
|
|
3171
3268
|
const count = countFor(token);
|
|
3172
3269
|
const loading = status === "loading" || status === "idle";
|
|
3173
|
-
const
|
|
3270
|
+
const filing = container.direction === "outgoing";
|
|
3271
|
+
const canAttach = info.canListCandidates && (!filing || isAssociationTargetType(token));
|
|
3174
3272
|
const canDrillIn = count > 0;
|
|
3175
3273
|
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
|
|
3176
3274
|
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
|
|
@@ -3218,7 +3316,7 @@ function AssociationCard({
|
|
|
3218
3316
|
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "block text-[11px] text-muted-foreground tabular-nums", children: loading ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { className: "inline-flex items-center gap-1", children: [
|
|
3219
3317
|
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(SpinnerIcon, { className: "h-3 w-3 animate-spin" }),
|
|
3220
3318
|
"Loading\u2026"
|
|
3221
|
-
] }) : `${count} attached` })
|
|
3319
|
+
] }) : `${count} ${container.direction === "outgoing" ? "filed under" : "attached"}` })
|
|
3222
3320
|
] })
|
|
3223
3321
|
]
|
|
3224
3322
|
}
|
|
@@ -3264,6 +3362,7 @@ function AssociationCard({
|
|
|
3264
3362
|
token,
|
|
3265
3363
|
...container.label !== void 0 ? { containerLabel: container.label } : {},
|
|
3266
3364
|
orgId: container.orgId ?? null,
|
|
3365
|
+
...filing ? { filing: true } : {},
|
|
3267
3366
|
attachedIds: attachedIdsFor(token),
|
|
3268
3367
|
onAttach: (resourceId, title) => attach(token, resourceId, title),
|
|
3269
3368
|
onDetach: (resourceId) => detach(token, resourceId)
|
|
@@ -3281,9 +3380,11 @@ function AssociationCardGrid({
|
|
|
3281
3380
|
className
|
|
3282
3381
|
}) {
|
|
3283
3382
|
const store = useAssociationsStore();
|
|
3383
|
+
const primary = usePrimaryEntity();
|
|
3284
3384
|
const excluded = new Set(excludeTokens ?? []);
|
|
3385
|
+
const filing = primary?.direction === "outgoing";
|
|
3285
3386
|
const list = (tokens ?? store.registry.curatedTokens()).filter(
|
|
3286
|
-
(token) => !excluded.has(token)
|
|
3387
|
+
(token) => !excluded.has(token) && (!filing || isAssociationTargetType(token))
|
|
3287
3388
|
);
|
|
3288
3389
|
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: (0, import_design_system7.cn)("space-y-5", className), children: CONTENT_ROLES.map((role) => {
|
|
3289
3390
|
const inRole = list.filter(
|
|
@@ -3317,11 +3418,7 @@ function metadataIsPinned2(metadata) {
|
|
|
3317
3418
|
}
|
|
3318
3419
|
function useContainerLinksAdapter(container, tokens) {
|
|
3319
3420
|
const store = useAssociationsStore();
|
|
3320
|
-
const links = useContainerLinks(
|
|
3321
|
-
containerType: container?.type ?? "organization",
|
|
3322
|
-
containerId: container?.id ?? null,
|
|
3323
|
-
orgId: container?.orgId ?? null
|
|
3324
|
-
});
|
|
3421
|
+
const links = useContainerLinks(containerLinksArgs(container));
|
|
3325
3422
|
const rows = container ? (tokens ?? store.registry.curatedTokens()).flatMap(
|
|
3326
3423
|
(token) => links.linksFor(token).map((l) => ({
|
|
3327
3424
|
key: l.edgeId,
|