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
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
var idleRecovery = require('./codex-idle-recovery');
|
|
2
|
+
|
|
3
|
+
// Serialize decisions, not whole model turns. Waiting for a target must release
|
|
4
|
+
// the gate so an unrelated Driver can still answer its Worker's permissions.
|
|
5
|
+
function attachRecoveryAdmission(ctx) {
|
|
6
|
+
var handoff = null;
|
|
7
|
+
var runtimes = [];
|
|
8
|
+
var targets = new Map();
|
|
9
|
+
var cleanupTasks = new Map();
|
|
10
|
+
var cleanupFailures = new Map();
|
|
11
|
+
var cleanup = Promise.resolve();
|
|
12
|
+
var unconfirmedSharedProcess = null;
|
|
13
|
+
|
|
14
|
+
function checkSharedExit() {
|
|
15
|
+
if (!unconfirmedSharedProcess) return;
|
|
16
|
+
if (unconfirmedSharedProcess.exitCode === null && unconfirmedSharedProcess.signalCode === null) {
|
|
17
|
+
throw new Error('Codex shared runtime exit could not be confirmed; recovery remains reserved.');
|
|
18
|
+
}
|
|
19
|
+
unconfirmedSharedProcess = null;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function checker(queryOpts) {
|
|
23
|
+
var epoch = ctx.state().epoch;
|
|
24
|
+
return function() {
|
|
25
|
+
idleRecovery.checkAbort(queryOpts);
|
|
26
|
+
var state = ctx.state();
|
|
27
|
+
if ((state.shuttingDown && !state.retiring) || state.epoch !== epoch) throw ctx.shutdownError();
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function cleanupRuntime(runtime) {
|
|
32
|
+
if (cleanupTasks.has(runtime)) return cleanupTasks.get(runtime);
|
|
33
|
+
var task = cleanup.catch(function() { return null; }).then(function() {
|
|
34
|
+
return runtime.shutdownForRecovery();
|
|
35
|
+
}).then(function() {
|
|
36
|
+
runtimes = runtimes.filter(function(current) { return current !== runtime; });
|
|
37
|
+
targets.forEach(function(current, threadId) { if (current === runtime) targets.delete(threadId); });
|
|
38
|
+
cleanupTasks.delete(runtime);
|
|
39
|
+
return true;
|
|
40
|
+
}, function(error) {
|
|
41
|
+
console.error('[yoke/codex] Isolated recovery runtime shutdown failed:', error.message || error);
|
|
42
|
+
// Retain ownership after an unconfirmed exit. In particular, never admit
|
|
43
|
+
// a second writer just because bounded process cleanup reached its limit.
|
|
44
|
+
cleanupFailures.set(runtime, error);
|
|
45
|
+
return false;
|
|
46
|
+
});
|
|
47
|
+
cleanupTasks.set(runtime, task);
|
|
48
|
+
cleanup = task;
|
|
49
|
+
return task;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
async function withAdmission(checkCurrent, action) {
|
|
53
|
+
var release;
|
|
54
|
+
var prior = handoff;
|
|
55
|
+
var own = new Promise(function(resolve) { release = resolve; });
|
|
56
|
+
var tail = Promise.resolve(prior).then(function() { return own; });
|
|
57
|
+
handoff = tail;
|
|
58
|
+
tail.then(function() { if (handoff === tail) handoff = null; });
|
|
59
|
+
try {
|
|
60
|
+
await idleRecovery.wait(prior || Promise.resolve(), checkCurrent);
|
|
61
|
+
await idleRecovery.wait(cleanup, checkCurrent);
|
|
62
|
+
checkSharedExit();
|
|
63
|
+
return await action();
|
|
64
|
+
} finally {
|
|
65
|
+
// An aborted waiter still links to its predecessor. Releasing its own
|
|
66
|
+
// slot cannot let a later caller overtake a probe that is still running.
|
|
67
|
+
release();
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
async function releaseTarget(threadId, checkCurrent) {
|
|
72
|
+
var prior = targets.get(threadId);
|
|
73
|
+
if (!prior) return true;
|
|
74
|
+
if (cleanupFailures.has(prior)) throw cleanupFailures.get(prior);
|
|
75
|
+
await prior.retireIdleForRecovery(checkCurrent);
|
|
76
|
+
await cleanup;
|
|
77
|
+
checkCurrent();
|
|
78
|
+
if (cleanupFailures.has(prior)) throw cleanupFailures.get(prior);
|
|
79
|
+
return !targets.has(threadId);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
async function prepareShared(threadId, checkCurrent) {
|
|
83
|
+
var state = ctx.state();
|
|
84
|
+
if (state.initializing) return false;
|
|
85
|
+
var retiredThreads = [];
|
|
86
|
+
if (state.refCount > 0) {
|
|
87
|
+
var snapshots = state.entries.map(function(entry) { return entry.handle && entry.handle.getIdleRecoverySnapshot(); });
|
|
88
|
+
if (await idleRecovery.retireIdleQueries(state.entries, state.server, checkCurrent)) {
|
|
89
|
+
retiredThreads = snapshots.filter(Boolean).map(function(snapshot) { return snapshot.threadId; });
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
state = ctx.state();
|
|
93
|
+
if (!state.server) return true;
|
|
94
|
+
if (!state.refCount && await idleRecovery.runtimeCanStop(state.server, retiredThreads, checkCurrent)) {
|
|
95
|
+
var proc = state.server.proc;
|
|
96
|
+
var stopped = await ctx.stopIdle();
|
|
97
|
+
if (stopped) { unconfirmedSharedProcess = proc || null; checkSharedExit(); }
|
|
98
|
+
return stopped;
|
|
99
|
+
}
|
|
100
|
+
return idleRecovery.releaseThread(state.entries, state.server, threadId, checkCurrent);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
async function waitUntilAvailable(queryOpts, action) {
|
|
104
|
+
var checkCurrent = checker(queryOpts);
|
|
105
|
+
var waiting = false;
|
|
106
|
+
if (typeof queryOpts.onRecoveryAdmission === 'function') queryOpts.onRecoveryAdmission(true);
|
|
107
|
+
try {
|
|
108
|
+
while (true) {
|
|
109
|
+
checkCurrent();
|
|
110
|
+
// Cancellation returns to the caller immediately, but an in-flight
|
|
111
|
+
// unsubscribe or shutdown retains the gate until its bounded RPC settles.
|
|
112
|
+
var result = await idleRecovery.wait(withAdmission(checkCurrent, action.bind(null, checkCurrent)), checkCurrent);
|
|
113
|
+
if (result) {
|
|
114
|
+
if (waiting && typeof queryOpts.onRecoveryWaiting === 'function') queryOpts.onRecoveryWaiting(false);
|
|
115
|
+
return result;
|
|
116
|
+
}
|
|
117
|
+
if (!waiting && typeof queryOpts.onRecoveryWaiting === 'function') queryOpts.onRecoveryWaiting(true);
|
|
118
|
+
waiting = true;
|
|
119
|
+
await idleRecovery.wait(new Promise(function(resolve) { setTimeout(resolve, 50); }), checkCurrent);
|
|
120
|
+
}
|
|
121
|
+
} finally {
|
|
122
|
+
if (typeof queryOpts.onRecoveryAdmission === 'function') queryOpts.onRecoveryAdmission(false);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function createQuery(queryOpts) {
|
|
127
|
+
return waitUntilAvailable(queryOpts, async function(checkCurrent) {
|
|
128
|
+
if (!await releaseTarget(queryOpts.resumeSessionId, checkCurrent)) return false;
|
|
129
|
+
if (!await prepareShared(queryOpts.resumeSessionId, checkCurrent)) return false;
|
|
130
|
+
checkCurrent();
|
|
131
|
+
var runtime = ctx.createRuntime(queryOpts);
|
|
132
|
+
runtimes.push(runtime);
|
|
133
|
+
targets.set(queryOpts.resumeSessionId, runtime);
|
|
134
|
+
try {
|
|
135
|
+
return await runtime.createQuery(Object.assign({}, queryOpts, {
|
|
136
|
+
isolatedRecovery: true,
|
|
137
|
+
onRuntimeFinished: function() { return cleanupRuntime(runtime); },
|
|
138
|
+
}));
|
|
139
|
+
} catch (error) {
|
|
140
|
+
await cleanupRuntime(runtime);
|
|
141
|
+
throw error;
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
return {
|
|
147
|
+
createQuery: createQuery,
|
|
148
|
+
pending: function() { return handoff; },
|
|
149
|
+
checkSharedExit: checkSharedExit,
|
|
150
|
+
hasTarget: function(threadId) { return targets.has(threadId); },
|
|
151
|
+
waitForTarget: function(queryOpts) {
|
|
152
|
+
return waitUntilAvailable(queryOpts, function(checkCurrent) { return releaseTarget(queryOpts.resumeSessionId, checkCurrent); });
|
|
153
|
+
},
|
|
154
|
+
shutdown: function() {
|
|
155
|
+
return Promise.all(runtimes.slice().map(cleanupRuntime)).then(function(results) {
|
|
156
|
+
checkSharedExit();
|
|
157
|
+
if (results.indexOf(false) !== -1) throw new Error('Codex recovery runtime cleanup could not be confirmed.');
|
|
158
|
+
return cleanup;
|
|
159
|
+
});
|
|
160
|
+
},
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
module.exports = { attachRecoveryAdmission: attachRecoveryAdmission };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// Serializable descriptions of implemented provider controls. Legacy setting
|
|
2
|
+
// keys and message names describe persistence compatibility, never authority.
|
|
3
|
+
var claude = {
|
|
4
|
+
auto: true,
|
|
5
|
+
permissionModes: [{ value: 'default', label: 'Ask' }, { value: 'plan', label: 'Plan' }, { value: 'acceptEdits', label: 'Auto-accept edits' }],
|
|
6
|
+
thinking: { options: ['disabled', 'adaptive', 'budget'], budget: true },
|
|
7
|
+
};
|
|
8
|
+
var codex = {
|
|
9
|
+
approval: { options: [{ value: 'never', label: 'Auto' }, { value: 'untrusted', label: 'Untrusted' }, { value: 'on-request', label: 'Ask' }], state: 'codexApproval', message: 'set_codex_approval', key: 'approval' },
|
|
10
|
+
sandbox: { options: [{ value: 'read-only', label: 'Read Only' }, { value: 'workspace-write', label: 'Workspace' }, { value: 'danger-full-access', label: 'Full Access' }], state: 'codexSandbox', message: 'set_codex_sandbox', key: 'sandbox' },
|
|
11
|
+
webSearch: { options: [{ value: 'disabled', label: 'Off' }, { value: 'cached', label: 'Cached' }, { value: 'live', label: 'Live' }], state: 'codexWebSearch', message: 'set_codex_websearch', key: 'webSearch' },
|
|
12
|
+
};
|
|
13
|
+
module.exports = { claude: claude, codex: codex };
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
// Installation resolution shared by adapter creation, startup and product UI.
|
|
2
|
+
// This never starts a provider; callers may replace resolvers for isolated tests.
|
|
3
|
+
var fs = require('fs');
|
|
4
|
+
var cp = require('child_process');
|
|
5
|
+
function onPath(binary, user) {
|
|
6
|
+
try {
|
|
7
|
+
if (user && !/^[a-z_][a-z0-9_-]*\$?$/i.test(user)) return null;
|
|
8
|
+
var command = user ? 'su' : process.platform === 'win32' ? 'where' : 'which';
|
|
9
|
+
var args = user ? ['-', user, '-c', 'which ' + binary] : [binary];
|
|
10
|
+
if (!/^[a-zA-Z0-9_.-]+$/.test(binary)) return null;
|
|
11
|
+
var result = cp.execFileSync(command, args, { encoding: 'utf8', timeout: 3000, stdio: ['pipe', 'pipe', 'pipe'] });
|
|
12
|
+
return String(result || '').trim().split(/\r?\n/)[0] || null;
|
|
13
|
+
} catch (error) { return null; }
|
|
14
|
+
}
|
|
15
|
+
// Native commands require an executable regular file. SDK-owned JavaScript
|
|
16
|
+
// entries are readable files launched through Node, not native executables.
|
|
17
|
+
function validEntry(file, script) {
|
|
18
|
+
try {
|
|
19
|
+
if (typeof file !== 'string' || !file || !fs.statSync(file).isFile()) return false;
|
|
20
|
+
fs.accessSync(file, script && /\.(?:c|m)?js$/i.test(file) ? fs.constants.R_OK : fs.constants.X_OK);
|
|
21
|
+
return true;
|
|
22
|
+
} catch (error) { return false; }
|
|
23
|
+
}
|
|
24
|
+
function explicitEntry(env, name, script) {
|
|
25
|
+
if (!Object.prototype.hasOwnProperty.call(env, name)) return undefined;
|
|
26
|
+
if (!validEntry(env[name], script)) throw new Error('Invalid explicit provider executable: ' + name);
|
|
27
|
+
return env[name];
|
|
28
|
+
}
|
|
29
|
+
function pathResolver(binary, override) {
|
|
30
|
+
return function(options) {
|
|
31
|
+
options = options || {};
|
|
32
|
+
var env = options.env || process.env;
|
|
33
|
+
if (!options.user && override) {
|
|
34
|
+
var explicit = explicitEntry(env, override, false);
|
|
35
|
+
if (explicit !== undefined) return explicit;
|
|
36
|
+
}
|
|
37
|
+
var resolved = onPath(binary, options.user);
|
|
38
|
+
return options.user || validEntry(resolved, false) ? resolved : null;
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
function bundledResolver(find, binary) {
|
|
42
|
+
return function(options) {
|
|
43
|
+
options = options || {};
|
|
44
|
+
// The mapped account cannot inherit the daemon account's installation.
|
|
45
|
+
if (options.user) return onPath(binary, options.user);
|
|
46
|
+
// The runtime resolver owns all fallback policy. Adding a discovery-only
|
|
47
|
+
// PATH fallback would advertise a runtime that its adapter cannot start.
|
|
48
|
+
return find();
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
function acpResolver(vendor) {
|
|
52
|
+
return function(options) {
|
|
53
|
+
if (options && options.user) return null;
|
|
54
|
+
var profiles = require('./acp-agent-profiles');
|
|
55
|
+
return profiles.findAcpAgentPath(profiles.getAcpAgentProfile(vendor));
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
function installed(options) {
|
|
59
|
+
var registry = options && options.registry || require('./vendor-registry').VENDOR_REGISTRY;
|
|
60
|
+
var result = {};
|
|
61
|
+
Object.keys(registry).forEach(function(vendor) {
|
|
62
|
+
var info = registry[vendor];
|
|
63
|
+
result[vendor] = false;
|
|
64
|
+
if (options && options.user && info.osUserIsolation !== true) return;
|
|
65
|
+
if (typeof info.resolveExecutable !== 'function') return;
|
|
66
|
+
try { result[vendor] = !!info.resolveExecutable(options || {}); } catch (error) {}
|
|
67
|
+
});
|
|
68
|
+
return result;
|
|
69
|
+
}
|
|
70
|
+
module.exports = { installed: installed, pathResolver: pathResolver, bundledResolver: bundledResolver, acpResolver: acpResolver, validEntry: validEntry, explicitEntry: explicitEntry };
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
function classify(provider, text) {
|
|
2
|
+
var service = require('./provider-contract').resolve(provider).classifyError;
|
|
3
|
+
return typeof service === 'function' ? service(text) : null;
|
|
4
|
+
}
|
|
5
|
+
function contextOverflow(error) {
|
|
6
|
+
return /prompt is too long|context_length|maximum context length/i.test(String(error || ""));
|
|
7
|
+
}
|
|
8
|
+
module.exports = { contextOverflow: contextOverflow, classify: classify };
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
// Provider compatibility at the host boundary. No effects occur on import.
|
|
2
|
+
function prepare(env) { delete env.CLAUDECODE; }
|
|
3
|
+
function reaper(env) {
|
|
4
|
+
return { idleMs: Number(env.CLAY_ADAPTER_IDLE_MS) || Number(env.CLAY_CODEX_IDLE_MS) || 5 * 60 * 1000,
|
|
5
|
+
reapMs: Number(env.CLAY_ADAPTER_REAPER_MS) || Number(env.CLAY_CODEX_REAPER_MS) || 60 * 1000 };
|
|
6
|
+
}
|
|
7
|
+
module.exports = { prepare: prepare, reaper: reaper };
|
package/lib/yoke/index.js
CHANGED
|
@@ -16,11 +16,12 @@ var createGrokAdapter = require("./adapters/grok").createGrokAdapter;
|
|
|
16
16
|
var createCopilotAdapter = require("./adapters/copilot").createCopilotAdapter;
|
|
17
17
|
var createQwenAdapter = require("./adapters/qwen").createQwenAdapter;
|
|
18
18
|
var createJunieAdapter = require("./adapters/junie").createJunieAdapter;
|
|
19
|
+
var createMuseAdapter = require("./adapters/muse").createMuseAdapter;
|
|
19
20
|
var createKiroAdapter = require("./adapters/kiro").createKiroAdapter;
|
|
20
21
|
|
|
21
22
|
// Keep the first session in a new project predictable. This order is also
|
|
22
23
|
// used by the UI when a project has no remembered vendor yet.
|
|
23
|
-
var DEFAULT_VENDOR_ORDER = ["claude", "codex", "grok", "kimi", "copilot", "qwen", "junie", "antigravity", "opencode", "kiro"];
|
|
24
|
+
var DEFAULT_VENDOR_ORDER = ["claude", "codex", "muse", "grok", "kimi", "copilot", "qwen", "junie", "antigravity", "opencode", "kiro"];
|
|
24
25
|
|
|
25
26
|
function resolveDefaultVendor(availableVendors) {
|
|
26
27
|
availableVendors = availableVendors || {};
|
|
@@ -97,6 +98,8 @@ function createAdapter(opts) {
|
|
|
97
98
|
adapter = createJunieAdapter(opts);
|
|
98
99
|
} else if (vendor === "kiro") {
|
|
99
100
|
adapter = createKiroAdapter(opts);
|
|
101
|
+
} else if (vendor === "muse") {
|
|
102
|
+
adapter = createMuseAdapter(opts);
|
|
100
103
|
} else {
|
|
101
104
|
throw new Error("[YOKE] Unknown adapter vendor: " + vendor);
|
|
102
105
|
}
|
|
@@ -262,6 +265,7 @@ function checkAuth() {
|
|
|
262
265
|
qwen: !!lookupBinary("qwen"),
|
|
263
266
|
junie: !!lookupBinary("junie"),
|
|
264
267
|
kiro: checkKiro(),
|
|
268
|
+
muse: null,
|
|
265
269
|
};
|
|
266
270
|
logAuthCheck(_authCache);
|
|
267
271
|
return _authCache;
|
|
@@ -280,54 +284,8 @@ function checkAuth() {
|
|
|
280
284
|
var _installedCache = null;
|
|
281
285
|
|
|
282
286
|
function checkInstalled() {
|
|
283
|
-
if (_installedCache)
|
|
284
|
-
|
|
285
|
-
var fs = require("fs");
|
|
286
|
-
var execFileSync = require("child_process").execFileSync;
|
|
287
|
-
var result = { claude: false, codex: false, antigravity: false, opencode: false, kimi: false, grok: false, copilot: false, qwen: false, junie: false, kiro: false };
|
|
288
|
-
try {
|
|
289
|
-
if (process.platform === "win32") execFileSync("where", ["claude"], { timeout: 3000, stdio: ["pipe", "pipe", "pipe"] });
|
|
290
|
-
else execFileSync("which", ["claude"], { timeout: 3000, stdio: ["pipe", "pipe", "pipe"] });
|
|
291
|
-
result.claude = true;
|
|
292
|
-
} catch (e) {}
|
|
293
|
-
try {
|
|
294
|
-
var findKiroPath = require("./kiro-acp-server").findKiroPath;
|
|
295
|
-
var kiroBin = findKiroPath();
|
|
296
|
-
if (kiroBin && fs.existsSync(kiroBin)) result.kiro = true;
|
|
297
|
-
} catch (e) {}
|
|
298
|
-
try {
|
|
299
|
-
var codexBin = null;
|
|
300
|
-
try {
|
|
301
|
-
var findCodexPath = require("./codex-app-server").findCodexPath;
|
|
302
|
-
codexBin = findCodexPath();
|
|
303
|
-
if (codexBin && fs.existsSync(codexBin)) {
|
|
304
|
-
result.codex = true;
|
|
305
|
-
}
|
|
306
|
-
} catch (e) {}
|
|
307
|
-
|
|
308
|
-
if (!result.codex) {
|
|
309
|
-
var whichOut = process.platform === "win32"
|
|
310
|
-
? execFileSync("where", ["codex"], { timeout: 3000, encoding: "utf8", stdio: ["pipe", "pipe", "pipe"] })
|
|
311
|
-
: execFileSync("which", ["codex"], { timeout: 3000, encoding: "utf8", stdio: ["pipe", "pipe", "pipe"] });
|
|
312
|
-
if (whichOut.trim()) result.codex = true;
|
|
313
|
-
}
|
|
314
|
-
} catch (e) {}
|
|
315
|
-
try {
|
|
316
|
-
var antigravityBinary = process.platform === "win32"
|
|
317
|
-
? execFileSync("where", ["agy"], { timeout: 3000, encoding: "utf8", stdio: ["pipe", "pipe", "pipe"] })
|
|
318
|
-
: execFileSync("which", ["agy"], { timeout: 3000, encoding: "utf8", stdio: ["pipe", "pipe", "pipe"] });
|
|
319
|
-
result.antigravity = !!antigravityBinary.trim();
|
|
320
|
-
} catch (e) {}
|
|
321
|
-
var acpVendorKeys = ["opencode", "kimi", "grok", "copilot", "qwen", "junie"];
|
|
322
|
-
for (var acpIndex = 0; acpIndex < acpVendorKeys.length; acpIndex++) {
|
|
323
|
-
try {
|
|
324
|
-
var acpProfiles = require("./acp-agent-profiles");
|
|
325
|
-
var acpVendor = acpVendorKeys[acpIndex];
|
|
326
|
-
result[acpVendor] = !!acpProfiles.findAcpAgentPath(acpProfiles.getAcpAgentProfile(acpVendor));
|
|
327
|
-
} catch (e) {}
|
|
328
|
-
}
|
|
329
|
-
_installedCache = result;
|
|
330
|
-
return result;
|
|
287
|
+
if (!_installedCache) _installedCache = require("./discovery").installed();
|
|
288
|
+
return _installedCache;
|
|
331
289
|
}
|
|
332
290
|
|
|
333
291
|
function invalidateAuthCache() {
|
|
@@ -352,7 +310,7 @@ function createAdapters(opts) {
|
|
|
352
310
|
// Tests can supply a fixed installation snapshot without probing or spawning
|
|
353
311
|
// vendor binaries; production callers always use the cached host scan.
|
|
354
312
|
var installed = opts._installed || checkInstalled();
|
|
355
|
-
var auth = { claude: false, codex: false, antigravity: false, opencode: false, kimi: false, grok: false, copilot: false, qwen: false, junie: false, kiro: false };
|
|
313
|
+
var auth = { claude: false, codex: false, antigravity: false, opencode: false, kimi: false, grok: false, copilot: false, qwen: false, junie: false, kiro: false, muse: false };
|
|
356
314
|
var adapters = {};
|
|
357
315
|
|
|
358
316
|
function supportsConfiguredIsolation(vendor) {
|
|
@@ -390,7 +348,7 @@ function createAdapters(opts) {
|
|
|
390
348
|
}
|
|
391
349
|
}
|
|
392
350
|
|
|
393
|
-
var subprocessVendors = ["antigravity", "opencode", "kimi", "grok", "copilot", "qwen", "junie"];
|
|
351
|
+
var subprocessVendors = ["antigravity", "opencode", "kimi", "grok", "copilot", "qwen", "junie", "muse"];
|
|
394
352
|
for (var subprocessIndex = 0; subprocessIndex < subprocessVendors.length; subprocessIndex++) {
|
|
395
353
|
var subprocessVendor = subprocessVendors[subprocessIndex];
|
|
396
354
|
var subprocessInfo = vendorRegistry.getVendorInfo(subprocessVendor);
|
package/lib/yoke/interface.js
CHANGED
|
@@ -21,6 +21,25 @@ var INITIALIZE_TIMEOUT_MS = 90000;
|
|
|
21
21
|
|
|
22
22
|
/*
|
|
23
23
|
* Optional adapter event contract:
|
|
24
|
+
* { yokeType: "turn_activity", phase: "waiting" | "running" | "background", turnId?, disposition? }
|
|
25
|
+
* Waiting reports a pending submission/acknowledged queue, never model
|
|
26
|
+
* reasoning. Running requires an observed native start. Background means the
|
|
27
|
+
* foreground yielded while real terminals remain pending. These presentation
|
|
28
|
+
* facts never settle a turn or authorize tools; human decision surfaces take
|
|
29
|
+
* precedence. Common processing records them for live/replayed progress UI.
|
|
30
|
+
*
|
|
31
|
+
* { yokeType: "foreground_available" }
|
|
32
|
+
* Observed next-message admission while background work retains its real
|
|
33
|
+
* terminal. Offers one queue admission bound to this exact live query. Does
|
|
34
|
+
* not emit result/done, clear processing, settle reviews or complete tasks.
|
|
35
|
+
* Common processing persists an assistant_boundary presentation event before
|
|
36
|
+
* offering admission. Live/replayed clients flush the current assistant bubble
|
|
37
|
+
* at this boundary without treating it as a terminal or completing tools.
|
|
38
|
+
* Stop, paused delivery and query replacement invalidate the admission.
|
|
39
|
+
* A later successful result may carry backgroundOnly: true when its earlier
|
|
40
|
+
* foreground yielded to a newer accepted message. It accounts for that send
|
|
41
|
+
* without settling the newer turn's reviews or user-work completion callbacks.
|
|
42
|
+
*
|
|
24
43
|
* { yokeType: "background_tasks_changed", tasks: [{ task_id, task_type, description }] }
|
|
25
44
|
*
|
|
26
45
|
* Each event replaces the complete live set. An adapter that emits this event
|
|
@@ -29,6 +48,25 @@ var INITIALIZE_TIMEOUT_MS = 90000;
|
|
|
29
48
|
* and adapters that emit nothing simply have no background-task indicator.
|
|
30
49
|
*/
|
|
31
50
|
|
|
51
|
+
/*
|
|
52
|
+
* Optional image output event (independent of image input or invocation APIs):
|
|
53
|
+
* { yokeType: "generated_image", toolId, blockId, data, mediaType,
|
|
54
|
+
* prompt, savedPath, transparentBackground, isError, status }
|
|
55
|
+
* data is base64 image bytes (the common processor also accepts data URLs).
|
|
56
|
+
* toolId identifies this output; blockId associates any existing tool display.
|
|
57
|
+
* prompt is optional observed prompt text; savedPath is optional provenance,
|
|
58
|
+
* never authority to open a provider path. transparentBackground is true/false
|
|
59
|
+
* only when observed, otherwise null. Failed output sets isError and carries
|
|
60
|
+
* no successful image bytes. Common processing saves bytes, persists imageRefs
|
|
61
|
+
* and sends authenticated project URLs; failed saves become tool errors.
|
|
62
|
+
* The historical name covers provider-produced image artifacts, not proof of
|
|
63
|
+
* model generation. Emit only observed bytes, never an input echo, guessed
|
|
64
|
+
* filename or opaque artifact reference. Codex normalizes imageGeneration;
|
|
65
|
+
* Muse can read an explicitly typed raster outputRef through item/readOutput.
|
|
66
|
+
* This optional event does not imply pushMessage image-input support, an
|
|
67
|
+
* always-available model tool, or a dedicated adapter.generateImage() method.
|
|
68
|
+
*/
|
|
69
|
+
|
|
32
70
|
/**
|
|
33
71
|
* Validate that an adapter object implements all required methods.
|
|
34
72
|
* Throws if any are missing. Development-time safety net only.
|
|
@@ -40,6 +78,84 @@ var INITIALIZE_TIMEOUT_MS = 90000;
|
|
|
40
78
|
* .createToolServer(def): ToolServer (opaque)
|
|
41
79
|
* .createQuery(opts): QueryHandle
|
|
42
80
|
*
|
|
81
|
+
* Optional query orchestration contract (.queryContract):
|
|
82
|
+
* toolTransport: "sdk-mcp" | "dynamic" | "stdio-mcp" (absent: unsupported)
|
|
83
|
+
* catalogLifetime: "query" | "conversation"
|
|
84
|
+
* externalToolTransport?: "dynamic" for remotely discovered definitions
|
|
85
|
+
* defaultUserInputMode?: "fallback" | "native" (auto otherwise)
|
|
86
|
+
* questionGuidance?(): string; provider-specific protocol guidance
|
|
87
|
+
* permissionModes?: string[]; implemented native modes, e.g. "auto"
|
|
88
|
+
* mcpPermissionOverrides?: true only for a working handle override setter
|
|
89
|
+
* interruptionMessage?: string; truthful feedback after Stop
|
|
90
|
+
* catalogVersion?(session, family): number
|
|
91
|
+
* recordCatalog?(session, versions): void
|
|
92
|
+
* staleCatalogReason?: string
|
|
93
|
+
*
|
|
94
|
+
* Conversation catalogs are immutable on resume. The host uses semantic tool
|
|
95
|
+
* families (schedules, questions, browser, issues, knowledge, linear) and their
|
|
96
|
+
* required revisions to request an exact-query recovery bridge. Adapter-owned
|
|
97
|
+
* mapping reads/writes persisted provider fields, including legacy names. A
|
|
98
|
+
* missing reader means unknown catalog; a missing writer never records success.
|
|
99
|
+
* Writers run only after a matching session_started event on the same live
|
|
100
|
+
* session/query generation. Creating a handle alone is not catalog confirmation.
|
|
101
|
+
* SDK transports must actually mount createToolServer output; dynamic transports
|
|
102
|
+
* must dispatch dynamicTools/callDynamicTool and deliver sessionMcpServer on
|
|
103
|
+
* resume or reject startup truthfully. These declarations never authorize tools:
|
|
104
|
+
* owner/foreign checks, target/review authority and live generation checks remain
|
|
105
|
+
* in common services. Stop cancels pending input/effects immediately; uncertain
|
|
106
|
+
* effects must not replay automatically. Provider protocols stay adapter-side.
|
|
107
|
+
* Init-free contracts live beside adapters and are also exposed by the registry
|
|
108
|
+
* for product controls before adapter initialization. Other providers retain
|
|
109
|
+
* their existing declared stdio transport or default to unsupported.
|
|
110
|
+
*
|
|
111
|
+
* Init-free provider services (adapter.providerContract or registry entry):
|
|
112
|
+
* mapQueryOptions(intent): object. Translates validated common intent to SDK
|
|
113
|
+
* namespaces; host never builds CLAUDE/CODEX/ACP/KIRO envelopes. Intent
|
|
114
|
+
* includes settings, thinking, nativePermissionMode/nativeBypass, readOnly,
|
|
115
|
+
* isolation, resumeAt, instructionSources, betas and start time. readOnly
|
|
116
|
+
* must dominate bypass, sandbox and search options. Unknown providers have
|
|
117
|
+
* no extra options; declared invalid/missing implementations must not imply
|
|
118
|
+
* success. Legacy persisted names remain accepted through provider codecs.
|
|
119
|
+
* configuration: serializable permission/thinking/approval/sandbox/search
|
|
120
|
+
* descriptions. These describe supported controls, never authorization.
|
|
121
|
+
* settings: defaults(), messages(settings), change(message, settings) returns
|
|
122
|
+
* a validated patch and response; host owns persistence and socket access.
|
|
123
|
+
* normalizeContext(value): { usedTokens, windowTokens, measurement, source }.
|
|
124
|
+
* measurement is observed, estimated or unavailable. Zero is a measurement;
|
|
125
|
+
* unknown is null. Billing totals are not context occupancy. YOKE usage
|
|
126
|
+
* projects result/account-quota history to the same client contract.
|
|
127
|
+
* authenticationReply(text), classifyError(text): protocol interpretation.
|
|
128
|
+
* Host handles authenticationRequired and classified errors, preserving
|
|
129
|
+
* identity, user-visible failure and explicit resumption requirements.
|
|
130
|
+
* resolveExecutable(options): path|null; discovery never runs the provider.
|
|
131
|
+
* Explicit supported overrides win; mapped users cannot inherit daemon
|
|
132
|
+
* credentials/installations. Errors or missing resolvers mean unavailable.
|
|
133
|
+
* login command/host metadata: only known validated token-only operations;
|
|
134
|
+
* OAuth URLs require exact hosts, PKCE, state and a loopback callback.
|
|
135
|
+
* Host still authorizes the exact owner/terminal and async flow revision.
|
|
136
|
+
* prepareIsolation, processControl: provider filesystem/PID protocol. Host
|
|
137
|
+
* authorizes identity and the exact process target before effects; absent
|
|
138
|
+
* verification refuses termination. No arbitrary shell/API dispatch.
|
|
139
|
+
* recoveryFactory(ctx): actual begin/enqueue/event/progress/cancel/current/
|
|
140
|
+
* valid/stopping/dispose implementation. Only the implemented confirmed
|
|
141
|
+
* termination protocol may retry; never replay uncertain delivery. Bindings
|
|
142
|
+
* retain the original service for immediate Stop and reject replacement
|
|
143
|
+
* providers. Unsupported providers receive no synthesized watchdog/retry.
|
|
144
|
+
* readSessionHistory(home, cwd, sessionId): actual provider fork-history
|
|
145
|
+
* reader. Local-history forks bypass file reading. Missing/nonfunction
|
|
146
|
+
* readers refuse; the host must not assume another provider's format.
|
|
147
|
+
* supportsLegacyGuiResume(session): implements the actual terminal format;
|
|
148
|
+
* the host retains idle/Stop/identity admission and persistence authority.
|
|
149
|
+
* notificationHooks, maintenance, provisionUser, credentialDirectories:
|
|
150
|
+
* bounded provider services; host owns provisioning and cleanup policy.
|
|
151
|
+
*
|
|
152
|
+
* publicInfo() sends only an explicit serializable field allowlist. Executable
|
|
153
|
+
* callbacks/services, OAuth internals and factories are never client metadata.
|
|
154
|
+
* Unknown/unsupported transports normalize to none. Declared SDK MCP transport
|
|
155
|
+
* with requested definitions must have a callable factory and non-null result;
|
|
156
|
+
* errors fail startup before admission. Capability data never grants canonical
|
|
157
|
+
* registry/query-generation authority, owner permissions or human review.
|
|
158
|
+
*
|
|
43
159
|
* Optional one-shot capability:
|
|
44
160
|
* .createOneShotQuery(opts): Promise<{ handle, backendPersistence }>
|
|
45
161
|
* backendPersistence is "ephemeral" only when the adapter can verify the
|
|
@@ -8,9 +8,9 @@ var fs = require("fs");
|
|
|
8
8
|
var { AcpProcessManager } = require("./acp-process-manager");
|
|
9
9
|
|
|
10
10
|
function findKiroPath() {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
var discovery = require("./discovery");
|
|
12
|
+
var explicit = discovery.explicitEntry(process.env, "KIRO_CLI_PATH", false);
|
|
13
|
+
if (explicit !== undefined) return explicit;
|
|
14
14
|
|
|
15
15
|
var binName = process.platform === "win32" ? "kiro-cli.exe" : "kiro-cli";
|
|
16
16
|
var realHome;
|
|
@@ -23,7 +23,7 @@ function findKiroPath() {
|
|
|
23
23
|
"/opt/homebrew/bin/" + binName,
|
|
24
24
|
];
|
|
25
25
|
for (var i = 0; i < candidates.length; i++) {
|
|
26
|
-
if (
|
|
26
|
+
if (discovery.validEntry(candidates[i], false)) return candidates[i];
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
try {
|
|
@@ -32,7 +32,7 @@ function findKiroPath() {
|
|
|
32
32
|
? execFileSync("where", [binName], { timeout: 3000, encoding: "utf8", stdio: ["pipe", "pipe", "pipe"] })
|
|
33
33
|
: execFileSync("which", ["kiro-cli"], { timeout: 3000, encoding: "utf8", stdio: ["pipe", "pipe", "pipe"] });
|
|
34
34
|
var resolved = out.trim().split(/\r?\n/)[0];
|
|
35
|
-
if (resolved) return resolved;
|
|
35
|
+
if (discovery.validEntry(resolved, false)) return resolved;
|
|
36
36
|
} catch (e) {}
|
|
37
37
|
|
|
38
38
|
throw new Error("Could not find kiro-cli binary (looked in ~/.local/bin, PATH, KIRO_CLI_PATH)");
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
// The existing imported terminal format. Product session creation/deletion
|
|
2
|
+
// remains in the host; these are provider file/grammar projections only.
|
|
3
|
+
var fs = require("fs"), path = require("path");
|
|
4
|
+
var hygiene = require("./claude-transcript-hygiene");
|
|
5
|
+
function directory(home, cwd) { return path.join(home, ".claude", "projects", require("../utils").encodeCwd(cwd)); }
|
|
6
|
+
function readHead(filePath) {
|
|
7
|
+
var MAX_READ = 64 * 1024;
|
|
8
|
+
try {
|
|
9
|
+
var stat = fs.statSync(filePath);
|
|
10
|
+
var fd = fs.openSync(filePath, "r");
|
|
11
|
+
var bytesToRead = Math.min(stat.size, MAX_READ);
|
|
12
|
+
var buf = Buffer.alloc(bytesToRead);
|
|
13
|
+
fs.readSync(fd, buf, 0, bytesToRead, 0);
|
|
14
|
+
fs.closeSync(fd);
|
|
15
|
+
var lines = buf.toString("utf8").split("\n");
|
|
16
|
+
var events = [];
|
|
17
|
+
for (var i = 0; i < lines.length; i++) {
|
|
18
|
+
if (!lines[i]) continue;
|
|
19
|
+
try {
|
|
20
|
+
var event = JSON.parse(lines[i]);
|
|
21
|
+
if (event && typeof event === "object") events.push(event);
|
|
22
|
+
} catch (e) {}
|
|
23
|
+
}
|
|
24
|
+
return events;
|
|
25
|
+
} catch (e) {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function metadata(events, fp) {
|
|
31
|
+
var userCount = 0;
|
|
32
|
+
var firstUserText = null;
|
|
33
|
+
var createdAtIso = null;
|
|
34
|
+
for (var li = 0; li < events.length; li++) {
|
|
35
|
+
var ev = events[li];
|
|
36
|
+
if (ev.type === "user" && ev.message && ev.message.role === "user") {
|
|
37
|
+
userCount++;
|
|
38
|
+
if (firstUserText == null) {
|
|
39
|
+
var c = ev.message.content;
|
|
40
|
+
if (typeof c === "string") {
|
|
41
|
+
firstUserText = c;
|
|
42
|
+
} else if (Array.isArray(c)) {
|
|
43
|
+
var parts = [];
|
|
44
|
+
for (var ci = 0; ci < c.length; ci++) {
|
|
45
|
+
if (c[ci] && c[ci].type === "text" && typeof c[ci].text === "string") parts.push(c[ci].text);
|
|
46
|
+
}
|
|
47
|
+
firstUserText = parts.join("");
|
|
48
|
+
}
|
|
49
|
+
if (ev.timestamp && !createdAtIso) createdAtIso = ev.timestamp;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (userCount === 0) return null;
|
|
55
|
+
// Defensive warmup skip (daemon also cleans these)
|
|
56
|
+
if (hygiene.isClaudeWarmupTranscript(events)) return null;
|
|
57
|
+
|
|
58
|
+
// Title: first user message trimmed/truncated. Fall back to a
|
|
59
|
+
// neutral label so the sidebar entry is identifiable.
|
|
60
|
+
var title = (firstUserText || "").trim().replace(/\s+/g, " ");
|
|
61
|
+
if (title.length > 60) title = title.slice(0, 57) + "...";
|
|
62
|
+
if (!title) title = "Imported CLI session";
|
|
63
|
+
|
|
64
|
+
var createdAt = Date.now();
|
|
65
|
+
if (createdAtIso) {
|
|
66
|
+
var t = Date.parse(createdAtIso);
|
|
67
|
+
if (!isNaN(t)) createdAt = t;
|
|
68
|
+
}
|
|
69
|
+
var lastActivity = createdAt;
|
|
70
|
+
try { lastActivity = fs.statSync(fp).mtimeMs; } catch (e) {}
|
|
71
|
+
|
|
72
|
+
return { title: title, createdAt: createdAt, lastActivity: lastActivity };
|
|
73
|
+
}
|
|
74
|
+
function candidates(dir, known, deleted) {
|
|
75
|
+
var files;
|
|
76
|
+
try { files = fs.readdirSync(dir); } catch (error) { return []; }
|
|
77
|
+
return files.filter(function(file) { return file.endsWith(".jsonl"); }).flatMap(function(file) {
|
|
78
|
+
var id = file.slice(0, -6);
|
|
79
|
+
if (known.has(id) || deleted.has(id)) return [];
|
|
80
|
+
var filename = path.join(dir, file), events = readHead(filename);
|
|
81
|
+
var value = events && metadata(events, filename);
|
|
82
|
+
return value ? [Object.assign({ id: id, vendor: "claude" }, value)] : [];
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
function obsolete(dir, session) {
|
|
86
|
+
var filename = path.join(dir, session.cliSessionId + ".jsonl"), events = readHead(filename);
|
|
87
|
+
return !fs.existsSync(filename) && (!session.history || session.history.length === 0) || events && hygiene.isClaudeWarmupTranscript(events);
|
|
88
|
+
}
|
|
89
|
+
module.exports = { candidates: candidates, obsolete: obsolete, directory: directory, readHead: readHead, metadata: metadata, isWarmup: hygiene.isClaudeWarmupTranscript };
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// Known provider login operations and output grammar; never accepts a command
|
|
2
|
+
// from model/client input. Identity and terminal permission stay in the host.
|
|
3
|
+
var PATTERNS = [/successfully logged in(?![ \t]+to[ \t]+mcp)/i, /logged in successfully/i, /login successful/i,
|
|
4
|
+
/successfully authenticated/i, /authentication successful/i, /signed in successfully/i,
|
|
5
|
+
/signed in with your [a-z ]+ account/i, /you(?:'re| are) (?:now )?(?:logged|signed) in/i];
|
|
6
|
+
function stripAnsi(text) { return String(text).replace(/\x1b\[[0-9;?]*[ -\/]*[@-~]|\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)|\r/g, ''); }
|
|
7
|
+
function successful(text) { return PATTERNS.some(function(pattern) { return pattern.test(text); }); }
|
|
8
|
+
function command(vendor, browser) {
|
|
9
|
+
var info = require('./provider-contract').resolve(vendor);
|
|
10
|
+
var operation = browser ? info.browserLoginCommand : info.terminalLoginCommand || info.loginCommand;
|
|
11
|
+
if (typeof operation !== 'string' || !/^[a-zA-Z0-9_.-]+(?: [a-zA-Z0-9_.-]+)*$/.test(operation)) throw new Error('Provider sign-in is unavailable.');
|
|
12
|
+
return operation;
|
|
13
|
+
}
|
|
14
|
+
function loginUrl(value, provider) {
|
|
15
|
+
try {
|
|
16
|
+
var hosts = require('./provider-contract').resolve(provider).oauthHosts || [];
|
|
17
|
+
var url = new URL(value);
|
|
18
|
+
if (url.protocol !== 'https:' || url.username || url.password || hosts.indexOf(url.hostname) < 0) return null;
|
|
19
|
+
if (!url.searchParams.get('state') || !url.searchParams.get('code_challenge')) return null;
|
|
20
|
+
var callback = new URL(url.searchParams.get('redirect_uri'));
|
|
21
|
+
if (callback.protocol !== 'http:' || ['localhost', '127.0.0.1', '[::1]'].indexOf(callback.hostname) < 0) return null;
|
|
22
|
+
return url.href;
|
|
23
|
+
} catch (error) { return null; }
|
|
24
|
+
}
|
|
25
|
+
module.exports = { stripAnsi: stripAnsi, successful: successful, command: command, loginUrl: loginUrl };
|