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/issues-service.js
CHANGED
|
@@ -129,25 +129,35 @@ function attachIssuesService(ctx) {
|
|
|
129
129
|
principal: principal, worktreeOnly: authorization.worktreeOnly };
|
|
130
130
|
}
|
|
131
131
|
|
|
132
|
-
function bind(source, isSession) {
|
|
132
|
+
function bind(source, isSession, canonicalClay) {
|
|
133
133
|
if (!source || typeof source.projectSlug !== "string") return null;
|
|
134
134
|
var initialSlug = source.projectSlug;
|
|
135
135
|
var initialProject = projectFor(initialSlug);
|
|
136
136
|
var initialSession = isSession ? source.session : null;
|
|
137
|
+
var clayInitial;
|
|
138
|
+
if (canonicalClay) { try { clayInitial = require("./canonical-clay-record-authority").resolve(source.authority, initialSlug); } catch (error) { return null; } }
|
|
137
139
|
if (!initialProject || (isSession && !initialSession)) return null;
|
|
138
140
|
if (initialSession) provenance.ensureOrigin(initialSession);
|
|
139
|
-
var initialUserId = initialSession ? initialSession.ownerId || null : source.userId || null;
|
|
141
|
+
var initialUserId = initialSession ? initialSession.ownerId || null : canonicalClay ? clayInitial.principal.userId || clayInitial.principal.singleUserOwnerId : source.userId || null;
|
|
140
142
|
var initialOrigin = initialSession ? initialSession.sessionOriginId || null : null;
|
|
141
143
|
var initial = bindingState(initialProject, initialSession, initialUserId, initialOrigin);
|
|
142
144
|
if (!initial) return null;
|
|
143
145
|
|
|
144
146
|
function current() {
|
|
145
147
|
if (projectFor(initialSlug) !== initialProject) throw new Error("This Issues binding is no longer valid.");
|
|
148
|
+
if (canonicalClay) {
|
|
149
|
+
var clayLive = require("./canonical-clay-record-authority").resolve(source.authority, initialSlug);
|
|
150
|
+
if (clayLive.project !== initialProject || clayLive.status.path !== clayInitial.status.path || clayLive.status.projectKnowledgeId !== clayInitial.status.projectKnowledgeId || clayLive.status.changeSetId !== clayInitial.status.changeSetId) throw new Error("Selected Issues context changed.");
|
|
151
|
+
}
|
|
146
152
|
var live = bindingState(initialProject, initialSession, initialUserId, initialOrigin);
|
|
147
153
|
if (!live) throw new Error("This Issues binding is no longer valid.");
|
|
148
154
|
return live;
|
|
149
155
|
}
|
|
150
156
|
|
|
157
|
+
function expected(entry, args) { if (canonicalClay && (!Number.isInteger(args.expectedRevision) || entry.revision !== args.expectedRevision)) throw new Error("Issue revision conflict."); }
|
|
158
|
+
|
|
159
|
+
function actor(state) { return canonicalClay ? require("./canonical-clay-record-authority").resolve(source.authority, initialSlug).actor : author(state.user, state.session ? "session" : "user", state.session); }
|
|
160
|
+
|
|
151
161
|
function visibleIssue(store, ref, state) {
|
|
152
162
|
var result = store.read(ref);
|
|
153
163
|
if (state.worktreeOnly && (!result.context || result.context.changeSetId !== state.status.changeSetId)) throw new Error("Issue not found.");
|
|
@@ -174,7 +184,7 @@ function attachIssuesService(ctx) {
|
|
|
174
184
|
path: state.status.path, knowledgeId: governing.projectKnowledgeId,
|
|
175
185
|
changeSetId: state.status.changeSetId || null, worktreeOnly: state.worktreeOnly,
|
|
176
186
|
recordContext: clone(issueContext(state.status)),
|
|
177
|
-
actor: clone(
|
|
187
|
+
actor: clone(actor(state)),
|
|
178
188
|
osIdentity: needsIdentity ? osIdentity(state) : null };
|
|
179
189
|
}
|
|
180
190
|
|
|
@@ -184,7 +194,7 @@ function attachIssuesService(ctx) {
|
|
|
184
194
|
var liveIdentity = needsIdentity ? osIdentity(fresh) : null;
|
|
185
195
|
if (fresh.project !== before.project || fresh.session !== before.session || (fresh.user.id || null) !== before.userId ||
|
|
186
196
|
fresh.status.path !== before.path || !governing || governing.projectKnowledgeId !== before.knowledgeId ||
|
|
187
|
-
(fresh.status.changeSetId || null) !== before.changeSetId || fresh.worktreeOnly !== before.worktreeOnly ||
|
|
197
|
+
(fresh.status.changeSetId || null) !== before.changeSetId || fresh.worktreeOnly !== before.worktreeOnly || JSON.stringify(issueContext(fresh.status)) !== JSON.stringify(before.recordContext) ||
|
|
188
198
|
JSON.stringify(liveIdentity) !== JSON.stringify(before.osIdentity)) throw new Error("Issue authorization changed during the operation.");
|
|
189
199
|
return fresh;
|
|
190
200
|
}
|
|
@@ -200,7 +210,7 @@ function attachIssuesService(ctx) {
|
|
|
200
210
|
var github = require('./issues-github').attachIssueGithub({
|
|
201
211
|
locks: githubLocks, assessments: githubAssessments, run: context.runGithub, analyze: source.analyzeGithub || context.analyzeGithub,
|
|
202
212
|
begin: function () {
|
|
203
|
-
if (isSession) throw new Error('GitHub filing requires an explicit action in the Issues panel.');
|
|
213
|
+
if (isSession || canonicalClay) throw new Error('GitHub filing requires an explicit action in the Issues panel.');
|
|
204
214
|
return operation(current(), true);
|
|
205
215
|
},
|
|
206
216
|
read: function (before, ref) {
|
|
@@ -217,6 +227,7 @@ function attachIssuesService(ctx) {
|
|
|
217
227
|
return {
|
|
218
228
|
searchGithubIssue: github.search, linkGithubIssue: github.link, createGithubIssue: github.create,
|
|
219
229
|
linkWorkSession: function (args, session) {
|
|
230
|
+
if (canonicalClay) throw new Error("Use reviewed project assignment or follow-up for Driver execution.");
|
|
220
231
|
var state = current();
|
|
221
232
|
var manager = state.project.getSessionManager();
|
|
222
233
|
if (!args || !Number.isInteger(args.expectedRevision)) throw new Error("expectedRevision is required.");
|
|
@@ -232,9 +243,10 @@ function attachIssuesService(ctx) {
|
|
|
232
243
|
if (links.some(function (link) { return link.sessionId === session.sessionOriginId; })) return entry;
|
|
233
244
|
var link = { sessionId: session.sessionOriginId, role: "driver", issueRevision: args.expectedRevision };
|
|
234
245
|
if (args.requestId !== undefined) link.requestId = schema.text(args.requestId, "work request id", 200, true);
|
|
235
|
-
return target.update(args.ref, { linkedWorkSessions: links.concat([link]), status: "in_progress" }, args.expectedRevision, author(state.user, "user", null));
|
|
246
|
+
return target.update(args.ref, { linkedWorkSessions: links.concat([link]), status: "in_progress" }, args.expectedRevision, canonicalClay ? actor(state) : author(state.user, "user", null));
|
|
236
247
|
},
|
|
237
248
|
resolveWorkSession: function (args) {
|
|
249
|
+
if (canonicalClay) throw new Error("Work sessions require the existing project Driver workflow.");
|
|
238
250
|
var state = current();
|
|
239
251
|
var entry = visibleIssue(openStore(state.status), args.ref, state);
|
|
240
252
|
if (!(entry.linkedWorkSessions || []).some(function (link) { return link.sessionId === args.sessionOriginId; })) throw new Error("Work session unavailable.");
|
|
@@ -255,9 +267,9 @@ function attachIssuesService(ctx) {
|
|
|
255
267
|
readIssueTombstone: function (args) { var state = current(); return scopedIssue(openStore(state.status), args && args.ref, state); },
|
|
256
268
|
issueHistory: function (args) { var state = current(); var store = openStore(state.status); var history = store.history(args && args.ref); if (state.worktreeOnly) { var historical = scopedIssue(store, args && args.ref, state); if (!historical.context || historical.context.changeSetId !== state.status.changeSetId) throw new Error("Issue not found."); } return history; },
|
|
257
269
|
readIssueRevision: function (args) { var state = current(); var store = openStore(state.status); visibleIssue(store, args && args.ref, state); return store.readRevision(args.ref, args.revision); },
|
|
258
|
-
commentIssue: function (args) { var state = current(); var target = openStore(state.status); visibleIssue(target, args && args.ref, state); return target.comment(args.ref, args.body, author(state.user, "user", null)); },
|
|
270
|
+
commentIssue: function (args) { var state = current(); var target = openStore(state.status); expected(visibleIssue(target, args && args.ref, state), args); return target.comment(args.ref, args.body, canonicalClay ? actor(state) : author(state.user, "user", null)); },
|
|
259
271
|
listIssueFeedback: function (args) {
|
|
260
|
-
if (!isSession) throw new Error("Only the Project Driver can review issue comments.");
|
|
272
|
+
if (!isSession && !canonicalClay) throw new Error("Only the Project Driver can review issue comments.");
|
|
261
273
|
var state = current(); var target = openStore(state.status); var out = []; var feedbackLimit = args && args.limit === undefined ? 200 : Number(args.limit);
|
|
262
274
|
if (!Number.isInteger(feedbackLimit) || feedbackLimit < 1 || feedbackLimit > 200) throw new Error("Feedback limit must be between 1 and 200.");
|
|
263
275
|
var position = { issueCursor: null, issueIndex: 0, commentOffset: 0 };
|
|
@@ -297,31 +309,32 @@ function attachIssuesService(ctx) {
|
|
|
297
309
|
return { feedback: out, total: out.length, nextCursor: nextCursor, truncated: !!nextCursor };
|
|
298
310
|
},
|
|
299
311
|
reviewIssueComment: function (args) {
|
|
300
|
-
if (!isSession) throw new Error("Only the Project Driver can review issue comments.");
|
|
312
|
+
if (!isSession && !canonicalClay) throw new Error("Only the Project Driver can review issue comments.");
|
|
301
313
|
var state = current(); var target = openStore(state.status); var entry = visibleIssue(target, args && args.ref, state);
|
|
314
|
+
expected(entry, args);
|
|
302
315
|
if (args.action === "incorporate") {
|
|
303
316
|
if (!Number.isInteger(args.expectedRevision)) throw new Error("expectedRevision is required to incorporate a comment.");
|
|
304
317
|
var data = cleanPublic(args, { ref: true, expectedRevision: true, commentId: true, action: true, response: true, commitSha: true }, true);
|
|
305
318
|
if (data.status === "resolved") throw new Error("Use update_issue with verified commit evidence before resolving this Issue.");
|
|
306
|
-
return target.incorporate(entry.ref, args.commentId, data, args.expectedRevision, args.response,
|
|
319
|
+
return target.incorporate(entry.ref, args.commentId, data, args.expectedRevision, args.response, actor(state));
|
|
307
320
|
}
|
|
308
|
-
return target.review(entry.ref, args.commentId, args.action, args.response,
|
|
321
|
+
return target.review(entry.ref, args.commentId, args.action, args.response, actor(state));
|
|
309
322
|
},
|
|
310
323
|
removeIssue: function (args) {
|
|
311
324
|
var state = current();
|
|
312
325
|
if (!state.principal.isProjectOwner) throw new Error("Only the project owner can delete Issues.");
|
|
313
326
|
var target = openStore(state.status); var entry = visibleIssue(target, args && args.ref, state);
|
|
314
327
|
if (!Number.isInteger(args && args.expectedRevision) || entry.revision !== args.expectedRevision) throw new Error("Issue revision conflict.");
|
|
315
|
-
return target.remove(entry.ref, author(state.user, "user", null), args.expectedRevision);
|
|
328
|
+
return target.remove(entry.ref, canonicalClay ? actor(state) : author(state.user, "user", null), args.expectedRevision);
|
|
316
329
|
},
|
|
317
330
|
createIssue: function (args) {
|
|
318
|
-
if (!isSession) throw new Error("People cannot create issues directly. Ask the Project Driver to create one.");
|
|
331
|
+
if (!isSession && !canonicalClay) throw new Error("People cannot create issues directly. Ask the Project Driver to create one.");
|
|
319
332
|
var data = cleanPublic(args, { commitSha: true }, true);
|
|
320
333
|
var status = data.status === undefined ? "open" : data.status;
|
|
321
334
|
if (schema.STATUSES.indexOf(status) === -1) throw new Error("Invalid status.");
|
|
322
335
|
var state = current();
|
|
323
336
|
if (status !== "resolved") return Promise.resolve(openStore(state.status).create(data,
|
|
324
|
-
|
|
337
|
+
actor(state), issueContext(state.status)));
|
|
325
338
|
if (typeof data.resolutionSummary !== "string" || !data.resolutionSummary.trim()) throw new Error("resolutionSummary is required when resolving an issue.");
|
|
326
339
|
var before = operation(state, true);
|
|
327
340
|
return evidence(before, args.commitSha).then(function (proof) {
|
|
@@ -340,7 +353,7 @@ function attachIssuesService(ctx) {
|
|
|
340
353
|
var existing = visibleIssue(target, ref, state);
|
|
341
354
|
if (existing.revision !== expectedRevision) throw new Error("Issue revision conflict.");
|
|
342
355
|
if (data.status !== "resolved") return Promise.resolve(target.update(ref, data, expectedRevision,
|
|
343
|
-
|
|
356
|
+
actor(state)));
|
|
344
357
|
if (typeof data.resolutionSummary !== "string" || !data.resolutionSummary.trim()) throw new Error("resolutionSummary is required when resolving an issue.");
|
|
345
358
|
var before = operation(state, true);
|
|
346
359
|
return evidence(before, args.commitSha).then(function (proof) {
|
|
@@ -354,6 +367,7 @@ function attachIssuesService(ctx) {
|
|
|
354
367
|
}
|
|
355
368
|
|
|
356
369
|
return { bindUser: function (source) { return bind(source, false); },
|
|
370
|
+
bindCanonicalClay: function (source) { return bind(source, false, true); },
|
|
357
371
|
bindProjectSession: function (source) { return bind(source, true); },
|
|
358
372
|
issueScopeIdForKnowledgeId: issuesStore.issueScopeIdForKnowledgeId };
|
|
359
373
|
}
|
package/lib/kiro-defaults.js
CHANGED
|
@@ -1,22 +1 @@
|
|
|
1
|
-
|
|
2
|
-
// elsewhere. Consumed by the server-side vendor plumbing and sent to clients
|
|
3
|
-
// via the config state so the UI renders the right controls.
|
|
4
|
-
|
|
5
|
-
var KIRO_DEFAULTS = {
|
|
6
|
-
// Kiro CLI 2.18.1 exposes the next-generation agent as the v3 engine. Its
|
|
7
|
-
// general-purpose mode id is "vibe" (displayed as "Default").
|
|
8
|
-
engine: "v3",
|
|
9
|
-
mode: "vibe",
|
|
10
|
-
};
|
|
11
|
-
|
|
12
|
-
function getKiroConfig(sm) {
|
|
13
|
-
return {
|
|
14
|
-
engine: (sm && sm.kiroEngine) || KIRO_DEFAULTS.engine,
|
|
15
|
-
mode: (sm && sm.kiroMode) || KIRO_DEFAULTS.mode,
|
|
16
|
-
};
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
module.exports = {
|
|
20
|
-
KIRO_DEFAULTS: KIRO_DEFAULTS,
|
|
21
|
-
getKiroConfig: getKiroConfig,
|
|
22
|
-
};
|
|
1
|
+
module.exports = require("./yoke/options/kiro-defaults");
|
|
@@ -38,9 +38,10 @@ function attachKnowledgeDbImport(ctx) {
|
|
|
38
38
|
}
|
|
39
39
|
function importRecords(args) {
|
|
40
40
|
// Snapshot caller-owned JSON before any asynchronous operation.
|
|
41
|
-
var batch = ctx.clone(input.batch(args)); args = ctx.clone(args);
|
|
41
|
+
var revalidate = args.revalidate; var batch = ctx.clone(input.batch(args)); args = ctx.clone(args); args.revalidate = revalidate;
|
|
42
42
|
var operationId = ctx.mutationId(args.operationId); var fingerprint = ctx.fingerprint("import", args);
|
|
43
43
|
return ctx.serialize(args.databaseId, function () { return ctx.load(args.databaseId).then(async function (current) {
|
|
44
|
+
ctx.guard(args, current);
|
|
44
45
|
var duplicate = ctx.receipt(current, operationId, fingerprint);
|
|
45
46
|
if (duplicate) return Object.assign({}, duplicate, { projectionPending: current.projectionPending === true, projectionError: current.projectionError || null });
|
|
46
47
|
if (current.archivedAt) throw ctx.error("Knowledge database is archived.", "ARCHIVED", current.revision);
|
|
@@ -60,10 +61,10 @@ function attachKnowledgeDbImport(ctx) {
|
|
|
60
61
|
// payload still conflicts. Preserve record values, archives and database revision.
|
|
61
62
|
if (!added.length) {
|
|
62
63
|
ctx.remember(next, operationId, fingerprint, result);
|
|
63
|
-
await ctx.replace(current, next);
|
|
64
|
+
await ctx.replace(current, next, args);
|
|
64
65
|
return Object.assign(result, { projectionPending: current.projectionPending === true, projectionError: current.projectionError || null });
|
|
65
66
|
}
|
|
66
|
-
var databases = await ctx.all(); var at = Date.now(); var who = ctx.actor(args.actor);
|
|
67
|
+
var databases = await ctx.all(); ctx.guard(args, current); var at = Date.now(); var who = ctx.actor(args.actor);
|
|
67
68
|
added.forEach(function (item) {
|
|
68
69
|
next.records.push({ id: item.mapping.recordId, revision: 1, values: {}, archivedAt: null, createdAt: at, updatedAt: at, createdBy: who, updatedBy: who });
|
|
69
70
|
next.recordHistory[item.mapping.recordId] = [];
|
|
@@ -78,7 +79,7 @@ function attachKnowledgeDbImport(ctx) {
|
|
|
78
79
|
next.revision++; next.updatedAt = at; next.updatedBy = who; next.projectionPending = true; next.projectionError = null;
|
|
79
80
|
result.databaseRevision = next.revision;
|
|
80
81
|
ctx.remember(next, operationId, fingerprint, result);
|
|
81
|
-
await ctx.replace(current, next);
|
|
82
|
+
await ctx.replace(current, next, args);
|
|
82
83
|
return ctx.finish(next, result, who);
|
|
83
84
|
}); });
|
|
84
85
|
}
|
|
@@ -30,7 +30,7 @@ function canonical(value) {
|
|
|
30
30
|
if (!value || typeof value !== "object") return value;
|
|
31
31
|
var out = {}; Object.keys(value).sort().forEach(function (key) { out[key] = canonical(value[key]); }); return out;
|
|
32
32
|
}
|
|
33
|
-
function fingerprint(label, args) { var envelope = Object.assign({}, args); delete envelope.actor; delete envelope.operationId; return crypto.createHash("sha256").update(label + ":" + JSON.stringify(canonical(envelope))).digest("hex"); }
|
|
33
|
+
function fingerprint(label, args) { var envelope = Object.assign({}, args); delete envelope.actor; delete envelope.operationId; delete envelope.revalidate; return crypto.createHash("sha256").update(label + ":" + JSON.stringify(canonical(envelope))).digest("hex"); }
|
|
34
34
|
function ensureRevision(value, current, label) {
|
|
35
35
|
if (!Number.isInteger(value) || value < 1) throw error("A valid " + label + " revision is required.", "STALE", current);
|
|
36
36
|
if (value !== current) throw error("This " + label + " changed since it was opened.", "STALE", current);
|
|
@@ -114,7 +114,8 @@ function createKnowledgeDbService(options) {
|
|
|
114
114
|
function all() { return storage.list(); }
|
|
115
115
|
function listCached(args) { var items = storage.getCached(); return { databases: items.filter(function (item) { return args && args.archived === true ? !!item.archivedAt : !item.archivedAt; }).sort(function (a, b) { return b.updatedAt - a.updatedAt || (a._id === b._id ? 0 : a._id < b._id ? -1 : 1); }).map(function (item) { return publicDatabase(item, false); }) }; }
|
|
116
116
|
function assertAggregate(next) { if (Buffer.byteLength(JSON.stringify(next), "utf8") > aggregateLimit) throw error("Knowledge database exceeds the " + aggregateLimit + " byte aggregate storage limit (records, history, mappings and live receipts).", "LIMIT"); }
|
|
117
|
-
function
|
|
117
|
+
function guard(args, current, phase) { if (args && typeof args.revalidate === 'function') args.revalidate(current ? publicDatabase(current, false) : null, phase); }
|
|
118
|
+
function replace(current, next, control) { assertAggregate(next); guard(control, current, 'saving'); return storage.replaceIfRevision(current._id, current.revision, next).then(function (replaced) { if (typeof replaced !== "boolean") throw storageModule.invalid("replaceIfRevision must resolve to a boolean."); if (!replaced) throw Object.assign(error("This database changed during the operation.", "STALE", current.revision), { persisted: false }); guard(control, null, "saved"); return next; }); }
|
|
118
119
|
function projectionContent(value) { return JSON.stringify({ schemaVersion: 1, namespace: "knowledge-database-summary", databaseId: value._id, name: value.name, archived: !!value.archivedAt, revision: value.revision, fields: value.schema.filter(function (field) { return !field.archived; }).map(function (field) { return { id: field.id, name: field.name, type: field.type }; }), views: (value.views || []).filter(function (view) { return !view.archived; }).map(function (view) { return { id: view.id, name: view.name, type: "table" }; }), recordCount: value.records.filter(function (record) { return !record.archivedAt; }).length }); }
|
|
119
120
|
function project(value, actorValue) {
|
|
120
121
|
if (typeof settings.projectSummary !== "function") return Promise.resolve({ pending: false });
|
|
@@ -125,18 +126,20 @@ function createKnowledgeDbService(options) {
|
|
|
125
126
|
function finish(value, result, actorValue) { return project(value, actorValue).then(function (projection) { return Object.assign({}, result, { projectionPending: projection.pending, projectionError: projection.error || null }); }); }
|
|
126
127
|
function mutate(databaseId, args, label, fn) {
|
|
127
128
|
var operationId = mutationId(args.operationId); var operationFingerprint = fingerprint(label, args); return serialize(databaseId, function () { return load(databaseId).then(function (current) {
|
|
129
|
+
guard(args, current);
|
|
128
130
|
var duplicate = receipt(current, operationId, operationFingerprint); if (duplicate) return Object.assign({}, duplicate, { projectionPending: current.projectionPending === true, projectionError: current.projectionError || null });
|
|
129
131
|
if (current.archivedAt && label !== "database") throw error("Knowledge database is archived.", "ARCHIVED", current.revision);
|
|
130
|
-
var next = clone(current); var result = fn(next, current); next.projectionPending = true; next.projectionError = null; remember(next, operationId, operationFingerprint, result); return replace(current, next).then(function () { return finish(next, result, actor(args.actor)); });
|
|
132
|
+
var next = clone(current); var result = fn(next, current); next.projectionPending = true; next.projectionError = null; remember(next, operationId, operationFingerprint, result); return replace(current, next, args).then(function () { return finish(next, result, actor(args.actor)); });
|
|
131
133
|
}); });
|
|
132
134
|
}
|
|
133
135
|
function create(args) {
|
|
134
136
|
var input = args || {}; var operationId = mutationId(input.operationId); var operationFingerprint = fingerprint("create", input); return serialize("create:" + operationId, function () { return all().then(function (items) {
|
|
137
|
+
guard(input);
|
|
135
138
|
var duplicate; var duplicateDatabase; items.some(function (item) { duplicate = receipt(item, operationId, operationFingerprint); if (duplicate) duplicateDatabase = item; return !!duplicate; }); if (duplicate) return Object.assign({}, duplicate, { projectionPending: duplicateDatabase.projectionPending === true, projectionError: duplicateDatabase.projectionError || null });
|
|
136
139
|
var at = now(); var who = actor(input.actor); var titleId = newId("fld"); var schema = input.schema ? validation.normalizeSchema(input.schema) : validation.normalizeSchema([{ id: titleId, name: "Name", type: "title", required: true }]);
|
|
137
140
|
var viewId = newId("view"); var item = { _id: newId("db"), name: validation.text(input.name, "Database name", 120, false), revision: 1, archivedAt: null, schema: schema,
|
|
138
141
|
views: [{ id: viewId, name: "Table", type: "table", columns: schema.filter(function (field) { return !field.archived; }).map(function (field) { return field.id; }), filters: [], sorts: [], archived: false }], records: [], recordHistory: {}, databaseHistory: [], receipts: [], createdAt: at, updatedAt: at, createdBy: who, updatedBy: who, projectionPending: true, projectionError: null };
|
|
139
|
-
var result = { database: publicDatabase(item, false) }; remember(item, operationId, operationFingerprint, result); assertAggregate(item); return storage.insert(item).then(function () { return finish(item, result, who); });
|
|
142
|
+
var result = { database: publicDatabase(item, false) }; remember(item, operationId, operationFingerprint, result); assertAggregate(item); guard(input, null, "saving"); return storage.insert(item).then(function () { guard(input, null, "saved"); return finish(item, result, who); });
|
|
140
143
|
}); });
|
|
141
144
|
}
|
|
142
145
|
function list(args) { return all().then(function (items) { return { databases: items.filter(function (item) { return args && args.archived === true ? !!item.archivedAt : !item.archivedAt; }).sort(function (a, b) { return b.updatedAt - a.updatedAt || (a._id === b._id ? 0 : a._id < b._id ? -1 : 1); }).map(function (item) { return publicDatabase(item, false); }) }; }); }
|
|
@@ -155,8 +158,8 @@ function createKnowledgeDbService(options) {
|
|
|
155
158
|
function archiveRecord(args) { return mutate(args.databaseId, args, "record", function (next) { var index = next.records.findIndex(function (record) { return record.id === validation.id(args.recordId, "record id"); }); if (index === -1) throw error("Knowledge database record not found.", "NOT_FOUND"); var before = next.records[index]; ensureRevision(args.expectedRevision, before.revision, "record"); next.recordHistory[before.id] = (next.recordHistory[before.id] || []).concat([{ revision: before.revision, at: now(), actor: actor(args.actor), action: args.recover === true ? "recover" : "archive", values: before.values, archivedAt: before.archivedAt }]).slice(-MAX_HISTORY); var record = clone(before); record.archivedAt = args.recover === true ? null : now(); record.revision++; record.updatedAt = now(); record.updatedBy = actor(args.actor); next.records[index] = record; next.revision++; next.updatedAt = record.updatedAt; next.updatedBy = record.updatedBy; return { databaseRevision: next.revision, record: publicRecord(record) }; }); }
|
|
156
159
|
function readRecord(args) { return all().then(function (databases) { var item = databases.filter(function (entry) { return entry._id === validation.id(args.databaseId, "database id"); })[0]; if (!item) throw error("Knowledge database not found.", "NOT_FOUND"); var record = item.records.filter(function (entry) { return entry.id === validation.id(args.recordId, "record id"); })[0]; if (!record) throw error("Knowledge database record not found.", "NOT_FOUND"); return { database: publicDatabase(item, false), record: publicRecord(record, referenceStates(item, record, databases, settings)), title: titleValue(item, record), history: clone(item.recordHistory[record.id] || []) }; }); }
|
|
157
160
|
function query(args) { return all().then(function (databases) { var item = databases.filter(function (entry) { return entry._id === validation.id(args.databaseId, "database id"); })[0]; if (!item) throw error("Knowledge database not found.", "NOT_FOUND"); if (item.archivedAt) throw error("Knowledge database is archived.", "ARCHIVED", item.revision); return queryRecords(item, args, databases, settings); }); }
|
|
158
|
-
function retryProjection(args) { return serialize(args.databaseId, function () { return load(args.databaseId).then(function (item) { return finish(item, { database: publicDatabase(item, false) }, actor(args.actor)); }); }); }
|
|
159
|
-
var importer = imports.attachKnowledgeDbImport({ clone: clone, error: error, actor: actor, newId: newId, mutationId: mutationId, fingerprint: fingerprint, ensureRevision: ensureRevision, receipt: receipt, remember: remember, serialize: serialize, load: load, all: all, referenceContext: referenceContext, replace: replace, finish: finish });
|
|
161
|
+
function retryProjection(args) { return serialize(args.databaseId, function () { return load(args.databaseId).then(function (item) { guard(args, item, "saving"); return finish(item, { database: publicDatabase(item, false) }, actor(args.actor)).then(function (result) { guard(args, null, "saved"); return result; }); }); }); }
|
|
162
|
+
var importer = imports.attachKnowledgeDbImport({ clone: clone, error: error, actor: actor, newId: newId, mutationId: mutationId, fingerprint: fingerprint, ensureRevision: ensureRevision, receipt: receipt, remember: remember, serialize: serialize, load: load, all: all, referenceContext: referenceContext, replace: replace, guard: guard, finish: finish });
|
|
160
163
|
return { readStorageStatus: function () { return typeof storage.diagnostics === "function" ? storage.diagnostics() : Promise.resolve(null); }, importRecords: importer.importRecords, readImportProgress: importer.readImportProgress, hasStore: function () { return storage.hasStore(); }, isReady: function () { return storage.isReady(); }, initialize: function () { return Promise.resolve(storage.initialize()).then(function () {}); }, listCached: listCached, create: create, list: list, read: read, rename: rename, archive: archive, recover: function (args) { return archive(Object.assign({}, args, { recover: true })); }, updateSchema: updateSchema, saveView: saveView, createRecord: createRecord, updateRecord: updateRecord, archiveRecord: archiveRecord, recoverRecord: function (args) { return archiveRecord(Object.assign({}, args, { recover: true })); }, readRecord: readRecord, query: query, retryProjection: retryProjection };
|
|
161
164
|
}
|
|
162
165
|
|
|
@@ -18,7 +18,8 @@ function createKnowledgeDocumentIndex(options) {
|
|
|
18
18
|
if (file.size > options.maxDocumentBytes) { errors.push({ name: file.name, code: "TOO_LARGE", error: "Document exceeds the safe read limit." }); continue; }
|
|
19
19
|
if (known && token && known.token === token) {
|
|
20
20
|
if (bytes + known.bytes > MAX_INDEX_BYTES) { errors.push({ name: file.name, code: "INDEX_LIMIT", error: "Workspace Knowledge exceeds the safe index limit." }); continue; }
|
|
21
|
-
|
|
21
|
+
var fresh = Object.assign({}, known, { document: Object.assign({}, known.document, file) });
|
|
22
|
+
next[key] = fresh; documents.push(fresh.document); bytes += known.bytes; continue;
|
|
22
23
|
}
|
|
23
24
|
try { content = options.read(file); } catch (error) { errors.push({ name: file.name, code: error.code || "READ_FAILED", error: error.message }); continue; }
|
|
24
25
|
var size = Buffer.byteLength(content, "utf8");
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
var validName = require('./knowledge-file-store').validName;
|
|
2
|
+
// Narrow operations over the same document store used by the Knowledge workbench.
|
|
3
|
+
function createKnowledgeProductOperations(ctx) {
|
|
4
|
+
function find(args, deleted) {
|
|
5
|
+
var item = args.documentId ? ctx.files.list().concat(deleted ? ctx.files.deleted() : []).find(function (entry) { return entry.id === args.documentId; }) : null;
|
|
6
|
+
if (args.documentId && !item) throw Object.assign(new Error('Knowledge document not found.'), { code: 'ENOENT' });
|
|
7
|
+
var name = args.name || item && item.name;
|
|
8
|
+
if (!name || item && args.name && args.name !== item.name) throw new Error('Choose one exact Knowledge document.');
|
|
9
|
+
if (item && item.deleted) return item;
|
|
10
|
+
var current = ctx.files.read(name);
|
|
11
|
+
if (current.itemType !== 'text') throw new Error('Legacy JSONL sources are read-only.');
|
|
12
|
+
return current;
|
|
13
|
+
}
|
|
14
|
+
function read(args) { var item = find(args); return { documentId: item.id, name: item.name, revision: item.revision, content: item.content }; }
|
|
15
|
+
function saved(item, who) { return Object.assign({ documentId: item.id, name: item.name, revision: item.revision, persisted: true }, ctx.mirror(who, [item.name])); }
|
|
16
|
+
function snapshot(op) {
|
|
17
|
+
if (op.action === 'retry_document_sync' && op.names.some(function (name) { return !validName(name); })) throw new Error('Invalid Knowledge source name.');
|
|
18
|
+
if (op.action === 'create_document') return ctx.files.list().filter(function (item) { return item.name === op.name; });
|
|
19
|
+
if (op.action === 'retry_document_sync') return ctx.files.list().filter(function (item) { return op.names.indexOf(item.name) >= 0; });
|
|
20
|
+
var item = find(op, op.action === 'restore_document');
|
|
21
|
+
var result = { documentId: item.id, name: item.name, revision: item.revision, deleted: !!item.deleted };
|
|
22
|
+
if (op.action === 'restore_document') result.version = ctx.files.readHistory(item.id, op.version);
|
|
23
|
+
if (op.action === 'rename_document') result.documents = ctx.files.list();
|
|
24
|
+
return result;
|
|
25
|
+
}
|
|
26
|
+
function mutate(op, who) {
|
|
27
|
+
if (op.action === 'create_document') return saved(ctx.files.save(op.name, op.content, null), who);
|
|
28
|
+
if (op.action === 'retry_document_sync') return Object.assign({ persisted: true }, ctx.mirror(who, op.names));
|
|
29
|
+
var item = find(op, op.action === 'restore_document');
|
|
30
|
+
if (op.action === 'update_document') return saved(ctx.files.save(item.name, op.content, op.expectedRevision), who);
|
|
31
|
+
if (op.action === 'rename_document') return ctx.rename({ from: item.name, name: op.newName, documentId: item.id, expectedRevision: op.expectedRevision }, who);
|
|
32
|
+
if (op.action === 'delete_document') { ctx.files.remove(item.name, op.expectedRevision); return Object.assign({ documentId: item.id, name: item.name, persisted: true, deleted: true }, ctx.mirror(who, [item.name])); }
|
|
33
|
+
if (op.action === 'restore_document') return saved(ctx.files.restore(item.id, op.version, item.name, item.deleted ? null : op.expectedRevision), who);
|
|
34
|
+
throw new Error('Unsupported Knowledge document operation.');
|
|
35
|
+
}
|
|
36
|
+
function query(op) {
|
|
37
|
+
if (op.action === 'list_documents') return { documents: op.deleted ? ctx.files.deleted() : ctx.files.list() };
|
|
38
|
+
if (op.action === 'read_document') return read(op);
|
|
39
|
+
var item = find(op, true);
|
|
40
|
+
if (op.action === 'document_history') return { documentId: item.id, name: item.name, versions: ctx.files.history(item.id) };
|
|
41
|
+
if (op.action === 'read_document_version') return Object.assign({ documentId: item.id, name: item.name }, ctx.files.readHistory(item.id, op.version));
|
|
42
|
+
throw new Error('Unsupported Knowledge document query.');
|
|
43
|
+
}
|
|
44
|
+
return { query: query, snapshot: snapshot, mutate: mutate };
|
|
45
|
+
}
|
|
46
|
+
module.exports = { createKnowledgeProductOperations: createKnowledgeProductOperations };
|
|
@@ -13,6 +13,7 @@ function schema() {
|
|
|
13
13
|
communicationStyle: z.string().describe("JSON array of communication preferences"),
|
|
14
14
|
autonomy: z.string().describe("A concise description of autonomy, boundaries, and escalation behavior"),
|
|
15
15
|
identityMarkdown: z.string().describe("The complete first-person Mate identity in Markdown"),
|
|
16
|
+
scheduleIntent: z.string().optional().describe("Optional JSON schedule intent to bind only after the Mate is created"),
|
|
16
17
|
};
|
|
17
18
|
}
|
|
18
19
|
|
|
@@ -39,6 +40,7 @@ function getToolDefs(onPropose) {
|
|
|
39
40
|
communicationStyle: parseArray(args.communicationStyle, "communicationStyle"),
|
|
40
41
|
autonomy: args.autonomy,
|
|
41
42
|
identityMarkdown: args.identityMarkdown,
|
|
43
|
+
scheduleIntent: args.scheduleIntent || null,
|
|
42
44
|
};
|
|
43
45
|
} catch (error) {
|
|
44
46
|
return Promise.resolve({ content: [{ type: "text", text: "Error: " + error.message }], isError: true });
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
var personal = require('./mcp-session-access');
|
|
2
|
+
var provenance = require('./session-provenance');
|
|
3
|
+
function assertCanonicalKnowledgeQuery(source, project, multiUser, generation, findUser) {
|
|
4
|
+
var session = source.session, manager = project && project.getSessionManager();
|
|
5
|
+
if (!session || !manager || manager.sessions.get(session.localId) !== session || Number(session._sdkQueryGeneration || 0) !== generation) throw new Error('This canonical Knowledge query is stale.');
|
|
6
|
+
if (session.destroying || session.hidden || session.taskStopRequested || session.abortController && session.abortController.signal.aborted || session.spawn || provenance.isWorker(session) || session.homeDebatePlanning || session.debateSetupMode || session._mentionInProgress || session.mateCreationMode || session.sessionVisibility === 'shared' || session._mcpForeignInput || session.delegated || session._delegatedBy || session._pairDelegation) throw new Error('Canonical Knowledge requires a live private owner-authored query.');
|
|
7
|
+
if (multiUser && (!source.projectOwnerId || session.ownerId !== source.projectOwnerId || !personal.canUsePersonalConnections(session, manager.sessions) || findUser && !findUser(source.projectOwnerId))) throw new Error('Canonical Knowledge owner access changed.');
|
|
8
|
+
if (!multiUser && (session.ownerId || (session.history || []).some(function (entry) { return entry.type === 'user_message' && entry.from && entry.from !== 'default'; }))) throw new Error('Foreign input cannot authorize canonical Knowledge.');
|
|
9
|
+
}
|
|
10
|
+
module.exports = { assertCanonicalKnowledgeQuery: assertCanonicalKnowledgeQuery };
|
|
@@ -387,7 +387,7 @@ function attachMateKnowledgeService(ctx) {
|
|
|
387
387
|
}
|
|
388
388
|
if (typeof resolveMate !== "function") return null;
|
|
389
389
|
var mate = resolveMate(source.projectOwnerId || null, source.mateId);
|
|
390
|
-
if (!mate || mate.id !== source.mateId) return null;
|
|
390
|
+
if (!mate || mate.lifecycleDeletion || mate.id !== source.mateId) return null;
|
|
391
391
|
if (isMultiUser()) {
|
|
392
392
|
if (!source.projectOwnerId) return null;
|
|
393
393
|
if (mate.createdBy !== source.projectOwnerId) return null;
|
|
@@ -398,7 +398,7 @@ function attachMateKnowledgeService(ctx) {
|
|
|
398
398
|
|
|
399
399
|
var def = mate.builtinKey ? builtinMates.getBuiltinByKey(mate.builtinKey) : null;
|
|
400
400
|
var isClay = !!(mate.builtinKey === "clay" && def && def.hostAgent === true);
|
|
401
|
-
return { own: own, isClay: isClay, ownerId: source.projectOwnerId || null,
|
|
401
|
+
return { project: project, own: own, isClay: isClay, ownerId: source.projectOwnerId || null,
|
|
402
402
|
databaseService: typeof project.getKnowledgeDbService === "function" ? project.getKnowledgeDbService() : null,
|
|
403
403
|
actor: { type: "user", userId: source.session && source.session.ownerId || source.projectOwnerId || null, displayName: null } };
|
|
404
404
|
}
|
|
@@ -410,12 +410,14 @@ function attachMateKnowledgeService(ctx) {
|
|
|
410
410
|
// to work through a handler that was created while it was still live.
|
|
411
411
|
function bind(source) {
|
|
412
412
|
var initial = resolve(source);
|
|
413
|
+
var generation = Number(source && source.session && source.session._sdkQueryGeneration || 0);
|
|
413
414
|
if (!initial) return null;
|
|
414
415
|
|
|
415
416
|
function revalidate() {
|
|
416
417
|
var current = resolve(source);
|
|
418
|
+
if (initial.isClay) require("./mate-knowledge-canonical-access").assertCanonicalKnowledgeQuery(source, getProjects().get(source.projectSlug), isMultiUser(), generation, context.findUser);
|
|
417
419
|
if (!current) throw new Error("This Knowledge binding is no longer valid for the current session.");
|
|
418
|
-
if (current.isClay !== initial.isClay || current.own.scopeId !== initial.own.scopeId || current.databaseService !== initial.databaseService) {
|
|
420
|
+
if (current.project !== initial.project || current.isClay !== initial.isClay || current.own.scopeId !== initial.own.scopeId || current.databaseService !== initial.databaseService) {
|
|
419
421
|
throw new Error("This Knowledge binding is no longer valid for the current session.");
|
|
420
422
|
}
|
|
421
423
|
return current;
|
|
@@ -446,7 +448,8 @@ function attachMateKnowledgeService(ctx) {
|
|
|
446
448
|
for (var i = 0; i < listed.length; i++) {
|
|
447
449
|
var entry = listed[i];
|
|
448
450
|
if (!entry || !entry.id || !entry.dir) continue;
|
|
449
|
-
|
|
451
|
+
var registered = resolveMate(ownerId, entry.id);
|
|
452
|
+
if (!registered || registered.lifecycleDeletion || isMultiUser() && registered.createdBy !== ownerId) continue;
|
|
450
453
|
var scope = scopeForMate(entry.dir, entry.id, entry.name || null);
|
|
451
454
|
if (!scope) continue;
|
|
452
455
|
out.push(scope);
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
var crypto = require('crypto');
|
|
2
|
+
function attachMateLifecycleService(ctx) {
|
|
3
|
+
var busy = new Set();
|
|
4
|
+
function owner(userId) {
|
|
5
|
+
if (ctx.users.isMultiUser() && (!userId || !ctx.users.findUserById(userId))) throw new Error('Mate owner is unavailable.');
|
|
6
|
+
return ctx.mates.buildMateCtx(ctx.users.isMultiUser() ? userId : null);
|
|
7
|
+
}
|
|
8
|
+
function read(userId, id) {
|
|
9
|
+
var mate = ctx.mates.getMate(owner(userId), id);
|
|
10
|
+
if (!mate || ctx.users.isMultiUser() && mate.createdBy !== userId) throw new Error('Mate is unavailable or belongs to another owner.');
|
|
11
|
+
return mate;
|
|
12
|
+
}
|
|
13
|
+
function validateReceipt(userId, id, allowMissing) {
|
|
14
|
+
var mate = ctx.mates.getMate(owner(userId), id);
|
|
15
|
+
if (!mate && allowMissing) return;
|
|
16
|
+
if (!mate || ctx.users.isMultiUser() && mate.createdBy !== userId) throw new Error('Mate receipt access changed.');
|
|
17
|
+
}
|
|
18
|
+
function list(userId) {
|
|
19
|
+
return ctx.mates.getAllMates(owner(userId)).filter(function (mate) { return !ctx.users.isMultiUser() || mate.createdBy === userId; });
|
|
20
|
+
}
|
|
21
|
+
function broadcast(userId, message, ws) {
|
|
22
|
+
var seen = new Set();
|
|
23
|
+
function send(socket) {
|
|
24
|
+
if (!socket || seen.has(socket) || socket.readyState !== 1) return;
|
|
25
|
+
if (ctx.users.isMultiUser() && (!socket._clayUser || socket._clayUser.id !== userId)) return;
|
|
26
|
+
seen.add(socket); socket.send(JSON.stringify(message));
|
|
27
|
+
}
|
|
28
|
+
send(ws);
|
|
29
|
+
ctx.projects.forEach(function (project) { project.forEachClient(send); });
|
|
30
|
+
}
|
|
31
|
+
function update(userId, id, updates, ws, requestId) {
|
|
32
|
+
var mate = read(userId, id);
|
|
33
|
+
if (Object.prototype.hasOwnProperty.call(updates, 'lifecycleDeletion')) throw new Error('Mate deletion state is server-managed.');
|
|
34
|
+
if (busy.has(id) || mate.lifecycleDeletion) throw new Error('Mate deletion is pending.');
|
|
35
|
+
var updated = ctx.mates.updateMate(owner(userId), id, updates);
|
|
36
|
+
if (!updated || updated.error) throw new Error(updated && updated.error || 'Mate not found');
|
|
37
|
+
try {
|
|
38
|
+
broadcast(userId, { type: 'mate_updated', mate: updated, requestId: requestId }, ws);
|
|
39
|
+
if (ctx.refresh) ctx.refresh(owner(userId));
|
|
40
|
+
} catch (error) { error.productControlResult = { persisted: true, retrySafe: false }; throw error; }
|
|
41
|
+
return updated;
|
|
42
|
+
}
|
|
43
|
+
function idle(project) {
|
|
44
|
+
if (!project) return;
|
|
45
|
+
if (project.inspectMateLifecycleRuntime && project.inspectMateLifecycleRuntime().some(function (t) { return !t.exited; })) throw new Error('Close the Mate terminals before deletion.');
|
|
46
|
+
project.getSessionManager().sessions.forEach(function (session) {
|
|
47
|
+
if (session.isProcessing || session._queryStarting || session.queryInstance || session.worker || session.terminalId || session.runtimeTerminalId || Object.keys(session._mentionSessions || {}).length) throw new Error('Wait for this Mate runtime to become idle before deletion.');
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
async function closeRuntime(slug, validate) {
|
|
51
|
+
var timer;
|
|
52
|
+
try {
|
|
53
|
+
return await Promise.race([Promise.resolve().then(function () { if (validate) validate(true); return ctx.removeProject(slug, true); }), new Promise(function (resolve, reject) {
|
|
54
|
+
timer = setTimeout(function () { reject(new Error('Mate runtime cleanup timed out; deletion remains pending.')); }, 10000);
|
|
55
|
+
})]);
|
|
56
|
+
} finally { clearTimeout(timer); }
|
|
57
|
+
}
|
|
58
|
+
async function remove(userId, id, validate, ws) {
|
|
59
|
+
var mate = read(userId, id), slug = 'mate-' + id, project = ctx.projects.get(slug);
|
|
60
|
+
if (mate.primary || mate.builtinKey === 'clay') throw new Error('Canonical Clay and primary Mates cannot be deleted.');
|
|
61
|
+
if (busy.has(id)) throw new Error('Another Mate lifecycle operation is applying.');
|
|
62
|
+
idle(project);
|
|
63
|
+
if (validate) validate();
|
|
64
|
+
busy.add(id);
|
|
65
|
+
var persisted = false, runtimeClosed = false;
|
|
66
|
+
try {
|
|
67
|
+
// Retain an owner-visible tombstone until every required cleanup is acknowledged.
|
|
68
|
+
if (!mate.lifecycleDeletion) mate = ctx.mates.updateMate(owner(userId), id, { lifecycleDeletion: { id: crypto.randomUUID(), runtimeRequired: !!project, runtimeClosed: !project } });
|
|
69
|
+
if (!mate || mate.error) throw new Error('Could not persist the pending Mate deletion.');
|
|
70
|
+
persisted = true;
|
|
71
|
+
if (mate.builtinKey) ctx.users.addDeletedBuiltinKey(userId, mate.builtinKey);
|
|
72
|
+
if (!project && mate.lifecycleDeletion.runtimeRequired && !mate.lifecycleDeletion.runtimeClosed) throw new Error('Runtime cleanup proof is unavailable; retain the pending deletion for operator recovery.');
|
|
73
|
+
if (project && await closeRuntime(slug, validate) !== true) throw new Error('Mate runtime cleanup was not acknowledged.');
|
|
74
|
+
runtimeClosed = true;
|
|
75
|
+
mate = ctx.mates.updateMate(owner(userId), id, { lifecycleDeletion: Object.assign({}, mate.lifecycleDeletion, { runtimeClosed: true }) });
|
|
76
|
+
if (!mate || mate.error) throw new Error('Runtime closure proof could not be saved.');
|
|
77
|
+
if (validate) validate(true);
|
|
78
|
+
var current = read(userId, id);
|
|
79
|
+
if (!current.lifecycleDeletion || current.lifecycleDeletion.id !== mate.lifecycleDeletion.id) throw new Error('Mate deletion identity changed.');
|
|
80
|
+
var result = ctx.mates.deleteMate(owner(userId), id, { strictCleanup: true });
|
|
81
|
+
if (!result || !result.ok) throw new Error(result && result.error || 'Mate deletion was not persisted.');
|
|
82
|
+
var definitions = require('./builtin-mates');
|
|
83
|
+
var available = ctx.mates.getMissingBuiltinKeys(owner(userId)).map(function (key) { var def = definitions.getBuiltinByKey(key); return def && { key: def.key, displayName: def.displayName, bio: def.bio, avatarCustom: def.avatarCustom || '', avatarStyle: def.avatarStyle || 'imprint', avatarColor: def.avatarColor || '' }; }).filter(Boolean);
|
|
84
|
+
broadcast(userId, { type: 'mate_deleted', mateId: id, availableBuiltins: available }, ws);
|
|
85
|
+
if (ctx.refresh) ctx.refresh(owner(userId));
|
|
86
|
+
return { persisted: true, runtimeClosed: true, directoryRemoved: true };
|
|
87
|
+
} catch (error) {
|
|
88
|
+
error.productControlResult = { persisted: persisted, runtimeClosed: runtimeClosed, deletionPending: !!ctx.mates.getMate(owner(userId), id), retrySafe: false };
|
|
89
|
+
throw error;
|
|
90
|
+
} finally { busy.delete(id); }
|
|
91
|
+
}
|
|
92
|
+
return { read: read, validateReceipt: validateReceipt, list: list, update: update, remove: remove };
|
|
93
|
+
}
|
|
94
|
+
module.exports = { attachMateLifecycleService: attachMateLifecycleService };
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
// Shared Home/Mate delivery. Canonical callers supply an exact live guard and
|
|
2
|
+
// persist delegated provenance before any provider input is admitted.
|
|
3
|
+
async function deliver(ctx, session, text, options) {
|
|
4
|
+
options = options || {};
|
|
5
|
+
var guarded = typeof options.revalidate === 'function';
|
|
6
|
+
function current() {
|
|
7
|
+
if (ctx.sm.sessions.get(session.localId) !== session) throw new Error('The conversation was deleted or replaced.');
|
|
8
|
+
if (guarded) {
|
|
9
|
+
options.revalidate();
|
|
10
|
+
if (session.taskStopRequested || session._pendingMessageDrainPaused || session._responseRecoveryStopPending || session.abortController && session.abortController.signal.aborted) throw new Error('The conversation is stopped; explicit owner resumption is required.');
|
|
11
|
+
}
|
|
12
|
+
return true;
|
|
13
|
+
}
|
|
14
|
+
if (guarded) current.exactProductDelivery = true;
|
|
15
|
+
current();
|
|
16
|
+
var event = options.event || { type: 'user_message', text: text };
|
|
17
|
+
if (guarded) {
|
|
18
|
+
if (ctx.sm.saveSessionFile(session) !== true) throw new Error('The conversation could not be saved; no provider delivery was attempted.');
|
|
19
|
+
if (ctx.sm.sendAndRecordDurably(session, event) !== true) throw new Error('The delegated message could not be saved; no provider delivery was attempted.');
|
|
20
|
+
session._mcpForeignInput = true;
|
|
21
|
+
} else ctx.sm.sendAndRecord(session, event);
|
|
22
|
+
var attempted = false;
|
|
23
|
+
try {
|
|
24
|
+
current();
|
|
25
|
+
var active = !!session.isProcessing;
|
|
26
|
+
session.isProcessing = true;
|
|
27
|
+
if (!active) session.sentToolResults = {};
|
|
28
|
+
if (options.onRecorded) options.onRecorded(session);
|
|
29
|
+
var queryText = options.queryText || text;
|
|
30
|
+
attempted = true;
|
|
31
|
+
if (session.queryInstance || session.worker && session.messageQueue === 'worker' || active) {
|
|
32
|
+
if (ctx.sdk.pushMessage(session, queryText, null) === true) return { status: 'queued', persisted: true, delivery: 'accepted', completion: 'pending' };
|
|
33
|
+
if (active) return { status: 'failed', persisted: true, delivery: 'rejected', retrySafe: false, error: 'The active provider did not accept the message. Inspect before another request.' };
|
|
34
|
+
}
|
|
35
|
+
var accepted = await ctx.sdk.startQuery(session, queryText, null, ctx.linuxUser || null, guarded ? current : undefined);
|
|
36
|
+
return { status: accepted === true ? 'started' : 'failed', persisted: true, delivery: accepted === true ? 'accepted' : 'not_confirmed', completion: 'pending', retrySafe: false };
|
|
37
|
+
} catch (error) {
|
|
38
|
+
if (!attempted) session.isProcessing = false;
|
|
39
|
+
error.productControlResult = { persisted: true, delivery: attempted ? 'unknown' : 'not_attempted', retrySafe: false };
|
|
40
|
+
throw error;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
module.exports = { deliver: deliver };
|
|
@@ -4,6 +4,7 @@ var resolveMateIdentityFile = require('./mate-identity-file').resolveMateIdentit
|
|
|
4
4
|
|
|
5
5
|
var fs = require("fs");
|
|
6
6
|
var path = require("path");
|
|
7
|
+
var scheduleInput = require("./mate-schedule-input");
|
|
7
8
|
|
|
8
9
|
function cleanLine(value, maxLength, field) {
|
|
9
10
|
if (typeof value !== "string") throw new Error(field + " is required.");
|
|
@@ -27,6 +28,11 @@ function normalize(definition) {
|
|
|
27
28
|
var identity = typeof definition.identityMarkdown === "string" ? definition.identityMarkdown.replace(/\u0000/g, "").trim() : "";
|
|
28
29
|
if (identity.length < 200) throw new Error("The Mate identity is incomplete.");
|
|
29
30
|
if (identity.length > 30000) throw new Error("The Mate identity is too long.");
|
|
31
|
+
var scheduleIntent = definition.scheduleIntent || null;
|
|
32
|
+
if (scheduleIntent) {
|
|
33
|
+
var scheduleChecked = scheduleInput.normalize(scheduleIntent);
|
|
34
|
+
scheduleIntent = { message: scheduleChecked.message, scheduleRule: scheduleChecked.rule };
|
|
35
|
+
}
|
|
30
36
|
return {
|
|
31
37
|
name: cleanLine(definition.name, 80, "Mate name"),
|
|
32
38
|
bio: cleanLine(definition.bio, 280, "Mate bio"),
|
|
@@ -37,6 +43,7 @@ function normalize(definition) {
|
|
|
37
43
|
identityMarkdown: identity,
|
|
38
44
|
vendor: cleanLine(definition.vendor || "claude", 40, "Vendor"),
|
|
39
45
|
model: cleanLine(definition.model, 240, "Mate model"),
|
|
46
|
+
scheduleIntent: scheduleIntent,
|
|
40
47
|
};
|
|
41
48
|
}
|
|
42
49
|
|
|
@@ -54,6 +61,7 @@ function createReadyMate(mates, mateCtx, definition) {
|
|
|
54
61
|
vendor: ready.vendor,
|
|
55
62
|
model: ready.model,
|
|
56
63
|
autonomy: ready.autonomy,
|
|
64
|
+
scheduleIntent: ready.scheduleIntent,
|
|
57
65
|
});
|
|
58
66
|
var mateDir = mates.getMateDir(mateCtx, mate.id);
|
|
59
67
|
var identityPath = resolveMateIdentityFile(mateDir);
|
|
@@ -80,7 +88,7 @@ function createReadyMate(mates, mateCtx, definition) {
|
|
|
80
88
|
vendor: ready.vendor,
|
|
81
89
|
model: ready.model,
|
|
82
90
|
profile: Object.assign({}, mate.profile || {}, { displayName: ready.name, bio: ready.bio }),
|
|
83
|
-
seedData: Object.assign({}, mate.seedData || {}, { relationship: ready.relationship, activity: ready.activities, communicationStyle: ready.communicationStyle, autonomy: ready.autonomy }),
|
|
91
|
+
seedData: Object.assign({}, mate.seedData || {}, { relationship: ready.relationship, activity: ready.activities, communicationStyle: ready.communicationStyle, autonomy: ready.autonomy, scheduleIntent: ready.scheduleIntent }),
|
|
84
92
|
});
|
|
85
93
|
mates.backupIdentity(mateDir, ready.identityMarkdown);
|
|
86
94
|
mates.logIdentityChange(mateDir, "clay_interview", ready.identityMarkdown, "");
|