aimeat 1.20.3 → 1.20.4

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.
Files changed (51) hide show
  1. package/dist/locales/en.json +50 -1
  2. package/dist/locales/fi.json +50 -1
  3. package/dist/public/css/views/profile.css +9 -0
  4. package/dist/public/css/views/public-workspace-viewer.css +23 -3
  5. package/dist/public/js/services/organisms.js +77 -6
  6. package/dist/public/views/profile/organisms-tab.js +308 -54
  7. package/dist/public/views/public-workspace-viewer.js +74 -11
  8. package/dist/src/cli/connect/mcp/tools/index.d.ts.map +1 -1
  9. package/dist/src/cli/connect/mcp/tools/index.js +2 -0
  10. package/dist/src/cli/connect/mcp/tools/index.js.map +1 -1
  11. package/dist/src/cli/connect/mcp/tools/organisms.d.ts.map +1 -1
  12. package/dist/src/cli/connect/mcp/tools/organisms.js +57 -0
  13. package/dist/src/cli/connect/mcp/tools/organisms.js.map +1 -1
  14. package/dist/src/cli/connect/mcp/tools/schedules.d.ts +15 -0
  15. package/dist/src/cli/connect/mcp/tools/schedules.d.ts.map +1 -0
  16. package/dist/src/cli/connect/mcp/tools/schedules.js +66 -0
  17. package/dist/src/cli/connect/mcp/tools/schedules.js.map +1 -0
  18. package/dist/src/cli/connect/tool-call.d.ts.map +1 -1
  19. package/dist/src/cli/connect/tool-call.js +79 -0
  20. package/dist/src/cli/connect/tool-call.js.map +1 -1
  21. package/dist/src/cli/init-wizard.d.ts.map +1 -1
  22. package/dist/src/cli/init-wizard.js +11 -3
  23. package/dist/src/cli/init-wizard.js.map +1 -1
  24. package/dist/src/generated/api-types.d.ts +499 -1
  25. package/dist/src/generated/api-types.d.ts.map +1 -1
  26. package/dist/src/mcp/annotations.d.ts.map +1 -1
  27. package/dist/src/mcp/annotations.js +6 -0
  28. package/dist/src/mcp/annotations.js.map +1 -1
  29. package/dist/src/mcp/catalog/definitions.d.ts.map +1 -1
  30. package/dist/src/mcp/catalog/definitions.js +65 -0
  31. package/dist/src/mcp/catalog/definitions.js.map +1 -1
  32. package/dist/src/mcp/catalog/surfaces.js +6 -6
  33. package/dist/src/mcp/catalog/surfaces.js.map +1 -1
  34. package/dist/src/mcp/organisms.d.ts.map +1 -1
  35. package/dist/src/mcp/organisms.js +145 -0
  36. package/dist/src/mcp/organisms.js.map +1 -1
  37. package/dist/src/routes/organisms.d.ts.map +1 -1
  38. package/dist/src/routes/organisms.js +406 -5
  39. package/dist/src/routes/organisms.js.map +1 -1
  40. package/dist/src/services/organism-comments.d.ts +30 -0
  41. package/dist/src/services/organism-comments.d.ts.map +1 -0
  42. package/dist/src/services/organism-comments.js +74 -0
  43. package/dist/src/services/organism-comments.js.map +1 -0
  44. package/dist/src/services/organism-search.d.ts +27 -0
  45. package/dist/src/services/organism-search.d.ts.map +1 -0
  46. package/dist/src/services/organism-search.js +84 -0
  47. package/dist/src/services/organism-search.js.map +1 -0
  48. package/dist/src/storage/interface.d.ts +7 -1
  49. package/dist/src/storage/interface.d.ts.map +1 -1
  50. package/dist/src/storage/interface.js.map +1 -1
  51. package/package.json +1 -1
@@ -82,24 +82,128 @@ import { Markdown, slugifyHeading } from '/components/Markdown.js';
82
82
  import { Mermaid } from '/components/Mermaid.js';
83
83
 
84
84
  /**
85
- * Organism-level member management (creator/admin only). Approve/reject pending join
86
- * requests and revoke (remove) existing members. Backend: GET /:id/join-requests,
87
- * POST /:id/join-requests/:rid/review, DELETE /:id/members/:ghii. Renders only inside an
88
- * expanded org card for users who can edit; refreshes the parent list via onChanged.
85
+ * Content search inside an organism — case-insensitive substring over the records + documents of
86
+ * every workspace the member can read. Backend: GET /v1/organisms/:id/search. Rendered in the
87
+ * expanded card for members; opening a hit takes the user to that workspace.
89
88
  */
