@staff0rd/assist 0.607.0 → 0.609.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -0
- package/claude/commands/slack-post.md +39 -0
- package/claude/settings.json +2 -0
- package/dist/commands/sessions/web/bundle.js +2 -2
- package/dist/index.js +208 -84
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -6,7 +6,7 @@ import { Command } from "commander";
|
|
|
6
6
|
// package.json
|
|
7
7
|
var package_default = {
|
|
8
8
|
name: "@staff0rd/assist",
|
|
9
|
-
version: "0.
|
|
9
|
+
version: "0.609.0",
|
|
10
10
|
type: "module",
|
|
11
11
|
main: "dist/index.js",
|
|
12
12
|
bin: {
|
|
@@ -547,6 +547,9 @@ var assistConfigShape = {
|
|
|
547
547
|
refreshToken: secretConfigValue(z3.string()).optional(),
|
|
548
548
|
tokenExpiresAt: z3.number().optional()
|
|
549
549
|
}).optional(),
|
|
550
|
+
slack: z3.strictObject({
|
|
551
|
+
channel: z3.string().optional()
|
|
552
|
+
}).optional(),
|
|
550
553
|
prs: z3.strictObject({
|
|
551
554
|
slack: z3.string().optional(),
|
|
552
555
|
required: z3.boolean().default(false),
|
|
@@ -4761,6 +4764,15 @@ var sessionsConfigHelp = [
|
|
|
4761
4764
|
}
|
|
4762
4765
|
];
|
|
4763
4766
|
|
|
4767
|
+
// src/commands/slack/slackConfigHelp.ts
|
|
4768
|
+
var slackConfigHelp = [
|
|
4769
|
+
{
|
|
4770
|
+
key: "slack.channel",
|
|
4771
|
+
setter: 'assist config set slack.channel "#general"',
|
|
4772
|
+
note: "channel 'assist slack post' targets when no [channel] argument is given"
|
|
4773
|
+
}
|
|
4774
|
+
];
|
|
4775
|
+
|
|
4764
4776
|
// src/commands/sql/sqlConfigHelp.ts
|
|
4765
4777
|
var sqlConfigHelp = [
|
|
4766
4778
|
{
|
|
@@ -4880,6 +4892,7 @@ var configHelpEntries = [
|
|
|
4880
4892
|
...runConfigHelp,
|
|
4881
4893
|
...seqConfigHelp,
|
|
4882
4894
|
...sessionsConfigHelp,
|
|
4895
|
+
...slackConfigHelp,
|
|
4883
4896
|
...sqlConfigHelp,
|
|
4884
4897
|
...transcriptConfigHelp,
|
|
4885
4898
|
...verifyConfigHelp,
|
|
@@ -31100,6 +31113,114 @@ function registerSignal(program2) {
|
|
|
31100
31113
|
});
|
|
31101
31114
|
}
|
|
31102
31115
|
|
|
31116
|
+
// src/commands/slack/parseSlackThreadRef.ts
|
|
31117
|
+
import { InvalidArgumentError as InvalidArgumentError3 } from "commander";
|
|
31118
|
+
var MESSAGE_TS = /^\d{10}\.\d{6}$/;
|
|
31119
|
+
var PERMALINK_TS = /\/archives\/[^/?#]+\/p(\d{10})(\d{6})\b/;
|
|
31120
|
+
var PERMALINK_THREAD_TS = /[?&]thread_ts=(\d{10}\.\d{6})\b/;
|
|
31121
|
+
function parseSlackThreadRef(value) {
|
|
31122
|
+
const trimmed = value.trim();
|
|
31123
|
+
if (MESSAGE_TS.test(trimmed)) return trimmed;
|
|
31124
|
+
const thread = PERMALINK_THREAD_TS.exec(trimmed);
|
|
31125
|
+
if (thread) return thread[1];
|
|
31126
|
+
const permalink = PERMALINK_TS.exec(trimmed);
|
|
31127
|
+
if (permalink) return `${permalink[1]}.${permalink[2]}`;
|
|
31128
|
+
throw new InvalidArgumentError3(
|
|
31129
|
+
"Expected a message ts (1712345678.123456) or a Slack archives permalink (https://<workspace>.slack.com/archives/<channel>/p1712345678123456)."
|
|
31130
|
+
);
|
|
31131
|
+
}
|
|
31132
|
+
|
|
31133
|
+
// src/commands/slack/postSlackMessage.ts
|
|
31134
|
+
import { mkdirSync as mkdirSync22, writeFileSync as writeFileSync42 } from "fs";
|
|
31135
|
+
|
|
31136
|
+
// src/commands/slack/reviewProposedSlackMessage.ts
|
|
31137
|
+
import { randomUUID as randomUUID17 } from "crypto";
|
|
31138
|
+
async function reviewProposedSlackMessage(target, body, working) {
|
|
31139
|
+
const sessionId = process.env.ASSIST_SESSION_ID;
|
|
31140
|
+
if (process.env.ASSIST_SESSION !== "1" || !sessionId) return body;
|
|
31141
|
+
const { channel, threadTs } = target;
|
|
31142
|
+
const decision = await awaitPreviewApproval(
|
|
31143
|
+
"Slack message preview",
|
|
31144
|
+
{
|
|
31145
|
+
sessionId,
|
|
31146
|
+
requestId: randomUUID17(),
|
|
31147
|
+
title: threadTs ? `Reply in ${channel} thread ${threadTs}` : `Post to ${channel}`,
|
|
31148
|
+
body,
|
|
31149
|
+
prNumber: null,
|
|
31150
|
+
kind: "slack-post"
|
|
31151
|
+
},
|
|
31152
|
+
{
|
|
31153
|
+
saveEditedBody: working.save,
|
|
31154
|
+
rejectionAdvice: `Nothing was posted to ${channel}. The previewed markdown is at ${working.path}: revise that file in place and re-run this command to preview the revision.`
|
|
31155
|
+
}
|
|
31156
|
+
);
|
|
31157
|
+
return decision.body ?? body;
|
|
31158
|
+
}
|
|
31159
|
+
|
|
31160
|
+
// src/commands/slack/slackWorkingFile.ts
|
|
31161
|
+
import { join as join73 } from "path";
|
|
31162
|
+
function slackWorkingFile(channel) {
|
|
31163
|
+
const slug = channel.replace(/^[#@]/, "").toLowerCase().replace(/[^a-z0-9._-]+/g, "-").replace(/^-+|-+$/g, "") || "channel";
|
|
31164
|
+
const dir = join73(getStoreDir(), "slack");
|
|
31165
|
+
return { dir, bodyPath: join73(dir, `${slug}.md`) };
|
|
31166
|
+
}
|
|
31167
|
+
|
|
31168
|
+
// src/commands/slack/postSlackMessage.ts
|
|
31169
|
+
var USAGE5 = "Usage: assist slack post [channel] --body <body|->";
|
|
31170
|
+
async function postSlackMessage(channelArg, options2) {
|
|
31171
|
+
const channel = (channelArg ?? loadConfig().slack?.channel ?? "").trim();
|
|
31172
|
+
const body = options2.body?.trim();
|
|
31173
|
+
if (!channel) {
|
|
31174
|
+
console.error(
|
|
31175
|
+
'No channel given and slack.channel is not set. Pass one, or set a default with: assist config set slack.channel "#general"'
|
|
31176
|
+
);
|
|
31177
|
+
console.error(USAGE5);
|
|
31178
|
+
process.exit(1);
|
|
31179
|
+
}
|
|
31180
|
+
if (!body) {
|
|
31181
|
+
console.error(USAGE5);
|
|
31182
|
+
process.exit(1);
|
|
31183
|
+
}
|
|
31184
|
+
const threadTs = options2.thread;
|
|
31185
|
+
const { dir, bodyPath } = slackWorkingFile(channel);
|
|
31186
|
+
mkdirSync22(dir, { recursive: true });
|
|
31187
|
+
const write = (text18) => writeFileSync42(bodyPath, `${text18}
|
|
31188
|
+
`);
|
|
31189
|
+
write(body);
|
|
31190
|
+
const approved = await reviewProposedSlackMessage(
|
|
31191
|
+
{ channel, threadTs },
|
|
31192
|
+
body,
|
|
31193
|
+
{ path: bodyPath, save: write }
|
|
31194
|
+
);
|
|
31195
|
+
write(approved);
|
|
31196
|
+
const target = threadTs ? `${channel} (thread_ts ${threadTs})` : channel;
|
|
31197
|
+
console.log(`Approved for ${target}. The body to post is at:`);
|
|
31198
|
+
console.log(bodyPath);
|
|
31199
|
+
}
|
|
31200
|
+
|
|
31201
|
+
// src/commands/registerSlack.ts
|
|
31202
|
+
function registerSlack(program2) {
|
|
31203
|
+
const slackCommand = program2.command("slack").description("Slack utilities");
|
|
31204
|
+
const postCommand = slackCommand.command("post [channel]").description(
|
|
31205
|
+
"Preview a markdown message bound for a Slack channel (body of - reads it from stdin)"
|
|
31206
|
+
).option("--body <body>", "Message body (- reads it from stdin)").option(
|
|
31207
|
+
"--thread <ts-or-permalink>",
|
|
31208
|
+
"Reply in this thread: a message ts (1712345678.123456) or a Slack archives permalink",
|
|
31209
|
+
parseSlackThreadRef
|
|
31210
|
+
).addHelpText(
|
|
31211
|
+
"after",
|
|
31212
|
+
"\nThe command does not post: Slack is reachable only over MCP, so it previews the message and hands the approved body back for /slack-post to send.\nIn an assist web session the body is previewed for approve/reject first (with inline comments). On approval the approved body \u2014 including any edit made in the pane \u2014 is written to a working file under ~/.assist/slack/ and its path printed on the last line, preceded by the resolved thread_ts when --thread was given. On rejection nothing is handed back: the command exits non-zero with the reason and any inline comments, leaving the previewed markdown in the working file to revise in place.\nOutside a web session there is no preview and the body passes straight through.\nslack_send_message accepts standard markdown as it is \u2014 bold, italic, code, blockquotes, lists, links, code blocks, tables and headers \u2014 capped at 5000 characters."
|
|
31213
|
+
).action(
|
|
31214
|
+
async (channel, options2) => {
|
|
31215
|
+
await postSlackMessage(channel, {
|
|
31216
|
+
...options2,
|
|
31217
|
+
body: options2.body ? await readBodyArgument(options2.body) : void 0
|
|
31218
|
+
});
|
|
31219
|
+
}
|
|
31220
|
+
);
|
|
31221
|
+
configHelp(postCommand, slackConfigHelp);
|
|
31222
|
+
}
|
|
31223
|
+
|
|
31103
31224
|
// src/commands/sql/sqlAuth.ts
|
|
31104
31225
|
import chalk220 from "chalk";
|
|
31105
31226
|
|
|
@@ -32132,20 +32253,20 @@ async function configure() {
|
|
|
32132
32253
|
|
|
32133
32254
|
// src/commands/transcript/list.ts
|
|
32134
32255
|
import { existsSync as existsSync72, readdirSync as readdirSync20, statSync as statSync11 } from "fs";
|
|
32135
|
-
import { join as
|
|
32256
|
+
import { join as join84 } from "path";
|
|
32136
32257
|
function list4() {
|
|
32137
32258
|
const { vttDir } = getTranscriptConfig();
|
|
32138
32259
|
if (!existsSync72(vttDir)) return;
|
|
32139
32260
|
for (const entry of readdirSync20(vttDir)) {
|
|
32140
32261
|
if (!entry.endsWith(".vtt")) continue;
|
|
32141
|
-
if (statSync11(
|
|
32262
|
+
if (statSync11(join84(vttDir, entry)).isDirectory()) continue;
|
|
32142
32263
|
console.log(entry);
|
|
32143
32264
|
}
|
|
32144
32265
|
}
|
|
32145
32266
|
|
|
32146
32267
|
// src/commands/transcript/move.ts
|
|
32147
|
-
import { existsSync as existsSync73, mkdirSync as
|
|
32148
|
-
import { basename as basename21, join as
|
|
32268
|
+
import { existsSync as existsSync73, mkdirSync as mkdirSync28, renameSync as renameSync2, writeFileSync as writeFileSync46 } from "fs";
|
|
32269
|
+
import { basename as basename21, join as join85 } from "path";
|
|
32149
32270
|
|
|
32150
32271
|
// src/commands/transcript/convertVttToMarkdown.ts
|
|
32151
32272
|
function convertVttToMarkdown(inputPath) {
|
|
@@ -32155,9 +32276,9 @@ function convertVttToMarkdown(inputPath) {
|
|
|
32155
32276
|
// src/commands/transcript/move.ts
|
|
32156
32277
|
var DATE_REGEX = /^\d{4}-\d{2}-\d{2}$/;
|
|
32157
32278
|
function archiveRawVtt(vttDir, sourcePath, filename) {
|
|
32158
|
-
const processedDir =
|
|
32159
|
-
|
|
32160
|
-
renameSync2(sourcePath,
|
|
32279
|
+
const processedDir = join85(vttDir, "processed");
|
|
32280
|
+
mkdirSync28(processedDir, { recursive: true });
|
|
32281
|
+
renameSync2(sourcePath, join85(processedDir, filename));
|
|
32161
32282
|
}
|
|
32162
32283
|
function move(file, options2) {
|
|
32163
32284
|
const { date, client } = options2;
|
|
@@ -32167,19 +32288,19 @@ function move(file, options2) {
|
|
|
32167
32288
|
}
|
|
32168
32289
|
const { vttDir, transcriptsDir, summaryDir } = getTranscriptConfig();
|
|
32169
32290
|
const filename = basename21(file);
|
|
32170
|
-
const sourcePath =
|
|
32291
|
+
const sourcePath = join85(vttDir, filename);
|
|
32171
32292
|
if (!existsSync73(sourcePath)) {
|
|
32172
32293
|
console.error(`Error: VTT file not found: ${sourcePath}`);
|
|
32173
32294
|
process.exit(1);
|
|
32174
32295
|
}
|
|
32175
32296
|
const base = basename21(filename, ".vtt").replace(/ Transcription$/, "");
|
|
32176
32297
|
const outputName = `${date} ${base}.md`;
|
|
32177
|
-
const formattedDir =
|
|
32178
|
-
|
|
32179
|
-
const formattedPath =
|
|
32180
|
-
|
|
32298
|
+
const formattedDir = join85(transcriptsDir, client);
|
|
32299
|
+
mkdirSync28(formattedDir, { recursive: true });
|
|
32300
|
+
const formattedPath = join85(formattedDir, outputName);
|
|
32301
|
+
writeFileSync46(formattedPath, convertVttToMarkdown(sourcePath), "utf8");
|
|
32181
32302
|
archiveRawVtt(vttDir, sourcePath, filename);
|
|
32182
|
-
const summaryPath =
|
|
32303
|
+
const summaryPath = join85(summaryDir, client, outputName);
|
|
32183
32304
|
console.log(`Formatted transcript: ${formattedPath}`);
|
|
32184
32305
|
console.log(`Summary target: ${summaryPath}`);
|
|
32185
32306
|
}
|
|
@@ -32262,38 +32383,38 @@ function registerVerify(program2) {
|
|
|
32262
32383
|
|
|
32263
32384
|
// src/commands/voice/devices.ts
|
|
32264
32385
|
import { spawnSync as spawnSync9 } from "child_process";
|
|
32265
|
-
import { join as
|
|
32386
|
+
import { join as join87 } from "path";
|
|
32266
32387
|
|
|
32267
32388
|
// src/commands/voice/shared.ts
|
|
32268
32389
|
import { homedir as homedir25 } from "os";
|
|
32269
|
-
import { dirname as dirname36, join as
|
|
32390
|
+
import { dirname as dirname36, join as join86 } from "path";
|
|
32270
32391
|
import { fileURLToPath as fileURLToPath9 } from "url";
|
|
32271
32392
|
var __dirname6 = dirname36(fileURLToPath9(import.meta.url));
|
|
32272
|
-
var VOICE_DIR =
|
|
32393
|
+
var VOICE_DIR = join86(homedir25(), ".assist", "voice");
|
|
32273
32394
|
var voicePaths = {
|
|
32274
32395
|
dir: VOICE_DIR,
|
|
32275
|
-
pid:
|
|
32276
|
-
log:
|
|
32277
|
-
venv:
|
|
32278
|
-
lock:
|
|
32396
|
+
pid: join86(VOICE_DIR, "voice.pid"),
|
|
32397
|
+
log: join86(VOICE_DIR, "voice.log"),
|
|
32398
|
+
venv: join86(VOICE_DIR, ".venv"),
|
|
32399
|
+
lock: join86(VOICE_DIR, "voice.lock")
|
|
32279
32400
|
};
|
|
32280
32401
|
function getPythonDir() {
|
|
32281
|
-
return
|
|
32402
|
+
return join86(__dirname6, "commands", "voice", "python");
|
|
32282
32403
|
}
|
|
32283
32404
|
function getVenvPython() {
|
|
32284
|
-
return process.platform === "win32" ?
|
|
32405
|
+
return process.platform === "win32" ? join86(voicePaths.venv, "Scripts", "python.exe") : join86(voicePaths.venv, "bin", "python");
|
|
32285
32406
|
}
|
|
32286
32407
|
function getLockDir() {
|
|
32287
32408
|
const config = loadConfig();
|
|
32288
32409
|
return config.voice?.lockDir ?? VOICE_DIR;
|
|
32289
32410
|
}
|
|
32290
32411
|
function getLockFile() {
|
|
32291
|
-
return
|
|
32412
|
+
return join86(getLockDir(), "voice.lock");
|
|
32292
32413
|
}
|
|
32293
32414
|
|
|
32294
32415
|
// src/commands/voice/devices.ts
|
|
32295
32416
|
function devices() {
|
|
32296
|
-
const script =
|
|
32417
|
+
const script = join87(getPythonDir(), "list_devices.py");
|
|
32297
32418
|
spawnSync9(getVenvPython(), [script], { stdio: "inherit" });
|
|
32298
32419
|
}
|
|
32299
32420
|
|
|
@@ -32327,13 +32448,13 @@ function logs(options2) {
|
|
|
32327
32448
|
|
|
32328
32449
|
// src/commands/voice/setup.ts
|
|
32329
32450
|
import { spawnSync as spawnSync10 } from "child_process";
|
|
32330
|
-
import { mkdirSync as
|
|
32331
|
-
import { join as
|
|
32451
|
+
import { mkdirSync as mkdirSync30 } from "fs";
|
|
32452
|
+
import { join as join89 } from "path";
|
|
32332
32453
|
|
|
32333
32454
|
// src/commands/voice/checkLockFile.ts
|
|
32334
32455
|
import { execSync as execSync58 } from "child_process";
|
|
32335
|
-
import { existsSync as existsSync75, mkdirSync as
|
|
32336
|
-
import { join as
|
|
32456
|
+
import { existsSync as existsSync75, mkdirSync as mkdirSync29, readFileSync as readFileSync57, writeFileSync as writeFileSync47 } from "fs";
|
|
32457
|
+
import { join as join88 } from "path";
|
|
32337
32458
|
function isProcessAlive2(pid) {
|
|
32338
32459
|
try {
|
|
32339
32460
|
process.kill(pid, 0);
|
|
@@ -32370,8 +32491,8 @@ function bootstrapVenv() {
|
|
|
32370
32491
|
}
|
|
32371
32492
|
function writeLockFile(pid) {
|
|
32372
32493
|
const lockFile = getLockFile();
|
|
32373
|
-
|
|
32374
|
-
|
|
32494
|
+
mkdirSync29(join88(lockFile, ".."), { recursive: true });
|
|
32495
|
+
writeFileSync47(
|
|
32375
32496
|
lockFile,
|
|
32376
32497
|
JSON.stringify({
|
|
32377
32498
|
pid,
|
|
@@ -32383,10 +32504,10 @@ function writeLockFile(pid) {
|
|
|
32383
32504
|
|
|
32384
32505
|
// src/commands/voice/setup.ts
|
|
32385
32506
|
function setup() {
|
|
32386
|
-
|
|
32507
|
+
mkdirSync30(voicePaths.dir, { recursive: true });
|
|
32387
32508
|
bootstrapVenv();
|
|
32388
32509
|
console.log("\nDownloading models...\n");
|
|
32389
|
-
const script =
|
|
32510
|
+
const script = join89(getPythonDir(), "setup_models.py");
|
|
32390
32511
|
const result = spawnSync10(getVenvPython(), [script], {
|
|
32391
32512
|
stdio: "inherit",
|
|
32392
32513
|
env: { ...process.env, VOICE_LOG_FILE: voicePaths.log }
|
|
@@ -32399,8 +32520,8 @@ function setup() {
|
|
|
32399
32520
|
|
|
32400
32521
|
// src/commands/voice/start.ts
|
|
32401
32522
|
import { spawn as spawn8 } from "child_process";
|
|
32402
|
-
import { mkdirSync as
|
|
32403
|
-
import { join as
|
|
32523
|
+
import { mkdirSync as mkdirSync31, writeFileSync as writeFileSync48 } from "fs";
|
|
32524
|
+
import { join as join90 } from "path";
|
|
32404
32525
|
|
|
32405
32526
|
// src/commands/voice/buildDaemonEnv.ts
|
|
32406
32527
|
function buildDaemonEnv(options2) {
|
|
@@ -32428,17 +32549,17 @@ function spawnBackground(python, script, env) {
|
|
|
32428
32549
|
console.error("Failed to start voice daemon");
|
|
32429
32550
|
process.exit(1);
|
|
32430
32551
|
}
|
|
32431
|
-
|
|
32552
|
+
writeFileSync48(voicePaths.pid, String(pid));
|
|
32432
32553
|
writeLockFile(pid);
|
|
32433
32554
|
console.log(`Voice daemon started (PID ${pid})`);
|
|
32434
32555
|
}
|
|
32435
32556
|
function start2(options2) {
|
|
32436
|
-
|
|
32557
|
+
mkdirSync31(voicePaths.dir, { recursive: true });
|
|
32437
32558
|
checkLockFile();
|
|
32438
32559
|
bootstrapVenv();
|
|
32439
32560
|
const debug = options2.debug || options2.foreground || process.platform === "win32";
|
|
32440
32561
|
const env = buildDaemonEnv({ debug });
|
|
32441
|
-
const script =
|
|
32562
|
+
const script = join90(getPythonDir(), "voice_daemon.py");
|
|
32442
32563
|
const python = getVenvPython();
|
|
32443
32564
|
if (options2.foreground) {
|
|
32444
32565
|
spawnForeground(python, script, env);
|
|
@@ -32569,11 +32690,11 @@ function changedPaths(from, cwd) {
|
|
|
32569
32690
|
}
|
|
32570
32691
|
|
|
32571
32692
|
// src/commands/watch/readBuiltVersion.ts
|
|
32572
|
-
import { join as
|
|
32693
|
+
import { join as join91 } from "path";
|
|
32573
32694
|
function readBuiltVersion(cwd) {
|
|
32574
32695
|
try {
|
|
32575
32696
|
const root = runGit3(["rev-parse", "--show-toplevel"], cwd);
|
|
32576
|
-
return readPackageJson(
|
|
32697
|
+
return readPackageJson(join91(root, "package.json")).version ?? "unknown";
|
|
32577
32698
|
} catch {
|
|
32578
32699
|
return "unknown";
|
|
32579
32700
|
}
|
|
@@ -32934,13 +33055,13 @@ import { existsSync as existsSync80 } from "fs";
|
|
|
32934
33055
|
// src/commands/run/resolveCommand.ts
|
|
32935
33056
|
import { execFileSync as execFileSync16 } from "child_process";
|
|
32936
33057
|
import { existsSync as existsSync79 } from "fs";
|
|
32937
|
-
import { dirname as dirname37, join as
|
|
33058
|
+
import { dirname as dirname37, join as join92, resolve as resolve20 } from "path";
|
|
32938
33059
|
function resolveCommand2(command) {
|
|
32939
33060
|
if (process.platform !== "win32" || command !== "bash") return command;
|
|
32940
33061
|
try {
|
|
32941
33062
|
const gitPath = execFileSync16("where", ["git"], { encoding: "utf8" }).trim().split("\r\n")[0];
|
|
32942
33063
|
const gitRoot = resolve20(dirname37(gitPath), "..");
|
|
32943
|
-
const gitBash =
|
|
33064
|
+
const gitBash = join92(gitRoot, "bin", "bash.exe");
|
|
32944
33065
|
if (existsSync79(gitBash)) return gitBash;
|
|
32945
33066
|
} catch {
|
|
32946
33067
|
return command;
|
|
@@ -33368,7 +33489,7 @@ async function auth() {
|
|
|
33368
33489
|
// src/commands/roam/postRoamActivity.ts
|
|
33369
33490
|
import { execFileSync as execFileSync18 } from "child_process";
|
|
33370
33491
|
import { readdirSync as readdirSync21, readFileSync as readFileSync60, statSync as statSync12 } from "fs";
|
|
33371
|
-
import { join as
|
|
33492
|
+
import { join as join93 } from "path";
|
|
33372
33493
|
function findPortFile(roamDir) {
|
|
33373
33494
|
let entries;
|
|
33374
33495
|
try {
|
|
@@ -33377,7 +33498,7 @@ function findPortFile(roamDir) {
|
|
|
33377
33498
|
return void 0;
|
|
33378
33499
|
}
|
|
33379
33500
|
const candidates = entries.filter((name) => /^roam-local-api(-[^.]+)?\.port$/.test(name)).map((name) => {
|
|
33380
|
-
const path90 =
|
|
33501
|
+
const path90 = join93(roamDir, name);
|
|
33381
33502
|
try {
|
|
33382
33503
|
return { path: path90, mtimeMs: statSync12(path90).mtimeMs };
|
|
33383
33504
|
} catch {
|
|
@@ -33394,7 +33515,7 @@ var PID_BY_APP = {
|
|
|
33394
33515
|
function postRoamActivity(app, event) {
|
|
33395
33516
|
const appData = process.env.APPDATA;
|
|
33396
33517
|
if (!appData) return;
|
|
33397
|
-
const portFile = findPortFile(
|
|
33518
|
+
const portFile = findPortFile(join93(appData, "Roam"));
|
|
33398
33519
|
if (!portFile) return;
|
|
33399
33520
|
let port;
|
|
33400
33521
|
try {
|
|
@@ -33529,8 +33650,8 @@ async function run3(name, args) {
|
|
|
33529
33650
|
}
|
|
33530
33651
|
|
|
33531
33652
|
// src/commands/run/add.ts
|
|
33532
|
-
import { mkdirSync as
|
|
33533
|
-
import { join as
|
|
33653
|
+
import { mkdirSync as mkdirSync32, writeFileSync as writeFileSync49 } from "fs";
|
|
33654
|
+
import { join as join94 } from "path";
|
|
33534
33655
|
|
|
33535
33656
|
// src/commands/run/extractOption.ts
|
|
33536
33657
|
function extractOption(args, flag) {
|
|
@@ -33591,16 +33712,16 @@ function saveNewRunConfig(name, command, args, cwd) {
|
|
|
33591
33712
|
saveConfig(config);
|
|
33592
33713
|
}
|
|
33593
33714
|
function createCommandFile(name) {
|
|
33594
|
-
const dir =
|
|
33595
|
-
|
|
33715
|
+
const dir = join94(".claude", "commands");
|
|
33716
|
+
mkdirSync32(dir, { recursive: true });
|
|
33596
33717
|
const content = `---
|
|
33597
33718
|
description: Run ${name}
|
|
33598
33719
|
---
|
|
33599
33720
|
|
|
33600
33721
|
Run \`assist run ${name} $ARGUMENTS 2>&1\`.
|
|
33601
33722
|
`;
|
|
33602
|
-
const filePath =
|
|
33603
|
-
|
|
33723
|
+
const filePath = join94(dir, `${name}.md`);
|
|
33724
|
+
writeFileSync49(filePath, content);
|
|
33604
33725
|
console.log(`Created command file: ${filePath}`);
|
|
33605
33726
|
}
|
|
33606
33727
|
function add3() {
|
|
@@ -33656,7 +33777,7 @@ function link2() {
|
|
|
33656
33777
|
|
|
33657
33778
|
// src/commands/run/remove.ts
|
|
33658
33779
|
import { existsSync as existsSync81, unlinkSync as unlinkSync21 } from "fs";
|
|
33659
|
-
import { join as
|
|
33780
|
+
import { join as join95 } from "path";
|
|
33660
33781
|
function findRemoveIndex() {
|
|
33661
33782
|
const idx = process.argv.indexOf("remove");
|
|
33662
33783
|
if (idx === -1 || idx + 1 >= process.argv.length) return -1;
|
|
@@ -33671,7 +33792,7 @@ function parseRemoveName() {
|
|
|
33671
33792
|
return process.argv[idx + 1];
|
|
33672
33793
|
}
|
|
33673
33794
|
function deleteCommandFile(name) {
|
|
33674
|
-
const filePath =
|
|
33795
|
+
const filePath = join95(".claude", "commands", `${name}.md`);
|
|
33675
33796
|
if (existsSync81(filePath)) {
|
|
33676
33797
|
unlinkSync21(filePath);
|
|
33677
33798
|
console.log(`Deleted command file: ${filePath}`);
|
|
@@ -33717,9 +33838,9 @@ function registerRun(program2) {
|
|
|
33717
33838
|
|
|
33718
33839
|
// src/commands/screenshot/index.ts
|
|
33719
33840
|
import { execSync as execSync60 } from "child_process";
|
|
33720
|
-
import { existsSync as existsSync82, mkdirSync as
|
|
33841
|
+
import { existsSync as existsSync82, mkdirSync as mkdirSync33, unlinkSync as unlinkSync22, writeFileSync as writeFileSync50 } from "fs";
|
|
33721
33842
|
import { tmpdir as tmpdir9 } from "os";
|
|
33722
|
-
import { join as
|
|
33843
|
+
import { join as join96, resolve as resolve21 } from "path";
|
|
33723
33844
|
import chalk227 from "chalk";
|
|
33724
33845
|
|
|
33725
33846
|
// src/commands/screenshot/captureWindowPs1.ts
|
|
@@ -33850,14 +33971,14 @@ Write-Output $OutputPath
|
|
|
33850
33971
|
// src/commands/screenshot/index.ts
|
|
33851
33972
|
function buildOutputPath(outputDir, processName) {
|
|
33852
33973
|
if (!existsSync82(outputDir)) {
|
|
33853
|
-
|
|
33974
|
+
mkdirSync33(outputDir, { recursive: true });
|
|
33854
33975
|
}
|
|
33855
33976
|
const timestamp6 = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
33856
33977
|
return resolve21(outputDir, `${processName}-${timestamp6}.png`);
|
|
33857
33978
|
}
|
|
33858
33979
|
function runPowerShellScript(processName, outputPath) {
|
|
33859
|
-
const scriptPath =
|
|
33860
|
-
|
|
33980
|
+
const scriptPath = join96(tmpdir9(), `assist-screenshot-${Date.now()}.ps1`);
|
|
33981
|
+
writeFileSync50(scriptPath, captureWindowPs1, "utf8");
|
|
33861
33982
|
try {
|
|
33862
33983
|
execSync60(
|
|
33863
33984
|
`powershell -NoProfile -ExecutionPolicy Bypass -File "${scriptPath}" -ProcessName "${processName}" -OutputPath "${outputPath}"`,
|
|
@@ -34090,7 +34211,7 @@ function requestDrain(socket, lines2) {
|
|
|
34090
34211
|
}
|
|
34091
34212
|
|
|
34092
34213
|
// src/commands/sessions/daemon/runDaemon.ts
|
|
34093
|
-
import { mkdirSync as
|
|
34214
|
+
import { mkdirSync as mkdirSync37 } from "fs";
|
|
34094
34215
|
|
|
34095
34216
|
// src/commands/sessions/daemon/createAutoExit.ts
|
|
34096
34217
|
var DEFAULT_GRACE_MS = 6e4;
|
|
@@ -34344,7 +34465,7 @@ var ClientHub = class extends Set {
|
|
|
34344
34465
|
};
|
|
34345
34466
|
|
|
34346
34467
|
// src/commands/sessions/daemon/createSession.ts
|
|
34347
|
-
import { randomUUID as
|
|
34468
|
+
import { randomUUID as randomUUID18 } from "crypto";
|
|
34348
34469
|
|
|
34349
34470
|
// src/commands/sessions/daemon/sessionBase.ts
|
|
34350
34471
|
function sessionBase(id, status3) {
|
|
@@ -34540,7 +34661,7 @@ function spawnRun(opts) {
|
|
|
34540
34661
|
function createSession(id, { prompt, cwd, design, auto, harness, holdPty } = {}) {
|
|
34541
34662
|
if (harness && harness !== "claude")
|
|
34542
34663
|
return createHarnessSession(id, harness, prompt, cwd, holdPty);
|
|
34543
|
-
const claudeSessionId =
|
|
34664
|
+
const claudeSessionId = randomUUID18();
|
|
34544
34665
|
return {
|
|
34545
34666
|
...sessionBase(id, prompt ? "running" : "waiting"),
|
|
34546
34667
|
name: `Session ${id}`,
|
|
@@ -34605,12 +34726,12 @@ import { basename as basename22 } from "path";
|
|
|
34605
34726
|
|
|
34606
34727
|
// src/commands/sessions/daemon/worktree/deleteStrandedTree.ts
|
|
34607
34728
|
import { existsSync as existsSync86 } from "fs";
|
|
34608
|
-
import { join as
|
|
34729
|
+
import { join as join99 } from "path";
|
|
34609
34730
|
|
|
34610
34731
|
// src/commands/sessions/daemon/worktree/deleteTreeDirectly.ts
|
|
34611
34732
|
import { statSync as statSync14 } from "fs";
|
|
34612
34733
|
import { rm as rm4 } from "fs/promises";
|
|
34613
|
-
import { join as
|
|
34734
|
+
import { join as join98 } from "path";
|
|
34614
34735
|
async function deleteTreeDirectly(clone, worktreePath, why) {
|
|
34615
34736
|
if (holdsAGitDirectoryRatherThanALink(worktreePath)) {
|
|
34616
34737
|
const refusal = "it is a clone of its own, not a linked worktree";
|
|
@@ -34638,7 +34759,7 @@ async function deleteTreeDirectly(clone, worktreePath, why) {
|
|
|
34638
34759
|
return { removed: true };
|
|
34639
34760
|
}
|
|
34640
34761
|
function holdsAGitDirectoryRatherThanALink(worktreePath) {
|
|
34641
|
-
return statSync14(
|
|
34762
|
+
return statSync14(join98(worktreePath, ".git"), {
|
|
34642
34763
|
throwIfNoEntry: false
|
|
34643
34764
|
})?.isDirectory() === true;
|
|
34644
34765
|
}
|
|
@@ -34674,7 +34795,7 @@ async function deleteStrandedTree(clone, worktreePath, cause) {
|
|
|
34674
34795
|
);
|
|
34675
34796
|
}
|
|
34676
34797
|
function strandedReason(worktreePath, cause) {
|
|
34677
|
-
if (!existsSync86(
|
|
34798
|
+
if (!existsSync86(join99(worktreePath, ".git")))
|
|
34678
34799
|
return "its .git link is already gone";
|
|
34679
34800
|
if (/not a working tree|not a git repository/i.test(reason2(cause)))
|
|
34680
34801
|
return "git no longer recognises it as a working tree";
|
|
@@ -35140,7 +35261,8 @@ var PREVIEW_KINDS = [
|
|
|
35140
35261
|
"github-issue",
|
|
35141
35262
|
"github-issue-comment",
|
|
35142
35263
|
"github-issue-edit",
|
|
35143
|
-
"miro-board"
|
|
35264
|
+
"miro-board",
|
|
35265
|
+
"slack-post"
|
|
35144
35266
|
];
|
|
35145
35267
|
function isPreviewKind(value) {
|
|
35146
35268
|
return PREVIEW_KINDS.includes(value);
|
|
@@ -35164,6 +35286,7 @@ function previewTargetLabel(kind, itemType, prNumber, draft) {
|
|
|
35164
35286
|
if (kind === "github-issue-edit") return "github issue edit";
|
|
35165
35287
|
if (kind === "github-issue") return "github issue";
|
|
35166
35288
|
if (kind === "miro-board") return "miro anchors";
|
|
35289
|
+
if (kind === "slack-post") return "slack post";
|
|
35167
35290
|
if (kind === "backlog-item") return `backlog ${itemType}`;
|
|
35168
35291
|
if (prNumber !== null) return `edit #${prNumber}`;
|
|
35169
35292
|
return draft ? "create draft" : "create";
|
|
@@ -35433,7 +35556,7 @@ function handleFailedResume(session, exitCode, onStatusChange) {
|
|
|
35433
35556
|
}
|
|
35434
35557
|
|
|
35435
35558
|
// src/commands/sessions/daemon/watchActivity.ts
|
|
35436
|
-
import { existsSync as existsSync90, mkdirSync as
|
|
35559
|
+
import { existsSync as existsSync90, mkdirSync as mkdirSync34, watch as watch2 } from "fs";
|
|
35437
35560
|
import { dirname as dirname39 } from "path";
|
|
35438
35561
|
|
|
35439
35562
|
// src/commands/sessions/daemon/applyActivityToSession.ts
|
|
@@ -35498,7 +35621,7 @@ function watchActivity(session, notify2, onClaudeSessionId) {
|
|
|
35498
35621
|
const path90 = activityPath(session.id);
|
|
35499
35622
|
const dir = dirname39(path90);
|
|
35500
35623
|
try {
|
|
35501
|
-
|
|
35624
|
+
mkdirSync34(dir, { recursive: true });
|
|
35502
35625
|
} catch {
|
|
35503
35626
|
return;
|
|
35504
35627
|
}
|
|
@@ -35701,10 +35824,10 @@ function headContainsSessionId(filePath, claudeSessionId) {
|
|
|
35701
35824
|
}
|
|
35702
35825
|
|
|
35703
35826
|
// src/commands/sessions/daemon/ensureProjectDirExists.ts
|
|
35704
|
-
import { mkdirSync as
|
|
35827
|
+
import { mkdirSync as mkdirSync35 } from "fs";
|
|
35705
35828
|
function ensureProjectDirExists(dir, sessionId) {
|
|
35706
35829
|
try {
|
|
35707
|
-
|
|
35830
|
+
mkdirSync35(dir, { recursive: true });
|
|
35708
35831
|
return true;
|
|
35709
35832
|
} catch (error) {
|
|
35710
35833
|
daemonLog(
|
|
@@ -36653,7 +36776,7 @@ function codexRespawnPlan(session) {
|
|
|
36653
36776
|
}
|
|
36654
36777
|
|
|
36655
36778
|
// src/commands/sessions/daemon/interactiveRespawnPlan.ts
|
|
36656
|
-
import { randomUUID as
|
|
36779
|
+
import { randomUUID as randomUUID19 } from "crypto";
|
|
36657
36780
|
function interactiveRespawnPlan(session, resumes) {
|
|
36658
36781
|
const { claudeSessionId, cwd, initialPrompt, design, auto } = session;
|
|
36659
36782
|
if (!resumes) return null;
|
|
@@ -36673,7 +36796,7 @@ function interactiveRespawnPlan(session, resumes) {
|
|
|
36673
36796
|
return null;
|
|
36674
36797
|
}
|
|
36675
36798
|
function freshClaudePlan(session, prompt, cwd) {
|
|
36676
|
-
const claudeSessionId =
|
|
36799
|
+
const claudeSessionId = randomUUID19();
|
|
36677
36800
|
return {
|
|
36678
36801
|
spawn: () => {
|
|
36679
36802
|
session.claudeSessionId = claudeSessionId;
|
|
@@ -37558,10 +37681,10 @@ function startReusedRunPty(session, assistArgs, itemId2, hold, clients, onStatus
|
|
|
37558
37681
|
}
|
|
37559
37682
|
|
|
37560
37683
|
// src/commands/sessions/daemon/createWatcherSession.ts
|
|
37561
|
-
import { randomUUID as
|
|
37684
|
+
import { randomUUID as randomUUID20 } from "crypto";
|
|
37562
37685
|
var WATCH_PROMPT = "/watch";
|
|
37563
37686
|
function createWatcherSession(id, cwd) {
|
|
37564
|
-
const claudeSessionId =
|
|
37687
|
+
const claudeSessionId = randomUUID20();
|
|
37565
37688
|
return {
|
|
37566
37689
|
...sessionBase(id, "running"),
|
|
37567
37690
|
name: `Session ${id}`,
|
|
@@ -38785,8 +38908,8 @@ function resumeSession(id, sessionId, cwd, name, holdPty, harness) {
|
|
|
38785
38908
|
import { existsSync as existsSync96 } from "fs";
|
|
38786
38909
|
|
|
38787
38910
|
// src/commands/sessions/daemon/worktree/carryTranscriptToTree.ts
|
|
38788
|
-
import { copyFileSync as copyFileSync7, existsSync as existsSync95, mkdirSync as
|
|
38789
|
-
import { join as
|
|
38911
|
+
import { copyFileSync as copyFileSync7, existsSync as existsSync95, mkdirSync as mkdirSync36 } from "fs";
|
|
38912
|
+
import { join as join101 } from "path";
|
|
38790
38913
|
function carryTranscriptToTree(claudeSessionId, fromCwd, toCwd) {
|
|
38791
38914
|
const dir = projectDirForCwd(toCwd);
|
|
38792
38915
|
if (dir === projectDirForCwd(fromCwd)) {
|
|
@@ -38795,7 +38918,7 @@ function carryTranscriptToTree(claudeSessionId, fromCwd, toCwd) {
|
|
|
38795
38918
|
);
|
|
38796
38919
|
return;
|
|
38797
38920
|
}
|
|
38798
|
-
const dest =
|
|
38921
|
+
const dest = join101(dir, `${claudeSessionId}.jsonl`);
|
|
38799
38922
|
if (existsSync95(dest)) {
|
|
38800
38923
|
daemonLog(`transcript ${claudeSessionId} already present in ${dir}`);
|
|
38801
38924
|
return;
|
|
@@ -38808,7 +38931,7 @@ function carryTranscriptToTree(claudeSessionId, fromCwd, toCwd) {
|
|
|
38808
38931
|
return;
|
|
38809
38932
|
}
|
|
38810
38933
|
try {
|
|
38811
|
-
|
|
38934
|
+
mkdirSync36(dir, { recursive: true });
|
|
38812
38935
|
copyFileSync7(source, dest);
|
|
38813
38936
|
daemonLog(
|
|
38814
38937
|
`transcript ${source} copied to ${dest} so ${toCwd} can resume it`
|
|
@@ -39433,7 +39556,7 @@ function handleConnection(socket, manager) {
|
|
|
39433
39556
|
}
|
|
39434
39557
|
|
|
39435
39558
|
// src/commands/sessions/daemon/onListening.ts
|
|
39436
|
-
import { unlinkSync as unlinkSync23, writeFileSync as
|
|
39559
|
+
import { unlinkSync as unlinkSync23, writeFileSync as writeFileSync51 } from "fs";
|
|
39437
39560
|
|
|
39438
39561
|
// src/commands/sessions/daemon/startPidFileWatchdog.ts
|
|
39439
39562
|
import { readFileSync as readFileSync64 } from "fs";
|
|
@@ -39455,7 +39578,7 @@ function ownsPidFile() {
|
|
|
39455
39578
|
|
|
39456
39579
|
// src/commands/sessions/daemon/onListening.ts
|
|
39457
39580
|
function onListening(manager, checkAutoExit) {
|
|
39458
|
-
|
|
39581
|
+
writeFileSync51(daemonPaths.pid, String(process.pid));
|
|
39459
39582
|
startPidFileWatchdog(() => {
|
|
39460
39583
|
daemonLog("lost daemon.pid ownership; shutting down sessions and exiting");
|
|
39461
39584
|
void manager.flushActiveMs().finally(() => {
|
|
@@ -39642,7 +39765,7 @@ async function recoverFromAddrInUse(server, manager, checkAutoExit) {
|
|
|
39642
39765
|
|
|
39643
39766
|
// src/commands/sessions/daemon/runDaemon.ts
|
|
39644
39767
|
async function runDaemon() {
|
|
39645
|
-
|
|
39768
|
+
mkdirSync37(daemonPaths.dir, { recursive: true });
|
|
39646
39769
|
daemonLog(
|
|
39647
39770
|
`starting (reason: ${process.env.ASSIST_DAEMON_SPAWN_REASON ?? "manual"})`
|
|
39648
39771
|
);
|
|
@@ -39922,9 +40045,9 @@ function buildLimitsSegment(rateLimits) {
|
|
|
39922
40045
|
|
|
39923
40046
|
// src/commands/readGitBranch.ts
|
|
39924
40047
|
import { readFileSync as readFileSync66, statSync as statSync16 } from "fs";
|
|
39925
|
-
import { isAbsolute as isAbsolute5, join as
|
|
40048
|
+
import { isAbsolute as isAbsolute5, join as join102, resolve as resolve23 } from "path";
|
|
39926
40049
|
function resolveGitDir(cwd) {
|
|
39927
|
-
const dotGit =
|
|
40050
|
+
const dotGit = join102(cwd, ".git");
|
|
39928
40051
|
let stat4;
|
|
39929
40052
|
try {
|
|
39930
40053
|
stat4 = statSync16(dotGit);
|
|
@@ -39954,7 +40077,7 @@ function readGitBranch(cwd) {
|
|
|
39954
40077
|
}
|
|
39955
40078
|
let head;
|
|
39956
40079
|
try {
|
|
39957
|
-
head = readFileSync66(
|
|
40080
|
+
head = readFileSync66(join102(gitDir, "HEAD"), "utf8");
|
|
39958
40081
|
} catch {
|
|
39959
40082
|
return null;
|
|
39960
40083
|
}
|
|
@@ -40144,6 +40267,7 @@ registerNetcap(program);
|
|
|
40144
40267
|
registerCriteriaExtension(program);
|
|
40145
40268
|
registerRavendb(program);
|
|
40146
40269
|
registerSeq(program);
|
|
40270
|
+
registerSlack(program);
|
|
40147
40271
|
registerSql(program);
|
|
40148
40272
|
registerTranscript(program);
|
|
40149
40273
|
registerVoice(program);
|