aismemory 0.8.3 → 0.8.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +146 -3
- package/dist/__tests__/agent-key-mode.test.js +46 -5
- package/dist/__tests__/agent-key-mode.test.js.map +1 -1
- package/dist/__tests__/ais-http.test.js +22 -0
- package/dist/__tests__/ais-http.test.js.map +1 -1
- package/dist/__tests__/auto-enroll-key.test.js +20 -1
- package/dist/__tests__/auto-enroll-key.test.js.map +1 -1
- package/dist/__tests__/cli-info.test.js +8 -4
- package/dist/__tests__/cli-info.test.js.map +1 -1
- package/dist/__tests__/client-credential-expiry.test.d.ts +1 -0
- package/dist/__tests__/client-credential-expiry.test.js +319 -0
- package/dist/__tests__/client-credential-expiry.test.js.map +1 -0
- package/dist/__tests__/declared-agent.test.d.ts +1 -0
- package/dist/__tests__/declared-agent.test.js +60 -0
- package/dist/__tests__/declared-agent.test.js.map +1 -0
- package/dist/__tests__/doctor.test.js +21 -2
- package/dist/__tests__/doctor.test.js.map +1 -1
- package/dist/__tests__/dream-poll.test.d.ts +1 -0
- package/dist/__tests__/dream-poll.test.js +130 -0
- package/dist/__tests__/dream-poll.test.js.map +1 -0
- package/dist/__tests__/enable-key-auth.test.d.ts +1 -0
- package/dist/__tests__/enable-key-auth.test.js +180 -0
- package/dist/__tests__/enable-key-auth.test.js.map +1 -0
- package/dist/__tests__/existing-hashes.test.js +3 -6
- package/dist/__tests__/existing-hashes.test.js.map +1 -1
- package/dist/__tests__/full-context-view-forwarding.test.js +20 -1
- package/dist/__tests__/full-context-view-forwarding.test.js.map +1 -1
- package/dist/__tests__/hooks.test.d.ts +1 -0
- package/dist/__tests__/hooks.test.js +455 -0
- package/dist/__tests__/hooks.test.js.map +1 -0
- package/dist/__tests__/hydration.test.js +2 -0
- package/dist/__tests__/hydration.test.js.map +1 -1
- package/dist/__tests__/install.test.js +28 -1
- package/dist/__tests__/install.test.js.map +1 -1
- package/dist/__tests__/invite-accept.test.js +167 -3
- package/dist/__tests__/invite-accept.test.js.map +1 -1
- package/dist/__tests__/list-all-agents.test.js +17 -15
- package/dist/__tests__/list-all-agents.test.js.map +1 -1
- package/dist/__tests__/mcp-instructions.test.d.ts +1 -0
- package/dist/__tests__/mcp-instructions.test.js +26 -0
- package/dist/__tests__/mcp-instructions.test.js.map +1 -0
- package/dist/__tests__/mcp-tools.test.js +65 -0
- package/dist/__tests__/mcp-tools.test.js.map +1 -1
- package/dist/__tests__/memory-export.test.d.ts +1 -0
- package/dist/__tests__/memory-export.test.js +78 -0
- package/dist/__tests__/memory-export.test.js.map +1 -0
- package/dist/__tests__/owner-credentials.test.d.ts +1 -0
- package/dist/__tests__/owner-credentials.test.js +250 -0
- package/dist/__tests__/owner-credentials.test.js.map +1 -0
- package/dist/__tests__/owner-keychain-agent-load.test.d.ts +1 -0
- package/dist/__tests__/owner-keychain-agent-load.test.js +57 -0
- package/dist/__tests__/owner-keychain-agent-load.test.js.map +1 -0
- package/dist/__tests__/recall-order-by.test.d.ts +1 -0
- package/dist/__tests__/recall-order-by.test.js +115 -0
- package/dist/__tests__/recall-order-by.test.js.map +1 -0
- package/dist/__tests__/remember-duplicate-truth.test.js +11 -0
- package/dist/__tests__/remember-duplicate-truth.test.js.map +1 -1
- package/dist/__tests__/resolve-agent-preference.test.js +19 -8
- package/dist/__tests__/resolve-agent-preference.test.js.map +1 -1
- package/dist/__tests__/signin-keychain.test.d.ts +1 -0
- package/dist/__tests__/signin-keychain.test.js +79 -0
- package/dist/__tests__/signin-keychain.test.js.map +1 -0
- package/dist/__tests__/startup-identity.test.d.ts +1 -0
- package/dist/__tests__/startup-identity.test.js +213 -0
- package/dist/__tests__/startup-identity.test.js.map +1 -0
- package/dist/__tests__/sync-auth.test.d.ts +1 -0
- package/dist/__tests__/sync-auth.test.js +69 -0
- package/dist/__tests__/sync-auth.test.js.map +1 -0
- package/dist/__tests__/sync-doc.test.d.ts +1 -0
- package/dist/__tests__/sync-doc.test.js +13 -0
- package/dist/__tests__/sync-doc.test.js.map +1 -0
- package/dist/__tests__/sync-memory-cli.test.js +1 -1
- package/dist/__tests__/sync-memory-cli.test.js.map +1 -1
- package/dist/__tests__/tool-args.test.js +6 -0
- package/dist/__tests__/tool-args.test.js.map +1 -1
- package/dist/agent-key-mode.js +22 -22
- package/dist/agent-key-mode.js.map +1 -1
- package/dist/agent-preference.d.ts +4 -0
- package/dist/agent-preference.js +7 -1
- package/dist/agent-preference.js.map +1 -1
- package/dist/ais-http-error.d.ts +5 -0
- package/dist/ais-http-error.js +10 -0
- package/dist/ais-http-error.js.map +1 -1
- package/dist/ais-http.js +8 -4
- package/dist/ais-http.js.map +1 -1
- package/dist/auto-handoff.js +2 -1
- package/dist/auto-handoff.js.map +1 -1
- package/dist/cli/doctor.d.ts +8 -0
- package/dist/cli/doctor.js +19 -0
- package/dist/cli/doctor.js.map +1 -1
- package/dist/cli/enable-key-auth.js +39 -18
- package/dist/cli/enable-key-auth.js.map +1 -1
- package/dist/cli/export-harness.d.ts +13 -0
- package/dist/cli/export-harness.js +110 -0
- package/dist/cli/export-harness.js.map +1 -0
- package/dist/cli/hooks.d.ts +62 -0
- package/dist/cli/hooks.js +634 -0
- package/dist/cli/hooks.js.map +1 -0
- package/dist/cli/install.d.ts +4 -0
- package/dist/cli/install.js +44 -5
- package/dist/cli/install.js.map +1 -1
- package/dist/cli/invite-accept.d.ts +36 -1
- package/dist/cli/invite-accept.js +135 -1
- package/dist/cli/invite-accept.js.map +1 -1
- package/dist/cli/owner-credentials.d.ts +52 -0
- package/dist/cli/owner-credentials.js +387 -0
- package/dist/cli/owner-credentials.js.map +1 -0
- package/dist/cli/sync-memory.js +7 -9
- package/dist/cli/sync-memory.js.map +1 -1
- package/dist/cli-info.js +6 -1
- package/dist/cli-info.js.map +1 -1
- package/dist/credential-expiry.d.ts +10 -0
- package/dist/credential-expiry.js +41 -0
- package/dist/credential-expiry.js.map +1 -0
- package/dist/declared-agent.d.ts +20 -0
- package/dist/declared-agent.js +40 -0
- package/dist/declared-agent.js.map +1 -0
- package/dist/device-poll.d.ts +1 -0
- package/dist/device-poll.js.map +1 -1
- package/dist/dream-poll.d.ts +19 -0
- package/dist/dream-poll.js +93 -0
- package/dist/dream-poll.js.map +1 -0
- package/dist/env-agent.d.ts +6 -1
- package/dist/env-agent.js +18 -5
- package/dist/env-agent.js.map +1 -1
- package/dist/hydration.js +2 -1
- package/dist/hydration.js.map +1 -1
- package/dist/index.js +124 -16
- package/dist/index.js.map +1 -1
- package/dist/key-auth.d.ts +13 -3
- package/dist/key-auth.js +27 -5
- package/dist/key-auth.js.map +1 -1
- package/dist/mcp/tools.js +37 -20
- package/dist/mcp/tools.js.map +1 -1
- package/dist/mcp-instructions.d.ts +6 -0
- package/dist/mcp-instructions.js +7 -0
- package/dist/mcp-instructions.js.map +1 -0
- package/dist/memory-export.d.ts +30 -0
- package/dist/memory-export.js +116 -0
- package/dist/memory-export.js.map +1 -0
- package/dist/pipeline/bulk-store.d.ts +2 -5
- package/dist/pipeline/bulk-store.js +2 -4
- package/dist/pipeline/bulk-store.js.map +1 -1
- package/dist/pipeline/existing-hashes.d.ts +2 -5
- package/dist/pipeline/existing-hashes.js +1 -2
- package/dist/pipeline/existing-hashes.js.map +1 -1
- package/dist/pipeline/sync-auth.d.ts +12 -0
- package/dist/pipeline/sync-auth.js +64 -0
- package/dist/pipeline/sync-auth.js.map +1 -0
- package/dist/refresh.js +2 -1
- package/dist/refresh.js.map +1 -1
- package/dist/run-pass-mode.js +8 -13
- package/dist/run-pass-mode.js.map +1 -1
- package/dist/signin-keychain.d.ts +54 -0
- package/dist/signin-keychain.js +200 -0
- package/dist/signin-keychain.js.map +1 -0
- package/dist/startup-identity.d.ts +71 -0
- package/dist/startup-identity.js +213 -0
- package/dist/startup-identity.js.map +1 -0
- package/dist/tool-args.d.ts +10 -0
- package/dist/tool-args.js +39 -0
- package/dist/tool-args.js.map +1 -1
- package/dist/types.d.ts +8 -0
- package/dist/workspace-key-mode.js +19 -19
- package/dist/workspace-key-mode.js.map +1 -1
- package/package.json +1 -1
package/dist/device-poll.d.ts
CHANGED
package/dist/device-poll.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"device-poll.js","sourceRoot":"","sources":["../src/device-poll.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,gFAAgF;AAChF,MAAM,CAAC,MAAM,qBAAqB,GAAG,MAAM,CAAC;AAE5C,+EAA+E;AAC/E,MAAM,OAAO,wBAAyB,SAAQ,KAAK;IAG/B;IACA;IAHT,qBAAqB,GAAG,IAAI,CAAC;IACtC,YACkB,kBAA0B,EAC1B,WAAmB;QAEnC,KAAK,CACH,oDAAoD;YAClD,UAAU,kBAAkB,IAAI;YAChC,SAAS,WAAW,EAAE,CACzB,CAAC;QAPc,uBAAkB,GAAlB,kBAAkB,CAAQ;QAC1B,gBAAW,GAAX,WAAW,CAAQ;QAOnC,IAAI,CAAC,IAAI,GAAG,0BAA0B,CAAC;IACzC,CAAC;CACF;
|
|
1
|
+
{"version":3,"file":"device-poll.js","sourceRoot":"","sources":["../src/device-poll.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,gFAAgF;AAChF,MAAM,CAAC,MAAM,qBAAqB,GAAG,MAAM,CAAC;AAE5C,+EAA+E;AAC/E,MAAM,OAAO,wBAAyB,SAAQ,KAAK;IAG/B;IACA;IAHT,qBAAqB,GAAG,IAAI,CAAC;IACtC,YACkB,kBAA0B,EAC1B,WAAmB;QAEnC,KAAK,CACH,oDAAoD;YAClD,UAAU,kBAAkB,IAAI;YAChC,SAAS,WAAW,EAAE,CACzB,CAAC;QAPc,uBAAkB,GAAlB,kBAAkB,CAAQ;QAC1B,gBAAW,GAAX,WAAW,CAAQ;QAOnC,IAAI,CAAC,IAAI,GAAG,0BAA0B,CAAC;IACzC,CAAC;CACF;AA6BD;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,MAAwB,EACxB,IAAkB;IAElB,MAAM,EACJ,QAAQ,EACR,YAAY,EACZ,UAAU,EACV,KAAK,GAAG,GAAW,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,EAChC,cAAc,GAAG,KAAK,GACvB,GAAG,IAAI,CAAC;IAET,MAAM,QAAQ,GAAG,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,SAAS;IACpD,IAAI,eAAe,GAAG,CAAC,CAAC;IACxB,MAAM,WAAW,GAAG,MAAM,CAAC,WAAW,CAAC;IAEvC,OAAO,KAAK,EAAE,GAAG,QAAQ,EAAE,CAAC;QAC1B,MAAM,IAAI,OAAO,CAAO,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,cAAc,CAAC,CAAC,CAAC;QAE9D,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,WAAW,CAAC,CAAC;QAEzC,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;YACtB,OAAO,IAAI,CAAC;QACd,CAAC;QAED,IAAI,IAAI,CAAC,KAAK,KAAK,uBAAuB,EAAE,CAAC;YAC3C,sBAAsB;YACtB,MAAM,GAAG,GAAG,KAAK,EAAE,CAAC;YACpB,IAAI,GAAG,GAAG,eAAe,IAAI,qBAAqB,EAAE,CAAC;gBACnD,eAAe,GAAG,GAAG,CAAC;gBACtB,IAAI,IAAI,CAAC,cAAc,KAAK,WAAW,EAAE,CAAC;oBACxC,UAAU,CAAC,kDAAkD,CAAC,CAAC;gBACjE,CAAC;qBAAM,CAAC;oBACN,UAAU,CAAC,yBAAyB,CAAC,CAAC;gBACxC,CAAC;YACH,CAAC;YACD,SAAS;QACX,CAAC;QAED,IAAI,IAAI,CAAC,KAAK,KAAK,WAAW,EAAE,CAAC;YAC/B,MAAM,IAAI,OAAO,CAAO,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,cAAc,CAAC,CAAC,CAAC;YAC9D,SAAS;QACX,CAAC;QAED,IAAI,IAAI,CAAC,KAAK,KAAK,eAAe,EAAE,CAAC;YACnC,mEAAmE;YACnE,MAAM,OAAO,GAAG,MAAM,YAAY,EAAE,CAAC;YACrC,MAAM,IAAI,wBAAwB,CAChC,OAAO,CAAC,yBAAyB,EACjC,OAAO,CAAC,SAAS,CAClB,CAAC;QACJ,CAAC;QAED,IAAI,IAAI,CAAC,KAAK,KAAK,eAAe,EAAE,CAAC;YACnC,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;QAClD,CAAC;QAED,sCAAsC;QACtC,MAAM,IAAI,KAAK,CAAC,6BAA6B,IAAI,CAAC,KAAK,IAAI,kBAAkB,EAAE,CAAC,CAAC;IACnF,CAAC;IAED,MAAM,IAAI,KAAK,CAAC,0BAA0B,CAAC,CAAC;AAC9C,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export declare const DEFAULT_DREAM_POLL_MS = 120000;
|
|
2
|
+
export declare const DEFAULT_DREAM_POLL_INTERVAL_MS = 2000;
|
|
3
|
+
export declare function getDreamPollMs(env?: Record<string, string | undefined>): number;
|
|
4
|
+
export declare function getDreamPollIntervalMs(env?: Record<string, string | undefined>): number;
|
|
5
|
+
export interface DreamPollOptions {
|
|
6
|
+
/** GET /v1/agents/:agentId/dream/:runId through the caller's own auth mode. */
|
|
7
|
+
getStatus: (runId: string) => Promise<unknown>;
|
|
8
|
+
deadlineMs?: number;
|
|
9
|
+
intervalMs?: number;
|
|
10
|
+
sleep?: (ms: number) => Promise<void>;
|
|
11
|
+
now?: () => number;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Resolve a dream POST response. A finished (old synchronous) response is
|
|
15
|
+
* returned untouched. A 202 is polled to completion: completed/partial return
|
|
16
|
+
* {success:true, data:<run>}, failed throws with the server's error text, and
|
|
17
|
+
* a spent deadline returns a non-error "still running" result.
|
|
18
|
+
*/
|
|
19
|
+
export declare function resolveDreamResponse(response: unknown, opts: DreamPollOptions): Promise<unknown>;
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Async dream handling (CORBOT-F88FD791). A dream cycle can outlast the 20 s
|
|
3
|
+
* per-request cap, so the server answers POST /dream either with the finished
|
|
4
|
+
* run (200, the original shape) or, when the run is still going, 202 with
|
|
5
|
+
* {runId, status:'running', pollUrl}. This module turns the 202 back into the
|
|
6
|
+
* synchronous result by polling GET /dream/:runId, so callers see one shape.
|
|
7
|
+
*
|
|
8
|
+
* The overall wait is AIS_DREAM_POLL_MS (default 120000) and is separate from
|
|
9
|
+
* AIS_MCP_REQUEST_TIMEOUT_MS: every poll GET still carries the per-request cap.
|
|
10
|
+
*/
|
|
11
|
+
import { isAisRequestTimeout, AisRequestTimeoutError } from './request-timeout.js';
|
|
12
|
+
export const DEFAULT_DREAM_POLL_MS = 120_000;
|
|
13
|
+
export const DEFAULT_DREAM_POLL_INTERVAL_MS = 2_000;
|
|
14
|
+
function positiveEnvMs(raw, fallback) {
|
|
15
|
+
const parsed = Number(raw?.trim());
|
|
16
|
+
return raw !== undefined && raw.trim() !== '' && Number.isFinite(parsed) && parsed > 0
|
|
17
|
+
? parsed
|
|
18
|
+
: fallback;
|
|
19
|
+
}
|
|
20
|
+
export function getDreamPollMs(env = process.env) {
|
|
21
|
+
return positiveEnvMs(env['AIS_DREAM_POLL_MS'], DEFAULT_DREAM_POLL_MS);
|
|
22
|
+
}
|
|
23
|
+
export function getDreamPollIntervalMs(env = process.env) {
|
|
24
|
+
return positiveEnvMs(env['AIS_DREAM_POLL_INTERVAL_MS'], DEFAULT_DREAM_POLL_INTERVAL_MS);
|
|
25
|
+
}
|
|
26
|
+
function asRecord(value) {
|
|
27
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value)
|
|
28
|
+
? value
|
|
29
|
+
: null;
|
|
30
|
+
}
|
|
31
|
+
/** The accepted-but-unfinished body of a 202, or null for a finished (200) result. */
|
|
32
|
+
function acceptedRun(response) {
|
|
33
|
+
const data = asRecord(asRecord(response)?.['data']);
|
|
34
|
+
if (data === null)
|
|
35
|
+
return null;
|
|
36
|
+
const runId = data['runId'];
|
|
37
|
+
if (data['status'] === 'running' && typeof runId === 'string' && runId !== '') {
|
|
38
|
+
return { runId };
|
|
39
|
+
}
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
function stillRunning(runId) {
|
|
43
|
+
return {
|
|
44
|
+
success: true,
|
|
45
|
+
data: {
|
|
46
|
+
runId,
|
|
47
|
+
status: 'running',
|
|
48
|
+
message: `Dream run ${runId} is still running on the server; it will finish on its own. ` +
|
|
49
|
+
'Calling dream again while it is active returns this same run; once it has finished, a new call starts a fresh cycle.',
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Resolve a dream POST response. A finished (old synchronous) response is
|
|
55
|
+
* returned untouched. A 202 is polled to completion: completed/partial return
|
|
56
|
+
* {success:true, data:<run>}, failed throws with the server's error text, and
|
|
57
|
+
* a spent deadline returns a non-error "still running" result.
|
|
58
|
+
*/
|
|
59
|
+
export async function resolveDreamResponse(response, opts) {
|
|
60
|
+
const accepted = acceptedRun(response);
|
|
61
|
+
if (accepted === null)
|
|
62
|
+
return response;
|
|
63
|
+
const { runId } = accepted;
|
|
64
|
+
const now = opts.now ?? Date.now;
|
|
65
|
+
const sleep = opts.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
|
|
66
|
+
const intervalMs = opts.intervalMs ?? getDreamPollIntervalMs();
|
|
67
|
+
const deadline = now() + (opts.deadlineMs ?? getDreamPollMs());
|
|
68
|
+
while (now() < deadline) {
|
|
69
|
+
await sleep(Math.min(intervalMs, Math.max(0, deadline - now())));
|
|
70
|
+
let status;
|
|
71
|
+
try {
|
|
72
|
+
status = await opts.getStatus(runId);
|
|
73
|
+
}
|
|
74
|
+
catch (err) {
|
|
75
|
+
// A single slow poll is not a failed run; keep waiting until the deadline.
|
|
76
|
+
if (isAisRequestTimeout(err) || err instanceof AisRequestTimeoutError)
|
|
77
|
+
continue;
|
|
78
|
+
throw err;
|
|
79
|
+
}
|
|
80
|
+
const run = asRecord(asRecord(status)?.['data']);
|
|
81
|
+
const state = run?.['status'];
|
|
82
|
+
if (run === null)
|
|
83
|
+
continue;
|
|
84
|
+
if (state === 'completed' || state === 'partial')
|
|
85
|
+
return { success: true, data: run };
|
|
86
|
+
if (state === 'failed') {
|
|
87
|
+
const detail = typeof run['error'] === 'string' && run['error'] !== '' ? run['error'] : 'no error text';
|
|
88
|
+
throw new Error(`Dream run ${runId} failed: ${detail}`);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return stillRunning(runId);
|
|
92
|
+
}
|
|
93
|
+
//# sourceMappingURL=dream-poll.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dream-poll.js","sourceRoot":"","sources":["../src/dream-poll.ts"],"names":[],"mappings":"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"}
|
package/dist/env-agent.d.ts
CHANGED
|
@@ -8,6 +8,10 @@ export interface TenantAgentSummary {
|
|
|
8
8
|
* Throws with a message suitable for stderr when the id is missing or unknown.
|
|
9
9
|
*/
|
|
10
10
|
export declare function assertEnvAgentInTenant(envAgentId: string, agents: TenantAgentSummary[]): TenantAgentSummary;
|
|
11
|
+
/** AIS_AGENT_NAME names no agent, or more than one, in the tenant (CORBOT-C1A01EB3). */
|
|
12
|
+
export declare class EnvAgentNameError extends Error {
|
|
13
|
+
constructor(message: string);
|
|
14
|
+
}
|
|
11
15
|
export interface AgentSelection {
|
|
12
16
|
agentId: string;
|
|
13
17
|
reason: 'env-name' | 'preferred' | 'first-active' | 'fallback';
|
|
@@ -17,7 +21,8 @@ export interface AgentSelection {
|
|
|
17
21
|
/**
|
|
18
22
|
* Pick which agent this session connects to (CORBOT-B0FA4A79).
|
|
19
23
|
*
|
|
20
|
-
* Priority: AIS_AGENT_NAME match
|
|
24
|
+
* Priority: AIS_AGENT_NAME match (throws EnvAgentNameError on no match or
|
|
25
|
+
* several) > previously bonded agent > first active >
|
|
21
26
|
* fallback (fresh provisional agent when the tenant has none). The bonded
|
|
22
27
|
* preference is the load-bearing part: without it, a re-auth reconnected a
|
|
23
28
|
* multi-agent user to whichever agent the server listed first — a different
|
package/dist/env-agent.js
CHANGED
|
@@ -11,10 +11,18 @@ export function assertEnvAgentInTenant(envAgentId, agents) {
|
|
|
11
11
|
throw new Error(`AIS_AGENT_ID="${envAgentId}" is not a valid agent in this tenant. ` +
|
|
12
12
|
`Available: ${available || '(none)'}`);
|
|
13
13
|
}
|
|
14
|
+
/** AIS_AGENT_NAME names no agent, or more than one, in the tenant (CORBOT-C1A01EB3). */
|
|
15
|
+
export class EnvAgentNameError extends Error {
|
|
16
|
+
constructor(message) {
|
|
17
|
+
super(message);
|
|
18
|
+
this.name = 'EnvAgentNameError';
|
|
19
|
+
}
|
|
20
|
+
}
|
|
14
21
|
/**
|
|
15
22
|
* Pick which agent this session connects to (CORBOT-B0FA4A79).
|
|
16
23
|
*
|
|
17
|
-
* Priority: AIS_AGENT_NAME match
|
|
24
|
+
* Priority: AIS_AGENT_NAME match (throws EnvAgentNameError on no match or
|
|
25
|
+
* several) > previously bonded agent > first active >
|
|
18
26
|
* fallback (fresh provisional agent when the tenant has none). The bonded
|
|
19
27
|
* preference is the load-bearing part: without it, a re-auth reconnected a
|
|
20
28
|
* multi-agent user to whichever agent the server listed first — a different
|
|
@@ -29,11 +37,16 @@ export function selectAgentForSession(opts) {
|
|
|
29
37
|
return { agentId: opts.fallbackAgentId, reason: 'fallback', notes };
|
|
30
38
|
}
|
|
31
39
|
if (opts.envAgentName) {
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
-
|
|
40
|
+
const wanted = opts.envAgentName.toLowerCase();
|
|
41
|
+
const matches = opts.agents.filter((a) => a.name.toLowerCase() === wanted);
|
|
42
|
+
if (matches.length === 1) {
|
|
43
|
+
return { agentId: matches[0].id, reason: 'env-name', notes };
|
|
44
|
+
}
|
|
45
|
+
// An explicit name asks for one identity: never connect as a different agent.
|
|
46
|
+
if (matches.length === 0) {
|
|
47
|
+
throw new EnvAgentNameError(`AIS_AGENT_NAME="${opts.envAgentName}" matches no agent. Available: ${opts.agents.map((a) => a.name).join(', ')}`);
|
|
35
48
|
}
|
|
36
|
-
|
|
49
|
+
throw new EnvAgentNameError(`AIS_AGENT_NAME="${opts.envAgentName}" matches ${matches.length} agents (${matches.map((a) => a.id).join(', ')}). Set AIS_AGENT_ID to the one this session should use.`);
|
|
37
50
|
}
|
|
38
51
|
if (opts.preferredAgentId) {
|
|
39
52
|
const match = opts.agents.find((a) => a.id === opts.preferredAgentId);
|
package/dist/env-agent.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"env-agent.js","sourceRoot":"","sources":["../src/env-agent.ts"],"names":[],"mappings":"AAMA;;;GAGG;AACH,MAAM,UAAU,sBAAsB,CACpC,UAAkB,EAClB,MAA4B;IAE5B,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,KAAK,UAAU,CAAC,CAAC;IAC9D,IAAI,KAAK,EAAE,CAAC;QACV,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,SAAS,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,GAAG,KAAK,CAAC,IAAI,KAAK,KAAK,CAAC,EAAE,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAClF,MAAM,IAAI,KAAK,CACb,iBAAiB,UAAU,yCAAyC;QAClE,cAAc,SAAS,IAAI,QAAQ,EAAE,CACxC,CAAC;AACJ,CAAC;AASD
|
|
1
|
+
{"version":3,"file":"env-agent.js","sourceRoot":"","sources":["../src/env-agent.ts"],"names":[],"mappings":"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"}
|
package/dist/hydration.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { getAisRequestTimeoutMs } from './request-timeout.js';
|
|
2
|
+
import { withDeclaredAgent } from './declared-agent.js';
|
|
2
3
|
const LOG_PREFIX = '[aismemory]';
|
|
3
4
|
function redactHydrationMessage(message) {
|
|
4
5
|
return message
|
|
@@ -29,7 +30,7 @@ export async function hydrateIdentity(aisUrl, agentId, token, memoriesLimit) {
|
|
|
29
30
|
try {
|
|
30
31
|
const query = memoriesLimit === undefined ? '' : `?memoriesLimit=${memoriesLimit}`;
|
|
31
32
|
const res = await fetch(`${aisUrl}/v1/agents/${agentId}/full-context${query}`, {
|
|
32
|
-
headers: { Authorization: `Bearer ${token}` },
|
|
33
|
+
headers: withDeclaredAgent({ Authorization: `Bearer ${token}` }),
|
|
33
34
|
signal: AbortSignal.timeout(getAisRequestTimeoutMs()),
|
|
34
35
|
});
|
|
35
36
|
if (!res.ok) {
|
package/dist/hydration.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hydration.js","sourceRoot":"","sources":["../src/hydration.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"hydration.js","sourceRoot":"","sources":["../src/hydration.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -11,23 +11,25 @@ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
|
11
11
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
12
12
|
import { mkdirSync, writeFileSync } from 'node:fs';
|
|
13
13
|
import { join } from 'node:path';
|
|
14
|
-
import { tryKeyAuth, enrollKeyIfNeeded, hasEnrolledKey } from './key-auth.js';
|
|
14
|
+
import { tryKeyAuth, enrollKeyIfNeeded, formatAutoEnrollFailureStderr, hasEnrolledKey } from './key-auth.js';
|
|
15
15
|
import { isCredsStale, isNoRegisteredKeysAuthError } from './auth-staleness.js';
|
|
16
16
|
import { AisHttpError } from './ais-http-error.js';
|
|
17
17
|
import { aisGet, aisPost, DEFAULT_AIS_URL } from './ais-http.js';
|
|
18
18
|
import { CallToolRequestSchema, GetPromptRequestSchema, ListPromptsRequestSchema, ListToolsRequestSchema, } from '@modelcontextprotocol/sdk/types.js';
|
|
19
19
|
import { homedir } from 'node:os';
|
|
20
|
-
import { loadOAuthCredentials, loadNonStaleDiskBearer, saveOAuthCredentials, } from './oauth-credentials.js';
|
|
20
|
+
import { credentialsFilePath, loadOAuthCredentials, loadNonStaleDiskBearer, saveOAuthCredentials, } from './oauth-credentials.js';
|
|
21
21
|
import { clearPendingDeviceFlow, isResumableDeviceFlow, loadPendingDeviceFlow, savePendingDeviceFlow, } from './pending-device-flow.js';
|
|
22
22
|
import { saveAgentPreference, loadAgentPreference, migrateCredentialsFileIfNeeded } from './agent-preference.js';
|
|
23
|
+
import { credentialsFromOwnerKeychain, isSigninKeychainAvailable, ownerUserIdFromAccessToken, requireOwnerKeychainCredentials, saveOwnerSignInToKeychain, } from './signin-keychain.js';
|
|
23
24
|
import { createTokenManager, isNoRegisteredKeyFailure } from './token-manager.js';
|
|
24
25
|
import { hydrateIdentity } from './hydration.js';
|
|
25
26
|
import { assemblePrompt } from './prompt-resource.js';
|
|
26
27
|
import { startRefreshTimer, stopRefreshTimer } from './refresh.js';
|
|
27
28
|
import { ActivityTracker, setupAutoHandoff } from './auto-handoff.js';
|
|
28
|
-
import { assertEnvAgentInTenant, selectAgentForSession } from './env-agent.js';
|
|
29
|
+
import { assertEnvAgentInTenant, EnvAgentNameError, selectAgentForSession } from './env-agent.js';
|
|
29
30
|
import { emitTelemetry, hashAgentId } from './telemetry.js';
|
|
30
31
|
import { INBOX_MAX_BODY_CHARS, INBOX_MAX_TASK_ID_CHARS, INBOX_MIN_TTL_SECONDS, INBOX_MAX_TTL_SECONDS, INBOX_DEFAULT_TTL_SECONDS, INBOX_MAX_PAGE_SIZE, INBOX_DEFAULT_PAGE_SIZE, INBOX_MAX_ACK_IDS, GOAL_MAX_TITLE_CHARS, GOAL_MAX_DESCRIPTION_CHARS, GOAL_MAX_CRITERIA_ITEMS, GOAL_DEFAULT_PAGE_SIZE, GOAL_MAX_PAGE_SIZE, } from './tool-args.js';
|
|
32
|
+
import { setDeclaredAgentSource } from './declared-agent.js';
|
|
31
33
|
import { identityCredentialFingerprint, loadSessionIdentity, verifyPinnedIdentity } from './session-identity.js';
|
|
32
34
|
import { runPollLoop, DeviceFlowRestartedError } from './device-poll.js';
|
|
33
35
|
import { loadAgentApiKeyConfig, AgentApiKeyConfigError, } from './agent-key-mode.js';
|
|
@@ -35,7 +37,9 @@ import { loadWorkspaceKeyConfig, WorkspaceKeyConfigError, } from './workspace-ke
|
|
|
35
37
|
import { loadRunPassConfig, RunPassConfigError, } from './run-pass-mode.js';
|
|
36
38
|
import { createAgentKeyCallToolHandler, createOAuthCallToolHandler, createRunPassCallToolHandler, createWorkspaceKeyCallToolHandler, } from './mcp/tools.js';
|
|
37
39
|
import { readPackageVersion, startVersionCheck } from './version-check.js';
|
|
40
|
+
import { AIS_MCP_INSTRUCTIONS } from './mcp-instructions.js';
|
|
38
41
|
import { HUMAN_HOWTO_TEXT, resolveInfoRequest } from './cli-info.js';
|
|
42
|
+
import { describeStartupIdentity, findDuplicateServerNames, formatDuplicateServerWarning, formatStartupIdentityLine, setServerNameConflicts, setStartupIdentity, } from './startup-identity.js';
|
|
39
43
|
import { AGENT_ARCHIVE_DESCRIPTION, AGENT_ARCHIVE_INPUT_SCHEMA, AGENT_DELETE_ALIAS_DESCRIPTION } from './agent-archive.js';
|
|
40
44
|
// ── Config ──────────────────────────────────────────────
|
|
41
45
|
const AIS_URL = process.env['AIS_URL']?.trim() || DEFAULT_AIS_URL;
|
|
@@ -52,8 +56,12 @@ function loadCredentials() {
|
|
|
52
56
|
// owns the live session and this v1 disk bearer must never be treated
|
|
53
57
|
// as it (F4) — see the hasEnrolledKey() guard at the bottom of main().
|
|
54
58
|
migrateCredentialsFileIfNeeded();
|
|
59
|
+
const pref = loadAgentPreference();
|
|
60
|
+
const fromKeychain = pref ? credentialsFromOwnerKeychain(AIS_URL, pref) : null;
|
|
61
|
+
if (fromKeychain)
|
|
62
|
+
return fromKeychain;
|
|
55
63
|
const data = loadOAuthCredentials();
|
|
56
|
-
if (!data)
|
|
64
|
+
if (!data?.token)
|
|
57
65
|
return null;
|
|
58
66
|
if (isCredsStale(data.expiresAt, Date.now())) {
|
|
59
67
|
stderr('Saved credentials expired or expiring soon. Re-authenticating...');
|
|
@@ -65,6 +73,23 @@ function loadCredentials() {
|
|
|
65
73
|
function stderr(msg) {
|
|
66
74
|
process.stderr.write(`[aismemory] ${msg}\n`);
|
|
67
75
|
}
|
|
76
|
+
/**
|
|
77
|
+
* CORBOT-5D16CF2A: one stderr line naming the client version, the agent and
|
|
78
|
+
* where its credential comes from, so version drift and a shadowed config
|
|
79
|
+
* entry are visible at startup. Also kept for whoami. Never prints a value.
|
|
80
|
+
*/
|
|
81
|
+
function reportStartupIdentity(input) {
|
|
82
|
+
const identity = describeStartupIdentity(PACKAGE_VERSION, input);
|
|
83
|
+
setStartupIdentity(identity);
|
|
84
|
+
stderr(formatStartupIdentityLine(identity));
|
|
85
|
+
}
|
|
86
|
+
/** CORBOT-5D16CF2A: warn when the launching config defines this server name in several scopes. */
|
|
87
|
+
function reportDuplicateServerNames() {
|
|
88
|
+
const conflicts = findDuplicateServerNames({ home: homedir(), cwd: process.cwd() });
|
|
89
|
+
setServerNameConflicts(conflicts);
|
|
90
|
+
for (const conflict of conflicts)
|
|
91
|
+
stderr(`Warning: ${formatDuplicateServerWarning(conflict)}`);
|
|
92
|
+
}
|
|
68
93
|
function rejectRunPassWithKeyEnv(env) {
|
|
69
94
|
if (env['AIS_RUN_PASS_FILE'] === undefined)
|
|
70
95
|
return;
|
|
@@ -195,7 +220,11 @@ async function resolveAgent(token, fallbackAgentId, fallbackTenantId, preferredA
|
|
|
195
220
|
}
|
|
196
221
|
return { agentId: selection.agentId, tenantId: fallbackTenantId };
|
|
197
222
|
}
|
|
198
|
-
catch {
|
|
223
|
+
catch (error) {
|
|
224
|
+
if (error instanceof EnvAgentNameError) {
|
|
225
|
+
stderr(error.message);
|
|
226
|
+
throw error;
|
|
227
|
+
}
|
|
199
228
|
stderr(`Could not list agents. Using new agent: ${fallbackAgentId}`);
|
|
200
229
|
return { agentId: fallbackAgentId, tenantId: fallbackTenantId };
|
|
201
230
|
}
|
|
@@ -454,7 +483,35 @@ flowRef) {
|
|
|
454
483
|
// a regression versus 0.6.2, which always persisted the token and
|
|
455
484
|
// reconnected silently. migrateCredentialsFileIfNeeded() (agent-preference.ts)
|
|
456
485
|
// is what later removes this token from disk, once a key gets enrolled.
|
|
457
|
-
|
|
486
|
+
const refreshToken = pollResp.refresh_token;
|
|
487
|
+
const ownerUserId = ownerUserIdFromAccessToken(creds.token);
|
|
488
|
+
const keychainPersisted = !sessionIdentity &&
|
|
489
|
+
typeof refreshToken === 'string' &&
|
|
490
|
+
refreshToken.length > 0 &&
|
|
491
|
+
ownerUserId !== null &&
|
|
492
|
+
isSigninKeychainAvailable();
|
|
493
|
+
if (keychainPersisted) {
|
|
494
|
+
try {
|
|
495
|
+
saveOwnerSignInToKeychain({
|
|
496
|
+
aisUrl: AIS_URL,
|
|
497
|
+
accessToken: creds.token,
|
|
498
|
+
refreshToken,
|
|
499
|
+
expiresAt: creds.expiresAt,
|
|
500
|
+
});
|
|
501
|
+
saveAgentPreference({ agentId: creds.agentId, tenantId: creds.tenantId, ownerUserId });
|
|
502
|
+
}
|
|
503
|
+
catch (err) {
|
|
504
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
505
|
+
stderr(`Could not store owner sign-in in the OS keychain (${message}); saving to disk instead.`);
|
|
506
|
+
if (hasEnrolledKey()) {
|
|
507
|
+
saveAgentPreference({ agentId: creds.agentId, tenantId: creds.tenantId, ownerUserId });
|
|
508
|
+
}
|
|
509
|
+
else {
|
|
510
|
+
saveOAuthCredentials(creds);
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
else if (hasEnrolledKey()) {
|
|
458
515
|
if (!sessionIdentity)
|
|
459
516
|
saveAgentPreference({ agentId: creds.agentId, tenantId: creds.tenantId });
|
|
460
517
|
}
|
|
@@ -486,6 +543,7 @@ const tools = [
|
|
|
486
543
|
type: { type: 'string', enum: ['fact', 'event', 'lesson', 'context', 'goal', 'task'], description: 'Memory type' },
|
|
487
544
|
importance: { type: 'number', minimum: 0, maximum: 1, description: 'Importance (0-1, default 0.5)' },
|
|
488
545
|
tags: { type: 'array', items: { type: 'string' }, description: 'Optional tags to filter on later, e.g. ["work", "acme"]. At most 20; each 1-64 characters of a-z 0-9 . _ : - (stored lower-case). Tags are a filter, not a permission — use separate agents to wall off e.g. work from personal.' },
|
|
546
|
+
supersedes: { type: 'string', description: 'Optional: the id of an older memory of yours that this one replaces (e.g. a lesson that turned out wrong). The old memory is kept but no longer returned by recall. Refused if that id is not one of your memories or is already superseded.' },
|
|
489
547
|
},
|
|
490
548
|
required: ['content'],
|
|
491
549
|
},
|
|
@@ -495,6 +553,7 @@ const tools = [
|
|
|
495
553
|
description: "Search memories by natural language query. Set principalAgentId to search a DIFFERENT " +
|
|
496
554
|
"agent's memories under a 'memory:read' grant from that agent's owner. " +
|
|
497
555
|
"Each memory carries createdAt, updatedAt (its last edit), and tags. " +
|
|
556
|
+
"Pass orderBy='newest' with type or tags to get the newest matching memories first. " +
|
|
498
557
|
"Memories superseded by a newer one are left out; to list or page through every memory, " +
|
|
499
558
|
"use the REST list route described in the aismemory README (cursor paging, sortBy=updatedAt, includeSuperseded=true)." + BOND_LINK_NOTE,
|
|
500
559
|
inputSchema: {
|
|
@@ -504,6 +563,7 @@ const tools = [
|
|
|
504
563
|
limit: { type: 'number', description: 'Max results (default 10)' },
|
|
505
564
|
type: { type: 'string', enum: ['fact', 'event', 'lesson', 'context', 'goal', 'task'], description: 'Filter by type' },
|
|
506
565
|
tags: { type: 'array', items: { type: 'string' }, description: 'Only memories carrying ALL of these tags. A hard filter: results are never widened past it.' },
|
|
566
|
+
orderBy: { type: 'string', enum: ['newest'], description: "Set 'newest' to list matching memories newest-first (createdAt descending) instead of ranking by meaning. Use it when you store near-duplicate memories, such as repeated task memories that differ by a counter, and need the latest one first. The query text is not used for ranking, and 'newest' needs type or tags. Default (omitted): ranked search, unchanged." },
|
|
507
567
|
principalAgentId: { type: 'string', description: "Optional: search ANOTHER agent's memories instead of your own (its agent UUID). Requires that agent's owner to have granted you the 'memory:read' scope and that you share a tenant; otherwise the call is refused with 403. Read-only — your own identity and write access are unchanged." },
|
|
508
568
|
},
|
|
509
569
|
required: ['query'],
|
|
@@ -554,12 +614,13 @@ const tools = [
|
|
|
554
614
|
memoriesLimit: { type: 'number', description: 'Number of memories to load (1-50, default 5). Lower values reduce context size. Governs recent memories only — on the full view that is a small share of the payload, so prefer view to bound the whole response.' },
|
|
555
615
|
view: { type: 'string', enum: ['full', 'lean', 'bootstrap'], description: "Which projection to load. 'full' (default) is everything the stores hold, bounded to 6000 tokens. 'lean' is continuity only — last handoff first, then recent memories. 'bootstrap' is lean plus goals and inbox, for starting a session in another harness. All three honour maxTokens." },
|
|
556
616
|
maxTokens: { type: 'number', description: 'Token ceiling (500-20000; default 6000 for full, 2000 for lean, 3000 for bootstrap). Content is evicted from the tail until the payload fits — assembled context sections, then facts, then goals, then recent memories on the full view — and each eviction is named in receipt.omitted. Identity, the operating layer and the last handoff are never dropped.' },
|
|
617
|
+
contextWindowSize: { type: 'number', description: "Your model's context window in tokens (1000-10000000). The skills budget scales with it; omit for the server default." },
|
|
557
618
|
},
|
|
558
619
|
},
|
|
559
620
|
},
|
|
560
621
|
{
|
|
561
622
|
name: 'dream',
|
|
562
|
-
description: 'Trigger a memory consolidation dream cycle — promotes important memories and archives old ones. Promotion only scans the session tier; active-tier memories move via context-clear or handoff, not dream.',
|
|
623
|
+
description: 'Trigger a memory consolidation dream cycle — promotes important memories and archives old ones. Promotion only scans the session tier; active-tier memories move via context-clear or handoff, not dream. A long cycle runs server-side; the call waits up to AIS_DREAM_POLL_MS (default 120 s) and, if still running, returns status "running" with the runId — the run keeps going on the server; calling dream again while it is active returns the same runId.',
|
|
563
624
|
inputSchema: { type: 'object', properties: {} },
|
|
564
625
|
},
|
|
565
626
|
{
|
|
@@ -807,7 +868,7 @@ async function runWorkspaceKeyModeServer(config) {
|
|
|
807
868
|
// Mutable copy so agent_load can switch the active agent.
|
|
808
869
|
let activeConfig = { ...config };
|
|
809
870
|
stderr(`Workspace key auth mode — agent starts at ${activeConfig.agentId} (agent_load can switch).`);
|
|
810
|
-
const server = new Server({ name: 'aismemory', version: PACKAGE_VERSION }, { capabilities: { tools: {}, prompts: {} } });
|
|
871
|
+
const server = new Server({ name: 'aismemory', version: PACKAGE_VERSION }, { capabilities: { tools: {}, prompts: {} }, instructions: AIS_MCP_INSTRUCTIONS });
|
|
811
872
|
server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools }));
|
|
812
873
|
server.setRequestHandler(ListPromptsRequestSchema, async () => ({ prompts: [] }));
|
|
813
874
|
server.setRequestHandler(GetPromptRequestSchema, async (request) => {
|
|
@@ -834,7 +895,7 @@ async function runWorkspaceKeyModeServer(config) {
|
|
|
834
895
|
*/
|
|
835
896
|
async function runPassModeServer(config) {
|
|
836
897
|
stderr(`Run-pass auth mode — agent fixed to ${config.agentId}; pass file ${config.runPassFile}`);
|
|
837
|
-
const server = new Server({ name: 'aismemory', version: PACKAGE_VERSION }, { capabilities: { tools: {}, prompts: {} } });
|
|
898
|
+
const server = new Server({ name: 'aismemory', version: PACKAGE_VERSION }, { capabilities: { tools: {}, prompts: {} }, instructions: AIS_MCP_INSTRUCTIONS });
|
|
838
899
|
server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools }));
|
|
839
900
|
server.setRequestHandler(ListPromptsRequestSchema, async () => ({ prompts: [] }));
|
|
840
901
|
server.setRequestHandler(GetPromptRequestSchema, async (request) => {
|
|
@@ -863,7 +924,7 @@ async function runPassModeServer(config) {
|
|
|
863
924
|
*/
|
|
864
925
|
async function runAgentKeyModeServer(config) {
|
|
865
926
|
stderr(`Agent API key auth mode — agent fixed to ${config.agentId} (no device flow, no DID key-auth).`);
|
|
866
|
-
const server = new Server({ name: 'aismemory', version: PACKAGE_VERSION }, { capabilities: { tools: {}, prompts: {} } });
|
|
927
|
+
const server = new Server({ name: 'aismemory', version: PACKAGE_VERSION }, { capabilities: { tools: {}, prompts: {} }, instructions: AIS_MCP_INSTRUCTIONS });
|
|
867
928
|
server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools }));
|
|
868
929
|
server.setRequestHandler(ListPromptsRequestSchema, async () => ({ prompts: [] }));
|
|
869
930
|
server.setRequestHandler(GetPromptRequestSchema, async (request) => {
|
|
@@ -891,6 +952,10 @@ async function main() {
|
|
|
891
952
|
(await import('./cli/install.js')).main(process.argv.slice(3));
|
|
892
953
|
return;
|
|
893
954
|
}
|
|
955
|
+
if (process.argv[2] === 'hooks') {
|
|
956
|
+
await (await import('./cli/hooks.js')).main(process.argv.slice(3));
|
|
957
|
+
return; // hook commands fail open and set process.exitCode themselves
|
|
958
|
+
}
|
|
894
959
|
if (process.argv[2] === 'enable-key-auth') {
|
|
895
960
|
await import('./cli/enable-key-auth.js');
|
|
896
961
|
return; // CLI calls process.exit() itself
|
|
@@ -907,10 +972,19 @@ async function main() {
|
|
|
907
972
|
await (await import('./cli/pull-memory.js')).main(process.argv.slice(3));
|
|
908
973
|
return;
|
|
909
974
|
}
|
|
975
|
+
if (process.argv[2] === 'export-harness') {
|
|
976
|
+
await (await import('./cli/export-harness.js')).main(process.argv.slice(3));
|
|
977
|
+
return;
|
|
978
|
+
}
|
|
910
979
|
if (process.argv[2] === 'invite') {
|
|
911
980
|
await (await import('./cli/invite-accept.js')).runFromCli(process.argv.slice(3));
|
|
912
981
|
return;
|
|
913
982
|
}
|
|
983
|
+
const ownerCommand = process.argv[2];
|
|
984
|
+
if (ownerCommand === 'rotate-token' || ownerCommand === 'api-keys' || ownerCommand === 'agents') {
|
|
985
|
+
await (await import('./cli/owner-credentials.js')).runFromCli(ownerCommand, process.argv.slice(3));
|
|
986
|
+
return;
|
|
987
|
+
}
|
|
914
988
|
// CORBOT-73753A98: a person at a terminal gets a how-to; MCP clients pipe stdin and see nothing new.
|
|
915
989
|
const humanAtTerminal = process.stdin.isTTY === true;
|
|
916
990
|
if (humanAtTerminal) {
|
|
@@ -921,7 +995,9 @@ async function main() {
|
|
|
921
995
|
// not wait on a third-party registry, and the answer is only needed later,
|
|
922
996
|
// when whoami or full_context is called. Resolves to a skip when offline.
|
|
923
997
|
void startVersionCheck({ currentVersion: PACKAGE_VERSION, onUpdateAvailable: stderr });
|
|
998
|
+
reportDuplicateServerNames();
|
|
924
999
|
sessionIdentity = loadSessionIdentity();
|
|
1000
|
+
setDeclaredAgentSource(() => sessionIdentity?.agentId);
|
|
925
1001
|
const adapterEnv = { ...process.env, AIS_AGENT_ID: sessionIdentity?.agentId };
|
|
926
1002
|
rejectRunPassWithKeyEnv(adapterEnv);
|
|
927
1003
|
// Explicit key auth modes keep their existing order when AIS_RUN_PASS_FILE is
|
|
@@ -939,6 +1015,7 @@ async function main() {
|
|
|
939
1015
|
throw err;
|
|
940
1016
|
}
|
|
941
1017
|
if (workspaceKeyConfig) {
|
|
1018
|
+
reportStartupIdentity({ kind: 'workspace-key', env: adapterEnv, agentId: workspaceKeyConfig.agentId });
|
|
942
1019
|
await runWorkspaceKeyModeServer(workspaceKeyConfig);
|
|
943
1020
|
return;
|
|
944
1021
|
}
|
|
@@ -958,6 +1035,7 @@ async function main() {
|
|
|
958
1035
|
throw err;
|
|
959
1036
|
}
|
|
960
1037
|
if (agentKeyConfig) {
|
|
1038
|
+
reportStartupIdentity({ kind: 'agent-api-key', env: adapterEnv, agentId: agentKeyConfig.agentId });
|
|
961
1039
|
await runAgentKeyModeServer(agentKeyConfig);
|
|
962
1040
|
return;
|
|
963
1041
|
}
|
|
@@ -975,6 +1053,7 @@ async function main() {
|
|
|
975
1053
|
throw err;
|
|
976
1054
|
}
|
|
977
1055
|
if (runPassConfig) {
|
|
1056
|
+
reportStartupIdentity({ kind: 'run-pass', runPassFile: runPassConfig.runPassFile, agentId: runPassConfig.agentId });
|
|
978
1057
|
await runPassModeServer(runPassConfig);
|
|
979
1058
|
return;
|
|
980
1059
|
}
|
|
@@ -987,6 +1066,17 @@ async function main() {
|
|
|
987
1066
|
// 401s NO_REGISTERED_KEYS but this bearer still works for REST memory.
|
|
988
1067
|
const diskBearerFallback = loadNonStaleDiskBearer();
|
|
989
1068
|
let creds = loadCredentials();
|
|
1069
|
+
const keyEnrolledAtStartup = hasEnrolledKey();
|
|
1070
|
+
const startupPreference = loadAgentPreference();
|
|
1071
|
+
reportStartupIdentity({
|
|
1072
|
+
kind: 'oauth',
|
|
1073
|
+
...(sessionIdentity ? { sessionAgentId: sessionIdentity.agentId } : {}),
|
|
1074
|
+
enrolledKeyDir: keyEnrolledAtStartup ? join(homedir(), '.aismemory', 'keys') : null,
|
|
1075
|
+
diskAgentId: creds?.agentId ?? null,
|
|
1076
|
+
credentialsFile: credentialsFilePath(),
|
|
1077
|
+
...(keyEnrolledAtStartup ? { preferredAgentId: startupPreference?.agentId } : {}),
|
|
1078
|
+
...(startupPreference?.ownerUserId ? { keychainOwnerSession: true } : {}),
|
|
1079
|
+
});
|
|
990
1080
|
let activeFlow = null;
|
|
991
1081
|
let postAuthDone = false;
|
|
992
1082
|
// Fires the auth.key.success telemetry event + the one-line stderr
|
|
@@ -1032,9 +1122,15 @@ async function main() {
|
|
|
1032
1122
|
resolveIdentity: async (token) => {
|
|
1033
1123
|
const claims = decodeJwtClaims(token);
|
|
1034
1124
|
const tenantId = claims.tenantId ?? '';
|
|
1035
|
-
const
|
|
1036
|
-
|
|
1037
|
-
|
|
1125
|
+
const pref = loadAgentPreference();
|
|
1126
|
+
const resolved = await resolveAgent(token, '', tenantId, pref?.agentId);
|
|
1127
|
+
if (!sessionIdentity) {
|
|
1128
|
+
saveAgentPreference({
|
|
1129
|
+
agentId: resolved.agentId,
|
|
1130
|
+
tenantId: resolved.tenantId || tenantId,
|
|
1131
|
+
...(pref?.ownerUserId ? { ownerUserId: pref.ownerUserId } : {}),
|
|
1132
|
+
});
|
|
1133
|
+
}
|
|
1038
1134
|
return { agentId: resolved.agentId, tenantId: resolved.tenantId || tenantId };
|
|
1039
1135
|
},
|
|
1040
1136
|
onEvent: (event, detail) => {
|
|
@@ -1046,7 +1142,7 @@ async function main() {
|
|
|
1046
1142
|
},
|
|
1047
1143
|
});
|
|
1048
1144
|
// Created here so `agent_load` and post-auth setup can reference it via closure.
|
|
1049
|
-
const server = new Server({ name: 'aismemory', version: PACKAGE_VERSION }, { capabilities: { tools: {}, prompts: {} } });
|
|
1145
|
+
const server = new Server({ name: 'aismemory', version: PACKAGE_VERSION }, { capabilities: { tools: {}, prompts: {} }, instructions: AIS_MCP_INSTRUCTIONS });
|
|
1050
1146
|
/**
|
|
1051
1147
|
* Wait briefly for the in-flight device-flow poll to complete. If the user
|
|
1052
1148
|
* has already approved, this returns the fresh credentials. If not, throws
|
|
@@ -1058,6 +1154,18 @@ async function main() {
|
|
|
1058
1154
|
* the next tool call without having to restart the MCP process.
|
|
1059
1155
|
*/
|
|
1060
1156
|
async function ensureCredentials(softTimeoutMs = 7000) {
|
|
1157
|
+
// CORBOT-EBCB2D2B: owner terminal sign-in uses the workspace credential
|
|
1158
|
+
// in the OS keychain (not the DID key or a stale disk bearer) so
|
|
1159
|
+
// agent_load can resolve agents by name via GET /v1/resolve.
|
|
1160
|
+
const ownerPref = loadAgentPreference();
|
|
1161
|
+
if (ownerPref?.ownerUserId) {
|
|
1162
|
+
creds = requireOwnerKeychainCredentials(AIS_URL, ownerPref, sessionAgentOverride?.agentId);
|
|
1163
|
+
if (!postAuthDone) {
|
|
1164
|
+
postAuthDone = true;
|
|
1165
|
+
void runPostAuth(creds);
|
|
1166
|
+
}
|
|
1167
|
+
return creds;
|
|
1168
|
+
}
|
|
1061
1169
|
// ── Key-enrolled path: all auth flows through the TokenManager ────────
|
|
1062
1170
|
// The manager owns authenticate + background renewal + backoff; on a
|
|
1063
1171
|
// sustained AIS outage it rejects with AisUnreachableError, which we let
|
|
@@ -1168,8 +1276,8 @@ async function main() {
|
|
|
1168
1276
|
stderr('DID key enrolled — future sessions re-authenticate silently (no re-bond)');
|
|
1169
1277
|
emitTelemetry({ event: 'auth.key.autoenroll', agentIdHash: hashAgentId(c.agentId), status: 'ok' });
|
|
1170
1278
|
}
|
|
1171
|
-
else if (enroll.reason.startsWith('register-failed')) {
|
|
1172
|
-
stderr(
|
|
1279
|
+
else if (enroll.reason.startsWith('register-failed') || enroll.reason.startsWith('register-refused')) {
|
|
1280
|
+
stderr(formatAutoEnrollFailureStderr(enroll.reason));
|
|
1173
1281
|
emitTelemetry({ event: 'auth.key.autoenroll', agentIdHash: hashAgentId(c.agentId), status: 'error', error: enroll.reason });
|
|
1174
1282
|
}
|
|
1175
1283
|
try {
|