90
- function OrgMemberManager({ orgId, ghii, showToast, confirm, onChanged }) {
89
+ function OrgSearch({ orgId, onOpenWorkspace }) {
90
+ const [q, setQ] = useState('');
91
+ const [results, setResults] = useState(null);
92
+ const [busy, setBusy] = useState(false);
93
+
94
+ const doSearch = async () => {
95
+ const query = q.trim();
96
+ if (query.length < 2) return;
97
+ setBusy(true);
98
+ try {
99
+ const r = await orgService.searchOrganism(orgId, query);
100
+ setResults(r?.data?.results || []);
101
+ } catch { setResults([]); }
102
+ finally { setBusy(false); }
103
+ };
104
+
105
+ return html`
106
+ <div class="card-detail">
107
+ <div class="section-title">${t('organisms.searchContent') || 'Search content'}</div>
108
+ <div class="flex-row-wrap">
109
+ <input class="input-field input-sm" placeholder=${t('organisms.searchPlaceholder') || 'Find records & documents…'} value=${q}
110
+ onInput=${(e) => setQ(e.target.value)} onKeyDown=${(e) => { if (e.key === 'Enter') doSearch(); }} />
111
+ <button class="btn-outline btn-sm" disabled=${busy || q.trim().length < 2} onClick=${doSearch}>${t('organisms.search') || 'Search'}</button>
112
+ </div>
113
+ ${results !== null && results.length === 0 ? html`<div class="section-desc">${t('organisms.searchNoResults') || 'No matches.'}</div>` : null}
114
+ ${(results || []).map(r => html`
115
+ <div class="pj-access-row card-clickable" key=${r.ws + '/' + r.space + '/' + r.id} role="button" onClick=${() => onOpenWorkspace?.(r.ws)}>
116
+ <span>
117
+ <b>${escHtml(r.title)}</b>
118
+ <span class="pj-mini"> — ${escHtml(r.wsName || r.ws)} · ${escHtml(r.space)}</span>
119
+ <div class="pj-mini">${escHtml(r.snippet)}</div>
120
+ </span>
121
+ </div>
122
+ `)}
123
+ </div>
124
+ `;
125
+ }
126
+
127
+ /**
128
+ * Banner listing the caller's pending organism invitations (status `invited`) across all
129
+ * organisms, with Accept / Decline. Invited organisms are not in the member's active list, so
130
+ * this is how an invitee discovers them. Backend: GET /v1/organisms/invitations/mine.
131
+ */
132
+ function IncomingInvitations({ showToast, onChanged }) {
133
+ const [invites, setInvites] = useState([]);
134
+ const [busy, setBusy] = useState(false);
135
+ const load = useCallback(async () => {
136
+ const r = await orgService.listMyInvitations().catch(() => null);
137
+ setInvites(r?.data?.invitations || []);
138
+ }, []);
139
+ useEffect(() => { load(); }, [load]);
140
+ const liveRef = useRef(load); liveRef.current = load;
141
+ useEffect(() => {
142
+ const h = () => liveRef.current();
143
+ window.addEventListener('aimeat-live-update', h);
144
+ return () => window.removeEventListener('aimeat-live-update', h);
145
+ }, []);
146
+ const act = async (id, accept) => {
147
+ setBusy(true);
148
+ try {
149
+ const r = accept ? await orgService.acceptInvitation(id) : await orgService.declineInvitation(id);
150
+ if (r?.ok === false) showToast(r?.error?.message || (t('organisms.inviteActionFailed') || 'Failed'));
151
+ else showToast(accept ? (t('organisms.invitationAccepted') || 'Joined') : (t('organisms.invitationDeclined') || 'Declined'));
152
+ await load(); onChanged?.();
153
+ } catch (e) { showToast((e && e.message) || (t('organisms.inviteActionFailed') || 'Failed')); }
154
+ finally { setBusy(false); }
155
+ };
156
+ if (!invites.length) return null;
157
+ return html`
158
+ <div class="card">
159
+ <div class="section-title">${t('organisms.youAreInvited') || 'You’re invited'}</div>
160
+ ${invites.map(({ membership, organism }) => html`
161
+ <div class="pj-access-row" key=${organism.id}>
162
+ <span><b>${escHtml(organism.name)}</b>${membership.invitedBy ? html` <span class="pj-mini">— ${(t('organisms.invitedByLabel') || 'invited by {who}').replace('{who}', escHtml(membership.invitedBy))}</span>` : null}</span>
163
+ <span class="flex-row-wrap">
164
+ <button class="btn-success btn-sm" disabled=${busy} onClick=${() => act(organism.id, true)}>${t('organisms.acceptInvite') || 'Accept'}</button>
165
+ <button class="btn-ghost btn-sm" disabled=${busy} onClick=${() => act(organism.id, false)}>${t('organisms.declineInvite') || 'Decline'}</button>
166
+ </span>
167
+ </div>
168
+ `)}
169
+ </div>
170
+ `;
171
+ }
172
+
173
+ /**
174
+ * Organism member panel. For creator/admin (`canManage`) it is a full manager: approve/reject
175
+ * join requests, invite by name, remove/block members, lift bans, transfer ownership (creator
176
+ * only), and attach/detach agents. For a regular member it renders a read-only roster + agent
177
+ * list (#6). Backend: /:id/{join-requests,invitations,members,transfer,agents}. Refreshes the
178
+ * parent list via onChanged so member counts stay current.
179
+ */
180
+ function OrgMemberManager({ org, ghii, canManage, isCreator, showToast, confirm, onChanged }) {
181
+ const orgId = org.id;
91
182
  const [requests, setRequests] = useState(null);
92
183
  const [members, setMembers] = useState(null);
184
+ const [banned, setBanned] = useState([]);
185
+ const [invitations, setInvitations] = useState([]);
186
+ const [inviteName, setInviteName] = useState('');
187
+ const [agentName, setAgentName] = useState('');
93
188
  const [busy, setBusy] = useState(false);
94
189
 
95
190
  const load = useCallback(async () => {
96
- const [rq, mb] = await Promise.all([
97
- orgService.listJoinRequests(orgId).catch(() => null),
98
- orgService.listMembers(orgId).catch(() => null),
99
- ]);
100
- setRequests(rq?.data?.join_requests || []);
191
+ const tasks = [orgService.listMembers(orgId).catch(() => null)];
192
+ if (canManage) {
193
+ tasks.push(
194
+ orgService.listJoinRequests(orgId).catch(() => null),
195
+ orgService.listMembers(orgId, 'banned').catch(() => null),
196
+ orgService.listInvitations(orgId).catch(() => null),
197
+ );
198
+ }
199
+ const [mb, rq, bn, inv] = await Promise.all(tasks);
101
200
  setMembers(mb?.data?.members || []);
102
- }, [orgId]);
201
+ if (canManage) {
202
+ setRequests(rq?.data?.join_requests || []);
203
+ setBanned(bn?.data?.members || []);
204
+ setInvitations(inv?.data?.invitations || []);
205
+ }
206
+ }, [orgId, canManage]);
103
207
 
