fuli-context 0.12.1 → 0.12.2
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.md +12 -5
- package/README.zh-CN.md +8 -4
- package/dist/web/assets/{index-DO10_fLc.js → index-CxNER7Oo.js} +1 -1
- package/dist/web/index.html +1 -1
- package/docs/client-connections.md +23 -1
- package/graph-provider/pyproject.toml +1 -1
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
- package/src/cli/connect-command.js +6 -3
- package/src/cli/mcp-command.js +4 -2
- package/src/cli/setup-command.js +5 -3
- package/src/mcp/runtime.js +2 -1
- package/src/mcp/tool-profiles.js +36 -0
- package/src/setup/agent-installation-status.js +5 -3
- package/src/setup/agents.js +23 -3
- package/src/setup/claude-desktop-config.js +60 -0
- package/src/setup/client-connection.js +11 -2
- package/src/setup/paths.js +3 -1
- package/src/setup/setup.js +1 -1
- package/src/setup/stable-package-root.js +29 -0
package/README.md
CHANGED
|
@@ -18,8 +18,9 @@
|
|
|
18
18
|
|
|
19
19
|
Fuli is a collaboration layer for long-lived agents across MCP-compatible AI clients. Connect
|
|
20
20
|
your tools to the same accessible Fuli data, select the same agent, and continue with its identity,
|
|
21
|
-
project responsibilities, and relevant working context.
|
|
22
|
-
automatic setup
|
|
21
|
+
project responsibilities, and relevant working context. Use `fuli connect` for standard MCP
|
|
22
|
+
configuration, or automatic setup where a client adapter is available (Codex, Claude Code, Cursor, and Claude
|
|
23
|
+
Desktop with a compact chat tool profile). See [client connections](docs/client-connections.md).
|
|
23
24
|
|
|
24
25
|
- **A lasting teammate:** keep an agent's role, collaboration history, and working memory between tasks.
|
|
25
26
|
- **Context with boundaries:** retrieve relevant project knowledge, decisions, and preferences with
|
|
@@ -28,7 +29,11 @@ automatic setup; other clients use `fuli connect`. See [client connections](docs
|
|
|
28
29
|
an available, authorized host client or executor.
|
|
29
30
|
- **Every task has an owner:** ask for work inside a project directory; Fuli registers the project
|
|
30
31
|
and staffs a lead agent. The reply ends with who led and who helped.
|
|
31
|
-
- **
|
|
32
|
+
- **Three built-in specialists:** Jefa manages projects, Bole handles AR (Agent Resources) for
|
|
33
|
+
recruiting and staffing, and Tonborg helps with judgment. Every space starts with all three.
|
|
34
|
+
- **Judgment guided by your preferences:** [Tonborg](docs/judgment-and-autonomy.md) reviews items
|
|
35
|
+
within your chosen autonomy level and recommends clients and models. Each decision has a log;
|
|
36
|
+
a thumbs up, thumbs down or short reason helps guide future judgments.
|
|
32
37
|
- **Agents talk to each other:** through the [Roundtable](#agent-roundtable), one agent asks another
|
|
33
38
|
conversation directly, and every exchange is recorded.
|
|
34
39
|
|
|
@@ -629,14 +634,16 @@ containers; it does not shut down Rancher Desktop, Docker Desktop, Kubernetes, o
|
|
|
629
634
|
itself. Native mode directly stops the corresponding Provider and Neo4j processes, so no shared VM
|
|
630
635
|
overhead remains while idle.
|
|
631
636
|
|
|
632
|
-
Jefa (project manager)
|
|
637
|
+
Jefa (project manager), Bole (AR, Agent Resources), and Tonborg (judgment) are built-in roles in every
|
|
638
|
+
space and are never hired. Bole's workbench shows staffing, current work, and recruitment history;
|
|
639
|
+
Tonborg's workbench shows decisions and feedback. **Project Agents → Hire an Agent** offers the other reusable employee templates.
|
|
633
640
|
Recruitment reuses a durable identity with separate project assignments. An installed employee workbench,
|
|
634
641
|
API and A2A share the FULI port; existing FULI MCP clients discover and call its tools. Recruitment does not
|
|
635
642
|
start a model or rewrite client settings. See the [employee package and extension contract](docs/employee-agents.md).
|
|
636
643
|
|
|
637
644
|
Project Agent identities remain control-plane records rather than one resident process per identity.
|
|
638
645
|
Roles now keep versioned, project-private working memory in the same Neo4j Provider. Task entry
|
|
639
|
-
restores one owner across
|
|
646
|
+
restores one owner across connected MCP clients; lifecycle checkpoints survive separate
|
|
640
647
|
MCP processes. See [role memory, host hooks and acceptance boundaries](docs/project-agent-memory.md).
|
|
641
648
|
Supported Codex and Claude Code hooks also journal visible conversations. Once unfolded messages pass
|
|
642
649
|
a size threshold (64 KB by default), older ones fold into a digest; recovery stays within a byte budget. Specialist loans and artifact verification share the same Provider.
|
package/README.zh-CN.md
CHANGED
|
@@ -17,14 +17,16 @@
|
|
|
17
17
|
**换 AI 工具,不用换搭档。**
|
|
18
18
|
|
|
19
19
|
复利是跨兼容 MCP 客户端的长期 Agent 协作层。让 AI 工具接入同一份可访问的 Fuli 数据,
|
|
20
|
-
选中同一位 Agent
|
|
21
|
-
|
|
20
|
+
选中同一位 Agent,就能延续它的身份、项目职责和相关工作脉络。运行 `fuli connect` 获取标准
|
|
21
|
+
MCP 配置,有适配器的客户端还支持自动配置(Codex、Claude Code、Cursor,以及使用精简聊天工具集的 Claude
|
|
22
|
+
桌面版)。详见[客户端接入](docs/client-connections.md)。
|
|
22
23
|
|
|
23
24
|
- **搭档留得住:**任务结束后,Agent 的职责、合作记录与工作记忆继续保留。
|
|
24
25
|
- **上下文有边界:**按需取回项目知识、决定与偏好,保留来源、作用域和确认状态。
|
|
25
26
|
- **需要时一起做:**协调不同专长的 Agent,通过可用且获授权的客户端或执行器开展任务,记录真实执行。
|
|
26
27
|
- **每个任务都有负责人:**在项目目录里直接提需求,Fuli 自动登记项目并安排一位负责 Agent;回复最后一行写明谁负责、谁协助。
|
|
27
|
-
-
|
|
28
|
+
- **三位专职随时在岗:**Jefa 管项目,Bole 做 AR(Agent Resources),负责招募与人员安排,Tonborg 帮你做判断;每个空间都自带这三位。
|
|
29
|
+
- **按你的偏好判断:**[Tonborg](docs/judgment-and-autonomy.md) 在你设定的自主程度内协助审核、建议客户端与模型。每次判断都有记录,点赞、点踩或补一句理由,帮助它改进后续判断。
|
|
28
30
|
- **Agent 之间直接对话:**通过[圆桌](#agent-圆桌),一个 Agent 可以直接去问另一段对话里的 Agent,往来全程留痕。
|
|
29
31
|
|
|
30
32
|
这里的“长期”指身份和上下文持续存在。Fuli 负责组织上下文与协调任务,接入的 AI 工具负责执行。
|
|
@@ -559,7 +561,9 @@ start 和 restart 会继续沿用。
|
|
|
559
561
|
Kubernetes 或整台容器虚拟机;原生模式会直接停止对应 Provider 和 Neo4j 进程,因此空闲时
|
|
560
562
|
不再保留共享虚拟机开销。
|
|
561
563
|
|
|
562
|
-
Jefa
|
|
564
|
+
Jefa(项目经理)、Bole(AR,Agent Resources)和 Tonborg(判断者)是每个空间自带的角色,
|
|
565
|
+
不需要招募。Bole 的工作台可查看人员安排、当前工作与招募历史;Tonborg 的工作台可查看判断与反馈。
|
|
566
|
+
“Agents → 聘请 Agent”提供其他可复用的员工模板。招募复用持久身份,
|
|
563
567
|
按项目单独任职;安装员工包后,侧栏工作台与 API/A2A 共用 FULI 端口,已有 FULI MCP 可发现和调用员工工具。
|
|
564
568
|
招募不等于启动模型,也不改写已有客户端配置。详见[员工包安装与扩展协议](docs/employee-agents.md)。
|
|
565
569
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/SharedJefaReportPage-Bg6lIk3E.js","assets/i18n-oJFlt8hW.js","assets/client-DnwnUBQV.js","assets/_plugin-vue_export-helper-BDNMzG2s.js","assets/client-CIuQ1icy.css","assets/useApi-CROJJdhE-7gt0QyQ5.js","assets/shared-report-CiX64ZiD.js","assets/ProjectScopePicker-CiDxM2Yx.js","assets/ProjectScopePicker-DYA7L1Ex.css","assets/shared-report-CGlCpmNd.css","assets/SharedJefaReportPage-D92FSPru.css","assets/RoundtablesPage-L3ShEWS3.js","assets/vue-router-CCvPGaLD.js","assets/RoundtablesPage-Drou-B81.css","assets/OverviewPage-3eZjQ26v.js","assets/console-Cw7TzOSC.js","assets/attention-store-CA5y8j1R.js","assets/profile-model-BQO4zNs9.js","assets/useAgentRoster-B84mzZIg.js","assets/task-evidence-DTiPCs7r.js","assets/paths-CDREouhi.js","assets/agent-work-summary-C-yW7x7A.js","assets/OverviewPage-8LBN8Shi.css","assets/PersonalProfilePage-CDQk096L.js","assets/UiButton-x8hiHNRM.js","assets/UiDialog-mjletK0y.js","assets/UiSelect-K29jnV-1.js","assets/UiSelect-Bv6R0yr1.css","assets/UiSegmented-WFfz9Evl.js","assets/KnowledgeInspector-Cj2yK4Qh.js","assets/UiDisclosure-_IxeiexW.js","assets/model-BJ-UF4cs.js","assets/conversation-launcher-settings-Yc13viwr.js","assets/KnowledgeInspector-pgDELOEf.css","assets/KnowledgeEditDialog-HmiqLC-Y.js","assets/identity-DSGS4CZc.js","assets/KnowledgeEditDialog-hT9znkoe.css","assets/personal-profile-graph-SOK0BR0w.js","assets/PersonalProfilePage-DrMDAAdy.css","assets/WritingTastePage-DCULB-d2.js","assets/WritingTastePage-B_zYD1df.css","assets/PersonalProjectsPage-CJxp4Wyz.js","assets/KnowledgeWorkspace-DA_dqVRG.js","assets/AgentName-DJpvkub2.js","assets/AgentName-BQTFCWn0.css","assets/project-team-api-C_0qJk_B.js","assets/KnowledgeWorkspace-D4a7FcAb.css","assets/KnowledgeOrganizerPage-DT3BROZm.js","assets/KnowledgeOrganizerPage-ccgscrPd.css","assets/AgentsDirectoryPage-CBFTg_IE.js","assets/AgentHand-UzVhbKUC.js","assets/AgentHand-Y83Oo36U.css","assets/agent-pins-DS4mNsNt.js","assets/catalog-D0VEfOAV.js","assets/ProjectAgentFirstTask-BkRJ0zwO.js","assets/ProjectAgentFirstTask-Bi1ZsTC1.css","assets/EmployeeRecruitDialog-D8Hvhc-M.js","assets/EmployeeRecruitDialog-CVbqCzHb.css","assets/AgentsDirectoryPage-Cv-vxw2C.css","assets/agent-profile-Bh3MJGvb.css","assets/AgentProfilePage-CFViQ8kj.js","assets/AgentConversations-Ccy41mEA.js","assets/AgentConversations-XqNEBY_2.css","assets/ProjectAgentsPage-BuNNqSEy.js","assets/ProjectAgentsPage-DWGkgIsr.css","assets/EmployeeWorkbenchPage-TBl_HNj6.js","assets/judgment-types-DR931cZ7.js","assets/EmployeeWorkbenchPage-BQes4L1f.css","assets/PublicProjectsPage-ByOT559r.js","assets/PublicProjectsPage-DKamXDV9.css","assets/KnowledgePage-C4J4VueL.js","assets/ReviewPage-C0Vdr9uq.js","assets/ConnectionsPage-uXcabab_.js","assets/ConnectionsPage-CM9C-zEI.css","assets/SettingsPage-McYuinGz.js","assets/SettingsPage-BE8pWbI6.css","assets/AboutPage-Dized8Uz.js","assets/fuli-logo-Bu9WBuQe.js","assets/AboutPage-c4dQpUiP.css","assets/NotFoundPage-x_Yd59mm.js"])))=>i.map(i=>d[i]);
|
|
2
|
-
import{B as e,E as t,F as n,H as r,I as i,M as a,N as o,P as s,Q as c,R as l,S as u,T as d,V as f,_ as p,a as m,b as h,c as g,et as _,g as v,h as y,i as b,it as x,j as S,m as C,n as w,ot as T,r as E,rt as D,t as O,v as k,w as A,x as j,y as M}from"./i18n-oJFlt8hW.js";import{n as N,t as P}from"./console-Cw7TzOSC.js";import{r as F,s as I}from"./client-DnwnUBQV.js";import{t as L}from"./_plugin-vue_export-helper-BDNMzG2s.js";import{t as R}from"./UiButton-x8hiHNRM.js";import{m as z}from"./useApi-CROJJdhE-7gt0QyQ5.js";import{i as B,n as V,r as H,t as U}from"./vue-router-CCvPGaLD.js";import{t as W}from"./fuli-logo-Bu9WBuQe.js";import{t as ee}from"./UiDialog-mjletK0y.js";import{t as te}from"./UiSelect-K29jnV-1.js";import{n as ne,t as G}from"./attention-store-CA5y8j1R.js";import{t as re}from"./AgentHand-UzVhbKUC.js";import{t as ie}from"./UiDisclosure-_IxeiexW.js";import{n as ae,t as K}from"./profile-model-BQO4zNs9.js";import{t as oe}from"./useAgentRoster-B84mzZIg.js";import{i as se,n as ce,r as q,t as le}from"./agent-pins-DS4mNsNt.js";import{n as ue,t as de}from"./paths-CDREouhi.js";(function(){let e=document.createElement(`link`).relList;if(e&&e.supports&&e.supports(`modulepreload`))return;for(let e of document.querySelectorAll(`link[rel="modulepreload"]`))n(e);new MutationObserver(e=>{for(let t of e)if(t.type===`childList`)for(let e of t.addedNodes)e.tagName===`LINK`&&e.rel===`modulepreload`&&n(e)}).observe(document,{childList:!0,subtree:!0});function t(e){let t={};return e.integrity&&(t.integrity=e.integrity),e.referrerPolicy&&(t.referrerPolicy=e.referrerPolicy),e.crossOrigin===`use-credentials`?t.credentials=`include`:e.crossOrigin===`anonymous`?t.credentials=`omit`:t.credentials=`same-origin`,t}function n(e){if(e.ep)return;e.ep=!0;let n=t(e);fetch(e.href,n)}})();var J={name:`fuli-context`,version:`0.12.
|
|
2
|
+
import{B as e,E as t,F as n,H as r,I as i,M as a,N as o,P as s,Q as c,R as l,S as u,T as d,V as f,_ as p,a as m,b as h,c as g,et as _,g as v,h as y,i as b,it as x,j as S,m as C,n as w,ot as T,r as E,rt as D,t as O,v as k,w as A,x as j,y as M}from"./i18n-oJFlt8hW.js";import{n as N,t as P}from"./console-Cw7TzOSC.js";import{r as F,s as I}from"./client-DnwnUBQV.js";import{t as L}from"./_plugin-vue_export-helper-BDNMzG2s.js";import{t as R}from"./UiButton-x8hiHNRM.js";import{m as z}from"./useApi-CROJJdhE-7gt0QyQ5.js";import{i as B,n as V,r as H,t as U}from"./vue-router-CCvPGaLD.js";import{t as W}from"./fuli-logo-Bu9WBuQe.js";import{t as ee}from"./UiDialog-mjletK0y.js";import{t as te}from"./UiSelect-K29jnV-1.js";import{n as ne,t as G}from"./attention-store-CA5y8j1R.js";import{t as re}from"./AgentHand-UzVhbKUC.js";import{t as ie}from"./UiDisclosure-_IxeiexW.js";import{n as ae,t as K}from"./profile-model-BQO4zNs9.js";import{t as oe}from"./useAgentRoster-B84mzZIg.js";import{i as se,n as ce,r as q,t as le}from"./agent-pins-DS4mNsNt.js";import{n as ue,t as de}from"./paths-CDREouhi.js";(function(){let e=document.createElement(`link`).relList;if(e&&e.supports&&e.supports(`modulepreload`))return;for(let e of document.querySelectorAll(`link[rel="modulepreload"]`))n(e);new MutationObserver(e=>{for(let t of e)if(t.type===`childList`)for(let e of t.addedNodes)e.tagName===`LINK`&&e.rel===`modulepreload`&&n(e)}).observe(document,{childList:!0,subtree:!0});function t(e){let t={};return e.integrity&&(t.integrity=e.integrity),e.referrerPolicy&&(t.referrerPolicy=e.referrerPolicy),e.crossOrigin===`use-credentials`?t.credentials=`include`:e.crossOrigin===`anonymous`?t.credentials=`omit`:t.credentials=`same-origin`,t}function n(e){if(e.ep)return;e.ep=!0;let n=t(e);fetch(e.href,n)}})();var J={name:`fuli-context`,version:`0.12.2`,description:`Local-first collaboration relationship graph for AI agents.`,type:`module`,files:[`README.zh-CN.md`,`npm-shrinkwrap.json`,`src/`,`dist/web/`,`docs/external-knowledge-architecture.md`,`docs/public-personal-architecture.md`,`docs/project-agent-memory.md`,`docs/agent-conversations-and-collaboration.md`,`docs/employee-agents.md`,`docs/agent-interface-architecture.md`,`docs/agent-roundtable.md`,`examples/external-knowledge/markdown-folder.mjs`,`graph-provider/Dockerfile`,`graph-provider/pyproject.toml`,`graph-provider/fuli_graph/*.py`,`graph-provider/fuli_graph/**/*.py`,`skills/`,`compose.graphiti.yml`,`docs/judgment-and-autonomy.md`,`docs/client-connections.md`],bin:{fl:`src/cli.js`,fuli:`src/cli.js`},keywords:[`ai-agent`,`mcp`,`context`,`knowledge-graph`,`local-first`,`codex`,`claude-code`],scripts:{mcp:`node src/mcp-server.js`,dev:`run-p dev:server dev:web`,"dev:server":`node src/server.js`,"dev:web":`vite`,build:`run-s typecheck:web build:web`,"build:web":`vite build`,"build:site":`node scripts/build-site.js`,"typecheck:web":`vue-tsc --noEmit -p tsconfig.app.json`,"test:node":`node --test`,"test:web":`vitest run --config vitest.config.ts`,"test:package":`node scripts/package-smoke.js`,"test:knowledge:live":`node acceptance/knowledge-live.js`,"test:external-knowledge:live":`node scripts/validate-external-knowledge-live.js`,start:`node src/server.js`,"graph:setup":`node src/graphiti/setup.js`,"graph:up":`docker compose -f compose.graphiti.yml up -d --build`,"graph:down":`docker compose -f compose.graphiti.yml down`,"test:structure":`node --test test/source-structure.test.js`,pretest:`npm run build:web`,test:`run-s typecheck:web test:node test:web`,prepack:`npm run build`,prepublishOnly:`npm test`},engines:{node:`>=24.12`},repository:{type:`git`,url:`git+https://github.com/JevonsCode/fuli.git`},homepage:`https://jevonscode.github.io/fuli/`,bugs:{url:`https://github.com/JevonsCode/fuli/issues`},publishConfig:{access:`public`},license:`Apache-2.0`,dependencies:{"@a2a-js/sdk":`1.3.0`,"@hono/node-server":`2.0.12`,"@modelcontextprotocol/sdk":`^1.31.0`,"@peculiar/x509":`2.1.0`,"reflect-metadata":`0.2.2`,zod:`^4.4.3`},devDependencies:{"@types/d3":`^7.4.3`,"@types/node":`^24.13.3`,"@vitejs/plugin-vue":`^6.0.8`,"@vue/test-utils":`^2.4.11`,"brace-expansion":`5.0.12`,d3:`^7.9.0`,jsdom:`^29.1.1`,linkedom:`^0.18.12`,"npm-run-all2":`^9.0.2`,pinia:`^4.0.2`,typescript:`~6.0.0`,vite:`^8.1.5`,vitest:`^4.1.10`,vue:`^3.5.42`,"vue-i18n":`^11.4.8`,"vue-router":`^5.2.0`,"vue-tsc":`^3.3.8`},overrides:{"@modelcontextprotocol/sdk":{"@hono/node-server":`2.0.12`},"brace-expansion":`$brace-expansion`,"fast-uri":`3.1.8`,qs:`6.16.0`}}.version,fe=[`aria-label`],Y={class:`brand-mark-wrap`},pe=[`src`],me={class:`brand-copy`},he={class:`brand-title-row`},ge={class:`brand-name`},_e=[`aria-label`,`aria-expanded`],ve={class:`brand-version`},ye={key:1,class:`brand-version`},be={class:`brand-title-row`},xe={class:`brand-name`},Se={class:`brand-version`},Ce=[`aria-label`],we=[`href`],Te=L(t({__name:`BrandEasterEgg`,setup(e){let t=c(null),n=c(null),r=c(0),i=c(!1),l=c(!1),d=c(!1),f=c(null),p=k(()=>f.value?.status===`ready`&&f.value.updateAvailable&&!!f.value.latestVersion),h=k(()=>f.value?.latestVersion??``),g=k(()=>f.value?.packageUrl??`https://www.npmjs.com/package/fuli-context`),_=new AbortController,v=!1;function b(){r.value+=1,i.value=!0}function C(){i.value=!1}function w(){p.value&&(d.value=!d.value)}function E(e){v=!1,l.value=!1,d.value&&!t.value?.contains(e.target)&&(d.value=!1)}function O(e){e.key===`Tab`&&(v=!0),e.key===`Escape`&&d.value&&(e.preventDefault(),d.value=!1,S(()=>n.value?.focus()))}function A(){l.value=v}function N(){l.value=!1}return o(()=>{window.addEventListener(`pointerdown`,E,!0),window.addEventListener(`keydown`,O,!0),F(`/api/system/version`,{signal:_.signal}).then(e=>{f.value=e}).catch(()=>{})}),a(()=>{_.abort(),window.removeEventListener(`pointerdown`,E,!0),window.removeEventListener(`keydown`,O,!0)}),(e,a)=>(s(),u(`div`,{ref_key:`root`,ref:t,class:x([`brand-block`,{"is-sparkling":i.value,"is-keyboard-focused":l.value}])},[M(`button`,{class:`brand-effect-button`,type:`button`,"aria-label":D(m)(`console.brandEffect.aria`),onClick:b,onFocus:A,onBlur:N},[M(`span`,Y,[M(`img`,{class:`brand-mark`,src:D(W),alt:``,"aria-hidden":`true`},null,8,pe),i.value?(s(),u(`span`,{key:`orbit-${r.value}`,class:`brand-orbit`,"aria-hidden":`true`})):j(``,!0)])],40,fe),M(`span`,me,[M(`span`,he,[M(`span`,ge,T(D(m)(`common.brand`)),1),p.value?(s(),u(`button`,{key:0,ref_key:`versionButton`,ref:n,class:`brand-version-button`,type:`button`,"aria-label":D(m)(`console.update.aria`,{version:h.value}),"aria-expanded":d.value,"aria-controls":`brand-update-details`,onClick:w},[M(`span`,ve,`v`+T(D(J)),1),a[0]||=M(`span`,{class:`brand-update-dot`,"aria-hidden":`true`},null,-1)],8,_e)):(s(),u(`span`,ye,`v`+T(D(J)),1))]),a[1]||=M(`span`,{class:`brand-subtitle`},`Context Graph`,-1),i.value?(s(),u(`span`,{key:`copy-reflection-${r.value}`,class:`brand-copy-reflection`,"aria-hidden":`true`,onAnimationend:y(C,[`self`])},[M(`span`,be,[M(`span`,xe,T(D(m)(`common.brand`)),1),M(`span`,Se,`v`+T(D(J)),1)])],32)):j(``,!0)]),d.value?(s(),u(`div`,{key:0,id:`brand-update-details`,class:`brand-update-popover`,role:`dialog`,"aria-label":D(m)(`console.update.title`,{version:h.value})},[M(`strong`,null,T(D(m)(`console.update.title`,{version:h.value})),1),M(`p`,null,T(D(m)(`console.update.copy`)),1),a[2]||=M(`code`,null,`fuli update --yes`,-1),M(`a`,{href:g.value,target:`_blank`,rel:`noopener noreferrer`},T(D(m)(`console.update.npmLink`)),9,we)],8,Ce)):j(``,!0)],2))}}),[[`__scopeId`,`data-v-68727ec7`]]),Ee=[`aria-label`],De=[`lang`,`aria-label`,`aria-pressed`,`onClick`],Oe=t({__name:`LocaleSwitcher`,setup(e){let t=k(()=>w()),n={"zh-CN":`中`,"en-US":`EN`};function r(e){e!==t.value&&b(e)}return(e,a)=>(s(),u(`div`,{class:`locale-switcher`,role:`group`,"aria-label":D(m)(`common.language.label`)},[(s(!0),u(v,null,i(D(O),e=>(s(),u(`button`,{key:e,type:`button`,lang:e,"aria-label":D(m)(e===`zh-CN`?`common.language.chinese`:`common.language.english`),"aria-pressed":t.value===e,onClick:t=>r(e)},T(n[e]),9,De))),128))],8,Ee))}}),X=_(null);function ke(e){let t=e.onError((t,n)=>{let r=e.resolve(n).href;!r.startsWith(`/`)||r.startsWith(`//`)||(X.value={href:r,resourceFailure:/dynamically imported module|module script|loading chunk|preload css|importing a module/i.test(String(t))})}),n=e.afterEach((e,t,n)=>{n||(X.value=null)});return()=>{t(),n()}}var Ae={key:0,class:`navigation-recovery`,role:`alert`},je=[`href`],Me=L(t({__name:`NavigationRecovery`,setup(e){return(e,t)=>D(X)?(s(),u(`div`,Ae,[M(`div`,null,[M(`strong`,null,T(D(m)(`routes.loadFailure.title`)),1),M(`p`,null,T(D(m)(D(X).resourceFailure?`routes.loadFailure.resources`:`routes.loadFailure.message`)),1)]),M(`a`,{href:D(X).href,class:`quiet-button`},T(D(m)(`routes.loadFailure.reload`)),9,je),M(`button`,{type:`button`,class:`navigation-recovery-dismiss`,onClick:t[0]||=e=>X.value=null},T(D(m)(`routes.loadFailure.dismiss`)),1)])):j(``,!0)}}),[[`__scopeId`,`data-v-d154c242`]]);function Ne(e){let t=e.requestedAction.split(`
|
|
3
3
|
`).map(e=>e.trim()).filter(e=>/^[A-F][.、))::]\s*\S/.test(e));return/(?:选择|选项|choose|select|options?|pick)/iu.test(e.requestedAction)&&t.length>=2&&t.every((e,t)=>e[0]===String.fromCharCode(65+t))?t.map((e,t)=>({id:`option-${t}`,label:e,value:e})):({approval:[`agree`,`decline`],review:[`accept`,`revise`],permission:[`agree`,`decline`],blocked:[`resolved`,`clarify`],question:[`clarify`]}[e.kind]??[`clarify`]).map(e=>({id:e,label:m(`attention.replies.${e}`),value:m(`attention.replies.${e}`)}))}function Pe(e,t,n){if(e===`other`)return t.trim();let r=n.find(t=>t.id===e);return r?[r.value,t.trim()].filter(Boolean).join(`
|
|
4
4
|
|
|
5
5
|
`):``}var Fe={class:`attention-question`},Ie={class:`attention-context`},Le=[`disabled`],Re=[`name`,`value`,`checked`,`onChange`],ze=[`name`,`checked`],Be={class:`attention-input`},Ve=[`for`],He=[`id`,`value`,`required`,`disabled`,`placeholder`],Ue={key:0,role:`alert`,class:`inline-error attention-response-error`},We={key:1,role:`alert`,class:`inline-error`},Ge={class:`attention-submit`},Ke=[`disabled`],qe={key:1},Je=L(t({__name:`AttentionReply`,props:{item:{},modelValue:{},busy:{type:Boolean},refreshing:{type:Boolean},error:{}},emits:[`update:modelValue`,`submit`],setup(e,{emit:t}){let n=e,a=t,o=k(()=>Ne(n.item)),c=k(()=>Pe(n.modelValue.choice,n.modelValue.text,o.value));function l(e){a(`update:modelValue`,{...n.modelValue,...e})}function d(){!n.busy&&!n.refreshing&&c.value&&c.value.length<=4096&&a(`submit`,c.value)}return(t,n)=>(s(),u(`form`,{class:`attention-reply`,onSubmit:y(d,[`prevent`])},[M(`div`,Fe,[M(`h3`,null,T(e.item.title),1),M(`p`,null,T(e.item.requestedAction),1)]),(s(),h(ie,{key:e.item.requestId,title:D(m)(`attention.context`)},{default:r(()=>[M(`p`,Ie,T(e.item.detail),1)]),_:1},8,[`title`])),M(`fieldset`,{disabled:e.busy||e.refreshing,class:`attention-choices`},[M(`legend`,null,T(D(m)(`attention.chooseReply`)),1),(s(!0),u(v,null,i(o.value,t=>(s(),u(`label`,{key:t.id,class:x([`attention-choice`,{"is-selected":e.modelValue.choice===t.id}])},[M(`input`,{type:`radio`,name:`reply-${e.item.requestId}`,value:t.id,checked:e.modelValue.choice===t.id,onChange:e=>l({choice:t.id})},null,40,Re),M(`span`,null,T(t.label),1)],2))),128)),M(`label`,{class:x([`attention-choice`,{"is-selected":e.modelValue.choice===`other`}])},[M(`input`,{type:`radio`,name:`reply-${e.item.requestId}`,value:`other`,checked:e.modelValue.choice===`other`,onChange:n[0]||=e=>l({choice:`other`})},null,40,ze),M(`span`,null,T(D(m)(`attention.other`)),1)],2)],8,Le),M(`div`,Be,[M(`label`,{for:`attention-${e.item.requestId}`},T(e.modelValue.choice===`other`?D(m)(`attention.response`):D(m)(`attention.note`)),9,Ve),M(`textarea`,{id:`attention-${e.item.requestId}`,value:e.modelValue.text,rows:`3`,maxlength:`4096`,required:e.modelValue.choice===`other`,disabled:e.busy||e.refreshing,placeholder:D(m)(`attention.placeholder`),onInput:n[1]||=t=>l({text:t.target.value,choice:e.modelValue.choice||`other`})},null,40,He)]),e.error?(s(),u(`p`,Ue,T(e.error),1)):j(``,!0),c.value.length>4096?(s(),u(`p`,We,T(D(m)(`attention.tooLong`)),1)):j(``,!0),M(`div`,Ge,[M(`p`,null,T(D(m)(`attention.replyHint`)),1),M(`button`,{type:`submit`,class:`primary-action`,disabled:e.busy||e.refreshing||!c.value||c.value.length>4096},[e.busy?(s(),h(I,{key:0,variant:`inline`,label:D(m)(`attention.sending`)},null,8,[`label`])):(s(),u(`span`,qe,T(D(m)(`attention.send`)),1))],8,Ke)])],32))}}),[[`__scopeId`,`data-v-6b64bc2c`]]),Ye=[`aria-label`],Xe={class:`attention-nav-status`},Ze=[`title`],Qe={key:0,role:`alert`,class:`attention-error`},$e={key:2,class:`attention-empty`},et=[`aria-busy`],tt=[`aria-label`],nt={class:`attention-queue-toolbar`},rt={class:`attention-request-list`},it=[`aria-current`,`disabled`,`onClick`],at={class:`attention-request-meta`},ot={class:`attention-request-project`},st={class:`attention-detail-meta`},ct={class:`ui-badge`},lt=[`href`],ut=t({__name:`AgentAttentionCenter`,props:{personalSpaceId:{},projects:{}},setup(t){let n=t,l=ne(),f=c({}),g=c({}),_=c(``),y=c(``),b=0,S=c({}),C=k(()=>S.value[_.value]??``),w=k(()=>l.items.find(e=>e.requestId===_.value)),E=k({get:()=>g.value[_.value]??{choice:``,text:``},set:e=>{w.value&&(g.value[_.value]={...e,revision:w.value.revision})}}),O=k(()=>new Map(n.projects.map(e=>[e.project_id,e.profile.name]))),N=k(()=>l.agentId?l.counts[l.agentId]??l.filteredTotal:l.total),P=k(()=>l.items.map(e=>({value:e.requestId,label:e.title,meta:`${f.value[e.agentId]||m(`attention.agentFallback`)} · ${O.value.get(e.personalProjectId)||m(`attention.projectFallback`)}`})));e(()=>n.personalSpaceId,e=>{b++,y.value=``,f.value={},g.value={},_.value=``,S.value={},l.setSpace(e===`current`?``:e)},{immediate:!0}),e(()=>l.open,async e=>{if(!e)return;let t=l.spaceId;try{let e=await F(`/api/project-agents?${new URLSearchParams({personalSpaceId:t})}`);t===l.spaceId&&(f.value=Object.fromEntries(e.map(e=>[e.agentId,e.profile.displayName||e.profile.name])))}catch{}}),e(()=>l.items,e=>{e.some(e=>e.requestId===_.value)||(_.value=e[0]?.requestId??``);for(let t of e){let e=g.value[t.requestId];e&&e.revision!==t.revision&&(g.value[t.requestId]={choice:``,text:e.text,revision:t.revision},S.value[t.requestId]=m(`attention.updated`))}});let L;function z(){document.visibilityState===`visible`&&!l.loading&&!l.open&&l.refresh()}o(()=>{L=setInterval(z,3e4),document.addEventListener(`visibilitychange`,z)}),a(()=>{clearInterval(L),document.removeEventListener(`visibilitychange`,z),l.setSpace(``)});async function B(e,t){if(y.value||!t.trim()||t.length>4096)return;let n=l.spaceId,r=++b;y.value=e.requestId,delete S.value[e.requestId];try{await l.respond(e,t),r===b&&n===l.spaceId&&delete g.value[e.requestId]}catch(t){r===b&&n===l.spaceId&&(S.value[e.requestId]=t instanceof Error?t.message:String(t),await l.refresh())}finally{r===b&&(y.value=``)}}return(e,t)=>(s(),u(v,null,[M(`button`,{class:`space-nav-button attention-nav`,"aria-label":D(l).total?`${D(m)(`attention.title`)} · ${D(m)(`attention.count`,{count:D(l).total})}`:D(m)(`attention.title`),type:`button`,onClick:t[0]||=e=>D(l).show()},[t[9]||=M(`span`,{class:`nav-icon nav-icon-review`,"aria-hidden":`true`},null,-1),M(`span`,null,T(D(m)(`attention.title`)),1),M(`span`,Xe,[d(re,{passive:``,"count-only":``}),D(l).error?(s(),u(`span`,{key:0,title:D(m)(`attention.loadError`)},`!`,8,Ze)):j(``,!0)])],8,Ye),(s(),h(p,{to:`body`},[d(ee,{open:D(l).open,class:`attention-dialog`,size:`xl`,busy:!!y.value,title:D(m)(`attention.title`),description:N.value?D(m)(`attention.count`,{count:N.value}):void 0,onClose:t[8]||=e=>D(l).open=!1},{default:r(()=>[D(l).error?(s(),u(`div`,Qe,[M(`span`,null,T(D(m)(`attention.loadError`)),1),d(R,{size:`sm`,disabled:D(l).loading,onClick:t[1]||=e=>D(l).refresh()},{default:r(()=>[A(T(D(m)(`attention.refresh`)),1)]),_:1},8,[`disabled`])])):j(``,!0),D(l).loading&&!D(l).items.length?(s(),h(I,{key:1,variant:`page`,label:D(m)(`attention.loading`)},null,8,[`label`])):!D(l).items.length&&!D(l).error?(s(),u(`div`,$e,[t[10]||=M(`span`,{"aria-hidden":`true`},`✓`,-1),M(`p`,null,T(D(m)(`attention.empty`)),1)])):D(l).items.length?(s(),u(`div`,{key:3,class:`attention-workspace`,"aria-busy":D(l).loading},[M(`aside`,{class:`attention-queue`,"aria-label":D(m)(`attention.queue`)},[M(`div`,nt,[M(`span`,null,T(D(l).agentId?f.value[D(l).agentId]||D(m)(`attention.agentFallback`):D(m)(`attention.all`)),1),D(l).agentId||!D(l).error?(s(),h(R,{key:0,size:`sm`,variant:`ghost`,disabled:D(l).loading||!!y.value,onClick:t[2]||=e=>D(l).agentId?D(l).show():D(l).refresh()},{default:r(()=>[A(T(D(l).agentId?D(m)(`attention.all`):D(m)(`attention.refresh`)),1)]),_:1},8,[`disabled`])):j(``,!0)]),d(te,{modelValue:_.value,"onUpdate:modelValue":t[3]||=e=>_.value=e,class:`attention-mobile-picker`,field:``,label:D(m)(`attention.selectRequest`),options:P.value,disabled:!!y.value},null,8,[`modelValue`,`label`,`options`,`disabled`]),M(`div`,rt,[(s(!0),u(v,null,i(D(l).items,e=>(s(),u(`button`,{key:e.requestId,type:`button`,class:x([`attention-request`,{"is-selected":_.value===e.requestId}]),"aria-current":_.value===e.requestId?`true`:void 0,disabled:!!y.value,onClick:t=>_.value=e.requestId},[M(`span`,at,[A(T(f.value[e.agentId]||D(m)(`attention.agentFallback`)),1),M(`span`,null,T(D(m)(`attention.kinds.${e.kind}`)),1)]),M(`strong`,null,T(e.title),1),M(`span`,ot,T(O.value.get(e.personalProjectId)||D(m)(`attention.projectFallback`)),1)],10,it))),128))]),D(l).items.length<D(l).filteredTotal?(s(),h(R,{key:0,class:`attention-more`,disabled:D(l).loading||!!y.value,onClick:t[4]||=e=>D(l).more()},{default:r(()=>[A(T(D(m)(`attention.more`)),1)]),_:1},8,[`disabled`])):j(``,!0)],8,tt),w.value?(s(),u(`section`,{key:w.value.requestId,class:`attention-detail`},[M(`div`,st,[M(`span`,null,T(f.value[w.value.agentId]||D(m)(`attention.agentFallback`))+` · `+T(O.value.get(w.value.personalProjectId)||D(m)(`attention.projectFallback`)),1),M(`span`,ct,T(D(m)(`attention.kinds.${w.value.kind}`)),1)]),d(Je,{modelValue:E.value,"onUpdate:modelValue":t[5]||=e=>E.value=e,item:w.value,busy:y.value===w.value.requestId,refreshing:D(l).loading,error:C.value,onSubmit:t[6]||=e=>B(w.value,e)},null,8,[`modelValue`,`item`,`busy`,`refreshing`,`error`]),w.value.taskId&&!y.value?(s(),u(`a`,{key:0,class:`attention-task-link`,href:D(G)(w.value),onClick:t[7]||=e=>D(l).open=!1},T(D(m)(`attention.task`))+` ↗`,9,lt)):j(``,!0)])):j(``,!0)],8,et)):j(``,!0)]),_:1},8,[`open`,`busy`,`title`,`description`])]))],64))}}),dt={key:0,class:`pinned-agents-nav`,"aria-labelledby":`pinned-agents-heading`},ft={class:`pinned-agents-heading-row`},pt={id:`pinned-agents-heading`,class:`pinned-agents-heading`},mt={class:`pinned-agents-list`},ht={class:`pinned-agent-portrait`,"aria-hidden":`true`},gt={class:`pinned-agent-name`},_t={key:1,class:`pinned-agents-error`,role:`alert`},vt=L(t({__name:`PinnedAgentsNav`,props:{spaceId:{},agents:{},pinnedAgentIds:{},loading:{type:Boolean},rosterLoading:{type:Boolean},error:{}},emits:[`retry`],setup(e,{emit:t}){let n=e,a=t,o=k(()=>n.pinnedAgentIds.map(e=>n.agents.find(t=>t.agentId===e)).filter(e=>!!e));function c(e,t){return q(e,t)}let l=k(()=>c(`navigation.title`,`pin`)),f=k(()=>c(`loading`,`Reading pinned Agents…`)),p=k(()=>m(`agentProfiles.loading`)),g=k(()=>c(`retry`,`Retry`)),_=k(()=>n.loading||!!n.rosterLoading);return(t,c)=>(s(),u(v,null,[e.spaceId&&o.value.length?(s(),u(`section`,dt,[M(`div`,ft,[M(`h2`,pt,T(l.value),1),_.value&&o.value.length?(s(),h(I,{key:0,variant:`inline`,label:n.rosterLoading&&!n.loading?p.value:f.value},null,8,[`label`])):j(``,!0)]),M(`ul`,mt,[(s(!0),u(v,null,i(o.value,t=>(s(),u(`li`,{key:t.agentId},[d(D(U),{class:`pinned-agent-nav`,to:D(ae)(e.spaceId,t.agentId),"aria-label":`${D(K)(t)} · ${D(m)(`agentProfiles.profile`)}`},{default:r(()=>[M(`span`,ht,T(t.profile.occupationEmoji||D(K)(t).slice(0,1)),1),M(`span`,gt,T(D(K)(t)),1)]),_:2},1032,[`to`,`aria-label`])]))),128))])])):j(``,!0),e.spaceId&&e.error?(s(),u(`div`,_t,[M(`span`,null,T(e.error),1),M(`button`,{class:`quiet-button`,type:`button`,onClick:c[0]||=e=>a(`retry`)},T(g.value),1)])):j(``,!0)],64))}}),[[`__scopeId`,`data-v-45d6ccab`]]),yt=[`routes.`,`common.`,`employees.`,`agentProfiles.`];function bt(e,t=``){let n=typeof e==`string`&&e?e:t;return yt.some(e=>n.startsWith(e))?m(n):n}function xt(e){if(typeof document>`u`)return;let t=bt(e,`routes.overview.title`);document.title=`${t} · ${m(`common.brand`)}`}var St={class:`app-shell`},Ct=[`onKeydown`],wt=[`aria-label`,`title`],Tt=[`aria-label`],Et={class:`nav-label`},Dt={class:`nav-label`},Ot={class:`nav-label`},kt={class:`nav-label`},At={class:`nav-label`},jt={class:`nav-label`},Mt={class:`nav-section-label`},Nt={class:`nav-label`},Pt={class:`nav-label`},Ft={class:`nav-label`},It={class:`nav-label`},Lt={class:`nav-label`},Rt={class:`nav-label`},zt={class:`sidebar-foot`},Bt=[`aria-label`],Vt={class:`runtime-status`},Ht={class:`service-details`},Ut={class:`runtime-status`},Wt=[`aria-label`],Gt=[`inert`],Kt=[`aria-expanded`,`aria-label`],qt={key:0,class:`workbench-host-label`},Jt={key:1,class:`topbar-heading`},Yt={key:2,class:`topbar-actions`},Xt=[`aria-label`],Zt=L(t({__name:`ConsoleLayout`,setup(t){let i=P(),p=z(),g=c(!1),_=c(null),v=c(null),b=k(()=>i.activePersonalSpace?.id??``),w=k(()=>b.value||`current`),E=k(()=>ue(w.value,`graph`)),O=k(()=>de(`personal`,w.value,`directory`)),N=oe(b),F=se(b),I=N.agents,L=N.loading,B=N.error,H=F.agentIds,W=F.loading,ee=F.error,te=k(()=>ee.value||B.value);n(ce,N),n(le,F);let ne=k(()=>bt(p.meta.title,`routes.overview.title`)),G=k(()=>p.meta.dedicatedWorkspace===!0),re=k(()=>i.publicRuntimeStatus===`ready`?m(`console.services.publicReady`):i.publicRuntimeStatus===`error`?m(`console.services.publicError`):m(`console.services.publicOffline`)),ie=k(()=>{if(i.publicRuntimeStatus===`ready`){let e=i.state?.capabilities;return e?.browsePublicProjects&&e?.subscribeProject&&!e?.publishProject&&!e?.submitKnowledge&&!e?.reviewProposals?m(`console.services.publicBrowseSubscribe`):m(`console.services.publicAvailable`)}return i.publicRuntimeStatus===`error`?m(`console.services.localUnaffected`):m(`console.services.localOnly`)}),ae=k(()=>i.state?.capabilities?.browsePublicProjects!==!1),K=k(()=>{let e=i.state?.capabilities;return e?.submitKnowledge!==!1||e?.reviewProposals===!0});o(()=>{i.runtimeStatus===`idle`&&i.refresh(),window.addEventListener(`resize`,q)}),a(()=>window.removeEventListener(`resize`,q));function q(){window.innerWidth>920&&(g.value=!1)}function J(e){if(!g.value||e.key!==`Tab`)return;let t=[...e.currentTarget.querySelectorAll(`button:not(:disabled), a[href], input:not(:disabled), [tabindex="0"]`)].filter(e=>e.getClientRects().length>0),n=t[0],r=t.at(-1);e.shiftKey&&document.activeElement===n?(e.preventDefault(),r?.focus()):!e.shiftKey&&document.activeElement===r&&(e.preventDefault(),n?.focus())}f(()=>{xt(p.meta.title)}),e(()=>p.fullPath,()=>{g.value=!1});async function fe(){g.value=!0,await S(),v.value?.focus({preventScroll:!0})}async function Y(){g.value=!1,await S(),_.value?.focus({preventScroll:!0})}function pe(){Promise.all([N.load(),F.load({force:!0})])}return(e,t)=>(s(),u(`div`,St,[M(`aside`,{id:`console-primary-sidebar`,class:x([`sidebar`,{"is-mobile-open":g.value}]),onKeydown:[C(y(Y,[`stop`]),[`esc`]),J]},[M(`button`,{ref_key:`mobileNavCloseRef`,ref:v,class:`mobile-nav-close quiet-button`,type:`button`,"aria-label":D(m)(`console.navigation.closeMenu`),title:D(m)(`console.navigation.closeMenu`),onClick:Y},[...t[1]||=[M(`span`,{class:`mobile-nav-close-icon`,"aria-hidden":`true`},null,-1)]],8,wt),d(Te),M(`nav`,{class:`primary-nav`,"aria-label":D(m)(`console.navigation.aria`)},[d(D(U),{to:`/`,"exact-active-class":`is-active`},{default:r(()=>[t[2]||=M(`span`,{class:`nav-icon nav-icon-overview`,"aria-hidden":`true`},null,-1),M(`span`,Et,T(D(m)(`console.navigation.overview`)),1)]),_:1}),d(D(U),{to:`/project-agents`,"active-class":`is-active`},{default:r(()=>[t[3]||=M(`span`,{class:`nav-icon nav-icon-project-agent`,"aria-hidden":`true`},null,-1),M(`span`,Dt,T(D(m)(`console.navigation.projectAgents`)),1)]),_:1}),d(ut,{"personal-space-id":w.value,projects:D(i).state?.personalProjects??[]},null,8,[`personal-space-id`,`projects`]),d(D(U),{to:`/roundtables`,"active-class":`is-active`},{default:r(()=>[t[4]||=M(`span`,{class:`nav-icon nav-icon-roundtable`,"aria-hidden":`true`},null,-1),M(`span`,Ot,T(D(m)(`console.navigation.roundtables`)),1)]),_:1}),d(D(U),{to:E.value,"active-class":`is-active`},{default:r(()=>[t[5]||=M(`span`,{class:`nav-icon nav-icon-personal-project`,"aria-hidden":`true`},null,-1),M(`span`,kt,T(D(m)(`console.navigation.personalProjects`)),1)]),_:1},8,[`to`]),d(D(U),{to:`/preferences`,"active-class":`is-active`},{default:r(()=>[t[6]||=M(`span`,{class:`nav-icon nav-icon-personal-profile`,"aria-hidden":`true`},null,-1),M(`span`,At,T(D(m)(`console.navigation.preferences`)),1)]),_:1}),d(D(U),{to:O.value,"active-class":`is-active`},{default:r(()=>[t[7]||=M(`span`,{class:`nav-icon nav-icon-knowledge-graph`,"aria-hidden":`true`},null,-1),M(`span`,jt,T(D(m)(`console.navigation.knowledge`)),1)]),_:1},8,[`to`]),d(vt,{"space-id":b.value,agents:D(I),"pinned-agent-ids":D(H),loading:D(W),"roster-loading":D(L),error:te.value,onRetry:pe},null,8,[`space-id`,`agents`,`pinned-agent-ids`,`loading`,`roster-loading`,`error`]),M(`p`,Mt,T(D(m)(`console.navigation.more`)),1),d(D(U),{to:`/organize`,"active-class":`is-active`},{default:r(()=>[t[8]||=M(`span`,{class:`nav-icon nav-icon-knowledge-organizer`,"aria-hidden":`true`},null,-1),M(`span`,Nt,T(D(m)(`console.navigation.organizer`)),1)]),_:1}),K.value?(s(),h(D(U),{key:0,to:`/review`,"active-class":`is-active`},{default:r(()=>[t[9]||=M(`span`,{class:`nav-icon nav-icon-review`,"aria-hidden":`true`},null,-1),M(`span`,Pt,T(D(m)(`console.navigation.review`)),1)]),_:1})):j(``,!0),ae.value?(s(),h(D(U),{key:1,to:`/public-projects`,"active-class":`is-active`},{default:r(()=>[t[10]||=M(`span`,{class:`nav-icon nav-icon-public-project`,"aria-hidden":`true`},null,-1),M(`span`,Ft,T(D(m)(`console.navigation.publicProjects`)),1)]),_:1})):j(``,!0),d(D(U),{to:`/connections`,"active-class":`is-active`},{default:r(()=>[t[11]||=M(`span`,{class:`nav-icon nav-icon-connections`,"aria-hidden":`true`},null,-1),M(`span`,It,T(D(m)(`console.navigation.connections`)),1)]),_:1}),d(D(U),{to:`/settings`,"active-class":`is-active`},{default:r(()=>[t[12]||=M(`span`,{class:`nav-icon nav-icon-settings`,"aria-hidden":`true`},null,-1),M(`span`,Lt,T(D(m)(`console.navigation.settings`)),1)]),_:1}),d(D(U),{to:`/about`,"active-class":`is-active`},{default:r(()=>[t[13]||=M(`span`,{class:`nav-icon nav-icon-about`,"aria-hidden":`true`},null,-1),M(`span`,Rt,T(D(m)(`console.navigation.about`)),1)]),_:1})],8,Tt),M(`div`,zt,[M(`div`,{class:`service-runtime-list`,"aria-label":D(m)(`console.services.aria`)},[M(`div`,Vt,[M(`span`,{class:x([`status-dot`,D(i).runtimeStatus])},null,2),M(`div`,null,[M(`strong`,null,T(D(i).runtimeStatus===`ready`?D(m)(`console.services.localReady`):D(i).runtimeStatus===`error`?D(m)(`console.services.localError`):D(m)(`console.services.localConnecting`)),1)])]),M(`details`,Ht,[M(`summary`,null,[M(`span`,{class:x([`status-dot`,D(i).publicRuntimeStatus])},null,2),A(T(re.value),1)]),M(`div`,Ut,[M(`div`,null,[M(`small`,null,T(ie.value),1),d(D(U),{to:`/connections`},{default:r(()=>[A(T(D(m)(`console.navigation.connections`)),1)]),_:1})])])])],8,Bt)])],42,Ct),g.value?(s(),u(`button`,{key:0,class:`mobile-nav-backdrop`,type:`button`,tabindex:`-1`,"aria-label":D(m)(`console.navigation.closeMenu`),onClick:Y},null,8,Wt)):j(``,!0),M(`main`,{class:`workspace`,inert:g.value||void 0},[M(`header`,{class:x([`topbar`,{"topbar--workbench":G.value}])},[M(`button`,{ref_key:`mobileNavToggleRef`,ref:_,class:`mobile-nav-toggle quiet-button`,type:`button`,"aria-controls":`console-primary-sidebar`,"aria-expanded":g.value,"aria-label":D(m)(`console.navigation.openMenu`),onClick:fe},[...t[14]||=[M(`span`,{class:`mobile-nav-icon`,"aria-hidden":`true`},null,-1)]],8,Kt),G.value?(s(),u(`span`,qt,`FULI`)):(s(),u(`div`,Jt,[M(`h1`,null,T(ne.value),1)])),G.value?j(``,!0):(s(),u(`div`,Yt,[D(p).name===`settings`?(s(),h(R,{key:0,variant:`primary`,disabled:D(i).settingsSaving,form:`settings-form`,type:`submit`},{default:r(()=>[A(T(D(m)(`settings.save`)),1)]),_:1},8,[`disabled`])):j(``,!0),d(Oe),d(R,{variant:`ghost`,icon:``,disabled:D(i).runtimeStatus===`loading`,"aria-label":D(m)(`common.actions.refresh`),title:D(m)(`common.actions.refresh`),onClick:D(i).refresh},{default:r(()=>[...t[15]||=[M(`svg`,{viewBox:`0 0 20 20`,width:`18`,height:`18`,fill:`none`,stroke:`currentColor`,"stroke-width":`1.5`,"stroke-linecap":`round`,"stroke-linejoin":`round`,"aria-hidden":`true`},[M(`path`,{d:`M16 7a6.5 6.5 0 1 0 .5 5M16 3v4h-4`})],-1)]]),_:1},8,[`disabled`,`aria-label`,`title`,`onClick`])]))],2),d(Me),D(i).feedback?(s(),u(`div`,{key:0,class:x([`feedback feedback-message`,{success:D(i).feedback.tone===`success`}]),role:`status`,"aria-live":`polite`},[M(`span`,null,T(D(i).feedback.message),1),M(`button`,{class:`feedback-dismiss`,type:`button`,"aria-label":D(m)(`common.actions.close`),onClick:t[0]||=(...e)=>D(i).clearFeedback&&D(i).clearFeedback(...e)},`×`,8,Xt)],2)):j(``,!0),d(D(V),null,{default:r(({Component:e})=>[(s(),h(l(e)))]),_:1})],8,Gt)]))}}),[[`__scopeId`,`data-v-2ba97143`]]),Qt=t({__name:`App`,setup(e){let t=z();return(e,n)=>D(t).meta.publicReport?(s(),h(D(V),{key:0})):(s(),h(Zt,{key:1}))}}),$t=`modulepreload`,en=function(e){return`/`+e},tn={},Z=function(e,t,n){let r=Promise.resolve();if(t&&t.length>0){let e=document.getElementsByTagName(`link`),i=document.querySelector(`meta[property=csp-nonce]`),a=i?.nonce||i?.getAttribute(`nonce`);function o(e){return Promise.all(e.map(e=>Promise.resolve(e).then(e=>({status:`fulfilled`,value:e}),e=>({status:`rejected`,reason:e}))))}function s(e){return import.meta.resolve?import.meta.resolve(e):new URL(e,import.meta.url).href}r=o(t.map(t=>{if(t=en(t,n),t=s(t),t in tn)return;tn[t]=!0;let r=t.endsWith(`.css`);for(let n=e.length-1;n>=0;n--){let i=e[n];if(i.href===t&&(!r||i.rel===`stylesheet`))return}let i=document.createElement(`link`);if(i.rel=r?`stylesheet`:$t,r||(i.as=`script`),i.crossOrigin=``,i.href=t,a&&i.setAttribute(`nonce`,a),document.head.appendChild(i),r)return new Promise((e,n)=>{i.addEventListener(`load`,e),i.addEventListener(`error`,()=>n(Error(`Unable to preload CSS for ${t}`)))})}))}function i(e){let t=new Event(`vite:preloadError`,{cancelable:!0});if(t.payload=e,window.dispatchEvent(t),!t.defaultPrevented)throw e}return r.then(t=>{for(let e of t||[])e.status===`rejected`&&i(e.reason);return e().catch(i)})};function nn(e){let t=e.match(/^#\/knowledge\/([^/?#]+)\/([^/?#]+)\/(entity|relationship)\/([^/?#]+)(?:\?([^#]*))?$/);if(!t)return null;let[,n,r,i,a,o]=t;return`/knowledge/${n}/${r}/directory/${i}/${a}${o?`?${o}`:``}`}var Q=H({history:B(`/`),routes:[{path:`/reports/jefa`,name:`shared-jefa-report`,component:()=>Z(()=>import(`./SharedJefaReportPage-Bg6lIk3E.js`),__vite__mapDeps([0,1,2,3,4,5,6,7,8,9,10])),meta:{publicReport:!0,title:`employees.share.title`}},{path:`/roundtables/:threadId?`,name:`roundtables`,component:()=>Z(()=>import(`./RoundtablesPage-L3ShEWS3.js`),__vite__mapDeps([11,1,2,3,4,5,12,13])),meta:{title:`routes.roundtable.title`}},{path:`/`,name:`overview`,component:()=>Z(()=>import(`./OverviewPage-3eZjQ26v.js`),__vite__mapDeps([14,1,15,2,3,4,12,5,16,17,18,19,20,21,22])),meta:{eyebrow:``,title:`routes.overview.title`}},{path:`/preferences`,name:`personal-profile`,component:()=>Z(()=>import(`./PersonalProfilePage-CDQk096L.js`),__vite__mapDeps([23,1,15,2,3,4,24,12,5,25,26,27,28,29,30,31,32,33,34,35,36,37,38])),meta:{eyebrow:`PERSONAL LENS`,title:`routes.preferences.title`,description:`routes.preferences.description`}},{path:`/preferences/writing`,name:`writing-taste`,component:()=>Z(()=>import(`./WritingTastePage-DCULB-d2.js`),__vite__mapDeps([39,1,15,2,3,4,12,5,30,34,24,25,26,27,35,31,36,37,40])),meta:{eyebrow:``,title:`routes.writingTaste.title`}},{path:`/personal/:spaceId/projects/:projectId/:mode/:itemKind/:itemId`,name:`personal-project-item`,component:()=>Z(()=>import(`./PersonalProjectsPage-CJxp4Wyz.js`),__vite__mapDeps([41,1,42,15,2,3,4,24,5,12,25,26,27,30,20,43,17,44,45,35,29,31,32,33,34,36,46])),meta:{eyebrow:`PERSONAL PROJECT`,title:`routes.personalProjects.title`}},{path:`/personal/:spaceId/projects/:mode/:itemKind/:itemId`,name:`personal-projects-item`,component:()=>Z(()=>import(`./PersonalProjectsPage-CJxp4Wyz.js`),__vite__mapDeps([41,1,42,15,2,3,4,24,5,12,25,26,27,30,20,43,17,44,45,35,29,31,32,33,34,36,46])),meta:{eyebrow:`PERSONAL PROJECTS`,title:`routes.personalProjects.title`,description:`routes.personalProjects.description`}},{path:`/personal/:spaceId/projects/:mode`,name:`personal-projects`,component:()=>Z(()=>import(`./PersonalProjectsPage-CJxp4Wyz.js`),__vite__mapDeps([41,1,42,15,2,3,4,24,5,12,25,26,27,30,20,43,17,44,45,35,29,31,32,33,34,36,46])),meta:{eyebrow:`PERSONAL PROJECTS`,title:`routes.personalProjects.title`,description:`routes.personalProjects.description`}},{path:`/personal/:spaceId/projects/:projectId/:mode`,name:`personal-project`,component:()=>Z(()=>import(`./PersonalProjectsPage-CJxp4Wyz.js`),__vite__mapDeps([41,1,42,15,2,3,4,24,5,12,25,26,27,30,20,43,17,44,45,35,29,31,32,33,34,36,46])),meta:{eyebrow:`PERSONAL PROJECT`,title:`routes.personalProjects.title`}},{path:`/organize`,name:`knowledge-organizer`,component:()=>Z(()=>import(`./KnowledgeOrganizerPage-DT3BROZm.js`),__vite__mapDeps([47,1,15,2,3,4,24,25,26,27,35,29,30,31,32,33,34,36,48])),meta:{eyebrow:`KNOWLEDGE CLASSIFICATION`,title:`routes.organizer.title`}},{path:`/project-agents`,name:`project-agents`,component:()=>Z(()=>import(`./AgentsDirectoryPage-CBFTg_IE.js`),__vite__mapDeps([49,1,15,2,3,4,5,12,26,27,50,16,51,17,52,18,19,21,53,54,55,56,24,25,20,7,8,57,58,59])),meta:{eyebrow:``,title:`routes.projectAgents.title`}},{path:`/agents/:spaceId/:agentId`,name:`agent-profile`,component:()=>Z(()=>import(`./AgentProfilePage-CFViQ8kj.js`),__vite__mapDeps([60,1,15,2,3,4,5,12,26,27,30,17,19,18,20,43,44,61,62,21,53,45,59])),meta:{eyebrow:``,title:`agentProfiles.profile`}},{path:`/project-agents/manage`,name:`agent-management`,component:()=>Z(()=>import(`./ProjectAgentsPage-BuNNqSEy.js`),__vite__mapDeps([63,1,15,2,3,4,24,5,12,25,26,27,50,16,51,19,61,62,21,53,54,55,7,8,56,20,57,64])),meta:{eyebrow:``,title:`agentProfiles.advanced`}},{path:`/employees/:templateId`,name:`employee-workbench`,component:()=>Z(()=>import(`./EmployeeWorkbenchPage-TBl_HNj6.js`),__vite__mapDeps([65,1,15,2,3,4,24,5,12,25,26,27,50,16,51,17,43,44,53,7,8,56,20,57,6,9,28,66,67])),meta:{eyebrow:``,title:`routes.employeeWorkbench.title`,dedicatedWorkspace:!0}},{path:`/public-projects`,name:`public-projects`,component:()=>Z(()=>import(`./PublicProjectsPage-ByOT559r.js`),__vite__mapDeps([68,1,15,2,3,4,24,5,25,26,27,20,35,69])),meta:{eyebrow:`PUBLIC PROJECTS`,title:`routes.publicProjects.title`,description:`routes.publicProjects.description`}},{path:`/knowledge`,name:`knowledge-default`,component:()=>Z(()=>import(`./KnowledgePage-C4J4VueL.js`),__vite__mapDeps([70,1,42,15,2,3,4,24,5,12,25,26,27,30,20,43,17,44,45,35,29,31,32,33,34,36,46])),meta:{eyebrow:`KNOWLEDGE BASE`,title:`routes.knowledge.title`}},{path:`/knowledge/:scope/:spaceId/:projectId/:mode/:itemKind/:itemId`,name:`project-knowledge-item`,component:()=>Z(()=>import(`./KnowledgePage-C4J4VueL.js`),__vite__mapDeps([70,1,42,15,2,3,4,24,5,12,25,26,27,30,20,43,17,44,45,35,29,31,32,33,34,36,46])),meta:{eyebrow:`KNOWLEDGE BASE`,title:`routes.knowledge.title`}},{path:`/knowledge/:scope/:spaceId/:mode/:itemKind/:itemId`,name:`knowledge-item`,component:()=>Z(()=>import(`./KnowledgePage-C4J4VueL.js`),__vite__mapDeps([70,1,42,15,2,3,4,24,5,12,25,26,27,30,20,43,17,44,45,35,29,31,32,33,34,36,46])),meta:{eyebrow:`KNOWLEDGE BASE`,title:`routes.knowledge.title`}},{path:`/knowledge/:scope/:spaceId/:projectId/:mode`,name:`project-knowledge`,component:()=>Z(()=>import(`./KnowledgePage-C4J4VueL.js`),__vite__mapDeps([70,1,42,15,2,3,4,24,5,12,25,26,27,30,20,43,17,44,45,35,29,31,32,33,34,36,46])),meta:{eyebrow:`KNOWLEDGE BASE`,title:`routes.knowledge.title`}},{path:`/knowledge/:scope/:spaceId/:mode`,name:`knowledge`,component:()=>Z(()=>import(`./KnowledgePage-C4J4VueL.js`),__vite__mapDeps([70,1,42,15,2,3,4,24,5,12,25,26,27,30,20,43,17,44,45,35,29,31,32,33,34,36,46])),meta:{eyebrow:`KNOWLEDGE BASE`,title:`routes.knowledge.title`}},{path:`/review`,name:`review`,component:()=>Z(()=>import(`./ReviewPage-C0Vdr9uq.js`),__vite__mapDeps([71,1,15,2,3,4,26,27,35,31])),meta:{eyebrow:`REVIEW WORKSPACE`,title:`routes.review.title`,description:`routes.review.description`}},{path:`/connections`,name:`connections`,component:()=>Z(()=>import(`./ConnectionsPage-uXcabab_.js`),__vite__mapDeps([72,1,15,2,3,4,26,27,30,35,73])),meta:{eyebrow:`SERVICE CONNECTIONS`,title:`routes.connections.title`,description:`routes.connections.description`}},{path:`/settings`,name:`settings`,component:()=>Z(()=>import(`./SettingsPage-McYuinGz.js`),__vite__mapDeps([74,1,15,2,3,4,24,26,27,30,66,32,75])),meta:{eyebrow:``,title:`routes.settings.title`}},{path:`/about`,name:`about`,component:()=>Z(()=>import(`./AboutPage-Dized8Uz.js`),__vite__mapDeps([76,1,3,77,78])),meta:{eyebrow:`FULI`,title:`routes.about.title`}},{path:`/:pathMatch(.*)*`,name:`not-found`,component:()=>Z(()=>import(`./NotFoundPage-x_Yd59mm.js`),__vite__mapDeps([79,1,12,5])),meta:{title:`common.errors.pageNotFound`}}],scrollBehavior:(e,t,n)=>n??(e.path!==t.path&&{top:0})});ke(Q),Q.beforeEach(e=>e.path!==`/`||typeof window>`u`?!0:nn(window.location.hash)??!0),Q.afterEach(e=>{xt(e.meta.title)});var $=g(Qt);$.use(N()),$.use(E),$.use(Q),await Q.isReady().catch(()=>void 0),$.mount(`#app`);
|
package/dist/web/index.html
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
/>
|
|
10
10
|
<link rel="icon" type="image/png" href="/assets/fuli-logo-ER1wQ8Kk.png" />
|
|
11
11
|
<title>复利 · Context Graph</title>
|
|
12
|
-
<script type="module" crossorigin src="/assets/index-
|
|
12
|
+
<script type="module" crossorigin src="/assets/index-CxNER7Oo.js"></script>
|
|
13
13
|
<link rel="modulepreload" crossorigin href="/assets/i18n-oJFlt8hW.js">
|
|
14
14
|
<link rel="modulepreload" crossorigin href="/assets/_plugin-vue_export-helper-BDNMzG2s.js">
|
|
15
15
|
<link rel="modulepreload" crossorigin href="/assets/client-DnwnUBQV.js">
|
|
@@ -25,6 +25,28 @@ directory, or `--runtime-config FILE` for an explicit runtime configuration.
|
|
|
25
25
|
`args` for clients with their own configuration editor. Paths with spaces remain
|
|
26
26
|
individual JSON arguments; do not paste them as an unquoted shell command.
|
|
27
27
|
|
|
28
|
+
## Claude Desktop and other chat apps
|
|
29
|
+
|
|
30
|
+
`fuli setup` detects Claude Desktop (Windows and macOS) and adds a `fuli` entry to
|
|
31
|
+
`claude_desktop_config.json`, keeping its other settings and servers and backing up the
|
|
32
|
+
file first. Quit and reopen Claude Desktop afterwards; it only reads the file at launch.
|
|
33
|
+
|
|
34
|
+
Chat apps load every tool schema into each conversation, so Claude Desktop gets the
|
|
35
|
+
**chat profile** (`--tool-profile chat`): 20 tools for preferences, project knowledge,
|
|
36
|
+
recording, completion checkpoints, conversation recovery and the Roundtable, about
|
|
37
|
+
40 KB of schema instead of about 200 KB for all 141 tools. Management (executors,
|
|
38
|
+
routing, publishing, recruitment) stays in the console. Its conversations are attributed
|
|
39
|
+
to `claude`. For another chat-style client, print the same entry with
|
|
40
|
+
`fuli connect --profile chat --source-application claude` (or the matching source).
|
|
41
|
+
|
|
42
|
+
Claude Desktop has no lifecycle hooks, so task entry and the closing attribution line
|
|
43
|
+
depend on the Agent following FULI's instructions, and visible conversations are not
|
|
44
|
+
captured automatically.
|
|
45
|
+
|
|
46
|
+
The generated paths go through the active Node location (for example nvm's
|
|
47
|
+
`C:\nvm4w\nodejs`) rather than a versioned install folder, so switching Node
|
|
48
|
+
versions with a version manager does not break client configuration.
|
|
49
|
+
|
|
28
50
|
Clients that only ask for a command can use `fuli mcp` if `fuli` is on their PATH.
|
|
29
51
|
`fuli mcp --tools` lists the available tool contract without starting a task.
|
|
30
52
|
Configuration export is read-only: it neither modifies client settings nor
|
|
@@ -54,7 +76,7 @@ is not proof that task entry or completion ran.
|
|
|
54
76
|
| Capability | Generic MCP | Current dedicated adapters |
|
|
55
77
|
| --- | --- | --- |
|
|
56
78
|
| Tools, authorized preferences and working memory | Available through tool calls | Shared behavior |
|
|
57
|
-
| Automatic configuration and bundled instructions | Merge generated configuration | Codex, Claude Code, Cursor |
|
|
79
|
+
| Automatic configuration and bundled instructions | Merge generated configuration | Codex, Claude Code, Cursor; Claude Desktop (configuration only, chat profile) |
|
|
58
80
|
| Task entry and completion hooks | Agent follows instructions; no guaranteed hook | Host-specific adapters; Cursor has a limited completion reminder |
|
|
59
81
|
| Automatic visible conversation capture | No | Supported Codex and Claude Code transcript formats |
|
|
60
82
|
| Roundtable wake/resume | Messages can wait for the recipient's next task | Codex and Claude Code CLIs |
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fuli-context",
|
|
3
|
-
"version": "0.12.
|
|
3
|
+
"version": "0.12.2",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "fuli-context",
|
|
9
|
-
"version": "0.12.
|
|
9
|
+
"version": "0.12.2",
|
|
10
10
|
"license": "Apache-2.0",
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"@a2a-js/sdk": "1.3.0",
|
package/package.json
CHANGED
|
@@ -4,13 +4,13 @@ import { clientConnectionConfig } from '../setup/client-connection.js';
|
|
|
4
4
|
|
|
5
5
|
export function runConnectCommand(args, { env = process.env, write = console.log } = {}) {
|
|
6
6
|
if (args.length === 1 && ['--help', '-h'].includes(args[0])) {
|
|
7
|
-
write('fuli connect [--format standard|vscode|server] [--data-dir DIR | --runtime-config FILE]\nPrint local MCP configuration; merge the fuli entry into your client settings. No files are changed.');
|
|
7
|
+
write('fuli connect [--format standard|vscode|server] [--profile full|chat] [--source-application codex|claude|claude_code|cursor|kiro|other] [--data-dir DIR | --runtime-config FILE]\nPrint local MCP configuration; merge the fuli entry into your client settings. No files are changed.\nUse --profile chat for chat apps that load every tool into each conversation. fuli setup configures Claude Desktop automatically.');
|
|
8
8
|
return;
|
|
9
9
|
}
|
|
10
10
|
const options = new Map();
|
|
11
11
|
for (let index = 0; index < args.length; index += 2) {
|
|
12
12
|
const flag = args[index];
|
|
13
|
-
if (!['--format', '--data-dir', '--runtime-config'].includes(flag)) throw new TypeError(`Unknown connect option: ${flag}`);
|
|
13
|
+
if (!['--format', '--profile', '--source-application', '--data-dir', '--runtime-config'].includes(flag)) throw new TypeError(`Unknown connect option: ${flag}`);
|
|
14
14
|
if (options.has(flag)) throw new TypeError(`Duplicate ${flag}`);
|
|
15
15
|
const value = args[index + 1];
|
|
16
16
|
if (!value?.trim() || value.startsWith('--')) throw new TypeError(`Missing value for ${flag}`);
|
|
@@ -22,7 +22,10 @@ export function runConnectCommand(args, { env = process.env, write = console.log
|
|
|
22
22
|
const paths = resolveSetupPaths({ dataDir: options.get('--data-dir'), env });
|
|
23
23
|
const runtimeConfigPath = options.has('--data-dir') ? paths.graphRuntimeConfigPath
|
|
24
24
|
: resolveGraphRuntimeOptions(options.has('--runtime-config') ? ['--runtime-config', options.get('--runtime-config')] : [], env).runtimeConfigPath;
|
|
25
|
-
const config = clientConnectionConfig({ mcpServerPath: paths.mcpServerPath, runtimeConfigPath }, options.get('--format')
|
|
25
|
+
const config = clientConnectionConfig({ mcpServerPath: paths.mcpServerPath, runtimeConfigPath }, options.get('--format'), {
|
|
26
|
+
profile: options.get('--profile') ?? 'full',
|
|
27
|
+
sourceApplication: options.get('--source-application') ?? 'other'
|
|
28
|
+
});
|
|
26
29
|
write(JSON.stringify(config, null, 2));
|
|
27
30
|
return config;
|
|
28
31
|
}
|
package/src/cli/mcp-command.js
CHANGED
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
import { runStdio } from '../mcp/runtime.js';
|
|
13
13
|
import { prepareDirectAgentToolCall } from '../mcp/direct-call.js';
|
|
14
14
|
import { normalizeMcpSourceApplication } from '../mcp/session-id.js';
|
|
15
|
+
import { toolNamesForProfile } from '../mcp/tool-profiles.js';
|
|
15
16
|
import { applicationErrorMessage } from '../mcp/tool-result.js';
|
|
16
17
|
|
|
17
18
|
export async function runMcpCommand(args, { env = process.env } = {}) {
|
|
@@ -42,7 +43,8 @@ export async function runMcpCommand(args, { env = process.env } = {}) {
|
|
|
42
43
|
runtimeConfigPath,
|
|
43
44
|
sourceApplication: configuredSourceApplication
|
|
44
45
|
? normalizeMcpSourceApplication(configuredSourceApplication)
|
|
45
|
-
: undefined
|
|
46
|
+
: undefined,
|
|
47
|
+
toolNames: toolNamesForProfile(args.includes('--tool-profile') ? requiredOption(args, '--tool-profile') : 'full')
|
|
46
48
|
});
|
|
47
49
|
}
|
|
48
50
|
|
|
@@ -92,7 +94,7 @@ export function startupMessage(error) {
|
|
|
92
94
|
|
|
93
95
|
function helpText() {
|
|
94
96
|
return 'Usage: fuli mcp [--runtime-config <graph-runtime.json>] ' +
|
|
95
|
-
'[--source-application <codex|claude|claude_code|cursor|kiro|other>]\n' +
|
|
97
|
+
'[--source-application <codex|claude|claude_code|cursor|kiro|other>] [--tool-profile <full|chat>]\n' +
|
|
96
98
|
' fuli mcp --tools\n' +
|
|
97
99
|
' fuli mcp --runtime-config <graph-runtime.json> ' +
|
|
98
100
|
'--call <tool> [--input <json>]\n';
|
package/src/cli/setup-command.js
CHANGED
|
@@ -102,9 +102,11 @@ export function formatSetupResult(result, plan) {
|
|
|
102
102
|
lines.push(`${agent.label}: ${state}${agent.message ? ` (${agent.message})` : ''}; retry fuli setup`);
|
|
103
103
|
continue;
|
|
104
104
|
}
|
|
105
|
-
lines.push(agent.
|
|
106
|
-
? `${agent.label}: connected;
|
|
107
|
-
:
|
|
105
|
+
lines.push(agent.restartRequired
|
|
106
|
+
? `${agent.label}: connected; quit and reopen the app to load Fuli`
|
|
107
|
+
: agent.newTaskRequired
|
|
108
|
+
? `${agent.label}: connected; create or reopen a task to load the new configuration`
|
|
109
|
+
: `${agent.label}: connected`);
|
|
108
110
|
for (const step of agent.nextSteps ?? []) lines.push(`${agent.label}: ${step}`);
|
|
109
111
|
}
|
|
110
112
|
const dataDir = plan?.paths?.dataDir;
|
package/src/mcp/runtime.js
CHANGED
|
@@ -7,12 +7,13 @@ import {
|
|
|
7
7
|
import { openFederatedGraphApplication } from '../graphiti/federated-application.js';
|
|
8
8
|
import { createMcpServer } from './create-mcp-server.js';
|
|
9
9
|
|
|
10
|
-
export async function runStdio({ runtimeConfigPath, sourceApplication }) {
|
|
10
|
+
export async function runStdio({ runtimeConfigPath, sourceApplication, toolNames = null }) {
|
|
11
11
|
const app = openFederatedGraphApplication({ runtimeConfigPath });
|
|
12
12
|
const leaseClient = createRuntimeLeaseClient({ runtimeConfigPath });
|
|
13
13
|
bindRuntimeLeaseAgentTools(app, leaseClient);
|
|
14
14
|
const server = createServerOrClose(app, createMcpServer, {
|
|
15
15
|
sourceApplication,
|
|
16
|
+
toolNames,
|
|
16
17
|
withRuntimeLease: leaseClient.withGraphLease
|
|
17
18
|
});
|
|
18
19
|
const transport = new StdioServerTransport();
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// Named MCP tool sets. Chat clients such as Claude Desktop load every tool schema
|
|
2
|
+
// into each conversation, so they get only the day-to-day memory, preference and
|
|
3
|
+
// Roundtable tools; management stays in the console and the full profile.
|
|
4
|
+
const CHAT_TOOLS = Object.freeze([
|
|
5
|
+
'get_collaboration_preferences',
|
|
6
|
+
'get_user_taste_skill',
|
|
7
|
+
'search_current_project_knowledge',
|
|
8
|
+
'search_knowledge_graph',
|
|
9
|
+
'capture_session_knowledge',
|
|
10
|
+
'record_knowledge_usage',
|
|
11
|
+
'record_decision_trace',
|
|
12
|
+
'checkpoint_task_knowledge',
|
|
13
|
+
'list_personal_projects',
|
|
14
|
+
'list_project_agents',
|
|
15
|
+
'get_project_agent_context',
|
|
16
|
+
'list_agent_conversations',
|
|
17
|
+
'read_agent_conversation',
|
|
18
|
+
'resume_agent_conversation',
|
|
19
|
+
'find_agents',
|
|
20
|
+
'message_agent',
|
|
21
|
+
'read_agent_messages',
|
|
22
|
+
'reply_agent_message',
|
|
23
|
+
'read_agent_thread',
|
|
24
|
+
'get_agent_message_status',
|
|
25
|
+
]);
|
|
26
|
+
|
|
27
|
+
export const MCP_TOOL_PROFILES = Object.freeze({ full: null, chat: CHAT_TOOLS });
|
|
28
|
+
|
|
29
|
+
// Returns the allow-listed tool names, or null for every tool.
|
|
30
|
+
export function toolNamesForProfile(profile = 'full') {
|
|
31
|
+
if (!Object.hasOwn(MCP_TOOL_PROFILES, profile)) {
|
|
32
|
+
throw new TypeError(`Unknown MCP tool profile: ${profile}. Use ${Object.keys(MCP_TOOL_PROFILES).join(' or ')}`);
|
|
33
|
+
}
|
|
34
|
+
const names = MCP_TOOL_PROFILES[profile];
|
|
35
|
+
return names ? [...names] : null;
|
|
36
|
+
}
|
|
@@ -3,6 +3,7 @@ import { existsSync, readFileSync } from 'node:fs';
|
|
|
3
3
|
import { replaceFuliTable } from './codex-config.js';
|
|
4
4
|
import { isCodexBootstrapCurrent } from './codex-bootstrap.js';
|
|
5
5
|
import { hasCurrentClaudeCodeHooks } from './claude-code-config.js';
|
|
6
|
+
import { CLAUDE_DESKTOP_SERVER_ARGS } from './claude-desktop-config.js';
|
|
6
7
|
import {
|
|
7
8
|
hasCodexTomlHookDefinitions,
|
|
8
9
|
hasCurrentCodexLifecycleHooks,
|
|
@@ -27,7 +28,7 @@ export function inspectAgentInstallations(agents, context, {
|
|
|
27
28
|
[context.projectSkillPath, agent.projectSkillPath],
|
|
28
29
|
[context.reviewSkillPath, agent.reviewSkillPath],
|
|
29
30
|
[context.operationSkillPath, agent.operationSkillPath]
|
|
30
|
-
];
|
|
31
|
+
].filter(([, targetPath]) => targetPath);
|
|
31
32
|
const skillsPresent = skillPairs.some(([, targetPath]) => fileExists(targetPath));
|
|
32
33
|
const skillsCurrent = skillPairs.every(
|
|
33
34
|
([sourcePath, targetPath]) => skillCurrent(sourcePath, targetPath)
|
|
@@ -89,8 +90,9 @@ function inspectRegistration(agent, context, readers) {
|
|
|
89
90
|
context.mcpServerPath,
|
|
90
91
|
'--runtime-config',
|
|
91
92
|
context.runtimeConfigPath,
|
|
92
|
-
'
|
|
93
|
-
|
|
93
|
+
...(agent.id === 'claude-desktop'
|
|
94
|
+
? CLAUDE_DESKTOP_SERVER_ARGS
|
|
95
|
+
: ['--source-application', agent.id === 'claude-code' ? 'claude_code' : agent.id])
|
|
94
96
|
]
|
|
95
97
|
};
|
|
96
98
|
try {
|
package/src/setup/agents.js
CHANGED
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
connectClaudeCode,
|
|
8
8
|
disconnectClaudeCode
|
|
9
9
|
} from './claude-code-config.js';
|
|
10
|
+
import { connectClaudeDesktop, disconnectClaudeDesktop } from './claude-desktop-config.js';
|
|
10
11
|
import { connectCursor, disconnectCursor } from './cursor-config.js';
|
|
11
12
|
import { connectCodex, disconnectCodex } from './codex-config.js';
|
|
12
13
|
import { adaptAgentForReviewSkill } from './review-skill-adapters.js';
|
|
@@ -69,32 +70,51 @@ export function discoverAgents({
|
|
|
69
70
|
fileExists(cursorHome)
|
|
70
71
|
)
|
|
71
72
|
}
|
|
72
|
-
].map((agent) => adaptAgentForReviewSkill(agent, { homeDir, pathApi }))
|
|
73
|
+
].map((agent) => adaptAgentForReviewSkill(agent, { homeDir, pathApi }))
|
|
74
|
+
.concat(claudeDesktop({ platform, env, homeDir, pathApi, fileExists }) ?? []);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// The chat app: MCP only, no hooks or Skills. Its config lives beside its app data.
|
|
78
|
+
function claudeDesktop({ platform, env, homeDir, pathApi, fileExists }) {
|
|
79
|
+
const appData = platform === 'win32' ? nonEmpty(env.APPDATA)
|
|
80
|
+
: platform === 'darwin' ? pathApi.join(homeDir, 'Library', 'Application Support') : null;
|
|
81
|
+
if (!appData) return null;
|
|
82
|
+
const configDir = pathApi.join(appData, 'Claude');
|
|
83
|
+
return {
|
|
84
|
+
id: 'claude-desktop',
|
|
85
|
+
label: 'Claude Desktop',
|
|
86
|
+
configPath: pathApi.join(configDir, 'claude_desktop_config.json'),
|
|
87
|
+
available: Boolean(fileExists(configDir))
|
|
88
|
+
};
|
|
73
89
|
}
|
|
74
90
|
|
|
75
91
|
export function connectAgent(agent, context, {
|
|
76
92
|
connectCodexConfig = connectCodex,
|
|
77
93
|
connectClaudeCodeConfig = connectClaudeCode,
|
|
78
|
-
connectCursorConfig = connectCursor
|
|
94
|
+
connectCursorConfig = connectCursor,
|
|
95
|
+
connectClaudeDesktopConfig = connectClaudeDesktop
|
|
79
96
|
} = {}) {
|
|
80
97
|
if (agent.id === 'codex') return connectCodexConfig(agent, context);
|
|
81
98
|
if (agent.id === 'claude-code') {
|
|
82
99
|
return connectClaudeCodeConfig(agent, context);
|
|
83
100
|
}
|
|
84
101
|
if (agent.id === 'cursor') return connectCursorConfig(agent, context);
|
|
102
|
+
if (agent.id === 'claude-desktop') return connectClaudeDesktopConfig(agent, context);
|
|
85
103
|
throw new TypeError(`Unsupported agent: ${agent.id}`);
|
|
86
104
|
}
|
|
87
105
|
|
|
88
106
|
export function disconnectAgent(agent, {
|
|
89
107
|
disconnectCodexConfig = disconnectCodex,
|
|
90
108
|
disconnectClaudeCodeConfig = disconnectClaudeCode,
|
|
91
|
-
disconnectJsonConfig = disconnectCursor
|
|
109
|
+
disconnectJsonConfig = disconnectCursor,
|
|
110
|
+
disconnectClaudeDesktopConfig = disconnectClaudeDesktop
|
|
92
111
|
} = {}) {
|
|
93
112
|
if (agent.id === 'codex') return disconnectCodexConfig(agent);
|
|
94
113
|
if (agent.id === 'claude-code') return disconnectClaudeCodeConfig(agent);
|
|
95
114
|
if (agent.id === 'cursor') {
|
|
96
115
|
return disconnectJsonConfig(agent);
|
|
97
116
|
}
|
|
117
|
+
if (agent.id === 'claude-desktop') return disconnectClaudeDesktopConfig(agent);
|
|
98
118
|
throw new TypeError(`Unsupported agent: ${agent.id}`);
|
|
99
119
|
}
|
|
100
120
|
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { existsSync } from 'node:fs';
|
|
2
|
+
|
|
3
|
+
import { readJsonFile, writeJsonFileAtomic } from '../storage/json-file.js';
|
|
4
|
+
|
|
5
|
+
// Arguments after the runtime config that identify the app and keep its tool list small.
|
|
6
|
+
export const CLAUDE_DESKTOP_SERVER_ARGS = Object.freeze(['--source-application', 'claude', '--tool-profile', 'chat']);
|
|
7
|
+
|
|
8
|
+
// Claude Desktop (the chat app) reads stdio MCP servers from
|
|
9
|
+
// claude_desktop_config.json. It has no lifecycle hooks or Skill folder, and it
|
|
10
|
+
// loads every tool schema into each chat, so it gets the compact chat profile.
|
|
11
|
+
export function connectClaudeDesktop(agent, context, {
|
|
12
|
+
readConfig = readJsonFile,
|
|
13
|
+
writeConfig = writeJsonFileAtomic
|
|
14
|
+
} = {}) {
|
|
15
|
+
const current = readConfig(agent.configPath, {});
|
|
16
|
+
assertObject(current, 'Claude Desktop config');
|
|
17
|
+
const currentServers = current.mcpServers ?? {};
|
|
18
|
+
assertObject(currentServers, 'Claude Desktop mcpServers');
|
|
19
|
+
const next = {
|
|
20
|
+
...current,
|
|
21
|
+
mcpServers: {
|
|
22
|
+
...currentServers,
|
|
23
|
+
fuli: {
|
|
24
|
+
command: context.nodePath,
|
|
25
|
+
args: [
|
|
26
|
+
context.mcpServerPath,
|
|
27
|
+
'--runtime-config',
|
|
28
|
+
context.runtimeConfigPath,
|
|
29
|
+
...CLAUDE_DESKTOP_SERVER_ARGS
|
|
30
|
+
]
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
const changed = JSON.stringify(current) !== JSON.stringify(next);
|
|
35
|
+
if (changed) writeConfig(agent.configPath, next);
|
|
36
|
+
// The app only reads its config at launch.
|
|
37
|
+
return { id: agent.id, label: agent.label, status: 'connected', restartRequired: changed };
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function disconnectClaudeDesktop(agent, {
|
|
41
|
+
fileExists = existsSync,
|
|
42
|
+
readConfig = readJsonFile,
|
|
43
|
+
writeConfig = writeJsonFileAtomic
|
|
44
|
+
} = {}) {
|
|
45
|
+
if (!fileExists(agent.configPath)) return { id: agent.id, label: agent.label, status: 'not_connected' };
|
|
46
|
+
const current = readConfig(agent.configPath, {});
|
|
47
|
+
assertObject(current, 'Claude Desktop config');
|
|
48
|
+
const currentServers = current.mcpServers ?? {};
|
|
49
|
+
assertObject(currentServers, 'Claude Desktop mcpServers');
|
|
50
|
+
if (!Object.hasOwn(currentServers, 'fuli')) return { id: agent.id, label: agent.label, status: 'not_connected' };
|
|
51
|
+
const { fuli: _removed, ...remainingServers } = currentServers;
|
|
52
|
+
writeConfig(agent.configPath, { ...current, mcpServers: remainingServers });
|
|
53
|
+
return { id: agent.id, label: agent.label, status: 'disconnected' };
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function assertObject(value, label) {
|
|
57
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
58
|
+
throw new TypeError(`${label} must be a JSON object`);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
@@ -1,5 +1,13 @@
|
|
|
1
|
+
import { toolNamesForProfile } from '../mcp/tool-profiles.js';
|
|
2
|
+
import { normalizeMcpSourceApplication } from '../mcp/session-id.js';
|
|
3
|
+
|
|
1
4
|
// Configuration only: no client discovery, file writes, credentials or model calls.
|
|
2
|
-
export function clientConnectionConfig({ nodePath = process.execPath, mcpServerPath, runtimeConfigPath }, format = 'standard'
|
|
5
|
+
export function clientConnectionConfig({ nodePath = process.execPath, mcpServerPath, runtimeConfigPath }, format = 'standard', {
|
|
6
|
+
profile = 'full',
|
|
7
|
+
sourceApplication = 'other'
|
|
8
|
+
} = {}) {
|
|
9
|
+
toolNamesForProfile(profile);
|
|
10
|
+
normalizeMcpSourceApplication(sourceApplication);
|
|
3
11
|
if (!['standard', 'vscode', 'server'].includes(format)) {
|
|
4
12
|
throw new TypeError('Connection format must be standard, vscode or server');
|
|
5
13
|
}
|
|
@@ -9,7 +17,8 @@ export function clientConnectionConfig({ nodePath = process.execPath, mcpServerP
|
|
|
9
17
|
const server = {
|
|
10
18
|
type: 'stdio',
|
|
11
19
|
command: nodePath,
|
|
12
|
-
args: [mcpServerPath, '--runtime-config', runtimeConfigPath, '--source-application',
|
|
20
|
+
args: [mcpServerPath, '--runtime-config', runtimeConfigPath, '--source-application', sourceApplication,
|
|
21
|
+
...(profile === 'full' ? [] : ['--tool-profile', profile])]
|
|
13
22
|
};
|
|
14
23
|
if (format === 'server') return server;
|
|
15
24
|
return { [format === 'vscode' ? 'servers' : 'mcpServers']: { fuli: server } };
|
package/src/setup/paths.js
CHANGED
|
@@ -2,7 +2,9 @@ import { homedir } from 'node:os';
|
|
|
2
2
|
import { dirname, join, resolve } from 'node:path';
|
|
3
3
|
import { fileURLToPath } from 'node:url';
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
import { stablePackageRoot } from './stable-package-root.js';
|
|
6
|
+
|
|
7
|
+
const DEFAULT_PACKAGE_ROOT = stablePackageRoot(dirname(dirname(dirname(fileURLToPath(import.meta.url)))));
|
|
6
8
|
|
|
7
9
|
export function resolveSetupPaths({
|
|
8
10
|
dataDir = null,
|
package/src/setup/setup.js
CHANGED
|
@@ -121,7 +121,7 @@ export async function applyLocalSetup(plan, options, dependencies = {}) {
|
|
|
121
121
|
[{ ...agent, skillPath: agent.projectSkillPath }, plan.paths.projectSkillPath],
|
|
122
122
|
[{ ...agent, skillPath: agent.reviewSkillPath }, plan.paths.reviewSkillPath],
|
|
123
123
|
[{ ...agent, skillPath: agent.operationSkillPath }, plan.paths.operationSkillPath]
|
|
124
|
-
]) {
|
|
124
|
+
].filter(([target]) => target.skillPath)) {
|
|
125
125
|
skills.push(await installSkill(target, {
|
|
126
126
|
sourcePath,
|
|
127
127
|
backupDir: plan.paths.backupDir
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { existsSync, realpathSync } from 'node:fs';
|
|
2
|
+
import { basename, dirname, join } from 'node:path';
|
|
3
|
+
|
|
4
|
+
// Version managers such as nvm-windows install each Node version in its own
|
|
5
|
+
// folder and expose the active one through a symlink (C:\nvm4w\nodejs). The
|
|
6
|
+
// module URL resolves to the versioned folder, which breaks client configs on
|
|
7
|
+
// the next `nvm use`. Prefer the same package seen through the active Node's
|
|
8
|
+
// directory when it is the identical install.
|
|
9
|
+
export function stablePackageRoot(root, {
|
|
10
|
+
execPath = process.execPath,
|
|
11
|
+
exists = existsSync,
|
|
12
|
+
realpath = realpathSync
|
|
13
|
+
} = {}) {
|
|
14
|
+
const nodeDir = dirname(execPath);
|
|
15
|
+
const name = basename(root);
|
|
16
|
+
const candidates = [
|
|
17
|
+
join(nodeDir, 'node_modules', name),
|
|
18
|
+
join(dirname(nodeDir), 'lib', 'node_modules', name)
|
|
19
|
+
];
|
|
20
|
+
let real;
|
|
21
|
+
try { real = realpath(root); } catch { return root; }
|
|
22
|
+
for (const candidate of candidates) {
|
|
23
|
+
if (candidate === root || !exists(candidate)) continue;
|
|
24
|
+
try {
|
|
25
|
+
if (realpath(candidate) === real) return candidate;
|
|
26
|
+
} catch { /* unreadable candidate */ }
|
|
27
|
+
}
|
|
28
|
+
return root;
|
|
29
|
+
}
|