@ai-ecoverse/slicc-agent 3.36.2 → 3.37.0
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 +56 -2
- package/dist/client.js +3 -1
- package/dist/client.js.map +2 -2
- package/dist/control.js +3 -1
- package/dist/control.js.map +2 -2
- package/dist/host.js +14 -3
- package/dist/host.js.map +2 -2
- package/dist/kernel/groups.js +6 -0
- package/dist/kernel/groups.js.map +2 -2
- package/dist/main.js +7 -1
- package/dist/main.js.map +2 -2
- package/dist/mcp/index.js +1 -0
- package/dist/mcp/index.js.map +2 -2
- package/dist/mcp/runtime.js +1 -0
- package/dist/mcp/runtime.js.map +2 -2
- package/dist/memory/format.js +8 -0
- package/dist/memory/format.js.map +2 -2
- package/dist/monitor/index.js +449 -0
- package/dist/monitor/index.js.map +7 -0
- package/dist/monitor/redact.js +25 -0
- package/dist/monitor/redact.js.map +7 -0
- package/dist/readonly.js +1 -1
- package/dist/readonly.js.map +2 -2
- package/dist/services.js.map +2 -2
- package/dist/spectrum/index.js +12 -1
- package/dist/spectrum/index.js.map +3 -3
- package/dist/spectrum/monitor-port.js +621 -0
- package/dist/spectrum/monitor-port.js.map +7 -0
- package/dist/spectrum/tray-port.js +0 -2
- package/dist/spectrum/tray-port.js.map +2 -2
- package/dist/types/client.d.ts +2 -1
- package/dist/types/control.d.ts +2 -1
- package/dist/types/host.d.ts +2 -0
- package/dist/types/kernel/groups.d.ts +1 -0
- package/dist/types/mcp/runtime.d.ts +1 -0
- package/dist/types/monitor/index.d.ts +67 -0
- package/dist/types/monitor/redact.d.ts +5 -0
- package/dist/types/services.d.ts +71 -0
- package/dist/types/spectrum/index.d.ts +7 -0
- package/dist/types/spectrum/monitor-port.d.ts +70 -0
- package/package.json +3 -3
package/dist/mcp/index.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/mcp/index.ts"],
|
|
4
|
-
"sourcesContent": ["import type { Context } from '@earendil-works/chord';\nimport type {\n Agent,\n Registry,\n ToolExecutionApi,\n ToolRegistration,\n} from '@earendil-works/pi-durable';\nimport type { CodemodeExtra } from './allow.ts';\nimport type { McpCatalog } from './catalog.ts';\nimport { parseMcpConfig } from './config.ts';\nimport type { McpAttach, McpRuntime } from './runtime.ts';\n\nexport { allows, type CodemodeExtra, McpAllowDoc, mcpEntries, serverAllowed } from './allow.ts';\nexport type { McpAccounts, McpAttach, McpRuntime, ServerStatus } from './runtime.ts';\n\nexport type McpLoader = () => Promise<typeof import('./runtime.ts')>;\n\nexport const loadRuntime: McpLoader = () => import('./runtime.ts');\n\nexport interface McpSetup {\n catalog(): McpCatalog | undefined;\n direct(names: readonly string[]): ToolRegistration[];\n codemode(api: ToolExecutionApi, agent: Agent, context: Context): Promise<CodemodeExtra>;\n attach(options: McpAttach, context: Context): Promise<McpRuntime>;\n}\n\nconst idle: McpRuntime = {\n accounts: async () => [],\n signIn: async (id) => {\n throw new Error(`${id} is not an MCP server that signs in`);\n },\n connect: async (id) => {\n throw new Error(`${id} is not an MCP server that takes a token`);\n },\n disconnect: async () => undefined,\n onChange: () => () => undefined,\n status: () => [],\n reload: async () => undefined,\n close: async () => undefined,\n};\n\nasync function unavailable(options: McpAttach, error: unknown, context: Context) {\n const file = `${options.home}/.pi/agent/mcp.json`;\n const read = await options.env.readTextFile(file, context);\n if (!parseMcpConfig(read.ok ? read.value : undefined).servers.length) return;\n await options.licks\n .deliver(\n {\n channel: 'fswatch',\n source: 'mcp:~/.pi/agent/mcp.json',\n title: \"MCP servers can't start in this SLICC\",\n text: error instanceof Error ? error.message : String(error),\n body: \"The MCP client didn't load, so the servers in ~/.pi/agent/mcp.json stay off until SLICC is updated.\",\n target: 'cone',\n severity: 'warn',\n eventId: 'mcp\\nunavailable',\n },\n context\n )\n .catch(() => undefined);\n}\n\nexport function setupMcp(registry: Registry, load: McpLoader = loadRuntime): McpSetup {\n let catalog: McpCatalog | undefined;\n return {\n catalog: () => catalog,\n direct: (names) => catalog?.direct(names) ?? [],\n codemode: async (api, agent, context) =>\n catalog ? catalog.codemode(api, agent, context) : { tools: [], globals: [] },\n async attach(options, context) {\n let started: Awaited<ReturnType<Awaited<ReturnType<McpLoader>>['startMcp']>>;\n try {\n started = await (await load()).startMcp(registry, options, context);\n } catch (error) {\n await unavailable(options, error, context);\n return idle;\n }\n catalog = started.catalog;\n return started.runtime;\n },\n };\n}\n"],
|
|
5
|
-
"mappings": "AASA,SAAS,sBAAsB;AAG/B,SAAS,QAA4B,aAAa,YAAY,qBAAqB;AAK5E,MAAM,cAAyB,MAAM,OAAO,cAAc;AASjE,MAAM,OAAmB;AAAA,EACvB,UAAU,YAAY,CAAC;AAAA,EACvB,QAAQ,OAAO,OAAO;AACpB,UAAM,IAAI,MAAM,GAAG,EAAE,qCAAqC;AAAA,EAC5D;AAAA,EACA,SAAS,OAAO,OAAO;AACrB,UAAM,IAAI,MAAM,GAAG,EAAE,0CAA0C;AAAA,EACjE;AAAA,EACA,YAAY,YAAY;AAAA,EACxB,UAAU,MAAM,MAAM;AAAA,EACtB,QAAQ,MAAM,CAAC;AAAA,EACf,QAAQ,YAAY;AAAA,EACpB,OAAO,YAAY;AACrB;AAEA,eAAe,YAAY,SAAoB,OAAgB,SAAkB;AAC/E,QAAM,OAAO,GAAG,QAAQ,IAAI;AAC5B,QAAM,OAAO,MAAM,QAAQ,IAAI,aAAa,MAAM,OAAO;AACzD,MAAI,CAAC,eAAe,KAAK,KAAK,KAAK,QAAQ,MAAS,EAAE,QAAQ,OAAQ;AACtE,QAAM,QAAQ,MACX;AAAA,IACC;AAAA,MACE,SAAS;AAAA,MACT,QAAQ;AAAA,MACR,OAAO;AAAA,MACP,MAAM,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAAA,MAC3D,MAAM;AAAA,MACN,QAAQ;AAAA,MACR,UAAU;AAAA,MACV,SAAS;AAAA,IACX;AAAA,IACA;AAAA,EACF,EACC,MAAM,MAAM,MAAS;AAC1B;AAEO,SAAS,SAAS,UAAoB,OAAkB,aAAuB;AACpF,MAAI;AACJ,SAAO;AAAA,IACL,SAAS,MAAM;AAAA,IACf,QAAQ,CAAC,UAAU,SAAS,OAAO,KAAK,KAAK,CAAC;AAAA,IAC9C,UAAU,OAAO,KAAK,OAAO,YAC3B,UAAU,QAAQ,SAAS,KAAK,OAAO,OAAO,IAAI,EAAE,OAAO,CAAC,GAAG,SAAS,CAAC,EAAE;AAAA,IAC7E,MAAM,OAAO,SAAS,SAAS;AAC7B,UAAI;AACJ,UAAI;AACF,kBAAU,OAAO,MAAM,KAAK,GAAG,SAAS,UAAU,SAAS,OAAO;AAAA,MACpE,SAAS,OAAO;AACd,cAAM,YAAY,SAAS,OAAO,OAAO;AACzC,eAAO;AAAA,MACT;AACA,gBAAU,QAAQ;AAClB,aAAO,QAAQ;AAAA,IACjB;AAAA,EACF;AACF;",
|
|
4
|
+
"sourcesContent": ["import type { Context } from '@earendil-works/chord';\nimport type {\n Agent,\n Registry,\n ToolExecutionApi,\n ToolRegistration,\n} from '@earendil-works/pi-durable';\nimport type { CodemodeExtra } from './allow.ts';\nimport type { McpCatalog } from './catalog.ts';\nimport { parseMcpConfig } from './config.ts';\nimport type { McpAttach, McpRuntime } from './runtime.ts';\n\nexport { allows, type CodemodeExtra, McpAllowDoc, mcpEntries, serverAllowed } from './allow.ts';\nexport type { McpAccounts, McpAttach, McpRuntime, ServerStatus } from './runtime.ts';\n\nexport type McpLoader = () => Promise<typeof import('./runtime.ts')>;\n\nexport const loadRuntime: McpLoader = () => import('./runtime.ts');\n\nexport interface McpSetup {\n catalog(): McpCatalog | undefined;\n direct(names: readonly string[]): ToolRegistration[];\n codemode(api: ToolExecutionApi, agent: Agent, context: Context): Promise<CodemodeExtra>;\n attach(options: McpAttach, context: Context): Promise<McpRuntime>;\n}\n\nconst idle: McpRuntime = {\n accounts: async () => [],\n signIn: async (id) => {\n throw new Error(`${id} is not an MCP server that signs in`);\n },\n connect: async (id) => {\n throw new Error(`${id} is not an MCP server that takes a token`);\n },\n disconnect: async () => undefined,\n onChange: () => () => undefined,\n status: () => [],\n secrets: () => [],\n reload: async () => undefined,\n close: async () => undefined,\n};\n\nasync function unavailable(options: McpAttach, error: unknown, context: Context) {\n const file = `${options.home}/.pi/agent/mcp.json`;\n const read = await options.env.readTextFile(file, context);\n if (!parseMcpConfig(read.ok ? read.value : undefined).servers.length) return;\n await options.licks\n .deliver(\n {\n channel: 'fswatch',\n source: 'mcp:~/.pi/agent/mcp.json',\n title: \"MCP servers can't start in this SLICC\",\n text: error instanceof Error ? error.message : String(error),\n body: \"The MCP client didn't load, so the servers in ~/.pi/agent/mcp.json stay off until SLICC is updated.\",\n target: 'cone',\n severity: 'warn',\n eventId: 'mcp\\nunavailable',\n },\n context\n )\n .catch(() => undefined);\n}\n\nexport function setupMcp(registry: Registry, load: McpLoader = loadRuntime): McpSetup {\n let catalog: McpCatalog | undefined;\n return {\n catalog: () => catalog,\n direct: (names) => catalog?.direct(names) ?? [],\n codemode: async (api, agent, context) =>\n catalog ? catalog.codemode(api, agent, context) : { tools: [], globals: [] },\n async attach(options, context) {\n let started: Awaited<ReturnType<Awaited<ReturnType<McpLoader>>['startMcp']>>;\n try {\n started = await (await load()).startMcp(registry, options, context);\n } catch (error) {\n await unavailable(options, error, context);\n return idle;\n }\n catalog = started.catalog;\n return started.runtime;\n },\n };\n}\n"],
|
|
5
|
+
"mappings": "AASA,SAAS,sBAAsB;AAG/B,SAAS,QAA4B,aAAa,YAAY,qBAAqB;AAK5E,MAAM,cAAyB,MAAM,OAAO,cAAc;AASjE,MAAM,OAAmB;AAAA,EACvB,UAAU,YAAY,CAAC;AAAA,EACvB,QAAQ,OAAO,OAAO;AACpB,UAAM,IAAI,MAAM,GAAG,EAAE,qCAAqC;AAAA,EAC5D;AAAA,EACA,SAAS,OAAO,OAAO;AACrB,UAAM,IAAI,MAAM,GAAG,EAAE,0CAA0C;AAAA,EACjE;AAAA,EACA,YAAY,YAAY;AAAA,EACxB,UAAU,MAAM,MAAM;AAAA,EACtB,QAAQ,MAAM,CAAC;AAAA,EACf,SAAS,MAAM,CAAC;AAAA,EAChB,QAAQ,YAAY;AAAA,EACpB,OAAO,YAAY;AACrB;AAEA,eAAe,YAAY,SAAoB,OAAgB,SAAkB;AAC/E,QAAM,OAAO,GAAG,QAAQ,IAAI;AAC5B,QAAM,OAAO,MAAM,QAAQ,IAAI,aAAa,MAAM,OAAO;AACzD,MAAI,CAAC,eAAe,KAAK,KAAK,KAAK,QAAQ,MAAS,EAAE,QAAQ,OAAQ;AACtE,QAAM,QAAQ,MACX;AAAA,IACC;AAAA,MACE,SAAS;AAAA,MACT,QAAQ;AAAA,MACR,OAAO;AAAA,MACP,MAAM,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAAA,MAC3D,MAAM;AAAA,MACN,QAAQ;AAAA,MACR,UAAU;AAAA,MACV,SAAS;AAAA,IACX;AAAA,IACA;AAAA,EACF,EACC,MAAM,MAAM,MAAS;AAC1B;AAEO,SAAS,SAAS,UAAoB,OAAkB,aAAuB;AACpF,MAAI;AACJ,SAAO;AAAA,IACL,SAAS,MAAM;AAAA,IACf,QAAQ,CAAC,UAAU,SAAS,OAAO,KAAK,KAAK,CAAC;AAAA,IAC9C,UAAU,OAAO,KAAK,OAAO,YAC3B,UAAU,QAAQ,SAAS,KAAK,OAAO,OAAO,IAAI,EAAE,OAAO,CAAC,GAAG,SAAS,CAAC,EAAE;AAAA,IAC7E,MAAM,OAAO,SAAS,SAAS;AAC7B,UAAI;AACJ,UAAI;AACF,kBAAU,OAAO,MAAM,KAAK,GAAG,SAAS,UAAU,SAAS,OAAO;AAAA,MACpE,SAAS,OAAO;AACd,cAAM,YAAY,SAAS,OAAO,OAAO;AACzC,eAAO;AAAA,MACT;AACA,gBAAU,QAAQ;AAClB,aAAO,QAAQ;AAAA,IACjB;AAAA,EACF;AACF;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist/mcp/runtime.js
CHANGED
|
@@ -204,6 +204,7 @@ async function attachMcp(catalog, options, context) {
|
|
|
204
204
|
tools: connection.tools.length,
|
|
205
205
|
...connection.error ? { error: scrub(connection.error, connection.secrets) } : {}
|
|
206
206
|
})),
|
|
207
|
+
secrets: () => [...catalog.connections.values()].flatMap((connection) => connection.secrets),
|
|
207
208
|
reload,
|
|
208
209
|
async close(using) {
|
|
209
210
|
clearTimeout(timer);
|
package/dist/mcp/runtime.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/mcp/runtime.ts"],
|
|
4
|
-
"sourcesContent": ["import type { Context } from '@earendil-works/chord';\nimport type { CredentialStore } from '@earendil-works/pi-ai';\nimport type { Registry } from '@earendil-works/pi-durable';\nimport type { ExecutionEnv, FileWatcher } from '@earendil-works/pi-durable/env';\nimport { StreamableHttpTransport } from '@earendil-works/pi-mcp';\nimport type { LickEvent, Licks } from '../licks/licks.ts';\nimport { type McpAccounts, mcpAccounts } from './accounts.ts';\nimport { McpCatalog } from './catalog.ts';\nimport {\n type McpConfigProblem,\n type McpServerEntry,\n parseMcpConfig,\n sameConfig,\n usesOAuth,\n} from './config.ts';\nimport { McpServerConnection } from './connection.ts';\nimport { resolveHeaders, scrub, secretNames } from './credentials.ts';\nimport { authProvider as oauthAuth, StoredOAuth } from './oauth.ts';\nimport { patchSse } from './sse.ts';\n\nexport const MCP_LOG_MAX_BYTES = 5 * 1024 * 1024;\n\nexport function configPath(home: string): string {\n return `${home}/.pi/agent/mcp.json`;\n}\n\nexport function logPath(home: string): string {\n return `${home}/.pi/agent/mcp.log`;\n}\n\nexport interface McpAttach {\n licks: Licks;\n env: ExecutionEnv;\n home: string;\n credentials: CredentialStore;\n fetch: typeof fetch;\n version: string;\n reloadMs: number;\n codemode: boolean;\n cors: boolean;\n redirect: string;\n}\n\nexport interface ServerStatus {\n name: string;\n state: string;\n tools: number;\n error?: string;\n}\n\nexport type { McpAccounts } from './accounts.ts';\n\nexport interface McpRuntime extends McpAccounts {\n status(): ServerStatus[];\n reload(context: Context): Promise<void>;\n close(context: Context): Promise<void>;\n}\n\nexport function problemLick(problem: McpConfigProblem, home: string): LickEvent {\n const file = `~${configPath(home).slice(home.length)}`;\n const where = problem.server ? `server \"${problem.server}\"` : file;\n const field = problem.field ? `, field ${problem.field}` : '';\n return {\n channel: 'fswatch',\n source: `mcp:${file}`,\n title: `MCP config problem: ${where}${field}`,\n text: problem.message,\n body: `${file}: the entry is skipped until it is fixed. The format is in the slicc-agent README.`,\n target: 'cone',\n severity: 'warn',\n eventId: `${problem.server ?? ''}\\n${problem.field ?? ''}\\n${problem.message}`,\n };\n}\n\nconst CORS_ERROR = /failed to fetch|networkerror|load failed|cors/i;\n\nexport function stateLick(connection: McpServerConnection, cors: boolean): LickEvent | undefined {\n const name = connection.name;\n const base = { channel: 'fswatch' as const, source: `mcp:${name}`, target: 'cone' as const };\n if (connection.state === 'needs-secret')\n return {\n ...base,\n title: `MCP server \"${name}\" needs a token`,\n text: `Its headers use ${connection.missing.map((item) => `\\${${item}}`).join(', ')}. Add the value in Settings \u203A MCP servers.`,\n severity: 'warn',\n eventId: `${name}\\nsecret\\n${connection.missing.join(',')}`,\n };\n if (connection.state === 'needs-auth')\n return {\n ...base,\n title: secretNames(connection.entry.config).length\n ? `MCP server \"${name}\" rejected its token`\n : `MCP server \"${name}\" needs sign-in`,\n text: connection.signInMessage(),\n severity: 'warn',\n eventId: `${name}\\nauth`,\n };\n if (connection.state !== 'failed') return undefined;\n const error = scrub(connection.error ?? 'unknown error', connection.secrets);\n const blocked = cors && CORS_ERROR.test(error);\n return {\n ...base,\n title: `MCP server \"${name}\" can't connect`,\n text: blocked\n ? \"Seven reaches it with the page's own fetch, and the server sends no CORS headers. Run slicc-node, slicc-swift or the SLICC extension, which fetch without CORS.\"\n : error,\n severity: 'warn',\n eventId: `${name}\\nfailed\\n${blocked ? 'cors' : error}`,\n };\n}\n\nexport function connectedLick(connection: McpServerConnection): LickEvent {\n const count = connection.tools.length;\n return {\n channel: 'fswatch',\n source: `mcp:${connection.name}`,\n title: `MCP server \"${connection.name}\" connected`,\n text: `${connection.entry.config.url} offers ${count} tool${count === 1 ? '' : 's'}.`,\n target: 'cone',\n eventId: `${connection.name}\\nconnected\\n${connection.entry.config.url}`,\n };\n}\n\nexport function logLine(\n server: string,\n params: unknown,\n secrets: readonly string[],\n at: Date\n): string {\n const { level, logger, data } = (params ?? {}) as {\n level?: string;\n logger?: string;\n data?: unknown;\n };\n const text = scrub(typeof data === 'string' ? data : (JSON.stringify(data) ?? ''), secrets);\n return `${at.toISOString()} [${server}] ${level ?? 'info'}${logger ? ` ${logger}` : ''}: ${text}\\n`;\n}\n\nfunction serverLog(options: McpAttach, context: Context) {\n let logging = Promise.resolve();\n const path = logPath(options.home);\n const { env } = options;\n return {\n write(connection: McpServerConnection, params: unknown) {\n const line = logLine(connection.name, params, connection.secrets, new Date());\n logging = logging.then(async () => {\n const info = await env.fileInfo(path, context);\n if (info.ok && info.value.size > MCP_LOG_MAX_BYTES)\n await env.renameFile(path, `${path}.1`, context);\n await env.appendFile(path, line, context);\n });\n },\n settled: () => logging,\n };\n}\n\nexport async function attachMcp(\n catalog: McpCatalog,\n options: McpAttach,\n context: Context\n): Promise<McpRuntime> {\n const { env, home } = options;\n catalog.codemodeOn = options.codemode;\n const reported = new Set<string>();\n const report = async (lick: LickEvent | undefined, using: Context) => {\n if (!lick?.eventId || reported.has(lick.eventId)) return;\n reported.add(lick.eventId);\n await options.licks.deliver(lick, using).catch(() => undefined);\n };\n const listeners = new Set<() => void>();\n const notify = () => {\n for (const listener of listeners) listener();\n };\n let initial: Set<string> = new Set();\n let first = true;\n const log = serverLog(options, context);\n const fetcher = (input: string | URL, init?: RequestInit) => options.fetch(input, init);\n const oauth = (entry: McpServerEntry) =>\n new StoredOAuth(entry, options.credentials, options.redirect);\n const transport = async (entry: McpServerEntry) => {\n const resolved = await resolveHeaders(entry.name, entry.config, options.credentials);\n if (!resolved.ok) return { missing: resolved.missing };\n const authProvider = usesOAuth(entry.config) ? oauthAuth(oauth(entry), entry) : undefined;\n return {\n transport: new StreamableHttpTransport({\n url: entry.config.url,\n headers: resolved.headers,\n fetch: fetcher,\n ...(authProvider ? { authProvider } : {}),\n }),\n secrets: resolved.secrets,\n };\n };\n const open = (entry: McpServerEntry) => {\n const connection = new McpServerConnection({\n entry,\n version: options.version,\n transport,\n onTools: () => catalog.rebuild(),\n onLog: log.write,\n onChange: (changed) => {\n if (catalog.connections.get(changed.name) !== changed) return;\n if (changed.state === 'connected' && !initial.has(changed.name))\n void report(connectedLick(changed), context);\n void report(stateLick(changed, options.cors), context);\n if (changed.state !== 'connected') catalog.rebuild();\n notify();\n },\n });\n catalog.connections.set(entry.name, connection);\n void connection.getClient().catch(() => undefined);\n };\n const reload = async (using: Context) => {\n const read = await env.readTextFile(configPath(home), using);\n const parsed = parseMcpConfig(read.ok ? read.value : undefined);\n for (const problem of parsed.problems) await report(problemLick(problem, home), using);\n const wanted = new Map(\n parsed.servers\n .filter((entry) => entry.config.enabled !== false)\n .map((entry) => [entry.name, entry])\n );\n const closing: Promise<void>[] = [];\n for (const [name, connection] of [...catalog.connections]) {\n const next = wanted.get(name);\n if (next && sameConfig(next.config, connection.entry.config)) continue;\n catalog.connections.delete(name);\n closing.push(connection.close());\n }\n if (first) initial = new Set(wanted.keys());\n first = false;\n for (const [name, entry] of wanted) if (!catalog.connections.has(name)) open(entry);\n catalog.rebuild();\n notify();\n await Promise.all(closing);\n };\n await reload(context);\n let timer: ReturnType<typeof setTimeout> | undefined;\n const schedule = () => {\n clearTimeout(timer);\n timer = setTimeout(() => void reload(context).catch(() => undefined), options.reloadMs);\n };\n const watched = await env.watch([{ path: configPath(home) }], schedule, context);\n const watcher: FileWatcher | undefined = watched.ok ? watched.value : undefined;\n const restart = (connection: McpServerConnection) => {\n open(connection.entry);\n void connection.close();\n catalog.rebuild();\n };\n return {\n ...mcpAccounts(\n catalog,\n { credentials: options.credentials, oauth, fetch: fetcher },\n restart,\n listeners\n ),\n status: () =>\n [...catalog.connections.values()].map((connection) => ({\n name: connection.name,\n state: connection.state,\n tools: connection.tools.length,\n ...(connection.error ? { error: scrub(connection.error, connection.secrets) } : {}),\n })),\n reload,\n async close(using) {\n clearTimeout(timer);\n await watcher?.close(using);\n const all = [...catalog.connections.values()];\n catalog.connections.clear();\n await Promise.all(all.map((connection) => connection.close()));\n catalog.rebuild();\n await log.settled();\n },\n };\n}\n\nexport async function startMcp(\n registry: Registry,\n options: McpAttach,\n context: Context\n): Promise<{ catalog: McpCatalog; runtime: McpRuntime }> {\n patchSse();\n const catalog = new McpCatalog(registry);\n return { catalog, runtime: await attachMcp(catalog, options, context) };\n}\n"],
|
|
5
|
-
"mappings": "AAIA,SAAS,+BAA+B;AAExC,SAA2B,mBAAmB;AAC9C,SAAS,kBAAkB;AAC3B;AAAA,EAGE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,2BAA2B;AACpC,SAAS,gBAAgB,OAAO,mBAAmB;AACnD,SAAS,gBAAgB,WAAW,mBAAmB;AACvD,SAAS,gBAAgB;AAElB,MAAM,oBAAoB,IAAI,OAAO;AAErC,SAAS,WAAW,MAAsB;AAC/C,SAAO,GAAG,IAAI;AAChB;AAEO,SAAS,QAAQ,MAAsB;AAC5C,SAAO,GAAG,IAAI;AAChB;
|
|
4
|
+
"sourcesContent": ["import type { Context } from '@earendil-works/chord';\nimport type { CredentialStore } from '@earendil-works/pi-ai';\nimport type { Registry } from '@earendil-works/pi-durable';\nimport type { ExecutionEnv, FileWatcher } from '@earendil-works/pi-durable/env';\nimport { StreamableHttpTransport } from '@earendil-works/pi-mcp';\nimport type { LickEvent, Licks } from '../licks/licks.ts';\nimport { type McpAccounts, mcpAccounts } from './accounts.ts';\nimport { McpCatalog } from './catalog.ts';\nimport {\n type McpConfigProblem,\n type McpServerEntry,\n parseMcpConfig,\n sameConfig,\n usesOAuth,\n} from './config.ts';\nimport { McpServerConnection } from './connection.ts';\nimport { resolveHeaders, scrub, secretNames } from './credentials.ts';\nimport { authProvider as oauthAuth, StoredOAuth } from './oauth.ts';\nimport { patchSse } from './sse.ts';\n\nexport const MCP_LOG_MAX_BYTES = 5 * 1024 * 1024;\n\nexport function configPath(home: string): string {\n return `${home}/.pi/agent/mcp.json`;\n}\n\nexport function logPath(home: string): string {\n return `${home}/.pi/agent/mcp.log`;\n}\n\nexport interface McpAttach {\n licks: Licks;\n env: ExecutionEnv;\n home: string;\n credentials: CredentialStore;\n fetch: typeof fetch;\n version: string;\n reloadMs: number;\n codemode: boolean;\n cors: boolean;\n redirect: string;\n}\n\nexport interface ServerStatus {\n name: string;\n state: string;\n tools: number;\n error?: string;\n}\n\nexport type { McpAccounts } from './accounts.ts';\n\nexport interface McpRuntime extends McpAccounts {\n status(): ServerStatus[];\n secrets(): string[];\n reload(context: Context): Promise<void>;\n close(context: Context): Promise<void>;\n}\n\nexport function problemLick(problem: McpConfigProblem, home: string): LickEvent {\n const file = `~${configPath(home).slice(home.length)}`;\n const where = problem.server ? `server \"${problem.server}\"` : file;\n const field = problem.field ? `, field ${problem.field}` : '';\n return {\n channel: 'fswatch',\n source: `mcp:${file}`,\n title: `MCP config problem: ${where}${field}`,\n text: problem.message,\n body: `${file}: the entry is skipped until it is fixed. The format is in the slicc-agent README.`,\n target: 'cone',\n severity: 'warn',\n eventId: `${problem.server ?? ''}\\n${problem.field ?? ''}\\n${problem.message}`,\n };\n}\n\nconst CORS_ERROR = /failed to fetch|networkerror|load failed|cors/i;\n\nexport function stateLick(connection: McpServerConnection, cors: boolean): LickEvent | undefined {\n const name = connection.name;\n const base = { channel: 'fswatch' as const, source: `mcp:${name}`, target: 'cone' as const };\n if (connection.state === 'needs-secret')\n return {\n ...base,\n title: `MCP server \"${name}\" needs a token`,\n text: `Its headers use ${connection.missing.map((item) => `\\${${item}}`).join(', ')}. Add the value in Settings \u203A MCP servers.`,\n severity: 'warn',\n eventId: `${name}\\nsecret\\n${connection.missing.join(',')}`,\n };\n if (connection.state === 'needs-auth')\n return {\n ...base,\n title: secretNames(connection.entry.config).length\n ? `MCP server \"${name}\" rejected its token`\n : `MCP server \"${name}\" needs sign-in`,\n text: connection.signInMessage(),\n severity: 'warn',\n eventId: `${name}\\nauth`,\n };\n if (connection.state !== 'failed') return undefined;\n const error = scrub(connection.error ?? 'unknown error', connection.secrets);\n const blocked = cors && CORS_ERROR.test(error);\n return {\n ...base,\n title: `MCP server \"${name}\" can't connect`,\n text: blocked\n ? \"Seven reaches it with the page's own fetch, and the server sends no CORS headers. Run slicc-node, slicc-swift or the SLICC extension, which fetch without CORS.\"\n : error,\n severity: 'warn',\n eventId: `${name}\\nfailed\\n${blocked ? 'cors' : error}`,\n };\n}\n\nexport function connectedLick(connection: McpServerConnection): LickEvent {\n const count = connection.tools.length;\n return {\n channel: 'fswatch',\n source: `mcp:${connection.name}`,\n title: `MCP server \"${connection.name}\" connected`,\n text: `${connection.entry.config.url} offers ${count} tool${count === 1 ? '' : 's'}.`,\n target: 'cone',\n eventId: `${connection.name}\\nconnected\\n${connection.entry.config.url}`,\n };\n}\n\nexport function logLine(\n server: string,\n params: unknown,\n secrets: readonly string[],\n at: Date\n): string {\n const { level, logger, data } = (params ?? {}) as {\n level?: string;\n logger?: string;\n data?: unknown;\n };\n const text = scrub(typeof data === 'string' ? data : (JSON.stringify(data) ?? ''), secrets);\n return `${at.toISOString()} [${server}] ${level ?? 'info'}${logger ? ` ${logger}` : ''}: ${text}\\n`;\n}\n\nfunction serverLog(options: McpAttach, context: Context) {\n let logging = Promise.resolve();\n const path = logPath(options.home);\n const { env } = options;\n return {\n write(connection: McpServerConnection, params: unknown) {\n const line = logLine(connection.name, params, connection.secrets, new Date());\n logging = logging.then(async () => {\n const info = await env.fileInfo(path, context);\n if (info.ok && info.value.size > MCP_LOG_MAX_BYTES)\n await env.renameFile(path, `${path}.1`, context);\n await env.appendFile(path, line, context);\n });\n },\n settled: () => logging,\n };\n}\n\nexport async function attachMcp(\n catalog: McpCatalog,\n options: McpAttach,\n context: Context\n): Promise<McpRuntime> {\n const { env, home } = options;\n catalog.codemodeOn = options.codemode;\n const reported = new Set<string>();\n const report = async (lick: LickEvent | undefined, using: Context) => {\n if (!lick?.eventId || reported.has(lick.eventId)) return;\n reported.add(lick.eventId);\n await options.licks.deliver(lick, using).catch(() => undefined);\n };\n const listeners = new Set<() => void>();\n const notify = () => {\n for (const listener of listeners) listener();\n };\n let initial: Set<string> = new Set();\n let first = true;\n const log = serverLog(options, context);\n const fetcher = (input: string | URL, init?: RequestInit) => options.fetch(input, init);\n const oauth = (entry: McpServerEntry) =>\n new StoredOAuth(entry, options.credentials, options.redirect);\n const transport = async (entry: McpServerEntry) => {\n const resolved = await resolveHeaders(entry.name, entry.config, options.credentials);\n if (!resolved.ok) return { missing: resolved.missing };\n const authProvider = usesOAuth(entry.config) ? oauthAuth(oauth(entry), entry) : undefined;\n return {\n transport: new StreamableHttpTransport({\n url: entry.config.url,\n headers: resolved.headers,\n fetch: fetcher,\n ...(authProvider ? { authProvider } : {}),\n }),\n secrets: resolved.secrets,\n };\n };\n const open = (entry: McpServerEntry) => {\n const connection = new McpServerConnection({\n entry,\n version: options.version,\n transport,\n onTools: () => catalog.rebuild(),\n onLog: log.write,\n onChange: (changed) => {\n if (catalog.connections.get(changed.name) !== changed) return;\n if (changed.state === 'connected' && !initial.has(changed.name))\n void report(connectedLick(changed), context);\n void report(stateLick(changed, options.cors), context);\n if (changed.state !== 'connected') catalog.rebuild();\n notify();\n },\n });\n catalog.connections.set(entry.name, connection);\n void connection.getClient().catch(() => undefined);\n };\n const reload = async (using: Context) => {\n const read = await env.readTextFile(configPath(home), using);\n const parsed = parseMcpConfig(read.ok ? read.value : undefined);\n for (const problem of parsed.problems) await report(problemLick(problem, home), using);\n const wanted = new Map(\n parsed.servers\n .filter((entry) => entry.config.enabled !== false)\n .map((entry) => [entry.name, entry])\n );\n const closing: Promise<void>[] = [];\n for (const [name, connection] of [...catalog.connections]) {\n const next = wanted.get(name);\n if (next && sameConfig(next.config, connection.entry.config)) continue;\n catalog.connections.delete(name);\n closing.push(connection.close());\n }\n if (first) initial = new Set(wanted.keys());\n first = false;\n for (const [name, entry] of wanted) if (!catalog.connections.has(name)) open(entry);\n catalog.rebuild();\n notify();\n await Promise.all(closing);\n };\n await reload(context);\n let timer: ReturnType<typeof setTimeout> | undefined;\n const schedule = () => {\n clearTimeout(timer);\n timer = setTimeout(() => void reload(context).catch(() => undefined), options.reloadMs);\n };\n const watched = await env.watch([{ path: configPath(home) }], schedule, context);\n const watcher: FileWatcher | undefined = watched.ok ? watched.value : undefined;\n const restart = (connection: McpServerConnection) => {\n open(connection.entry);\n void connection.close();\n catalog.rebuild();\n };\n return {\n ...mcpAccounts(\n catalog,\n { credentials: options.credentials, oauth, fetch: fetcher },\n restart,\n listeners\n ),\n status: () =>\n [...catalog.connections.values()].map((connection) => ({\n name: connection.name,\n state: connection.state,\n tools: connection.tools.length,\n ...(connection.error ? { error: scrub(connection.error, connection.secrets) } : {}),\n })),\n secrets: () => [...catalog.connections.values()].flatMap((connection) => connection.secrets),\n reload,\n async close(using) {\n clearTimeout(timer);\n await watcher?.close(using);\n const all = [...catalog.connections.values()];\n catalog.connections.clear();\n await Promise.all(all.map((connection) => connection.close()));\n catalog.rebuild();\n await log.settled();\n },\n };\n}\n\nexport async function startMcp(\n registry: Registry,\n options: McpAttach,\n context: Context\n): Promise<{ catalog: McpCatalog; runtime: McpRuntime }> {\n patchSse();\n const catalog = new McpCatalog(registry);\n return { catalog, runtime: await attachMcp(catalog, options, context) };\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist/memory/format.js
CHANGED
|
@@ -215,6 +215,14 @@ const SECRETS = [
|
|
|
215
215
|
/([?&][\w.-]*(?:sig|signature|token|key|secret|credential|password|auth|code)[\w.-]*=)[^&\s#)"']+/gi,
|
|
216
216
|
(_match, name) => `${name}${REDACTED}`
|
|
217
217
|
],
|
|
218
|
+
[
|
|
219
|
+
/\b([A-Z0-9_]*(?:TOKEN|KEY|SECRET|PASSWORD|PASSWD|AUTH|CREDENTIALS?|SESSION)[A-Z0-9_]*)=("[^"]*"|'[^']*'|[^\s"']+)/g,
|
|
220
|
+
(_match, name) => `${name}=${REDACTED}`
|
|
221
|
+
],
|
|
222
|
+
[
|
|
223
|
+
/(--?(?:token|password|passwd|secret|api-key|apikey|auth|key)(?:=|\s+))("[^"]*"|'[^']*'|[^\s"'-][^\s"']*)/gi,
|
|
224
|
+
(_match, flag) => `${flag}${REDACTED}`
|
|
225
|
+
],
|
|
218
226
|
[
|
|
219
227
|
/\b((?:api|access|secret|private|client)[_-]?(?:key|token|secret)|token|password|passwd|secret)\s*([:=])\s*["']?[^\s"',;]{6,}["']?/gi,
|
|
220
228
|
named
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/memory/format.ts"],
|
|
4
|
-
"sourcesContent": ["export type MemoryTag = 'user' | 'feedback' | 'project';\n\nexport interface MemoryEntry {\n id: string;\n scope: string;\n section: string;\n title: string;\n body: string;\n tag: MemoryTag | null;\n updatedAt: number;\n source: 'entry' | 'notes';\n}\n\nexport interface MemoryScope {\n id: string;\n label: string;\n group?: 'cones' | 'roles';\n}\n\nexport type Entry = { title: string; tag: MemoryTag | null; body: string };\nexport type Section = { name: string; intro: string; entries: Entry[] };\nexport type MemoryDoc = { head: string; sections: Section[] };\n\nexport const MEMORY_FILE = 'MEMORY.md';\nexport const NOTES = 'Notes';\nexport const MAX_LINES = 200;\nexport const MAX_BYTES = 16 * 1024;\nconst TAGS = new Set<string>(['user', 'feedback', 'project']);\n\nexport function slugOf(text: string): string {\n return (\n text\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '')\n .slice(0, 60) || 'untitled'\n );\n}\n\nfunction trimBlock(lines: string[]): string {\n return lines\n .join('\\n')\n .replace(/^\\s*\\n/, '')\n .trimEnd();\n}\n\ntype Raw = { name: string; intro: string[]; entries: { title: string; lines: string[] }[] };\n\nexport function parseMemory(text: string): MemoryDoc {\n const doc: MemoryDoc = { head: '', sections: [] };\n const head: string[] = [];\n const sections: Raw[] = [];\n let section: Raw | null = null;\n let fenced = false;\n for (const line of text.replace(/\\r\\n?/g, '\\n').split('\\n')) {\n if (/^\\s*(```|~~~)/.test(line)) fenced = !fenced;\n const h2 = fenced ? null : /^##\\s+(.+?)\\s*#*\\s*$/.exec(line);\n const h3 = fenced ? null : /^###\\s+(.+?)\\s*#*\\s*$/.exec(line);\n if (h2 && !line.startsWith('###')) {\n section = { name: h2[1] as string, intro: [], entries: [] };\n sections.push(section);\n } else if (h3) {\n if (!section) {\n section = { name: NOTES, intro: [], entries: [] };\n sections.push(section);\n }\n section.entries.push({ title: h3[1] as string, lines: [] });\n } else if (!section) head.push(line);\n else {\n const entry = section.entries.at(-1);\n (entry ? entry.lines : section.intro).push(line);\n }\n }\n doc.head = trimBlock(head);\n for (const found of sections) {\n doc.sections.push({\n name: found.name,\n intro: trimBlock(found.intro),\n entries: found.entries.map(({ title, lines }) => {\n const first = lines.findIndex((line) => line.trim() !== '');\n const tagged = first < 0 ? null : /^tag:\\s*(\\w+)\\s*$/i.exec(lines[first] as string);\n const tag =\n tagged && TAGS.has((tagged[1] as string).toLowerCase())\n ? ((tagged[1] as string).toLowerCase() as MemoryTag)\n : null;\n return { title, tag, body: trimBlock(tag ? lines.slice(first + 1) : lines) };\n }),\n });\n }\n return doc;\n}\n\nexport function serializeMemory(doc: MemoryDoc): string {\n const parts: string[] = [];\n if (doc.head) parts.push(doc.head);\n for (const section of doc.sections) {\n parts.push(`## ${section.name}`);\n if (section.intro) parts.push(section.intro);\n for (const entry of section.entries) {\n const lines = [`### ${entry.title}`];\n if (entry.tag) lines.push(`tag: ${entry.tag}`);\n parts.push(lines.join('\\n'));\n if (entry.body) parts.push(entry.body);\n }\n }\n return parts.length ? `${parts.join('\\n\\n')}\\n` : '';\n}\n\nfunction headNotes(head: string): string {\n return head\n .split('\\n')\n .filter((line) => !/^#\\s/.test(line))\n .join('\\n')\n .trim();\n}\n\ntype Target =\n | { kind: 'head'; section: null; entry: null }\n | { kind: 'intro'; section: Section; entry: null }\n | { kind: 'entry'; section: Section; entry: Entry };\n\nfunction walk(doc: MemoryDoc): Target[] {\n const out: Target[] = [];\n if (headNotes(doc.head)) out.push({ kind: 'head', section: null, entry: null });\n for (const section of doc.sections) {\n if (section.intro) out.push({ kind: 'intro', section, entry: null });\n for (const entry of section.entries) out.push({ kind: 'entry', section, entry });\n }\n return out;\n}\n\nfunction identify(targets: Target[], scope: string): string[] {\n const used = new Set<string>();\n return targets.map((target) => {\n const parts =\n target.kind === 'head'\n ? [NOTES]\n : target.kind === 'intro'\n ? [target.section.name]\n : [target.section.name, target.entry.title];\n const base = [scope, ...parts.map(slugOf)].join('/');\n let candidate = base;\n for (let n = 2; used.has(candidate); n++) candidate = `${base}-${n}`;\n used.add(candidate);\n return candidate;\n });\n}\n\nexport function memoryEntries(doc: MemoryDoc, scope: string, updatedAt: number): MemoryEntry[] {\n const targets = walk(doc);\n const ids = identify(targets, scope);\n return targets.map((target, index) => {\n const id = ids[index] as string;\n if (target.kind === 'head')\n return {\n id,\n scope,\n section: NOTES,\n title: NOTES,\n body: headNotes(doc.head),\n tag: null,\n updatedAt,\n source: 'notes',\n };\n if (target.kind === 'intro')\n return {\n id,\n scope,\n section: target.section.name,\n title: target.section.name,\n body: target.section.intro,\n tag: null,\n updatedAt,\n source: 'notes',\n };\n return {\n id,\n scope,\n section: target.section.name,\n title: target.entry.title,\n body: target.entry.body,\n tag: target.entry.tag,\n updatedAt,\n source: 'entry',\n };\n });\n}\n\nexport type Change =\n | {\n kind: 'save';\n id?: string;\n section: string;\n title: string;\n body: string;\n tag: MemoryTag | null;\n }\n | { kind: 'remove'; id?: string; section?: string; title?: string };\n\nexport function oneLine(text: string): string {\n return text.replace(/\\s+/g, ' ').trim();\n}\n\nexport function demote(body: string): string {\n let fenced = false;\n return body\n .trim()\n .split('\\n')\n .map((line) => {\n if (/^\\s*(```|~~~)/.test(line)) fenced = !fenced;\n return fenced ? line : line.replace(/^(\\s{0,3})#{2,3}(?=\\s)/, '$1####');\n })\n .join('\\n');\n}\n\nconst same = (a: string, b: string) => a.toLowerCase() === b.toLowerCase();\n\nexport function applyChange(\n doc: MemoryDoc,\n scope: string,\n change: Change\n): { doc: MemoryDoc; found: boolean } {\n const next: MemoryDoc = {\n head: doc.head,\n sections: doc.sections.map((section) => ({ ...section, entries: [...section.entries] })),\n };\n const targets = walk(next);\n const ids = identify(targets, scope);\n const byId = change.id ? targets[ids.indexOf(change.id)] : undefined;\n const byTitle =\n change.section !== undefined && change.title !== undefined\n ? targets.find(\n (target) =>\n target.kind === 'entry' &&\n same(target.section.name, change.section as string) &&\n same(target.entry.title, change.title as string)\n )\n : undefined;\n const target = byId ?? byTitle;\n const drop = () => {\n if (target?.kind === 'head')\n next.head = next.head\n .split('\\n')\n .filter((line) => /^#\\s/.test(line))\n .join('\\n');\n else if (target?.kind === 'intro') target.section.intro = '';\n else if (target?.kind === 'entry')\n target.section.entries.splice(target.section.entries.indexOf(target.entry), 1);\n };\n const tidy = () => {\n next.sections = next.sections.filter((section) => section.intro || section.entries.length);\n return { doc: next, found: target !== undefined };\n };\n if (change.kind === 'remove') {\n drop();\n return tidy();\n }\n const name = oneLine(change.section);\n const entry: Entry = { title: oneLine(change.title), tag: change.tag, body: demote(change.body) };\n if (target?.kind === 'entry' && same(target.section.name, name)) {\n target.section.entries[target.section.entries.indexOf(target.entry)] = entry;\n return tidy();\n }\n drop();\n let section = next.sections.find((item) => same(item.name, name));\n if (!section) {\n section = { name, intro: '', entries: [] };\n next.sections.push(section);\n }\n const clash = section.entries.findIndex((item) => same(item.title, entry.title));\n if (clash >= 0) section.entries[clash] = entry;\n else section.entries.push(entry);\n return tidy();\n}\n\nexport function excerpt(text: string): { text: string; capped: boolean } {\n const lines = text.split('\\n');\n let out = lines.slice(0, MAX_LINES).join('\\n');\n let capped = lines.length > MAX_LINES;\n const bytes = new TextEncoder().encode(out);\n if (bytes.length > MAX_BYTES) {\n out = new TextDecoder().decode(bytes.slice(0, MAX_BYTES)).replace(/\uFFFD$/, '');\n capped = true;\n }\n return { text: out, capped };\n}\n\nexport function byteLength(text: string): number {\n return new TextEncoder().encode(text).length;\n}\n\nexport const REDACTED = '[redacted]';\n\nconst named = (match: string, name: string, sign: string) => `${name}${sign} ${REDACTED}`;\n\nconst SECRETS: [RegExp, (match: string, ...groups: string[]) => string][] = [\n [/-----BEGIN [A-Z ]*PRIVATE KEY-----[\\s\\S]*?-----END [A-Z ]*PRIVATE KEY-----/g, () => REDACTED],\n [/\\b(authorization|proxy-authorization)\\s*([:=])\\s*(\"[^\"\\n]*\"|'[^'\\n]*'|[^\\n]*)/gi, named],\n [/\\bbearer\\s+[A-Za-z0-9._~+/-]{8,}=*/gi, () => REDACTED],\n [/\\b(?:sk|pk|rk)-(?:[A-Za-z0-9]+-)*[A-Za-z0-9_-]{16,}/g, () => REDACTED],\n [/\\b(?:AKIA|ASIA)[0-9A-Z]{16}\\b/g, () => REDACTED],\n [/\\bABSK[A-Za-z0-9+/=]{16,}/g, () => REDACTED],\n [/\\bgh[pousr]_[A-Za-z0-9]{20,}\\b/g, () => REDACTED],\n [/\\bgithub_pat_[A-Za-z0-9_]{20,}\\b/g, () => REDACTED],\n [/\\bxox[abprs]-[A-Za-z0-9-]{10,}\\b/g, () => REDACTED],\n [/\\bAIza[0-9A-Za-z_-]{30,}\\b/g, () => REDACTED],\n [/\\beyJ[A-Za-z0-9_-]{8,}\\.[A-Za-z0-9_-]{8,}\\.[A-Za-z0-9_-]{8,}/g, () => REDACTED],\n [/(https?:\\/\\/[^\\s#)]*)#[^\\s)]*\\bkey\\b[^\\s)]*/gi, (_match, url) => `${url}#${REDACTED}`],\n [\n /([?&][\\w.-]*(?:sig|signature|token|key|secret|credential|password|auth|code)[\\w.-]*=)[^&\\s#)\"']+/gi,\n (_match, name) => `${name}${REDACTED}`,\n ],\n [\n /\\b((?:api|access|secret|private|client)[_-]?(?:key|token|secret)|token|password|passwd|secret)\\s*([:=])\\s*[\"']?[^\\s\"',;]{6,}[\"']?/gi,\n named,\n ],\n];\n\nexport function redactSecrets(text: string): { text: string; count: number } {\n let count = 0;\n let out = text;\n for (const [pattern, replace] of SECRETS)\n out = out.replace(pattern, (match: string, ...groups: string[]) => {\n if (match.endsWith(REDACTED)) return match;\n count++;\n return replace(match, ...groups);\n });\n return { text: out, count };\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["export type MemoryTag = 'user' | 'feedback' | 'project';\n\nexport interface MemoryEntry {\n id: string;\n scope: string;\n section: string;\n title: string;\n body: string;\n tag: MemoryTag | null;\n updatedAt: number;\n source: 'entry' | 'notes';\n}\n\nexport interface MemoryScope {\n id: string;\n label: string;\n group?: 'cones' | 'roles';\n}\n\nexport type Entry = { title: string; tag: MemoryTag | null; body: string };\nexport type Section = { name: string; intro: string; entries: Entry[] };\nexport type MemoryDoc = { head: string; sections: Section[] };\n\nexport const MEMORY_FILE = 'MEMORY.md';\nexport const NOTES = 'Notes';\nexport const MAX_LINES = 200;\nexport const MAX_BYTES = 16 * 1024;\nconst TAGS = new Set<string>(['user', 'feedback', 'project']);\n\nexport function slugOf(text: string): string {\n return (\n text\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '')\n .slice(0, 60) || 'untitled'\n );\n}\n\nfunction trimBlock(lines: string[]): string {\n return lines\n .join('\\n')\n .replace(/^\\s*\\n/, '')\n .trimEnd();\n}\n\ntype Raw = { name: string; intro: string[]; entries: { title: string; lines: string[] }[] };\n\nexport function parseMemory(text: string): MemoryDoc {\n const doc: MemoryDoc = { head: '', sections: [] };\n const head: string[] = [];\n const sections: Raw[] = [];\n let section: Raw | null = null;\n let fenced = false;\n for (const line of text.replace(/\\r\\n?/g, '\\n').split('\\n')) {\n if (/^\\s*(```|~~~)/.test(line)) fenced = !fenced;\n const h2 = fenced ? null : /^##\\s+(.+?)\\s*#*\\s*$/.exec(line);\n const h3 = fenced ? null : /^###\\s+(.+?)\\s*#*\\s*$/.exec(line);\n if (h2 && !line.startsWith('###')) {\n section = { name: h2[1] as string, intro: [], entries: [] };\n sections.push(section);\n } else if (h3) {\n if (!section) {\n section = { name: NOTES, intro: [], entries: [] };\n sections.push(section);\n }\n section.entries.push({ title: h3[1] as string, lines: [] });\n } else if (!section) head.push(line);\n else {\n const entry = section.entries.at(-1);\n (entry ? entry.lines : section.intro).push(line);\n }\n }\n doc.head = trimBlock(head);\n for (const found of sections) {\n doc.sections.push({\n name: found.name,\n intro: trimBlock(found.intro),\n entries: found.entries.map(({ title, lines }) => {\n const first = lines.findIndex((line) => line.trim() !== '');\n const tagged = first < 0 ? null : /^tag:\\s*(\\w+)\\s*$/i.exec(lines[first] as string);\n const tag =\n tagged && TAGS.has((tagged[1] as string).toLowerCase())\n ? ((tagged[1] as string).toLowerCase() as MemoryTag)\n : null;\n return { title, tag, body: trimBlock(tag ? lines.slice(first + 1) : lines) };\n }),\n });\n }\n return doc;\n}\n\nexport function serializeMemory(doc: MemoryDoc): string {\n const parts: string[] = [];\n if (doc.head) parts.push(doc.head);\n for (const section of doc.sections) {\n parts.push(`## ${section.name}`);\n if (section.intro) parts.push(section.intro);\n for (const entry of section.entries) {\n const lines = [`### ${entry.title}`];\n if (entry.tag) lines.push(`tag: ${entry.tag}`);\n parts.push(lines.join('\\n'));\n if (entry.body) parts.push(entry.body);\n }\n }\n return parts.length ? `${parts.join('\\n\\n')}\\n` : '';\n}\n\nfunction headNotes(head: string): string {\n return head\n .split('\\n')\n .filter((line) => !/^#\\s/.test(line))\n .join('\\n')\n .trim();\n}\n\ntype Target =\n | { kind: 'head'; section: null; entry: null }\n | { kind: 'intro'; section: Section; entry: null }\n | { kind: 'entry'; section: Section; entry: Entry };\n\nfunction walk(doc: MemoryDoc): Target[] {\n const out: Target[] = [];\n if (headNotes(doc.head)) out.push({ kind: 'head', section: null, entry: null });\n for (const section of doc.sections) {\n if (section.intro) out.push({ kind: 'intro', section, entry: null });\n for (const entry of section.entries) out.push({ kind: 'entry', section, entry });\n }\n return out;\n}\n\nfunction identify(targets: Target[], scope: string): string[] {\n const used = new Set<string>();\n return targets.map((target) => {\n const parts =\n target.kind === 'head'\n ? [NOTES]\n : target.kind === 'intro'\n ? [target.section.name]\n : [target.section.name, target.entry.title];\n const base = [scope, ...parts.map(slugOf)].join('/');\n let candidate = base;\n for (let n = 2; used.has(candidate); n++) candidate = `${base}-${n}`;\n used.add(candidate);\n return candidate;\n });\n}\n\nexport function memoryEntries(doc: MemoryDoc, scope: string, updatedAt: number): MemoryEntry[] {\n const targets = walk(doc);\n const ids = identify(targets, scope);\n return targets.map((target, index) => {\n const id = ids[index] as string;\n if (target.kind === 'head')\n return {\n id,\n scope,\n section: NOTES,\n title: NOTES,\n body: headNotes(doc.head),\n tag: null,\n updatedAt,\n source: 'notes',\n };\n if (target.kind === 'intro')\n return {\n id,\n scope,\n section: target.section.name,\n title: target.section.name,\n body: target.section.intro,\n tag: null,\n updatedAt,\n source: 'notes',\n };\n return {\n id,\n scope,\n section: target.section.name,\n title: target.entry.title,\n body: target.entry.body,\n tag: target.entry.tag,\n updatedAt,\n source: 'entry',\n };\n });\n}\n\nexport type Change =\n | {\n kind: 'save';\n id?: string;\n section: string;\n title: string;\n body: string;\n tag: MemoryTag | null;\n }\n | { kind: 'remove'; id?: string; section?: string; title?: string };\n\nexport function oneLine(text: string): string {\n return text.replace(/\\s+/g, ' ').trim();\n}\n\nexport function demote(body: string): string {\n let fenced = false;\n return body\n .trim()\n .split('\\n')\n .map((line) => {\n if (/^\\s*(```|~~~)/.test(line)) fenced = !fenced;\n return fenced ? line : line.replace(/^(\\s{0,3})#{2,3}(?=\\s)/, '$1####');\n })\n .join('\\n');\n}\n\nconst same = (a: string, b: string) => a.toLowerCase() === b.toLowerCase();\n\nexport function applyChange(\n doc: MemoryDoc,\n scope: string,\n change: Change\n): { doc: MemoryDoc; found: boolean } {\n const next: MemoryDoc = {\n head: doc.head,\n sections: doc.sections.map((section) => ({ ...section, entries: [...section.entries] })),\n };\n const targets = walk(next);\n const ids = identify(targets, scope);\n const byId = change.id ? targets[ids.indexOf(change.id)] : undefined;\n const byTitle =\n change.section !== undefined && change.title !== undefined\n ? targets.find(\n (target) =>\n target.kind === 'entry' &&\n same(target.section.name, change.section as string) &&\n same(target.entry.title, change.title as string)\n )\n : undefined;\n const target = byId ?? byTitle;\n const drop = () => {\n if (target?.kind === 'head')\n next.head = next.head\n .split('\\n')\n .filter((line) => /^#\\s/.test(line))\n .join('\\n');\n else if (target?.kind === 'intro') target.section.intro = '';\n else if (target?.kind === 'entry')\n target.section.entries.splice(target.section.entries.indexOf(target.entry), 1);\n };\n const tidy = () => {\n next.sections = next.sections.filter((section) => section.intro || section.entries.length);\n return { doc: next, found: target !== undefined };\n };\n if (change.kind === 'remove') {\n drop();\n return tidy();\n }\n const name = oneLine(change.section);\n const entry: Entry = { title: oneLine(change.title), tag: change.tag, body: demote(change.body) };\n if (target?.kind === 'entry' && same(target.section.name, name)) {\n target.section.entries[target.section.entries.indexOf(target.entry)] = entry;\n return tidy();\n }\n drop();\n let section = next.sections.find((item) => same(item.name, name));\n if (!section) {\n section = { name, intro: '', entries: [] };\n next.sections.push(section);\n }\n const clash = section.entries.findIndex((item) => same(item.title, entry.title));\n if (clash >= 0) section.entries[clash] = entry;\n else section.entries.push(entry);\n return tidy();\n}\n\nexport function excerpt(text: string): { text: string; capped: boolean } {\n const lines = text.split('\\n');\n let out = lines.slice(0, MAX_LINES).join('\\n');\n let capped = lines.length > MAX_LINES;\n const bytes = new TextEncoder().encode(out);\n if (bytes.length > MAX_BYTES) {\n out = new TextDecoder().decode(bytes.slice(0, MAX_BYTES)).replace(/\uFFFD$/, '');\n capped = true;\n }\n return { text: out, capped };\n}\n\nexport function byteLength(text: string): number {\n return new TextEncoder().encode(text).length;\n}\n\nexport const REDACTED = '[redacted]';\n\nconst named = (match: string, name: string, sign: string) => `${name}${sign} ${REDACTED}`;\n\nconst SECRETS: [RegExp, (match: string, ...groups: string[]) => string][] = [\n [/-----BEGIN [A-Z ]*PRIVATE KEY-----[\\s\\S]*?-----END [A-Z ]*PRIVATE KEY-----/g, () => REDACTED],\n [/\\b(authorization|proxy-authorization)\\s*([:=])\\s*(\"[^\"\\n]*\"|'[^'\\n]*'|[^\\n]*)/gi, named],\n [/\\bbearer\\s+[A-Za-z0-9._~+/-]{8,}=*/gi, () => REDACTED],\n [/\\b(?:sk|pk|rk)-(?:[A-Za-z0-9]+-)*[A-Za-z0-9_-]{16,}/g, () => REDACTED],\n [/\\b(?:AKIA|ASIA)[0-9A-Z]{16}\\b/g, () => REDACTED],\n [/\\bABSK[A-Za-z0-9+/=]{16,}/g, () => REDACTED],\n [/\\bgh[pousr]_[A-Za-z0-9]{20,}\\b/g, () => REDACTED],\n [/\\bgithub_pat_[A-Za-z0-9_]{20,}\\b/g, () => REDACTED],\n [/\\bxox[abprs]-[A-Za-z0-9-]{10,}\\b/g, () => REDACTED],\n [/\\bAIza[0-9A-Za-z_-]{30,}\\b/g, () => REDACTED],\n [/\\beyJ[A-Za-z0-9_-]{8,}\\.[A-Za-z0-9_-]{8,}\\.[A-Za-z0-9_-]{8,}/g, () => REDACTED],\n [/(https?:\\/\\/[^\\s#)]*)#[^\\s)]*\\bkey\\b[^\\s)]*/gi, (_match, url) => `${url}#${REDACTED}`],\n [\n /([?&][\\w.-]*(?:sig|signature|token|key|secret|credential|password|auth|code)[\\w.-]*=)[^&\\s#)\"']+/gi,\n (_match, name) => `${name}${REDACTED}`,\n ],\n [\n /\\b([A-Z0-9_]*(?:TOKEN|KEY|SECRET|PASSWORD|PASSWD|AUTH|CREDENTIALS?|SESSION)[A-Z0-9_]*)=(\"[^\"]*\"|'[^']*'|[^\\s\"']+)/g,\n (_match, name) => `${name}=${REDACTED}`,\n ],\n [\n /(--?(?:token|password|passwd|secret|api-key|apikey|auth|key)(?:=|\\s+))(\"[^\"]*\"|'[^']*'|[^\\s\"'-][^\\s\"']*)/gi,\n (_match, flag) => `${flag}${REDACTED}`,\n ],\n [\n /\\b((?:api|access|secret|private|client)[_-]?(?:key|token|secret)|token|password|passwd|secret)\\s*([:=])\\s*[\"']?[^\\s\"',;]{6,}[\"']?/gi,\n named,\n ],\n];\n\nexport function redactSecrets(text: string): { text: string; count: number } {\n let count = 0;\n let out = text;\n for (const [pattern, replace] of SECRETS)\n out = out.replace(pattern, (match: string, ...groups: string[]) => {\n if (match.endsWith(REDACTED)) return match;\n count++;\n return replace(match, ...groups);\n });\n return { text: out, count };\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["section", "target"]
|
|
7
7
|
}
|