104
208
  useEffect(() => { load(); }, [load]);
105
209
  const liveRef = useRef(load); liveRef.current = load;
@@ -109,65 +213,123 @@ function OrgMemberManager({ orgId, ghii, showToast, confirm, onChanged }) {
109
213
  return () => window.removeEventListener('aimeat-live-update', handler);
110
214
  }, []);
111
215
 
112
- const review = async (rid, decision) => {
216
+ const run = async (fn, okMsg, failKey) => {
113
217
  setBusy(true);
114
218
  try {
115
- const r = await orgService.reviewJoinRequest(orgId, rid, decision);
116
- if (r?.ok === false) showToast(r?.error?.message || (t('organisms.reviewFailed') || 'Review failed'));
117
- else showToast(decision === 'approved' ? (t('organisms.joinApproved') || 'Request approved') : (t('organisms.joinRejected') || 'Request declined'));
219
+ const r = await fn();
220
+ if (r?.ok === false) showToast(r?.error?.message || (t(failKey) || 'Failed'));
221
+ else if (okMsg) showToast(okMsg);
118
222
  await load(); onChanged?.();
119
- } catch (e) { showToast((e && e.message) || (t('organisms.reviewFailed') || 'Review failed')); }
223
+ } catch (e) { showToast((e && e.message) || (t(failKey) || 'Failed')); }
120
224
  finally { setBusy(false); }
121
225
  };
122
226
 
