yapout 0.8.0 → 0.10.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/dist/index.js +606 -354
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -7,16 +7,16 @@ import {
|
|
|
7
7
|
} from "./chunk-DLHFRTYU.js";
|
|
8
8
|
|
|
9
9
|
// src/index.ts
|
|
10
|
-
import { Command as
|
|
10
|
+
import { Command as Command17 } from "commander";
|
|
11
11
|
|
|
12
12
|
// src/commands/login.ts
|
|
13
|
-
import { Command } from "commander";
|
|
14
|
-
import
|
|
15
|
-
import { createHash } from "crypto";
|
|
16
|
-
import { hostname, userInfo } from "os";
|
|
17
|
-
import
|
|
13
|
+
import { Command as Command2 } from "commander";
|
|
14
|
+
import http2 from "http";
|
|
15
|
+
import { createHash as createHash2 } from "crypto";
|
|
16
|
+
import { hostname as hostname2, userInfo as userInfo2 } from "os";
|
|
17
|
+
import chalk3 from "chalk";
|
|
18
18
|
import open from "open";
|
|
19
|
-
import { anyApi as
|
|
19
|
+
import { anyApi as anyApi3 } from "convex/server";
|
|
20
20
|
|
|
21
21
|
// src/lib/config.ts
|
|
22
22
|
import { homedir } from "os";
|
|
@@ -521,8 +521,267 @@ function registerProtocolHandler() {
|
|
|
521
521
|
}
|
|
522
522
|
}
|
|
523
523
|
|
|
524
|
+
// src/commands/serve.ts
|
|
525
|
+
import { Command } from "commander";
|
|
526
|
+
import http from "http";
|
|
527
|
+
import { createHash } from "crypto";
|
|
528
|
+
import { hostname, userInfo, platform as platform2, type } from "os";
|
|
529
|
+
import { join as join3 } from "path";
|
|
530
|
+
import {
|
|
531
|
+
readFileSync as readFileSync2,
|
|
532
|
+
writeFileSync as writeFileSync3,
|
|
533
|
+
existsSync as existsSync2,
|
|
534
|
+
unlinkSync as unlinkSync3,
|
|
535
|
+
openSync
|
|
536
|
+
} from "fs";
|
|
537
|
+
import { spawn } from "child_process";
|
|
538
|
+
import chalk2 from "chalk";
|
|
539
|
+
import { anyApi as anyApi2 } from "convex/server";
|
|
540
|
+
|
|
541
|
+
// src/lib/auth.ts
|
|
542
|
+
import chalk from "chalk";
|
|
543
|
+
function requireAuth() {
|
|
544
|
+
const creds = readCredentials();
|
|
545
|
+
if (!creds) {
|
|
546
|
+
console.error(
|
|
547
|
+
chalk.red("Not logged in.") + " Run " + chalk.cyan("yapout login") + " first."
|
|
548
|
+
);
|
|
549
|
+
process.exit(1);
|
|
550
|
+
}
|
|
551
|
+
if (Date.now() > creds.expiresAt) {
|
|
552
|
+
console.error(
|
|
553
|
+
chalk.red("Session expired.") + " Run " + chalk.cyan("yapout login") + " to re-authenticate."
|
|
554
|
+
);
|
|
555
|
+
process.exit(1);
|
|
556
|
+
}
|
|
557
|
+
return creds;
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
// src/commands/serve.ts
|
|
561
|
+
var CLI_VERSION = "0.10.0";
|
|
562
|
+
var DEFAULT_PORT = 7777;
|
|
563
|
+
var PORT_RANGE = 10;
|
|
564
|
+
var HEARTBEAT_MS = 3e4;
|
|
565
|
+
var PID_FILE = join3(getYapoutDir(), "serve.pid");
|
|
566
|
+
var PORT_FILE = join3(getYapoutDir(), "serve.port");
|
|
567
|
+
var LOG_FILE = join3(getYapoutDir(), "serve.log");
|
|
568
|
+
var ALLOWED_ORIGINS = [
|
|
569
|
+
"https://yapout.com",
|
|
570
|
+
"https://www.yapout.com",
|
|
571
|
+
"https://yapout.vercel.app",
|
|
572
|
+
// Local dev / sandbox ports — wide range so any worktree's auto-allocated
|
|
573
|
+
// Next.js port works without configuration.
|
|
574
|
+
...Array.from({ length: 20 }, (_, i) => `http://localhost:${3e3 + i}`),
|
|
575
|
+
...Array.from({ length: 20 }, (_, i) => `http://127.0.0.1:${3e3 + i}`)
|
|
576
|
+
];
|
|
577
|
+
function computeDeviceId() {
|
|
578
|
+
return createHash("sha256").update(hostname() + userInfo().username).digest("hex").slice(0, 16);
|
|
579
|
+
}
|
|
580
|
+
function corsHeadersFor(origin) {
|
|
581
|
+
const allowOrigin = origin && ALLOWED_ORIGINS.includes(origin) ? origin : ALLOWED_ORIGINS[0];
|
|
582
|
+
return {
|
|
583
|
+
"Access-Control-Allow-Origin": allowOrigin,
|
|
584
|
+
"Access-Control-Allow-Methods": "GET, OPTIONS",
|
|
585
|
+
"Access-Control-Allow-Headers": "Content-Type",
|
|
586
|
+
"Access-Control-Allow-Private-Network": "true",
|
|
587
|
+
Vary: "Origin"
|
|
588
|
+
};
|
|
589
|
+
}
|
|
590
|
+
function startServer(payload) {
|
|
591
|
+
const server = http.createServer((req, res) => {
|
|
592
|
+
const origin = req.headers.origin;
|
|
593
|
+
const headers = corsHeadersFor(origin);
|
|
594
|
+
if (req.method === "OPTIONS") {
|
|
595
|
+
res.writeHead(204, headers);
|
|
596
|
+
res.end();
|
|
597
|
+
return;
|
|
598
|
+
}
|
|
599
|
+
if (req.method === "GET" && req.url === "/device") {
|
|
600
|
+
res.writeHead(200, {
|
|
601
|
+
...headers,
|
|
602
|
+
"Content-Type": "application/json",
|
|
603
|
+
"Cache-Control": "no-store"
|
|
604
|
+
});
|
|
605
|
+
res.end(JSON.stringify(payload));
|
|
606
|
+
return;
|
|
607
|
+
}
|
|
608
|
+
res.writeHead(404, headers);
|
|
609
|
+
res.end();
|
|
610
|
+
});
|
|
611
|
+
return new Promise((resolve12, reject) => {
|
|
612
|
+
let attempt = 0;
|
|
613
|
+
const tryListen = () => {
|
|
614
|
+
const port = DEFAULT_PORT + attempt;
|
|
615
|
+
const onError = (err) => {
|
|
616
|
+
server.removeListener("error", onError);
|
|
617
|
+
if (err.code === "EADDRINUSE" && attempt < PORT_RANGE - 1) {
|
|
618
|
+
attempt++;
|
|
619
|
+
tryListen();
|
|
620
|
+
} else {
|
|
621
|
+
reject(err);
|
|
622
|
+
}
|
|
623
|
+
};
|
|
624
|
+
server.once("error", onError);
|
|
625
|
+
server.listen(port, "127.0.0.1", () => {
|
|
626
|
+
server.removeListener("error", onError);
|
|
627
|
+
resolve12({
|
|
628
|
+
port,
|
|
629
|
+
close: () => server.close()
|
|
630
|
+
});
|
|
631
|
+
});
|
|
632
|
+
};
|
|
633
|
+
tryListen();
|
|
634
|
+
});
|
|
635
|
+
}
|
|
636
|
+
async function runForeground() {
|
|
637
|
+
const creds = requireAuth();
|
|
638
|
+
const deviceId = computeDeviceId();
|
|
639
|
+
const payload = {
|
|
640
|
+
deviceId,
|
|
641
|
+
name: hostname(),
|
|
642
|
+
hostname: hostname(),
|
|
643
|
+
platform: `${type()} ${platform2()}`,
|
|
644
|
+
cliVersion: CLI_VERSION
|
|
645
|
+
};
|
|
646
|
+
const { port } = await startServer(payload);
|
|
647
|
+
writeFileSync3(PORT_FILE, String(port));
|
|
648
|
+
writeFileSync3(PID_FILE, String(process.pid));
|
|
649
|
+
console.log(chalk2.green(`yapout serve listening on http://127.0.0.1:${port}`));
|
|
650
|
+
console.log(chalk2.dim(`Device: ${payload.name} (${deviceId})`));
|
|
651
|
+
console.log(chalk2.dim("Press Ctrl-C to stop."));
|
|
652
|
+
const client = createConvexClient(creds.token);
|
|
653
|
+
const heartbeat = async () => {
|
|
654
|
+
try {
|
|
655
|
+
await client.mutation(anyApi2.functions.devices.heartbeatDevice, {
|
|
656
|
+
deviceId
|
|
657
|
+
});
|
|
658
|
+
} catch {
|
|
659
|
+
}
|
|
660
|
+
};
|
|
661
|
+
client.mutation(anyApi2.functions.devices.registerDevice, {
|
|
662
|
+
deviceId,
|
|
663
|
+
name: payload.name,
|
|
664
|
+
cliVersion: CLI_VERSION,
|
|
665
|
+
machineHostname: payload.hostname
|
|
666
|
+
}).catch(() => {
|
|
667
|
+
});
|
|
668
|
+
void heartbeat();
|
|
669
|
+
const interval = setInterval(heartbeat, HEARTBEAT_MS);
|
|
670
|
+
const shutdown = async () => {
|
|
671
|
+
clearInterval(interval);
|
|
672
|
+
try {
|
|
673
|
+
await client.mutation(anyApi2.functions.devices.markDeviceOffline, {
|
|
674
|
+
deviceId
|
|
675
|
+
});
|
|
676
|
+
} catch {
|
|
677
|
+
}
|
|
678
|
+
try {
|
|
679
|
+
if (existsSync2(PID_FILE)) unlinkSync3(PID_FILE);
|
|
680
|
+
} catch {
|
|
681
|
+
}
|
|
682
|
+
try {
|
|
683
|
+
if (existsSync2(PORT_FILE)) unlinkSync3(PORT_FILE);
|
|
684
|
+
} catch {
|
|
685
|
+
}
|
|
686
|
+
process.exit(0);
|
|
687
|
+
};
|
|
688
|
+
process.on("SIGINT", () => {
|
|
689
|
+
void shutdown();
|
|
690
|
+
});
|
|
691
|
+
process.on("SIGTERM", () => {
|
|
692
|
+
void shutdown();
|
|
693
|
+
});
|
|
694
|
+
await new Promise(() => {
|
|
695
|
+
});
|
|
696
|
+
}
|
|
697
|
+
function isProcessRunning(pid) {
|
|
698
|
+
try {
|
|
699
|
+
process.kill(pid, 0);
|
|
700
|
+
return true;
|
|
701
|
+
} catch {
|
|
702
|
+
return false;
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
function readPid() {
|
|
706
|
+
if (!existsSync2(PID_FILE)) return null;
|
|
707
|
+
const raw = readFileSync2(PID_FILE, "utf-8").trim();
|
|
708
|
+
const pid = parseInt(raw, 10);
|
|
709
|
+
return Number.isFinite(pid) ? pid : null;
|
|
710
|
+
}
|
|
711
|
+
function readPort() {
|
|
712
|
+
if (!existsSync2(PORT_FILE)) return null;
|
|
713
|
+
const raw = readFileSync2(PORT_FILE, "utf-8").trim();
|
|
714
|
+
const port = parseInt(raw, 10);
|
|
715
|
+
return Number.isFinite(port) ? port : null;
|
|
716
|
+
}
|
|
717
|
+
function spawnServeDaemon(argv0) {
|
|
718
|
+
const existingPid = readPid();
|
|
719
|
+
if (existingPid && isProcessRunning(existingPid)) return;
|
|
720
|
+
const logFd = openSync(LOG_FILE, "a");
|
|
721
|
+
const child = spawn(process.execPath, [argv0, "serve"], {
|
|
722
|
+
detached: true,
|
|
723
|
+
stdio: ["ignore", logFd, logFd],
|
|
724
|
+
env: process.env
|
|
725
|
+
});
|
|
726
|
+
child.unref();
|
|
727
|
+
}
|
|
728
|
+
var serveCommand = new Command("serve").description(
|
|
729
|
+
"Run the local device discovery server (auto-started by `yapout login`)"
|
|
730
|
+
).option("--status", "Check if the server is running").option("--stop", "Stop the running server").action(async (opts) => {
|
|
731
|
+
if (opts.status) {
|
|
732
|
+
const pid = readPid();
|
|
733
|
+
const port = readPort();
|
|
734
|
+
if (pid && isProcessRunning(pid)) {
|
|
735
|
+
console.log(
|
|
736
|
+
chalk2.green(`yapout serve is running`) + chalk2.dim(` (PID ${pid}, port ${port ?? "?"})`)
|
|
737
|
+
);
|
|
738
|
+
} else {
|
|
739
|
+
if (pid) unlinkSync3(PID_FILE);
|
|
740
|
+
console.log(chalk2.dim("yapout serve is not running"));
|
|
741
|
+
}
|
|
742
|
+
return;
|
|
743
|
+
}
|
|
744
|
+
if (opts.stop) {
|
|
745
|
+
const pid = readPid();
|
|
746
|
+
if (!pid) {
|
|
747
|
+
console.log(chalk2.dim("yapout serve is not running"));
|
|
748
|
+
return;
|
|
749
|
+
}
|
|
750
|
+
try {
|
|
751
|
+
process.kill(pid, "SIGTERM");
|
|
752
|
+
console.log(chalk2.green(`Stopped yapout serve`) + chalk2.dim(` (PID ${pid})`));
|
|
753
|
+
} catch {
|
|
754
|
+
console.log(chalk2.dim("Server already stopped"));
|
|
755
|
+
}
|
|
756
|
+
try {
|
|
757
|
+
unlinkSync3(PID_FILE);
|
|
758
|
+
} catch {
|
|
759
|
+
}
|
|
760
|
+
try {
|
|
761
|
+
unlinkSync3(PORT_FILE);
|
|
762
|
+
} catch {
|
|
763
|
+
}
|
|
764
|
+
return;
|
|
765
|
+
}
|
|
766
|
+
const existingPid = readPid();
|
|
767
|
+
if (existingPid && !isProcessRunning(existingPid)) {
|
|
768
|
+
try {
|
|
769
|
+
unlinkSync3(PID_FILE);
|
|
770
|
+
} catch {
|
|
771
|
+
}
|
|
772
|
+
} else if (existingPid && isProcessRunning(existingPid)) {
|
|
773
|
+
console.log(
|
|
774
|
+
chalk2.dim(
|
|
775
|
+
`yapout serve is already running (PID ${existingPid}). Use --stop first.`
|
|
776
|
+
)
|
|
777
|
+
);
|
|
778
|
+
process.exit(1);
|
|
779
|
+
}
|
|
780
|
+
await runForeground();
|
|
781
|
+
});
|
|
782
|
+
|
|
524
783
|
// src/commands/login.ts
|
|
525
|
-
var
|
|
784
|
+
var CLI_VERSION2 = "0.10.0";
|
|
526
785
|
function safeReturnTo(raw) {
|
|
527
786
|
if (!raw) return null;
|
|
528
787
|
try {
|
|
@@ -541,7 +800,7 @@ function startCallbackServer() {
|
|
|
541
800
|
resolveData = res;
|
|
542
801
|
rejectData = rej;
|
|
543
802
|
});
|
|
544
|
-
const server =
|
|
803
|
+
const server = http2.createServer((req, res) => {
|
|
545
804
|
const url = new URL(req.url, `http://localhost`);
|
|
546
805
|
if (url.pathname === "/callback") {
|
|
547
806
|
const token = url.searchParams.get("token");
|
|
@@ -593,14 +852,21 @@ function startCallbackServer() {
|
|
|
593
852
|
}, 12e4);
|
|
594
853
|
});
|
|
595
854
|
}
|
|
596
|
-
var loginCommand = new
|
|
597
|
-
console.log(
|
|
855
|
+
var loginCommand = new Command2("login").description("Authenticate with yapout").action(async () => {
|
|
856
|
+
console.log(chalk3.dim("Starting authentication..."));
|
|
598
857
|
const { port, data } = await startCallbackServer();
|
|
599
858
|
const appUrl = getAppUrl();
|
|
600
|
-
const
|
|
601
|
-
|
|
859
|
+
const deviceId = createHash2("sha256").update(hostname2() + userInfo2().username).digest("hex").slice(0, 16);
|
|
860
|
+
const authParams = new URLSearchParams({
|
|
861
|
+
port: String(port),
|
|
862
|
+
deviceId,
|
|
863
|
+
cliVersion: CLI_VERSION2,
|
|
864
|
+
hostname: hostname2()
|
|
865
|
+
});
|
|
866
|
+
const authUrl = `${appUrl}/auth/cli?${authParams.toString()}`;
|
|
867
|
+
console.log(chalk3.dim(`Opening browser...`));
|
|
602
868
|
await open(authUrl);
|
|
603
|
-
console.log(
|
|
869
|
+
console.log(chalk3.dim("Waiting for authentication in browser..."));
|
|
604
870
|
try {
|
|
605
871
|
const result = await data;
|
|
606
872
|
const creds = {
|
|
@@ -615,74 +881,59 @@ var loginCommand = new Command("login").description("Authenticate with yapout").
|
|
|
615
881
|
Math.round((result.expiresAt - Date.now()) / 864e5)
|
|
616
882
|
);
|
|
617
883
|
console.log(
|
|
618
|
-
|
|
884
|
+
chalk3.green("Logged in as ") + chalk3.bold(result.email) + chalk3.dim(
|
|
619
885
|
` (expires in ${daysLeft} day${daysLeft === 1 ? "" : "s"})`
|
|
620
886
|
)
|
|
621
887
|
);
|
|
622
888
|
try {
|
|
623
889
|
const client = createConvexClient(creds.token);
|
|
624
|
-
|
|
625
|
-
await client.mutation(anyApi2.functions.devices.registerDevice, {
|
|
890
|
+
await client.mutation(anyApi3.functions.devices.registerDevice, {
|
|
626
891
|
deviceId,
|
|
627
|
-
name:
|
|
628
|
-
cliVersion:
|
|
892
|
+
name: hostname2(),
|
|
893
|
+
cliVersion: CLI_VERSION2
|
|
629
894
|
});
|
|
630
895
|
} catch {
|
|
631
|
-
console.warn(
|
|
896
|
+
console.warn(chalk3.dim("Note: Could not register device. This is non-fatal."));
|
|
632
897
|
}
|
|
633
898
|
try {
|
|
634
899
|
registerProtocolHandler();
|
|
635
900
|
console.log(
|
|
636
|
-
|
|
901
|
+
chalk3.dim("Registered yapout:// protocol handler")
|
|
637
902
|
);
|
|
638
903
|
} catch {
|
|
639
904
|
}
|
|
905
|
+
try {
|
|
906
|
+
spawnServeDaemon(process.argv[1]);
|
|
907
|
+
console.log(chalk3.dim("Started yapout serve in the background"));
|
|
908
|
+
} catch {
|
|
909
|
+
}
|
|
640
910
|
process.exit(0);
|
|
641
911
|
} catch (err) {
|
|
642
|
-
console.error(
|
|
912
|
+
console.error(chalk3.red(err.message));
|
|
643
913
|
process.exit(1);
|
|
644
914
|
}
|
|
645
915
|
});
|
|
646
916
|
|
|
647
917
|
// src/commands/logout.ts
|
|
648
|
-
import { Command as
|
|
649
|
-
import
|
|
650
|
-
var logoutCommand = new
|
|
918
|
+
import { Command as Command3 } from "commander";
|
|
919
|
+
import chalk4 from "chalk";
|
|
920
|
+
var logoutCommand = new Command3("logout").description("Log out of yapout").action(() => {
|
|
651
921
|
deleteCredentials();
|
|
652
|
-
console.log(
|
|
922
|
+
console.log(chalk4.green("Logged out."));
|
|
653
923
|
});
|
|
654
924
|
|
|
655
925
|
// src/commands/link.ts
|
|
656
|
-
import { Command as
|
|
657
|
-
import { resolve as resolve2, join as
|
|
926
|
+
import { Command as Command4 } from "commander";
|
|
927
|
+
import { resolve as resolve2, join as join4 } from "path";
|
|
658
928
|
import {
|
|
659
|
-
existsSync as
|
|
929
|
+
existsSync as existsSync3,
|
|
660
930
|
mkdirSync as mkdirSync3,
|
|
661
|
-
readFileSync as
|
|
662
|
-
writeFileSync as
|
|
931
|
+
readFileSync as readFileSync3,
|
|
932
|
+
writeFileSync as writeFileSync4,
|
|
663
933
|
appendFileSync
|
|
664
934
|
} from "fs";
|
|
665
|
-
import { hostname as
|
|
666
|
-
import
|
|
667
|
-
|
|
668
|
-
// src/lib/auth.ts
|
|
669
|
-
import chalk3 from "chalk";
|
|
670
|
-
function requireAuth() {
|
|
671
|
-
const creds = readCredentials();
|
|
672
|
-
if (!creds) {
|
|
673
|
-
console.error(
|
|
674
|
-
chalk3.red("Not logged in.") + " Run " + chalk3.cyan("yapout login") + " first."
|
|
675
|
-
);
|
|
676
|
-
process.exit(1);
|
|
677
|
-
}
|
|
678
|
-
if (Date.now() > creds.expiresAt) {
|
|
679
|
-
console.error(
|
|
680
|
-
chalk3.red("Session expired.") + " Run " + chalk3.cyan("yapout login") + " to re-authenticate."
|
|
681
|
-
);
|
|
682
|
-
process.exit(1);
|
|
683
|
-
}
|
|
684
|
-
return creds;
|
|
685
|
-
}
|
|
935
|
+
import { hostname as hostname3 } from "os";
|
|
936
|
+
import chalk5 from "chalk";
|
|
686
937
|
|
|
687
938
|
// src/lib/prompts.ts
|
|
688
939
|
import { select } from "@inquirer/prompts";
|
|
@@ -734,7 +985,7 @@ branch_prefix: feat
|
|
|
734
985
|
# {{ticket.linearTicketId}}, {{ticket.id}}
|
|
735
986
|
# commit_template: "{{ticket.type}}({{ticket.linearTicketId}}): {{ticket.title}}"
|
|
736
987
|
`;
|
|
737
|
-
var linkCommand = new
|
|
988
|
+
var linkCommand = new Command4("link").description("Link the current directory to a yapout project").action(async () => {
|
|
738
989
|
const creds = requireAuth();
|
|
739
990
|
const cwd = resolveRepoRoot(resolve2(process.cwd()));
|
|
740
991
|
const client = createConvexClient(creds.token);
|
|
@@ -746,25 +997,25 @@ var linkCommand = new Command3("link").description("Link the current directory t
|
|
|
746
997
|
);
|
|
747
998
|
} catch (err) {
|
|
748
999
|
console.error(
|
|
749
|
-
|
|
1000
|
+
chalk5.red("Failed to fetch projects."),
|
|
750
1001
|
err.message
|
|
751
1002
|
);
|
|
752
1003
|
process.exit(1);
|
|
753
1004
|
}
|
|
754
1005
|
if (projects.length === 0) {
|
|
755
1006
|
console.error(
|
|
756
|
-
|
|
1007
|
+
chalk5.yellow("No projects found.") + " Create one at " + chalk5.cyan(`${getAppUrl()}/dashboard`)
|
|
757
1008
|
);
|
|
758
1009
|
process.exit(1);
|
|
759
1010
|
}
|
|
760
1011
|
const selected = await pickProject(projects);
|
|
761
|
-
const device = getOrCreateDeviceIdentity(
|
|
1012
|
+
const device = getOrCreateDeviceIdentity(hostname3());
|
|
762
1013
|
try {
|
|
763
1014
|
await client.mutation(anyApi.functions.devices.registerDevice, {
|
|
764
1015
|
deviceId: device.deviceId,
|
|
765
1016
|
name: device.name,
|
|
766
1017
|
cliVersion: getCliVersion(),
|
|
767
|
-
machineHostname:
|
|
1018
|
+
machineHostname: hostname3()
|
|
768
1019
|
});
|
|
769
1020
|
await client.mutation(anyApi.functions.projectCheckouts.linkCheckout, {
|
|
770
1021
|
projectId: selected.id,
|
|
@@ -773,7 +1024,7 @@ var linkCommand = new Command3("link").description("Link the current directory t
|
|
|
773
1024
|
});
|
|
774
1025
|
} catch (err) {
|
|
775
1026
|
console.warn(
|
|
776
|
-
|
|
1027
|
+
chalk5.yellow("Warning: failed to record this checkout \u2014 "),
|
|
777
1028
|
err.message
|
|
778
1029
|
);
|
|
779
1030
|
}
|
|
@@ -782,17 +1033,17 @@ var linkCommand = new Command3("link").description("Link the current directory t
|
|
|
782
1033
|
projectName: selected.name,
|
|
783
1034
|
linkedAt: Date.now()
|
|
784
1035
|
});
|
|
785
|
-
const yapoutDir =
|
|
786
|
-
if (!
|
|
1036
|
+
const yapoutDir = join4(cwd, ".yapout");
|
|
1037
|
+
if (!existsSync3(yapoutDir)) {
|
|
787
1038
|
mkdirSync3(yapoutDir, { recursive: true });
|
|
788
1039
|
}
|
|
789
|
-
const configPath =
|
|
790
|
-
if (!
|
|
791
|
-
|
|
1040
|
+
const configPath = join4(yapoutDir, "config.yml");
|
|
1041
|
+
if (!existsSync3(configPath)) {
|
|
1042
|
+
writeFileSync4(configPath, CONFIG_YAML_CONTENT);
|
|
792
1043
|
}
|
|
793
|
-
const gitignorePath =
|
|
794
|
-
if (
|
|
795
|
-
const content =
|
|
1044
|
+
const gitignorePath = join4(cwd, ".gitignore");
|
|
1045
|
+
if (existsSync3(gitignorePath)) {
|
|
1046
|
+
const content = readFileSync3(gitignorePath, "utf-8");
|
|
796
1047
|
if (!content.includes(".yapout/")) {
|
|
797
1048
|
appendFileSync(
|
|
798
1049
|
gitignorePath,
|
|
@@ -800,13 +1051,13 @@ var linkCommand = new Command3("link").description("Link the current directory t
|
|
|
800
1051
|
);
|
|
801
1052
|
}
|
|
802
1053
|
} else {
|
|
803
|
-
|
|
1054
|
+
writeFileSync4(gitignorePath, "# yapout local config\n.yapout/\n");
|
|
804
1055
|
}
|
|
805
|
-
const mcpPath =
|
|
1056
|
+
const mcpPath = join4(cwd, ".mcp.json");
|
|
806
1057
|
let mcpConfig = {};
|
|
807
|
-
if (
|
|
1058
|
+
if (existsSync3(mcpPath)) {
|
|
808
1059
|
try {
|
|
809
|
-
mcpConfig = JSON.parse(
|
|
1060
|
+
mcpConfig = JSON.parse(readFileSync3(mcpPath, "utf-8"));
|
|
810
1061
|
} catch {
|
|
811
1062
|
}
|
|
812
1063
|
}
|
|
@@ -815,17 +1066,17 @@ var linkCommand = new Command3("link").description("Link the current directory t
|
|
|
815
1066
|
command: "yapout",
|
|
816
1067
|
args: ["mcp-server"]
|
|
817
1068
|
};
|
|
818
|
-
|
|
1069
|
+
writeFileSync4(mcpPath, JSON.stringify(mcpConfig, null, 2) + "\n");
|
|
819
1070
|
const label = selected.githubRepoFullName ? `${selected.name} (${selected.githubRepoFullName})` : selected.name;
|
|
820
1071
|
const orgSuffix = selected.org ? ` in ${selected.org.name}` : "";
|
|
821
1072
|
console.log(
|
|
822
|
-
|
|
1073
|
+
chalk5.green(`Linked to ${label}${orgSuffix}.`) + " Claude Code will discover yapout tools automatically."
|
|
823
1074
|
);
|
|
824
1075
|
});
|
|
825
1076
|
function getCliVersion() {
|
|
826
1077
|
try {
|
|
827
1078
|
const pkg = JSON.parse(
|
|
828
|
-
|
|
1079
|
+
readFileSync3(join4(import.meta.dirname, "..", "package.json"), "utf-8")
|
|
829
1080
|
);
|
|
830
1081
|
return pkg.version ?? "unknown";
|
|
831
1082
|
} catch {
|
|
@@ -834,15 +1085,15 @@ function getCliVersion() {
|
|
|
834
1085
|
}
|
|
835
1086
|
|
|
836
1087
|
// src/commands/unlink.ts
|
|
837
|
-
import { Command as
|
|
838
|
-
import { resolve as resolve3, join as
|
|
839
|
-
import { existsSync as
|
|
840
|
-
import
|
|
841
|
-
var unlinkCommand = new
|
|
1088
|
+
import { Command as Command5 } from "commander";
|
|
1089
|
+
import { resolve as resolve3, join as join5 } from "path";
|
|
1090
|
+
import { existsSync as existsSync4, readFileSync as readFileSync4, writeFileSync as writeFileSync5, rmSync } from "fs";
|
|
1091
|
+
import chalk6 from "chalk";
|
|
1092
|
+
var unlinkCommand = new Command5("unlink").description("Unlink the current directory from its yapout project").action(async () => {
|
|
842
1093
|
const cwd = resolve3(process.cwd());
|
|
843
1094
|
const mapping = getProjectMapping(cwd);
|
|
844
1095
|
if (!mapping) {
|
|
845
|
-
console.error(
|
|
1096
|
+
console.error(chalk6.yellow("No project linked to this directory."));
|
|
846
1097
|
process.exit(1);
|
|
847
1098
|
}
|
|
848
1099
|
const device = readDeviceIdentity();
|
|
@@ -856,26 +1107,26 @@ var unlinkCommand = new Command4("unlink").description("Unlink the current direc
|
|
|
856
1107
|
});
|
|
857
1108
|
} catch (err) {
|
|
858
1109
|
console.warn(
|
|
859
|
-
|
|
1110
|
+
chalk6.yellow("Warning: failed to update server \u2014 "),
|
|
860
1111
|
err.message
|
|
861
1112
|
);
|
|
862
1113
|
}
|
|
863
1114
|
}
|
|
864
1115
|
removeProjectMapping(cwd);
|
|
865
|
-
const yapoutDir =
|
|
866
|
-
if (
|
|
1116
|
+
const yapoutDir = join5(cwd, ".yapout");
|
|
1117
|
+
if (existsSync4(yapoutDir)) {
|
|
867
1118
|
rmSync(yapoutDir, { recursive: true });
|
|
868
1119
|
}
|
|
869
|
-
const mcpPath =
|
|
870
|
-
if (
|
|
1120
|
+
const mcpPath = join5(cwd, ".mcp.json");
|
|
1121
|
+
if (existsSync4(mcpPath)) {
|
|
871
1122
|
try {
|
|
872
|
-
const mcpConfig = JSON.parse(
|
|
1123
|
+
const mcpConfig = JSON.parse(readFileSync4(mcpPath, "utf-8"));
|
|
873
1124
|
if (mcpConfig.mcpServers?.yapout) {
|
|
874
1125
|
delete mcpConfig.mcpServers.yapout;
|
|
875
1126
|
if (Object.keys(mcpConfig.mcpServers).length === 0) {
|
|
876
1127
|
rmSync(mcpPath);
|
|
877
1128
|
} else {
|
|
878
|
-
|
|
1129
|
+
writeFileSync5(
|
|
879
1130
|
mcpPath,
|
|
880
1131
|
JSON.stringify(mcpConfig, null, 2) + "\n"
|
|
881
1132
|
);
|
|
@@ -884,23 +1135,23 @@ var unlinkCommand = new Command4("unlink").description("Unlink the current direc
|
|
|
884
1135
|
} catch {
|
|
885
1136
|
}
|
|
886
1137
|
}
|
|
887
|
-
console.log(
|
|
1138
|
+
console.log(chalk6.green("Unlinked."));
|
|
888
1139
|
});
|
|
889
1140
|
|
|
890
1141
|
// src/commands/status.ts
|
|
891
|
-
import { Command as
|
|
1142
|
+
import { Command as Command6 } from "commander";
|
|
892
1143
|
import { resolve as resolve4 } from "path";
|
|
893
|
-
import
|
|
894
|
-
var statusCommand = new
|
|
895
|
-
console.log(
|
|
1144
|
+
import chalk7 from "chalk";
|
|
1145
|
+
var statusCommand = new Command6("status").description("Show yapout status for this directory").action(() => {
|
|
1146
|
+
console.log(chalk7.bold("yapout status\n"));
|
|
896
1147
|
const creds = readCredentials();
|
|
897
1148
|
if (!creds) {
|
|
898
1149
|
console.log(
|
|
899
|
-
` Auth: ${
|
|
1150
|
+
` Auth: ${chalk7.red("Not logged in.")} Run ${chalk7.cyan("yapout login")}.`
|
|
900
1151
|
);
|
|
901
1152
|
} else if (Date.now() > creds.expiresAt) {
|
|
902
1153
|
console.log(
|
|
903
|
-
` Auth: ${
|
|
1154
|
+
` Auth: ${chalk7.red("Session expired.")} Run ${chalk7.cyan("yapout login")}.`
|
|
904
1155
|
);
|
|
905
1156
|
} else {
|
|
906
1157
|
const daysLeft = Math.max(
|
|
@@ -908,35 +1159,35 @@ var statusCommand = new Command5("status").description("Show yapout status for t
|
|
|
908
1159
|
Math.round((creds.expiresAt - Date.now()) / 864e5)
|
|
909
1160
|
);
|
|
910
1161
|
console.log(
|
|
911
|
-
` Auth: ${
|
|
1162
|
+
` Auth: ${chalk7.green(creds.email)} (expires in ${daysLeft} day${daysLeft === 1 ? "" : "s"})`
|
|
912
1163
|
);
|
|
913
1164
|
}
|
|
914
1165
|
const cwd = resolve4(process.cwd());
|
|
915
1166
|
const mapping = getProjectMapping(cwd);
|
|
916
1167
|
if (!mapping) {
|
|
917
1168
|
console.log(
|
|
918
|
-
` Project: ${
|
|
1169
|
+
` Project: ${chalk7.yellow("No project linked.")} Run ${chalk7.cyan("yapout link")} in a repo.`
|
|
919
1170
|
);
|
|
920
1171
|
} else {
|
|
921
|
-
console.log(` Project: ${
|
|
1172
|
+
console.log(` Project: ${chalk7.green(mapping.projectName)}`);
|
|
922
1173
|
}
|
|
923
|
-
console.log(` Daemon: ${
|
|
924
|
-
console.log(` Work: ${
|
|
1174
|
+
console.log(` Daemon: ${chalk7.dim("not running")}`);
|
|
1175
|
+
console.log(` Work: ${chalk7.dim("no active tickets")}`);
|
|
925
1176
|
console.log();
|
|
926
1177
|
});
|
|
927
1178
|
|
|
928
1179
|
// src/commands/init.ts
|
|
929
|
-
import { Command as
|
|
930
|
-
import { resolve as resolve5, join as
|
|
1180
|
+
import { Command as Command7 } from "commander";
|
|
1181
|
+
import { resolve as resolve5, join as join6 } from "path";
|
|
931
1182
|
import {
|
|
932
|
-
existsSync as
|
|
1183
|
+
existsSync as existsSync5,
|
|
933
1184
|
mkdirSync as mkdirSync4,
|
|
934
|
-
writeFileSync as
|
|
935
|
-
readFileSync as
|
|
1185
|
+
writeFileSync as writeFileSync6,
|
|
1186
|
+
readFileSync as readFileSync5,
|
|
936
1187
|
appendFileSync as appendFileSync2
|
|
937
1188
|
} from "fs";
|
|
938
|
-
import { hostname as
|
|
939
|
-
import
|
|
1189
|
+
import { hostname as hostname4 } from "os";
|
|
1190
|
+
import chalk8 from "chalk";
|
|
940
1191
|
var CONFIG_YAML_CONTENT2 = `# yapout local configuration
|
|
941
1192
|
# See: https://docs.yapout.dev/cli/config
|
|
942
1193
|
|
|
@@ -961,7 +1212,7 @@ branch_prefix: feat
|
|
|
961
1212
|
# {{ticket.linearTicketId}}, {{ticket.id}}
|
|
962
1213
|
# commit_template: "{{ticket.type}}({{ticket.linearTicketId}}): {{ticket.title}}"
|
|
963
1214
|
`;
|
|
964
|
-
var initCommand = new
|
|
1215
|
+
var initCommand = new Command7("init").description("Create a yapout project from the current repo and link it").argument("[name]", "Project name (defaults to repo name)").option("--org <slug>", "Org slug to create the project in (skips picker)").action(async (name, options) => {
|
|
965
1216
|
const creds = requireAuth();
|
|
966
1217
|
const cwd = resolveRepoRoot(resolve5(process.cwd()));
|
|
967
1218
|
let repoFullName;
|
|
@@ -971,7 +1222,7 @@ var initCommand = new Command6("init").description("Create a yapout project from
|
|
|
971
1222
|
defaultBranch = getDefaultBranch(cwd);
|
|
972
1223
|
} catch (err) {
|
|
973
1224
|
console.error(
|
|
974
|
-
|
|
1225
|
+
chalk8.red("Not a git repo with a GitHub remote."),
|
|
975
1226
|
err.message
|
|
976
1227
|
);
|
|
977
1228
|
process.exit(1);
|
|
@@ -986,14 +1237,14 @@ var initCommand = new Command6("init").description("Create a yapout project from
|
|
|
986
1237
|
);
|
|
987
1238
|
} catch (err) {
|
|
988
1239
|
console.error(
|
|
989
|
-
|
|
1240
|
+
chalk8.red("Failed to load your orgs."),
|
|
990
1241
|
err.message
|
|
991
1242
|
);
|
|
992
1243
|
process.exit(1);
|
|
993
1244
|
}
|
|
994
1245
|
if (!orgs || orgs.length === 0) {
|
|
995
1246
|
console.error(
|
|
996
|
-
|
|
1247
|
+
chalk8.red(
|
|
997
1248
|
"You aren't a member of any org. Sign in to the web app once to create your personal org, then re-run."
|
|
998
1249
|
)
|
|
999
1250
|
);
|
|
@@ -1005,10 +1256,10 @@ var initCommand = new Command6("init").description("Create a yapout project from
|
|
|
1005
1256
|
const match = orgs.find((o) => o.org.slug === options.org);
|
|
1006
1257
|
if (!match) {
|
|
1007
1258
|
console.error(
|
|
1008
|
-
|
|
1259
|
+
chalk8.red(`Org "${options.org}" not found among your memberships.`)
|
|
1009
1260
|
);
|
|
1010
1261
|
console.error(
|
|
1011
|
-
|
|
1262
|
+
chalk8.dim(
|
|
1012
1263
|
"Available: " + orgs.map((o) => o.org.slug).join(", ")
|
|
1013
1264
|
)
|
|
1014
1265
|
);
|
|
@@ -1020,7 +1271,7 @@ var initCommand = new Command6("init").description("Create a yapout project from
|
|
|
1020
1271
|
chosenOrgId = orgs[0].org._id;
|
|
1021
1272
|
chosenOrgName = orgs[0].org.name;
|
|
1022
1273
|
console.log(
|
|
1023
|
-
|
|
1274
|
+
chalk8.dim(`Creating in `) + chalk8.cyan(chosenOrgName)
|
|
1024
1275
|
);
|
|
1025
1276
|
} else {
|
|
1026
1277
|
const picked = await pickOrg(
|
|
@@ -1034,17 +1285,17 @@ var initCommand = new Command6("init").description("Create a yapout project from
|
|
|
1034
1285
|
chosenOrgId = picked.id;
|
|
1035
1286
|
chosenOrgName = picked.name;
|
|
1036
1287
|
}
|
|
1037
|
-
const device = getOrCreateDeviceIdentity(
|
|
1288
|
+
const device = getOrCreateDeviceIdentity(hostname4());
|
|
1038
1289
|
try {
|
|
1039
1290
|
await client.mutation(anyApi.functions.devices.registerDevice, {
|
|
1040
1291
|
deviceId: device.deviceId,
|
|
1041
1292
|
name: device.name,
|
|
1042
1293
|
cliVersion: getCliVersion2(),
|
|
1043
|
-
machineHostname:
|
|
1294
|
+
machineHostname: hostname4()
|
|
1044
1295
|
});
|
|
1045
1296
|
} catch (err) {
|
|
1046
1297
|
console.warn(
|
|
1047
|
-
|
|
1298
|
+
chalk8.yellow("Warning: device registration failed \u2014 "),
|
|
1048
1299
|
err.message
|
|
1049
1300
|
);
|
|
1050
1301
|
}
|
|
@@ -1061,7 +1312,7 @@ var initCommand = new Command6("init").description("Create a yapout project from
|
|
|
1061
1312
|
);
|
|
1062
1313
|
} catch (err) {
|
|
1063
1314
|
console.error(
|
|
1064
|
-
|
|
1315
|
+
chalk8.red("Failed to create project."),
|
|
1065
1316
|
err.message
|
|
1066
1317
|
);
|
|
1067
1318
|
process.exit(1);
|
|
@@ -1074,7 +1325,7 @@ var initCommand = new Command6("init").description("Create a yapout project from
|
|
|
1074
1325
|
});
|
|
1075
1326
|
} catch (err) {
|
|
1076
1327
|
console.warn(
|
|
1077
|
-
|
|
1328
|
+
chalk8.yellow("Warning: failed to record project checkout \u2014 "),
|
|
1078
1329
|
err.message
|
|
1079
1330
|
);
|
|
1080
1331
|
}
|
|
@@ -1083,15 +1334,15 @@ var initCommand = new Command6("init").description("Create a yapout project from
|
|
|
1083
1334
|
projectName: result.projectName,
|
|
1084
1335
|
linkedAt: Date.now()
|
|
1085
1336
|
});
|
|
1086
|
-
const yapoutDir =
|
|
1087
|
-
if (!
|
|
1088
|
-
const configPath =
|
|
1089
|
-
if (!
|
|
1090
|
-
|
|
1091
|
-
}
|
|
1092
|
-
const gitignorePath =
|
|
1093
|
-
if (
|
|
1094
|
-
const content =
|
|
1337
|
+
const yapoutDir = join6(cwd, ".yapout");
|
|
1338
|
+
if (!existsSync5(yapoutDir)) mkdirSync4(yapoutDir, { recursive: true });
|
|
1339
|
+
const configPath = join6(yapoutDir, "config.yml");
|
|
1340
|
+
if (!existsSync5(configPath)) {
|
|
1341
|
+
writeFileSync6(configPath, CONFIG_YAML_CONTENT2);
|
|
1342
|
+
}
|
|
1343
|
+
const gitignorePath = join6(cwd, ".gitignore");
|
|
1344
|
+
if (existsSync5(gitignorePath)) {
|
|
1345
|
+
const content = readFileSync5(gitignorePath, "utf-8");
|
|
1095
1346
|
if (!content.includes(".yapout/")) {
|
|
1096
1347
|
appendFileSync2(
|
|
1097
1348
|
gitignorePath,
|
|
@@ -1099,11 +1350,11 @@ var initCommand = new Command6("init").description("Create a yapout project from
|
|
|
1099
1350
|
);
|
|
1100
1351
|
}
|
|
1101
1352
|
}
|
|
1102
|
-
const mcpPath =
|
|
1353
|
+
const mcpPath = join6(cwd, ".mcp.json");
|
|
1103
1354
|
let mcpConfig = {};
|
|
1104
|
-
if (
|
|
1355
|
+
if (existsSync5(mcpPath)) {
|
|
1105
1356
|
try {
|
|
1106
|
-
mcpConfig = JSON.parse(
|
|
1357
|
+
mcpConfig = JSON.parse(readFileSync5(mcpPath, "utf-8"));
|
|
1107
1358
|
} catch {
|
|
1108
1359
|
}
|
|
1109
1360
|
}
|
|
@@ -1112,20 +1363,20 @@ var initCommand = new Command6("init").description("Create a yapout project from
|
|
|
1112
1363
|
command: "yapout",
|
|
1113
1364
|
args: ["mcp-server"]
|
|
1114
1365
|
};
|
|
1115
|
-
|
|
1366
|
+
writeFileSync6(mcpPath, JSON.stringify(mcpConfig, null, 2) + "\n");
|
|
1116
1367
|
console.log(
|
|
1117
|
-
|
|
1368
|
+
chalk8.green(`Created project "${result.projectName}"`) + chalk8.dim(
|
|
1118
1369
|
` in ${chosenOrgName} (${repoFullName}, branch: ${defaultBranch})`
|
|
1119
1370
|
)
|
|
1120
1371
|
);
|
|
1121
1372
|
console.log(
|
|
1122
|
-
|
|
1373
|
+
chalk8.dim("Run ") + chalk8.cyan("yapout_compact") + chalk8.dim(" in Claude Code to generate project context.")
|
|
1123
1374
|
);
|
|
1124
1375
|
});
|
|
1125
1376
|
function getCliVersion2() {
|
|
1126
1377
|
try {
|
|
1127
1378
|
const pkg = JSON.parse(
|
|
1128
|
-
|
|
1379
|
+
readFileSync5(join6(import.meta.dirname, "..", "package.json"), "utf-8")
|
|
1129
1380
|
);
|
|
1130
1381
|
return pkg.version ?? "unknown";
|
|
1131
1382
|
} catch {
|
|
@@ -1134,18 +1385,18 @@ function getCliVersion2() {
|
|
|
1134
1385
|
}
|
|
1135
1386
|
|
|
1136
1387
|
// src/commands/mcp-server.ts
|
|
1137
|
-
import { Command as
|
|
1388
|
+
import { Command as Command8 } from "commander";
|
|
1138
1389
|
|
|
1139
1390
|
// src/mcp/server.ts
|
|
1140
1391
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
1141
1392
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
1142
1393
|
import { ConvexHttpClient as ConvexHttpClient2 } from "convex/browser";
|
|
1143
|
-
import { anyApi as
|
|
1394
|
+
import { anyApi as anyApi4 } from "convex/server";
|
|
1144
1395
|
|
|
1145
1396
|
// src/mcp/tools/init.ts
|
|
1146
1397
|
import { z } from "zod";
|
|
1147
|
-
import { join as
|
|
1148
|
-
import { existsSync as
|
|
1398
|
+
import { join as join7 } from "path";
|
|
1399
|
+
import { existsSync as existsSync6, mkdirSync as mkdirSync5, writeFileSync as writeFileSync7 } from "fs";
|
|
1149
1400
|
import { stringify as yamlStringify } from "yaml";
|
|
1150
1401
|
function registerInitTool(server, ctx) {
|
|
1151
1402
|
server.tool(
|
|
@@ -1161,7 +1412,7 @@ function registerInitTool(server, ctx) {
|
|
|
1161
1412
|
const defaultBranch = getDefaultBranch(repoRoot);
|
|
1162
1413
|
const projectName = args.name || repoFullName.split("/")[1] || "unnamed";
|
|
1163
1414
|
const result = await ctx.client.mutation(
|
|
1164
|
-
|
|
1415
|
+
anyApi4.functions.projects.createProjectFromCli,
|
|
1165
1416
|
{
|
|
1166
1417
|
name: projectName,
|
|
1167
1418
|
githubRepoFullName: repoFullName,
|
|
@@ -1176,11 +1427,11 @@ function registerInitTool(server, ctx) {
|
|
|
1176
1427
|
projectName: result.projectName,
|
|
1177
1428
|
linkedAt: Date.now()
|
|
1178
1429
|
});
|
|
1179
|
-
const yapoutDir =
|
|
1180
|
-
if (!
|
|
1181
|
-
const configPath =
|
|
1182
|
-
if (!
|
|
1183
|
-
|
|
1430
|
+
const yapoutDir = join7(repoRoot, ".yapout");
|
|
1431
|
+
if (!existsSync6(yapoutDir)) mkdirSync5(yapoutDir, { recursive: true });
|
|
1432
|
+
const configPath = join7(yapoutDir, "config.yml");
|
|
1433
|
+
if (!existsSync6(configPath)) {
|
|
1434
|
+
writeFileSync7(
|
|
1184
1435
|
configPath,
|
|
1185
1436
|
`# yapout local configuration
|
|
1186
1437
|
|
|
@@ -1249,7 +1500,7 @@ function registerCompactTool(server, ctx) {
|
|
|
1249
1500
|
let lastUpdated;
|
|
1250
1501
|
try {
|
|
1251
1502
|
const project = await ctx.client.query(
|
|
1252
|
-
|
|
1503
|
+
anyApi4.functions.projects.getProject,
|
|
1253
1504
|
{ projectId: ctx.projectId }
|
|
1254
1505
|
);
|
|
1255
1506
|
currentContext = project?.contextSummary ?? void 0;
|
|
@@ -1292,7 +1543,7 @@ function registerUpdateContextTool(server, ctx) {
|
|
|
1292
1543
|
};
|
|
1293
1544
|
}
|
|
1294
1545
|
await ctx.client.mutation(
|
|
1295
|
-
|
|
1546
|
+
anyApi4.functions.projects.updateProjectContext,
|
|
1296
1547
|
{
|
|
1297
1548
|
projectId: ctx.projectId,
|
|
1298
1549
|
summary: args.summary
|
|
@@ -1362,7 +1613,7 @@ function registerQueueTool(server, ctx) {
|
|
|
1362
1613
|
};
|
|
1363
1614
|
}
|
|
1364
1615
|
const data = await ctx.client.query(
|
|
1365
|
-
|
|
1616
|
+
anyApi4.functions.workQueue.getWorkQueue,
|
|
1366
1617
|
{ projectId: ctx.projectId }
|
|
1367
1618
|
);
|
|
1368
1619
|
if (!data) {
|
|
@@ -1471,7 +1722,7 @@ function registerGetBriefTool(server, ctx) {
|
|
|
1471
1722
|
}
|
|
1472
1723
|
try {
|
|
1473
1724
|
const data = await ctx.client.query(
|
|
1474
|
-
|
|
1725
|
+
anyApi4.functions.findings.getFindingBrief,
|
|
1475
1726
|
{ findingId: itemId }
|
|
1476
1727
|
);
|
|
1477
1728
|
if (data) {
|
|
@@ -1485,7 +1736,7 @@ function registerGetBriefTool(server, ctx) {
|
|
|
1485
1736
|
}
|
|
1486
1737
|
try {
|
|
1487
1738
|
const bundle = await ctx.client.query(
|
|
1488
|
-
|
|
1739
|
+
anyApi4.functions.bundles.getBundle,
|
|
1489
1740
|
{ bundleId: itemId }
|
|
1490
1741
|
);
|
|
1491
1742
|
if (bundle) {
|
|
@@ -1536,8 +1787,8 @@ function registerGetBriefTool(server, ctx) {
|
|
|
1536
1787
|
|
|
1537
1788
|
// src/mcp/tools/claim.ts
|
|
1538
1789
|
import { z as z5 } from "zod";
|
|
1539
|
-
import { join as
|
|
1540
|
-
import { existsSync as
|
|
1790
|
+
import { join as join8 } from "path";
|
|
1791
|
+
import { existsSync as existsSync7, mkdirSync as mkdirSync6, writeFileSync as writeFileSync8 } from "fs";
|
|
1541
1792
|
function readBranchPrefix(cwd) {
|
|
1542
1793
|
try {
|
|
1543
1794
|
const config = readYapoutConfig(cwd);
|
|
@@ -1656,7 +1907,7 @@ function formatBundleBrief(bundle, projectContext) {
|
|
|
1656
1907
|
async function detectWorkItemKind(client, workItemId) {
|
|
1657
1908
|
try {
|
|
1658
1909
|
const bundle = await client.query(
|
|
1659
|
-
|
|
1910
|
+
anyApi4.functions.bundles.getBundle,
|
|
1660
1911
|
{ bundleId: workItemId }
|
|
1661
1912
|
);
|
|
1662
1913
|
if (bundle) {
|
|
@@ -1710,7 +1961,7 @@ function registerClaimTool(server, ctx) {
|
|
|
1710
1961
|
}
|
|
1711
1962
|
async function claimStandalone(ctx, args, findingId) {
|
|
1712
1963
|
const briefData = await ctx.client.query(
|
|
1713
|
-
|
|
1964
|
+
anyApi4.functions.findings.getFindingBrief,
|
|
1714
1965
|
{ findingId }
|
|
1715
1966
|
);
|
|
1716
1967
|
if (!briefData) {
|
|
@@ -1731,11 +1982,11 @@ async function claimStandalone(ctx, args, findingId) {
|
|
|
1731
1982
|
const slug = slugify(finding.title);
|
|
1732
1983
|
const branchName = linearIssueId ? `${prefix}/${linearIssueId.toLowerCase()}-${slug}` : `${prefix}/${slug}`;
|
|
1733
1984
|
const localClaim = await ctx.client.mutation(
|
|
1734
|
-
|
|
1985
|
+
anyApi4.functions.findings.claimFindingLocal,
|
|
1735
1986
|
{ findingId, branchName }
|
|
1736
1987
|
);
|
|
1737
1988
|
const claim = await ctx.client.mutation(
|
|
1738
|
-
|
|
1989
|
+
anyApi4.functions.workQueue.claimForImplementation,
|
|
1739
1990
|
{
|
|
1740
1991
|
projectId: ctx.projectId,
|
|
1741
1992
|
workItemId: findingId,
|
|
@@ -1745,7 +1996,7 @@ async function claimStandalone(ctx, args, findingId) {
|
|
|
1745
1996
|
if (linearIssueId && ctx.projectId) {
|
|
1746
1997
|
try {
|
|
1747
1998
|
await ctx.client.action(
|
|
1748
|
-
|
|
1999
|
+
anyApi4.functions.linearStatusMutations.moveIssueStatus,
|
|
1749
2000
|
{
|
|
1750
2001
|
projectId: ctx.projectId,
|
|
1751
2002
|
linearIssueId,
|
|
@@ -1802,11 +2053,11 @@ async function claimBundle(ctx, args, bundleId, bundleData) {
|
|
|
1802
2053
|
};
|
|
1803
2054
|
}
|
|
1804
2055
|
const localClaim = await ctx.client.mutation(
|
|
1805
|
-
|
|
2056
|
+
anyApi4.functions.findings.claimFindingLocal,
|
|
1806
2057
|
{ findingId: primaryFinding._id, branchName }
|
|
1807
2058
|
);
|
|
1808
2059
|
const claim = await ctx.client.mutation(
|
|
1809
|
-
|
|
2060
|
+
anyApi4.functions.workQueue.claimForImplementation,
|
|
1810
2061
|
{
|
|
1811
2062
|
projectId: ctx.projectId,
|
|
1812
2063
|
workItemId: bundleId,
|
|
@@ -1817,7 +2068,7 @@ async function claimBundle(ctx, args, bundleId, bundleData) {
|
|
|
1817
2068
|
if (f.linearIssueId && ctx.projectId) {
|
|
1818
2069
|
try {
|
|
1819
2070
|
await ctx.client.action(
|
|
1820
|
-
|
|
2071
|
+
anyApi4.functions.linearStatusMutations.moveIssueStatus,
|
|
1821
2072
|
{
|
|
1822
2073
|
projectId: ctx.projectId,
|
|
1823
2074
|
linearIssueId: f.linearIssueId,
|
|
@@ -1831,7 +2082,7 @@ async function claimBundle(ctx, args, bundleId, bundleData) {
|
|
|
1831
2082
|
let projectContext;
|
|
1832
2083
|
try {
|
|
1833
2084
|
const briefData = await ctx.client.query(
|
|
1834
|
-
|
|
2085
|
+
anyApi4.functions.findings.getFindingBrief,
|
|
1835
2086
|
{ findingId: primaryFinding._id }
|
|
1836
2087
|
);
|
|
1837
2088
|
projectContext = briefData?.projectContext;
|
|
@@ -1871,7 +2122,7 @@ async function claimBundle(ctx, args, bundleId, bundleData) {
|
|
|
1871
2122
|
async function getDefaultBranchForProject(ctx) {
|
|
1872
2123
|
try {
|
|
1873
2124
|
const data = await ctx.client.query(
|
|
1874
|
-
|
|
2125
|
+
anyApi4.functions.projects.getProject,
|
|
1875
2126
|
{ projectId: ctx.projectId }
|
|
1876
2127
|
);
|
|
1877
2128
|
return data?.githubDefaultBranch || "main";
|
|
@@ -1890,7 +2141,7 @@ async function setupWorktree(ctx, itemId, branchName, defaultBranch, brief, pipe
|
|
|
1890
2141
|
writeBrief(worktreePath, brief);
|
|
1891
2142
|
try {
|
|
1892
2143
|
await ctx.client.mutation(
|
|
1893
|
-
|
|
2144
|
+
anyApi4.functions.pipelineRuns.reportDaemonEvent,
|
|
1894
2145
|
{
|
|
1895
2146
|
pipelineRunId,
|
|
1896
2147
|
event: "worktree_created",
|
|
@@ -1919,14 +2170,14 @@ async function setupWorktree(ctx, itemId, branchName, defaultBranch, brief, pipe
|
|
|
1919
2170
|
};
|
|
1920
2171
|
}
|
|
1921
2172
|
function writeBrief(dir, brief) {
|
|
1922
|
-
const yapoutDir =
|
|
1923
|
-
if (!
|
|
1924
|
-
|
|
2173
|
+
const yapoutDir = join8(dir, ".yapout");
|
|
2174
|
+
if (!existsSync7(yapoutDir)) mkdirSync6(yapoutDir, { recursive: true });
|
|
2175
|
+
writeFileSync8(join8(yapoutDir, "brief.md"), brief);
|
|
1925
2176
|
}
|
|
1926
2177
|
async function reportClaimEvents(ctx, pipelineRunId, title, branchName) {
|
|
1927
2178
|
try {
|
|
1928
2179
|
await ctx.client.mutation(
|
|
1929
|
-
|
|
2180
|
+
anyApi4.functions.pipelineRuns.reportDaemonEvent,
|
|
1930
2181
|
{
|
|
1931
2182
|
pipelineRunId,
|
|
1932
2183
|
event: "daemon_claimed",
|
|
@@ -1934,7 +2185,7 @@ async function reportClaimEvents(ctx, pipelineRunId, title, branchName) {
|
|
|
1934
2185
|
}
|
|
1935
2186
|
);
|
|
1936
2187
|
await ctx.client.mutation(
|
|
1937
|
-
|
|
2188
|
+
anyApi4.functions.pipelineRuns.reportDaemonEvent,
|
|
1938
2189
|
{
|
|
1939
2190
|
pipelineRunId,
|
|
1940
2191
|
event: "branch_created",
|
|
@@ -1961,7 +2212,7 @@ function registerEventTool(server, ctx) {
|
|
|
1961
2212
|
async (args) => {
|
|
1962
2213
|
try {
|
|
1963
2214
|
await ctx.client.mutation(
|
|
1964
|
-
|
|
2215
|
+
anyApi4.functions.pipelineRuns.reportDaemonEvent,
|
|
1965
2216
|
{
|
|
1966
2217
|
pipelineRunId: args.pipelineRunId,
|
|
1967
2218
|
event: args.event,
|
|
@@ -2053,8 +2304,8 @@ async function createPullRequest(title, body, branch, base, repoFullName, cwd) {
|
|
|
2053
2304
|
}
|
|
2054
2305
|
|
|
2055
2306
|
// src/mcp/tools/ship.ts
|
|
2056
|
-
import { join as
|
|
2057
|
-
import { existsSync as
|
|
2307
|
+
import { join as join9 } from "path";
|
|
2308
|
+
import { existsSync as existsSync8, readFileSync as readFileSync6 } from "fs";
|
|
2058
2309
|
function buildCommitMessage(message, template, finding, allLinearIds) {
|
|
2059
2310
|
if (message) return message;
|
|
2060
2311
|
if (template) {
|
|
@@ -2105,9 +2356,9 @@ function registerShipTool(server, ctx) {
|
|
|
2105
2356
|
let isBundle = false;
|
|
2106
2357
|
let bundleTitle;
|
|
2107
2358
|
try {
|
|
2108
|
-
const briefPath =
|
|
2109
|
-
if (
|
|
2110
|
-
const brief =
|
|
2359
|
+
const briefPath = join9(gitCwd, ".yapout", "brief.md");
|
|
2360
|
+
if (existsSync8(briefPath)) {
|
|
2361
|
+
const brief = readFileSync6(briefPath, "utf-8");
|
|
2111
2362
|
const bundleMatch = brief.match(/^# Bundle: (.+)$/m);
|
|
2112
2363
|
if (bundleMatch) {
|
|
2113
2364
|
isBundle = true;
|
|
@@ -2218,7 +2469,7 @@ function registerShipTool(server, ctx) {
|
|
|
2218
2469
|
}
|
|
2219
2470
|
try {
|
|
2220
2471
|
await ctx.client.mutation(
|
|
2221
|
-
|
|
2472
|
+
anyApi4.functions.pipelineRuns.reportDaemonEvent,
|
|
2222
2473
|
{
|
|
2223
2474
|
pipelineRunId: args.pipelineRunId,
|
|
2224
2475
|
event: "push_completed",
|
|
@@ -2227,7 +2478,7 @@ function registerShipTool(server, ctx) {
|
|
|
2227
2478
|
);
|
|
2228
2479
|
if (prUrl) {
|
|
2229
2480
|
await ctx.client.mutation(
|
|
2230
|
-
|
|
2481
|
+
anyApi4.functions.pipelineRuns.reportDaemonEvent,
|
|
2231
2482
|
{
|
|
2232
2483
|
pipelineRunId: args.pipelineRunId,
|
|
2233
2484
|
event: "pr_opened",
|
|
@@ -2239,7 +2490,7 @@ function registerShipTool(server, ctx) {
|
|
|
2239
2490
|
}
|
|
2240
2491
|
try {
|
|
2241
2492
|
await ctx.client.mutation(
|
|
2242
|
-
|
|
2493
|
+
anyApi4.functions.pipelineRuns.completePipelineLocal,
|
|
2243
2494
|
{
|
|
2244
2495
|
pipelineRunId: args.pipelineRunId,
|
|
2245
2496
|
githubPrNumber: prNumber,
|
|
@@ -2255,7 +2506,7 @@ function registerShipTool(server, ctx) {
|
|
|
2255
2506
|
if (ctx.projectId) {
|
|
2256
2507
|
try {
|
|
2257
2508
|
await ctx.client.action(
|
|
2258
|
-
|
|
2509
|
+
anyApi4.functions.linearStatusMutations.moveIssueStatus,
|
|
2259
2510
|
{
|
|
2260
2511
|
projectId: ctx.projectId,
|
|
2261
2512
|
linearIssueId: linearId,
|
|
@@ -2267,7 +2518,7 @@ function registerShipTool(server, ctx) {
|
|
|
2267
2518
|
if (prUrl) {
|
|
2268
2519
|
try {
|
|
2269
2520
|
await ctx.client.action(
|
|
2270
|
-
|
|
2521
|
+
anyApi4.functions.linearStatusMutations.addLinearComment,
|
|
2271
2522
|
{
|
|
2272
2523
|
projectId: ctx.projectId,
|
|
2273
2524
|
linearIssueId: linearId,
|
|
@@ -2285,7 +2536,7 @@ function registerShipTool(server, ctx) {
|
|
|
2285
2536
|
result.worktreeCleaned = true;
|
|
2286
2537
|
try {
|
|
2287
2538
|
await ctx.client.mutation(
|
|
2288
|
-
|
|
2539
|
+
anyApi4.functions.pipelineRuns.reportDaemonEvent,
|
|
2289
2540
|
{
|
|
2290
2541
|
pipelineRunId: args.pipelineRunId,
|
|
2291
2542
|
event: "worktree_cleaned",
|
|
@@ -2376,7 +2627,7 @@ function registerCheckTool(server, ctx) {
|
|
|
2376
2627
|
if (args.pipelineRunId) {
|
|
2377
2628
|
try {
|
|
2378
2629
|
await ctx.client.mutation(
|
|
2379
|
-
|
|
2630
|
+
anyApi4.functions.pipelineRuns.reportDaemonEvent,
|
|
2380
2631
|
{
|
|
2381
2632
|
pipelineRunId: args.pipelineRunId,
|
|
2382
2633
|
event: "running_check",
|
|
@@ -2396,7 +2647,7 @@ function registerCheckTool(server, ctx) {
|
|
|
2396
2647
|
if (args.pipelineRunId) {
|
|
2397
2648
|
try {
|
|
2398
2649
|
await ctx.client.mutation(
|
|
2399
|
-
|
|
2650
|
+
anyApi4.functions.pipelineRuns.reportDaemonEvent,
|
|
2400
2651
|
{
|
|
2401
2652
|
pipelineRunId: args.pipelineRunId,
|
|
2402
2653
|
event: passed ? "check_passed" : "check_failed",
|
|
@@ -2428,8 +2679,8 @@ function registerCheckTool(server, ctx) {
|
|
|
2428
2679
|
|
|
2429
2680
|
// src/mcp/tools/bundle.ts
|
|
2430
2681
|
import { z as z9 } from "zod";
|
|
2431
|
-
import { join as
|
|
2432
|
-
import { existsSync as
|
|
2682
|
+
import { join as join10 } from "path";
|
|
2683
|
+
import { existsSync as existsSync9, writeFileSync as writeFileSync9, mkdirSync as mkdirSync7 } from "fs";
|
|
2433
2684
|
function registerBundleTool(server, ctx) {
|
|
2434
2685
|
server.tool(
|
|
2435
2686
|
"yapout_bundle",
|
|
@@ -2440,11 +2691,11 @@ function registerBundleTool(server, ctx) {
|
|
|
2440
2691
|
},
|
|
2441
2692
|
async (args) => {
|
|
2442
2693
|
const result = await ctx.client.mutation(
|
|
2443
|
-
|
|
2694
|
+
anyApi4.functions.bundles.createBundle,
|
|
2444
2695
|
{ leadFindingId: args.withFinding, joiningFindingId: args.findingId }
|
|
2445
2696
|
);
|
|
2446
2697
|
const bundledBrief = await ctx.client.query(
|
|
2447
|
-
|
|
2698
|
+
anyApi4.functions.bundles.getBundledBrief,
|
|
2448
2699
|
{ bundleId: result.bundleId }
|
|
2449
2700
|
);
|
|
2450
2701
|
if (!bundledBrief) {
|
|
@@ -2482,9 +2733,9 @@ function registerBundleTool(server, ctx) {
|
|
|
2482
2733
|
sections.push("## Project Context", "", bundledBrief.projectContext);
|
|
2483
2734
|
}
|
|
2484
2735
|
const combinedBrief = sections.join("\n");
|
|
2485
|
-
const yapoutDir =
|
|
2486
|
-
if (!
|
|
2487
|
-
|
|
2736
|
+
const yapoutDir = join10(ctx.cwd, ".yapout");
|
|
2737
|
+
if (!existsSync9(yapoutDir)) mkdirSync7(yapoutDir, { recursive: true });
|
|
2738
|
+
writeFileSync9(join10(yapoutDir, "brief.md"), combinedBrief);
|
|
2488
2739
|
return {
|
|
2489
2740
|
content: [
|
|
2490
2741
|
{
|
|
@@ -2541,7 +2792,7 @@ After calling this tool, you should:
|
|
|
2541
2792
|
}
|
|
2542
2793
|
try {
|
|
2543
2794
|
const result = await ctx.client.mutation(
|
|
2544
|
-
|
|
2795
|
+
anyApi4.functions.localPipeline.claimForEnrichment,
|
|
2545
2796
|
{
|
|
2546
2797
|
projectId,
|
|
2547
2798
|
...args.findingId ? { findingId: args.findingId } : {}
|
|
@@ -2601,7 +2852,7 @@ function registerGetExistingFindingsTool(server, ctx) {
|
|
|
2601
2852
|
}
|
|
2602
2853
|
try {
|
|
2603
2854
|
const findings = await ctx.client.query(
|
|
2604
|
-
|
|
2855
|
+
anyApi4.functions.localPipeline.getExistingFindingTitles,
|
|
2605
2856
|
{ projectId }
|
|
2606
2857
|
);
|
|
2607
2858
|
if (!findings || findings.length === 0) {
|
|
@@ -2703,7 +2954,7 @@ The finding transitions: enriching \u2192 enriched \u2192 ready.`,
|
|
|
2703
2954
|
async (args) => {
|
|
2704
2955
|
try {
|
|
2705
2956
|
await ctx.client.mutation(
|
|
2706
|
-
|
|
2957
|
+
anyApi4.functions.localPipeline.saveLocalEnrichment,
|
|
2707
2958
|
{
|
|
2708
2959
|
findingId: args.findingId,
|
|
2709
2960
|
title: args.title,
|
|
@@ -2718,11 +2969,11 @@ The finding transitions: enriching \u2192 enriched \u2192 ready.`,
|
|
|
2718
2969
|
}
|
|
2719
2970
|
);
|
|
2720
2971
|
await ctx.client.action(
|
|
2721
|
-
|
|
2972
|
+
anyApi4.functions.localPipeline.syncFindingToLinearLocal,
|
|
2722
2973
|
{ findingId: args.findingId }
|
|
2723
2974
|
);
|
|
2724
2975
|
const finding = await ctx.client.query(
|
|
2725
|
-
|
|
2976
|
+
anyApi4.functions.findings.getFinding,
|
|
2726
2977
|
{ findingId: args.findingId }
|
|
2727
2978
|
);
|
|
2728
2979
|
if (args.sessionId) {
|
|
@@ -2781,7 +3032,7 @@ function registerSyncToLinearTool(server, ctx) {
|
|
|
2781
3032
|
async (args) => {
|
|
2782
3033
|
try {
|
|
2783
3034
|
await ctx.client.action(
|
|
2784
|
-
|
|
3035
|
+
anyApi4.functions.localPipeline.syncFindingToLinearLocal,
|
|
2785
3036
|
{ findingId: args.findingId }
|
|
2786
3037
|
);
|
|
2787
3038
|
return {
|
|
@@ -2839,7 +3090,7 @@ function registerSubmitYapSessionTool(server, ctx) {
|
|
|
2839
3090
|
}
|
|
2840
3091
|
try {
|
|
2841
3092
|
const captureId = await ctx.client.mutation(
|
|
2842
|
-
|
|
3093
|
+
anyApi4.functions.captures.createFromYapSession,
|
|
2843
3094
|
{
|
|
2844
3095
|
projectId: ctx.projectId,
|
|
2845
3096
|
title: args.title,
|
|
@@ -3115,7 +3366,7 @@ function registerExtractFromYapTool(server, ctx) {
|
|
|
3115
3366
|
}
|
|
3116
3367
|
try {
|
|
3117
3368
|
const result = await ctx.client.mutation(
|
|
3118
|
-
|
|
3369
|
+
anyApi4.functions.captures.extractFromYapSession,
|
|
3119
3370
|
{
|
|
3120
3371
|
projectId: ctx.projectId,
|
|
3121
3372
|
title: args.sessionTitle,
|
|
@@ -3227,7 +3478,7 @@ full spec \u2014 schema changes, files to modify, edge cases, and acceptance cri
|
|
|
3227
3478
|
}
|
|
3228
3479
|
try {
|
|
3229
3480
|
const result = await ctx.client.mutation(
|
|
3230
|
-
|
|
3481
|
+
anyApi4.functions.localPipeline.decomposeIntoBundle,
|
|
3231
3482
|
{
|
|
3232
3483
|
findingId: args.findingId,
|
|
3233
3484
|
bundleDescription: args.bundleDescription,
|
|
@@ -3300,7 +3551,7 @@ The finding must be in "enriching" or "enriched" status. It will be transitioned
|
|
|
3300
3551
|
}
|
|
3301
3552
|
try {
|
|
3302
3553
|
const result = await ctx.client.mutation(
|
|
3303
|
-
|
|
3554
|
+
anyApi4.functions.findings.markDuplicate,
|
|
3304
3555
|
{
|
|
3305
3556
|
findingId: args.findingId,
|
|
3306
3557
|
duplicateOfLinearId: args.duplicateOfLinearId,
|
|
@@ -3363,7 +3614,7 @@ and issue counts so you can ask the user for confirmation before creating a new
|
|
|
3363
3614
|
}
|
|
3364
3615
|
try {
|
|
3365
3616
|
const project = await ctx.client.query(
|
|
3366
|
-
|
|
3617
|
+
anyApi4.functions.projects.getProject,
|
|
3367
3618
|
{ projectId: ctx.projectId }
|
|
3368
3619
|
);
|
|
3369
3620
|
if (!project?.linearTeamId) {
|
|
@@ -3378,7 +3629,7 @@ and issue counts so you can ask the user for confirmation before creating a new
|
|
|
3378
3629
|
};
|
|
3379
3630
|
}
|
|
3380
3631
|
const projects = await ctx.client.action(
|
|
3381
|
-
|
|
3632
|
+
anyApi4.functions.linearProjectsMutations.fetchProjectsDetailed,
|
|
3382
3633
|
{ projectId: ctx.projectId, teamId: project.linearTeamId }
|
|
3383
3634
|
);
|
|
3384
3635
|
return {
|
|
@@ -3440,7 +3691,7 @@ Optionally filter by tags, capture, or explicit finding IDs.`,
|
|
|
3440
3691
|
}
|
|
3441
3692
|
try {
|
|
3442
3693
|
const allFindings = await ctx.client.query(
|
|
3443
|
-
|
|
3694
|
+
anyApi4.functions.findings.getProjectFindings,
|
|
3444
3695
|
{ projectId }
|
|
3445
3696
|
);
|
|
3446
3697
|
let drafts = (allFindings ?? []).filter((f) => f.status === "draft");
|
|
@@ -3510,7 +3761,7 @@ When done=true, all findings have been processed.`,
|
|
|
3510
3761
|
if (args.skip && args.skipFindingId) {
|
|
3511
3762
|
try {
|
|
3512
3763
|
await ctx.client.mutation(
|
|
3513
|
-
|
|
3764
|
+
anyApi4.functions.localPipeline.releaseEnrichmentClaim,
|
|
3514
3765
|
{ findingId: args.skipFindingId }
|
|
3515
3766
|
);
|
|
3516
3767
|
updateSessionStats(args.sessionId, {
|
|
@@ -3520,7 +3771,7 @@ When done=true, all findings have been processed.`,
|
|
|
3520
3771
|
}
|
|
3521
3772
|
}
|
|
3522
3773
|
const allFindings = await ctx.client.query(
|
|
3523
|
-
|
|
3774
|
+
anyApi4.functions.findings.getProjectFindings,
|
|
3524
3775
|
{ projectId: session.projectId }
|
|
3525
3776
|
);
|
|
3526
3777
|
let drafts = (allFindings ?? []).filter(
|
|
@@ -3562,7 +3813,7 @@ When done=true, all findings have been processed.`,
|
|
|
3562
3813
|
}
|
|
3563
3814
|
const next = drafts[0];
|
|
3564
3815
|
const claimResult = await ctx.client.mutation(
|
|
3565
|
-
|
|
3816
|
+
anyApi4.functions.localPipeline.claimForEnrichment,
|
|
3566
3817
|
{ projectId: session.projectId, findingId: next._id }
|
|
3567
3818
|
);
|
|
3568
3819
|
if (!claimResult) {
|
|
@@ -3643,7 +3894,7 @@ The bundle and all its findings transition to "enriching" status.`,
|
|
|
3643
3894
|
async (args) => {
|
|
3644
3895
|
try {
|
|
3645
3896
|
const result = await ctx.client.mutation(
|
|
3646
|
-
|
|
3897
|
+
anyApi4.functions.bundles.claimBundleForEnrichment,
|
|
3647
3898
|
{ bundleId: args.bundleId }
|
|
3648
3899
|
);
|
|
3649
3900
|
if (!result) {
|
|
@@ -3702,7 +3953,7 @@ Call yapout_sync_bundle_to_linear afterwards to create the Linear project.`,
|
|
|
3702
3953
|
async (args) => {
|
|
3703
3954
|
try {
|
|
3704
3955
|
await ctx.client.mutation(
|
|
3705
|
-
|
|
3956
|
+
anyApi4.functions.bundles.saveBundleEnrichment,
|
|
3706
3957
|
{
|
|
3707
3958
|
bundleId: args.bundleId,
|
|
3708
3959
|
title: args.title,
|
|
@@ -3761,7 +4012,7 @@ Transitions: enriching \u2192 needs_input. The user sees the blockerReason and q
|
|
|
3761
4012
|
async (args) => {
|
|
3762
4013
|
try {
|
|
3763
4014
|
await ctx.client.mutation(
|
|
3764
|
-
|
|
4015
|
+
anyApi4.functions.localPipeline.blockLocalEnrichment,
|
|
3765
4016
|
{
|
|
3766
4017
|
findingId: args.findingId,
|
|
3767
4018
|
blockerReason: args.blockerReason,
|
|
@@ -3810,7 +4061,7 @@ Same semantics as yapout_block_enrichment but for an entire bundle. Bundle statu
|
|
|
3810
4061
|
async (args) => {
|
|
3811
4062
|
try {
|
|
3812
4063
|
await ctx.client.mutation(
|
|
3813
|
-
|
|
4064
|
+
anyApi4.functions.bundles.blockBundleEnrichment,
|
|
3814
4065
|
{
|
|
3815
4066
|
bundleId: args.bundleId,
|
|
3816
4067
|
blockerReason: args.blockerReason,
|
|
@@ -3878,7 +4129,7 @@ async function startMcpServer() {
|
|
|
3878
4129
|
};
|
|
3879
4130
|
const server = new McpServer({
|
|
3880
4131
|
name: "yapout",
|
|
3881
|
-
version: "0.
|
|
4132
|
+
version: "0.10.0"
|
|
3882
4133
|
});
|
|
3883
4134
|
registerInitTool(server, ctx);
|
|
3884
4135
|
registerCompactTool(server, ctx);
|
|
@@ -3910,40 +4161,40 @@ async function startMcpServer() {
|
|
|
3910
4161
|
}
|
|
3911
4162
|
|
|
3912
4163
|
// src/commands/mcp-server.ts
|
|
3913
|
-
var mcpServerCommand = new
|
|
4164
|
+
var mcpServerCommand = new Command8("mcp-server").description("Start the MCP server (used by Claude Code)").action(async () => {
|
|
3914
4165
|
await startMcpServer();
|
|
3915
4166
|
});
|
|
3916
4167
|
|
|
3917
4168
|
// src/commands/worktrees.ts
|
|
3918
|
-
import { Command as
|
|
3919
|
-
import
|
|
4169
|
+
import { Command as Command9 } from "commander";
|
|
4170
|
+
import chalk9 from "chalk";
|
|
3920
4171
|
import { resolve as resolve6 } from "path";
|
|
3921
|
-
var worktreesCommand = new
|
|
4172
|
+
var worktreesCommand = new Command9("worktrees").description("List active yapout worktrees").action(() => {
|
|
3922
4173
|
const cwd = resolve6(process.cwd());
|
|
3923
4174
|
const worktrees = listWorktrees(cwd);
|
|
3924
4175
|
if (worktrees.length === 0) {
|
|
3925
|
-
console.log(
|
|
4176
|
+
console.log(chalk9.dim("No active yapout worktrees."));
|
|
3926
4177
|
return;
|
|
3927
4178
|
}
|
|
3928
|
-
console.log(
|
|
4179
|
+
console.log(chalk9.bold("Active worktrees:\n"));
|
|
3929
4180
|
for (const wt of worktrees) {
|
|
3930
4181
|
console.log(
|
|
3931
|
-
` ${
|
|
4182
|
+
` ${chalk9.cyan(wt.path)} ${chalk9.green(wt.branch)}` + (wt.ticketId ? ` ${chalk9.dim(`(${wt.ticketId})`)}` : "")
|
|
3932
4183
|
);
|
|
3933
4184
|
}
|
|
3934
4185
|
console.log();
|
|
3935
4186
|
});
|
|
3936
4187
|
|
|
3937
4188
|
// src/commands/clean.ts
|
|
3938
|
-
import { Command as
|
|
3939
|
-
import
|
|
4189
|
+
import { Command as Command10 } from "commander";
|
|
4190
|
+
import chalk10 from "chalk";
|
|
3940
4191
|
import { resolve as resolve7 } from "path";
|
|
3941
|
-
var cleanCommand = new
|
|
4192
|
+
var cleanCommand = new Command10("clean").description("Remove worktrees for completed or failed tickets").action(async () => {
|
|
3942
4193
|
const creds = requireAuth();
|
|
3943
4194
|
const cwd = resolve7(process.cwd());
|
|
3944
4195
|
const worktrees = listWorktrees(cwd);
|
|
3945
4196
|
if (worktrees.length === 0) {
|
|
3946
|
-
console.log(
|
|
4197
|
+
console.log(chalk10.dim("No worktrees to clean."));
|
|
3947
4198
|
return;
|
|
3948
4199
|
}
|
|
3949
4200
|
const client = createConvexClient(creds.token);
|
|
@@ -3959,7 +4210,7 @@ var cleanCommand = new Command9("clean").description("Remove worktrees for compl
|
|
|
3959
4210
|
if (isStale) {
|
|
3960
4211
|
const label = ticket ? `${ticket.status}: ${ticket.title}` : "ticket not found";
|
|
3961
4212
|
console.log(
|
|
3962
|
-
|
|
4213
|
+
chalk10.dim(`Removing worktree for ${wt.ticketId} (${label})...`)
|
|
3963
4214
|
);
|
|
3964
4215
|
removeWorktree(cwd, wt.path);
|
|
3965
4216
|
cleaned++;
|
|
@@ -3968,10 +4219,10 @@ var cleanCommand = new Command9("clean").description("Remove worktrees for compl
|
|
|
3968
4219
|
}
|
|
3969
4220
|
}
|
|
3970
4221
|
if (cleaned === 0) {
|
|
3971
|
-
console.log(
|
|
4222
|
+
console.log(chalk10.dim("All worktrees are still active."));
|
|
3972
4223
|
} else {
|
|
3973
4224
|
console.log(
|
|
3974
|
-
|
|
4225
|
+
chalk10.green(
|
|
3975
4226
|
`Cleaned ${cleaned} worktree${cleaned === 1 ? "" : "s"}.`
|
|
3976
4227
|
)
|
|
3977
4228
|
);
|
|
@@ -3979,27 +4230,27 @@ var cleanCommand = new Command9("clean").description("Remove worktrees for compl
|
|
|
3979
4230
|
});
|
|
3980
4231
|
|
|
3981
4232
|
// src/commands/watch.ts
|
|
3982
|
-
import { Command as
|
|
4233
|
+
import { Command as Command11 } from "commander";
|
|
3983
4234
|
import { resolve as resolve8 } from "path";
|
|
3984
4235
|
import {
|
|
3985
|
-
readFileSync as
|
|
3986
|
-
writeFileSync as
|
|
3987
|
-
existsSync as
|
|
3988
|
-
unlinkSync as
|
|
4236
|
+
readFileSync as readFileSync7,
|
|
4237
|
+
writeFileSync as writeFileSync10,
|
|
4238
|
+
existsSync as existsSync11,
|
|
4239
|
+
unlinkSync as unlinkSync4
|
|
3989
4240
|
} from "fs";
|
|
3990
|
-
import { join as
|
|
3991
|
-
import
|
|
4241
|
+
import { join as join12 } from "path";
|
|
4242
|
+
import chalk12 from "chalk";
|
|
3992
4243
|
import { ConvexHttpClient as ConvexHttpClient3 } from "convex/browser";
|
|
3993
4244
|
|
|
3994
4245
|
// src/daemon/watcher.ts
|
|
3995
|
-
import { anyApi as
|
|
4246
|
+
import { anyApi as anyApi6 } from "convex/server";
|
|
3996
4247
|
import { execSync as execSync4 } from "child_process";
|
|
3997
|
-
import { existsSync as
|
|
3998
|
-
import { join as
|
|
4248
|
+
import { existsSync as existsSync10, mkdirSync as mkdirSync8 } from "fs";
|
|
4249
|
+
import { join as join11 } from "path";
|
|
3999
4250
|
import { hostname as osHostname } from "os";
|
|
4000
4251
|
|
|
4001
4252
|
// src/daemon/heartbeat.ts
|
|
4002
|
-
import { anyApi as
|
|
4253
|
+
import { anyApi as anyApi5 } from "convex/server";
|
|
4003
4254
|
var HEARTBEAT_INTERVAL = 3e4;
|
|
4004
4255
|
var Heartbeat = class {
|
|
4005
4256
|
client;
|
|
@@ -4027,14 +4278,14 @@ var Heartbeat = class {
|
|
|
4027
4278
|
if (currentTicketId) args.currentTicketId = currentTicketId;
|
|
4028
4279
|
if (currentBranch) args.currentBranch = currentBranch;
|
|
4029
4280
|
if (worktreePath) args.worktreePath = worktreePath;
|
|
4030
|
-
await this.client.mutation(
|
|
4281
|
+
await this.client.mutation(anyApi5.functions.agents.agentHeartbeat, args);
|
|
4031
4282
|
} catch {
|
|
4032
4283
|
}
|
|
4033
4284
|
}
|
|
4034
4285
|
};
|
|
4035
4286
|
|
|
4036
4287
|
// src/daemon/spawner.ts
|
|
4037
|
-
import { spawn } from "child_process";
|
|
4288
|
+
import { spawn as spawn2 } from "child_process";
|
|
4038
4289
|
|
|
4039
4290
|
// src/daemon/notifications.ts
|
|
4040
4291
|
var notifier = null;
|
|
@@ -4123,7 +4374,7 @@ var Spawner = class {
|
|
|
4123
4374
|
...process.env,
|
|
4124
4375
|
YAPOUT_PROJECT_ID: this.projectId
|
|
4125
4376
|
};
|
|
4126
|
-
const child =
|
|
4377
|
+
const child = spawn2("claude", ["--dangerously-skip-permissions", prompt], {
|
|
4127
4378
|
cwd: worktreePath,
|
|
4128
4379
|
stdio: ["pipe", "pipe", "pipe"],
|
|
4129
4380
|
env,
|
|
@@ -4235,7 +4486,7 @@ var Spawner = class {
|
|
|
4235
4486
|
};
|
|
4236
4487
|
|
|
4237
4488
|
// src/daemon/display.ts
|
|
4238
|
-
import
|
|
4489
|
+
import chalk11 from "chalk";
|
|
4239
4490
|
function formatElapsed(ms) {
|
|
4240
4491
|
const seconds = Math.floor(ms / 1e3);
|
|
4241
4492
|
if (seconds < 60) return `${seconds}s`;
|
|
@@ -4264,35 +4515,35 @@ function render(state) {
|
|
|
4264
4515
|
if (queuedCount > 0) statusParts.push(`${queuedCount} queued`);
|
|
4265
4516
|
const statusLine = statusParts.length > 0 ? statusParts.join(" | ") : "idle";
|
|
4266
4517
|
lines.push(
|
|
4267
|
-
`${
|
|
4518
|
+
`${chalk11.bold("yapout watch")} \u2014 ${state.projectName}`
|
|
4268
4519
|
);
|
|
4269
|
-
lines.push(`${
|
|
4520
|
+
lines.push(`${chalk11.green("Watching")} | ${statusLine}`);
|
|
4270
4521
|
lines.push("");
|
|
4271
4522
|
for (const agent of state.activeAgents) {
|
|
4272
4523
|
const elapsed = formatElapsed(now - agent.startedAt);
|
|
4273
|
-
const wt = agent.worktree ?
|
|
4524
|
+
const wt = agent.worktree ? chalk11.dim(`worktree/${agent.ticketRef.toLowerCase()}`) : "";
|
|
4274
4525
|
lines.push(
|
|
4275
|
-
` ${
|
|
4526
|
+
` ${chalk11.green("\u25CF")} ${chalk11.bold(agent.ticketRef)} ${chalk11.dim(truncate2(`"${agent.title}"`, 35))} ${chalk11.yellow(agent.phase)} ${wt} ${chalk11.dim(elapsed)}`
|
|
4276
4527
|
);
|
|
4277
4528
|
}
|
|
4278
4529
|
for (const ticket of state.queuedTickets) {
|
|
4279
4530
|
lines.push(
|
|
4280
|
-
` ${
|
|
4531
|
+
` ${chalk11.dim("\u25CB")} ${chalk11.bold(ticket.ticketRef)} ${chalk11.dim(truncate2(`"${ticket.title}"`, 35))} ${chalk11.dim("queued")}`
|
|
4281
4532
|
);
|
|
4282
4533
|
}
|
|
4283
4534
|
if (state.activeAgents.length > 0 || state.queuedTickets.length > 0) {
|
|
4284
4535
|
lines.push("");
|
|
4285
4536
|
}
|
|
4286
4537
|
if (state.recentEvents.length > 0) {
|
|
4287
|
-
lines.push(
|
|
4538
|
+
lines.push(chalk11.dim("Recent:"));
|
|
4288
4539
|
for (const event of state.recentEvents.slice(0, 8)) {
|
|
4289
4540
|
lines.push(
|
|
4290
|
-
` ${
|
|
4541
|
+
` ${chalk11.dim(formatTime(event.time))} ${event.icon} ${event.message}`
|
|
4291
4542
|
);
|
|
4292
4543
|
}
|
|
4293
4544
|
lines.push("");
|
|
4294
4545
|
}
|
|
4295
|
-
lines.push(
|
|
4546
|
+
lines.push(chalk11.dim("Ctrl+C to stop (agents will finish)"));
|
|
4296
4547
|
return lines.join("\n");
|
|
4297
4548
|
}
|
|
4298
4549
|
function clearAndRender(state) {
|
|
@@ -4334,7 +4585,7 @@ var Watcher = class {
|
|
|
4334
4585
|
);
|
|
4335
4586
|
process.exit(1);
|
|
4336
4587
|
}
|
|
4337
|
-
await this.client.mutation(
|
|
4588
|
+
await this.client.mutation(anyApi6.functions.agents.registerAgent, {
|
|
4338
4589
|
projectId: this.options.projectId,
|
|
4339
4590
|
sessionId: this.sessionId,
|
|
4340
4591
|
machineHostname: this.getHostname()
|
|
@@ -4370,7 +4621,7 @@ Waiting for ${this.spawner.activeCount} agent(s) to finish...`
|
|
|
4370
4621
|
await this.spawner.gracefulShutdown();
|
|
4371
4622
|
}
|
|
4372
4623
|
try {
|
|
4373
|
-
await this.client.mutation(
|
|
4624
|
+
await this.client.mutation(anyApi6.functions.agents.unregisterAgent, {
|
|
4374
4625
|
sessionId: this.sessionId
|
|
4375
4626
|
});
|
|
4376
4627
|
} catch {
|
|
@@ -4384,7 +4635,7 @@ Waiting for ${this.spawner.activeCount} agent(s) to finish...`
|
|
|
4384
4635
|
}
|
|
4385
4636
|
this.heartbeat.stop();
|
|
4386
4637
|
this.spawner.forceKill();
|
|
4387
|
-
this.client.mutation(
|
|
4638
|
+
this.client.mutation(anyApi6.functions.agents.unregisterAgent, {
|
|
4388
4639
|
sessionId: this.sessionId
|
|
4389
4640
|
}).catch(() => {
|
|
4390
4641
|
});
|
|
@@ -4426,7 +4677,7 @@ Waiting for ${this.spawner.activeCount} agent(s) to finish...`
|
|
|
4426
4677
|
}
|
|
4427
4678
|
async checkForEnrichmentWork(maxSlots) {
|
|
4428
4679
|
const tickets = await this.client.query(
|
|
4429
|
-
|
|
4680
|
+
anyApi6.functions.localPipeline.getUnenrichedTickets,
|
|
4430
4681
|
{ projectId: this.options.projectId }
|
|
4431
4682
|
);
|
|
4432
4683
|
if (!tickets || tickets.length === 0) return;
|
|
@@ -4455,7 +4706,7 @@ Waiting for ${this.spawner.activeCount} agent(s) to finish...`
|
|
|
4455
4706
|
}
|
|
4456
4707
|
async checkForImplementationWork(maxSlots) {
|
|
4457
4708
|
const data = await this.client.query(
|
|
4458
|
-
|
|
4709
|
+
anyApi6.functions.tickets.getLocalQueuedTickets,
|
|
4459
4710
|
{ projectId: this.options.projectId }
|
|
4460
4711
|
);
|
|
4461
4712
|
if (!data || data.ready.length === 0) return;
|
|
@@ -4487,10 +4738,10 @@ Waiting for ${this.spawner.activeCount} agent(s) to finish...`
|
|
|
4487
4738
|
}
|
|
4488
4739
|
ensureEnrichWorktree() {
|
|
4489
4740
|
const wtDir = getWorktreesDir(this.options.cwd);
|
|
4490
|
-
const enrichPath =
|
|
4491
|
-
if (
|
|
4741
|
+
const enrichPath = join11(wtDir, "_enrich");
|
|
4742
|
+
if (existsSync10(enrichPath)) return enrichPath;
|
|
4492
4743
|
try {
|
|
4493
|
-
if (!
|
|
4744
|
+
if (!existsSync10(wtDir)) mkdirSync8(wtDir, { recursive: true });
|
|
4494
4745
|
const defaultBranch = getDefaultBranch(this.options.cwd);
|
|
4495
4746
|
execSync4(
|
|
4496
4747
|
`git worktree add "${enrichPath}" origin/${defaultBranch}`,
|
|
@@ -4528,7 +4779,7 @@ Waiting for ${this.spawner.activeCount} agent(s) to finish...`
|
|
|
4528
4779
|
if (wt.ticketId) {
|
|
4529
4780
|
try {
|
|
4530
4781
|
const ticket = await this.client.query(
|
|
4531
|
-
|
|
4782
|
+
anyApi6.functions.tickets.getTicket,
|
|
4532
4783
|
{ ticketId: wt.ticketId }
|
|
4533
4784
|
);
|
|
4534
4785
|
if (ticket && (ticket.status === "failed" || ticket.status === "workflow2_done")) {
|
|
@@ -4593,38 +4844,38 @@ Waiting for ${this.spawner.activeCount} agent(s) to finish...`
|
|
|
4593
4844
|
};
|
|
4594
4845
|
|
|
4595
4846
|
// src/commands/watch.ts
|
|
4596
|
-
var
|
|
4597
|
-
var
|
|
4598
|
-
var watchCommand = new
|
|
4847
|
+
var PID_FILE2 = join12(getYapoutDir(), "watch.pid");
|
|
4848
|
+
var LOG_FILE2 = join12(getYapoutDir(), "watch.log");
|
|
4849
|
+
var watchCommand = new Command11("watch").description("Watch for work and spawn Claude Code agents").option("--bg", "Run in background (detached)").option("--stop", "Stop the background watcher").option("--status", "Check if watcher is running").option("--force", "Force kill on Ctrl+C (don't wait for agents)").action(async (opts) => {
|
|
4599
4850
|
if (opts.status) {
|
|
4600
|
-
if (
|
|
4601
|
-
const pid = parseInt(
|
|
4602
|
-
if (
|
|
4851
|
+
if (existsSync11(PID_FILE2)) {
|
|
4852
|
+
const pid = parseInt(readFileSync7(PID_FILE2, "utf-8").trim(), 10);
|
|
4853
|
+
if (isProcessRunning2(pid)) {
|
|
4603
4854
|
console.log(
|
|
4604
|
-
|
|
4855
|
+
chalk12.green("Watcher is running") + chalk12.dim(` (PID ${pid})`)
|
|
4605
4856
|
);
|
|
4606
4857
|
} else {
|
|
4607
|
-
console.log(
|
|
4608
|
-
|
|
4858
|
+
console.log(chalk12.dim("Watcher is not running (stale PID file)"));
|
|
4859
|
+
unlinkSync4(PID_FILE2);
|
|
4609
4860
|
}
|
|
4610
4861
|
} else {
|
|
4611
|
-
console.log(
|
|
4862
|
+
console.log(chalk12.dim("Watcher is not running"));
|
|
4612
4863
|
}
|
|
4613
4864
|
return;
|
|
4614
4865
|
}
|
|
4615
4866
|
if (opts.stop) {
|
|
4616
|
-
if (!
|
|
4617
|
-
console.log(
|
|
4867
|
+
if (!existsSync11(PID_FILE2)) {
|
|
4868
|
+
console.log(chalk12.dim("No watcher running"));
|
|
4618
4869
|
return;
|
|
4619
4870
|
}
|
|
4620
|
-
const pid = parseInt(
|
|
4871
|
+
const pid = parseInt(readFileSync7(PID_FILE2, "utf-8").trim(), 10);
|
|
4621
4872
|
try {
|
|
4622
4873
|
process.kill(pid, "SIGTERM");
|
|
4623
|
-
console.log(
|
|
4874
|
+
console.log(chalk12.green(`Stopped watcher (PID ${pid})`));
|
|
4624
4875
|
} catch {
|
|
4625
|
-
console.log(
|
|
4876
|
+
console.log(chalk12.dim("Watcher already stopped"));
|
|
4626
4877
|
}
|
|
4627
|
-
|
|
4878
|
+
unlinkSync4(PID_FILE2);
|
|
4628
4879
|
return;
|
|
4629
4880
|
}
|
|
4630
4881
|
const creds = requireAuth();
|
|
@@ -4632,7 +4883,7 @@ var watchCommand = new Command10("watch").description("Watch for work and spawn
|
|
|
4632
4883
|
const mapping = getProjectMapping(cwd);
|
|
4633
4884
|
if (!mapping) {
|
|
4634
4885
|
console.error(
|
|
4635
|
-
|
|
4886
|
+
chalk12.red("No project linked.") + " Run " + chalk12.cyan("yapout link") + " in a repo."
|
|
4636
4887
|
);
|
|
4637
4888
|
process.exit(1);
|
|
4638
4889
|
}
|
|
@@ -4640,16 +4891,16 @@ var watchCommand = new Command10("watch").description("Watch for work and spawn
|
|
|
4640
4891
|
const client = new ConvexHttpClient3(getConvexUrl());
|
|
4641
4892
|
client.setAuth(creds.token);
|
|
4642
4893
|
if (opts.bg) {
|
|
4643
|
-
|
|
4894
|
+
writeFileSync10(PID_FILE2, process.pid.toString());
|
|
4644
4895
|
console.log(
|
|
4645
|
-
|
|
4896
|
+
chalk12.green("Watcher started in background") + chalk12.dim(` (PID ${process.pid}, log: ${LOG_FILE2})`)
|
|
4646
4897
|
);
|
|
4647
4898
|
}
|
|
4648
|
-
console.log(
|
|
4899
|
+
console.log(chalk12.bold(`yapout watch v${"0.10.0"}`));
|
|
4649
4900
|
console.log(
|
|
4650
|
-
`Project: ${
|
|
4901
|
+
`Project: ${chalk12.green(mapping.projectName)} (${mapping.projectId})`
|
|
4651
4902
|
);
|
|
4652
|
-
console.log(
|
|
4903
|
+
console.log(chalk12.dim("Watching..."));
|
|
4653
4904
|
console.log();
|
|
4654
4905
|
const watcher = new Watcher(
|
|
4655
4906
|
{
|
|
@@ -4666,17 +4917,17 @@ var watchCommand = new Command10("watch").description("Watch for work and spawn
|
|
|
4666
4917
|
const shutdown = async () => {
|
|
4667
4918
|
if (shuttingDown) {
|
|
4668
4919
|
watcher.forceStop();
|
|
4669
|
-
if (
|
|
4920
|
+
if (existsSync11(PID_FILE2)) unlinkSync4(PID_FILE2);
|
|
4670
4921
|
process.exit(0);
|
|
4671
4922
|
}
|
|
4672
4923
|
shuttingDown = true;
|
|
4673
|
-
console.log(
|
|
4924
|
+
console.log(chalk12.dim("\nShutting down..."));
|
|
4674
4925
|
if (opts.force) {
|
|
4675
4926
|
watcher.forceStop();
|
|
4676
4927
|
} else {
|
|
4677
4928
|
await watcher.stop();
|
|
4678
4929
|
}
|
|
4679
|
-
if (
|
|
4930
|
+
if (existsSync11(PID_FILE2)) unlinkSync4(PID_FILE2);
|
|
4680
4931
|
process.exit(0);
|
|
4681
4932
|
};
|
|
4682
4933
|
process.on("SIGINT", () => {
|
|
@@ -4689,7 +4940,7 @@ var watchCommand = new Command10("watch").description("Watch for work and spawn
|
|
|
4689
4940
|
await new Promise(() => {
|
|
4690
4941
|
});
|
|
4691
4942
|
});
|
|
4692
|
-
function
|
|
4943
|
+
function isProcessRunning2(pid) {
|
|
4693
4944
|
try {
|
|
4694
4945
|
process.kill(pid, 0);
|
|
4695
4946
|
return true;
|
|
@@ -4699,88 +4950,88 @@ function isProcessRunning(pid) {
|
|
|
4699
4950
|
}
|
|
4700
4951
|
|
|
4701
4952
|
// src/commands/queue.ts
|
|
4702
|
-
import { Command as
|
|
4953
|
+
import { Command as Command12 } from "commander";
|
|
4703
4954
|
import { resolve as resolve9 } from "path";
|
|
4704
|
-
import
|
|
4705
|
-
var queueCommand = new
|
|
4955
|
+
import chalk13 from "chalk";
|
|
4956
|
+
var queueCommand = new Command12("queue").description("Show pipeline state \u2014 what's ready, blocked, and pending").action(async () => {
|
|
4706
4957
|
const creds = requireAuth();
|
|
4707
4958
|
const cwd = resolve9(process.cwd());
|
|
4708
4959
|
const mapping = getProjectMapping(cwd);
|
|
4709
4960
|
if (!mapping) {
|
|
4710
4961
|
console.error(
|
|
4711
|
-
|
|
4962
|
+
chalk13.red("No project linked.") + " Run " + chalk13.cyan("yapout link") + " in a repo."
|
|
4712
4963
|
);
|
|
4713
4964
|
process.exit(1);
|
|
4714
4965
|
}
|
|
4715
4966
|
const client = createConvexClient(creds.token);
|
|
4716
|
-
const { anyApi:
|
|
4967
|
+
const { anyApi: anyApi7 } = await import("convex/server");
|
|
4717
4968
|
const [queueData, unenriched, pending] = await Promise.all([
|
|
4718
|
-
client.query(
|
|
4969
|
+
client.query(anyApi7.functions.tickets.getLocalQueuedTickets, {
|
|
4719
4970
|
projectId: mapping.projectId
|
|
4720
4971
|
}),
|
|
4721
|
-
client.query(
|
|
4972
|
+
client.query(anyApi7.functions.localPipeline.getUnenrichedTickets, {
|
|
4722
4973
|
projectId: mapping.projectId
|
|
4723
4974
|
}),
|
|
4724
|
-
client.query(
|
|
4975
|
+
client.query(anyApi7.functions.localPipeline.getPendingSources, {
|
|
4725
4976
|
projectId: mapping.projectId
|
|
4726
4977
|
})
|
|
4727
4978
|
]);
|
|
4728
4979
|
console.log();
|
|
4729
4980
|
if (queueData?.ready && queueData.ready.length > 0) {
|
|
4730
|
-
console.log(
|
|
4981
|
+
console.log(chalk13.bold("Ready to implement:"));
|
|
4731
4982
|
for (const t of queueData.ready) {
|
|
4732
4983
|
const ref = t.linearTicketId ?? t.ticketId;
|
|
4733
4984
|
const prio = colorPriority(t.priority);
|
|
4734
4985
|
console.log(
|
|
4735
|
-
` ${
|
|
4986
|
+
` ${chalk13.bold(ref)} ${t.title.slice(0, 45).padEnd(45)} ${prio} ${chalk13.dim(t.type)}`
|
|
4736
4987
|
);
|
|
4737
4988
|
}
|
|
4738
4989
|
console.log();
|
|
4739
4990
|
}
|
|
4740
4991
|
if (queueData?.blocked && queueData.blocked.length > 0) {
|
|
4741
|
-
console.log(
|
|
4992
|
+
console.log(chalk13.bold("Blocked:"));
|
|
4742
4993
|
for (const t of queueData.blocked) {
|
|
4743
4994
|
console.log(
|
|
4744
|
-
` ${
|
|
4995
|
+
` ${chalk13.bold(t.ticketId.slice(-6))} ${t.title.slice(0, 45)} ${chalk13.red("blocked by " + t.blockedBy.map((id) => id.slice(-6)).join(", "))}`
|
|
4745
4996
|
);
|
|
4746
4997
|
}
|
|
4747
4998
|
console.log();
|
|
4748
4999
|
}
|
|
4749
5000
|
if (unenriched && unenriched.length > 0) {
|
|
4750
|
-
console.log(
|
|
5001
|
+
console.log(chalk13.bold("Needs enrichment:"));
|
|
4751
5002
|
for (const t of unenriched) {
|
|
4752
5003
|
const ref = t.ticketId;
|
|
4753
5004
|
console.log(
|
|
4754
|
-
` ${
|
|
5005
|
+
` ${chalk13.bold(ref.slice(-6))} ${t.title.slice(0, 45).padEnd(45)} ${chalk13.dim(t.priority)}`
|
|
4755
5006
|
);
|
|
4756
5007
|
}
|
|
4757
5008
|
console.log();
|
|
4758
5009
|
}
|
|
4759
5010
|
if (pending && pending.length > 0) {
|
|
4760
|
-
console.log(
|
|
5011
|
+
console.log(chalk13.bold("Pending extraction:"));
|
|
4761
5012
|
for (const t of pending) {
|
|
4762
5013
|
const ago = formatAgo(Date.now() - t.createdAt);
|
|
4763
5014
|
console.log(
|
|
4764
|
-
` "${t.meetingTitle ?? "Untitled"}" ${
|
|
5015
|
+
` "${t.meetingTitle ?? "Untitled"}" ${chalk13.dim(`(uploaded ${ago})`)}`
|
|
4765
5016
|
);
|
|
4766
5017
|
}
|
|
4767
5018
|
console.log();
|
|
4768
5019
|
}
|
|
4769
5020
|
if ((!queueData?.ready || queueData.ready.length === 0) && (!unenriched || unenriched.length === 0) && (!pending || pending.length === 0)) {
|
|
4770
|
-
console.log(
|
|
5021
|
+
console.log(chalk13.dim("Queue is empty. Upload a transcript to get started."));
|
|
4771
5022
|
console.log();
|
|
4772
5023
|
}
|
|
4773
5024
|
});
|
|
4774
5025
|
function colorPriority(p) {
|
|
4775
5026
|
switch (p) {
|
|
4776
5027
|
case "urgent":
|
|
4777
|
-
return
|
|
5028
|
+
return chalk13.red(p);
|
|
4778
5029
|
case "high":
|
|
4779
|
-
return
|
|
5030
|
+
return chalk13.yellow(p);
|
|
4780
5031
|
case "medium":
|
|
4781
|
-
return
|
|
5032
|
+
return chalk13.white(p);
|
|
4782
5033
|
case "low":
|
|
4783
|
-
return
|
|
5034
|
+
return chalk13.dim(p);
|
|
4784
5035
|
default:
|
|
4785
5036
|
return p;
|
|
4786
5037
|
}
|
|
@@ -4796,29 +5047,29 @@ function formatAgo(ms) {
|
|
|
4796
5047
|
}
|
|
4797
5048
|
|
|
4798
5049
|
// src/commands/next.ts
|
|
4799
|
-
import { Command as
|
|
5050
|
+
import { Command as Command13 } from "commander";
|
|
4800
5051
|
import { resolve as resolve10 } from "path";
|
|
4801
|
-
import { writeFileSync as
|
|
4802
|
-
import { join as
|
|
4803
|
-
import
|
|
4804
|
-
var nextCommand = new
|
|
5052
|
+
import { writeFileSync as writeFileSync11 } from "fs";
|
|
5053
|
+
import { join as join13 } from "path";
|
|
5054
|
+
import chalk14 from "chalk";
|
|
5055
|
+
var nextCommand = new Command13("next").description("Claim the highest priority ticket and set up for implementation").option("--worktree", "Create a git worktree instead of checking out a branch").action(async (opts) => {
|
|
4805
5056
|
const creds = requireAuth();
|
|
4806
5057
|
const cwd = resolve10(process.cwd());
|
|
4807
5058
|
const mapping = getProjectMapping(cwd);
|
|
4808
5059
|
if (!mapping) {
|
|
4809
5060
|
console.error(
|
|
4810
|
-
|
|
5061
|
+
chalk14.red("No project linked.") + " Run " + chalk14.cyan("yapout link") + " in a repo."
|
|
4811
5062
|
);
|
|
4812
5063
|
process.exit(1);
|
|
4813
5064
|
}
|
|
4814
5065
|
const client = createConvexClient(creds.token);
|
|
4815
|
-
const { anyApi:
|
|
5066
|
+
const { anyApi: anyApi7 } = await import("convex/server");
|
|
4816
5067
|
const data = await client.query(
|
|
4817
|
-
|
|
5068
|
+
anyApi7.functions.tickets.getLocalQueuedTickets,
|
|
4818
5069
|
{ projectId: mapping.projectId }
|
|
4819
5070
|
);
|
|
4820
5071
|
if (!data?.ready || data.ready.length === 0) {
|
|
4821
|
-
console.log(
|
|
5072
|
+
console.log(chalk14.dim("No tickets ready for implementation."));
|
|
4822
5073
|
return;
|
|
4823
5074
|
}
|
|
4824
5075
|
const ticket = data.ready[0];
|
|
@@ -4826,32 +5077,32 @@ var nextCommand = new Command12("next").description("Claim the highest priority
|
|
|
4826
5077
|
const config = readYapoutConfig(cwd);
|
|
4827
5078
|
const defaultBranch = getDefaultBranch(cwd);
|
|
4828
5079
|
const branchName = `${config.branch_prefix}/${ref.toLowerCase().replace(/\s+/g, "-")}-${ticket.title.toLowerCase().replace(/[^a-z0-9]+/g, "-").slice(0, 40)}`;
|
|
4829
|
-
console.log(
|
|
5080
|
+
console.log(chalk14.bold(`
|
|
4830
5081
|
Claimed: ${ref} "${ticket.title}"`));
|
|
4831
5082
|
fetchOrigin(cwd);
|
|
4832
5083
|
let workDir = cwd;
|
|
4833
5084
|
if (opts.worktree) {
|
|
4834
5085
|
const { createWorktree: createWorktree2 } = await import("./worktree-ZZZIL7TK.js");
|
|
4835
5086
|
workDir = createWorktree2(cwd, ticket.ticketId, branchName, defaultBranch);
|
|
4836
|
-
console.log(`Worktree: ${
|
|
5087
|
+
console.log(`Worktree: ${chalk14.cyan(workDir)}`);
|
|
4837
5088
|
} else {
|
|
4838
5089
|
checkoutNewBranch(branchName, defaultBranch, cwd);
|
|
4839
5090
|
}
|
|
4840
|
-
console.log(`Branch: ${
|
|
5091
|
+
console.log(`Branch: ${chalk14.cyan(branchName)}`);
|
|
4841
5092
|
const brief = await client.query(
|
|
4842
|
-
|
|
5093
|
+
anyApi7.functions.tickets.getTicketBrief,
|
|
4843
5094
|
{ ticketId: ticket.ticketId }
|
|
4844
5095
|
);
|
|
4845
5096
|
if (brief) {
|
|
4846
|
-
const briefPath =
|
|
5097
|
+
const briefPath = join13(workDir, ".yapout", "brief.md");
|
|
4847
5098
|
const briefContent = formatBrief(ref, ticket, brief);
|
|
4848
|
-
|
|
4849
|
-
console.log(`Brief: ${
|
|
5099
|
+
writeFileSync11(briefPath, briefContent);
|
|
5100
|
+
console.log(`Brief: ${chalk14.cyan(briefPath)}`);
|
|
4850
5101
|
}
|
|
4851
5102
|
console.log();
|
|
4852
5103
|
console.log("Start Claude Code to implement, or run:");
|
|
4853
5104
|
console.log(
|
|
4854
|
-
|
|
5105
|
+
chalk14.cyan(
|
|
4855
5106
|
` claude --dangerously-skip-permissions "Read .yapout/brief.md, implement it, run yapout_check, then yapout_ship"`
|
|
4856
5107
|
)
|
|
4857
5108
|
);
|
|
@@ -4901,21 +5152,21 @@ function formatBrief(ref, ticket, brief) {
|
|
|
4901
5152
|
}
|
|
4902
5153
|
|
|
4903
5154
|
// src/commands/recap.ts
|
|
4904
|
-
import { Command as
|
|
5155
|
+
import { Command as Command14 } from "commander";
|
|
4905
5156
|
import { resolve as resolve11 } from "path";
|
|
4906
|
-
import
|
|
4907
|
-
var recapCommand = new
|
|
5157
|
+
import chalk15 from "chalk";
|
|
5158
|
+
var recapCommand = new Command14("recap").description("Show a summary of recent yapout activity").option("--week", "Show full week summary (default: today)").action(async (opts) => {
|
|
4908
5159
|
const creds = requireAuth();
|
|
4909
5160
|
const cwd = resolve11(process.cwd());
|
|
4910
5161
|
const mapping = getProjectMapping(cwd);
|
|
4911
5162
|
if (!mapping) {
|
|
4912
5163
|
console.error(
|
|
4913
|
-
|
|
5164
|
+
chalk15.red("No project linked.") + " Run " + chalk15.cyan("yapout link") + " in a repo."
|
|
4914
5165
|
);
|
|
4915
5166
|
process.exit(1);
|
|
4916
5167
|
}
|
|
4917
5168
|
const client = createConvexClient(creds.token);
|
|
4918
|
-
const { anyApi:
|
|
5169
|
+
const { anyApi: anyApi7 } = await import("convex/server");
|
|
4919
5170
|
const now = /* @__PURE__ */ new Date();
|
|
4920
5171
|
const todayStart = new Date(
|
|
4921
5172
|
now.getFullYear(),
|
|
@@ -4925,33 +5176,33 @@ var recapCommand = new Command13("recap").description("Show a summary of recent
|
|
|
4925
5176
|
const weekStart = todayStart - 6 * 24 * 60 * 60 * 1e3;
|
|
4926
5177
|
const since = opts.week ? weekStart : todayStart;
|
|
4927
5178
|
const data = await client.query(
|
|
4928
|
-
|
|
5179
|
+
anyApi7.functions.localPipeline.getRecentActivity,
|
|
4929
5180
|
{ projectId: mapping.projectId, since }
|
|
4930
5181
|
);
|
|
4931
5182
|
if (!data) {
|
|
4932
|
-
console.log(
|
|
5183
|
+
console.log(chalk15.dim("Could not fetch activity data."));
|
|
4933
5184
|
return;
|
|
4934
5185
|
}
|
|
4935
5186
|
const period = opts.week ? "This week" : "Today";
|
|
4936
5187
|
console.log();
|
|
4937
|
-
console.log(
|
|
5188
|
+
console.log(chalk15.bold(`${period}:`));
|
|
4938
5189
|
if (data.recentTickets.length > 0) {
|
|
4939
5190
|
for (const t of data.recentTickets) {
|
|
4940
5191
|
const ref = t.linearTicketId ?? "ticket";
|
|
4941
|
-
console.log(` ${
|
|
5192
|
+
console.log(` ${chalk15.green("\u2713")} ${ref} ${t.title}`);
|
|
4942
5193
|
}
|
|
4943
5194
|
}
|
|
4944
5195
|
if (data.recentPRs.length > 0) {
|
|
4945
5196
|
for (const p of data.recentPRs) {
|
|
4946
5197
|
const prRef = p.githubPrNumber ? `PR #${p.githubPrNumber}` : "PR";
|
|
4947
|
-
const statusColor = p.status === "opened" ?
|
|
5198
|
+
const statusColor = p.status === "opened" ? chalk15.green : p.status === "draft" ? chalk15.dim : chalk15.yellow;
|
|
4948
5199
|
console.log(
|
|
4949
5200
|
` ${statusColor("\u2191")} ${p.prTitle.slice(0, 45)} ${statusColor(prRef)} ${statusColor(p.status)}`
|
|
4950
5201
|
);
|
|
4951
5202
|
}
|
|
4952
5203
|
}
|
|
4953
5204
|
if (data.recentTickets.length === 0 && data.recentPRs.length === 0) {
|
|
4954
|
-
console.log(
|
|
5205
|
+
console.log(chalk15.dim(" No activity yet."));
|
|
4955
5206
|
}
|
|
4956
5207
|
console.log();
|
|
4957
5208
|
console.log(
|
|
@@ -4961,12 +5212,12 @@ var recapCommand = new Command13("recap").description("Show a summary of recent
|
|
|
4961
5212
|
});
|
|
4962
5213
|
|
|
4963
5214
|
// src/commands/yap.ts
|
|
4964
|
-
import { Command as
|
|
4965
|
-
import
|
|
4966
|
-
var yapCommand = new
|
|
5215
|
+
import { Command as Command15 } from "commander";
|
|
5216
|
+
import chalk16 from "chalk";
|
|
5217
|
+
var yapCommand = new Command15("yap").description(
|
|
4967
5218
|
"Start a yap session \u2014 brainstorm with an AI that knows your codebase"
|
|
4968
5219
|
).action(() => {
|
|
4969
|
-
console.log(
|
|
5220
|
+
console.log(chalk16.bold("yapout yap sessions"));
|
|
4970
5221
|
console.log();
|
|
4971
5222
|
console.log(
|
|
4972
5223
|
"Yap sessions run inside Claude \u2014 Desktop, CLI, or web \u2014 anywhere the"
|
|
@@ -4975,27 +5226,27 @@ var yapCommand = new Command14("yap").description(
|
|
|
4975
5226
|
console.log();
|
|
4976
5227
|
console.log("Just tell Claude:");
|
|
4977
5228
|
console.log(
|
|
4978
|
-
|
|
5229
|
+
chalk16.green(` "Let's have a yap session about [topic]"`)
|
|
4979
5230
|
);
|
|
4980
5231
|
console.log(
|
|
4981
|
-
|
|
5232
|
+
chalk16.green(
|
|
4982
5233
|
' "I want to brainstorm [idea] \u2014 be a skeptical QA engineer"'
|
|
4983
5234
|
)
|
|
4984
5235
|
);
|
|
4985
5236
|
console.log();
|
|
4986
|
-
console.log(
|
|
5237
|
+
console.log(chalk16.dim("Personas: tech lead, qa engineer, product owner, end user, or custom"));
|
|
4987
5238
|
console.log(
|
|
4988
|
-
|
|
5239
|
+
chalk16.dim(
|
|
4989
5240
|
"Claude will call yapout_start_yap to get instructions and yapout_submit_yap_session when done."
|
|
4990
5241
|
)
|
|
4991
5242
|
);
|
|
4992
5243
|
});
|
|
4993
5244
|
|
|
4994
5245
|
// src/commands/handle-uri.ts
|
|
4995
|
-
import { Command as
|
|
4996
|
-
import { spawn as
|
|
4997
|
-
import { platform as
|
|
4998
|
-
import
|
|
5246
|
+
import { Command as Command16 } from "commander";
|
|
5247
|
+
import { spawn as spawn3 } from "child_process";
|
|
5248
|
+
import { platform as platform3 } from "os";
|
|
5249
|
+
import chalk17 from "chalk";
|
|
4999
5250
|
var VALID_ACTIONS = ["claim", "enrich", "enrich-bulk", "enrich-bundle", "yap", "compact"];
|
|
5000
5251
|
function parseYapoutUri(raw) {
|
|
5001
5252
|
const url = new URL(raw);
|
|
@@ -5108,11 +5359,11 @@ function findProjectDir() {
|
|
|
5108
5359
|
return dirs[0];
|
|
5109
5360
|
}
|
|
5110
5361
|
function launchTerminal(cwd, claudeArgs) {
|
|
5111
|
-
const os =
|
|
5362
|
+
const os = platform3();
|
|
5112
5363
|
const claudeCmd = `claude ${claudeArgs.map(shellEscape).join(" ")}`;
|
|
5113
5364
|
if (os === "win32") {
|
|
5114
5365
|
const wtArgs = ["wt", "-d", cwd, "cmd", "/k", claudeCmd];
|
|
5115
|
-
const child =
|
|
5366
|
+
const child = spawn3("cmd", ["/c", "start", ...wtArgs], {
|
|
5116
5367
|
cwd,
|
|
5117
5368
|
stdio: "ignore",
|
|
5118
5369
|
detached: true,
|
|
@@ -5120,7 +5371,7 @@ function launchTerminal(cwd, claudeArgs) {
|
|
|
5120
5371
|
});
|
|
5121
5372
|
child.unref();
|
|
5122
5373
|
child.on("error", () => {
|
|
5123
|
-
const fallback =
|
|
5374
|
+
const fallback = spawn3(
|
|
5124
5375
|
"cmd",
|
|
5125
5376
|
["/c", "start", "cmd", "/k", claudeCmd],
|
|
5126
5377
|
{ cwd, stdio: "ignore", detached: true, shell: true }
|
|
@@ -5133,7 +5384,7 @@ function launchTerminal(cwd, claudeArgs) {
|
|
|
5133
5384
|
activate
|
|
5134
5385
|
do script "cd ${shellEscape(cwd)} && ${escaped}"
|
|
5135
5386
|
end tell`;
|
|
5136
|
-
const child =
|
|
5387
|
+
const child = spawn3("osascript", ["-e", script], {
|
|
5137
5388
|
stdio: "ignore",
|
|
5138
5389
|
detached: true
|
|
5139
5390
|
});
|
|
@@ -5148,7 +5399,7 @@ end tell`;
|
|
|
5148
5399
|
let launched = false;
|
|
5149
5400
|
for (const term of terminals) {
|
|
5150
5401
|
try {
|
|
5151
|
-
const child =
|
|
5402
|
+
const child = spawn3(term.cmd, term.args, {
|
|
5152
5403
|
stdio: "ignore",
|
|
5153
5404
|
detached: true
|
|
5154
5405
|
});
|
|
@@ -5161,44 +5412,44 @@ end tell`;
|
|
|
5161
5412
|
}
|
|
5162
5413
|
if (!launched) {
|
|
5163
5414
|
console.error(
|
|
5164
|
-
|
|
5415
|
+
chalk17.red("Could not find a terminal emulator. Install gnome-terminal, konsole, or xterm.")
|
|
5165
5416
|
);
|
|
5166
5417
|
process.exit(1);
|
|
5167
5418
|
}
|
|
5168
5419
|
}
|
|
5169
5420
|
}
|
|
5170
5421
|
function shellEscape(s) {
|
|
5171
|
-
if (
|
|
5422
|
+
if (platform3() === "win32") {
|
|
5172
5423
|
return `"${s.replace(/"/g, '""')}"`;
|
|
5173
5424
|
}
|
|
5174
5425
|
return `'${s.replace(/'/g, "'\\''")}'`;
|
|
5175
5426
|
}
|
|
5176
|
-
var handleUriCommand = new
|
|
5427
|
+
var handleUriCommand = new Command16("handle-uri").description("Handle a yapout:// URI (used by OS protocol handler)").argument("<uri>", "The yapout:// URI to handle").action(async (uri) => {
|
|
5177
5428
|
try {
|
|
5178
5429
|
const parsed = parseYapoutUri(uri);
|
|
5179
5430
|
const prompt = buildPrompt(parsed);
|
|
5180
5431
|
const cwd = findProjectDir();
|
|
5181
5432
|
if (!cwd) {
|
|
5182
5433
|
console.error(
|
|
5183
|
-
|
|
5434
|
+
chalk17.red(
|
|
5184
5435
|
"No linked project found. Run `yapout init` or `yapout link` in your repo first."
|
|
5185
5436
|
)
|
|
5186
5437
|
);
|
|
5187
5438
|
process.exit(1);
|
|
5188
5439
|
}
|
|
5189
5440
|
const label = parsed.ticketId ? `${parsed.action} ${parsed.ticketId}` : parsed.action;
|
|
5190
|
-
console.log(
|
|
5441
|
+
console.log(chalk17.dim(`Launching Claude Code to ${label}...`));
|
|
5191
5442
|
launchTerminal(cwd, ["--dangerously-skip-permissions", prompt]);
|
|
5192
5443
|
setTimeout(() => process.exit(0), 500);
|
|
5193
5444
|
} catch (err) {
|
|
5194
|
-
console.error(
|
|
5445
|
+
console.error(chalk17.red(err.message));
|
|
5195
5446
|
process.exit(1);
|
|
5196
5447
|
}
|
|
5197
5448
|
});
|
|
5198
5449
|
|
|
5199
5450
|
// src/index.ts
|
|
5200
|
-
var program = new
|
|
5201
|
-
program.name("yapout").description("yapout \u2014 from meeting transcript to merged PR").version("0.
|
|
5451
|
+
var program = new Command17();
|
|
5452
|
+
program.name("yapout").description("yapout \u2014 from meeting transcript to merged PR").version("0.10.0");
|
|
5202
5453
|
program.addCommand(loginCommand);
|
|
5203
5454
|
program.addCommand(logoutCommand);
|
|
5204
5455
|
program.addCommand(initCommand);
|
|
@@ -5214,4 +5465,5 @@ program.addCommand(nextCommand);
|
|
|
5214
5465
|
program.addCommand(recapCommand);
|
|
5215
5466
|
program.addCommand(yapCommand);
|
|
5216
5467
|
program.addCommand(handleUriCommand);
|
|
5468
|
+
program.addCommand(serveCommand);
|
|
5217
5469
|
program.parse();
|