fuli-context 0.7.6 → 0.7.7

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 (146) hide show
  1. package/README.md +69 -13
  2. package/README.zh-CN.md +60 -14
  3. package/dist/web/assets/{AboutPage-sLV9WChi.js → AboutPage-BcZeFcHe.js} +1 -1
  4. package/dist/web/assets/{ConnectionsPage-BWn4ywGJ.js → ConnectionsPage-xAQYl1SQ.js} +1 -1
  5. package/dist/web/assets/EmployeeRecruitDialog-CbPAmhy7.js +1 -0
  6. package/dist/web/assets/EmployeeRecruitDialog-CfFlyKSh.css +1 -0
  7. package/dist/web/assets/EmployeeWorkbenchPage-BQvTLoc8.css +1 -0
  8. package/dist/web/assets/EmployeeWorkbenchPage-DF3EL0Ui.js +1 -0
  9. package/dist/web/assets/KnowledgeEditDialog-UnnBDt0I.js +1 -0
  10. package/dist/web/assets/{KnowledgeEditDialog-DWUV_NPp.css → KnowledgeEditDialog-iv-dgUeD.css} +1 -1
  11. package/dist/web/assets/{KnowledgeInspector-CRQWOaos.js → KnowledgeInspector-BqPJH5Rr.js} +1 -1
  12. package/dist/web/assets/{KnowledgeOrganizerPage-Dfj3vIpU.js → KnowledgeOrganizerPage-CyvRflXM.js} +1 -1
  13. package/dist/web/assets/KnowledgePage-59eczTqe.js +1 -0
  14. package/dist/web/assets/{KnowledgeWorkspace-ChEB5Bwk.js → KnowledgeWorkspace-CfIjhOog.js} +1 -1
  15. package/dist/web/assets/{OverviewPage-Cd66M0RT.js → OverviewPage-Xyfm5xkZ.js} +1 -1
  16. package/dist/web/assets/{PersonalProfilePage-RCFHL0Wz.js → PersonalProfilePage-DB9mByB3.js} +1 -1
  17. package/dist/web/assets/PersonalProjectsPage-_-YXVi5O.js +1 -0
  18. package/dist/web/assets/ProjectAgentsPage-C3vW6wmk.css +1 -0
  19. package/dist/web/assets/ProjectAgentsPage-DeeQByPX.js +11 -0
  20. package/dist/web/assets/{PublicProjectsPage-mstPEjHe.js → PublicProjectsPage-BEZ1YPs3.js} +1 -1
  21. package/dist/web/assets/{ReviewPage-6Y1SmfZy.js → ReviewPage-CQYGwFBH.js} +1 -1
  22. package/dist/web/assets/SearchableSelect-D27H0MoP.js +1 -0
  23. package/dist/web/assets/{SettingsPage--LdTMUm7.js → SettingsPage-BlEZ03Yi.js} +1 -1
  24. package/dist/web/assets/{WritingTastePage-CIpKswvs.js → WritingTastePage-DvRt_nmP.js} +1 -1
  25. package/dist/web/assets/catalog-DFvIaHVS.js +1 -0
  26. package/dist/web/assets/{console-BT1P2Db4.js → console-tOxOl8Vq.js} +1 -1
  27. package/dist/web/assets/conversation-launcher-settings-DuFSpPAo.js +1 -0
  28. package/dist/web/assets/{i18n-js6gfc7j.js → i18n-CgBHZthI.js} +3 -3
  29. package/dist/web/assets/{identity-CfDfanpa.js → identity-CFo_Uw1H.js} +1 -1
  30. package/dist/web/assets/index-CJc5ppXH.css +1 -0
  31. package/dist/web/assets/index-yCi3cz2l.js +2 -0
  32. package/dist/web/assets/{model-DJkLAJsg.js → model-BtnVr7fX.js} +1 -1
  33. package/dist/web/assets/{useApi-CROJJdhE-BdSti7Y2.js → useApi-CROJJdhE-B6MHm_Av.js} +1 -1
  34. package/dist/web/assets/{vue-router-Kk67EaCP.js → vue-router-CzHm-y-x.js} +1 -1
  35. package/dist/web/index.html +7 -6
  36. package/docs/employee-agents.md +99 -0
  37. package/docs/project-agent-memory.md +479 -0
  38. package/graph-provider/fuli_graph/knowledge_audit_models.py +171 -0
  39. package/graph-provider/fuli_graph/model_base.py +5 -0
  40. package/graph-provider/fuli_graph/model_validation.py +32 -0
  41. package/graph-provider/fuli_graph/models.py +26 -170
  42. package/graph-provider/fuli_graph/project_agent_context_models.py +29 -0
  43. package/graph-provider/fuli_graph/project_agent_executor_models.py +35 -7
  44. package/graph-provider/fuli_graph/project_agent_memory_models.py +79 -0
  45. package/graph-provider/fuli_graph/project_agent_memory_routes.py +46 -0
  46. package/graph-provider/fuli_graph/project_agent_models.py +9 -0
  47. package/graph-provider/fuli_graph/project_agent_recruitment_values.py +48 -0
  48. package/graph-provider/fuli_graph/project_agent_routes.py +21 -1
  49. package/graph-provider/fuli_graph/project_agent_task_models.py +217 -29
  50. package/graph-provider/fuli_graph/runtime.py +37 -1
  51. package/graph-provider/fuli_graph/store.py +6 -0
  52. package/graph-provider/fuli_graph/store_project_agent_context.py +65 -0
  53. package/graph-provider/fuli_graph/store_project_agent_executor_learning.py +175 -11
  54. package/graph-provider/fuli_graph/store_project_agent_executor_routing.py +33 -10
  55. package/graph-provider/fuli_graph/store_project_agent_executors.py +181 -14
  56. package/graph-provider/fuli_graph/store_project_agent_memory.py +174 -0
  57. package/graph-provider/fuli_graph/store_project_agent_task_activity.py +423 -0
  58. package/graph-provider/fuli_graph/store_project_agent_task_persistence.py +152 -0
  59. package/graph-provider/fuli_graph/store_project_agent_task_reads.py +187 -21
  60. package/graph-provider/fuli_graph/store_project_agent_task_recruitment.py +748 -162
  61. package/graph-provider/fuli_graph/store_project_agent_task_staffing.py +230 -18
  62. package/graph-provider/fuli_graph/store_project_agent_tasks.py +261 -468
  63. package/graph-provider/fuli_graph/store_project_agents.py +214 -46
  64. package/graph-provider/fuli_graph/store_task_contexts.py +217 -0
  65. package/graph-provider/fuli_graph/store_transactions.py +40 -0
  66. package/graph-provider/fuli_graph/task_context_models.py +50 -0
  67. package/graph-provider/fuli_graph/task_context_routes.py +31 -0
  68. package/graph-provider/fuli_graph/workflow_observation_models.py +1 -1
  69. package/graph-provider/pyproject.toml +1 -1
  70. package/npm-shrinkwrap.json +8 -8
  71. package/package.json +5 -2
  72. package/skills/capturing-session-knowledge/SKILL.md +18 -6
  73. package/src/adaptive-runtime/executor-pool.js +46 -5
  74. package/src/adaptive-runtime/graph-services.js +10 -3
  75. package/src/adaptive-runtime/lease-client.js +66 -14
  76. package/src/adaptive-runtime/runtime-broker.js +24 -9
  77. package/src/agent-tools/employee-definitions.js +43 -0
  78. package/src/agent-tools/graph-definitions.js +25 -6
  79. package/src/agent-tools/graph-handlers.js +11 -0
  80. package/src/agent-tools/project-agent-definitions.js +35 -4
  81. package/src/agent-tools/project-agent-memory-definitions.js +36 -0
  82. package/src/agent-tools.js +6 -2
  83. package/src/agents/codex/lifecycle-hook.js +107 -0
  84. package/src/agents/codex/lifecycle-hooks.js +231 -0
  85. package/src/agents/cursor/lifecycle-hook.js +133 -0
  86. package/src/agents/cursor/lifecycle-hooks.js +50 -0
  87. package/src/agents/lifecycle-message.js +19 -0
  88. package/src/app/agent-request-context.js +23 -0
  89. package/src/cli/command-registry.js +2 -0
  90. package/src/cli/employee-command.js +17 -0
  91. package/src/cli/remote-mcp-command.js +282 -0
  92. package/src/cli/setup-command.js +5 -0
  93. package/src/cli.js +10 -0
  94. package/src/employees/catalog/jefa.json +21 -0
  95. package/src/employees/install-package.js +77 -0
  96. package/src/employees/management-policy.js +88 -0
  97. package/src/employees/manifest.js +53 -0
  98. package/src/employees/package-registry.js +107 -0
  99. package/src/employees/project-selection.js +50 -0
  100. package/src/employees/recruitment.js +199 -0
  101. package/src/employees/service.js +83 -0
  102. package/src/employees/task-entry.js +39 -0
  103. package/src/graphiti/agent-knowledge-workflows.js +135 -25
  104. package/src/graphiti/federated-application.js +78 -35
  105. package/src/graphiti/project-agent-control-plane.js +20 -3
  106. package/src/graphiti/project-agent-mapping.js +155 -5
  107. package/src/graphiti/project-agent-memory.js +115 -0
  108. package/src/graphiti/project-agent-task-entry.js +126 -0
  109. package/src/graphiti/project-agent-workflows.js +30 -14
  110. package/src/graphiti/provider-client.js +66 -4
  111. package/src/http/api-router.js +25 -5
  112. package/src/http/employee-api-router.js +64 -0
  113. package/src/http/error-mapping.js +4 -0
  114. package/src/http/graph-api-router.js +2 -0
  115. package/src/http/request-policy.js +6 -3
  116. package/src/http/static-handler.js +4 -3
  117. package/src/mcp/create-mcp-server.js +98 -37
  118. package/src/mcp/direct-call.js +38 -0
  119. package/src/mcp/instructions.js +8 -7
  120. package/src/mcp/provider-task-context-registry.js +74 -0
  121. package/src/mcp/remote-http-server.js +761 -0
  122. package/src/mcp/session-id.js +29 -3
  123. package/src/mcp/task-context-registry.js +88 -29
  124. package/src/mcp/tool-annotations.js +10 -2
  125. package/src/mcp/tool-result.js +8 -3
  126. package/src/mcp-server.js +20 -8
  127. package/src/native-runtime/runtime.js +58 -8
  128. package/src/server.js +76 -28
  129. package/src/setup/agent-installation-status.js +38 -6
  130. package/src/setup/agents.js +20 -8
  131. package/src/setup/claude-code-config.js +55 -13
  132. package/src/setup/codex-bootstrap.js +11 -10
  133. package/src/setup/codex-config.js +74 -7
  134. package/src/setup/config-backup.js +18 -2
  135. package/src/setup/cursor-config.js +22 -5
  136. package/src/setup/setup.js +30 -22
  137. package/src/storage/json-file.js +11 -3
  138. package/dist/web/assets/KnowledgeEditDialog-CZ5ziPrD.js +0 -1
  139. package/dist/web/assets/KnowledgePage-BRYC9S5Y.js +0 -1
  140. package/dist/web/assets/PersonalProjectsPage-DEh8XWby.js +0 -1
  141. package/dist/web/assets/ProjectAgentsPage-Crh7PrXa.css +0 -1
  142. package/dist/web/assets/ProjectAgentsPage-DPnaH-TR.js +0 -11
  143. package/dist/web/assets/SearchableSelect-D3HM8YF8.js +0 -1
  144. package/dist/web/assets/conversation-launcher-settings-DrJEotdf.js +0 -1
  145. package/dist/web/assets/index-BnH5mcZx.css +0 -1
  146. package/dist/web/assets/index-GqJf1xqg.js +0 -2