123
- const remove = (memberGhii) => {
124
- confirm(
125
- (t('organisms.confirmRemoveMember') || 'Revoke {member}’s access to this organism?').replace('{member}', memberGhii),
126
- async () => {
127
- setBusy(true);
128
- try {
129
- const r = await orgService.removeMember(orgId, memberGhii);
130
- if (r?.ok === false) showToast(r?.error?.message || (t('organisms.removeFailed') || 'Remove failed'));
131
- else showToast(t('organisms.memberRemoved') || 'Member removed');
132
- await load(); onChanged?.();
133
- } catch (e) { showToast((e && e.message) || (t('organisms.removeFailed') || 'Remove failed')); }
134
- finally { setBusy(false); }
135
- },
136
- { danger: true },
137
- );
227
+ const review = (rid, decision) => run(
228
+ () => orgService.reviewJoinRequest(orgId, rid, decision),
229
+ decision === 'approved' ? (t('organisms.joinApproved') || 'Request approved') : (t('organisms.joinRejected') || 'Request declined'),
230
+ 'organisms.reviewFailed');
231
+
232
+ const invite = () => {
233
+ const name = inviteName.trim();
234
+ if (!name) return;
235
+ setInviteName('');
236
+ run(() => orgService.inviteMember(orgId, name), (t('organisms.invitationSent') || 'Invitation sent'), 'organisms.inviteFailed');
138
237
  };
139
238
 
239
+ const remove = (memberGhii, ban) => confirm(
240
+ (ban ? (t('organisms.confirmBlockMember') || 'Block {member} and remove them from this organism?') : (t('organisms.confirmRemoveMember') || 'Revoke {member}’s access to this organism?')).replace('{member}', memberGhii),
241
+ () => run(() => orgService.removeMember(orgId, memberGhii, ban), ban ? (t('organisms.memberBlocked') || 'Member blocked') : (t('organisms.memberRemoved') || 'Member removed'), 'organisms.removeFailed'),
242
+ { danger: true });
243
+
244
+ const unban = (memberGhii) => run(() => orgService.unbanMember(orgId, memberGhii), (t('organisms.banLifted') || 'Block lifted'), 'organisms.removeFailed');
245
+
246
+ const transfer = (toGhii) => confirm(
247
+ (t('organisms.confirmTransfer') || 'Make {member} the creator? You will become an admin.').replace('{member}', toGhii),
248
+ () => run(() => orgService.transferOwnership(orgId, toGhii), (t('organisms.ownershipTransferred') || 'Ownership transferred'), 'organisms.transferFailed'),
249
+ { danger: true });
250
+
251
+ const attachAgent = () => {
252
+ const g = agentName.trim();
253
+ if (!g) return;
254
+ setAgentName('');
255
+ run(() => orgService.attachAgent(orgId, g), (t('organisms.agentAttached') || 'Agent attached'), 'organisms.agentFailed');
256
+ };
257
+ const detachAgent = (g) => run(() => orgService.detachAgent(orgId, g), (t('organisms.agentDetached') || 'Agent detached'), 'organisms.agentFailed');
258
+
140
259
  const pending = (requests || []).filter(r => r.status === 'pending');
260
+ const agents = org.agentGaiis || [];
141
261
 
142
262
  return html`
143
263
  <div class="card-detail">
144
- <div class="section-title">${t('organisms.manageMembers') || 'Manage members'}</div>
145
- <div class="section-desc">${t('organisms.manageMembersDesc') || 'Approve join requests and revoke member access.'}</div>
146
-
147
- <div class="detail-label">${t('organisms.pendingRequests') || 'Pending join requests'}</div>
148
- ${requests === null
149
- ? html`<div class="section-desc">…</div>`
150
- : pending.length === 0
151
- ? html`<div class="section-desc">${t('organisms.noPendingRequests') || 'No pending requests.'}</div>`
152
- : pending.map(r => html`
153
- <div class="pj-access-row" key=${r.id}>
154
- <span>${escHtml(r.ghii)}${r.message ? html` <span class="pj-mini">— ${escHtml(r.message)}</span>` : null}</span>
155
- <span class="flex-row-wrap">
156
- <button class="btn-success btn-sm" disabled=${busy} onClick=${() => review(r.id, 'approved')}>${t('organisms.approve') || 'Approve'}</button>
157
- <button class="btn-ghost btn-sm" disabled=${busy} onClick=${() => review(r.id, 'rejected')}>${t('organisms.reject') || 'Reject'}</button>
158
- </span>
159
- </div>
160
- `)}
264
+ <div class="section-title">${canManage ? (t('organisms.manageMembers') || 'Manage members') : (t('organisms.membersRoster') || 'Members')}</div>
265
+ ${canManage ? html`<div class="section-desc">${t('organisms.manageMembersDesc') || 'Invite, approve, block and revoke member access.'}</div>` : null}
266
+
267
+ ${canManage ? html`
268
+ <div class="detail-label">${t('organisms.inviteMember') || 'Invite a member'}</div>
269
+ <div class="flex-row-wrap">
270
+ <input class="input-field input-sm" placeholder=${t('organisms.inviteePlaceholder') || 'owner name'} value=${inviteName}
271
+ onInput=${(e) => setInviteName(e.target.value)} onKeyDown=${(e) => { if (e.key === 'Enter') invite(); }} />
272
+ <button class="btn-primary btn-sm" disabled=${busy || !inviteName.trim()} onClick=${invite}>${t('organisms.invite') || 'Invite'}</button>
273
+ </div>
274
+ ${invitations.length > 0 ? html`
275
+ <div class="section-desc">${t('organisms.outstandingInvites') || 'Awaiting acceptance'}: ${invitations.map(m => escHtml(m.ghii)).join(', ')}</div>
276
+ ` : null}
277
+
278
+ <div class="detail-label">${t('organisms.pendingRequests') || 'Pending join requests'}</div>
279
+ ${requests === null
280
+ ? html`<div class="section-desc">…</div>`
281
+ : pending.length === 0
282
+ ? html`<div class="section-desc">${t('organisms.noPendingRequests') || 'No pending requests.'}</div>`
283
+ : pending.map(r => html`
284
+ <div class="pj-access-row" key=${r.id}>
285
+ <span>${escHtml(r.ghii)}${r.message ? html` <span class="pj-mini">— ${escHtml(r.message)}</span>` : null}</span>
286
+ <span class="flex-row-wrap">
287
+ <button class="btn-success btn-sm" disabled=${busy} onClick=${() => review(r.id, 'approved')}>${t('organisms.approve') || 'Approve'}</button>
288
+ <button class="btn-ghost btn-sm" disabled=${busy} onClick=${() => review(r.id, 'rejected')}>${t('organisms.reject') || 'Reject'}</button>
289
+ </span>
290
+ </div>
291
+ `)}
292
+ ` : null}
161
293
 
162
294
  <div class="detail-label">${t('organisms.members') || 'Members'}</div>
163
295
  ${(members || []).map(m => html`
164
296
  <div class="pj-access-row" key=${m.ghii}>
165
297
  <span>${escHtml(m.ghii)} <span class="badge ${m.role === 'creator' ? 'badge-success' : 'badge-info'} pj-mini">${escHtml(m.role || 'member')}</span></span>
166
- ${(m.role !== 'creator' && m.ghii !== ghii)
167
- ? html`<button class="btn-danger btn-sm" disabled=${busy} onClick=${() => remove(m.ghii)}>${t('organisms.remove') || 'Remove'}</button>`
298
+ ${canManage && m.role !== 'creator' && m.ghii !== ghii ? html`
299
+ <span class="flex-row-wrap">
300
+ ${isCreator ? html`<button class="btn-ghost btn-sm" disabled=${busy} onClick=${() => transfer(m.ghii)}>${t('organisms.makeCreator') || 'Make creator'}</button>` : null}
301
+ <button class="btn-outline btn-sm" disabled=${busy} onClick=${() => remove(m.ghii, false)}>${t('organisms.remove') || 'Remove'}</button>
302
+ <button class="btn-danger btn-sm" disabled=${busy} onClick=${() => remove(m.ghii, true)}>${t('organisms.block') || 'Block'}</button>
303
+ </span>
304
+ ` : null}
305
+ </div>
306
+ `)}
307
+
308
+ ${canManage && banned.length > 0 ? html`
309
+ <div class="detail-label">${t('organisms.blockedMembers') || 'Blocked'}</div>
310
+ ${banned.map(m => html`
311
+ <div class="pj-access-row" key=${'ban-' + m.ghii}>
312
+ <span>${escHtml(m.ghii)}</span>
313
+ <button class="btn-ghost btn-sm" disabled=${busy} onClick=${() => unban(m.ghii)}>${t('organisms.unblock') || 'Unblock'}</button>
314
+ </div>
315
+ `)}
316
+ ` : null}
317
+
318
+ <div class="detail-label">${t('organisms.attachedAgents') || 'Attached agents'}</div>
319
+ ${agents.length === 0 ? html`<div class="section-desc">${t('organisms.noAgents') || 'No agents attached.'}</div>` : null}
320
+ ${agents.map(g => html`
321
+ <div class="pj-access-row" key=${'ag-' + g}>
322
+ <span class="mono">${escHtml(g)}</span>
323
+ ${(canManage || g.includes('#' + ghii + '@'))
324
+ ? html`<button class="btn-ghost btn-sm" disabled=${busy} onClick=${() => detachAgent(g)}>${t('organisms.detach') || 'Detach'}</button>`
168
325
  : null}
169
326
  </div>
170
327
  `)}
328
+ <div class="flex-row-wrap">
329
+ <input class="input-field input-sm" placeholder=${t('organisms.agentGaiiPlaceholder') || 'agent#you@node'} value=${agentName}
330
+ onInput=${(e) => setAgentName(e.target.value)} onKeyDown=${(e) => { if (e.key === 'Enter') attachAgent(); }} />
331
+ <button class="btn-outline btn-sm" disabled=${busy || !agentName.trim()} onClick=${attachAgent}>${t('organisms.attachAgent') || 'Attach agent'}</button>
332
+ </div>
171
333
  </div>
172
334
  `;
173
335
  }
@@ -508,9 +670,15 @@ export default function OrganismsTab({ session, showToast, onStats }) {
508
670
  ` : null}
509
671
  </div>
510
672
 
511
- ${canEdit ? html`<${OrgMemberManager}
673
+ ${(canEdit || isMember) ? html`<${OrgSearch}
512
674
  orgId=${org.id}
675
+ onOpenWorkspace=${(ws) => { setOpenWs(ws); setOpenId(org.id); }} />` : null}
676
+
677
+ ${(canEdit || isMember) ? html`<${OrgMemberManager}
678
+ org=${org}
513
679
  ghii=${ghii}
680
+ canManage=${canEdit}
681
+ isCreator=${isCreator}
514
682
  showToast=${showToast}
515
683
  confirm=${confirm}
516
684
  onChanged=${loadData} />` : null}
@@ -590,6 +758,9 @@ export default function OrganismsTab({ session, showToast, onStats }) {
590
758
  `}
591
759
  </div>
592
760
 
761
+ <!-- Incoming invitations -->
762
+ <${IncomingInvitations} showToast=${showToast} onChanged=${loadData} />
763
+
593
764
  <!-- My Organisms -->
594
765
  <input type="file" accept=".zip,application/zip" ref=${orgFileRef} style="display:none" onChange=${(e) => { const f = e.target.files && e.target.files[0]; e.target.value = ''; doImportOrg(f); }} />
595
766
  <div class="pj-ws-topbar">
@@ -1013,6 +1184,88 @@ function ParticipantsPanel({ orgId, wsId }) {
1013
1184
  </div>`;
1014
1185
  }
1015
1186
 
1187
+ /**
1188
+ * Comment thread on one workspace object (record or document). Targeted by orgId+ws+space+instanceId.
1189
+ * Members read + add comments; an author (or org admin) deletes. Supports an optional quote anchor
1190
+ * (comment on a specific passage) and threaded replies (parentId). Backend: /v1/organisms/:id/comments.
1191
+ * Agents use the same endpoints via aimeat_workspace_comment(s).
1192
+ */
1193
+ function WorkspaceComments({ orgId, ws, space, instanceId, showToast }) {
1194
+ const [comments, setComments] = useState(null);
1195
+ const [body, setBody] = useState('');
1196
+ const [anchorQuote, setAnchorQuote] = useState('');
1197
+ const [replyTo, setReplyTo] = useState(null); // { id, body } of the comment being replied to
1198
+ const [busy, setBusy] = useState(false);
1199
+ const me = (() => { try { return window.AIMEAT?.auth?.getSession?.() || {}; } catch { return {}; } })();
1200
+ const mine = (author) => author && (author === me.gaii || author === me.ghii);
1201
+
1202
+ const load = useCallback(async () => {
1203
+ if (!ws || !space || !instanceId) return;
1204
+ const r = await orgService.listComments(orgId, ws, space, instanceId).catch(() => null);
1205
+ setComments(r?.data?.comments || []);
1206
+ }, [orgId, ws, space, instanceId]);
1207
+ useEffect(() => { load(); }, [load]);
1208
+ const liveRef = useRef(load); liveRef.current = load;
1209
+ useEffect(() => {
1210
+ const h = () => liveRef.current();
1211
+ window.addEventListener('aimeat-live-update', h);
1212
+ return () => window.removeEventListener('aimeat-live-update', h);
1213
+ }, []);
1214
+
1215
+ const submit = async () => {
1216
+ const text = body.trim();
1217
+ if (!text) return;
1218
+ setBusy(true);
1219
+ try {
1220
+ const anchor = anchorQuote.trim() ? { quote: anchorQuote.trim() } : undefined;
1221
+ const r = await orgService.addComment(orgId, { ws, space, instanceId, body: text, anchor, parentId: replyTo?.id });
1222
+ if (r?.ok === false) showToast(r?.error?.message || (t('organisms.commentFailed') || 'Could not post comment'));
1223
+ else { setBody(''); setAnchorQuote(''); setReplyTo(null); await load(); }
1224
+ } catch (e) { showToast((e && e.message) || (t('organisms.commentFailed') || 'Could not post comment')); }
1225
+ finally { setBusy(false); }
1226
+ };
1227
+ const remove = async (c) => {
1228
+ setBusy(true);
1229
+ try {
1230
+ const r = await orgService.deleteComment(orgId, c.id, ws, space, instanceId);
1231
+ if (r?.ok === false) showToast(r?.error?.message || (t('organisms.commentDeleteFailed') || 'Could not delete'));
1232
+ else await load();
1233
+ } catch (e) { showToast((e && e.message) || (t('organisms.commentDeleteFailed') || 'Could not delete')); }
1234
+ finally { setBusy(false); }
1235
+ };
1236
+
1237
+ const list = comments || [];
1238
+ return html`
1239
+ <div class="pj-comments">
1240
+ <div class="detail-label">${(t('organisms.commentsHeading') || 'Comments') + (list.length ? ` (${list.length})` : '')}</div>
1241
+ ${comments === null ? html`<div class="section-desc">…</div>` : null}
1242
+ ${comments !== null && list.length === 0 ? html`<div class="section-desc">${t('organisms.noComments') || 'No comments yet.'}</div>` : null}
1243
+ ${list.map(c => html`
1244
+ <div class="pj-comment ${c.parentId ? 'pj-comment-reply' : ''}" key=${c.id}>
1245
+ <div class="pj-comment-head">
1246
+ <b>${escHtml(c.author || '?')}</b>
1247
+ ${c.parentId ? html`<span class="pj-mini"> · ${t('organisms.inReply') || 'reply'}</span>` : null}
1248
+ ${c.anchor?.quote ? html`<span class="pj-mini"> · “${escHtml(String(c.anchor.quote).slice(0, 80))}”</span>` : null}
1249
+ ${c.anchor?.section ? html`<span class="pj-mini"> · §${escHtml(c.anchor.section)}</span>` : null}
1250
+ <span class="pj-mini"> · ${c.createdAt ? dt(c.createdAt) : ''}</span>
1251
+ </div>
1252
+ <div class="pj-comment-body">${escHtml(c.body || '')}</div>
1253
+ <div class="pj-comment-actions">
1254
+ <button class="btn-ghost btn-sm" disabled=${busy} onClick=${() => setReplyTo({ id: c.id, body: c.body })}>${t('organisms.reply') || 'Reply'}</button>
1255
+ ${mine(c.author) ? html`<button class="btn-ghost btn-sm" disabled=${busy} onClick=${() => remove(c)}>${t('organisms.delete') || 'Delete'}</button>` : null}
1256
+ </div>
1257
+ </div>
1258
+ `)}
1259
+ <div class="pj-comment-compose">
1260
+ ${replyTo ? html`<div class="pj-mini">${t('organisms.replyingTo') || 'Replying to'}: “${escHtml(String(replyTo.body || '').slice(0, 60))}” <button class="btn-ghost btn-sm" onClick=${() => setReplyTo(null)}>${t('organisms.cancel') || 'Cancel'}</button></div>` : null}
1261
+ <input class="input-field input-sm" placeholder=${t('organisms.anchorQuotePlaceholder') || 'Optional: quote a passage to anchor the comment'} value=${anchorQuote} onInput=${(e) => setAnchorQuote(e.target.value)} />
1262
+ <textarea class="input-field input-sm" rows="2" placeholder=${t('organisms.commentPlaceholder') || 'Add a comment…'} value=${body} onInput=${(e) => setBody(e.target.value)}></textarea>
1263
+ <button class="btn-primary btn-sm" disabled=${busy || !body.trim()} onClick=${submit}>${t('organisms.postComment') || 'Comment'}</button>
1264
+ </div>
1265
+ </div>
1266
+ `;
1267
+ }
1268
+
1016
1269
  function Workspace({ org, wsId, showToast, onBack }) {
1017
1270
  const orgId = org.id;
1018
1271
  // Pop a document out into its own window (served by doc-solo.js) so several can sit side by side,
@@ -1579,7 +1832,8 @@ function Workspace({ org, wsId, showToast, onBack }) {
1579
1832
  const target = docs.find(d => (d.title || '').toLowerCase() === title.toLowerCase());
1580
1833
  if (target) { setActiveDoc({ type: ot.name, mode: 'view', page: target }); scrollToAnchor(); }
1581
1834
  else showToast((t('organisms.docNotFound') || 'No document titled “{title}”').replace('{title}', title));
1582
- }} />`;
1835
+ }} />
1836
+ <${WorkspaceComments} orgId=${orgId} ws=${wsId} space=${ot.name} instanceId=${livePage.id} showToast=${showToast} />`;
1583
1837
  })()}
