clay-server 5.2.0-beta.4 → 5.2.0-beta.6
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/lib/account-auth-socket.js +1 -0
- package/lib/builtin-mates.js +17 -14
- package/lib/canonical-clay-record-authority.js +15 -0
- package/lib/canonical-clay-scheduling-authority.js +19 -0
- package/lib/claude-hook-installer.js +1 -239
- package/lib/claude-jsonl-watcher.js +1 -204
- package/lib/clay-mate-chat-receipts.js +26 -0
- package/lib/clay-mate-chat.js +87 -0
- package/lib/clay-mate-knowledge-input.js +26 -0
- package/lib/clay-mate-knowledge.js +95 -0
- package/lib/clay-mate-lifecycle.js +95 -0
- package/lib/clay-product-control-input.js +33 -0
- package/lib/clay-product-control-tools.js +51 -0
- package/lib/clay-product-control.js +237 -0
- package/lib/clay-project-lifecycle.js +154 -0
- package/lib/clay-project-record-input.js +44 -0
- package/lib/clay-project-records.js +83 -0
- package/lib/clay-scheduling-input.js +21 -0
- package/lib/clay-scheduling-receipts.js +26 -0
- package/lib/clay-scheduling.js +119 -0
- package/lib/clay-screen-controls.js +96 -0
- package/lib/clay-skill-install.js +1 -33
- package/lib/clay-workspace-controls.js +83 -0
- package/lib/clay-workspace-input.js +17 -0
- package/lib/clay-workspace-receipts.js +26 -0
- package/lib/cli-sessions.js +1 -300
- package/lib/codex-defaults.js +1 -28
- package/lib/context-usage.js +3 -2
- package/lib/daemon-project-access.js +11 -0
- package/lib/daemon-project-lifecycle-callbacks.js +15 -0
- package/lib/daemon-project-lifecycle.js +262 -0
- package/lib/daemon-projects.js +1 -1
- package/lib/daemon.js +78 -276
- package/lib/default-ai-runtime.js +4 -8
- package/lib/email-mcp-server.js +1 -1
- package/lib/issues-service.js +29 -15
- package/lib/kiro-defaults.js +1 -22
- package/lib/knowledge-db-import.js +5 -4
- package/lib/knowledge-db-service.js +9 -6
- package/lib/knowledge-document-index.js +2 -1
- package/lib/knowledge-product-operations.js +46 -0
- package/lib/mate-creation-mcp-server.js +2 -0
- package/lib/mate-knowledge-canonical-access.js +10 -0
- package/lib/mate-knowledge-service.js +7 -4
- package/lib/mate-lifecycle-service.js +94 -0
- package/lib/mate-message-delivery.js +43 -0
- package/lib/mate-ready-creation.js +9 -1
- package/lib/mate-schedule-input.js +29 -0
- package/lib/mate-schedule-lifecycle.js +151 -0
- package/lib/mate-scheduling.js +103 -0
- package/lib/mates.js +4 -3
- package/lib/mcp-proxy.js +2 -32
- package/lib/mcp-query-bridge.js +1 -1
- package/lib/mcp-source-adapters.js +1 -91
- package/lib/mcp-source-context.js +1 -42
- package/lib/mcp-source-discovery.js +1 -169
- package/lib/mcp-source-plugins.js +1 -68
- package/lib/mcp-source-restrictions.js +1 -47
- package/lib/mcp-tool-policy.js +1 -26
- package/lib/notes-checklist.js +50 -0
- package/lib/notes.js +49 -3
- package/lib/os-user-diagnostics.js +2 -4
- package/lib/os-users.js +24 -70
- package/lib/project-admin-overview.js +51 -0
- package/lib/project-ask-user.js +4 -2
- package/lib/project-connection.js +8 -7
- package/lib/project-delegated-follow-up.js +2 -1
- package/lib/project-directory-claim.js +65 -0
- package/lib/project-file-operations.js +61 -0
- package/lib/project-filesystem.js +13 -87
- package/lib/project-full-access.js +23 -2
- package/lib/project-http.js +4 -4
- package/lib/project-knowledge.js +32 -18
- package/lib/project-lifecycle-operations.js +98 -0
- package/lib/project-lifecycle-process-witness.js +32 -0
- package/lib/project-lifecycle-runtime.js +50 -0
- package/lib/project-linux-access.js +22 -0
- package/lib/project-logs-canonical-clay.js +27 -0
- package/lib/project-logs-clay-query.js +16 -0
- package/lib/project-logs-schema.js +4 -2
- package/lib/project-logs-service.js +8 -7
- package/lib/project-logs.js +1 -0
- package/lib/project-loop.js +1 -0
- package/lib/project-mate-chat-control.js +55 -0
- package/lib/project-mate-creation-proposal.js +18 -3
- package/lib/project-mcp.js +2 -2
- package/lib/project-models.js +14 -31
- package/lib/project-notifications.js +74 -16
- package/lib/project-ownership.js +77 -0
- package/lib/project-pair-result-delivery.js +14 -3
- package/lib/project-pair-usage.js +12 -13
- package/lib/project-pending-message-queue.js +4 -1
- package/lib/project-product-control.js +87 -0
- package/lib/project-product-session-queue.js +46 -0
- package/lib/project-push-access.js +28 -0
- package/lib/project-scheduled-message-queue.js +30 -0
- package/lib/project-scheduled-messages.js +63 -64
- package/lib/project-scheduled-task-control.js +83 -0
- package/lib/project-scheduled-tasks.js +13 -2
- package/lib/project-scheduling-access.js +10 -0
- package/lib/project-session-actions.js +65 -0
- package/lib/project-session-delete.js +8 -1
- package/lib/project-session-github.js +47 -12
- package/lib/project-session-history-actions.js +167 -0
- package/lib/project-session-pair.js +1 -1
- package/lib/project-session-runtime-actions.js +64 -0
- package/lib/project-session-spawn.js +2 -3
- package/lib/project-session-vendor.js +55 -0
- package/lib/project-sessions.js +82 -267
- package/lib/project-user-message.js +31 -1
- package/lib/project-vendor-login.js +6 -36
- package/lib/project-workspace-operations.js +126 -0
- package/lib/project-workspace-query.js +9 -2
- package/lib/project.js +95 -3
- package/lib/public/app.js +1 -0
- package/lib/public/css/clay-tool-activity.css +51 -0
- package/lib/public/css/home-mate-creation.css +5 -0
- package/lib/public/css/messages.css +6 -2
- package/lib/public/css/overlays.css +4 -2
- package/lib/public/css/project-admin-overview.css +13 -0
- package/lib/public/css/session-folders.css +11 -0
- package/lib/public/css/session-github.css +3 -0
- package/lib/public/css/sticky-notes.css +61 -1
- package/lib/public/index.html +1 -1
- package/lib/public/modules/admin-settings-projects.js +6 -2
- package/lib/public/modules/app-connection.js +8 -1
- package/lib/public/modules/app-favicon.js +11 -2
- package/lib/public/modules/app-header.js +4 -2
- package/lib/public/modules/app-loop-ui.js +2 -0
- package/lib/public/modules/app-message-router.js +1 -1
- package/lib/public/modules/app-messages.js +54 -8
- package/lib/public/modules/app-notifications.js +1 -2
- package/lib/public/modules/app-panels.js +61 -123
- package/lib/public/modules/app-projects.js +5 -0
- package/lib/public/modules/app-rate-limit.js +7 -27
- package/lib/public/modules/chat-render-runtime.js +3 -0
- package/lib/public/modules/clay-owner-navigation.js +27 -0
- package/lib/public/modules/clay-tool-activity.js +140 -0
- package/lib/public/modules/clay-tool-presentation.js +338 -0
- package/lib/public/modules/command-palette.js +1 -1
- package/lib/public/modules/default-ai.js +11 -3
- package/lib/public/modules/home-debate-planning.js +5 -5
- package/lib/public/modules/home-mate-chat.js +8 -6
- package/lib/public/modules/home-mate-creation.js +73 -1
- package/lib/public/modules/mcp-connection-view.js +1 -1
- package/lib/public/modules/permission-control.js +5 -4
- package/lib/public/modules/personal-settings-dialog.js +7 -1
- package/lib/public/modules/project-access-recovery.js +17 -0
- package/lib/public/modules/project-admin-overview.js +21 -0
- package/lib/public/modules/scheduler.js +2 -0
- package/lib/public/modules/session-create-form.js +10 -10
- package/lib/public/modules/session-folder-layout.js +1 -1
- package/lib/public/modules/session-folder-view-menu.js +9 -0
- package/lib/public/modules/session-github.js +65 -8
- package/lib/public/modules/settings-defaults.js +27 -28
- package/lib/public/modules/sidebar-session-folders-ui.js +1 -1
- package/lib/public/modules/sticky-note-markdown.js +72 -6
- package/lib/public/modules/sticky-notes-actions.js +30 -0
- package/lib/public/modules/sticky-notes-browser.js +9 -2
- package/lib/public/modules/sticky-notes-card.js +23 -7
- package/lib/public/modules/sticky-notes-checklist.js +71 -0
- package/lib/public/modules/sticky-notes-editor.js +108 -44
- package/lib/public/modules/sticky-notes-shared.js +50 -2
- package/lib/public/modules/sticky-notes-state.js +66 -0
- package/lib/public/modules/sticky-notes.js +34 -51
- package/lib/public/modules/thinking-lifecycle.js +33 -3
- package/lib/public/modules/thinking-view.js +23 -1
- package/lib/public/modules/tools.js +36 -7
- package/lib/public/modules/tui-grab.js +1 -2
- package/lib/public/modules/user-settings-appearance.js +10 -3
- package/lib/public/modules/user-settings-editors.js +1 -1
- package/lib/public/modules/user-settings-layout.js +11 -2
- package/lib/public/modules/user-settings-preferences.js +6 -2
- package/lib/public/modules/user-settings-profile.js +12 -2
- package/lib/public/modules/user-settings.js +3 -2
- package/lib/public/modules/vendor-login-browser.js +5 -3
- package/lib/public/modules/vendor-login.js +2 -2
- package/lib/public/modules/vendor-priority.js +15 -1
- package/lib/public/muse-avatar.svg +4 -0
- package/lib/public/style.css +2 -0
- package/lib/safe-bash-commands.js +3 -45
- package/lib/scheduled-task-records.js +3 -1
- package/lib/scheduler.js +2 -0
- package/lib/sdk-bridge.js +334 -403
- package/lib/sdk-foreground-admission.js +16 -0
- package/lib/sdk-mcp-descriptors.js +2 -37
- package/lib/sdk-message-processor.js +52 -17
- package/lib/sdk-quota-snapshot.js +1 -1
- package/lib/sdk-response-recovery.js +1 -0
- package/lib/sdk-worker.js +2 -677
- package/lib/server-admin.js +63 -16
- package/lib/server-dm.js +1 -1
- package/lib/server-global-ws.js +10 -20
- package/lib/server-home-chat-events.js +7 -3
- package/lib/server-home-chat.js +4 -16
- package/lib/server-home-mate-creation.js +1 -0
- package/lib/server-home-mcp-consent.js +3 -3
- package/lib/server-mates.js +25 -67
- package/lib/server-owner-ui.js +77 -0
- package/lib/server-path-access.js +38 -0
- package/lib/server-project-removal.js +22 -0
- package/lib/server.js +100 -30
- package/lib/session-config-transition.js +45 -0
- package/lib/session-folders.js +7 -2
- package/lib/session-fork-history.js +21 -0
- package/lib/session-github.js +9 -2
- package/lib/session-hygiene.js +3 -35
- package/lib/session-permission-mode.js +4 -3
- package/lib/session-skill-scope.js +11 -0
- package/lib/session-visibility.js +5 -2
- package/lib/sessions.js +27 -89
- package/lib/terminal-manager.js +52 -0
- package/lib/tool-llm.js +1 -1
- package/lib/tui-transcript-index.js +1 -132
- package/lib/users-permissions.js +2 -8
- package/lib/users.js +4 -0
- package/lib/vendor-login-browser.js +1 -11
- package/lib/workspace-query-access.js +4 -1
- package/lib/ws-schema.js +8 -2
- package/lib/yoke/acp-agent-profiles.js +5 -3
- package/lib/yoke/adapters/antigravity.js +3 -14
- package/lib/yoke/adapters/claude-query-contract.js +9 -0
- package/lib/yoke/adapters/claude.js +54 -50
- package/lib/yoke/adapters/codex-query-contract.js +24 -0
- package/lib/yoke/adapters/codex.js +53 -111
- package/lib/yoke/adapters/kiro.js +3 -1
- package/lib/yoke/adapters/muse-query-contract.js +7 -0
- package/lib/yoke/adapters/muse.js +122 -0
- package/lib/yoke/auth-events.js +17 -0
- package/lib/yoke/claude-hook-installer.js +267 -0
- package/lib/yoke/claude-jsonl-watcher.js +204 -0
- package/lib/yoke/claude-maintenance.js +55 -0
- package/lib/yoke/claude-permission-patterns.js +53 -0
- package/lib/yoke/claude-response-recovery.js +155 -0
- package/lib/yoke/claude-transcript-hygiene.js +34 -0
- package/lib/yoke/claude-worker-startup.js +28 -0
- package/lib/yoke/clay-skill-install.js +33 -0
- package/lib/yoke/cli-sessions.js +300 -0
- package/lib/yoke/codex-app-server.js +7 -12
- package/lib/yoke/codex-idle-recovery.js +81 -1
- package/lib/yoke/codex-recovery-admission.js +164 -0
- package/lib/yoke/configuration.js +13 -0
- package/lib/yoke/discovery.js +70 -0
- package/lib/yoke/errors.js +8 -0
- package/lib/yoke/host-environment.js +7 -0
- package/lib/yoke/index.js +9 -51
- package/lib/yoke/interface.js +116 -0
- package/lib/yoke/kiro-acp-server.js +5 -5
- package/lib/yoke/legacy-sessions.js +89 -0
- package/lib/yoke/login-protocol.js +25 -0
- package/lib/yoke/maintenance.js +12 -0
- package/lib/yoke/mcp-proxy.js +32 -0
- package/lib/yoke/mcp-source-adapters.js +91 -0
- package/lib/yoke/mcp-source-context.js +42 -0
- package/lib/yoke/mcp-source-discovery.js +169 -0
- package/lib/yoke/mcp-source-plugins.js +68 -0
- package/lib/yoke/mcp-source-restrictions.js +47 -0
- package/lib/yoke/mcp-tool-policy-normalize.js +28 -0
- package/lib/yoke/model-preferences.js +6 -0
- package/lib/yoke/muse-artifacts.js +36 -0
- package/lib/yoke/muse-controls.js +50 -0
- package/lib/yoke/muse-input.js +64 -0
- package/lib/yoke/muse-items.js +157 -0
- package/lib/yoke/muse-policy.js +52 -0
- package/lib/yoke/muse-query.js +428 -0
- package/lib/yoke/muse-runtime.js +211 -0
- package/lib/yoke/muse-services.js +79 -0
- package/lib/yoke/muse-skills.js +79 -0
- package/lib/yoke/muse-turns.js +71 -0
- package/lib/yoke/options/acp.js +2 -0
- package/lib/yoke/options/antigravity.js +2 -0
- package/lib/yoke/options/claude.js +21 -0
- package/lib/yoke/options/codex-defaults.js +29 -0
- package/lib/yoke/options/codex-settings.js +21 -0
- package/lib/yoke/options/codex.js +6 -0
- package/lib/yoke/options/kiro-defaults.js +22 -0
- package/lib/yoke/options/kiro.js +5 -0
- package/lib/yoke/options/muse.js +5 -0
- package/lib/yoke/provider-contract.js +5 -0
- package/lib/yoke/providers/antigravity-executable.js +8 -0
- package/lib/yoke/providers/claude-executable.js +40 -0
- package/lib/yoke/providers/claude-model-descriptions.js +14 -0
- package/lib/yoke/providers/claude-process.js +97 -0
- package/lib/yoke/providers/claude-provision.js +75 -0
- package/lib/yoke/providers/codex-errors.js +8 -0
- package/lib/yoke/providers/muse-executable.js +17 -0
- package/lib/yoke/provisioning.js +6 -0
- package/lib/yoke/query-options.js +10 -0
- package/lib/yoke/response-recovery.js +41 -0
- package/lib/yoke/sdk-mcp-descriptors.js +37 -0
- package/lib/yoke/sdk-server-factory.js +7 -0
- package/lib/yoke/session-history.js +8 -0
- package/lib/yoke/session-tool-transport.js +34 -13
- package/lib/yoke/settings.js +23 -0
- package/lib/yoke/source-locations.js +4 -0
- package/lib/yoke/title-query.js +18 -7
- package/lib/yoke/tui-transcript-index.js +132 -0
- package/lib/yoke/usage.js +48 -0
- package/lib/yoke/user-input.js +13 -0
- package/lib/yoke/vendor-registry.js +81 -1
- package/package.json +3 -2
package/lib/daemon-projects.js
CHANGED
|
@@ -146,7 +146,7 @@ function cleanupWorktreesForParent(relay, parentSlug) {
|
|
|
146
146
|
function getFilteredRemovedProjects(config, userId) {
|
|
147
147
|
if (!config.removedProjects || config.removedProjects.length === 0) return [];
|
|
148
148
|
return config.removedProjects.filter(function (rp) {
|
|
149
|
-
if (userId && rp.userId
|
|
149
|
+
if (userId && rp.userId !== userId) return false;
|
|
150
150
|
if (!userId && rp.userId) return false;
|
|
151
151
|
return fs.existsSync(rp.path);
|
|
152
152
|
});
|
package/lib/daemon.js
CHANGED
|
@@ -20,7 +20,7 @@ process.setMaxListeners(50);
|
|
|
20
20
|
|
|
21
21
|
// Remove CLAUDECODE env var so the SDK can spawn Claude Code child processes
|
|
22
22
|
// (prevents "cannot be launched inside another Claude Code session" error)
|
|
23
|
-
|
|
23
|
+
require("./yoke/host-environment").prepare(process.env);
|
|
24
24
|
|
|
25
25
|
var fs = require("fs");
|
|
26
26
|
var path = require("path");
|
|
@@ -67,6 +67,8 @@ try {
|
|
|
67
67
|
console.error("[daemon] ensureMultiUser threw (continuing):", e && e.message);
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
+
config = require("./project-ownership").repair(config, usersModule.getAllUsers(), saveConfig, osUsersMod.resolveOsUserInfo);
|
|
71
|
+
|
|
70
72
|
if (projectLogContext.initializeProjectKnowledge(config)) {
|
|
71
73
|
saveConfig(config);
|
|
72
74
|
console.log("[daemon] Assigned stable knowledge identities to existing projects");
|
|
@@ -187,7 +189,14 @@ function registerProjectWorktrees(project, requestUser) {
|
|
|
187
189
|
}
|
|
188
190
|
}
|
|
189
191
|
|
|
192
|
+
var projectLifecycle = require("./daemon-project-lifecycle").attachProjectLifecycle({
|
|
193
|
+
getConfig: function () { return config; }, setConfig: function (next) { config = next; }, saveConfig: saveConfig,
|
|
194
|
+
getRelay: function () { return relay; }, resolveIdentity: osUsersMod.resolveOsUserInfo,
|
|
195
|
+
findUser: usersModule.findUserById, registerWorktrees: registerProjectWorktrees,
|
|
196
|
+
});
|
|
197
|
+
var lifecycleCallbacks = require("./daemon-project-lifecycle-callbacks").attachLifecycleCallbacks({ service: projectLifecycle });
|
|
190
198
|
var relay = createServer({
|
|
199
|
+
projectLifecycle: projectLifecycle,
|
|
191
200
|
tlsOptions: tlsOptions,
|
|
192
201
|
caPath: caRoot,
|
|
193
202
|
builtinCert: config.builtinCert || false,
|
|
@@ -198,122 +207,11 @@ var relay = createServer({
|
|
|
198
207
|
osUsers: config.osUsers || false,
|
|
199
208
|
lanHost: lanIp ? lanIp + ":" + config.port : null,
|
|
200
209
|
getRemovedProjects: function (userId) { return getFilteredRemovedProjects(config, userId); },
|
|
201
|
-
onAddProject:
|
|
202
|
-
|
|
203
|
-
for (var j = 0; j < config.projects.length; j++) {
|
|
204
|
-
if (config.projects[j].path === absPath) {
|
|
205
|
-
return { ok: true, slug: config.projects[j].slug, existing: true };
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
var slugs = config.projects.map(function (p) { return p.slug; });
|
|
209
|
-
var slug = generateSlug(absPath, slugs);
|
|
210
|
-
var projectEntry = { path: absPath, slug: slug, addedAt: Date.now(), visibility: "private" };
|
|
211
|
-
projectEntry.projectKnowledgeId = rememberedProjectKnowledgeId(absPath);
|
|
212
|
-
// The user who adds a project always becomes the owner
|
|
213
|
-
if (wsUser && wsUser.id) {
|
|
214
|
-
projectEntry.ownerId = wsUser.id;
|
|
215
|
-
}
|
|
216
|
-
config.projects.push(projectEntry);
|
|
217
|
-
relay.addProject(absPath, slug, null, null, wsUser ? wsUser.id : null, null, projectRuntimeOptions(projectEntry));
|
|
218
|
-
// Remove from removedProjects if present
|
|
219
|
-
if (config.removedProjects) {
|
|
220
|
-
config.removedProjects = config.removedProjects.filter(function (rp) { return rp.path !== absPath; });
|
|
221
|
-
}
|
|
222
|
-
saveConfig(config);
|
|
223
|
-
try { syncClayrc(config.projects); } catch (e) {}
|
|
224
|
-
console.log("[daemon] Added project (web):", slug, "→", absPath);
|
|
225
|
-
// OS users mode: grant ACL to project owner
|
|
226
|
-
if (config.osUsers) {
|
|
227
|
-
var newProj = config.projects[config.projects.length - 1];
|
|
228
|
-
if (newProj.ownerId) {
|
|
229
|
-
var ownerUser = usersModule.findUserById(newProj.ownerId);
|
|
230
|
-
if (ownerUser && ownerUser.linuxUser) {
|
|
231
|
-
grantProjectAccess(absPath, ownerUser.linuxUser);
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
// Discover and register worktrees for the new project
|
|
236
|
-
registerProjectWorktrees(projectEntry, wsUser);
|
|
237
|
-
// Broadcast updated project list to all clients
|
|
238
|
-
relay.broadcastAll({
|
|
239
|
-
type: "projects_updated",
|
|
240
|
-
projects: relay.getProjects(),
|
|
241
|
-
projectCount: config.projects.length,
|
|
242
|
-
});
|
|
243
|
-
return { ok: true, slug: slug };
|
|
244
|
-
},
|
|
245
|
-
onCreateProject: function (projectName, wsUser) {
|
|
246
|
-
console.log("[daemon] onCreateProject wsUser:", JSON.stringify(wsUser ? { id: wsUser.id, role: wsUser.role, username: wsUser.username, linuxUser: wsUser.linuxUser } : null));
|
|
247
|
-
var os = require("os");
|
|
248
|
-
var execFileSync = require("child_process").execFileSync;
|
|
249
|
-
var baseDir;
|
|
250
|
-
if (config.osUsers) {
|
|
251
|
-
baseDir = "/var/clay/projects";
|
|
252
|
-
} else {
|
|
253
|
-
baseDir = config.projectsDir || path.join(REAL_HOME, "clay-projects");
|
|
254
|
-
}
|
|
255
|
-
try { fs.mkdirSync(baseDir, { recursive: true }); } catch (e) {}
|
|
256
|
-
// Generate slug and deduplicate
|
|
257
|
-
var slugs = config.projects.map(function (p) { return p.slug; });
|
|
258
|
-
var slug = generateSlug(path.join(baseDir, projectName), slugs);
|
|
259
|
-
var targetDir = path.join(baseDir, slug);
|
|
260
|
-
try {
|
|
261
|
-
fs.mkdirSync(targetDir, { recursive: true });
|
|
262
|
-
// Run git init
|
|
263
|
-
if (config.osUsers && wsUser) {
|
|
264
|
-
var linuxUser = wsUser.linuxUser;
|
|
265
|
-
if (linuxUser) {
|
|
266
|
-
var uidGid = null;
|
|
267
|
-
try {
|
|
268
|
-
uidGid = {
|
|
269
|
-
uid: parseInt(execFileSync("id", ["-u", linuxUser], { encoding: "utf8", stdio: "pipe" }).trim(), 10),
|
|
270
|
-
gid: parseInt(execFileSync("id", ["-g", linuxUser], { encoding: "utf8", stdio: "pipe" }).trim(), 10),
|
|
271
|
-
};
|
|
272
|
-
} catch (e) {}
|
|
273
|
-
if (uidGid) {
|
|
274
|
-
fs.chmodSync(targetDir, 0o700);
|
|
275
|
-
execFileSync("chown", ["-R", linuxUser + ":" + linuxUser, targetDir]);
|
|
276
|
-
var gitInit = osUsersMod.wrapSpawnAsUser("git", ["init"], { cwd: targetDir, uid: uidGid.uid, gid: uidGid.gid, env: { PATH: "/usr/local/bin:/usr/bin:/bin" } });
|
|
277
|
-
execFileSync(gitInit.command, gitInit.args, gitInit.options);
|
|
278
|
-
} else {
|
|
279
|
-
execFileSync("git", ["init"], { cwd: targetDir });
|
|
280
|
-
}
|
|
281
|
-
} else {
|
|
282
|
-
execFileSync("git", ["init"], { cwd: targetDir });
|
|
283
|
-
}
|
|
284
|
-
} else {
|
|
285
|
-
execFileSync("git", ["init"], { cwd: targetDir });
|
|
286
|
-
}
|
|
287
|
-
} catch (e) {
|
|
288
|
-
try { fs.rmSync(targetDir, { recursive: true, force: true }); } catch (ce) {}
|
|
289
|
-
return { ok: false, error: "Failed to create project: " + e.message };
|
|
290
|
-
}
|
|
291
|
-
// Register project - creator always becomes owner, default private
|
|
292
|
-
var projectEntry = { path: targetDir, slug: slug, addedAt: Date.now(), visibility: "private" };
|
|
293
|
-
projectEntry.projectKnowledgeId = projectLogContext.createProjectKnowledgeId();
|
|
294
|
-
if (wsUser && wsUser.id) {
|
|
295
|
-
projectEntry.ownerId = wsUser.id;
|
|
296
|
-
}
|
|
297
|
-
relay.addProject(targetDir, slug, null, null, wsUser ? wsUser.id : null, null, projectRuntimeOptions(projectEntry));
|
|
298
|
-
config.projects.push(projectEntry);
|
|
299
|
-
saveConfig(config);
|
|
300
|
-
try { syncClayrc(config.projects); } catch (e) {}
|
|
301
|
-
console.log("[daemon] Created project:", slug, "→", targetDir, "entry:", JSON.stringify({ ownerId: projectEntry.ownerId, visibility: projectEntry.visibility }));
|
|
302
|
-
// OS users mode: grant ACL
|
|
303
|
-
if (config.osUsers && wsUser && wsUser.linuxUser) {
|
|
304
|
-
console.log("[daemon] Granting ACL:", targetDir, "→", wsUser.linuxUser);
|
|
305
|
-
grantProjectAccess(targetDir, wsUser.linuxUser);
|
|
306
|
-
} else if (config.osUsers) {
|
|
307
|
-
console.log("[daemon] Skipping ACL grant: osUsers=true but linuxUser=", wsUser && wsUser.linuxUser);
|
|
308
|
-
}
|
|
309
|
-
relay.broadcastAll({
|
|
310
|
-
type: "projects_updated",
|
|
311
|
-
projects: relay.getProjects(),
|
|
312
|
-
projectCount: config.projects.length,
|
|
313
|
-
});
|
|
314
|
-
return { ok: true, slug: slug };
|
|
315
|
-
},
|
|
210
|
+
onAddProject: lifecycleCallbacks.onAddProject,
|
|
211
|
+
onCreateProject: lifecycleCallbacks.onCreateProject,
|
|
316
212
|
onCloneProject: function (cloneUrl, wsUser, callback) {
|
|
213
|
+
wsUser = wsUser && usersModule.findUserById(wsUser.id);
|
|
214
|
+
if (usersModule.isMultiUser() && !wsUser) { callback({ ok: false, error: "A valid account is required." }); return; }
|
|
317
215
|
var os = require("os");
|
|
318
216
|
var spawn = require("child_process").spawn;
|
|
319
217
|
var execFileSync = require("child_process").execFileSync;
|
|
@@ -323,12 +221,15 @@ var relay = createServer({
|
|
|
323
221
|
} else {
|
|
324
222
|
baseDir = config.projectsDir || path.join(REAL_HOME, "clay-projects");
|
|
325
223
|
}
|
|
326
|
-
try { fs.mkdirSync(baseDir, { recursive: true }); } catch (e) {}
|
|
327
224
|
// Derive slug from repo URL
|
|
328
225
|
var repoName = cloneUrl.replace(/\.git$/, "").split("/").pop() || "project";
|
|
329
226
|
var slugs = config.projects.map(function (p) { return p.slug; });
|
|
330
227
|
var slug = generateSlug(path.join(baseDir, repoName), slugs);
|
|
331
|
-
var targetDir
|
|
228
|
+
var targetDir;
|
|
229
|
+
var directoryClaim;
|
|
230
|
+
var settled = false;
|
|
231
|
+
function finish(result) { if (settled) return; settled = true; callback(result); }
|
|
232
|
+
function cleanup() { if (directoryClaim) { try { directoryClaim.cleanup(); } catch (error) {} } }
|
|
332
233
|
// Clone as user to use their git credentials
|
|
333
234
|
var spawnOpts = { cwd: baseDir };
|
|
334
235
|
if (config.osUsers && wsUser && wsUser.linuxUser) {
|
|
@@ -341,22 +242,23 @@ var relay = createServer({
|
|
|
341
242
|
});
|
|
342
243
|
} catch (e) {}
|
|
343
244
|
}
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
245
|
+
try {
|
|
246
|
+
directoryClaim = require("./project-directory-claim").claim({ baseDir: baseDir, slug: slug, projects: config.projects, userId: wsUser && wsUser.id });
|
|
247
|
+
targetDir = directoryClaim.path;
|
|
248
|
+
directoryClaim.assertOwned();
|
|
249
|
+
if (config.osUsers && wsUser && wsUser.linuxUser && spawnOpts.uid != null) fs.chownSync(targetDir, spawnOpts.uid, spawnOpts.gid);
|
|
250
|
+
directoryClaim.assertOwned();
|
|
251
|
+
} catch (error) {
|
|
252
|
+
cleanup();
|
|
253
|
+
finish({ ok: false, error: "Failed to prepare project directory: " + error.message });
|
|
347
254
|
return;
|
|
348
255
|
}
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
return;
|
|
356
|
-
}
|
|
357
|
-
}
|
|
358
|
-
var cloneSpawn = osUsersMod.wrapSpawnAsUser("git", ["clone", cloneUrl, targetDir], spawnOpts);
|
|
359
|
-
var proc = spawn(cloneSpawn.command, cloneSpawn.args, cloneSpawn.options);
|
|
256
|
+
var proc;
|
|
257
|
+
try {
|
|
258
|
+
directoryClaim.assertOwned();
|
|
259
|
+
var cloneSpawn = osUsersMod.wrapSpawnAsUser("git", ["clone", cloneUrl, targetDir], spawnOpts);
|
|
260
|
+
proc = spawn(cloneSpawn.command, cloneSpawn.args, cloneSpawn.options);
|
|
261
|
+
} catch (error) { cleanup(); finish({ ok: false, error: "Failed to start git clone: " + error.message }); return; }
|
|
360
262
|
var stderrBuf = "";
|
|
361
263
|
proc.stderr.on("data", function (chunk) { stderrBuf += chunk.toString(); });
|
|
362
264
|
// 5 minute timeout
|
|
@@ -365,19 +267,23 @@ var relay = createServer({
|
|
|
365
267
|
}, 5 * 60 * 1000);
|
|
366
268
|
proc.on("close", function (code) {
|
|
367
269
|
clearTimeout(cloneTimeout);
|
|
270
|
+
if (settled) return;
|
|
271
|
+
try { directoryClaim.assertOwned(); } catch (error) { finish({ ok: false, error: error.message }); return; }
|
|
368
272
|
if (code !== 0) {
|
|
369
|
-
|
|
273
|
+
cleanup();
|
|
370
274
|
var errMsg = stderrBuf.trim().split("\n").pop() || "Clone failed (exit code " + code + ")";
|
|
371
|
-
|
|
275
|
+
finish({ ok: false, error: errMsg });
|
|
372
276
|
return;
|
|
373
277
|
}
|
|
374
278
|
// chown and restrict permissions if osUsers
|
|
375
279
|
if (config.osUsers && wsUser && wsUser.linuxUser) {
|
|
376
280
|
try {
|
|
281
|
+
directoryClaim.assertOwned();
|
|
377
282
|
fs.chmodSync(targetDir, 0o700);
|
|
378
283
|
execFileSync("chown", ["-R", wsUser.linuxUser + ":" + wsUser.linuxUser, targetDir]);
|
|
379
284
|
} catch (e) {}
|
|
380
285
|
}
|
|
286
|
+
if (usersModule.isMultiUser() && (!wsUser || !usersModule.findUserById(wsUser.id))) { finish({ ok: false, error: "The creating account is no longer available." }); return; }
|
|
381
287
|
// Register project - creator always becomes owner
|
|
382
288
|
// Creator always becomes owner, default private
|
|
383
289
|
var projectEntry = { path: targetDir, slug: slug, addedAt: Date.now(), visibility: "private" };
|
|
@@ -385,9 +291,11 @@ var relay = createServer({
|
|
|
385
291
|
if (wsUser && wsUser.id) {
|
|
386
292
|
projectEntry.ownerId = wsUser.id;
|
|
387
293
|
}
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
294
|
+
try {
|
|
295
|
+
directoryClaim.assertOwned();
|
|
296
|
+
config = require("./project-ownership").register(config, projectEntry, usersModule.getAllUsers(), saveConfig, osUsersMod.resolveOsUserInfo);
|
|
297
|
+
} catch (error) { finish({ ok: false, error: "Failed to register project: " + error.message }); return; }
|
|
298
|
+
relay.addProject(targetDir, slug, null, null, projectEntry.ownerId || null, null, projectRuntimeOptions(projectEntry));
|
|
391
299
|
try { syncClayrc(config.projects); } catch (e) {}
|
|
392
300
|
console.log("[daemon] Cloned project:", slug, "→", targetDir);
|
|
393
301
|
if (config.osUsers && wsUser && wsUser.linuxUser) {
|
|
@@ -398,12 +306,13 @@ var relay = createServer({
|
|
|
398
306
|
projects: relay.getProjects(),
|
|
399
307
|
projectCount: config.projects.length,
|
|
400
308
|
});
|
|
401
|
-
|
|
309
|
+
finish({ ok: true, slug: slug });
|
|
402
310
|
});
|
|
403
311
|
proc.on("error", function (err) {
|
|
404
312
|
clearTimeout(cloneTimeout);
|
|
405
|
-
|
|
406
|
-
|
|
313
|
+
if (settled) return;
|
|
314
|
+
cleanup();
|
|
315
|
+
finish({ ok: false, error: "Failed to start git clone: " + err.message });
|
|
407
316
|
});
|
|
408
317
|
},
|
|
409
318
|
onRemoveProject: function (slug, userId) {
|
|
@@ -444,40 +353,7 @@ var relay = createServer({
|
|
|
444
353
|
});
|
|
445
354
|
return { ok: true };
|
|
446
355
|
}
|
|
447
|
-
|
|
448
|
-
for (var j = 0; j < config.projects.length; j++) {
|
|
449
|
-
if (config.projects[j].slug === slug) { found = config.projects[j]; break; }
|
|
450
|
-
}
|
|
451
|
-
if (!found) return { ok: false, error: "Project not found" };
|
|
452
|
-
// Cascade remove worktrees belonging to this parent
|
|
453
|
-
cleanupWorktreesForParent(relay, slug);
|
|
454
|
-
// Save to removedProjects for re-add functionality
|
|
455
|
-
if (!config.removedProjects) config.removedProjects = [];
|
|
456
|
-
config.removedProjects.push({
|
|
457
|
-
path: found.path,
|
|
458
|
-
title: found.title || null,
|
|
459
|
-
icon: found.icon || null,
|
|
460
|
-
userId: userId || null,
|
|
461
|
-
projectKnowledgeId: found.projectKnowledgeId || null,
|
|
462
|
-
removedAt: Date.now(),
|
|
463
|
-
});
|
|
464
|
-
// Cap at 20 entries (oldest first)
|
|
465
|
-
if (config.removedProjects.length > 20) {
|
|
466
|
-
config.removedProjects = config.removedProjects.slice(config.removedProjects.length - 20);
|
|
467
|
-
}
|
|
468
|
-
relay.removeProject(slug);
|
|
469
|
-
config.projects = config.projects.filter(function (p) { return p.slug !== slug; });
|
|
470
|
-
saveConfig(config);
|
|
471
|
-
// Remove from .clayrc so it doesn't appear in restore prompt
|
|
472
|
-
if (found.path) { try { removeFromClayrc(found.path); } catch (e) {} }
|
|
473
|
-
try { syncClayrc(config.projects); } catch (e) {}
|
|
474
|
-
console.log("[daemon] Removed project (web):", slug);
|
|
475
|
-
relay.broadcastAll({
|
|
476
|
-
type: "projects_updated",
|
|
477
|
-
projects: relay.getProjects(),
|
|
478
|
-
projectCount: config.projects.length,
|
|
479
|
-
});
|
|
480
|
-
return { ok: true };
|
|
356
|
+
return lifecycleCallbacks.onRemoveProject(slug, userId);
|
|
481
357
|
},
|
|
482
358
|
onReorderProjects: function (slugs) {
|
|
483
359
|
// Build a slug->project map from current projects
|
|
@@ -511,25 +387,8 @@ var relay = createServer({
|
|
|
511
387
|
return { ok: true };
|
|
512
388
|
},
|
|
513
389
|
onSetProjectTitle: function (slug, newTitle) {
|
|
514
|
-
relay.setProjectTitle(slug, newTitle);
|
|
515
|
-
|
|
516
|
-
if (config.projects[ti].slug === slug) {
|
|
517
|
-
if (newTitle) {
|
|
518
|
-
config.projects[ti].title = newTitle;
|
|
519
|
-
} else {
|
|
520
|
-
delete config.projects[ti].title;
|
|
521
|
-
}
|
|
522
|
-
break;
|
|
523
|
-
}
|
|
524
|
-
}
|
|
525
|
-
saveConfig(config);
|
|
526
|
-
try { syncClayrc(config.projects); } catch (e) {}
|
|
527
|
-
relay.broadcastAll({
|
|
528
|
-
type: "projects_updated",
|
|
529
|
-
projects: relay.getProjects(),
|
|
530
|
-
projectCount: config.projects.length,
|
|
531
|
-
});
|
|
532
|
-
return { ok: true };
|
|
390
|
+
if (isWorktreeSlug(slug)) { relay.setProjectTitle(slug, newTitle); return { ok: true }; }
|
|
391
|
+
return lifecycleCallbacks.onSetProjectTitle(slug, newTitle);
|
|
533
392
|
},
|
|
534
393
|
onSetProjectIcon: function (slug, newIcon) {
|
|
535
394
|
relay.setProjectIcon(slug, newIcon);
|
|
@@ -553,30 +412,28 @@ var relay = createServer({
|
|
|
553
412
|
return { ok: true };
|
|
554
413
|
},
|
|
555
414
|
onSetProjectSessionVisibilityDefault: function (slug, visibility) {
|
|
556
|
-
|
|
557
|
-
if (result.error) return { ok: false, error: result.error };
|
|
558
|
-
saveConfig(config);
|
|
559
|
-
relay.broadcastAll({ type: "projects_updated", projects: relay.getProjects(), projectCount: config.projects.length });
|
|
560
|
-
return result;
|
|
415
|
+
return projectLifecycle.update(slug, "session_visibility", visibility);
|
|
561
416
|
},
|
|
562
417
|
onProjectOwnerChanged: function (slug, ownerId) {
|
|
418
|
+
if (!config.osUsers) return projectLifecycle.update(slug, "owner", ownerId);
|
|
563
419
|
if (slug.indexOf("mate-") === 0) return {error:"Mate ownership cannot be transferred."};
|
|
420
|
+
if (!ownerId || !usersModule.findUserById(ownerId)) return { error: "A valid owner is required." };
|
|
564
421
|
console.log("[daemon] onProjectOwnerChanged:", slug, "→", ownerId);
|
|
422
|
+
var previousConfig = JSON.parse(JSON.stringify(config));
|
|
565
423
|
var oldOwnerId = null;
|
|
566
424
|
var projectIdx = -1;
|
|
567
425
|
for (var oi = 0; oi < config.projects.length; oi++) {
|
|
568
426
|
if (config.projects[oi].slug === slug) {
|
|
569
427
|
oldOwnerId = config.projects[oi].ownerId || null;
|
|
570
428
|
projectIdx = oi;
|
|
571
|
-
|
|
572
|
-
config.projects[oi].ownerId = ownerId;
|
|
573
|
-
} else {
|
|
574
|
-
delete config.projects[oi].ownerId;
|
|
575
|
-
}
|
|
429
|
+
config.projects[oi].ownerId = ownerId;
|
|
576
430
|
break;
|
|
577
431
|
}
|
|
578
432
|
}
|
|
579
|
-
saveConfig(config);
|
|
433
|
+
try { saveConfig(config); } catch (error) { config = previousConfig; throw error; }
|
|
434
|
+
relay.forEachProject(function (project, projectSlug) {
|
|
435
|
+
if (projectSlug === slug || daemonProjectAccess.parentSlugFor(projectSlug) === slug) project.setProjectOwner(ownerId);
|
|
436
|
+
});
|
|
580
437
|
// OS users mode: revoke old owner ACL, grant new owner ACL
|
|
581
438
|
if (config.osUsers && projectIdx >= 0) {
|
|
582
439
|
var projectPath = config.projects[projectIdx].path;
|
|
@@ -615,18 +472,7 @@ var relay = createServer({
|
|
|
615
472
|
return { envrc: "" };
|
|
616
473
|
},
|
|
617
474
|
onSetProjectEnv: function (slug, envrc) {
|
|
618
|
-
|
|
619
|
-
if (config.projects[ei].slug === slug) {
|
|
620
|
-
if (envrc) {
|
|
621
|
-
config.projects[ei].envrc = envrc;
|
|
622
|
-
} else {
|
|
623
|
-
delete config.projects[ei].envrc;
|
|
624
|
-
}
|
|
625
|
-
saveConfig(config);
|
|
626
|
-
return { ok: true };
|
|
627
|
-
}
|
|
628
|
-
}
|
|
629
|
-
return { ok: false, error: "Project not found" };
|
|
475
|
+
return lifecycleCallbacks.onSetProjectEnv(slug, envrc);
|
|
630
476
|
},
|
|
631
477
|
onGetSharedEnv: function () {
|
|
632
478
|
return { envrc: config.sharedEnv || "" };
|
|
@@ -927,6 +773,7 @@ var relay = createServer({
|
|
|
927
773
|
spawnAndRestart();
|
|
928
774
|
},
|
|
929
775
|
onSetProjectVisibility: function (slug, visibility) {
|
|
776
|
+
if (!config.osUsers) return projectLifecycle.update(slug, "visibility", visibility);
|
|
930
777
|
if (slug.indexOf("mate-") === 0) return {error:"Mates cannot be shared."};
|
|
931
778
|
for (var i = 0; i < config.projects.length; i++) {
|
|
932
779
|
if (config.projects[i].slug === slug) {
|
|
@@ -962,6 +809,7 @@ var relay = createServer({
|
|
|
962
809
|
return { error: "Project not found" };
|
|
963
810
|
},
|
|
964
811
|
onSetProjectAllowedUsers: function (slug, allowedUsers) {
|
|
812
|
+
if (!config.osUsers && !daemonProjectAccess.parentSlugFor(slug)) return projectLifecycle.update(slug, "allowed_users", allowedUsers);
|
|
965
813
|
var accessBefore = daemonProjectAccess.getProjectAccess(config, slug, config.osUsers);
|
|
966
814
|
var result = daemonProjectAccess.setAllowedUsers(config, slug, allowedUsers);
|
|
967
815
|
if (result.error) return result;
|
|
@@ -1062,8 +910,9 @@ var relay = createServer({
|
|
|
1062
910
|
// process may implement the optional shutdownIfIdle(ms); adapters without one
|
|
1063
911
|
// (Claude, which runs in-process or under sdk-worker) are simply skipped.
|
|
1064
912
|
// The CLAY_CODEX_* names are kept as aliases for backwards compatibility.
|
|
1065
|
-
var
|
|
1066
|
-
var
|
|
913
|
+
var adapterReaperConfig = require("./yoke/host-environment").reaper(process.env);
|
|
914
|
+
var IDLE_MS = adapterReaperConfig.idleMs;
|
|
915
|
+
var REAP_MS = adapterReaperConfig.reapMs;
|
|
1067
916
|
var reaperHandle = setInterval(function () {
|
|
1068
917
|
if (!relay || typeof relay.forEachProject !== "function") return;
|
|
1069
918
|
relay.forEachProject(function (ctx) {
|
|
@@ -1131,11 +980,11 @@ var ipc = createIPCServer(socketPath(), function (msg) {
|
|
|
1131
980
|
}
|
|
1132
981
|
var slugs = config.projects.map(function (p) { return p.slug; });
|
|
1133
982
|
var slug = generateSlug(absPath, slugs);
|
|
1134
|
-
var projectEntry = { path: absPath, slug: slug, addedAt: Date.now(), visibility: "private" };
|
|
983
|
+
var projectEntry = { path: absPath, slug: slug, addedAt: Date.now(), visibility: "private", ownershipRecovery: "required" };
|
|
1135
984
|
projectEntry.projectKnowledgeId = rememberedProjectKnowledgeId(absPath);
|
|
1136
|
-
|
|
1137
|
-
config.projects.
|
|
1138
|
-
|
|
985
|
+
config = require("./project-ownership").register(config, projectEntry, usersModule.getAllUsers(), saveConfig, osUsersMod.resolveOsUserInfo);
|
|
986
|
+
var registeredProject = config.projects[config.projects.length - 1];
|
|
987
|
+
relay.addProject(absPath, slug, null, null, registeredProject.ownerId || null, null, projectRuntimeOptions(registeredProject));
|
|
1139
988
|
try { syncClayrc(config.projects); } catch (e) {}
|
|
1140
989
|
console.log("[daemon] Added project:", slug, "→", absPath);
|
|
1141
990
|
// Discover and register worktrees for the new project
|
|
@@ -1367,6 +1216,10 @@ var ipc = createIPCServer(socketPath(), function (msg) {
|
|
|
1367
1216
|
var projects = config.projects || [];
|
|
1368
1217
|
for (var i = 0; i < projects.length; i++) {
|
|
1369
1218
|
var p = projects[i];
|
|
1219
|
+
if (!projectLifecycle.canRestore(p)) {
|
|
1220
|
+
console.log("[daemon] Project removal needs recovery; runtime remains stopped:", p.slug);
|
|
1221
|
+
continue;
|
|
1222
|
+
}
|
|
1370
1223
|
if (fs.existsSync(p.path)) {
|
|
1371
1224
|
console.log("[daemon] Adding project:", p.slug, "→", p.path);
|
|
1372
1225
|
relay.addProject(p.path, p.slug, p.title, p.icon, p.ownerId, null, projectRuntimeOptions(p));
|
|
@@ -1413,7 +1266,7 @@ if (usersModule.isMultiUser()) {
|
|
|
1413
1266
|
var mateDir = mates.getMateDir(mateCtx, m.id);
|
|
1414
1267
|
var mateSlug = "mate-" + m.id;
|
|
1415
1268
|
var mateName = (m.profile && m.profile.displayName) || m.name || "New Mate";
|
|
1416
|
-
if (fs.existsSync(mateDir)) {
|
|
1269
|
+
if (!m.lifecycleDeletion && fs.existsSync(mateDir)) {
|
|
1417
1270
|
var mateDef = m.builtinKey ? require("./builtin-mates").getBuiltinByKey(m.builtinKey) : null;
|
|
1418
1271
|
var isHost = !!(mateDef && mateDef.hostAgent);
|
|
1419
1272
|
console.log("[daemon] Adding mate project:", mateSlug + (isHost ? " (host agent)" : ""));
|
|
@@ -1430,7 +1283,7 @@ if (usersModule.isMultiUser()) {
|
|
|
1430
1283
|
var mateDir = mates.getMateDir(mateCtx, m.id);
|
|
1431
1284
|
var mateSlug = "mate-" + m.id;
|
|
1432
1285
|
var mateName = (m.profile && m.profile.displayName) || m.name || "New Mate";
|
|
1433
|
-
if (fs.existsSync(mateDir)) {
|
|
1286
|
+
if (!m.lifecycleDeletion && fs.existsSync(mateDir)) {
|
|
1434
1287
|
var mateDef2 = m.builtinKey ? require("./builtin-mates").getBuiltinByKey(m.builtinKey) : null;
|
|
1435
1288
|
var isHost2 = !!(mateDef2 && mateDef2.hostAgent);
|
|
1436
1289
|
console.log("[daemon] Adding mate project:", mateSlug + (isHost2 ? " (host agent)" : ""));
|
|
@@ -1467,58 +1320,7 @@ try { syncClayrc(config.projects); } catch (e) {}
|
|
|
1467
1320
|
// Multi-user OS-isolated installs have per-user ~/.claude trees that the
|
|
1468
1321
|
// daemon process can't traverse; the inline cleanup in claude-worker.js
|
|
1469
1322
|
// covers those.
|
|
1470
|
-
function cleanupSdkWarmupSessions() {
|
|
1471
|
-
var sessionHygiene = require("./session-hygiene");
|
|
1472
|
-
var projectsRoot = path.join(REAL_HOME, ".claude", "projects");
|
|
1473
|
-
var projectDirs;
|
|
1474
|
-
try { projectDirs = fs.readdirSync(projectsRoot, { withFileTypes: true }); }
|
|
1475
|
-
catch (e) { return; }
|
|
1476
|
-
|
|
1477
|
-
var deleted = 0;
|
|
1478
|
-
var nowMs = Date.now();
|
|
1479
|
-
var MAX_BYTES = 64 * 1024;
|
|
1480
|
-
var MIN_AGE_MS = 60 * 1000;
|
|
1481
|
-
|
|
1482
|
-
for (var di = 0; di < projectDirs.length; di++) {
|
|
1483
|
-
if (!projectDirs[di].isDirectory()) continue;
|
|
1484
|
-
var projDir = path.join(projectsRoot, projectDirs[di].name);
|
|
1485
|
-
var files;
|
|
1486
|
-
try { files = fs.readdirSync(projDir); } catch (e) { continue; }
|
|
1487
|
-
|
|
1488
|
-
for (var fi = 0; fi < files.length; fi++) {
|
|
1489
|
-
var f = files[fi];
|
|
1490
|
-
if (!f.endsWith(".jsonl")) continue;
|
|
1491
|
-
var fp = path.join(projDir, f);
|
|
1492
|
-
|
|
1493
|
-
var st;
|
|
1494
|
-
try { st = fs.statSync(fp); } catch (e) { continue; }
|
|
1495
|
-
if (st.size >= MAX_BYTES) continue;
|
|
1496
|
-
if (nowMs - st.mtimeMs < MIN_AGE_MS) continue;
|
|
1497
|
-
|
|
1498
|
-
var raw;
|
|
1499
|
-
try { raw = fs.readFileSync(fp, "utf8"); } catch (e) { continue; }
|
|
1500
|
-
var lines = raw.split("\n");
|
|
1501
|
-
var events = [];
|
|
1502
|
-
var parseOk = true;
|
|
1503
|
-
for (var li = 0; li < lines.length; li++) {
|
|
1504
|
-
var line = lines[li];
|
|
1505
|
-
if (!line) continue;
|
|
1506
|
-
var ev;
|
|
1507
|
-
try { ev = JSON.parse(line); } catch (e) { parseOk = false; break; }
|
|
1508
|
-
if (!ev || typeof ev !== "object") continue;
|
|
1509
|
-
events.push(ev);
|
|
1510
|
-
}
|
|
1511
|
-
if (!parseOk) continue;
|
|
1512
|
-
if (!sessionHygiene.isClaudeWarmupTranscript(events)) continue;
|
|
1513
|
-
|
|
1514
|
-
try { fs.unlinkSync(fp); deleted++; } catch (e) {}
|
|
1515
|
-
}
|
|
1516
|
-
}
|
|
1517
|
-
|
|
1518
|
-
if (deleted > 0) {
|
|
1519
|
-
console.log("[daemon] Removed " + deleted + " stale SDK warmup session file(s)");
|
|
1520
|
-
}
|
|
1521
|
-
}
|
|
1323
|
+
function cleanupSdkWarmupSessions() { return require("./yoke/maintenance").cleanup(REAL_HOME); }
|
|
1522
1324
|
|
|
1523
1325
|
// --- Start listening (with retry for port-in-use during update handoff) ---
|
|
1524
1326
|
var listenRetries = 0;
|
|
@@ -3,11 +3,7 @@
|
|
|
3
3
|
var modelEntryMatches = require("./model-entry").modelEntryMatches;
|
|
4
4
|
var modelEntryValue = require("./model-entry").modelEntryValue;
|
|
5
5
|
|
|
6
|
-
var
|
|
7
|
-
var VENDOR_FAMILY_ORDER = {
|
|
8
|
-
claude: ["opus", "sonnet", "haiku"],
|
|
9
|
-
codex: ["astra", "sol", "gpt", "o"],
|
|
10
|
-
};
|
|
6
|
+
var providerInfo = require("./yoke/vendor-registry").getVendorInfo;
|
|
11
7
|
|
|
12
8
|
function text(entry) {
|
|
13
9
|
if (typeof entry === "string") return entry;
|
|
@@ -18,10 +14,10 @@ function selectTopModel(vendor, catalog) {
|
|
|
18
14
|
var models = catalog && Array.isArray(catalog.models) ? catalog.models : [];
|
|
19
15
|
if (!models.length) return "";
|
|
20
16
|
var defaultModel = catalog.defaultModel;
|
|
21
|
-
if (
|
|
17
|
+
if (!providerInfo(vendor) && defaultModel) {
|
|
22
18
|
for (var di = 0; di < models.length; di++) if (modelEntryMatches(models[di], defaultModel)) return modelEntryValue(models[di]);
|
|
23
19
|
}
|
|
24
|
-
var familyOrder =
|
|
20
|
+
var familyOrder = (providerInfo(vendor) || {}).preferredModelFamilies || [];
|
|
25
21
|
if (familyOrder.length) {
|
|
26
22
|
for (var fi = 0; fi < familyOrder.length; fi++) {
|
|
27
23
|
for (var mi = 0; mi < models.length; mi++) if (new RegExp("(^|[^a-z])" + familyOrder[fi] + "([^a-z]|$)", "i").test(text(models[mi]))) return modelEntryValue(models[mi]);
|
|
@@ -114,4 +110,4 @@ function createDefaultAiRuntimeResolver(deps) {
|
|
|
114
110
|
};
|
|
115
111
|
}
|
|
116
112
|
|
|
117
|
-
module.exports = { resolveDefaultAiRuntime: resolveDefaultAiRuntime, createDefaultAiRuntimeResolver: createDefaultAiRuntimeResolver, selectTopModel: selectTopModel, exactModel: exactModel, resolveEffort: resolveEffort, KNOWN_VENDORS:
|
|
113
|
+
module.exports = { resolveDefaultAiRuntime: resolveDefaultAiRuntime, createDefaultAiRuntimeResolver: createDefaultAiRuntimeResolver, selectTopModel: selectTopModel, exactModel: exactModel, resolveEffort: resolveEffort, KNOWN_VENDORS: Object.keys(require("./yoke/vendor-registry").VENDOR_REGISTRY), VENDOR_FAMILY_ORDER: require("./yoke/model-preferences").families() };
|
package/lib/email-mcp-server.js
CHANGED
|
@@ -37,7 +37,7 @@ function buildShape(props, required) {
|
|
|
37
37
|
// appendAuditLog(entry) -> void
|
|
38
38
|
function create(deps) {
|
|
39
39
|
var sdk;
|
|
40
|
-
try { sdk = require("
|
|
40
|
+
try { sdk = require("./yoke/sdk-server-factory").load(); } catch (e) {
|
|
41
41
|
console.error("[email-mcp] Failed to load SDK:", e.message);
|
|
42
42
|
return null;
|
|
43
43
|
}
|