askshepherd 0.1.41 → 0.1.42
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/bin/shepherd-onboard.js +167 -55
- package/package.json +2 -1
- package/source-selection.cjs +18 -0
package/bin/shepherd-onboard.js
CHANGED
|
@@ -1,18 +1,21 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { execFile, execFileSync, spawn } from "node:child_process";
|
|
3
3
|
import { createHash } from "node:crypto";
|
|
4
|
-
import { constants as fsConstants, existsSync, mkdirSync, readdirSync, readFileSync, renameSync, unlinkSync, watch, writeFileSync } from "node:fs";
|
|
4
|
+
import { constants as fsConstants, existsSync, mkdirSync, readdirSync, readFileSync, realpathSync, renameSync, unlinkSync, watch, writeFileSync } from "node:fs";
|
|
5
5
|
import { access, chmod, mkdir, readdir, readFile, stat, writeFile } from "node:fs/promises";
|
|
6
6
|
import { createServer } from "node:http";
|
|
7
7
|
import { homedir, platform } from "node:os";
|
|
8
8
|
import { basename, dirname, join } from "node:path";
|
|
9
9
|
import readline from "node:readline";
|
|
10
10
|
import { fileURLToPath } from "node:url";
|
|
11
|
+
import sourceSelectionHelpers from "../source-selection.cjs";
|
|
12
|
+
|
|
13
|
+
const { sourceSelectionFromSession } = sourceSelectionHelpers;
|
|
11
14
|
|
|
12
15
|
const DEFAULT_API_URL = "https://brain-api-customer-facing.up.railway.app";
|
|
13
16
|
const PACKAGE_NAME = "askshepherd";
|
|
14
17
|
const PACKAGE_SPEC = `${PACKAGE_NAME}@latest`;
|
|
15
|
-
const PACKAGE_VERSION = "0.1.
|
|
18
|
+
const PACKAGE_VERSION = "0.1.42";
|
|
16
19
|
const MCP_SERVER_NAME = "shepherd";
|
|
17
20
|
const PACKAGE_DIR = dirname(dirname(fileURLToPath(import.meta.url)));
|
|
18
21
|
const DEFAULT_AGENT_STATE_PATH = join(homedir(), ".shepherd", "raw-onboarding-agent.json");
|
|
@@ -115,18 +118,30 @@ const command = rawArgv[0] && !rawArgv[0].startsWith("--") ? rawArgv[0] : "onboa
|
|
|
115
118
|
const args = parseArgs(command === "onboard" ? rawArgv : rawArgv.slice(1));
|
|
116
119
|
let messagesPermissionNoticePrinted = false;
|
|
117
120
|
|
|
118
|
-
if (
|
|
119
|
-
|
|
120
|
-
|
|
121
|
+
if (isCliEntrypoint()) {
|
|
122
|
+
if (command === "help" || args.help) {
|
|
123
|
+
printHelp(command === "help" ? "onboard" : command);
|
|
124
|
+
process.exit(0);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
void dispatch().catch((err) => {
|
|
128
|
+
console.error(`\nShepherd onboarding failed: ${safeError(err)}`);
|
|
129
|
+
if (args.debug === true) {
|
|
130
|
+
console.error(rawErrorDetails(err));
|
|
131
|
+
}
|
|
132
|
+
process.exit(1);
|
|
133
|
+
});
|
|
121
134
|
}
|
|
122
135
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
136
|
+
function isCliEntrypoint() {
|
|
137
|
+
if (!process.argv[1]) return false;
|
|
138
|
+
const modulePath = fileURLToPath(import.meta.url);
|
|
139
|
+
try {
|
|
140
|
+
return realpathSync(modulePath) === realpathSync(process.argv[1]);
|
|
141
|
+
} catch {
|
|
142
|
+
return modulePath === process.argv[1];
|
|
127
143
|
}
|
|
128
|
-
|
|
129
|
-
});
|
|
144
|
+
}
|
|
130
145
|
|
|
131
146
|
async function dispatch() {
|
|
132
147
|
if (command === "onboard") {
|
|
@@ -153,6 +168,10 @@ async function dispatch() {
|
|
|
153
168
|
await runWriteMessagesConfig();
|
|
154
169
|
} else if (command === "install-messages-agent") {
|
|
155
170
|
await runInstallMessagesAgent();
|
|
171
|
+
} else if (command === "write-coding-sessions-config") {
|
|
172
|
+
await runWriteCodingSessionsConfig();
|
|
173
|
+
} else if (command === "install-coding-sessions-agent") {
|
|
174
|
+
await runInstallCodingSessionsAgent();
|
|
156
175
|
} else if (command === "coding-sessions-agent") {
|
|
157
176
|
await runCodingSessionsAgent();
|
|
158
177
|
} else if (command === "coding-sessions-status") {
|
|
@@ -1412,6 +1431,7 @@ async function runWriteMessagesConfig() {
|
|
|
1412
1431
|
apiUrl: trimTrailingSlash(requiredConfigString(input.apiUrl, "apiUrl")),
|
|
1413
1432
|
userId: requiredConfigString(input.userId, "userId"),
|
|
1414
1433
|
agentToken: requiredConfigString(input.agentToken, "agentToken"),
|
|
1434
|
+
handle: optionalString(input.handle),
|
|
1415
1435
|
backfillDays: parseBackfillDays(input.backfillDays, null),
|
|
1416
1436
|
allowedChatIds: input.allowedChatIds,
|
|
1417
1437
|
selectedChats: Array.isArray(input.selectedChats) ? input.selectedChats : [],
|
|
@@ -1419,6 +1439,20 @@ async function runWriteMessagesConfig() {
|
|
|
1419
1439
|
console.log(JSON.stringify({ configPath }, null, 2));
|
|
1420
1440
|
}
|
|
1421
1441
|
|
|
1442
|
+
async function runWriteCodingSessionsConfig() {
|
|
1443
|
+
const input = await readJsonInput();
|
|
1444
|
+
if (!input || typeof input !== "object" || Array.isArray(input)) {
|
|
1445
|
+
throw new Error("write-coding-sessions-config expects a JSON object on stdin.");
|
|
1446
|
+
}
|
|
1447
|
+
const configPath = await writeCodingSessionsConfig({
|
|
1448
|
+
apiUrl: trimTrailingSlash(requiredConfigString(input.apiUrl, "apiUrl")),
|
|
1449
|
+
userId: requiredConfigString(input.userId, "userId"),
|
|
1450
|
+
agentToken: requiredConfigString(input.agentToken, "agentToken"),
|
|
1451
|
+
intervalSeconds: Number(input.intervalSeconds ?? args["coding-sessions-interval-seconds"] ?? 60),
|
|
1452
|
+
});
|
|
1453
|
+
console.log(JSON.stringify({ configPath }, null, 2));
|
|
1454
|
+
}
|
|
1455
|
+
|
|
1422
1456
|
async function runInstallMessagesAgent() {
|
|
1423
1457
|
const configPath = stringArg("config");
|
|
1424
1458
|
if (!configPath) throw new Error("install-messages-agent requires --config <path>");
|
|
@@ -1444,6 +1478,31 @@ async function runInstallMessagesAgent() {
|
|
|
1444
1478
|
console.log(JSON.stringify(install, null, 2));
|
|
1445
1479
|
}
|
|
1446
1480
|
|
|
1481
|
+
async function runInstallCodingSessionsAgent() {
|
|
1482
|
+
const configPath = stringArg("config");
|
|
1483
|
+
if (!configPath) throw new Error("install-coding-sessions-agent requires --config <path>");
|
|
1484
|
+
let config;
|
|
1485
|
+
try {
|
|
1486
|
+
config = JSON.parse(await readFile(configPath, "utf8"));
|
|
1487
|
+
} catch (err) {
|
|
1488
|
+
if (err && typeof err === "object" && "code" in err) throw err;
|
|
1489
|
+
throw new Error(`install-coding-sessions-agent: config file at ${configPath} does not contain valid JSON.`);
|
|
1490
|
+
}
|
|
1491
|
+
const userId = stringArg("user-id") ?? requiredConfigString(config.userId, "userId");
|
|
1492
|
+
const overrides = {
|
|
1493
|
+
programArguments: parseJsonArrayArg("program"),
|
|
1494
|
+
environment: parseJsonObjectArg("env"),
|
|
1495
|
+
};
|
|
1496
|
+
|
|
1497
|
+
if (args["dry-run"]) {
|
|
1498
|
+
console.log(JSON.stringify(buildCodingSessionsAgentInstall(configPath, userId, overrides), null, 2));
|
|
1499
|
+
return;
|
|
1500
|
+
}
|
|
1501
|
+
|
|
1502
|
+
const install = await installCodingSessionsAgent(configPath, userId, overrides);
|
|
1503
|
+
console.log(JSON.stringify(install, null, 2));
|
|
1504
|
+
}
|
|
1505
|
+
|
|
1447
1506
|
async function readJsonInput() {
|
|
1448
1507
|
const chunks = [];
|
|
1449
1508
|
for await (const chunk of process.stdin) chunks.push(chunk);
|
|
@@ -1932,7 +1991,7 @@ Options:
|
|
|
1932
1991
|
return;
|
|
1933
1992
|
}
|
|
1934
1993
|
|
|
1935
|
-
if (which === "write-agent-state" || which === "write-messages-config" || which === "install-messages-agent") {
|
|
1994
|
+
if (which === "write-agent-state" || which === "write-messages-config" || which === "install-messages-agent" || which === "write-coding-sessions-config" || which === "install-coding-sessions-agent") {
|
|
1936
1995
|
console.log(`Shepherd onboarding engine commands
|
|
1937
1996
|
|
|
1938
1997
|
These non-interactive commands are used by GUI onboarding apps (for example the
|
|
@@ -1944,9 +2003,12 @@ Usage:
|
|
|
1944
2003
|
shepherd-onboard write-messages-config JSON object on stdin ({apiUrl, userId, agentToken, backfillDays?, allowedChatIds, selectedChats?}) is written to ~/.shepherd/raw-messages/<userId>.json. Prints {configPath}.
|
|
1945
2004
|
shepherd-onboard install-messages-agent --config <path>
|
|
1946
2005
|
Installs and verifies the Messages launchd agent for an existing config. Prints install metadata.
|
|
2006
|
+
shepherd-onboard write-coding-sessions-config JSON object on stdin ({apiUrl, userId, agentToken, intervalSeconds?}) is written to ~/.shepherd/coding-sessions/<userId>.json. Prints {configPath}.
|
|
2007
|
+
shepherd-onboard install-coding-sessions-agent --config <path>
|
|
2008
|
+
Installs and verifies the Coding Sessions launchd agent for an existing config. Prints install metadata.
|
|
1947
2009
|
|
|
1948
|
-
install
|
|
1949
|
-
--config <path>
|
|
2010
|
+
install agent options:
|
|
2011
|
+
--config <path> Agent config created by onboarding. Required.
|
|
1950
2012
|
--user-id <id> Override the user ID. Defaults to the config's userId.
|
|
1951
2013
|
--program <json_array> Replace the default npx launcher with custom ProgramArguments (e.g. a signed app binary). --config <path> is appended.
|
|
1952
2014
|
--env <json_object> Extra EnvironmentVariables merged into the launchd plist (e.g. ELECTRON_RUN_AS_NODE).
|
|
@@ -2294,23 +2356,6 @@ function selectedSources() {
|
|
|
2294
2356
|
return selected;
|
|
2295
2357
|
}
|
|
2296
2358
|
|
|
2297
|
-
function sourceSelectionFromSession(response, fallback) {
|
|
2298
|
-
const raw = response?.sources;
|
|
2299
|
-
if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
|
|
2300
|
-
return fallback ? { ...fallback } : null;
|
|
2301
|
-
}
|
|
2302
|
-
return {
|
|
2303
|
-
google: raw.google === true,
|
|
2304
|
-
slack: raw.slack === true,
|
|
2305
|
-
github: raw.github === true,
|
|
2306
|
-
granola: raw.granola === true,
|
|
2307
|
-
messages: raw.messages === true,
|
|
2308
|
-
discord: raw.discord === true,
|
|
2309
|
-
instagram: raw.instagram === true,
|
|
2310
|
-
codingSessions: raw.codingSessions === true,
|
|
2311
|
-
};
|
|
2312
|
-
}
|
|
2313
|
-
|
|
2314
2359
|
function sourceSelectionFromList(value) {
|
|
2315
2360
|
const selected = {
|
|
2316
2361
|
google: false,
|
|
@@ -2927,6 +2972,7 @@ async function writeMessagesConfig(input) {
|
|
|
2927
2972
|
apiUrl: input.apiUrl,
|
|
2928
2973
|
userId: input.userId,
|
|
2929
2974
|
agentToken: input.agentToken,
|
|
2975
|
+
...(input.handle ? { handle: input.handle } : {}),
|
|
2930
2976
|
backfillDays: input.backfillDays,
|
|
2931
2977
|
allChats,
|
|
2932
2978
|
allowedChatIds: allChats ? [] : allowedChatIds,
|
|
@@ -3057,22 +3103,29 @@ async function writeCodingSessionsConfig(input) {
|
|
|
3057
3103
|
return path;
|
|
3058
3104
|
}
|
|
3059
3105
|
|
|
3060
|
-
|
|
3061
|
-
if (platform() !== "darwin") {
|
|
3062
|
-
throw new Error("automatic local coding-session sync is only supported on macOS");
|
|
3063
|
-
}
|
|
3064
|
-
|
|
3106
|
+
function buildCodingSessionsAgentInstall(configPath, userId, overrides = {}) {
|
|
3065
3107
|
const safeId = safeFileId(userId);
|
|
3066
3108
|
const label = `ai.shepherd.coding-sessions.${safeId}`;
|
|
3067
3109
|
const rawDir = join(homedir(), ".shepherd", "coding-sessions");
|
|
3068
3110
|
const agentsDir = join(homedir(), "Library", "LaunchAgents");
|
|
3069
|
-
await mkdir(rawDir, { recursive: true });
|
|
3070
|
-
await mkdir(agentsDir, { recursive: true });
|
|
3071
|
-
|
|
3072
3111
|
const plistPath = join(agentsDir, `${label}.plist`);
|
|
3073
3112
|
const stdoutPath = join(rawDir, `${safeId}.out.log`);
|
|
3074
3113
|
const stderrPath = join(rawDir, `${safeId}.err.log`);
|
|
3075
|
-
const
|
|
3114
|
+
const programPrefix = Array.isArray(overrides.programArguments) && overrides.programArguments.length > 0
|
|
3115
|
+
? overrides.programArguments
|
|
3116
|
+
: ["/usr/bin/env", "npx", "-y", PACKAGE_SPEC, "coding-sessions-agent"];
|
|
3117
|
+
const programArguments = [...programPrefix, "--config", configPath];
|
|
3118
|
+
const environment = {
|
|
3119
|
+
PATH: launchAgentPath(),
|
|
3120
|
+
...stringRecord(overrides.environment),
|
|
3121
|
+
};
|
|
3122
|
+
|
|
3123
|
+
const programArgumentsXml = programArguments
|
|
3124
|
+
.map((value) => ` <string>${xmlEscape(value)}</string>`)
|
|
3125
|
+
.join("\n");
|
|
3126
|
+
const environmentXml = Object.entries(environment)
|
|
3127
|
+
.map(([key, value]) => ` <key>${xmlEscape(key)}</key>\n <string>${xmlEscape(value)}</string>`)
|
|
3128
|
+
.join("\n");
|
|
3076
3129
|
|
|
3077
3130
|
const plist = `<?xml version="1.0" encoding="UTF-8"?>
|
|
3078
3131
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
@@ -3082,39 +3135,50 @@ async function installCodingSessionsAgent(configPath, userId) {
|
|
|
3082
3135
|
<string>${xmlEscape(label)}</string>
|
|
3083
3136
|
<key>ProgramArguments</key>
|
|
3084
3137
|
<array>
|
|
3085
|
-
|
|
3086
|
-
<string>npx</string>
|
|
3087
|
-
<string>-y</string>
|
|
3088
|
-
<string>${PACKAGE_SPEC}</string>
|
|
3089
|
-
<string>coding-sessions-agent</string>
|
|
3090
|
-
<string>--config</string>
|
|
3091
|
-
<string>${xmlEscape(configPath)}</string>
|
|
3138
|
+
${programArgumentsXml}
|
|
3092
3139
|
</array>
|
|
3093
3140
|
<key>KeepAlive</key>
|
|
3094
3141
|
<true/>
|
|
3095
3142
|
<key>RunAtLoad</key>
|
|
3096
3143
|
<true/>
|
|
3144
|
+
<key>ThrottleInterval</key>
|
|
3145
|
+
<integer>10</integer>
|
|
3146
|
+
<key>WorkingDirectory</key>
|
|
3147
|
+
<string>${xmlEscape(rawDir)}</string>
|
|
3097
3148
|
<key>StandardOutPath</key>
|
|
3098
3149
|
<string>${xmlEscape(stdoutPath)}</string>
|
|
3099
3150
|
<key>StandardErrorPath</key>
|
|
3100
3151
|
<string>${xmlEscape(stderrPath)}</string>
|
|
3101
3152
|
<key>EnvironmentVariables</key>
|
|
3102
3153
|
<dict>
|
|
3103
|
-
|
|
3104
|
-
<string>${xmlEscape(launchPath)}</string>
|
|
3154
|
+
${environmentXml}
|
|
3105
3155
|
</dict>
|
|
3106
3156
|
</dict>
|
|
3107
3157
|
</plist>
|
|
3108
3158
|
`;
|
|
3109
3159
|
|
|
3160
|
+
return { label, rawDir, agentsDir, plistPath, stdoutPath, stderrPath, programArguments, environment, plist };
|
|
3161
|
+
}
|
|
3162
|
+
|
|
3163
|
+
async function installCodingSessionsAgent(configPath, userId, overrides = {}) {
|
|
3164
|
+
if (platform() !== "darwin") {
|
|
3165
|
+
throw new Error("automatic local coding-session sync is only supported on macOS");
|
|
3166
|
+
}
|
|
3167
|
+
|
|
3168
|
+
const install = buildCodingSessionsAgentInstall(configPath, userId, overrides);
|
|
3169
|
+
const { label, rawDir, agentsDir, plistPath, stdoutPath, stderrPath, plist } = install;
|
|
3170
|
+
await mkdir(rawDir, { recursive: true });
|
|
3171
|
+
await mkdir(agentsDir, { recursive: true });
|
|
3172
|
+
|
|
3110
3173
|
await writeFile(plistPath, plist, { mode: 0o600 });
|
|
3174
|
+
await chmod(plistPath, 0o600);
|
|
3111
3175
|
const stdoutOffset = await fileLength(stdoutPath);
|
|
3112
3176
|
const stderrOffset = await fileLength(stderrPath);
|
|
3113
3177
|
await execFileQuiet("launchctl", ["unload", plistPath], { ignoreError: true });
|
|
3114
3178
|
await execFileQuiet("launchctl", ["load", plistPath]);
|
|
3115
3179
|
await execFileQuiet("launchctl", ["start", label], { ignoreError: true });
|
|
3116
3180
|
await verifyCodingSessionsAgentLaunch({ label, stdoutPath, stderrPath, stdoutOffset, stderrOffset });
|
|
3117
|
-
return
|
|
3181
|
+
return install;
|
|
3118
3182
|
}
|
|
3119
3183
|
|
|
3120
3184
|
async function verifyCodingSessionsAgentLaunch({ label, stdoutPath, stderrPath, stdoutOffset, stderrOffset }) {
|
|
@@ -4249,10 +4313,19 @@ function messageIdentity(msg) {
|
|
|
4249
4313
|
}
|
|
4250
4314
|
|
|
4251
4315
|
function messageState(msg) {
|
|
4316
|
+
const participant = messageParticipant(msg);
|
|
4252
4317
|
return {
|
|
4253
4318
|
text: msg?.text ?? null,
|
|
4319
|
+
chatId: msg?.chatId ?? null,
|
|
4320
|
+
chatKind: messageChatKind(msg),
|
|
4321
|
+
participant,
|
|
4322
|
+
isFromMe: Boolean(msg?.isFromMe),
|
|
4254
4323
|
editedAt: isoDate(msg?.editedAt),
|
|
4255
4324
|
retractedAt: isoDate(msg?.retractedAt),
|
|
4325
|
+
replyToMessageId: msg?.replyToMessageId ?? null,
|
|
4326
|
+
threadRootMessageId: msg?.threadRootMessageId ?? null,
|
|
4327
|
+
affectedParticipant: msg?.affectedParticipant ?? null,
|
|
4328
|
+
kind: msg?.kind ?? null,
|
|
4256
4329
|
hasAttachments: Boolean(msg?.hasAttachments ?? (Array.isArray(msg?.attachments) && msg.attachments.length > 0)),
|
|
4257
4330
|
attachments: messageAttachmentState(msg),
|
|
4258
4331
|
};
|
|
@@ -4260,8 +4333,16 @@ function messageState(msg) {
|
|
|
4260
4333
|
|
|
4261
4334
|
function sameMessageState(a, b) {
|
|
4262
4335
|
return a.text === b.text
|
|
4336
|
+
&& a.chatId === b.chatId
|
|
4337
|
+
&& a.chatKind === b.chatKind
|
|
4338
|
+
&& a.participant === b.participant
|
|
4339
|
+
&& a.isFromMe === b.isFromMe
|
|
4263
4340
|
&& a.editedAt === b.editedAt
|
|
4264
4341
|
&& a.retractedAt === b.retractedAt
|
|
4342
|
+
&& a.replyToMessageId === b.replyToMessageId
|
|
4343
|
+
&& a.threadRootMessageId === b.threadRootMessageId
|
|
4344
|
+
&& a.affectedParticipant === b.affectedParticipant
|
|
4345
|
+
&& a.kind === b.kind
|
|
4265
4346
|
&& a.hasAttachments === b.hasAttachments
|
|
4266
4347
|
&& stableLocalJson(a.attachments) === stableLocalJson(b.attachments);
|
|
4267
4348
|
}
|
|
@@ -4699,7 +4780,7 @@ function startMessagesContactSync(sender, contactLookup, opts = {}) {
|
|
|
4699
4780
|
const observeMessages = (messages) => {
|
|
4700
4781
|
let changed = false;
|
|
4701
4782
|
for (const msg of messages ?? []) {
|
|
4702
|
-
if (rememberObservedHandle(observedHandles, contactLookup, msg
|
|
4783
|
+
if (rememberObservedHandle(observedHandles, contactLookup, messageParticipant(msg))) changed = true;
|
|
4703
4784
|
if (msg?.affectedParticipant) {
|
|
4704
4785
|
if (rememberObservedHandle(observedHandles, contactLookup, msg.affectedParticipant)) changed = true;
|
|
4705
4786
|
}
|
|
@@ -4784,6 +4865,8 @@ function createMessageSerializer(kit, contactLookup = emptyContactLookup()) {
|
|
|
4784
4865
|
},
|
|
4785
4866
|
serialize(msg) {
|
|
4786
4867
|
const chatId = msg.chatId ?? "unknown";
|
|
4868
|
+
const participant = messageParticipant(msg);
|
|
4869
|
+
const chatKind = messageChatKind(msg);
|
|
4787
4870
|
const attachments = Array.isArray(msg.attachments) ? msg.attachments : [];
|
|
4788
4871
|
return {
|
|
4789
4872
|
messageId: String(msg.id ?? msg.messageId ?? msg.rowId),
|
|
@@ -4791,9 +4874,9 @@ function createMessageSerializer(kit, contactLookup = emptyContactLookup()) {
|
|
|
4791
4874
|
text: msg.text ?? null,
|
|
4792
4875
|
service: msg.service ?? "iMessage",
|
|
4793
4876
|
chatId,
|
|
4794
|
-
chatKind
|
|
4877
|
+
chatKind,
|
|
4795
4878
|
chatName: chatNames.get(chatId) ?? null,
|
|
4796
|
-
participant
|
|
4879
|
+
participant,
|
|
4797
4880
|
isFromMe: Boolean(msg.isFromMe),
|
|
4798
4881
|
createdAt: isoDate(msg.createdAt) ?? new Date().toISOString(),
|
|
4799
4882
|
deliveredAt: isoDate(msg.deliveredAt),
|
|
@@ -4835,13 +4918,31 @@ function createMessageSerializer(kit, contactLookup = emptyContactLookup()) {
|
|
|
4835
4918
|
isForwarded: Boolean(msg.isForwarded),
|
|
4836
4919
|
affectedParticipant: msg.affectedParticipant ?? null,
|
|
4837
4920
|
newGroupName: msg.newGroupName ?? null,
|
|
4838
|
-
_resolved_name:
|
|
4839
|
-
_is_self_handle:
|
|
4921
|
+
_resolved_name: participant ? contactLookup.resolveName(participant) : null,
|
|
4922
|
+
_is_self_handle: participant ? contactLookup.isSelfHandle(participant) : false,
|
|
4840
4923
|
};
|
|
4841
4924
|
},
|
|
4842
4925
|
};
|
|
4843
4926
|
}
|
|
4844
4927
|
|
|
4928
|
+
function messageParticipant(msg) {
|
|
4929
|
+
const explicit = typeof msg?.participant === "string" ? msg.participant.trim() : "";
|
|
4930
|
+
if (explicit) return explicit;
|
|
4931
|
+
if (!isDirectMessageKind(messageChatKind(msg))) return null;
|
|
4932
|
+
return parseDmHandleFromChatId(msg?.chatId);
|
|
4933
|
+
}
|
|
4934
|
+
|
|
4935
|
+
function messageChatKind(msg) {
|
|
4936
|
+
const explicit = typeof msg?.chatKind === "string" ? msg.chatKind.trim() : "";
|
|
4937
|
+
if (explicit === "direct") return "dm";
|
|
4938
|
+
if (explicit) return explicit;
|
|
4939
|
+
return parseDmHandleFromChatId(msg?.chatId) ? "dm" : "unknown";
|
|
4940
|
+
}
|
|
4941
|
+
|
|
4942
|
+
function isDirectMessageKind(kind) {
|
|
4943
|
+
return kind === "dm";
|
|
4944
|
+
}
|
|
4945
|
+
|
|
4845
4946
|
function buildContactLookup(opts = {}) {
|
|
4846
4947
|
const addressBook = platform() === "darwin" ? loadContactsFromAddressBookDb() : { contacts: [], myCard: null };
|
|
4847
4948
|
if (opts.userId) {
|
|
@@ -5975,6 +6076,10 @@ function requiredConfigString(value, label) {
|
|
|
5975
6076
|
return value.trim();
|
|
5976
6077
|
}
|
|
5977
6078
|
|
|
6079
|
+
function optionalString(value) {
|
|
6080
|
+
return typeof value === "string" && value.trim() ? value.trim() : undefined;
|
|
6081
|
+
}
|
|
6082
|
+
|
|
5978
6083
|
function execFileQuiet(file, argv, opts = {}) {
|
|
5979
6084
|
return new Promise((resolve, reject) => {
|
|
5980
6085
|
execFile(file, argv, { windowsHide: true }, (error) => {
|
|
@@ -6040,3 +6145,10 @@ function rawErrorDetails(err) {
|
|
|
6040
6145
|
if (err instanceof Error) return err.stack ?? err.message;
|
|
6041
6146
|
return String(err);
|
|
6042
6147
|
}
|
|
6148
|
+
|
|
6149
|
+
export const __test = {
|
|
6150
|
+
messageChatKind,
|
|
6151
|
+
messageParticipant,
|
|
6152
|
+
messageState,
|
|
6153
|
+
sameMessageState,
|
|
6154
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "askshepherd",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.42",
|
|
4
4
|
"description": "Customer-facing Shepherd production onboarding and MCP CLI",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
"files": [
|
|
16
16
|
"assets",
|
|
17
17
|
"bin",
|
|
18
|
+
"source-selection.cjs",
|
|
18
19
|
"README.md"
|
|
19
20
|
],
|
|
20
21
|
"engines": {
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
function sourceSelectionFromSession(response, fallback) {
|
|
2
|
+
const raw = response?.sources;
|
|
3
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
|
|
4
|
+
return fallback ? { ...fallback } : null;
|
|
5
|
+
}
|
|
6
|
+
return {
|
|
7
|
+
google: raw.google === true,
|
|
8
|
+
slack: raw.slack === true,
|
|
9
|
+
github: raw.github === true,
|
|
10
|
+
granola: raw.granola === true,
|
|
11
|
+
messages: raw.messages === true,
|
|
12
|
+
discord: raw.discord === true,
|
|
13
|
+
instagram: raw.instagram === true,
|
|
14
|
+
codingSessions: raw.codingSessions === true,
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
module.exports = { sourceSelectionFromSession };
|