1584
1838
  </div>
1585
1839
  </div>
@@ -1774,7 +2028,7 @@ function Workspace({ org, wsId, showToast, onBack }) {
1774
2028
  <button class="btn-primary btn-sm" onClick=${() => publish(ot, d.id)} disabled=${busy}>${t('organisms.publish') || 'Publish'}</button>
1775
2029
  <button class="pj-icon-btn" title=${t('organisms.delete') || 'Delete'} disabled=${busy} onClick=${() => removeObject(ot.namespace, d.id, String(d[PRIMARY_FIELD[ot.name] || 'title'] || d.id))}>🗑</button>
1776
2030
  </div>
1777
- ${expandedRec[ot.name + ':' + d.id] ? html`<div class="pj-rec-fields">${recordFields(d)}</div>` : null}
2031
+ ${expandedRec[ot.name + ':' + d.id] ? html`<div class="pj-rec-fields">${recordFields(d)}</div><${WorkspaceComments} orgId=${orgId} ws=${wsId} space=${ot.name} instanceId=${d.id} showToast=${showToast} />` : null}
1778
2032
  </div>
1779
2033
  `)}
1780
2034
 
@@ -1787,7 +2041,7 @@ function Workspace({ org, wsId, showToast, onBack }) {
1787
2041
  ${o.status ? html`<span class="badge badge-info">${escHtml(o.status)}</span>` : null}
1788
2042
  <button class="pj-icon-btn" title=${t('organisms.delete') || 'Delete'} disabled=${busy} onClick=${() => removeObject(ot.namespace, o.id, String(o[PRIMARY_FIELD[ot.name] || 'title'] || o.id))}>🗑</button>
1789
2043
  </div>
1790
- ${expandedRec[ot.name + ':' + o.id] ? html`<div class="pj-rec-fields">${recordFields(o)}</div>` : null}
2044
+ ${expandedRec[ot.name + ':' + o.id] ? html`<div class="pj-rec-fields">${recordFields(o)}</div><${WorkspaceComments} orgId=${orgId} ws=${wsId} space=${ot.name} instanceId=${o.id} showToast=${showToast} />` : null}
1791
2045
  </div>
1792
2046
  `)
