@hellolynk-ai/workbuddy-mcp 0.3.96 → 0.3.98
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 +17 -2
- package/bin/hellolynk-client-setup.mjs +7 -0
- package/clients/core/hellolynk-native-addressing-tools.cjs +1 -1
- package/clients/core/hellolynk-neutral-host-process.mjs +1 -1
- package/clients/core/hellolynk-release-retention.mjs +157 -19
- package/hellolynk-client-pack-manifest.json +21 -21
- package/hellolynk-client-pack-pin.json +1 -1
- package/integrations/workbuddy/package.json +1 -1
- package/package.json +1 -1
- package/runtime/core/hellolynk-native-addressing-tools.cjs +1 -1
- package/runtime/core/hellolynk-neutral-host-process.mjs +1 -1
- package/runtime/core/hellolynk-release-retention.mjs +157 -19
- package/runtime/neutral-host-release-manifest.json +3 -3
- package/runtime/neutral-host-release-pin.json +1 -1
- package/workbuddy-package-manifest.json +1 -1
- package/workbuddy-package-pin.json +1 -1
package/README.md
CHANGED
|
@@ -46,15 +46,26 @@ Windows 10/11、Node.js 22.16 或更高版本、PowerShell 7,以及打开过
|
|
|
46
46
|
## 安装
|
|
47
47
|
|
|
48
48
|
1. 打开 [HelloLynk 官网(Official site)](https://hellolynk.com)。新用户注册账号;已有账号登录后,查看自己的公开灵信号。
|
|
49
|
-
2.
|
|
49
|
+
2. 两种装法任选一种。
|
|
50
|
+
|
|
51
|
+
用安装包,在官网或 [GitHub Release](https://github.com/haoyun18881-beep/HelloLynk/releases) 下载 WorkBuddy 安装包,完整解压,在包含 `package` 文件夹的目录打开 PowerShell,运行:
|
|
50
52
|
|
|
51
53
|
```powershell
|
|
52
54
|
node .\package\bin\hellolynk-client-setup.mjs init
|
|
53
55
|
```
|
|
54
56
|
|
|
57
|
+
用 npm,在 PowerShell 运行:
|
|
58
|
+
|
|
59
|
+
```powershell
|
|
60
|
+
npm install -g @hellolynk-ai/workbuddy-mcp
|
|
61
|
+
hellolynk-workbuddy init
|
|
62
|
+
```
|
|
63
|
+
|
|
55
64
|
3. 完全退出并重新打开 WorkBuddy。
|
|
56
65
|
|
|
57
|
-
|
|
66
|
+
可以把本说明交给你的本地 AI,请它帮你安装;用安装包时,把解压目录也告诉它。
|
|
67
|
+
|
|
68
|
+
下文命令按安装包写法给出。用 npm 装的,把 `node .\package\bin\hellolynk-client-setup.mjs` 换成 `hellolynk-workbuddy`,在任意目录运行。
|
|
58
69
|
|
|
59
70
|
## 首次连接
|
|
60
71
|
|
|
@@ -78,10 +89,14 @@ node .\package\bin\hellolynk-client-setup.mjs connect --hellolynk-id hellolynk:i
|
|
|
78
89
|
node .\package\bin\hellolynk-client-setup.mjs setup
|
|
79
90
|
```
|
|
80
91
|
|
|
92
|
+
用 npm 装的,先运行 `npm install -g @hellolynk-ai/workbuddy-mcp` 装上新版,再运行 `hellolynk-workbuddy setup`。
|
|
93
|
+
|
|
81
94
|
## 卸载
|
|
82
95
|
|
|
83
96
|
在包含 `package` 文件夹的目录运行 `node .\package\bin\hellolynk-client-setup.mjs uninstall`。账号、联系人和聊天记录留在这台电脑上,重新安装后不用重新连接。
|
|
84
97
|
|
|
98
|
+
用 npm 装的,运行 `hellolynk-workbuddy uninstall`,再运行 `npm uninstall -g @hellolynk-ai/workbuddy-mcp`。
|
|
99
|
+
|
|
85
100
|
## 求助
|
|
86
101
|
|
|
87
102
|
运行 `node .\package\bin\hellolynk-client-setup.mjs doctor` 检查安装,把结果和错误码发到 [haoyun18881@gmail.com](mailto:haoyun18881@gmail.com)。
|
|
@@ -84,6 +84,13 @@ try {
|
|
|
84
84
|
if (mutating) {
|
|
85
85
|
await prepareFinalClientRoot(locations);
|
|
86
86
|
installed = await installStablePackage({ packageClosure, sourceRelease, locations: packageLocations });
|
|
87
|
+
if (metadata.client === "codex") {
|
|
88
|
+
// The invoking updater can still be B255 code. Stop its old cleanup
|
|
89
|
+
// before switching the binding/cache to a release with process records.
|
|
90
|
+
const cleanup = await importStableCore(installed.packageRoot, "hellolynk-release-retention.mjs", "hellolynk_release_retention_unavailable");
|
|
91
|
+
await cleanup.protectRetentionReceipt({ releasesRoot: path.dirname(installed.packageRoot),
|
|
92
|
+
client: "codex", currentRelease: installed.packageRoot });
|
|
93
|
+
}
|
|
87
94
|
}
|
|
88
95
|
const activation = await inspectActivation(locations.hostRoot, metadata.profileId);
|
|
89
96
|
// Both public install commands use the actual account state. Native recovery
|
|
@@ -18,7 +18,7 @@ const conversationGuidance = "HelloLynk 是本人授权的 AI 通讯。接着已
|
|
|
18
18
|
// What every client shows for the shared tools; nativeTool applies it.
|
|
19
19
|
const toolText = Object.freeze({
|
|
20
20
|
hellolynk_reply_authorized_message: { title: "回复来信", description: "接着当前对话的一封来信发送;不接手其他对话。" },
|
|
21
|
-
hellolynk_send_authorized_message: { title: "发起通信", description: "向本人授权的联系人发起新通信。contact 填对方名字;本人点名了对话时,targetConversationTitle
|
|
21
|
+
hellolynk_send_authorized_message: { title: "发起通信", description: "向本人授权的联系人发起新通信。contact 填对方名字;本人点名了对话时,targetConversationTitle 填完整标题。未指定对话的新通信默认送到对方的 HelloLynk 独立会话;要继续已有来往,用 hellolynk_reply_authorized_message 回复原信。" },
|
|
22
22
|
hellolynk_list_authorized_contacts: { title: "查找联系人", description: queryDescription },
|
|
23
23
|
hellolynk_claim_message: { title: "读取来信", description: "按自动提醒里的 batchId 一次读取整批来信(合计不超过 2 万字);手动读单条传 localMessageId 和 conversationKey。" },
|
|
24
24
|
hellolynk_list_pending_messages: { title: "待处理来信", description: "列出当前对话等待 AI 处理的来信,不含正文。" },
|
|
@@ -34,7 +34,7 @@ export const HELLOLYNK_NEUTRAL_HOST_PROCESS_CONTRACT = "hellolynk-neutral-host-p
|
|
|
34
34
|
export const HELLOLYNK_NEUTRAL_HOST_DISCOVERY_CONTRACT = "hellolynk-neutral-host-discovery-v1";
|
|
35
35
|
// Raised with every release batch, together with the six client versions. A Host reports it
|
|
36
36
|
// in its health; the higher release stays and the lower one makes room.
|
|
37
|
-
export const HELLOLYNK_HOST_RELEASE_ORDINAL =
|
|
37
|
+
export const HELLOLYNK_HOST_RELEASE_ORDINAL = 14;
|
|
38
38
|
|
|
39
39
|
const INSTALLATION_LOCK_CONTRACT = "hellolynk-neutral-host-installation-lock-v2";
|
|
40
40
|
const INSTALLATION_LOCK_MAX_BYTES = 4 * 1024;
|
|
@@ -7,9 +7,37 @@ import { promisify } from 'node:util';
|
|
|
7
7
|
const execute = promisify(execFile);
|
|
8
8
|
const clients = ['codex', 'openclaw', 'trae-work', 'workbuddy', 'dsh', 'claude-code'];
|
|
9
9
|
const contract = 'hellolynk-release-retention-v1';
|
|
10
|
+
// Claude starts every HelloLynk process through one stable copy of the entry, so
|
|
11
|
+
// a command line never names the release that process loaded. The entry records
|
|
12
|
+
// it under releases/.claude-code-processes/<pid>.json (see stable-entry.mjs).
|
|
13
|
+
// Cleanup code from before these records reads only a v1 receipt and stops at
|
|
14
|
+
// any other one before deleting, so a client with a stable entry keeps a v2
|
|
15
|
+
// receipt: an older worker that cleans up after an update deletes nothing.
|
|
16
|
+
const ENTRY = { 'claude-code': ['claude-code', 'hellolynk-claude-code.mjs'] };
|
|
17
|
+
const contractWithEntry = 'hellolynk-release-retention-v2';
|
|
18
|
+
// B255 workers understand v2 but do not read Codex process records.
|
|
19
|
+
const codexContract = 'hellolynk-release-retention-v3';
|
|
20
|
+
const PROCESS_CONTRACT = 'hellolynk-release-process-v1';
|
|
21
|
+
const START_TOLERANCE_MS = 15000;
|
|
22
|
+
export const releaseProcessDirectory = (releasesRoot, client) => path.join(releasesRoot, `.${client}-processes`);
|
|
10
23
|
const failure = code => Object.assign(new Error(code), { code });
|
|
11
24
|
const equal = (a, b) => process.platform === 'win32' ? a.toLowerCase() === b.toLowerCase() : a === b;
|
|
12
25
|
|
|
26
|
+
// A cache MCP keeps an installed prepare function in memory. Record its most
|
|
27
|
+
// recent successful binding, even when its command line names only the cache.
|
|
28
|
+
// A checkout/uninstalled fixture has no immutable release to retain.
|
|
29
|
+
export async function recordCodexReleaseProcess(packageRoot) {
|
|
30
|
+
if (process.platform !== 'win32' || !path.isAbsolute(packageRoot || '')
|
|
31
|
+
|| path.basename(path.dirname(packageRoot)) !== 'releases' || !/^codex-[a-f0-9]{64}$/.test(path.basename(packageRoot))) return;
|
|
32
|
+
try {
|
|
33
|
+
const root = await rootPath(path.dirname(packageRoot));
|
|
34
|
+
const folder = releaseProcessDirectory(root, 'codex');
|
|
35
|
+
await fs.mkdir(folder, { recursive: true });
|
|
36
|
+
await writeReceipt(path.join(folder, `${process.pid}.json`), { contract: PROCESS_CONTRACT, pid: process.pid,
|
|
37
|
+
startedAt: Math.round(performance.timeOrigin), release: path.basename(packageRoot) });
|
|
38
|
+
} catch { /* A missing record defers cleanup; it must not stop communication. */ }
|
|
39
|
+
}
|
|
40
|
+
|
|
13
41
|
async function directory(target) {
|
|
14
42
|
const stat = await fs.lstat(target);
|
|
15
43
|
if (!stat.isDirectory() || stat.isSymbolicLink()) throw failure('release_retention_path_invalid');
|
|
@@ -56,6 +84,68 @@ export async function runningReleaseNames(releasesRoot) {
|
|
|
56
84
|
return names;
|
|
57
85
|
}
|
|
58
86
|
|
|
87
|
+
// The given pids, this installation's stable entry, and Codex cache children:
|
|
88
|
+
// pid, start time and whether it runs the entry. Only processes
|
|
89
|
+
// with a positive pid are listed, and command lines never leave PowerShell.
|
|
90
|
+
export async function entryProcessList(client, releasesRoot, pids = []) {
|
|
91
|
+
if (!ENTRY[client] && client !== 'codex') return [];
|
|
92
|
+
if (process.platform !== 'win32') throw failure('release_retention_process_check_unavailable');
|
|
93
|
+
if (!Array.isArray(pids) || pids.some(pid => !Number.isSafeInteger(pid) || pid <= 0)) throw failure('release_retention_process_check_invalid');
|
|
94
|
+
const root = await rootPath(releasesRoot);
|
|
95
|
+
// This installation's entry only, in its given and canonical spellings:
|
|
96
|
+
// any case, either slash, quoted or not.
|
|
97
|
+
const literal = value => value.split(/[\\/]+/).map(part => part.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')).join('[\\\\/]+');
|
|
98
|
+
const entries = ENTRY[client] ? [...new Set([root, path.resolve(releasesRoot)])].map(value => literal(path.join(path.dirname(value), ...ENTRY[client]))) : [];
|
|
99
|
+
const pattern = (client === 'codex' ? '(?:^|["\\s\\\\/])(?:\\.[\\\\/])?server[\\\\/]mcp-proxy\\.mjs(?=["\\s]|$)'
|
|
100
|
+
: `(?<=^|["\\s])(?:${entries.join('|')})(?=["\\s]|$)`).replaceAll("'", "''");
|
|
101
|
+
// Relative cache entries do not reveal their installation. An older Codex
|
|
102
|
+
// child without a record conservatively delays this client's cleanup until
|
|
103
|
+
// it reconnects through a recording release or exits. Other Node apps do not.
|
|
104
|
+
const parentCheck = client === 'codex' ? "$_.Name -ieq 'node.exe' -and ($codexParents -contains $_.ParentProcessId) -and " : '';
|
|
105
|
+
const script = `$ErrorActionPreference='Stop'; $wanted=@(${pids.join(',')}); $epoch=[datetime]::new(1970,1,1,0,0,0,[DateTimeKind]::Utc); $all=@(Get-CimInstance Win32_Process); $codexParents=@($all | Where-Object { $_.Name -ieq 'Codex.exe' } | ForEach-Object { $_.ProcessId }); $list=@($all | Where-Object { $_.ProcessId -gt 0 } | ForEach-Object { $entry=[bool](${parentCheck}$_.CommandLine -and [regex]::IsMatch($_.CommandLine,'${pattern}','IgnoreCase')); if ($entry -or ($wanted -contains [int64]$_.ProcessId)) { [pscustomobject]@{ pid=[int64]$_.ProcessId; startedAt=$(if ($_.CreationDate) { [int64](($_.CreationDate.ToUniversalTime() - $epoch).TotalMilliseconds) } else { $null }); entry=$entry } } }); ConvertTo-Json -Compress -InputObject $list`;
|
|
106
|
+
const shell = path.join(process.env.SystemRoot || process.env.SYSTEMROOT || 'C:\\Windows', 'System32/WindowsPowerShell/v1.0/powershell.exe');
|
|
107
|
+
const { stdout } = await execute(shell, ['-NoLogo', '-NoProfile', '-NonInteractive', '-Command', script],
|
|
108
|
+
{ windowsHide: true, timeout: 15000, maxBuffer: 1024 * 1024 });
|
|
109
|
+
const list = JSON.parse(stdout.replace(/^\uFEFF/, '').trim() || '[]');
|
|
110
|
+
if (!Array.isArray(list) || list.some(p => !Number.isSafeInteger(p?.pid) || p.pid <= 0 || typeof p.entry !== 'boolean'
|
|
111
|
+
|| (p.startedAt !== null && !Number.isSafeInteger(p.startedAt)))) throw failure('release_retention_process_check_invalid');
|
|
112
|
+
return list;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Releases named by live entry records, and whether a process started through
|
|
116
|
+
// the stable entry has no matching record (one from before records existed).
|
|
117
|
+
// Records of exited or reused pids are removed, so a release can go at the
|
|
118
|
+
// next install once its last process is gone.
|
|
119
|
+
async function entryReleases(releasesRoot, root, client, pattern, dependencies) {
|
|
120
|
+
if (!ENTRY[client] && client !== 'codex') return { names: [], unregistered: false };
|
|
121
|
+
const folder = releaseProcessDirectory(root, client);
|
|
122
|
+
let items = [];
|
|
123
|
+
try {
|
|
124
|
+
await directory(folder);
|
|
125
|
+
items = await fs.readdir(folder, { withFileTypes: true });
|
|
126
|
+
} catch (error) { if (error.code !== 'ENOENT') throw error; }
|
|
127
|
+
const records = items.filter(item => item.isFile() && /^[1-9]\d{0,9}\.json$/.test(item.name))
|
|
128
|
+
.map(item => ({ pid: Number(item.name.slice(0, -5)), file: path.join(folder, item.name) }));
|
|
129
|
+
// The given root too: an entry may be named in the spelling the caller uses, not only the canonical one.
|
|
130
|
+
const processes = await (dependencies.entryProcesses || entryProcessList)(client, releasesRoot, records.map(record => record.pid));
|
|
131
|
+
const live = new Map(processes.map(p => [p.pid, p])), names = new Set(), registered = new Set();
|
|
132
|
+
let unregistered = false;
|
|
133
|
+
for (const { pid, file } of records) {
|
|
134
|
+
const alive = live.get(pid), started = Number.isSafeInteger(alive?.startedAt) ? alive.startedAt : null;
|
|
135
|
+
let record = null;
|
|
136
|
+
try { record = JSON.parse(await fs.readFile(file, 'utf8')); } catch {}
|
|
137
|
+
const valid = record?.contract === PROCESS_CONTRACT && record.pid === pid && Number.isSafeInteger(record.startedAt)
|
|
138
|
+
&& typeof record.release === 'string' && pattern.test(record.release);
|
|
139
|
+
if (valid && started !== null && Math.abs(started - record.startedAt) <= START_TOLERANCE_MS) {
|
|
140
|
+
registered.add(pid); names.add(record.release);
|
|
141
|
+
} else if (!alive || (valid && started !== null)) {
|
|
142
|
+
await fs.rm(file, { force: true }).catch(() => {}); // Exited, or the pid now belongs to a later process.
|
|
143
|
+
} else unregistered = true; // Live, but its record is still being written or its start time is unknown.
|
|
144
|
+
}
|
|
145
|
+
if (processes.some(p => p.entry && !registered.has(p.pid))) unregistered = true;
|
|
146
|
+
return { names: [...names], unregistered };
|
|
147
|
+
}
|
|
148
|
+
|
|
59
149
|
// A stopped on-demand task is still a configuration reference. Keeping only
|
|
60
150
|
// live processes can delete its executable before the next client startup.
|
|
61
151
|
export async function configuredReleaseNames(releasesRoot) {
|
|
@@ -91,14 +181,7 @@ export async function pruneInstalledReleases({ releasesRoot, client, currentRele
|
|
|
91
181
|
};
|
|
92
182
|
const current = nameOf(currentRelease);
|
|
93
183
|
const receiptPath = path.join(root, `.${client}-retention.json`);
|
|
94
|
-
|
|
95
|
-
try {
|
|
96
|
-
const stat = await fs.lstat(receiptPath);
|
|
97
|
-
if (!stat.isFile() || stat.isSymbolicLink() || stat.nlink !== 1 || stat.size > 4096) throw failure('release_retention_receipt_invalid');
|
|
98
|
-
old = JSON.parse(await fs.readFile(receiptPath, 'utf8'));
|
|
99
|
-
if (old?.contract !== contract || old.client !== client || !pattern.test(old.current)
|
|
100
|
-
|| old.previous !== null && !pattern.test(old.previous) || old.current === old.previous) throw failure('release_retention_receipt_invalid');
|
|
101
|
-
} catch (error) { if (error.code !== 'ENOENT') throw error; }
|
|
184
|
+
const old = await readReceipt(receiptPath, client, pattern);
|
|
102
185
|
const supplied = previousRelease === null ? null : nameOf(previousRelease);
|
|
103
186
|
const previous = supplied && supplied !== current ? supplied
|
|
104
187
|
: old?.current === current ? old.previous : old?.current || null;
|
|
@@ -106,21 +189,68 @@ export async function pruneInstalledReleases({ releasesRoot, client, currentRele
|
|
|
106
189
|
for (const name of retained) await directory(path.join(root, name));
|
|
107
190
|
const referenced = new Set([...referencedReleases.map(nameOf),
|
|
108
191
|
...await (dependencies.configuredReleases || configuredReleaseNames)(releasesRoot)]);
|
|
109
|
-
const
|
|
192
|
+
const entry = await entryReleases(releasesRoot, root, client, pattern, dependencies);
|
|
193
|
+
const running = new Set([...await (dependencies.runningReleases || runningReleaseNames)(root), ...entry.names]);
|
|
110
194
|
// Publish before deleting. An interrupted cleanup can retry the exact same
|
|
111
195
|
// pair on same-version reinstall without accidentally dropping its backup.
|
|
112
|
-
|
|
113
|
-
try {
|
|
114
|
-
await fs.writeFile(temporary, JSON.stringify({ contract, client, current, previous }) + '\n', { flag: 'wx', mode: 0o600 });
|
|
115
|
-
await fs.rename(temporary, receiptPath);
|
|
116
|
-
} finally { await fs.unlink(temporary).catch(e => { if (e.code !== 'ENOENT') throw e; }); }
|
|
196
|
+
await writeReceipt(receiptPath, { contract: receiptContract(client), client, current, previous });
|
|
117
197
|
result.retained = retained;
|
|
118
|
-
await removeReleases(root, name => pattern.test(name) && !retained.includes(name), referenced, running, result, dependencies);
|
|
198
|
+
await removeReleases(root, name => pattern.test(name) && !retained.includes(name), referenced, running, result, dependencies, entry.unregistered);
|
|
119
199
|
result.complete = result.deferred.length === 0;
|
|
120
200
|
} catch (error) { result.error = safeCode(error); }
|
|
121
201
|
return result;
|
|
122
202
|
}
|
|
123
203
|
|
|
204
|
+
// Call before switching the binding/entry. An earlier updater cleans up after
|
|
205
|
+
// setup with its own code. Claude needs v2 to stop pre-B255 workers; Codex needs
|
|
206
|
+
// v3 to stop B255 workers that know only Claude records. Preserve the recorded
|
|
207
|
+
// adoption order and resolve with whether the receipt changed. Throw when that
|
|
208
|
+
// cannot be confirmed, even for a cause that passes before the worker reads the
|
|
209
|
+
// receipt (a file another process holds open): the caller then switches nothing.
|
|
210
|
+
// currentRelease, the release the install starts now, is recorded only when
|
|
211
|
+
// there is no receipt yet.
|
|
212
|
+
export async function protectRetentionReceipt({ releasesRoot, client, currentRelease }) {
|
|
213
|
+
if (!ENTRY[client] && client !== 'codex') throw failure('release_retention_client_invalid');
|
|
214
|
+
const root = await rootPath(releasesRoot), pattern = new RegExp(`^${client}-[a-f0-9]{64}$`);
|
|
215
|
+
const receiptPath = path.join(root, `.${client}-retention.json`);
|
|
216
|
+
const old = await readReceipt(receiptPath, client, pattern);
|
|
217
|
+
if (old?.contract === receiptContract(client)) return false;
|
|
218
|
+
let current = old?.current;
|
|
219
|
+
if (!current) {
|
|
220
|
+
if (typeof currentRelease !== 'string' || !path.isAbsolute(currentRelease) || !pattern.test(path.basename(currentRelease))
|
|
221
|
+
|| ![root, path.resolve(releasesRoot)].some(p => equal(path.dirname(path.resolve(currentRelease)), p))) throw failure('release_retention_target_invalid');
|
|
222
|
+
current = path.basename(currentRelease);
|
|
223
|
+
await directory(path.join(root, current));
|
|
224
|
+
}
|
|
225
|
+
await writeReceipt(receiptPath, { contract: receiptContract(client), client, current, previous: old ? old.previous : null });
|
|
226
|
+
return true;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
const receiptContract = client => client === 'codex' ? codexContract : ENTRY[client] ? contractWithEntry : contract;
|
|
230
|
+
|
|
231
|
+
async function readReceipt(receiptPath, client, pattern) {
|
|
232
|
+
let old = null;
|
|
233
|
+
try {
|
|
234
|
+
const stat = await fs.lstat(receiptPath);
|
|
235
|
+
if (!stat.isFile() || stat.isSymbolicLink() || stat.nlink !== 1 || stat.size > 4096) throw failure('release_retention_receipt_invalid');
|
|
236
|
+
old = JSON.parse(await fs.readFile(receiptPath, 'utf8'));
|
|
237
|
+
if (![contract, contractWithEntry, ...(client === 'codex' ? [codexContract] : [])].includes(old?.contract) || old.client !== client || !pattern.test(old.current)
|
|
238
|
+
|| old.previous !== null && !pattern.test(old.previous) || old.current === old.previous) throw failure('release_retention_receipt_invalid');
|
|
239
|
+
} catch (error) {
|
|
240
|
+
if (error.code === 'ENOENT') return null;
|
|
241
|
+
throw error.code ? error : failure('release_retention_receipt_invalid');
|
|
242
|
+
}
|
|
243
|
+
return old;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
async function writeReceipt(receiptPath, receipt) {
|
|
247
|
+
const temporary = `${receiptPath}.${crypto.randomUUID()}.tmp`;
|
|
248
|
+
try {
|
|
249
|
+
await fs.writeFile(temporary, JSON.stringify(receipt) + '\n', { flag: 'wx', mode: 0o600 });
|
|
250
|
+
await fs.rename(temporary, receiptPath);
|
|
251
|
+
} finally { await fs.unlink(temporary).catch(e => { if (e.code !== 'ENOENT') throw e; }); }
|
|
252
|
+
}
|
|
253
|
+
|
|
124
254
|
// Uninstall keeps no release. One a process or scheduled task still uses is
|
|
125
255
|
// left for the next install or uninstall, like any other deferred release.
|
|
126
256
|
export async function removeInstalledReleases({ releasesRoot, client }, dependencies = {}) {
|
|
@@ -130,19 +260,27 @@ export async function removeInstalledReleases({ releasesRoot, client }, dependen
|
|
|
130
260
|
try { await fs.lstat(releasesRoot); } catch (error) { if (error.code === 'ENOENT') return { ...result, complete: true }; throw error; }
|
|
131
261
|
const root = await rootPath(releasesRoot), pattern = new RegExp(`^${client}-[a-f0-9]{64}$`);
|
|
132
262
|
const referenced = new Set(await (dependencies.configuredReleases || configuredReleaseNames)(releasesRoot));
|
|
133
|
-
const
|
|
134
|
-
|
|
135
|
-
|
|
263
|
+
const entry = await entryReleases(releasesRoot, root, client, pattern, dependencies);
|
|
264
|
+
const running = new Set([...await (dependencies.runningReleases || runningReleaseNames)(root), ...entry.names]);
|
|
265
|
+
await removeReleases(root, name => pattern.test(name), referenced, running, result, dependencies, entry.unregistered);
|
|
266
|
+
if (!result.deferred.length) {
|
|
267
|
+
await fs.rm(path.join(root, `.${client}-retention.json`), { force: true });
|
|
268
|
+
// entryReleases checked above that this is a folder in the releases root.
|
|
269
|
+
if (ENTRY[client] || client === 'codex') await fs.rm(releaseProcessDirectory(root, client), { recursive: true, force: true });
|
|
270
|
+
}
|
|
136
271
|
result.complete = result.deferred.length === 0;
|
|
137
272
|
} catch (error) { result.error = safeCode(error); }
|
|
138
273
|
return result;
|
|
139
274
|
}
|
|
140
275
|
|
|
141
|
-
|
|
276
|
+
// An unregistered entry process may run any release of its client, so then
|
|
277
|
+
// none is removed until it exits.
|
|
278
|
+
async function removeReleases(root, selected, referenced, running, result, dependencies, unregistered = false) {
|
|
142
279
|
for (const name of await fs.readdir(root)) {
|
|
143
280
|
if (!selected(name)) continue;
|
|
144
281
|
if (referenced.has(name)) { result.deferred.push({ name, reason: 'release_still_referenced' }); continue; }
|
|
145
282
|
if (running.has(name)) { result.deferred.push({ name, reason: 'release_in_use' }); continue; }
|
|
283
|
+
if (unregistered) { result.deferred.push({ name, reason: 'release_in_use_unregistered' }); continue; }
|
|
146
284
|
try {
|
|
147
285
|
// The final absolute target is a checked direct child of the canonical
|
|
148
286
|
// releases root; never follow a junction inside an obsolete package.
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"contract": "hellolynk-client-npm-pack-manifest-v1",
|
|
3
3
|
"client": "workbuddy",
|
|
4
4
|
"packageName": "@hellolynk-ai/workbuddy-mcp",
|
|
5
|
-
"version": "0.3.
|
|
5
|
+
"version": "0.3.98",
|
|
6
6
|
"workbench": {
|
|
7
7
|
"path": "runtime/workbench/hellolynk-workbench-build.json",
|
|
8
8
|
"contract": "hellolynk-shared-workbench-build-v1",
|
|
@@ -12,8 +12,8 @@
|
|
|
12
12
|
"files": [
|
|
13
13
|
{
|
|
14
14
|
"path": "bin/hellolynk-client-setup.mjs",
|
|
15
|
-
"bytes":
|
|
16
|
-
"sha256": "
|
|
15
|
+
"bytes": 141769,
|
|
16
|
+
"sha256": "0bb0706c06bd193cfa37007dd95e3107b52aacb0a7ebaec2249b153ff7dd772b"
|
|
17
17
|
},
|
|
18
18
|
{
|
|
19
19
|
"path": "bin/hellolynk-mcp-config-shape.mjs",
|
|
@@ -167,8 +167,8 @@
|
|
|
167
167
|
},
|
|
168
168
|
{
|
|
169
169
|
"path": "clients/core/hellolynk-native-addressing-tools.cjs",
|
|
170
|
-
"bytes":
|
|
171
|
-
"sha256": "
|
|
170
|
+
"bytes": 19674,
|
|
171
|
+
"sha256": "cce89fa33dbe630a78d77843919a8e4b0c12f3482e754f783e6ff038b81929c4"
|
|
172
172
|
},
|
|
173
173
|
{
|
|
174
174
|
"path": "clients/core/hellolynk-native-conversations.mjs",
|
|
@@ -223,7 +223,7 @@
|
|
|
223
223
|
{
|
|
224
224
|
"path": "clients/core/hellolynk-neutral-host-process.mjs",
|
|
225
225
|
"bytes": 229535,
|
|
226
|
-
"sha256": "
|
|
226
|
+
"sha256": "5e5b9f535331444d284b2e62cc2593d6279b8a30332c82f4f85c7ff25e2f3727"
|
|
227
227
|
},
|
|
228
228
|
{
|
|
229
229
|
"path": "clients/core/hellolynk-neutral-host-store-adapters.mjs",
|
|
@@ -247,8 +247,8 @@
|
|
|
247
247
|
},
|
|
248
248
|
{
|
|
249
249
|
"path": "clients/core/hellolynk-release-retention.mjs",
|
|
250
|
-
"bytes":
|
|
251
|
-
"sha256": "
|
|
250
|
+
"bytes": 20922,
|
|
251
|
+
"sha256": "9f8b5b97eee7530dc8ef965b0df6a19065b06012255100977d8abb17ce50d204"
|
|
252
252
|
},
|
|
253
253
|
{
|
|
254
254
|
"path": "clients/core/hellolynk-runtime-safety.cjs",
|
|
@@ -303,7 +303,7 @@
|
|
|
303
303
|
{
|
|
304
304
|
"path": "integrations/workbuddy/package.json",
|
|
305
305
|
"bytes": 1124,
|
|
306
|
-
"sha256": "
|
|
306
|
+
"sha256": "b213e8830b815cd7033231766874f3b0156fa3acad5bcf4853125e8c73bb6902"
|
|
307
307
|
},
|
|
308
308
|
{
|
|
309
309
|
"path": "integrations/workbuddy/server/host-lifecycle.mjs",
|
|
@@ -413,12 +413,12 @@
|
|
|
413
413
|
{
|
|
414
414
|
"path": "package.json",
|
|
415
415
|
"bytes": 2018,
|
|
416
|
-
"sha256": "
|
|
416
|
+
"sha256": "a427edcc3907e7a38f9f1ce64966fb5330fdaddbe899cfee770289fa38ac12e3"
|
|
417
417
|
},
|
|
418
418
|
{
|
|
419
419
|
"path": "README.md",
|
|
420
|
-
"bytes":
|
|
421
|
-
"sha256": "
|
|
420
|
+
"bytes": 4610,
|
|
421
|
+
"sha256": "502d39787b2007307b9f32872f17b72e90cf4927cacfa33e5dc3f7f04f0bade9"
|
|
422
422
|
},
|
|
423
423
|
{
|
|
424
424
|
"path": "runtime/connect-activate.mjs",
|
|
@@ -577,8 +577,8 @@
|
|
|
577
577
|
},
|
|
578
578
|
{
|
|
579
579
|
"path": "runtime/core/hellolynk-native-addressing-tools.cjs",
|
|
580
|
-
"bytes":
|
|
581
|
-
"sha256": "
|
|
580
|
+
"bytes": 19443,
|
|
581
|
+
"sha256": "f4bd81b3d03277e28955a62409383a0c4072c6212567f71425df4e18ece75d63"
|
|
582
582
|
},
|
|
583
583
|
{
|
|
584
584
|
"path": "runtime/core/hellolynk-native-conversations.mjs",
|
|
@@ -628,7 +628,7 @@
|
|
|
628
628
|
{
|
|
629
629
|
"path": "runtime/core/hellolynk-neutral-host-process.mjs",
|
|
630
630
|
"bytes": 225161,
|
|
631
|
-
"sha256": "
|
|
631
|
+
"sha256": "af6cb6585baae477f87ee880bd044dffb4c7f71667bfa78bcbf0d4d20e7483af"
|
|
632
632
|
},
|
|
633
633
|
{
|
|
634
634
|
"path": "runtime/core/hellolynk-neutral-host-store-adapters.mjs",
|
|
@@ -652,8 +652,8 @@
|
|
|
652
652
|
},
|
|
653
653
|
{
|
|
654
654
|
"path": "runtime/core/hellolynk-release-retention.mjs",
|
|
655
|
-
"bytes":
|
|
656
|
-
"sha256": "
|
|
655
|
+
"bytes": 20624,
|
|
656
|
+
"sha256": "9b02a42a510fa5ef4a251b6e675f9ccc60f20b718d17c1617027cd048c5634dd"
|
|
657
657
|
},
|
|
658
658
|
{
|
|
659
659
|
"path": "runtime/core/hellolynk-runtime-safety.cjs",
|
|
@@ -688,12 +688,12 @@
|
|
|
688
688
|
{
|
|
689
689
|
"path": "runtime/neutral-host-release-manifest.json",
|
|
690
690
|
"bytes": 11228,
|
|
691
|
-
"sha256": "
|
|
691
|
+
"sha256": "8171d1ac9ba90e45f3cf9cc7dab5f4c05a283101c2457e4c5e8870ae54269eba"
|
|
692
692
|
},
|
|
693
693
|
{
|
|
694
694
|
"path": "runtime/neutral-host-release-pin.json",
|
|
695
695
|
"bytes": 146,
|
|
696
|
-
"sha256": "
|
|
696
|
+
"sha256": "a5cc48363f9cb8ff174f02d6cb20f95e314c7520f89eab5027f47a41a3017e2c"
|
|
697
697
|
},
|
|
698
698
|
{
|
|
699
699
|
"path": "runtime/platform/windows/configure-agent.ps1",
|
|
@@ -873,12 +873,12 @@
|
|
|
873
873
|
{
|
|
874
874
|
"path": "workbuddy-package-manifest.json",
|
|
875
875
|
"bytes": 22134,
|
|
876
|
-
"sha256": "
|
|
876
|
+
"sha256": "fb956894f5beca013d7b0ae19353475cdf93c80b0ed166fde06e0a6dc2eb7a2b"
|
|
877
877
|
},
|
|
878
878
|
{
|
|
879
879
|
"path": "workbuddy-package-pin.json",
|
|
880
880
|
"bytes": 143,
|
|
881
|
-
"sha256": "
|
|
881
|
+
"sha256": "ab7c4123868f507d33f52eef1e3506e52ded6a514396116ca1f68960b176ddb9"
|
|
882
882
|
}
|
|
883
883
|
]
|
|
884
884
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hellolynk-ai/workbuddy-mcp",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.98",
|
|
4
4
|
"description": "HelloLynk Messaging for WorkBuddy: open conversations and let your AI message other people's AI assistants.",
|
|
5
5
|
"homepage": "https://hellolynk.com",
|
|
6
6
|
"repository": {
|
|
@@ -18,7 +18,7 @@ const conversationGuidance = "HelloLynk 是本人授权的 AI 通讯。接着已
|
|
|
18
18
|
// What every client shows for the shared tools; nativeTool applies it.
|
|
19
19
|
const toolText = Object.freeze({
|
|
20
20
|
hellolynk_reply_authorized_message: { title: "回复来信", description: "接着当前对话的一封来信发送;不接手其他对话。" },
|
|
21
|
-
hellolynk_send_authorized_message: { title: "发起通信", description: "向本人授权的联系人发起新通信。contact 填对方名字;本人点名了对话时,targetConversationTitle
|
|
21
|
+
hellolynk_send_authorized_message: { title: "发起通信", description: "向本人授权的联系人发起新通信。contact 填对方名字;本人点名了对话时,targetConversationTitle 填完整标题。未指定对话的新通信默认送到对方的 HelloLynk 独立会话;要继续已有来往,用 hellolynk_reply_authorized_message 回复原信。" },
|
|
22
22
|
hellolynk_list_authorized_contacts: { title: "查找联系人", description: queryDescription },
|
|
23
23
|
hellolynk_claim_message: { title: "读取来信", description: "按自动提醒里的 batchId 一次读取整批来信(合计不超过 2 万字);手动读单条传 localMessageId 和 conversationKey。" },
|
|
24
24
|
hellolynk_list_pending_messages: { title: "待处理来信", description: "列出当前对话等待 AI 处理的来信,不含正文。" },
|
|
@@ -34,7 +34,7 @@ export const HELLOLYNK_NEUTRAL_HOST_PROCESS_CONTRACT = "hellolynk-neutral-host-p
|
|
|
34
34
|
export const HELLOLYNK_NEUTRAL_HOST_DISCOVERY_CONTRACT = "hellolynk-neutral-host-discovery-v1";
|
|
35
35
|
// Raised with every release batch, together with the six client versions. A Host reports it
|
|
36
36
|
// in its health; the higher release stays and the lower one makes room.
|
|
37
|
-
export const HELLOLYNK_HOST_RELEASE_ORDINAL =
|
|
37
|
+
export const HELLOLYNK_HOST_RELEASE_ORDINAL = 14;
|
|
38
38
|
|
|
39
39
|
const INSTALLATION_LOCK_CONTRACT = "hellolynk-neutral-host-installation-lock-v2";
|
|
40
40
|
const INSTALLATION_LOCK_MAX_BYTES = 4 * 1024;
|
|
@@ -7,9 +7,37 @@ import { promisify } from 'node:util';
|
|
|
7
7
|
const execute = promisify(execFile);
|
|
8
8
|
const clients = ['codex', 'openclaw', 'trae-work', 'workbuddy', 'dsh', 'claude-code'];
|
|
9
9
|
const contract = 'hellolynk-release-retention-v1';
|
|
10
|
+
// Claude starts every HelloLynk process through one stable copy of the entry, so
|
|
11
|
+
// a command line never names the release that process loaded. The entry records
|
|
12
|
+
// it under releases/.claude-code-processes/<pid>.json (see stable-entry.mjs).
|
|
13
|
+
// Cleanup code from before these records reads only a v1 receipt and stops at
|
|
14
|
+
// any other one before deleting, so a client with a stable entry keeps a v2
|
|
15
|
+
// receipt: an older worker that cleans up after an update deletes nothing.
|
|
16
|
+
const ENTRY = { 'claude-code': ['claude-code', 'hellolynk-claude-code.mjs'] };
|
|
17
|
+
const contractWithEntry = 'hellolynk-release-retention-v2';
|
|
18
|
+
// B255 workers understand v2 but do not read Codex process records.
|
|
19
|
+
const codexContract = 'hellolynk-release-retention-v3';
|
|
20
|
+
const PROCESS_CONTRACT = 'hellolynk-release-process-v1';
|
|
21
|
+
const START_TOLERANCE_MS = 15000;
|
|
22
|
+
export const releaseProcessDirectory = (releasesRoot, client) => path.join(releasesRoot, `.${client}-processes`);
|
|
10
23
|
const failure = code => Object.assign(new Error(code), { code });
|
|
11
24
|
const equal = (a, b) => process.platform === 'win32' ? a.toLowerCase() === b.toLowerCase() : a === b;
|
|
12
25
|
|
|
26
|
+
// A cache MCP keeps an installed prepare function in memory. Record its most
|
|
27
|
+
// recent successful binding, even when its command line names only the cache.
|
|
28
|
+
// A checkout/uninstalled fixture has no immutable release to retain.
|
|
29
|
+
export async function recordCodexReleaseProcess(packageRoot) {
|
|
30
|
+
if (process.platform !== 'win32' || !path.isAbsolute(packageRoot || '')
|
|
31
|
+
|| path.basename(path.dirname(packageRoot)) !== 'releases' || !/^codex-[a-f0-9]{64}$/.test(path.basename(packageRoot))) return;
|
|
32
|
+
try {
|
|
33
|
+
const root = await rootPath(path.dirname(packageRoot));
|
|
34
|
+
const folder = releaseProcessDirectory(root, 'codex');
|
|
35
|
+
await fs.mkdir(folder, { recursive: true });
|
|
36
|
+
await writeReceipt(path.join(folder, `${process.pid}.json`), { contract: PROCESS_CONTRACT, pid: process.pid,
|
|
37
|
+
startedAt: Math.round(performance.timeOrigin), release: path.basename(packageRoot) });
|
|
38
|
+
} catch { /* A missing record defers cleanup; it must not stop communication. */ }
|
|
39
|
+
}
|
|
40
|
+
|
|
13
41
|
async function directory(target) {
|
|
14
42
|
const stat = await fs.lstat(target);
|
|
15
43
|
if (!stat.isDirectory() || stat.isSymbolicLink()) throw failure('release_retention_path_invalid');
|
|
@@ -56,6 +84,68 @@ export async function runningReleaseNames(releasesRoot) {
|
|
|
56
84
|
return names;
|
|
57
85
|
}
|
|
58
86
|
|
|
87
|
+
// The given pids, this installation's stable entry, and Codex cache children:
|
|
88
|
+
// pid, start time and whether it runs the entry. Only processes
|
|
89
|
+
// with a positive pid are listed, and command lines never leave PowerShell.
|
|
90
|
+
export async function entryProcessList(client, releasesRoot, pids = []) {
|
|
91
|
+
if (!ENTRY[client] && client !== 'codex') return [];
|
|
92
|
+
if (process.platform !== 'win32') throw failure('release_retention_process_check_unavailable');
|
|
93
|
+
if (!Array.isArray(pids) || pids.some(pid => !Number.isSafeInteger(pid) || pid <= 0)) throw failure('release_retention_process_check_invalid');
|
|
94
|
+
const root = await rootPath(releasesRoot);
|
|
95
|
+
// This installation's entry only, in its given and canonical spellings:
|
|
96
|
+
// any case, either slash, quoted or not.
|
|
97
|
+
const literal = value => value.split(/[\\/]+/).map(part => part.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')).join('[\\\\/]+');
|
|
98
|
+
const entries = ENTRY[client] ? [...new Set([root, path.resolve(releasesRoot)])].map(value => literal(path.join(path.dirname(value), ...ENTRY[client]))) : [];
|
|
99
|
+
const pattern = (client === 'codex' ? '(?:^|["\\s\\\\/])(?:\\.[\\\\/])?server[\\\\/]mcp-proxy\\.mjs(?=["\\s]|$)'
|
|
100
|
+
: `(?<=^|["\\s])(?:${entries.join('|')})(?=["\\s]|$)`).replaceAll("'", "''");
|
|
101
|
+
// Relative cache entries do not reveal their installation. An older Codex
|
|
102
|
+
// child without a record conservatively delays this client's cleanup until
|
|
103
|
+
// it reconnects through a recording release or exits. Other Node apps do not.
|
|
104
|
+
const parentCheck = client === 'codex' ? "$_.Name -ieq 'node.exe' -and ($codexParents -contains $_.ParentProcessId) -and " : '';
|
|
105
|
+
const script = `$ErrorActionPreference='Stop'; $wanted=@(${pids.join(',')}); $epoch=[datetime]::new(1970,1,1,0,0,0,[DateTimeKind]::Utc); $all=@(Get-CimInstance Win32_Process); $codexParents=@($all | Where-Object { $_.Name -ieq 'Codex.exe' } | ForEach-Object { $_.ProcessId }); $list=@($all | Where-Object { $_.ProcessId -gt 0 } | ForEach-Object { $entry=[bool](${parentCheck}$_.CommandLine -and [regex]::IsMatch($_.CommandLine,'${pattern}','IgnoreCase')); if ($entry -or ($wanted -contains [int64]$_.ProcessId)) { [pscustomobject]@{ pid=[int64]$_.ProcessId; startedAt=$(if ($_.CreationDate) { [int64](($_.CreationDate.ToUniversalTime() - $epoch).TotalMilliseconds) } else { $null }); entry=$entry } } }); ConvertTo-Json -Compress -InputObject $list`;
|
|
106
|
+
const shell = path.join(process.env.SystemRoot || process.env.SYSTEMROOT || 'C:\\Windows', 'System32/WindowsPowerShell/v1.0/powershell.exe');
|
|
107
|
+
const { stdout } = await execute(shell, ['-NoLogo', '-NoProfile', '-NonInteractive', '-Command', script],
|
|
108
|
+
{ windowsHide: true, timeout: 15000, maxBuffer: 1024 * 1024 });
|
|
109
|
+
const list = JSON.parse(stdout.replace(/^\uFEFF/, '').trim() || '[]');
|
|
110
|
+
if (!Array.isArray(list) || list.some(p => !Number.isSafeInteger(p?.pid) || p.pid <= 0 || typeof p.entry !== 'boolean'
|
|
111
|
+
|| (p.startedAt !== null && !Number.isSafeInteger(p.startedAt)))) throw failure('release_retention_process_check_invalid');
|
|
112
|
+
return list;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Releases named by live entry records, and whether a process started through
|
|
116
|
+
// the stable entry has no matching record (one from before records existed).
|
|
117
|
+
// Records of exited or reused pids are removed, so a release can go at the
|
|
118
|
+
// next install once its last process is gone.
|
|
119
|
+
async function entryReleases(releasesRoot, root, client, pattern, dependencies) {
|
|
120
|
+
if (!ENTRY[client] && client !== 'codex') return { names: [], unregistered: false };
|
|
121
|
+
const folder = releaseProcessDirectory(root, client);
|
|
122
|
+
let items = [];
|
|
123
|
+
try {
|
|
124
|
+
await directory(folder);
|
|
125
|
+
items = await fs.readdir(folder, { withFileTypes: true });
|
|
126
|
+
} catch (error) { if (error.code !== 'ENOENT') throw error; }
|
|
127
|
+
const records = items.filter(item => item.isFile() && /^[1-9]\d{0,9}\.json$/.test(item.name))
|
|
128
|
+
.map(item => ({ pid: Number(item.name.slice(0, -5)), file: path.join(folder, item.name) }));
|
|
129
|
+
// The given root too: an entry may be named in the spelling the caller uses, not only the canonical one.
|
|
130
|
+
const processes = await (dependencies.entryProcesses || entryProcessList)(client, releasesRoot, records.map(record => record.pid));
|
|
131
|
+
const live = new Map(processes.map(p => [p.pid, p])), names = new Set(), registered = new Set();
|
|
132
|
+
let unregistered = false;
|
|
133
|
+
for (const { pid, file } of records) {
|
|
134
|
+
const alive = live.get(pid), started = Number.isSafeInteger(alive?.startedAt) ? alive.startedAt : null;
|
|
135
|
+
let record = null;
|
|
136
|
+
try { record = JSON.parse(await fs.readFile(file, 'utf8')); } catch {}
|
|
137
|
+
const valid = record?.contract === PROCESS_CONTRACT && record.pid === pid && Number.isSafeInteger(record.startedAt)
|
|
138
|
+
&& typeof record.release === 'string' && pattern.test(record.release);
|
|
139
|
+
if (valid && started !== null && Math.abs(started - record.startedAt) <= START_TOLERANCE_MS) {
|
|
140
|
+
registered.add(pid); names.add(record.release);
|
|
141
|
+
} else if (!alive || (valid && started !== null)) {
|
|
142
|
+
await fs.rm(file, { force: true }).catch(() => {}); // Exited, or the pid now belongs to a later process.
|
|
143
|
+
} else unregistered = true; // Live, but its record is still being written or its start time is unknown.
|
|
144
|
+
}
|
|
145
|
+
if (processes.some(p => p.entry && !registered.has(p.pid))) unregistered = true;
|
|
146
|
+
return { names: [...names], unregistered };
|
|
147
|
+
}
|
|
148
|
+
|
|
59
149
|
// A stopped on-demand task is still a configuration reference. Keeping only
|
|
60
150
|
// live processes can delete its executable before the next client startup.
|
|
61
151
|
export async function configuredReleaseNames(releasesRoot) {
|
|
@@ -91,14 +181,7 @@ export async function pruneInstalledReleases({ releasesRoot, client, currentRele
|
|
|
91
181
|
};
|
|
92
182
|
const current = nameOf(currentRelease);
|
|
93
183
|
const receiptPath = path.join(root, `.${client}-retention.json`);
|
|
94
|
-
|
|
95
|
-
try {
|
|
96
|
-
const stat = await fs.lstat(receiptPath);
|
|
97
|
-
if (!stat.isFile() || stat.isSymbolicLink() || stat.nlink !== 1 || stat.size > 4096) throw failure('release_retention_receipt_invalid');
|
|
98
|
-
old = JSON.parse(await fs.readFile(receiptPath, 'utf8'));
|
|
99
|
-
if (old?.contract !== contract || old.client !== client || !pattern.test(old.current)
|
|
100
|
-
|| old.previous !== null && !pattern.test(old.previous) || old.current === old.previous) throw failure('release_retention_receipt_invalid');
|
|
101
|
-
} catch (error) { if (error.code !== 'ENOENT') throw error; }
|
|
184
|
+
const old = await readReceipt(receiptPath, client, pattern);
|
|
102
185
|
const supplied = previousRelease === null ? null : nameOf(previousRelease);
|
|
103
186
|
const previous = supplied && supplied !== current ? supplied
|
|
104
187
|
: old?.current === current ? old.previous : old?.current || null;
|
|
@@ -106,21 +189,68 @@ export async function pruneInstalledReleases({ releasesRoot, client, currentRele
|
|
|
106
189
|
for (const name of retained) await directory(path.join(root, name));
|
|
107
190
|
const referenced = new Set([...referencedReleases.map(nameOf),
|
|
108
191
|
...await (dependencies.configuredReleases || configuredReleaseNames)(releasesRoot)]);
|
|
109
|
-
const
|
|
192
|
+
const entry = await entryReleases(releasesRoot, root, client, pattern, dependencies);
|
|
193
|
+
const running = new Set([...await (dependencies.runningReleases || runningReleaseNames)(root), ...entry.names]);
|
|
110
194
|
// Publish before deleting. An interrupted cleanup can retry the exact same
|
|
111
195
|
// pair on same-version reinstall without accidentally dropping its backup.
|
|
112
|
-
|
|
113
|
-
try {
|
|
114
|
-
await fs.writeFile(temporary, JSON.stringify({ contract, client, current, previous }) + '\n', { flag: 'wx', mode: 0o600 });
|
|
115
|
-
await fs.rename(temporary, receiptPath);
|
|
116
|
-
} finally { await fs.unlink(temporary).catch(e => { if (e.code !== 'ENOENT') throw e; }); }
|
|
196
|
+
await writeReceipt(receiptPath, { contract: receiptContract(client), client, current, previous });
|
|
117
197
|
result.retained = retained;
|
|
118
|
-
await removeReleases(root, name => pattern.test(name) && !retained.includes(name), referenced, running, result, dependencies);
|
|
198
|
+
await removeReleases(root, name => pattern.test(name) && !retained.includes(name), referenced, running, result, dependencies, entry.unregistered);
|
|
119
199
|
result.complete = result.deferred.length === 0;
|
|
120
200
|
} catch (error) { result.error = safeCode(error); }
|
|
121
201
|
return result;
|
|
122
202
|
}
|
|
123
203
|
|
|
204
|
+
// Call before switching the binding/entry. An earlier updater cleans up after
|
|
205
|
+
// setup with its own code. Claude needs v2 to stop pre-B255 workers; Codex needs
|
|
206
|
+
// v3 to stop B255 workers that know only Claude records. Preserve the recorded
|
|
207
|
+
// adoption order and resolve with whether the receipt changed. Throw when that
|
|
208
|
+
// cannot be confirmed, even for a cause that passes before the worker reads the
|
|
209
|
+
// receipt (a file another process holds open): the caller then switches nothing.
|
|
210
|
+
// currentRelease, the release the install starts now, is recorded only when
|
|
211
|
+
// there is no receipt yet.
|
|
212
|
+
export async function protectRetentionReceipt({ releasesRoot, client, currentRelease }) {
|
|
213
|
+
if (!ENTRY[client] && client !== 'codex') throw failure('release_retention_client_invalid');
|
|
214
|
+
const root = await rootPath(releasesRoot), pattern = new RegExp(`^${client}-[a-f0-9]{64}$`);
|
|
215
|
+
const receiptPath = path.join(root, `.${client}-retention.json`);
|
|
216
|
+
const old = await readReceipt(receiptPath, client, pattern);
|
|
217
|
+
if (old?.contract === receiptContract(client)) return false;
|
|
218
|
+
let current = old?.current;
|
|
219
|
+
if (!current) {
|
|
220
|
+
if (typeof currentRelease !== 'string' || !path.isAbsolute(currentRelease) || !pattern.test(path.basename(currentRelease))
|
|
221
|
+
|| ![root, path.resolve(releasesRoot)].some(p => equal(path.dirname(path.resolve(currentRelease)), p))) throw failure('release_retention_target_invalid');
|
|
222
|
+
current = path.basename(currentRelease);
|
|
223
|
+
await directory(path.join(root, current));
|
|
224
|
+
}
|
|
225
|
+
await writeReceipt(receiptPath, { contract: receiptContract(client), client, current, previous: old ? old.previous : null });
|
|
226
|
+
return true;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
const receiptContract = client => client === 'codex' ? codexContract : ENTRY[client] ? contractWithEntry : contract;
|
|
230
|
+
|
|
231
|
+
async function readReceipt(receiptPath, client, pattern) {
|
|
232
|
+
let old = null;
|
|
233
|
+
try {
|
|
234
|
+
const stat = await fs.lstat(receiptPath);
|
|
235
|
+
if (!stat.isFile() || stat.isSymbolicLink() || stat.nlink !== 1 || stat.size > 4096) throw failure('release_retention_receipt_invalid');
|
|
236
|
+
old = JSON.parse(await fs.readFile(receiptPath, 'utf8'));
|
|
237
|
+
if (![contract, contractWithEntry, ...(client === 'codex' ? [codexContract] : [])].includes(old?.contract) || old.client !== client || !pattern.test(old.current)
|
|
238
|
+
|| old.previous !== null && !pattern.test(old.previous) || old.current === old.previous) throw failure('release_retention_receipt_invalid');
|
|
239
|
+
} catch (error) {
|
|
240
|
+
if (error.code === 'ENOENT') return null;
|
|
241
|
+
throw error.code ? error : failure('release_retention_receipt_invalid');
|
|
242
|
+
}
|
|
243
|
+
return old;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
async function writeReceipt(receiptPath, receipt) {
|
|
247
|
+
const temporary = `${receiptPath}.${crypto.randomUUID()}.tmp`;
|
|
248
|
+
try {
|
|
249
|
+
await fs.writeFile(temporary, JSON.stringify(receipt) + '\n', { flag: 'wx', mode: 0o600 });
|
|
250
|
+
await fs.rename(temporary, receiptPath);
|
|
251
|
+
} finally { await fs.unlink(temporary).catch(e => { if (e.code !== 'ENOENT') throw e; }); }
|
|
252
|
+
}
|
|
253
|
+
|
|
124
254
|
// Uninstall keeps no release. One a process or scheduled task still uses is
|
|
125
255
|
// left for the next install or uninstall, like any other deferred release.
|
|
126
256
|
export async function removeInstalledReleases({ releasesRoot, client }, dependencies = {}) {
|
|
@@ -130,19 +260,27 @@ export async function removeInstalledReleases({ releasesRoot, client }, dependen
|
|
|
130
260
|
try { await fs.lstat(releasesRoot); } catch (error) { if (error.code === 'ENOENT') return { ...result, complete: true }; throw error; }
|
|
131
261
|
const root = await rootPath(releasesRoot), pattern = new RegExp(`^${client}-[a-f0-9]{64}$`);
|
|
132
262
|
const referenced = new Set(await (dependencies.configuredReleases || configuredReleaseNames)(releasesRoot));
|
|
133
|
-
const
|
|
134
|
-
|
|
135
|
-
|
|
263
|
+
const entry = await entryReleases(releasesRoot, root, client, pattern, dependencies);
|
|
264
|
+
const running = new Set([...await (dependencies.runningReleases || runningReleaseNames)(root), ...entry.names]);
|
|
265
|
+
await removeReleases(root, name => pattern.test(name), referenced, running, result, dependencies, entry.unregistered);
|
|
266
|
+
if (!result.deferred.length) {
|
|
267
|
+
await fs.rm(path.join(root, `.${client}-retention.json`), { force: true });
|
|
268
|
+
// entryReleases checked above that this is a folder in the releases root.
|
|
269
|
+
if (ENTRY[client] || client === 'codex') await fs.rm(releaseProcessDirectory(root, client), { recursive: true, force: true });
|
|
270
|
+
}
|
|
136
271
|
result.complete = result.deferred.length === 0;
|
|
137
272
|
} catch (error) { result.error = safeCode(error); }
|
|
138
273
|
return result;
|
|
139
274
|
}
|
|
140
275
|
|
|
141
|
-
|
|
276
|
+
// An unregistered entry process may run any release of its client, so then
|
|
277
|
+
// none is removed until it exits.
|
|
278
|
+
async function removeReleases(root, selected, referenced, running, result, dependencies, unregistered = false) {
|
|
142
279
|
for (const name of await fs.readdir(root)) {
|
|
143
280
|
if (!selected(name)) continue;
|
|
144
281
|
if (referenced.has(name)) { result.deferred.push({ name, reason: 'release_still_referenced' }); continue; }
|
|
145
282
|
if (running.has(name)) { result.deferred.push({ name, reason: 'release_in_use' }); continue; }
|
|
283
|
+
if (unregistered) { result.deferred.push({ name, reason: 'release_in_use_unregistered' }); continue; }
|
|
146
284
|
try {
|
|
147
285
|
// The final absolute target is a checked direct child of the canonical
|
|
148
286
|
// releases root; never follow a junction inside an obsolete package.
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
},
|
|
49
49
|
{
|
|
50
50
|
"path": "core/hellolynk-release-retention.mjs",
|
|
51
|
-
"sha256": "
|
|
51
|
+
"sha256": "9b02a42a510fa5ef4a251b6e675f9ccc60f20b718d17c1617027cd048c5634dd"
|
|
52
52
|
},
|
|
53
53
|
{
|
|
54
54
|
"path": "core/hellolynk-contact-request-e2ee.mjs",
|
|
@@ -164,7 +164,7 @@
|
|
|
164
164
|
},
|
|
165
165
|
{
|
|
166
166
|
"path": "core/hellolynk-native-addressing-tools.cjs",
|
|
167
|
-
"sha256": "
|
|
167
|
+
"sha256": "f4bd81b3d03277e28955a62409383a0c4072c6212567f71425df4e18ece75d63"
|
|
168
168
|
},
|
|
169
169
|
{
|
|
170
170
|
"path": "core/hellolynk-native-human-confirmation-broker.mjs",
|
|
@@ -184,7 +184,7 @@
|
|
|
184
184
|
},
|
|
185
185
|
{
|
|
186
186
|
"path": "core/hellolynk-neutral-host-process.mjs",
|
|
187
|
-
"sha256": "
|
|
187
|
+
"sha256": "af6cb6585baae477f87ee880bd044dffb4c7f71667bfa78bcbf0d4d20e7483af"
|
|
188
188
|
},
|
|
189
189
|
{
|
|
190
190
|
"path": "core/hellolynk-neutral-host-store-adapters.mjs",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"contract":"hellolynk-workbuddy-immutable-package-v1","entry":"integrations/workbuddy/server/mcp-proxy.mjs","files":[{"path":"clients/core/hellolynk-client-account.mjs","sha256":"a22f14f494c1a44a9272ca95e160f8cb1df612a1ceb8b54e32596b13f90c3740"},{"path":"clients/core/hellolynk-client-core.mjs","sha256":"af7c9cb7a996fdb194c51dbcc745c48b616ff1686d79a1451104690d882df1b8"},{"path":"clients/core/hellolynk-client-profile.mjs","sha256":"81d4f64c11c8dbccec04a05435cc42b53823db2649f2c88739647299b3c97fd2"},{"path":"clients/core/hellolynk-client-update-entry.mjs","sha256":"dc62228a7351c721514b5ca7921d485dc6aa05475aaa2e3881b78d7de0e1a134"},{"path":"clients/core/hellolynk-client-update-runtime.mjs","sha256":"0a76f2bdcf338c544e493ca7d0b7168f03ffa32ed223e3537eccafc1cbaafba0"},{"path":"clients/core/hellolynk-client-update.mjs","sha256":"a4104a67dd72cb7a1950585c92aa8424b9387c1eda4f191e0df3f901c4f16a8f"},{"path":"clients/core/hellolynk-contact-request-e2ee.mjs","sha256":"18526628b354d18bcbe5e621360ecfcd5dfa4cb4d91397fb87d0c20e1f332a5d"},{"path":"clients/core/hellolynk-device-enrollment.mjs","sha256":"18f9decb843a5a82ef8dfc3e866904e0b04bbc48d700eac55a8ae54c5729c2aa"},{"path":"clients/core/hellolynk-direct-text-e2ee-client.mjs","sha256":"dd5dfa410a664e21e14b3c253ca496dd303e36aa5a2e1370b78cc51ec1fba973"},{"path":"clients/core/hellolynk-direct-text-e2ee.mjs","sha256":"3fee00210896b81cf40d25c634a6a758adee18704ef4a74fbc00b699a58d53e5"},{"path":"clients/core/hellolynk-host-auth.mjs","sha256":"49baa0b82ab078ad74a892a179189bdbd303a791d580ba4d6eac457564fad535"},{"path":"clients/core/hellolynk-host-protected-store.mjs","sha256":"0cefa22574df9dd99073d73bb688e9cae3faf6da862af013c1dfe9c87efef32e"},{"path":"clients/core/hellolynk-host-transport-client.mjs","sha256":"0c97425346496a5d5e1f2b3d092d5d227179051b63e8097bab225dffe576008a"},{"path":"clients/core/hellolynk-host.mjs","sha256":"ed88f2285b4c5eb8618a2f3f3c2a7a65d798465933b91b109121bb90b45f5880"},{"path":"clients/core/hellolynk-human-confirmation-ledger.mjs","sha256":"265ae39e93112416588841a14eb0351905d60b2552cf04c8cf8bd057acd64586"},{"path":"clients/core/hellolynk-human-relationship-controller.mjs","sha256":"01589c3eeb1c35f26cb50a14ce4e603c7bffe71e0b11863aed97c85f356e3c97"},{"path":"clients/core/hellolynk-inbox-read-state.mjs","sha256":"3c354aaa7038446f8f554f9520db287cc06559e6cb22cb69f0121a179ff2cb01"},{"path":"clients/core/hellolynk-indexed-message-store.mjs","sha256":"101f928dc5fab8064132e8755f74e157d35f921b5fe7d52fc80c0e46dc131428"},{"path":"clients/core/hellolynk-instance-conversation.mjs","sha256":"2e4a23917d4a86216b653ed04ec46216b9400fa94c13c0a00f1afc7877e284cb"},{"path":"clients/core/hellolynk-local-contact-requests.mjs","sha256":"3cbf0a0c6adeff17ceb310d202138c2dde7e23d0e8309f2584c161aae4c36acd"},{"path":"clients/core/hellolynk-local-contacts.mjs","sha256":"93d923702bdb5cbcbd47faf01f2c2e30bfe612fc450ef35ee98477412b2bbc6e"},{"path":"clients/core/hellolynk-local-data-migration.mjs","sha256":"72046a992b14f43167d6a671ec1094d34041cf43ba16d9d507583228045c7aa2"},{"path":"clients/core/hellolynk-local-data-protection.mjs","sha256":"798f42e9bd45a00565b628282233a55abfdc4d7102423cb0558a7e01fab76810"},{"path":"clients/core/hellolynk-local-identity-trust.mjs","sha256":"658fb5264d587341497e7d869408e51c1850f750856585ec7368a13c26f76a07"},{"path":"clients/core/hellolynk-local-messaging.mjs","sha256":"76b4348eb6eff34dec41c90666ac8ee14554018c5729c39b5b78bac30f0eaf80"},{"path":"clients/core/hellolynk-local-peer-transport.mjs","sha256":"4b8f01002b03fa19a9eea9dd72c7a41c4c951d6ef201f06dd1a89086a0a872cd"},{"path":"clients/core/hellolynk-local-process-lock.mjs","sha256":"5dd9b21f4e4509b148daaf2b495036e336e56be320d2bf7a3fac08b8a567d3bf"},{"path":"clients/core/hellolynk-model-inbox.mjs","sha256":"e112cbbb1caff5aa6f4a71bdfcb2d1c38260a96e3e4ab076b5f95c55e1da645e"},{"path":"clients/core/hellolynk-model-notices.cjs","sha256":"1b1c6e190b89f7305d05e1dddddaa6d50b7289b90aeab4599073eaaae27396f1"},{"path":"clients/core/hellolynk-native-addressing-tools.cjs","sha256":"e583c769b72d8cf52523c19b3320c982c2550f002041770f5953f16951690162"},{"path":"clients/core/hellolynk-native-conversations.mjs","sha256":"38116a956c2c96dbac6b5355e2097385475879ab5e9965ae3552912739379630"},{"path":"clients/core/hellolynk-native-human-confirmation-broker.mjs","sha256":"755fd03a4ee3b97cdfdb1efc491fb4cf602e25173819380ea8a715c04c82ea5a"},{"path":"clients/core/hellolynk-native-inbox-runtime.mjs","sha256":"bee3a5789420cc25cbc153cc8291f144b3a10ae50e96269823b7890cb603789d"},{"path":"clients/core/hellolynk-native-notice.mjs","sha256":"6cdbae7ad07f104c1d19123299d9b672d9d51265e5e1f512acd12a083617d419"},{"path":"clients/core/hellolynk-native-reply-routes.mjs","sha256":"65af258205a7eb9d2c599e0f400dbd9ea198c38a26f491e06f27c5c46101fc9b"},{"path":"clients/core/hellolynk-native-task-index.cjs","sha256":"aaeb19ee32e4736bd4b8fd23c544305d98c41908ab5ff9b211454b913edd009e"},{"path":"clients/core/hellolynk-native-worker-lease.mjs","sha256":"41eb3103c216a09b80159522700b7bb78f3b082a644501fd19fa51ce1bf6bab7"},{"path":"clients/core/hellolynk-neutral-host-assembly.mjs","sha256":"98b2b669183cda15272b182d5c04d3ae77511b8b657cd3179cbf2fa5d5f27920"},{"path":"clients/core/hellolynk-neutral-host-installation-store.mjs","sha256":"9ff399639d320e5527e51cd0ddbf049e7e0e8d3cc225cdc30f0d4637356a1590"},{"path":"clients/core/hellolynk-neutral-host-launcher.mjs","sha256":"490f8010bd84fc7c92a00ec4d4a996c27dd398b2e3584ded8bcebb74c598c18d"},{"path":"clients/core/hellolynk-neutral-host-process.mjs","sha256":"42cc6be6d187755bb80479892b4107901ea712f75bdf01d1a4b9517a2a7b64a2"},{"path":"clients/core/hellolynk-neutral-host-store-adapters.mjs","sha256":"b033d5cdedc54847bf1a9fd4d5b70af6d0e1ed8094e74feebbb592c242a0cde9"},{"path":"clients/core/hellolynk-neutral-host-workbench-read-model.mjs","sha256":"6767b4aaf5c7304587d7126f203535f02d1f1bfd692741105ad644686ecb1612"},{"path":"clients/core/hellolynk-platform-credential-store.mjs","sha256":"0558aca043ff586f10d7b82e1b2fe9b537ff661913dce76fc92feaf9bd7e5546"},{"path":"clients/core/hellolynk-relay-client-cli.mjs","sha256":"e3134f37ff8c327b3148a4c417ee14c6c8bfbc3be9680e25c1ea29d215dff1d7"},{"path":"clients/core/hellolynk-release-retention.mjs","sha256":"f5488a756dc9063fe5b44e0ea45dcdcc1903be3909717c7a8674b15e4952bfac"},{"path":"clients/core/hellolynk-runtime-safety.cjs","sha256":"1518d9904b329f05a92092f0f2d4014675014597573ba85f33e3e06c25ecea16"},{"path":"clients/core/hellolynk-workbench-action-grants.mjs","sha256":"7247f4bce07e6fafce6559604ef9c7a8f7a033b922c212344462411be55ea9ac"},{"path":"clients/core/hellolynk-workbench-connection.mjs","sha256":"198fb21c3db2c91b85ca38d334c0ffe56ef28f2f052b6b62a8d2ed5c166fcd82"},{"path":"clients/platform/windows/credential-store.ps1","sha256":"7ec7362eba2c442d9417035ff14c1108c7a58558b6f09ac36a2275828370debb"},{"path":"clients/platform/windows/hellolynk-host-protected-store.ps1","sha256":"84ac61c3762b7f944bf3e2c895f9a6427985ce697052afd9bc610474c921adad"},{"path":"clients/platform/windows/hellolynk-human-confirmation-ledger.ps1","sha256":"317409f270f2cbd8017b61384292cf9caf4bd0fce6ef7a9894c1ec4c173b240c"},{"path":"clients/platform/windows/hellolynk-local-data-key.ps1","sha256":"3143122114c9756370e2ff3f56eba4a03e4a1657888aab1c6d4387427081d937"},{"path":"clients/platform/windows/hellolynk-native-human-confirmation-broker.ps1","sha256":"d63e02b34eb43d1a81d771f0e23f0b8d38e34c8f96663156d0c7b79985802936"},{"path":"clients/workbench/contract.mjs","sha256":"9994f8c7260495355d9e02ff96b7dd1074e1bf2ee238fbaafa6864bf749c095c"},{"path":"clients/workbench/service.mjs","sha256":"681fe98e286a69a187fb59c8f955c274a51bb38606b9618800ee5995f768e367"},{"path":"integrations/workbuddy/package.json","sha256":"7d90b13b0d510c545f492d6d8b012ef1246f94ad342861f4c55ddcafc2909215"},{"path":"integrations/workbuddy/server/host-lifecycle.mjs","sha256":"3b8e6d6d537226a6242059830759df1a686a42f50c3103c5e949d79806c1a4f9"},{"path":"integrations/workbuddy/server/mcp-proxy.mjs","sha256":"5b4a4ac035e23bea30e4559451252ce0aa48fc7e2929c910fa9a2e31324bfc70"},{"path":"integrations/workbuddy/server/mcp-server.mjs","sha256":"00ea077f3cbcd5cc75f5d3df8689c6a46381506198149fcad98ef20f85833b18"},{"path":"integrations/workbuddy/server/model-call-origin.mjs","sha256":"4cece99ea644c71388323557dc0d9ba493a96cff75b55421d5e53d35ec97f584"},{"path":"integrations/workbuddy/server/native-task-cdp.mjs","sha256":"4a6894cc97866c8e9d0beae138e2e0a98412191207494e98844b17120ec839f5"},{"path":"integrations/workbuddy/server/native-task-debug-startup.mjs","sha256":"2bb5a92a82213191c120af0c3e6ce62977e3164551bec60d1e0bcbb3635d99e4"},{"path":"integrations/workbuddy/server/native-task-debug-startup.ps1","sha256":"49b2c00c806cce6b6b50abf8e4e6cf699777889fe4b488872e926980b6368615"},{"path":"integrations/workbuddy/server/native-task-mcp-registration.mjs","sha256":"fe19db7cd3d700542c20325589f99a3f607c3d2b893a950afd06c9007fd01d7b"},{"path":"integrations/workbuddy/server/native-task-service-registration.mjs","sha256":"025e9be428c438bb87565536404ded32cb1db56614441911c74169270f6e1422"},{"path":"integrations/workbuddy/server/native-task-worker.mjs","sha256":"8b6d11fca70adde335a6b1c92776c6d76ba69ff669457a7d803a8076457b4c8d"},{"path":"integrations/workbuddy/server/neutral-host-adapter.mjs","sha256":"fa053192e761bbd9eecea95e127b68d3b94d56e91d861230bd9771a1cd754b09"},{"path":"integrations/workbuddy/server/origin-hook.mjs","sha256":"4f2fe78f59771fef1ca1e1cc145a38df566cc70ff318ff6192f2e4003d76bc3d"},{"path":"integrations/workbuddy/server/origin-routes.mjs","sha256":"893bfb495c78579062e1007afab6dee07f0994d48109413355d8951eceb52dd5"},{"path":"integrations/workbuddy/server/package-bootstrap.mjs","sha256":"8794c98a846c6d1c3683fa31b9296267725a5f4f9160b57a6f6039937292cb25"},{"path":"integrations/workbuddy/server/workbench-candidate.mjs","sha256":"caa64a710a71afe67dde53b7a46dd91ea555b5a946a2749909fcf54e5f9265c0"},{"path":"integrations/workbuddy/server/workbench-hidden-launcher.vbs","sha256":"0fc1a0da2efdc49d39784888036b39a72aa6edf1f496a064ad4db105890b1a9e"},{"path":"integrations/workbuddy/server/workbench-process.mjs","sha256":"dbbb372e522b17894b6e50c12a13fc172ff752d1487354c772fcc670add212c0"},{"path":"integrations/workbuddy/server/workbench-task.ps1","sha256":"c2973667a10eefc96c0f999290f8aecc5e3b2062870f7637bf828252dff15fb5"},{"path":"integrations/workbuddy/skills/hellolynk-inbox/SKILL.md","sha256":"27b0f6b8033b702bcb22f0c70e39eac89ea61e0f1f2f6973a79361b0ec854942"},{"path":"integrations/workbuddy/skills/hellolynk-inbox/workbuddy.json","sha256":"163e506e3c87dd3f5128cd449de6affba48591c573e927edc128aeb93cd28735"},{"path":"runtime/connect-activate.mjs","sha256":"50ec8b0a58ac5b099a653722b0946acb23d0a29a054bfb3856dc963db6f84bee"},{"path":"runtime/core/hellolynk-agent-configurator.mjs","sha256":"505b010ffd2c3fb614f2a4c6eae92a9fc5b640b8e48dff39e563dcbaabfd344b"},{"path":"runtime/core/hellolynk-client-account.mjs","sha256":"ab7ec5dda92e510e7deb14f900fd2df4c6c3373fbeb4af4fb2b6c1a72aa41a99"},{"path":"runtime/core/hellolynk-client-core.mjs","sha256":"94bbad1d0ccee969bbffed176449e427188f1b892512a64167ab31f63d258e2b"},{"path":"runtime/core/hellolynk-client-profile.mjs","sha256":"4b45a78b4d6c4794a1f494bd95777579c32c56a68321a1d3b484048942ae4742"},{"path":"runtime/core/hellolynk-client-update-entry.mjs","sha256":"b2740406d79d0fa129c3bd1b5e6a07c3f52eed5e35a91ffea40b099ddc708936"},{"path":"runtime/core/hellolynk-client-update-runtime.mjs","sha256":"3ed31f0cea704c3ad26481126a78a7d39c21df69a5c52d1074a096a2b7b3e32f"},{"path":"runtime/core/hellolynk-client-update.mjs","sha256":"8f0d6f54313c91bd2ffb4643859a91dd1e122bb5f1da9143fe2851a3370d7fbf"},{"path":"runtime/core/hellolynk-contact-request-e2ee.mjs","sha256":"657664c6250d2738061e1ec2680eda6b36063c357d9e2d9c743e4218ece50895"},{"path":"runtime/core/hellolynk-device-enrollment.mjs","sha256":"f3e99ff2bdfa76e5a830a518792a1b9e5e705d7a8a01eca725dd7c5c8391d4ef"},{"path":"runtime/core/hellolynk-direct-text-e2ee-client.mjs","sha256":"4007bf5e6c91df00adf10384cc1f0d0d28491b8ded518365dddbac717f3ac5be"},{"path":"runtime/core/hellolynk-direct-text-e2ee.mjs","sha256":"f0abc3714cfad007669140ead4bfbb3f5bd56edd24d4389c3addee3f42887a01"},{"path":"runtime/core/hellolynk-host-auth.mjs","sha256":"db1ec56f4e60e6450fba50188eecf89748f39f5d7a75c2456c30a6053233555d"},{"path":"runtime/core/hellolynk-host-protected-store.mjs","sha256":"89b6e6c4ce9c6ba2984f8c301de4251da6004bdd402cc44d578a4505c21b75b1"},{"path":"runtime/core/hellolynk-host-transport-client.mjs","sha256":"9f27d3e44ce8333413e712eb38b970a335b64081d7e3be6882ff5ca921668859"},{"path":"runtime/core/hellolynk-host.mjs","sha256":"6cbe0ba6ec7aa81059a4a2d0e247fbedb6731687ec21ded4aaefa0e79be9e493"},{"path":"runtime/core/hellolynk-human-confirmation-ledger.mjs","sha256":"63bcbbb0870ad83fc031636d74ce77fc070d5f4d1d4c10297f8b3ec9ad85bbf6"},{"path":"runtime/core/hellolynk-human-relationship-controller.mjs","sha256":"7ef584c30febf0e142f621b719e433c0a9f5d976bbb917ab15f6cc1abb39ad52"},{"path":"runtime/core/hellolynk-inbox-read-state.mjs","sha256":"bf2353075f0a10cc3492c0d7309f8d3fef4a4bda1996b878cfbae8515beaeb34"},{"path":"runtime/core/hellolynk-indexed-message-store.mjs","sha256":"61a9d642fb0453aa949c6e634a30ae3f8562a81d3a666580a2f32d414c9f80ad"},{"path":"runtime/core/hellolynk-instance-conversation.mjs","sha256":"f00161cbdab48b33f0be1a809389145c167d8b8bdfab32d8c929db3bc167b4a1"},{"path":"runtime/core/hellolynk-local-contact-requests.mjs","sha256":"9724729b28c4c979696fcd53531e89eddb18a3045e32f602ecfb002af1c44b4c"},{"path":"runtime/core/hellolynk-local-contacts.mjs","sha256":"b7c722f0c300f951ed390ea82aec04975b226f2ea4d5c873764ab36ef9a8bc2c"},{"path":"runtime/core/hellolynk-local-data-migration.mjs","sha256":"1e791114633770fe3955842725965798dfd749e1dbf513f08efc4e01b9ed1756"},{"path":"runtime/core/hellolynk-local-data-protection.mjs","sha256":"1bda879aa0bdf46700a63374e82cc7bc639385656b1463a75a49e8510971066c"},{"path":"runtime/core/hellolynk-local-identity-trust.mjs","sha256":"b6d22715c627820c0ea92ca543cf52bbfeee5d5f416d242c2e21230640310420"},{"path":"runtime/core/hellolynk-local-messaging.mjs","sha256":"23e701818b18b96ba36ad1dfc3c2489d80fec8dafa2f433cf29947175786ed07"},{"path":"runtime/core/hellolynk-local-peer-transport.mjs","sha256":"9c32b2fa5f716f1ff36e09b3f2cd697479acc2f3c6bcb6e96045f5ca65e3b1c6"},{"path":"runtime/core/hellolynk-local-process-lock.mjs","sha256":"5212990a98b9ad2eb83fa2d5fb8a123d687c5ef6daf6cba49a4b6d04a7fe251e"},{"path":"runtime/core/hellolynk-model-inbox.mjs","sha256":"516c846340ee7a2fd624eaedaa51ded81988ef875b8a7eeb15c2e296774bfa63"},{"path":"runtime/core/hellolynk-model-notices.cjs","sha256":"c1b0d9071d3750c87755bc9fdf969d89c7fa62a0dede4c37b8cb2954b81163b0"},{"path":"runtime/core/hellolynk-native-addressing-tools.cjs","sha256":"252251de855c3fe9c5ebdd54a97ba976a8009f4ac57ec44f492bed8c7fb903de"},{"path":"runtime/core/hellolynk-native-conversations.mjs","sha256":"671030938a5259f6cce0c1eb4e61997f7f89232c677c9ba26062daea91b6f8c6"},{"path":"runtime/core/hellolynk-native-human-confirmation-broker.mjs","sha256":"2fb2d3b40869362be3e40a1ec55947021319af5315cbf8fdc5ed59df717cceb3"},{"path":"runtime/core/hellolynk-native-inbox-runtime.mjs","sha256":"039ba7fe8273357d178556fc57e751c469e2bf0056bcaee5029e7fe376099c72"},{"path":"runtime/core/hellolynk-native-notice.mjs","sha256":"6a5fe50fbccac465d690612839eaf7c10a5622cd84151277b0bf4507eccbe087"},{"path":"runtime/core/hellolynk-native-reply-routes.mjs","sha256":"8ed07580f2b6fe6bff9953951ea79f6c7c1c806887cd0bf21d4893ba8343ebe2"},{"path":"runtime/core/hellolynk-native-worker-lease.mjs","sha256":"e4e6864ff047b1d3511c363eb2bc7a3a3841a453f5d9d40b94bde55cc38cebc5"},{"path":"runtime/core/hellolynk-neutral-host-assembly.mjs","sha256":"d0ac9c697bf8a85263d99a0739da557c62f52c72f4afb105eb97b3aac2ae1f3b"},{"path":"runtime/core/hellolynk-neutral-host-installation-store.mjs","sha256":"b5f6288732af6f9b9c0c750f6002eae657dde9513fc97674f6e59200f3cc9dc6"},{"path":"runtime/core/hellolynk-neutral-host-launcher.mjs","sha256":"789b2531cdbde6e6d8f91f2a40746372e903e9e48e8aa6846b9abf2d28150780"},{"path":"runtime/core/hellolynk-neutral-host-process.mjs","sha256":"6d1913e3fb6e35d9a090afde39bf4a1521b17d1620fb09420e507d60af77cce4"},{"path":"runtime/core/hellolynk-neutral-host-store-adapters.mjs","sha256":"3e425ca2cc111e750f55e94be2561cae8a3b308e473fb549e42da3443b67fd34"},{"path":"runtime/core/hellolynk-neutral-host-workbench-read-model.mjs","sha256":"65ca217dbd5be05f4cf38fd977b0d536526f79463a402fae90a7329dac375670"},{"path":"runtime/core/hellolynk-platform-credential-store.mjs","sha256":"f27f5f377cc4d6d2b5664212cf8fcc4c98d910064c1677ff9c1f776df1a59dba"},{"path":"runtime/core/hellolynk-relay-client-cli.mjs","sha256":"29707c4e0d91d5db6f46408b4c1101b9ab30b117500a9e315da8802e71a43010"},{"path":"runtime/core/hellolynk-release-retention.mjs","sha256":"68321383ecf73adf55d842c7215f5e0b0fe72851aac292885740be99743e1bd0"},{"path":"runtime/core/hellolynk-runtime-safety.cjs","sha256":"43d576d9f774409f4a735793c1503a6f397e787b10c59a4ac9cc9257299f5efe"},{"path":"runtime/core/hellolynk-workbench-action-grants.mjs","sha256":"076d1bb848c85c06695440f33daebd853a9f49147a85cf582cc3e2964d95198a"},{"path":"runtime/core/hellolynk-workbench-connection.mjs","sha256":"d3396350fd75af78e60772e021cf6dfb643d9eee41894c5461c959a56650cb60"},{"path":"runtime/neutral-host-bootstrap.mjs","sha256":"db0ffd88a5fbb9091f16ceab4e391ac6919ba2640cdbc358574034779f848d7e"},{"path":"runtime/neutral-host-release-entry.mjs","sha256":"d434d392c85728228772369e9a890cef34598833ab2433dcc7b963c17bf5c146"},{"path":"runtime/neutral-host-release-loader.mjs","sha256":"00b226c65732bcd4d18d2b1b4ebc5092b7073fac52ee500d5d746b01217bfa65"},{"path":"runtime/neutral-host-release-manifest.json","sha256":"2f11bc431837eadac3a49baa4d31f7a4fc303476eeb586df0cf28d0766e204e5"},{"path":"runtime/neutral-host-release-pin.json","sha256":"13bf0f7f291e82d3a34c791c86219a22126fae3dfea77fcf46500a4277f75e76"},{"path":"runtime/platform/windows/configure-agent.ps1","sha256":"7dc7c75bf0f7e45060b041a08d502993afe84581040f165e7f4437bf490708fa"},{"path":"runtime/platform/windows/credential-store.ps1","sha256":"d00dae4af08205fffa52c4956d1c87d5c3423e8f20982ccfc1b76e3424fe442e"},{"path":"runtime/platform/windows/hellolynk-host-protected-store.ps1","sha256":"24357e8ce54090b4ec68e457f02c9e834a80f3273ef3c03a8c0fa7258797fb49"},{"path":"runtime/platform/windows/hellolynk-human-confirmation-ledger.ps1","sha256":"4612561e2128dfd96c018f2c2d9ae41016f35bb6df8536314e9f0fb428165a82"},{"path":"runtime/platform/windows/hellolynk-local-data-key.ps1","sha256":"0976a0ecdd724e767b87e65743a230569c3fcb30e2449cf38bb718eb1604c15c"},{"path":"runtime/platform/windows/hellolynk-native-human-confirmation-broker.ps1","sha256":"757a731a3e8761d5d473db19ecfc330783f2826663a0057c4d6896e679d7a388"},{"path":"runtime/workbench/candidate-bootstrap.mjs","sha256":"891b02f750693e5b4836e716922c2d632f6736b2a5b3b7417f161499459f3f56"},{"path":"runtime/workbench/contract.mjs","sha256":"20648c3ed8e20b984b698010855414f8d4acaf0e2ade53b997b5582a85d90a08"},{"path":"runtime/workbench/hellolynk-workbench-build.json","sha256":"43e42633242cb456ecf2a120380230485e4d8533934ad6242089049d9282da11"},{"path":"runtime/workbench/host-capabilities.mjs","sha256":"4e1a82e6cb46dd775ba39e2d34ff21eb1c293523883d18e607084ca91cfffb87"},{"path":"runtime/workbench/i18n.mjs","sha256":"272917746c06cabc1b87b94341f2deca5591f0bea2d7a0e07b2d959d8e1f8c74"},{"path":"runtime/workbench/loopback-surface.mjs","sha256":"6a550034c5dd558dfd22f9cb589fd76df40a99e976538e3b5d01371d212c9aa6"},{"path":"runtime/workbench/mcp-app-bundle.mjs","sha256":"48fb8224cbaa7f78a386a79b2dba761f4de6c4b83b16032f7f96bd9783e172e4"},{"path":"runtime/workbench/service.mjs","sha256":"3bf82a0076e9fe3b62105c626fe0d622092224f28d3905c62eafd65bf5385dcc"},{"path":"runtime/workbench/state.mjs","sha256":"770d10f3bf76236772c87e86f5da346c013da387fb40c08360f895a7052cf7b5"},{"path":"runtime/workbench/transports.mjs","sha256":"0c9f42ca9c9a4b4cc29b1bdcc0a0488d16a9ad06c235c642dff9cd4fc6f0d528"},{"path":"runtime/workbench/ui/app.mjs","sha256":"643a5ac8d303f936ee87dd7c0c851aa1988e99ea9a9a45c6c89da28bdc76e799"},{"path":"runtime/workbench/ui/connection-form.mjs","sha256":"700ca793f5eddca1dfea5f220c73732efc51ea4e1f8b8fc36da2bb67136240f0"},{"path":"runtime/workbench/ui/hellolynk-mark.png","sha256":"108e5c90e1717a87169d317c15f8de33859ed487b06654888047c729d9ab5982"},{"path":"runtime/workbench/ui/http-transport.mjs","sha256":"b2fedbc2c34bcf065e0fc23c8c5fb37d358c03daa2c82ba46530b8dfb8fdc571"},{"path":"runtime/workbench/ui/icons/arrow-left.svg","sha256":"1c527dd347b5fba0312cdcd66cf7514a261855672f7585d1c8b1882f602442a6"},{"path":"runtime/workbench/ui/icons/close.svg","sha256":"22f5c4fb0660601a817ead151c37e82e93d39b2ef4ce1192d66f9099a3c59b36"},{"path":"runtime/workbench/ui/icons/contacts.svg","sha256":"de0add3c43bca68d8cae7736bc3ea8145ca0abb7f32c25127542c6f5a27b3f45"},{"path":"runtime/workbench/ui/icons/inbox.svg","sha256":"e1938770f085e6794a2e22aa3f8e890e083ac341a3c3faa13098a8243dc8306b"},{"path":"runtime/workbench/ui/icons/refresh.svg","sha256":"a7b91e87c1a25d117b1352d2ec131bf6e3fe67df2020af87e0d3575c06d86f29"},{"path":"runtime/workbench/ui/icons/search.svg","sha256":"135df34e348445114a1b88757fe7ef79a6718ffa4cc761c30f8026044552b699"},{"path":"runtime/workbench/ui/icons/security.svg","sha256":"9b6c502b2ce2795530f2e7018e2c24aaaf1cf49472f040868bad148d3321071e"},{"path":"runtime/workbench/ui/icons/settings.svg","sha256":"17b528a15b8187aecd80c4974c7432ec6e58e6a12e062104fae70bf63c46caa2"},{"path":"runtime/workbench/ui/index.html","sha256":"b24cd1f768d5132539722ac7ade3acfe5aa86a47ee16a2adacf3bbf18b70c989"},{"path":"runtime/workbench/ui/loopback-entry.mjs","sha256":"0e5e5d259ab6e2d8408c6d2e089551e6f279dcb1267e9db19f9d9dded0956fd4"},{"path":"runtime/workbench/ui/mcp-app-client.mjs","sha256":"91b1e6e84a12434c2be7614845febfa44afa341d5d7f580bc1bfc106ed37f8f8"},{"path":"runtime/workbench/ui/mcp-app-entry.mjs","sha256":"ba82ac55c4efcf7701bda33b6c6e0df4d59da542b1d6c33c96ba7f2391c4773a"},{"path":"runtime/workbench/ui/styles.css","sha256":"34d24d3d35800a796905049eb5f785f402cf1e82118c66efd4893bd003adbe31"}]}
|
|
1
|
+
{"contract":"hellolynk-workbuddy-immutable-package-v1","entry":"integrations/workbuddy/server/mcp-proxy.mjs","files":[{"path":"clients/core/hellolynk-client-account.mjs","sha256":"a22f14f494c1a44a9272ca95e160f8cb1df612a1ceb8b54e32596b13f90c3740"},{"path":"clients/core/hellolynk-client-core.mjs","sha256":"af7c9cb7a996fdb194c51dbcc745c48b616ff1686d79a1451104690d882df1b8"},{"path":"clients/core/hellolynk-client-profile.mjs","sha256":"81d4f64c11c8dbccec04a05435cc42b53823db2649f2c88739647299b3c97fd2"},{"path":"clients/core/hellolynk-client-update-entry.mjs","sha256":"dc62228a7351c721514b5ca7921d485dc6aa05475aaa2e3881b78d7de0e1a134"},{"path":"clients/core/hellolynk-client-update-runtime.mjs","sha256":"0a76f2bdcf338c544e493ca7d0b7168f03ffa32ed223e3537eccafc1cbaafba0"},{"path":"clients/core/hellolynk-client-update.mjs","sha256":"a4104a67dd72cb7a1950585c92aa8424b9387c1eda4f191e0df3f901c4f16a8f"},{"path":"clients/core/hellolynk-contact-request-e2ee.mjs","sha256":"18526628b354d18bcbe5e621360ecfcd5dfa4cb4d91397fb87d0c20e1f332a5d"},{"path":"clients/core/hellolynk-device-enrollment.mjs","sha256":"18f9decb843a5a82ef8dfc3e866904e0b04bbc48d700eac55a8ae54c5729c2aa"},{"path":"clients/core/hellolynk-direct-text-e2ee-client.mjs","sha256":"dd5dfa410a664e21e14b3c253ca496dd303e36aa5a2e1370b78cc51ec1fba973"},{"path":"clients/core/hellolynk-direct-text-e2ee.mjs","sha256":"3fee00210896b81cf40d25c634a6a758adee18704ef4a74fbc00b699a58d53e5"},{"path":"clients/core/hellolynk-host-auth.mjs","sha256":"49baa0b82ab078ad74a892a179189bdbd303a791d580ba4d6eac457564fad535"},{"path":"clients/core/hellolynk-host-protected-store.mjs","sha256":"0cefa22574df9dd99073d73bb688e9cae3faf6da862af013c1dfe9c87efef32e"},{"path":"clients/core/hellolynk-host-transport-client.mjs","sha256":"0c97425346496a5d5e1f2b3d092d5d227179051b63e8097bab225dffe576008a"},{"path":"clients/core/hellolynk-host.mjs","sha256":"ed88f2285b4c5eb8618a2f3f3c2a7a65d798465933b91b109121bb90b45f5880"},{"path":"clients/core/hellolynk-human-confirmation-ledger.mjs","sha256":"265ae39e93112416588841a14eb0351905d60b2552cf04c8cf8bd057acd64586"},{"path":"clients/core/hellolynk-human-relationship-controller.mjs","sha256":"01589c3eeb1c35f26cb50a14ce4e603c7bffe71e0b11863aed97c85f356e3c97"},{"path":"clients/core/hellolynk-inbox-read-state.mjs","sha256":"3c354aaa7038446f8f554f9520db287cc06559e6cb22cb69f0121a179ff2cb01"},{"path":"clients/core/hellolynk-indexed-message-store.mjs","sha256":"101f928dc5fab8064132e8755f74e157d35f921b5fe7d52fc80c0e46dc131428"},{"path":"clients/core/hellolynk-instance-conversation.mjs","sha256":"2e4a23917d4a86216b653ed04ec46216b9400fa94c13c0a00f1afc7877e284cb"},{"path":"clients/core/hellolynk-local-contact-requests.mjs","sha256":"3cbf0a0c6adeff17ceb310d202138c2dde7e23d0e8309f2584c161aae4c36acd"},{"path":"clients/core/hellolynk-local-contacts.mjs","sha256":"93d923702bdb5cbcbd47faf01f2c2e30bfe612fc450ef35ee98477412b2bbc6e"},{"path":"clients/core/hellolynk-local-data-migration.mjs","sha256":"72046a992b14f43167d6a671ec1094d34041cf43ba16d9d507583228045c7aa2"},{"path":"clients/core/hellolynk-local-data-protection.mjs","sha256":"798f42e9bd45a00565b628282233a55abfdc4d7102423cb0558a7e01fab76810"},{"path":"clients/core/hellolynk-local-identity-trust.mjs","sha256":"658fb5264d587341497e7d869408e51c1850f750856585ec7368a13c26f76a07"},{"path":"clients/core/hellolynk-local-messaging.mjs","sha256":"76b4348eb6eff34dec41c90666ac8ee14554018c5729c39b5b78bac30f0eaf80"},{"path":"clients/core/hellolynk-local-peer-transport.mjs","sha256":"4b8f01002b03fa19a9eea9dd72c7a41c4c951d6ef201f06dd1a89086a0a872cd"},{"path":"clients/core/hellolynk-local-process-lock.mjs","sha256":"5dd9b21f4e4509b148daaf2b495036e336e56be320d2bf7a3fac08b8a567d3bf"},{"path":"clients/core/hellolynk-model-inbox.mjs","sha256":"e112cbbb1caff5aa6f4a71bdfcb2d1c38260a96e3e4ab076b5f95c55e1da645e"},{"path":"clients/core/hellolynk-model-notices.cjs","sha256":"1b1c6e190b89f7305d05e1dddddaa6d50b7289b90aeab4599073eaaae27396f1"},{"path":"clients/core/hellolynk-native-addressing-tools.cjs","sha256":"cce89fa33dbe630a78d77843919a8e4b0c12f3482e754f783e6ff038b81929c4"},{"path":"clients/core/hellolynk-native-conversations.mjs","sha256":"38116a956c2c96dbac6b5355e2097385475879ab5e9965ae3552912739379630"},{"path":"clients/core/hellolynk-native-human-confirmation-broker.mjs","sha256":"755fd03a4ee3b97cdfdb1efc491fb4cf602e25173819380ea8a715c04c82ea5a"},{"path":"clients/core/hellolynk-native-inbox-runtime.mjs","sha256":"bee3a5789420cc25cbc153cc8291f144b3a10ae50e96269823b7890cb603789d"},{"path":"clients/core/hellolynk-native-notice.mjs","sha256":"6cdbae7ad07f104c1d19123299d9b672d9d51265e5e1f512acd12a083617d419"},{"path":"clients/core/hellolynk-native-reply-routes.mjs","sha256":"65af258205a7eb9d2c599e0f400dbd9ea198c38a26f491e06f27c5c46101fc9b"},{"path":"clients/core/hellolynk-native-task-index.cjs","sha256":"aaeb19ee32e4736bd4b8fd23c544305d98c41908ab5ff9b211454b913edd009e"},{"path":"clients/core/hellolynk-native-worker-lease.mjs","sha256":"41eb3103c216a09b80159522700b7bb78f3b082a644501fd19fa51ce1bf6bab7"},{"path":"clients/core/hellolynk-neutral-host-assembly.mjs","sha256":"98b2b669183cda15272b182d5c04d3ae77511b8b657cd3179cbf2fa5d5f27920"},{"path":"clients/core/hellolynk-neutral-host-installation-store.mjs","sha256":"9ff399639d320e5527e51cd0ddbf049e7e0e8d3cc225cdc30f0d4637356a1590"},{"path":"clients/core/hellolynk-neutral-host-launcher.mjs","sha256":"490f8010bd84fc7c92a00ec4d4a996c27dd398b2e3584ded8bcebb74c598c18d"},{"path":"clients/core/hellolynk-neutral-host-process.mjs","sha256":"5e5b9f535331444d284b2e62cc2593d6279b8a30332c82f4f85c7ff25e2f3727"},{"path":"clients/core/hellolynk-neutral-host-store-adapters.mjs","sha256":"b033d5cdedc54847bf1a9fd4d5b70af6d0e1ed8094e74feebbb592c242a0cde9"},{"path":"clients/core/hellolynk-neutral-host-workbench-read-model.mjs","sha256":"6767b4aaf5c7304587d7126f203535f02d1f1bfd692741105ad644686ecb1612"},{"path":"clients/core/hellolynk-platform-credential-store.mjs","sha256":"0558aca043ff586f10d7b82e1b2fe9b537ff661913dce76fc92feaf9bd7e5546"},{"path":"clients/core/hellolynk-relay-client-cli.mjs","sha256":"e3134f37ff8c327b3148a4c417ee14c6c8bfbc3be9680e25c1ea29d215dff1d7"},{"path":"clients/core/hellolynk-release-retention.mjs","sha256":"9f8b5b97eee7530dc8ef965b0df6a19065b06012255100977d8abb17ce50d204"},{"path":"clients/core/hellolynk-runtime-safety.cjs","sha256":"1518d9904b329f05a92092f0f2d4014675014597573ba85f33e3e06c25ecea16"},{"path":"clients/core/hellolynk-workbench-action-grants.mjs","sha256":"7247f4bce07e6fafce6559604ef9c7a8f7a033b922c212344462411be55ea9ac"},{"path":"clients/core/hellolynk-workbench-connection.mjs","sha256":"198fb21c3db2c91b85ca38d334c0ffe56ef28f2f052b6b62a8d2ed5c166fcd82"},{"path":"clients/platform/windows/credential-store.ps1","sha256":"7ec7362eba2c442d9417035ff14c1108c7a58558b6f09ac36a2275828370debb"},{"path":"clients/platform/windows/hellolynk-host-protected-store.ps1","sha256":"84ac61c3762b7f944bf3e2c895f9a6427985ce697052afd9bc610474c921adad"},{"path":"clients/platform/windows/hellolynk-human-confirmation-ledger.ps1","sha256":"317409f270f2cbd8017b61384292cf9caf4bd0fce6ef7a9894c1ec4c173b240c"},{"path":"clients/platform/windows/hellolynk-local-data-key.ps1","sha256":"3143122114c9756370e2ff3f56eba4a03e4a1657888aab1c6d4387427081d937"},{"path":"clients/platform/windows/hellolynk-native-human-confirmation-broker.ps1","sha256":"d63e02b34eb43d1a81d771f0e23f0b8d38e34c8f96663156d0c7b79985802936"},{"path":"clients/workbench/contract.mjs","sha256":"9994f8c7260495355d9e02ff96b7dd1074e1bf2ee238fbaafa6864bf749c095c"},{"path":"clients/workbench/service.mjs","sha256":"681fe98e286a69a187fb59c8f955c274a51bb38606b9618800ee5995f768e367"},{"path":"integrations/workbuddy/package.json","sha256":"b213e8830b815cd7033231766874f3b0156fa3acad5bcf4853125e8c73bb6902"},{"path":"integrations/workbuddy/server/host-lifecycle.mjs","sha256":"3b8e6d6d537226a6242059830759df1a686a42f50c3103c5e949d79806c1a4f9"},{"path":"integrations/workbuddy/server/mcp-proxy.mjs","sha256":"5b4a4ac035e23bea30e4559451252ce0aa48fc7e2929c910fa9a2e31324bfc70"},{"path":"integrations/workbuddy/server/mcp-server.mjs","sha256":"00ea077f3cbcd5cc75f5d3df8689c6a46381506198149fcad98ef20f85833b18"},{"path":"integrations/workbuddy/server/model-call-origin.mjs","sha256":"4cece99ea644c71388323557dc0d9ba493a96cff75b55421d5e53d35ec97f584"},{"path":"integrations/workbuddy/server/native-task-cdp.mjs","sha256":"4a6894cc97866c8e9d0beae138e2e0a98412191207494e98844b17120ec839f5"},{"path":"integrations/workbuddy/server/native-task-debug-startup.mjs","sha256":"2bb5a92a82213191c120af0c3e6ce62977e3164551bec60d1e0bcbb3635d99e4"},{"path":"integrations/workbuddy/server/native-task-debug-startup.ps1","sha256":"49b2c00c806cce6b6b50abf8e4e6cf699777889fe4b488872e926980b6368615"},{"path":"integrations/workbuddy/server/native-task-mcp-registration.mjs","sha256":"fe19db7cd3d700542c20325589f99a3f607c3d2b893a950afd06c9007fd01d7b"},{"path":"integrations/workbuddy/server/native-task-service-registration.mjs","sha256":"025e9be428c438bb87565536404ded32cb1db56614441911c74169270f6e1422"},{"path":"integrations/workbuddy/server/native-task-worker.mjs","sha256":"8b6d11fca70adde335a6b1c92776c6d76ba69ff669457a7d803a8076457b4c8d"},{"path":"integrations/workbuddy/server/neutral-host-adapter.mjs","sha256":"fa053192e761bbd9eecea95e127b68d3b94d56e91d861230bd9771a1cd754b09"},{"path":"integrations/workbuddy/server/origin-hook.mjs","sha256":"4f2fe78f59771fef1ca1e1cc145a38df566cc70ff318ff6192f2e4003d76bc3d"},{"path":"integrations/workbuddy/server/origin-routes.mjs","sha256":"893bfb495c78579062e1007afab6dee07f0994d48109413355d8951eceb52dd5"},{"path":"integrations/workbuddy/server/package-bootstrap.mjs","sha256":"8794c98a846c6d1c3683fa31b9296267725a5f4f9160b57a6f6039937292cb25"},{"path":"integrations/workbuddy/server/workbench-candidate.mjs","sha256":"caa64a710a71afe67dde53b7a46dd91ea555b5a946a2749909fcf54e5f9265c0"},{"path":"integrations/workbuddy/server/workbench-hidden-launcher.vbs","sha256":"0fc1a0da2efdc49d39784888036b39a72aa6edf1f496a064ad4db105890b1a9e"},{"path":"integrations/workbuddy/server/workbench-process.mjs","sha256":"dbbb372e522b17894b6e50c12a13fc172ff752d1487354c772fcc670add212c0"},{"path":"integrations/workbuddy/server/workbench-task.ps1","sha256":"c2973667a10eefc96c0f999290f8aecc5e3b2062870f7637bf828252dff15fb5"},{"path":"integrations/workbuddy/skills/hellolynk-inbox/SKILL.md","sha256":"27b0f6b8033b702bcb22f0c70e39eac89ea61e0f1f2f6973a79361b0ec854942"},{"path":"integrations/workbuddy/skills/hellolynk-inbox/workbuddy.json","sha256":"163e506e3c87dd3f5128cd449de6affba48591c573e927edc128aeb93cd28735"},{"path":"runtime/connect-activate.mjs","sha256":"50ec8b0a58ac5b099a653722b0946acb23d0a29a054bfb3856dc963db6f84bee"},{"path":"runtime/core/hellolynk-agent-configurator.mjs","sha256":"505b010ffd2c3fb614f2a4c6eae92a9fc5b640b8e48dff39e563dcbaabfd344b"},{"path":"runtime/core/hellolynk-client-account.mjs","sha256":"ab7ec5dda92e510e7deb14f900fd2df4c6c3373fbeb4af4fb2b6c1a72aa41a99"},{"path":"runtime/core/hellolynk-client-core.mjs","sha256":"94bbad1d0ccee969bbffed176449e427188f1b892512a64167ab31f63d258e2b"},{"path":"runtime/core/hellolynk-client-profile.mjs","sha256":"4b45a78b4d6c4794a1f494bd95777579c32c56a68321a1d3b484048942ae4742"},{"path":"runtime/core/hellolynk-client-update-entry.mjs","sha256":"b2740406d79d0fa129c3bd1b5e6a07c3f52eed5e35a91ffea40b099ddc708936"},{"path":"runtime/core/hellolynk-client-update-runtime.mjs","sha256":"3ed31f0cea704c3ad26481126a78a7d39c21df69a5c52d1074a096a2b7b3e32f"},{"path":"runtime/core/hellolynk-client-update.mjs","sha256":"8f0d6f54313c91bd2ffb4643859a91dd1e122bb5f1da9143fe2851a3370d7fbf"},{"path":"runtime/core/hellolynk-contact-request-e2ee.mjs","sha256":"657664c6250d2738061e1ec2680eda6b36063c357d9e2d9c743e4218ece50895"},{"path":"runtime/core/hellolynk-device-enrollment.mjs","sha256":"f3e99ff2bdfa76e5a830a518792a1b9e5e705d7a8a01eca725dd7c5c8391d4ef"},{"path":"runtime/core/hellolynk-direct-text-e2ee-client.mjs","sha256":"4007bf5e6c91df00adf10384cc1f0d0d28491b8ded518365dddbac717f3ac5be"},{"path":"runtime/core/hellolynk-direct-text-e2ee.mjs","sha256":"f0abc3714cfad007669140ead4bfbb3f5bd56edd24d4389c3addee3f42887a01"},{"path":"runtime/core/hellolynk-host-auth.mjs","sha256":"db1ec56f4e60e6450fba50188eecf89748f39f5d7a75c2456c30a6053233555d"},{"path":"runtime/core/hellolynk-host-protected-store.mjs","sha256":"89b6e6c4ce9c6ba2984f8c301de4251da6004bdd402cc44d578a4505c21b75b1"},{"path":"runtime/core/hellolynk-host-transport-client.mjs","sha256":"9f27d3e44ce8333413e712eb38b970a335b64081d7e3be6882ff5ca921668859"},{"path":"runtime/core/hellolynk-host.mjs","sha256":"6cbe0ba6ec7aa81059a4a2d0e247fbedb6731687ec21ded4aaefa0e79be9e493"},{"path":"runtime/core/hellolynk-human-confirmation-ledger.mjs","sha256":"63bcbbb0870ad83fc031636d74ce77fc070d5f4d1d4c10297f8b3ec9ad85bbf6"},{"path":"runtime/core/hellolynk-human-relationship-controller.mjs","sha256":"7ef584c30febf0e142f621b719e433c0a9f5d976bbb917ab15f6cc1abb39ad52"},{"path":"runtime/core/hellolynk-inbox-read-state.mjs","sha256":"bf2353075f0a10cc3492c0d7309f8d3fef4a4bda1996b878cfbae8515beaeb34"},{"path":"runtime/core/hellolynk-indexed-message-store.mjs","sha256":"61a9d642fb0453aa949c6e634a30ae3f8562a81d3a666580a2f32d414c9f80ad"},{"path":"runtime/core/hellolynk-instance-conversation.mjs","sha256":"f00161cbdab48b33f0be1a809389145c167d8b8bdfab32d8c929db3bc167b4a1"},{"path":"runtime/core/hellolynk-local-contact-requests.mjs","sha256":"9724729b28c4c979696fcd53531e89eddb18a3045e32f602ecfb002af1c44b4c"},{"path":"runtime/core/hellolynk-local-contacts.mjs","sha256":"b7c722f0c300f951ed390ea82aec04975b226f2ea4d5c873764ab36ef9a8bc2c"},{"path":"runtime/core/hellolynk-local-data-migration.mjs","sha256":"1e791114633770fe3955842725965798dfd749e1dbf513f08efc4e01b9ed1756"},{"path":"runtime/core/hellolynk-local-data-protection.mjs","sha256":"1bda879aa0bdf46700a63374e82cc7bc639385656b1463a75a49e8510971066c"},{"path":"runtime/core/hellolynk-local-identity-trust.mjs","sha256":"b6d22715c627820c0ea92ca543cf52bbfeee5d5f416d242c2e21230640310420"},{"path":"runtime/core/hellolynk-local-messaging.mjs","sha256":"23e701818b18b96ba36ad1dfc3c2489d80fec8dafa2f433cf29947175786ed07"},{"path":"runtime/core/hellolynk-local-peer-transport.mjs","sha256":"9c32b2fa5f716f1ff36e09b3f2cd697479acc2f3c6bcb6e96045f5ca65e3b1c6"},{"path":"runtime/core/hellolynk-local-process-lock.mjs","sha256":"5212990a98b9ad2eb83fa2d5fb8a123d687c5ef6daf6cba49a4b6d04a7fe251e"},{"path":"runtime/core/hellolynk-model-inbox.mjs","sha256":"516c846340ee7a2fd624eaedaa51ded81988ef875b8a7eeb15c2e296774bfa63"},{"path":"runtime/core/hellolynk-model-notices.cjs","sha256":"c1b0d9071d3750c87755bc9fdf969d89c7fa62a0dede4c37b8cb2954b81163b0"},{"path":"runtime/core/hellolynk-native-addressing-tools.cjs","sha256":"f4bd81b3d03277e28955a62409383a0c4072c6212567f71425df4e18ece75d63"},{"path":"runtime/core/hellolynk-native-conversations.mjs","sha256":"671030938a5259f6cce0c1eb4e61997f7f89232c677c9ba26062daea91b6f8c6"},{"path":"runtime/core/hellolynk-native-human-confirmation-broker.mjs","sha256":"2fb2d3b40869362be3e40a1ec55947021319af5315cbf8fdc5ed59df717cceb3"},{"path":"runtime/core/hellolynk-native-inbox-runtime.mjs","sha256":"039ba7fe8273357d178556fc57e751c469e2bf0056bcaee5029e7fe376099c72"},{"path":"runtime/core/hellolynk-native-notice.mjs","sha256":"6a5fe50fbccac465d690612839eaf7c10a5622cd84151277b0bf4507eccbe087"},{"path":"runtime/core/hellolynk-native-reply-routes.mjs","sha256":"8ed07580f2b6fe6bff9953951ea79f6c7c1c806887cd0bf21d4893ba8343ebe2"},{"path":"runtime/core/hellolynk-native-worker-lease.mjs","sha256":"e4e6864ff047b1d3511c363eb2bc7a3a3841a453f5d9d40b94bde55cc38cebc5"},{"path":"runtime/core/hellolynk-neutral-host-assembly.mjs","sha256":"d0ac9c697bf8a85263d99a0739da557c62f52c72f4afb105eb97b3aac2ae1f3b"},{"path":"runtime/core/hellolynk-neutral-host-installation-store.mjs","sha256":"b5f6288732af6f9b9c0c750f6002eae657dde9513fc97674f6e59200f3cc9dc6"},{"path":"runtime/core/hellolynk-neutral-host-launcher.mjs","sha256":"789b2531cdbde6e6d8f91f2a40746372e903e9e48e8aa6846b9abf2d28150780"},{"path":"runtime/core/hellolynk-neutral-host-process.mjs","sha256":"af6cb6585baae477f87ee880bd044dffb4c7f71667bfa78bcbf0d4d20e7483af"},{"path":"runtime/core/hellolynk-neutral-host-store-adapters.mjs","sha256":"3e425ca2cc111e750f55e94be2561cae8a3b308e473fb549e42da3443b67fd34"},{"path":"runtime/core/hellolynk-neutral-host-workbench-read-model.mjs","sha256":"65ca217dbd5be05f4cf38fd977b0d536526f79463a402fae90a7329dac375670"},{"path":"runtime/core/hellolynk-platform-credential-store.mjs","sha256":"f27f5f377cc4d6d2b5664212cf8fcc4c98d910064c1677ff9c1f776df1a59dba"},{"path":"runtime/core/hellolynk-relay-client-cli.mjs","sha256":"29707c4e0d91d5db6f46408b4c1101b9ab30b117500a9e315da8802e71a43010"},{"path":"runtime/core/hellolynk-release-retention.mjs","sha256":"9b02a42a510fa5ef4a251b6e675f9ccc60f20b718d17c1617027cd048c5634dd"},{"path":"runtime/core/hellolynk-runtime-safety.cjs","sha256":"43d576d9f774409f4a735793c1503a6f397e787b10c59a4ac9cc9257299f5efe"},{"path":"runtime/core/hellolynk-workbench-action-grants.mjs","sha256":"076d1bb848c85c06695440f33daebd853a9f49147a85cf582cc3e2964d95198a"},{"path":"runtime/core/hellolynk-workbench-connection.mjs","sha256":"d3396350fd75af78e60772e021cf6dfb643d9eee41894c5461c959a56650cb60"},{"path":"runtime/neutral-host-bootstrap.mjs","sha256":"db0ffd88a5fbb9091f16ceab4e391ac6919ba2640cdbc358574034779f848d7e"},{"path":"runtime/neutral-host-release-entry.mjs","sha256":"d434d392c85728228772369e9a890cef34598833ab2433dcc7b963c17bf5c146"},{"path":"runtime/neutral-host-release-loader.mjs","sha256":"00b226c65732bcd4d18d2b1b4ebc5092b7073fac52ee500d5d746b01217bfa65"},{"path":"runtime/neutral-host-release-manifest.json","sha256":"8171d1ac9ba90e45f3cf9cc7dab5f4c05a283101c2457e4c5e8870ae54269eba"},{"path":"runtime/neutral-host-release-pin.json","sha256":"a5cc48363f9cb8ff174f02d6cb20f95e314c7520f89eab5027f47a41a3017e2c"},{"path":"runtime/platform/windows/configure-agent.ps1","sha256":"7dc7c75bf0f7e45060b041a08d502993afe84581040f165e7f4437bf490708fa"},{"path":"runtime/platform/windows/credential-store.ps1","sha256":"d00dae4af08205fffa52c4956d1c87d5c3423e8f20982ccfc1b76e3424fe442e"},{"path":"runtime/platform/windows/hellolynk-host-protected-store.ps1","sha256":"24357e8ce54090b4ec68e457f02c9e834a80f3273ef3c03a8c0fa7258797fb49"},{"path":"runtime/platform/windows/hellolynk-human-confirmation-ledger.ps1","sha256":"4612561e2128dfd96c018f2c2d9ae41016f35bb6df8536314e9f0fb428165a82"},{"path":"runtime/platform/windows/hellolynk-local-data-key.ps1","sha256":"0976a0ecdd724e767b87e65743a230569c3fcb30e2449cf38bb718eb1604c15c"},{"path":"runtime/platform/windows/hellolynk-native-human-confirmation-broker.ps1","sha256":"757a731a3e8761d5d473db19ecfc330783f2826663a0057c4d6896e679d7a388"},{"path":"runtime/workbench/candidate-bootstrap.mjs","sha256":"891b02f750693e5b4836e716922c2d632f6736b2a5b3b7417f161499459f3f56"},{"path":"runtime/workbench/contract.mjs","sha256":"20648c3ed8e20b984b698010855414f8d4acaf0e2ade53b997b5582a85d90a08"},{"path":"runtime/workbench/hellolynk-workbench-build.json","sha256":"43e42633242cb456ecf2a120380230485e4d8533934ad6242089049d9282da11"},{"path":"runtime/workbench/host-capabilities.mjs","sha256":"4e1a82e6cb46dd775ba39e2d34ff21eb1c293523883d18e607084ca91cfffb87"},{"path":"runtime/workbench/i18n.mjs","sha256":"272917746c06cabc1b87b94341f2deca5591f0bea2d7a0e07b2d959d8e1f8c74"},{"path":"runtime/workbench/loopback-surface.mjs","sha256":"6a550034c5dd558dfd22f9cb589fd76df40a99e976538e3b5d01371d212c9aa6"},{"path":"runtime/workbench/mcp-app-bundle.mjs","sha256":"48fb8224cbaa7f78a386a79b2dba761f4de6c4b83b16032f7f96bd9783e172e4"},{"path":"runtime/workbench/service.mjs","sha256":"3bf82a0076e9fe3b62105c626fe0d622092224f28d3905c62eafd65bf5385dcc"},{"path":"runtime/workbench/state.mjs","sha256":"770d10f3bf76236772c87e86f5da346c013da387fb40c08360f895a7052cf7b5"},{"path":"runtime/workbench/transports.mjs","sha256":"0c9f42ca9c9a4b4cc29b1bdcc0a0488d16a9ad06c235c642dff9cd4fc6f0d528"},{"path":"runtime/workbench/ui/app.mjs","sha256":"643a5ac8d303f936ee87dd7c0c851aa1988e99ea9a9a45c6c89da28bdc76e799"},{"path":"runtime/workbench/ui/connection-form.mjs","sha256":"700ca793f5eddca1dfea5f220c73732efc51ea4e1f8b8fc36da2bb67136240f0"},{"path":"runtime/workbench/ui/hellolynk-mark.png","sha256":"108e5c90e1717a87169d317c15f8de33859ed487b06654888047c729d9ab5982"},{"path":"runtime/workbench/ui/http-transport.mjs","sha256":"b2fedbc2c34bcf065e0fc23c8c5fb37d358c03daa2c82ba46530b8dfb8fdc571"},{"path":"runtime/workbench/ui/icons/arrow-left.svg","sha256":"1c527dd347b5fba0312cdcd66cf7514a261855672f7585d1c8b1882f602442a6"},{"path":"runtime/workbench/ui/icons/close.svg","sha256":"22f5c4fb0660601a817ead151c37e82e93d39b2ef4ce1192d66f9099a3c59b36"},{"path":"runtime/workbench/ui/icons/contacts.svg","sha256":"de0add3c43bca68d8cae7736bc3ea8145ca0abb7f32c25127542c6f5a27b3f45"},{"path":"runtime/workbench/ui/icons/inbox.svg","sha256":"e1938770f085e6794a2e22aa3f8e890e083ac341a3c3faa13098a8243dc8306b"},{"path":"runtime/workbench/ui/icons/refresh.svg","sha256":"a7b91e87c1a25d117b1352d2ec131bf6e3fe67df2020af87e0d3575c06d86f29"},{"path":"runtime/workbench/ui/icons/search.svg","sha256":"135df34e348445114a1b88757fe7ef79a6718ffa4cc761c30f8026044552b699"},{"path":"runtime/workbench/ui/icons/security.svg","sha256":"9b6c502b2ce2795530f2e7018e2c24aaaf1cf49472f040868bad148d3321071e"},{"path":"runtime/workbench/ui/icons/settings.svg","sha256":"17b528a15b8187aecd80c4974c7432ec6e58e6a12e062104fae70bf63c46caa2"},{"path":"runtime/workbench/ui/index.html","sha256":"b24cd1f768d5132539722ac7ade3acfe5aa86a47ee16a2adacf3bbf18b70c989"},{"path":"runtime/workbench/ui/loopback-entry.mjs","sha256":"0e5e5d259ab6e2d8408c6d2e089551e6f279dcb1267e9db19f9d9dded0956fd4"},{"path":"runtime/workbench/ui/mcp-app-client.mjs","sha256":"91b1e6e84a12434c2be7614845febfa44afa341d5d7f580bc1bfc106ed37f8f8"},{"path":"runtime/workbench/ui/mcp-app-entry.mjs","sha256":"ba82ac55c4efcf7701bda33b6c6e0df4d59da542b1d6c33c96ba7f2391c4773a"},{"path":"runtime/workbench/ui/styles.css","sha256":"34d24d3d35800a796905049eb5f785f402cf1e82118c66efd4893bd003adbe31"}]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"contract":"hellolynk-workbuddy-immutable-package-pin-v1","manifestSha256":"
|
|
1
|
+
{"contract":"hellolynk-workbuddy-immutable-package-pin-v1","manifestSha256":"fb956894f5beca013d7b0ae19353475cdf93c80b0ed166fde06e0a6dc2eb7a2b"}
|