@@ -1,7 +1,11 @@
1
1
  import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
- import { CallToolRequestSchema } from '@modelcontextprotocol/sdk/types.js';
2
+ import {
3
+ CallToolRequestSchema,
4
+ ListToolsRequestSchema
5
+ } from '@modelcontextprotocol/sdk/types.js';
3
6
 
4
7
  import { callAgentTool, listAgentTools } from '../agent-tools.js';
8
+ import { ApplicationError, ApplicationErrorCode } from '../app/application-error.js';
5
9
  import { FULI_VERSION } from '../package-metadata.js';
6
10
  import { MCP_INSTRUCTIONS } from './instructions.js';
7
11
  import { createProjectActionPreviewTokens } from './project-action-preview-tokens.js';
@@ -24,8 +28,13 @@ import {
24
28
  } from './session-id.js';
25
29
 
26
30
  const TOOL_RESULT_LIMIT_BYTES = Object.freeze({
27
- begin_task_context: 16 * 1024,
28
- get_collaboration_preferences: 16 * 1024,
31
+ list_employee_templates: 32 * 1024,
32
+ recruit_employee: 64 * 1024,
33
+ list_employee_tools: 64 * 1024,
34
+ call_employee_tool: 64 * 1024,
35
+ begin_task_context: 64 * 1024,
36
+ checkpoint_task_knowledge: 16 * 1024,
37
+ get_collaboration_preferences: 64 * 1024,
29
38
  get_user_taste_skill: 32 * 1024,
30
39
  search_knowledge_graph: 32 * 1024,
31
40
  search_connected_knowledge: 64 * 1024,
@@ -38,6 +47,8 @@ const TOOL_RESULT_LIMIT_BYTES = Object.freeze({
38
47
  get_project_agent: 32 * 1024,
39
48
  list_project_agent_assignments: 32 * 1024,
40
49
  get_project_agent_context: 64 * 1024,
50
+ get_project_agent_memory: 128 * 1024,
51
+ checkpoint_project_agent_memory: 64 * 1024,
41
52
  coordinate_project_agent_task: 256 * 1024,
42
53
  acquire_runtime_lease: 4 * 1024,
43
54
  refresh_runtime_lease: 4 * 1024,
@@ -63,33 +74,46 @@ export function createMcpServer(
63
74
  env = process.env,
64
75
  clock = () => new Date(),
65
76
  sourceApplication = nativeCodexThreadId(env) ? 'codex' : 'other',
66
- withRuntimeLease = (_owner, operation) => operation()
77
+ withRuntimeLease = (_owner, operation) => operation(),
78
+ hostSessionId = null,
79
+ instructions = MCP_INSTRUCTIONS,
80
+ toolNames = null,
81
+ prepareToolInput = (_name, input) => input,
82
+ registerResources = true
67
83
  } = {}
68
84
  ) {
69
85
  const server = new McpServer(
70
86
  { name: 'fuli', version: FULI_VERSION },
71
- { instructions: MCP_INSTRUCTIONS }
87
+ { instructions }
72
88
  );
73
89
 
74
- const nativeThreadId = nativeCodexThreadId(env);
75
90
  const authoritativeSourceApplication = normalizeMcpSourceApplication(
76
91
  sourceApplication
77
92
  );
93
+ const nativeThreadId = authoritativeSourceApplication === 'codex' ? nativeCodexThreadId(env) : null;
78
94
  const tools = createToolMap(
79
95
  app,
80
96
  createProjectActionPreviewTokens(),
81
97
  nativeThreadId,
82
- mcpHostSessionId(env),
98
+ hostSessionId ?? mcpHostSessionId(authoritativeSourceApplication === 'codex' ? env : {}),
83
99
  clock,
84
100
  authoritativeSourceApplication,
85
- withRuntimeLease
101
+ withRuntimeLease,
102
+ toolNames,
103
+ prepareToolInput
86
104
  );
87
105
  for (const tool of tools.values()) registerTool(server, tool);
88
- registerFuliContextResources(server, app, { withRuntimeLease });
106
+ if (!tools.size) registerEmptyToolList(server);
107
+ if (registerResources) registerFuliContextResources(server, app, { withRuntimeLease });
89
108
  registerCallHandler(server, tools);
90
109
  return server;
91
110
  }
92
111
 
112
+ function registerEmptyToolList(server) {
113
+ server.server.registerCapabilities({ tools: { listChanged: true } });
114
+ server.server.setRequestHandler(ListToolsRequestSchema, () => ({ tools: [] }));
115
+ }
116
+
93
117
  function createToolMap(
94
118
  app,
95
119
  projectActionPreviews,
@@ -97,29 +121,52 @@ function createToolMap(
97
121
  hostSessionId,
98
122
  clock,
99
123
  sourceApplication,
100
- withRuntimeLease
124
+ withRuntimeLease,
125
+ toolNames,
126
+ prepareToolInput
101
127
  ) {
102
128
  const commonKnowledgePreviews = createCommonKnowledgePreviewTokens();
103
- return new Map(listAgentTools().map((definition) => [definition.name, {
129
+ if (toolNames !== null && !Array.isArray(toolNames)) {
130
+ throw new TypeError('MCP toolNames must be an array or null');
131
+ }
132
+ const definitions = listAgentTools();
133
+ const allowedTools = toolNames === null ? null : new Set(toolNames);
134
+ if (allowedTools) {
135
+ const available = new Set(definitions.map(({ name }) => name));
136
+ const unknown = [...allowedTools].filter((name) => !available.has(name));
137
+ if (unknown.length) {
138
+ throw new TypeError(
139
+ `Unknown MCP tool name${unknown.length === 1 ? '' : 's'}: ${unknown.join(', ')}`
140
+ );
141
+ }
142
+ }
143
+ return new Map(definitions
144
+ .filter((definition) => !allowedTools || allowedTools.has(definition.name))
145
+ .map((definition) => [definition.name, {
104
146
  definition,
105
147
  schema: jsonSchemaToZod(definition.inputSchema),
106
- invoke: (input) => withRuntimeLease(
107
- `mcp-tool:${definition.name}`,
108
- () => invokeAgentTool(
109
- app,
110
- definition.name,
111
- normalizeAgentSessionInput(
148
+ invoke: (input, requestContext = null) => {
149
+ requestContext?.signal?.throwIfAborted?.();
150
+ return withRuntimeLease(
151
+ `mcp-tool:${definition.name}`,
152
+ () => invokeAgentTool(
153
+ app,
112
154
  definition.name,
113
- input,
114
- nativeThreadId,
115
- hostSessionId,
116
- clock,
117
- sourceApplication
155
+ normalizeAgentSessionInput(
156
+ definition.name,
157
+ prepareToolInput(definition.name, input),
158
+ nativeThreadId,
159
+ hostSessionId,
160
+ clock,
161
+ sourceApplication
162
+ ),
163
+ projectActionPreviews,
164
+ commonKnowledgePreviews,
165
+ requestContext
118
166
  ),
119
- projectActionPreviews,
120
- commonKnowledgePreviews
121
- )
122
- )
167
+ requestContext
168
+ );
169
+ }
123
170
  }]));
124
171
  }
125
172
 
@@ -131,22 +178,35 @@ function registerTool(server, tool) {
131
178
  inputSchema: schema,
132
179
  outputSchema: openObjectSchema(),
133
180
  annotations: annotationsFor(definition.name)
134
- }, (input) => invokeTool(tool, input));
181
+ }, (input, extra) => invokeTool(tool, input, extra));
135
182
  }
136
183
 
137
184
  function registerCallHandler(server, tools) {
138
- server.server.setRequestHandler(CallToolRequestSchema, async (request) => {
185
+ server.server.setRequestHandler(CallToolRequestSchema, async (request, extra) => {
139
186
  const tool = tools.get(request.params.name);
140
- if (!tool) return errorToolResult(new Error('Unknown tool'));
187
+ if (!tool) {
188
+ return errorToolResult(new ApplicationError(
189
+ ApplicationErrorCode.NOT_FOUND,
190
+ 'Unknown Fuli tool'
191
+ ));
192
+ }
141
193
  const parsed = await tool.schema.safeParseAsync(request.params.arguments ?? {});
142
- if (!parsed.success) return protocolErrorResult('Input validation error');
143
- return invokeTool(tool, parsed.data);
194
+ if (!parsed.success) {
195
+ return protocolErrorResult(
196
+ 'Input validation error',
197
+ parsed.error.issues.map(({ path, message }) => ({
198
+ field: path.length ? path.join('.') : 'arguments',
199
+ message
200
+ }))
201
+ );
202
+ }
203
+ return invokeTool(tool, parsed.data, extra);
144
204
  });
145
205
  }
146
206
 
147
- async function invokeTool(tool, input) {
207
+ async function invokeTool(tool, input, requestContext = null) {
148
208
  try {
149
- const value = await tool.invoke(input);
209
+ const value = await tool.invoke(input, requestContext);
150
210
  auditLifecycleTool(tool.definition.name);
151
211
  const limitBytes = TOOL_RESULT_LIMIT_BYTES[tool.definition.name];
152
212
  if (tool.definition.name === 'begin_task_context') {
@@ -167,10 +227,11 @@ async function invokeAgentTool(
167
227
  name,
168
228
  input,
169
229
  projectActionPreviews,
170
- commonKnowledgePreviews
230
+ commonKnowledgePreviews,
231
+ requestContext = null
171
232
  ) {
172
233
  if (name === 'preview_personal_project_action') {
173
- const result = await callAgentTool(app, name, input);
234
+ const result = await callAgentTool(app, name, input, requestContext);
174
235
  return {
175
236
  ...result,
176
237
  previewToken: projectActionPreviews.issue(input)
@@ -180,7 +241,7 @@ async function invokeAgentTool(
180
241
  projectActionPreviews.consume(input.previewToken, input);
181
242
  }
182
243
  if (name === 'preview_common_knowledge_promotion') {
183
- const result = await callAgentTool(app, name, input);
244
+ const result = await callAgentTool(app, name, input, requestContext);
184
245
  return {
185
246
  ...result,
186
247
  previewToken: commonKnowledgePreviews.issue(input)
@@ -189,5 +250,5 @@ async function invokeAgentTool(
189
250
  if (name === 'apply_common_knowledge_promotion') {
190
251
  commonKnowledgePreviews.consume(input.previewToken, input);
191
252
  }
192
- return callAgentTool(app, name, input);
253
+ return callAgentTool(app, name, input, requestContext);
193
254
  }
@@ -0,0 +1,38 @@
1
+ import { listAgentTools } from '../agent-tools.js';
2
+ import {
3
+ mcpHostSessionId,
4
+ nativeCodexThreadId,
5
+ normalizeAgentSessionInput,
6
+ normalizeMcpSourceApplication
7
+ } from './session-id.js';
8
+ import { jsonSchemaToZod } from './tool-schema.js';
9
+
10
+ export async function prepareDirectAgentToolCall({
11
+ toolName,
12
+ input,
13
+ sourceApplication = 'other',
14
+ env = process.env,
15
+ clock = () => new Date(),
16
+ hostSessionId = null
17
+ }) {
18
+ const definition = listAgentTools().find((item) => item.name === toolName);
19
+ if (!definition) throw new TypeError('Unknown tool');
20
+ const parsed = await jsonSchemaToZod(definition.inputSchema).safeParseAsync(input ?? {});
21
+ if (!parsed.success) throw new TypeError('Input validation error');
22
+ const source = normalizeMcpSourceApplication(sourceApplication);
23
+ const nativeThreadId = source === 'codex' ? nativeCodexThreadId(env) : null;
24
+ const authoritativeHostSessionId = hostSessionId ?? mcpHostSessionId(
25
+ source === 'codex' ? env : {}
26
+ );
27
+ return {
28
+ definition,
29
+ input: normalizeAgentSessionInput(
30
+ toolName,
31
+ parsed.data,
32
+ nativeThreadId,
33
+ authoritativeHostSessionId,
34
+ clock,
35
+ source
36
+ )
37
+ };
38
+ }
@@ -1,9 +1,10 @@
1
1
  export const MCP_INSTRUCTIONS = [
2
- 'Each user task: hook-provided task context via begin_task_context; otherwise before other tools/answer call exactly get_collaboration_preferences(projectPath=cwd taskPrompt=current user request) as fallback; never substitute a project action. Apply all effective_preferences: personal-global everywhere; matched project, authorized inheritable parent. get_user_taste_skill never replaces a user-authored Skill. Resolve deferred_conflict; never guess personalProjectId. Writes use actual payload; final text not compliance.',
3
- 'Before asking for stable project fact or method inspect task_knowledge_recall. On miss search_current_project_knowledge with focused action, artifact, target-system, or identifier queries; never use the whole conversational request as the only query. Search active child first, then authorized inheritable parent (PART_OF/USES_KNOWLEDGE_FROM); local_only/RELATED_TO never inherit.',
4
- 'Before saying unknown call search_knowledge_graph; exact IDs for extra projects. RELATED_TO suggests; ask. all_local_confirmed only after consent; rg safe current repo/workspace; Never scan outside it. monitoring/Git MCP; search_connected_knowledge; agent_decide response-only.',
5
- 'record_decision_trace; failures record_knowledge_feedback. Batch durable confirmed knowledge: capture_session_knowledge; no secrets. checkpoint_task_knowledge: capture_candidates or retain_nothing; record_knowledge_usage.',
6
- 'Team: coordinate_project_agent_task gives isolated contexts; Fuli never spawns. Host: acquire_runtime_lease, start workers, report activity/executor, release_runtime_lease in finally.',
7
- 'Non-empty Provider executionSummary: one row/worker: occupation emoji/label, actual executor/sourceApplication, work summary, workerStatus/status. Empty/absent executionSummary: omit. Configured/allowed/available are not evidence.',
8
- 'Terminal-safe Markdown; never wrap in HTML. A match is a candidate only. If it supports the answer, MUST begin sourceMarker.leadMarkdown and append sourceMarker.markdown; otherwise use noMatchSourceMarker (empty). Keep unchanged.'
2
+ "Each user task: begin_task_context hook-provided task context; else before tools/answer call exactly get_collaboration_preferences(projectPath=cwd taskPrompt=current user request); never substitute project action. All effective_preferences: personal-global everywhere; matched project, authorized inheritable parent. get_user_taste_skill never replaces user Skill. Resolve deferred_conflict; never guess personalProjectId. Writes=actual payload; final text=not compliance.",
3
+ "Before asking stable project fact/method: task_knowledge_recall; miss: search_current_project_knowledge with focused action/artifact/target/ID queries, never only the full request. Active child first, then inheritable parent; no local_only/RELATED_TO.",
4
+ "Before saying unknown: search_knowledge_graph; extra projects=exact IDs. all_local_confirmed only after consent; rg only current repo/workspace. monitoring/Git MCP; search_connected_knowledge; agent_decide response-only.",
5
+ "record_decision_trace; errors: record_knowledge_feedback. Batch durable confirmed knowledge: capture_session_knowledge; no secrets. checkpoint_task_knowledge: capture_candidates/retain_nothing; record_knowledge_usage.",
6
+ "coordinate_project_agent_task=isolated context; Fuli never spawns. acquire_runtime_lease; run/report; release_runtime_lease in finally.",
7
+ "project_management_context: actionable work via authorized manager+board; keep chosen specialist; no excluded projects/extra model. Rename: exact current native session, host rename tool, manual-title protection; receipt after actual client result.",
8
+ "Task runs until all workerStatus terminal. executionSummary: one table row/worker: occupation emoji/label, actual executor/sourceApplication, work/status/session/link, source-labelled cumulative tokens. Missing=unknown; no invent/estimate/copy totals. Empty: omit. Configured/allowed/available not evidence.",
9
+ "Terminal-safe Markdown; no HTML. Match=candidate only. If supported: MUST begin sourceMarker.leadMarkdown; append sourceMarker.markdown; otherwise noMatchSourceMarker (empty). Keep unchanged."
9
10
  ].join(' ');
@@ -0,0 +1,74 @@
1
+ import { randomUUID } from 'node:crypto';
2
+
3
+ // The Provider is the sole source of truth. Hooks commonly use separate MCP
4
+ // processes; a process-local cache cannot prove that a task was checkpointed.
5
+ export class ProviderTaskContextRegistry {
6
+ constructor(provider, personalSpaceId) {
7
+ this.provider = provider;
8
+ this.personalSpaceId = personalSpaceId;
9
+ }
10
+
11
+ async begin(input) {
12
+ return taskRecord(await this.provider.beginTaskContext({
13
+ personal_space_id: this.personalSpaceId,
14
+ personal_project_id: input.personalProjectId ?? null,
15
+ project_agent_id: input.projectAgentId ?? null,
16
+ session_id: input.sessionId,
17
+ source_application: input.sourceApplication ?? 'other',
18
+ source_session_id: input.sourceSessionId ?? null,
19
+ token: `fuli-task-${randomUUID()}`,
20
+ turn_id: input.turnId ?? null,
21
+ memory_revision: input.memoryRevision ?? null
22
+ }));
23
+ }
24
+
25
+ async context(token, sourceApplication = 'other') {
26
+ return taskRecord(await this.provider.getTaskContext(token, {
27
+ personal_space_id: this.personalSpaceId, source_application: sourceApplication
28
+ }));
29
+ }
30
+
31
+ prepare(token, checkpoint, sourceApplication = 'other', agentMemory = null) {
32
+ return this.#write(token, checkpoint, 'prepare', sourceApplication, agentMemory);
33
+ }
34
+
35
+ checkpoint(token, checkpoint, sourceApplication = 'other') {
36
+ return this.#write(token, checkpoint, 'complete', sourceApplication);
37
+ }
38
+
39
+ verify(sessionId, sourceApplication = 'other') {
40
+ return this.provider.verifyTaskCheckpoint({
41
+ personal_space_id: this.personalSpaceId, session_id: sessionId,
42
+ source_application: sourceApplication
43
+ });
44
+ }
45
+
46
+ async #write(token, value, phase, sourceApplication, agentMemory = null) {
47
+ return taskRecord(await this.provider.checkpointTaskContext(token, {
48
+ personal_space_id: this.personalSpaceId, source_application: sourceApplication,
49
+ phase, disposition: value.disposition, reason: value.reason,
50
+ fingerprint: value.fingerprint, capture_status: value.captureStatus ?? null,
51
+ ...(agentMemory ? { agent_memory: agentMemory } : {})
52
+ }));
53
+ }
54
+ }
55
+
56
+ function taskRecord(value) {
57
+ if (typeof value?.token !== 'string' || !value?.session_id) {
58
+ throw new TypeError('Provider did not return a durable task context');
59
+ }
60
+ return {
61
+ token: value.token, sessionId: value.session_id,
62
+ personalProjectId: value.personal_project_id,
63
+ projectAgentId: value.project_agent_id,
64
+ sourceApplication: value.source_application,
65
+ sourceSessionId: value.source_session_id ?? null,
66
+ turnId: value.turn_id ?? null,
67
+ memoryRevision: value.memory_revision,
68
+ agentMemory: value.agent_memory ?? null,
69
+ previousCheckpointMissing: Boolean(value.previous_checkpoint_missing),
70
+ checkpoint: value.checkpoint ? {
71
+ ...value.checkpoint, captureStatus: value.checkpoint.capture_status
72
+ } : null
73
+ };
74
+ }