1793
2047
  }
@@ -4,15 +4,20 @@
4
4
  * Reads the no-auth endpoint GET /v1/organisms/:id/workspace/public/documents?ws=… (which serves
5
5
  * only PUBLISHED docs the workspace's meta.share marks public) and renders each page's markdown with
6
6
  * the safe Markdown component. A table-of-contents lists the shared pages; [[Wiki links]] jump
7
- * between them. "Print / Save as PDF" uses the browser's native print (a print stylesheet hides the
8
- * chrome) — there is no server-side PDF. Deep-link a single page with &type=…&id=….
7
+ * between them. The whole-space view renders EVERY shared page stacked in one continuous document
8
+ * (the TOC scroll-spies + scrolls), so "Print / Save as PDF" captures all pages in one go — there is
9
+ * no server-side PDF. A single page can still be deep-linked (and isolated) with &type=…&id=….
10
+ * "Copy AI link" copies the no-auth Markdown-bundle API URL (?format=md) so an agent can read the
11
+ * raw content directly; drop &format=md for the JSON form.
9
12
  * @structure PublicWorkspaceViewer (default export)
10
13
  * @usage route /v1/publicworkspaceviewer?org=<id>&ws=<ws>[&type=<space>&id=<docId>]
11
14
  * @version-history
12
15
  * v1.0.0 — 2026-06-09 — Initial: slice 2 of the workspace public-sharing plan.
16
+ * v1.1.0 — 2026-06-09 — Continuous whole-space render (all pages stacked → print captures everything)
17
+ * with scroll-spy TOC; "Copy AI link" button exposing the ?format=md Markdown-bundle API URL.
13
18
  */
14
19
  import { h } from 'preact';
15
- import { useState, useEffect, useCallback } from 'preact/hooks';
20
+ import { useState, useEffect, useCallback, useRef } from 'preact/hooks';
16
21
  import htm from 'htm';
17
22
  import { t } from '/js/i18n.js';
18
23
  import { Markdown } from '/components/Markdown.js';
@@ -21,6 +26,8 @@ import { useViewCSS } from '/components/useViewCSS.js';
21
26
  const html = htm.bind(h);
22
27
 
23
28
  const docKey = (d) => `${d.type}/${d.id}`;
29
+ // A DOM-id-safe anchor for each stacked page so the TOC can scroll to it.
30
+ const anchorId = (d) => `pwv-doc-${docKey(d).replace(/[^a-zA-Z0-9_-]/g, '-')}`;
24
31
 
25
32
  function parseParams() {
26
33
  const p = new URLSearchParams(window.location.search);
@@ -64,18 +71,65 @@ export default function PublicWorkspaceViewer() {
64
71
  return () => document.body.classList.remove('pwv-active');
65
72
  }, []);
66
73
 
74
+ // A doc is "isolated" (single-page mode) only when the link explicitly deep-links one page via
75
+ // &type=&id=. The plain whole-space link renders EVERY page stacked (continuous document) so the
76
+ // browser print captures all of them at once.
77
+ const isSingle = Array.isArray(docs) && !!type && !!id && docs.some(d => docKey(d) === `${type}/${id}`);
78
+ const visibleDocs = Array.isArray(docs) ? (isSingle ? docs.filter(d => docKey(d) === `${type}/${id}`) : docs) : [];
67
79
  const current = Array.isArray(docs) ? docs.find(d => docKey(d) === selected) : null;
68
80
  useEffect(() => {
69
81
  if (current?.title) document.title = `${current.title} — AIMEAT`;
70
82
  }, [current?.title]);
71
83
 
84
+ // Scroll a page into view and mark it active (TOC click + initial deep-link land).
85
+ const goTo = useCallback((d) => {
86
+ setSelected(docKey(d));
87
+ const el = document.getElementById(anchorId(d));
88
+ if (el) el.scrollIntoView({ behavior: 'smooth', block: 'start' });
89
+ }, []);
90
+
91
+ // On first load of the whole-space view, if a page was deep-linked, scroll to it.
92
+ const didLand = useRef(false);
93
+ useEffect(() => {
94
+ if (didLand.current || isSingle || !Array.isArray(docs) || docs.length === 0) return;
95
+ if (type && id) {
96
+ const hit = docs.find(d => docKey(d) === `${type}/${id}`);
97
+ if (hit) { didLand.current = true; setTimeout(() => goTo(hit), 0); }
98
+ }
99
+ }, [docs, isSingle, type, id, goTo]);
100
+
101
+ // Scroll-spy: highlight the TOC entry for the page currently in view (whole-space mode only).
102
+ useEffect(() => {
103
+ if (isSingle || !Array.isArray(docs) || docs.length === 0) return;
104
+ const obs = new IntersectionObserver((entries) => {
105
+ const top = entries.filter(e => e.isIntersecting).sort((a, b) => a.boundingClientRect.top - b.boundingClientRect.top)[0];
106
+ if (top) setSelected(top.target.dataset.pwvKey);
107
+ }, { rootMargin: '-10% 0px -75% 0px', threshold: 0 });
108
+ docs.forEach(d => { const el = document.getElementById(anchorId(d)); if (el) obs.observe(el); });
109
+ return () => obs.disconnect();
110
+ }, [docs, isSingle]);
111
+
72
112
  // [[Wiki links]] jump to another shared page by (case-insensitive) title.
73
113
  const onWikiLink = useCallback((title) => {
74
114
  if (!Array.isArray(docs)) return;
75
115
  const want = String(title).split('#')[0].trim().toLowerCase();
76
116
  const hit = docs.find(d => String(d.title).trim().toLowerCase() === want);
77
- if (hit) setSelected(docKey(hit));
78
- }, [docs]);
117
+ if (hit) goTo(hit);
118
+ }, [docs, goTo]);
119
+
120
+ // The no-auth Markdown-bundle API URL — paste it to an AI agent to read the raw content directly.
121
+ // Single-page link when isolated, whole-space bundle otherwise; drop &format=md for the JSON form.
122
+ const aiLink = isSingle
123
+ ? `${window.location.origin}/v1/organisms/${encodeURIComponent(org)}/workspace/public/document?ws=${encodeURIComponent(ws)}&type=${encodeURIComponent(type)}&id=${encodeURIComponent(id)}&format=md`
124
+ : `${window.location.origin}/v1/organisms/${encodeURIComponent(org)}/workspace/public/documents?ws=${encodeURIComponent(ws)}&format=md`;
125
+ const [copied, setCopied] = useState(false);
126
+ const copyAiLink = useCallback(async () => {
127
+ try {
128
+ await navigator.clipboard.writeText(aiLink);
129
+ setCopied(true);
130
+ setTimeout(() => setCopied(false), 1800);
131
+ } catch { /* clipboard unavailable — ignore */ }
132
+ }, [aiLink]);
79
133
 
80
134
  if (docs === undefined) {
81
135
  return html`<div class="pwv-container"><div class="pwv-state">${t('pwv.loading') || 'Loading…'}</div></div>`;
@@ -105,7 +159,7 @@ export default function PublicWorkspaceViewer() {
105
159
  ${docs.map(d => html`
106
160
  <button
107
161
  class="pwv-toc-item ${docKey(d) === selected ? 'pwv-active' : ''}"
108
- onClick=${() => setSelected(docKey(d))}
162
+ onClick=${() => goTo(d)}
109
163
  >${d.title || d.id}</button>
110
164
  `)}
111
165
  </nav>
@@ -114,12 +168,21 @@ export default function PublicWorkspaceViewer() {
114
168
  <main class="pwv-main">
115
169
  <div class="pwv-bar">
116
170
  <span class="pwv-badge">${t('pwv.publicBadge') || 'Public document'}</span>
117
- <button class="btn-outline btn-sm pwv-print" onClick=${() => window.print()}>
118
- ${t('pwv.print') || 'Print / Save as PDF'}
119
- </button>
171
+ <div class="pwv-bar-actions">
172
+ <button class="btn-outline btn-sm pwv-action" onClick=${copyAiLink}>
173
+ ${copied ? (t('pwv.copied') || 'Copied!') : (t('pwv.copyAiLink') || 'Copy AI link (Markdown)')}
174
+ </button>
175
+ <button class="btn-outline btn-sm pwv-action" onClick=${() => window.print()}>
176
+ ${t('pwv.print') || 'Print / Save as PDF'}
177
+ </button>
178
+ </div>
120
179
  </div>
121
- ${current
122
- ? html`<article class="pwv-doc"><${Markdown} text=${current.markdown || ''} onWikiLink=${onWikiLink} /></article>`
180
+ ${visibleDocs.length > 0
181
+ ? visibleDocs.map(d => html`
182
+ <article class="pwv-doc" id=${anchorId(d)} data-pwv-key=${docKey(d)}>
183
+ <${Markdown} text=${d.markdown || ''} onWikiLink=${onWikiLink} />
184
+ </article>
185
+ `)
123
186
  : html`<div class="pwv-state">${t('pwv.selectDocument') || 'Select a document.'}</div>`
124
187
  }
125
188
  </main>
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../src/cli/connect/mcp/tools/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AA0B7D,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,SAAS,EAAE,QAAQ,EAAE,aAAa,GAAG,IAAI,CAwB9E"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../src/cli/connect/mcp/tools/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AA2B7D,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,SAAS,EAAE,QAAQ,EAAE,aAAa,GAAG,IAAI,CAyB9E"}
@@ -13,6 +13,7 @@ import { registerAppsTools } from './apps.js';
13
13
  import { registerKnowledgeTools } from './knowledge.js';
14
14
  import { registerOrganismsTools } from './organisms.js';
15
15
  import { registerWorkspaceTools } from './workspaces.js';
16
+ import { registerSchedulesTools } from './schedules.js';
16
17
  import { registerConsentTools } from './consent.js';
17
18
  import { registerGroupsTools } from './groups.js';
18
19
  import { registerInstancesTools } from './instances.js';
@@ -37,6 +38,7 @@ export function registerAllTools(mcp, registry) {
37
38
  registerKnowledgeTools(mcp, registry);
38
39
  registerOrganismsTools(mcp, registry);
39
40
  registerWorkspaceTools(mcp, registry);
41
+ registerSchedulesTools(mcp, registry);
40
42
  registerConsentTools(mcp, registry);
41
43
  registerGroupsTools(mcp, registry);
42
44
  registerInstancesTools(mcp, registry);
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../../src/cli/connect/mcp/tools/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../../src/cli/connect/mcp/tools/index.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"organisms.d.ts","sourceRoot":"","sources":["../../../../../../src/cli/connect/mcp/tools/organisms.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAI7D,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,SAAS,EAAE,QAAQ,EAAE,aAAa,GAAG,IAAI,CA0EpF"}
1
+ {"version":3,"file":"organisms.d.ts","sourceRoot":"","sources":["../../../../../../src/cli/connect/mcp/tools/organisms.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAI7D,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,SAAS,EAAE,QAAQ,EAAE,aAAa,GAAG,IAAI,CAsIpF"}