yapout 0.8.0 → 0.9.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 +599 -353
- 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.9.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.9.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,14 @@ 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
859
|
const authUrl = `${appUrl}/auth/cli?port=${port}`;
|
|
601
|
-
console.log(
|
|
860
|
+
console.log(chalk3.dim(`Opening browser...`));
|
|
602
861
|
await open(authUrl);
|
|
603
|
-
console.log(
|
|
862
|
+
console.log(chalk3.dim("Waiting for authentication in browser..."));
|
|
604
863
|
try {
|
|
605
864
|
const result = await data;
|
|
606
865
|
const creds = {
|
|
@@ -615,74 +874,60 @@ var loginCommand = new Command("login").description("Authenticate with yapout").
|
|
|
615
874
|
Math.round((result.expiresAt - Date.now()) / 864e5)
|
|
616
875
|
);
|
|
617
876
|
console.log(
|
|
618
|
-
|
|
877
|
+
chalk3.green("Logged in as ") + chalk3.bold(result.email) + chalk3.dim(
|
|
619
878
|
` (expires in ${daysLeft} day${daysLeft === 1 ? "" : "s"})`
|
|
620
879
|
)
|
|
621
880
|
);
|
|
622
881
|
try {
|
|
623
882
|
const client = createConvexClient(creds.token);
|
|
624
|
-
const deviceId =
|
|
625
|
-
await client.mutation(
|
|
883
|
+
const deviceId = createHash2("sha256").update(hostname2() + userInfo2().username).digest("hex").slice(0, 16);
|
|
884
|
+
await client.mutation(anyApi3.functions.devices.registerDevice, {
|
|
626
885
|
deviceId,
|
|
627
|
-
name:
|
|
628
|
-
cliVersion:
|
|
886
|
+
name: hostname2(),
|
|
887
|
+
cliVersion: CLI_VERSION2
|
|
629
888
|
});
|
|
630
889
|
} catch {
|
|
631
|
-
console.warn(
|
|
890
|
+
console.warn(chalk3.dim("Note: Could not register device. This is non-fatal."));
|
|
632
891
|
}
|
|
633
892
|
try {
|
|
634
893
|
registerProtocolHandler();
|
|
635
894
|
console.log(
|
|
636
|
-
|
|
895
|
+
chalk3.dim("Registered yapout:// protocol handler")
|
|
637
896
|
);
|
|
638
897
|
} catch {
|
|
639
898
|
}
|
|
899
|
+
try {
|
|
900
|
+
spawnServeDaemon(process.argv[1]);
|
|
901
|
+
console.log(chalk3.dim("Started yapout serve in the background"));
|
|
902
|
+
} catch {
|
|
903
|
+
}
|
|
640
904
|
process.exit(0);
|
|
641
905
|
} catch (err) {
|
|
642
|
-
console.error(
|
|
906
|
+
console.error(chalk3.red(err.message));
|
|
643
907
|
process.exit(1);
|
|
644
908
|
}
|
|
645
909
|
});
|
|
646
910
|
|
|
647
911
|
// src/commands/logout.ts
|
|
648
|
-
import { Command as
|
|
649
|
-
import
|
|
650
|
-
var logoutCommand = new
|
|
912
|
+
import { Command as Command3 } from "commander";
|
|
913
|
+
import chalk4 from "chalk";
|
|
914
|
+
var logoutCommand = new Command3("logout").description("Log out of yapout").action(() => {
|
|
651
915
|
deleteCredentials();
|
|
652
|
-
console.log(
|
|
916
|
+
console.log(chalk4.green("Logged out."));
|
|
653
917
|
});
|
|
654
918
|
|
|
655
919
|
// src/commands/link.ts
|
|
656
|
-
import { Command as
|
|
657
|
-
import { resolve as resolve2, join as
|
|
920
|
+
import { Command as Command4 } from "commander";
|
|
921
|
+
import { resolve as resolve2, join as join4 } from "path";
|
|
658
922
|
import {
|
|
659
|
-
existsSync as
|
|
923
|
+
existsSync as existsSync3,
|
|
660
924
|
mkdirSync as mkdirSync3,
|
|
661
|
-
readFileSync as
|
|
662
|
-
writeFileSync as
|
|
925
|
+
readFileSync as readFileSync3,
|
|
926
|
+
writeFileSync as writeFileSync4,
|
|
663
927
|
appendFileSync
|
|
664
928
|
} 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
|
-
}
|
|
929
|
+
import { hostname as hostname3 } from "os";
|
|
930
|
+
import chalk5 from "chalk";
|
|
686
931
|
|
|
687
932
|
// src/lib/prompts.ts
|
|
688
933
|
import { select } from "@inquirer/prompts";
|
|
@@ -734,7 +979,7 @@ branch_prefix: feat
|
|
|
734
979
|
# {{ticket.linearTicketId}}, {{ticket.id}}
|
|
735
980
|
# commit_template: "{{ticket.type}}({{ticket.linearTicketId}}): {{ticket.title}}"
|
|
736
981
|
`;
|
|
737
|
-
var linkCommand = new
|
|
982
|
+
var linkCommand = new Command4("link").description("Link the current directory to a yapout project").action(async () => {
|
|
738
983
|
const creds = requireAuth();
|
|
739
984
|
const cwd = resolveRepoRoot(resolve2(process.cwd()));
|
|
740
985
|
const client = createConvexClient(creds.token);
|
|
@@ -746,25 +991,25 @@ var linkCommand = new Command3("link").description("Link the current directory t
|
|
|
746
991
|
);
|
|
747
992
|
} catch (err) {
|
|
748
993
|
console.error(
|
|
749
|
-
|
|
994
|
+
chalk5.red("Failed to fetch projects."),
|
|
750
995
|
err.message
|
|
751
996
|
);
|
|
752
997
|
process.exit(1);
|
|
753
998
|
}
|
|
754
999
|
if (projects.length === 0) {
|
|
755
1000
|
console.error(
|
|
756
|
-
|
|
1001
|
+
chalk5.yellow("No projects found.") + " Create one at " + chalk5.cyan(`${getAppUrl()}/dashboard`)
|
|
757
1002
|
);
|
|
758
1003
|
process.exit(1);
|
|
759
1004
|
}
|
|
760
1005
|
const selected = await pickProject(projects);
|
|
761
|
-
const device = getOrCreateDeviceIdentity(
|
|
1006
|
+
const device = getOrCreateDeviceIdentity(hostname3());
|
|
762
1007
|
try {
|
|
763
1008
|
await client.mutation(anyApi.functions.devices.registerDevice, {
|
|
764
1009
|
deviceId: device.deviceId,
|
|
765
1010
|
name: device.name,
|
|
766
1011
|
cliVersion: getCliVersion(),
|
|
767
|
-
machineHostname:
|
|
1012
|
+
machineHostname: hostname3()
|
|
768
1013
|
});
|
|
769
1014
|
await client.mutation(anyApi.functions.projectCheckouts.linkCheckout, {
|
|
770
1015
|
projectId: selected.id,
|
|
@@ -773,7 +1018,7 @@ var linkCommand = new Command3("link").description("Link the current directory t
|
|
|
773
1018
|
});
|
|
774
1019
|
} catch (err) {
|
|
775
1020
|
console.warn(
|
|
776
|
-
|
|
1021
|
+
chalk5.yellow("Warning: failed to record this checkout \u2014 "),
|
|
777
1022
|
err.message
|
|
778
1023
|
);
|
|
779
1024
|
}
|
|
@@ -782,17 +1027,17 @@ var linkCommand = new Command3("link").description("Link the current directory t
|
|
|
782
1027
|
projectName: selected.name,
|
|
783
1028
|
linkedAt: Date.now()
|
|
784
1029
|
});
|
|
785
|
-
const yapoutDir =
|
|
786
|
-
if (!
|
|
1030
|
+
const yapoutDir = join4(cwd, ".yapout");
|
|
1031
|
+
if (!existsSync3(yapoutDir)) {
|
|
787
1032
|
mkdirSync3(yapoutDir, { recursive: true });
|
|
788
1033
|
}
|
|
789
|
-
const configPath =
|
|
790
|
-
if (!
|
|
791
|
-
|
|
1034
|
+
const configPath = join4(yapoutDir, "config.yml");
|
|
1035
|
+
if (!existsSync3(configPath)) {
|
|
1036
|
+
writeFileSync4(configPath, CONFIG_YAML_CONTENT);
|
|
792
1037
|
}
|
|
793
|
-
const gitignorePath =
|
|
794
|
-
if (
|
|
795
|
-
const content =
|
|
1038
|
+
const gitignorePath = join4(cwd, ".gitignore");
|
|
1039
|
+
if (existsSync3(gitignorePath)) {
|
|
1040
|
+
const content = readFileSync3(gitignorePath, "utf-8");
|
|
796
1041
|
if (!content.includes(".yapout/")) {
|
|
797
1042
|
appendFileSync(
|
|
798
1043
|
gitignorePath,
|
|
@@ -800,13 +1045,13 @@ var linkCommand = new Command3("link").description("Link the current directory t
|
|
|
800
1045
|
);
|
|
801
1046
|
}
|
|
802
1047
|
} else {
|
|
803
|
-
|
|
1048
|
+
writeFileSync4(gitignorePath, "# yapout local config\n.yapout/\n");
|
|
804
1049
|
}
|
|
805
|
-
const mcpPath =
|
|
1050
|
+
const mcpPath = join4(cwd, ".mcp.json");
|
|
806
1051
|
let mcpConfig = {};
|
|
807
|
-
if (
|
|
1052
|
+
if (existsSync3(mcpPath)) {
|
|
808
1053
|
try {
|
|
809
|
-
mcpConfig = JSON.parse(
|
|
1054
|
+
mcpConfig = JSON.parse(readFileSync3(mcpPath, "utf-8"));
|
|
810
1055
|
} catch {
|
|
811
1056
|
}
|
|
812
1057
|
}
|
|
@@ -815,17 +1060,17 @@ var linkCommand = new Command3("link").description("Link the current directory t
|
|
|
815
1060
|
command: "yapout",
|
|
816
1061
|
args: ["mcp-server"]
|
|
817
1062
|
};
|
|
818
|
-
|
|
1063
|
+
writeFileSync4(mcpPath, JSON.stringify(mcpConfig, null, 2) + "\n");
|
|
819
1064
|
const label = selected.githubRepoFullName ? `${selected.name} (${selected.githubRepoFullName})` : selected.name;
|
|
820
1065
|
const orgSuffix = selected.org ? ` in ${selected.org.name}` : "";
|
|
821
1066
|
console.log(
|
|
822
|
-
|
|
1067
|
+
chalk5.green(`Linked to ${label}${orgSuffix}.`) + " Claude Code will discover yapout tools automatically."
|
|
823
1068
|
);
|
|
824
1069
|
});
|
|
825
1070
|
function getCliVersion() {
|
|
826
1071
|
try {
|
|
827
1072
|
const pkg = JSON.parse(
|
|
828
|
-
|
|
1073
|
+
readFileSync3(join4(import.meta.dirname, "..", "package.json"), "utf-8")
|
|
829
1074
|
);
|
|
830
1075
|
return pkg.version ?? "unknown";
|
|
831
1076
|
} catch {
|
|
@@ -834,15 +1079,15 @@ function getCliVersion() {
|
|
|
834
1079
|
}
|
|
835
1080
|
|
|
836
1081
|
// 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
|
|
1082
|
+
import { Command as Command5 } from "commander";
|
|
1083
|
+
import { resolve as resolve3, join as join5 } from "path";
|
|
1084
|
+
import { existsSync as existsSync4, readFileSync as readFileSync4, writeFileSync as writeFileSync5, rmSync } from "fs";
|
|
1085
|
+
import chalk6 from "chalk";
|
|
1086
|
+
var unlinkCommand = new Command5("unlink").description("Unlink the current directory from its yapout project").action(async () => {
|
|
842
1087
|
const cwd = resolve3(process.cwd());
|
|
843
1088
|
const mapping = getProjectMapping(cwd);
|
|
844
1089
|
if (!mapping) {
|
|
845
|
-
console.error(
|
|
1090
|
+
console.error(chalk6.yellow("No project linked to this directory."));
|
|
846
1091
|
process.exit(1);
|
|
847
1092
|
}
|
|
848
1093
|
const device = readDeviceIdentity();
|
|
@@ -856,26 +1101,26 @@ var unlinkCommand = new Command4("unlink").description("Unlink the current direc
|
|
|
856
1101
|
});
|
|
857
1102
|
} catch (err) {
|
|
858
1103
|
console.warn(
|
|
859
|
-
|
|
1104
|
+
chalk6.yellow("Warning: failed to update server \u2014 "),
|
|
860
1105
|
err.message
|
|
861
1106
|
);
|
|
862
1107
|
}
|
|
863
1108
|
}
|
|
864
1109
|
removeProjectMapping(cwd);
|
|
865
|
-
const yapoutDir =
|
|
866
|
-
if (
|
|
1110
|
+
const yapoutDir = join5(cwd, ".yapout");
|
|
1111
|
+
if (existsSync4(yapoutDir)) {
|
|
867
1112
|
rmSync(yapoutDir, { recursive: true });
|
|
868
1113
|
}
|
|
869
|
-
const mcpPath =
|
|
870
|
-
if (
|
|
1114
|
+
const mcpPath = join5(cwd, ".mcp.json");
|
|
1115
|
+
if (existsSync4(mcpPath)) {
|
|
871
1116
|
try {
|
|
872
|
-
const mcpConfig = JSON.parse(
|
|
1117
|
+
const mcpConfig = JSON.parse(readFileSync4(mcpPath, "utf-8"));
|
|
873
1118
|
if (mcpConfig.mcpServers?.yapout) {
|
|
874
1119
|
delete mcpConfig.mcpServers.yapout;
|
|
875
1120
|
if (Object.keys(mcpConfig.mcpServers).length === 0) {
|
|
876
1121
|
rmSync(mcpPath);
|
|
877
1122
|
} else {
|
|
878
|
-
|
|
1123
|
+
writeFileSync5(
|
|
879
1124
|
mcpPath,
|
|
880
1125
|
JSON.stringify(mcpConfig, null, 2) + "\n"
|
|
881
1126
|
);
|
|
@@ -884,23 +1129,23 @@ var unlinkCommand = new Command4("unlink").description("Unlink the current direc
|
|
|
884
1129
|
} catch {
|
|
885
1130
|
}
|
|
886
1131
|
}
|
|
887
|
-
console.log(
|
|
1132
|
+
console.log(chalk6.green("Unlinked."));
|
|
888
1133
|
});
|
|
889
1134
|
|
|
890
1135
|
// src/commands/status.ts
|
|
891
|
-
import { Command as
|
|
1136
|
+
import { Command as Command6 } from "commander";
|
|
892
1137
|
import { resolve as resolve4 } from "path";
|
|
893
|
-
import
|
|
894
|
-
var statusCommand = new
|
|
895
|
-
console.log(
|
|
1138
|
+
import chalk7 from "chalk";
|
|
1139
|
+
var statusCommand = new Command6("status").description("Show yapout status for this directory").action(() => {
|
|
1140
|
+
console.log(chalk7.bold("yapout status\n"));
|
|
896
1141
|
const creds = readCredentials();
|
|
897
1142
|
if (!creds) {
|
|
898
1143
|
console.log(
|
|
899
|
-
` Auth: ${
|
|
1144
|
+
` Auth: ${chalk7.red("Not logged in.")} Run ${chalk7.cyan("yapout login")}.`
|
|
900
1145
|
);
|
|
901
1146
|
} else if (Date.now() > creds.expiresAt) {
|
|
902
1147
|
console.log(
|
|
903
|
-
` Auth: ${
|
|
1148
|
+
` Auth: ${chalk7.red("Session expired.")} Run ${chalk7.cyan("yapout login")}.`
|
|
904
1149
|
);
|
|
905
1150
|
} else {
|
|
906
1151
|
const daysLeft = Math.max(
|
|
@@ -908,35 +1153,35 @@ var statusCommand = new Command5("status").description("Show yapout status for t
|
|
|
908
1153
|
Math.round((creds.expiresAt - Date.now()) / 864e5)
|
|
909
1154
|
);
|
|
910
1155
|
console.log(
|
|
911
|
-
` Auth: ${
|
|
1156
|
+
` Auth: ${chalk7.green(creds.email)} (expires in ${daysLeft} day${daysLeft === 1 ? "" : "s"})`
|
|
912
1157
|
);
|
|
913
1158
|
}
|
|
914
1159
|
const cwd = resolve4(process.cwd());
|
|
915
1160
|
const mapping = getProjectMapping(cwd);
|
|
916
1161
|
if (!mapping) {
|
|
917
1162
|
console.log(
|
|
918
|
-
` Project: ${
|
|
1163
|
+
` Project: ${chalk7.yellow("No project linked.")} Run ${chalk7.cyan("yapout link")} in a repo.`
|
|
919
1164
|
);
|
|
920
1165
|
} else {
|
|
921
|
-
console.log(` Project: ${
|
|
1166
|
+
console.log(` Project: ${chalk7.green(mapping.projectName)}`);
|
|
922
1167
|
}
|
|
923
|
-
console.log(` Daemon: ${
|
|
924
|
-
console.log(` Work: ${
|
|
1168
|
+
console.log(` Daemon: ${chalk7.dim("not running")}`);
|
|
1169
|
+
console.log(` Work: ${chalk7.dim("no active tickets")}`);
|
|
925
1170
|
console.log();
|
|
926
1171
|
});
|
|
927
1172
|
|
|
928
1173
|
// src/commands/init.ts
|
|
929
|
-
import { Command as
|
|
930
|
-
import { resolve as resolve5, join as
|
|
1174
|
+
import { Command as Command7 } from "commander";
|
|
1175
|
+
import { resolve as resolve5, join as join6 } from "path";
|
|
931
1176
|
import {
|
|
932
|
-
existsSync as
|
|
1177
|
+
existsSync as existsSync5,
|
|
933
1178
|
mkdirSync as mkdirSync4,
|
|
934
|
-
writeFileSync as
|
|
935
|
-
readFileSync as
|
|
1179
|
+
writeFileSync as writeFileSync6,
|
|
1180
|
+
readFileSync as readFileSync5,
|
|
936
1181
|
appendFileSync as appendFileSync2
|
|
937
1182
|
} from "fs";
|
|
938
|
-
import { hostname as
|
|
939
|
-
import
|
|
1183
|
+
import { hostname as hostname4 } from "os";
|
|
1184
|
+
import chalk8 from "chalk";
|
|
940
1185
|
var CONFIG_YAML_CONTENT2 = `# yapout local configuration
|
|
941
1186
|
# See: https://docs.yapout.dev/cli/config
|
|
942
1187
|
|
|
@@ -961,7 +1206,7 @@ branch_prefix: feat
|
|
|
961
1206
|
# {{ticket.linearTicketId}}, {{ticket.id}}
|
|
962
1207
|
# commit_template: "{{ticket.type}}({{ticket.linearTicketId}}): {{ticket.title}}"
|
|
963
1208
|
`;
|
|
964
|
-
var initCommand = new
|
|
1209
|
+
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
1210
|
const creds = requireAuth();
|
|
966
1211
|
const cwd = resolveRepoRoot(resolve5(process.cwd()));
|
|
967
1212
|
let repoFullName;
|
|
@@ -971,7 +1216,7 @@ var initCommand = new Command6("init").description("Create a yapout project from
|
|
|
971
1216
|
defaultBranch = getDefaultBranch(cwd);
|
|
972
1217
|
} catch (err) {
|
|
973
1218
|
console.error(
|
|
974
|
-
|
|
1219
|
+
chalk8.red("Not a git repo with a GitHub remote."),
|
|
975
1220
|
err.message
|
|
976
1221
|
);
|
|
977
1222
|
process.exit(1);
|
|
@@ -986,14 +1231,14 @@ var initCommand = new Command6("init").description("Create a yapout project from
|
|
|
986
1231
|
);
|
|
987
1232
|
} catch (err) {
|
|
988
1233
|
console.error(
|
|
989
|
-
|
|
1234
|
+
chalk8.red("Failed to load your orgs."),
|
|
990
1235
|
err.message
|
|
991
1236
|
);
|
|
992
1237
|
process.exit(1);
|
|
993
1238
|
}
|
|
994
1239
|
if (!orgs || orgs.length === 0) {
|
|
995
1240
|
console.error(
|
|
996
|
-
|
|
1241
|
+
chalk8.red(
|
|
997
1242
|
"You aren't a member of any org. Sign in to the web app once to create your personal org, then re-run."
|
|
998
1243
|
)
|
|
999
1244
|
);
|
|
@@ -1005,10 +1250,10 @@ var initCommand = new Command6("init").description("Create a yapout project from
|
|
|
1005
1250
|
const match = orgs.find((o) => o.org.slug === options.org);
|
|
1006
1251
|
if (!match) {
|
|
1007
1252
|
console.error(
|
|
1008
|
-
|
|
1253
|
+
chalk8.red(`Org "${options.org}" not found among your memberships.`)
|
|
1009
1254
|
);
|
|
1010
1255
|
console.error(
|
|
1011
|
-
|
|
1256
|
+
chalk8.dim(
|
|
1012
1257
|
"Available: " + orgs.map((o) => o.org.slug).join(", ")
|
|
1013
1258
|
)
|
|
1014
1259
|
);
|
|
@@ -1020,7 +1265,7 @@ var initCommand = new Command6("init").description("Create a yapout project from
|
|
|
1020
1265
|
chosenOrgId = orgs[0].org._id;
|
|
1021
1266
|
chosenOrgName = orgs[0].org.name;
|
|
1022
1267
|
console.log(
|
|
1023
|
-
|
|
1268
|
+
chalk8.dim(`Creating in `) + chalk8.cyan(chosenOrgName)
|
|
1024
1269
|
);
|
|
1025
1270
|
} else {
|
|
1026
1271
|
const picked = await pickOrg(
|
|
@@ -1034,17 +1279,17 @@ var initCommand = new Command6("init").description("Create a yapout project from
|
|
|
1034
1279
|
chosenOrgId = picked.id;
|
|
1035
1280
|
chosenOrgName = picked.name;
|
|
1036
1281
|
}
|
|
1037
|
-
const device = getOrCreateDeviceIdentity(
|
|
1282
|
+
const device = getOrCreateDeviceIdentity(hostname4());
|
|
1038
1283
|
try {
|
|
1039
1284
|
await client.mutation(anyApi.functions.devices.registerDevice, {
|
|
1040
1285
|
deviceId: device.deviceId,
|
|
1041
1286
|
name: device.name,
|
|
1042
1287
|
cliVersion: getCliVersion2(),
|
|
1043
|
-
machineHostname:
|
|
1288
|
+
machineHostname: hostname4()
|
|
1044
1289
|
});
|
|
1045
1290
|
} catch (err) {
|
|
1046
1291
|
console.warn(
|
|
1047
|
-
|
|
1292
|
+
chalk8.yellow("Warning: device registration failed \u2014 "),
|
|
1048
1293
|
err.message
|
|
1049
1294
|
);
|
|
1050
1295
|
}
|
|
@@ -1061,7 +1306,7 @@ var initCommand = new Command6("init").description("Create a yapout project from
|
|
|
1061
1306
|
);
|
|
1062
1307
|
} catch (err) {
|
|
1063
1308
|
console.error(
|
|
1064
|
-
|
|
1309
|
+
chalk8.red("Failed to create project."),
|
|
1065
1310
|
err.message
|
|
1066
1311
|
);
|
|
1067
1312
|
process.exit(1);
|
|
@@ -1074,7 +1319,7 @@ var initCommand = new Command6("init").description("Create a yapout project from
|
|
|
1074
1319
|
});
|
|
1075
1320
|
} catch (err) {
|
|
1076
1321
|
console.warn(
|
|
1077
|
-
|
|
1322
|
+
chalk8.yellow("Warning: failed to record project checkout \u2014 "),
|
|
1078
1323
|
err.message
|
|
1079
1324
|
);
|
|
1080
1325
|
}
|
|
@@ -1083,15 +1328,15 @@ var initCommand = new Command6("init").description("Create a yapout project from
|
|
|
1083
1328
|
projectName: result.projectName,
|
|
1084
1329
|
linkedAt: Date.now()
|
|
1085
1330
|
});
|
|
1086
|
-
const yapoutDir =
|
|
1087
|
-
if (!
|
|
1088
|
-
const configPath =
|
|
1089
|
-
if (!
|
|
1090
|
-
|
|
1091
|
-
}
|
|
1092
|
-
const gitignorePath =
|
|
1093
|
-
if (
|
|
1094
|
-
const content =
|
|
1331
|
+
const yapoutDir = join6(cwd, ".yapout");
|
|
1332
|
+
if (!existsSync5(yapoutDir)) mkdirSync4(yapoutDir, { recursive: true });
|
|
1333
|
+
const configPath = join6(yapoutDir, "config.yml");
|
|
1334
|
+
if (!existsSync5(configPath)) {
|
|
1335
|
+
writeFileSync6(configPath, CONFIG_YAML_CONTENT2);
|
|
1336
|
+
}
|
|
1337
|
+
const gitignorePath = join6(cwd, ".gitignore");
|
|
1338
|
+
if (existsSync5(gitignorePath)) {
|
|
1339
|
+
const content = readFileSync5(gitignorePath, "utf-8");
|
|
1095
1340
|
if (!content.includes(".yapout/")) {
|
|
1096
1341
|
appendFileSync2(
|
|
1097
1342
|
gitignorePath,
|
|
@@ -1099,11 +1344,11 @@ var initCommand = new Command6("init").description("Create a yapout project from
|
|
|
1099
1344
|
);
|
|
1100
1345
|
}
|
|
1101
1346
|
}
|
|
1102
|
-
const mcpPath =
|
|
1347
|
+
const mcpPath = join6(cwd, ".mcp.json");
|
|
1103
1348
|
let mcpConfig = {};
|
|
1104
|
-
if (
|
|
1349
|
+
if (existsSync5(mcpPath)) {
|
|
1105
1350
|
try {
|
|
1106
|
-
mcpConfig = JSON.parse(
|
|
1351
|
+
mcpConfig = JSON.parse(readFileSync5(mcpPath, "utf-8"));
|
|
1107
1352
|
} catch {
|
|
1108
1353
|
}
|
|
1109
1354
|
}
|
|
@@ -1112,20 +1357,20 @@ var initCommand = new Command6("init").description("Create a yapout project from
|
|
|
1112
1357
|
command: "yapout",
|
|
1113
1358
|
args: ["mcp-server"]
|
|
1114
1359
|
};
|
|
1115
|
-
|
|
1360
|
+
writeFileSync6(mcpPath, JSON.stringify(mcpConfig, null, 2) + "\n");
|
|
1116
1361
|
console.log(
|
|
1117
|
-
|
|
1362
|
+
chalk8.green(`Created project "${result.projectName}"`) + chalk8.dim(
|
|
1118
1363
|
` in ${chosenOrgName} (${repoFullName}, branch: ${defaultBranch})`
|
|
1119
1364
|
)
|
|
1120
1365
|
);
|
|
1121
1366
|
console.log(
|
|
1122
|
-
|
|
1367
|
+
chalk8.dim("Run ") + chalk8.cyan("yapout_compact") + chalk8.dim(" in Claude Code to generate project context.")
|
|
1123
1368
|
);
|
|
1124
1369
|
});
|
|
1125
1370
|
function getCliVersion2() {
|
|
1126
1371
|
try {
|
|
1127
1372
|
const pkg = JSON.parse(
|
|
1128
|
-
|
|
1373
|
+
readFileSync5(join6(import.meta.dirname, "..", "package.json"), "utf-8")
|
|
1129
1374
|
);
|
|
1130
1375
|
return pkg.version ?? "unknown";
|
|
1131
1376
|
} catch {
|
|
@@ -1134,18 +1379,18 @@ function getCliVersion2() {
|
|
|
1134
1379
|
}
|
|
1135
1380
|
|
|
1136
1381
|
// src/commands/mcp-server.ts
|
|
1137
|
-
import { Command as
|
|
1382
|
+
import { Command as Command8 } from "commander";
|
|
1138
1383
|
|
|
1139
1384
|
// src/mcp/server.ts
|
|
1140
1385
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
1141
1386
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
1142
1387
|
import { ConvexHttpClient as ConvexHttpClient2 } from "convex/browser";
|
|
1143
|
-
import { anyApi as
|
|
1388
|
+
import { anyApi as anyApi4 } from "convex/server";
|
|
1144
1389
|
|
|
1145
1390
|
// src/mcp/tools/init.ts
|
|
1146
1391
|
import { z } from "zod";
|
|
1147
|
-
import { join as
|
|
1148
|
-
import { existsSync as
|
|
1392
|
+
import { join as join7 } from "path";
|
|
1393
|
+
import { existsSync as existsSync6, mkdirSync as mkdirSync5, writeFileSync as writeFileSync7 } from "fs";
|
|
1149
1394
|
import { stringify as yamlStringify } from "yaml";
|
|
1150
1395
|
function registerInitTool(server, ctx) {
|
|
1151
1396
|
server.tool(
|
|
@@ -1161,7 +1406,7 @@ function registerInitTool(server, ctx) {
|
|
|
1161
1406
|
const defaultBranch = getDefaultBranch(repoRoot);
|
|
1162
1407
|
const projectName = args.name || repoFullName.split("/")[1] || "unnamed";
|
|
1163
1408
|
const result = await ctx.client.mutation(
|
|
1164
|
-
|
|
1409
|
+
anyApi4.functions.projects.createProjectFromCli,
|
|
1165
1410
|
{
|
|
1166
1411
|
name: projectName,
|
|
1167
1412
|
githubRepoFullName: repoFullName,
|
|
@@ -1176,11 +1421,11 @@ function registerInitTool(server, ctx) {
|
|
|
1176
1421
|
projectName: result.projectName,
|
|
1177
1422
|
linkedAt: Date.now()
|
|
1178
1423
|
});
|
|
1179
|
-
const yapoutDir =
|
|
1180
|
-
if (!
|
|
1181
|
-
const configPath =
|
|
1182
|
-
if (!
|
|
1183
|
-
|
|
1424
|
+
const yapoutDir = join7(repoRoot, ".yapout");
|
|
1425
|
+
if (!existsSync6(yapoutDir)) mkdirSync5(yapoutDir, { recursive: true });
|
|
1426
|
+
const configPath = join7(yapoutDir, "config.yml");
|
|
1427
|
+
if (!existsSync6(configPath)) {
|
|
1428
|
+
writeFileSync7(
|
|
1184
1429
|
configPath,
|
|
1185
1430
|
`# yapout local configuration
|
|
1186
1431
|
|
|
@@ -1249,7 +1494,7 @@ function registerCompactTool(server, ctx) {
|
|
|
1249
1494
|
let lastUpdated;
|
|
1250
1495
|
try {
|
|
1251
1496
|
const project = await ctx.client.query(
|
|
1252
|
-
|
|
1497
|
+
anyApi4.functions.projects.getProject,
|
|
1253
1498
|
{ projectId: ctx.projectId }
|
|
1254
1499
|
);
|
|
1255
1500
|
currentContext = project?.contextSummary ?? void 0;
|
|
@@ -1292,7 +1537,7 @@ function registerUpdateContextTool(server, ctx) {
|
|
|
1292
1537
|
};
|
|
1293
1538
|
}
|
|
1294
1539
|
await ctx.client.mutation(
|
|
1295
|
-
|
|
1540
|
+
anyApi4.functions.projects.updateProjectContext,
|
|
1296
1541
|
{
|
|
1297
1542
|
projectId: ctx.projectId,
|
|
1298
1543
|
summary: args.summary
|
|
@@ -1362,7 +1607,7 @@ function registerQueueTool(server, ctx) {
|
|
|
1362
1607
|
};
|
|
1363
1608
|
}
|
|
1364
1609
|
const data = await ctx.client.query(
|
|
1365
|
-
|
|
1610
|
+
anyApi4.functions.workQueue.getWorkQueue,
|
|
1366
1611
|
{ projectId: ctx.projectId }
|
|
1367
1612
|
);
|
|
1368
1613
|
if (!data) {
|
|
@@ -1471,7 +1716,7 @@ function registerGetBriefTool(server, ctx) {
|
|
|
1471
1716
|
}
|
|
1472
1717
|
try {
|
|
1473
1718
|
const data = await ctx.client.query(
|
|
1474
|
-
|
|
1719
|
+
anyApi4.functions.findings.getFindingBrief,
|
|
1475
1720
|
{ findingId: itemId }
|
|
1476
1721
|
);
|
|
1477
1722
|
if (data) {
|
|
@@ -1485,7 +1730,7 @@ function registerGetBriefTool(server, ctx) {
|
|
|
1485
1730
|
}
|
|
1486
1731
|
try {
|
|
1487
1732
|
const bundle = await ctx.client.query(
|
|
1488
|
-
|
|
1733
|
+
anyApi4.functions.bundles.getBundle,
|
|
1489
1734
|
{ bundleId: itemId }
|
|
1490
1735
|
);
|
|
1491
1736
|
if (bundle) {
|
|
@@ -1536,8 +1781,8 @@ function registerGetBriefTool(server, ctx) {
|
|
|
1536
1781
|
|
|
1537
1782
|
// src/mcp/tools/claim.ts
|
|
1538
1783
|
import { z as z5 } from "zod";
|
|
1539
|
-
import { join as
|
|
1540
|
-
import { existsSync as
|
|
1784
|
+
import { join as join8 } from "path";
|
|
1785
|
+
import { existsSync as existsSync7, mkdirSync as mkdirSync6, writeFileSync as writeFileSync8 } from "fs";
|
|
1541
1786
|
function readBranchPrefix(cwd) {
|
|
1542
1787
|
try {
|
|
1543
1788
|
const config = readYapoutConfig(cwd);
|
|
@@ -1656,7 +1901,7 @@ function formatBundleBrief(bundle, projectContext) {
|
|
|
1656
1901
|
async function detectWorkItemKind(client, workItemId) {
|
|
1657
1902
|
try {
|
|
1658
1903
|
const bundle = await client.query(
|
|
1659
|
-
|
|
1904
|
+
anyApi4.functions.bundles.getBundle,
|
|
1660
1905
|
{ bundleId: workItemId }
|
|
1661
1906
|
);
|
|
1662
1907
|
if (bundle) {
|
|
@@ -1710,7 +1955,7 @@ function registerClaimTool(server, ctx) {
|
|
|
1710
1955
|
}
|
|
1711
1956
|
async function claimStandalone(ctx, args, findingId) {
|
|
1712
1957
|
const briefData = await ctx.client.query(
|
|
1713
|
-
|
|
1958
|
+
anyApi4.functions.findings.getFindingBrief,
|
|
1714
1959
|
{ findingId }
|
|
1715
1960
|
);
|
|
1716
1961
|
if (!briefData) {
|
|
@@ -1731,11 +1976,11 @@ async function claimStandalone(ctx, args, findingId) {
|
|
|
1731
1976
|
const slug = slugify(finding.title);
|
|
1732
1977
|
const branchName = linearIssueId ? `${prefix}/${linearIssueId.toLowerCase()}-${slug}` : `${prefix}/${slug}`;
|
|
1733
1978
|
const localClaim = await ctx.client.mutation(
|
|
1734
|
-
|
|
1979
|
+
anyApi4.functions.findings.claimFindingLocal,
|
|
1735
1980
|
{ findingId, branchName }
|
|
1736
1981
|
);
|
|
1737
1982
|
const claim = await ctx.client.mutation(
|
|
1738
|
-
|
|
1983
|
+
anyApi4.functions.workQueue.claimForImplementation,
|
|
1739
1984
|
{
|
|
1740
1985
|
projectId: ctx.projectId,
|
|
1741
1986
|
workItemId: findingId,
|
|
@@ -1745,7 +1990,7 @@ async function claimStandalone(ctx, args, findingId) {
|
|
|
1745
1990
|
if (linearIssueId && ctx.projectId) {
|
|
1746
1991
|
try {
|
|
1747
1992
|
await ctx.client.action(
|
|
1748
|
-
|
|
1993
|
+
anyApi4.functions.linearStatusMutations.moveIssueStatus,
|
|
1749
1994
|
{
|
|
1750
1995
|
projectId: ctx.projectId,
|
|
1751
1996
|
linearIssueId,
|
|
@@ -1802,11 +2047,11 @@ async function claimBundle(ctx, args, bundleId, bundleData) {
|
|
|
1802
2047
|
};
|
|
1803
2048
|
}
|
|
1804
2049
|
const localClaim = await ctx.client.mutation(
|
|
1805
|
-
|
|
2050
|
+
anyApi4.functions.findings.claimFindingLocal,
|
|
1806
2051
|
{ findingId: primaryFinding._id, branchName }
|
|
1807
2052
|
);
|
|
1808
2053
|
const claim = await ctx.client.mutation(
|
|
1809
|
-
|
|
2054
|
+
anyApi4.functions.workQueue.claimForImplementation,
|
|
1810
2055
|
{
|
|
1811
2056
|
projectId: ctx.projectId,
|
|
1812
2057
|
workItemId: bundleId,
|
|
@@ -1817,7 +2062,7 @@ async function claimBundle(ctx, args, bundleId, bundleData) {
|
|
|
1817
2062
|
if (f.linearIssueId && ctx.projectId) {
|
|
1818
2063
|
try {
|
|
1819
2064
|
await ctx.client.action(
|
|
1820
|
-
|
|
2065
|
+
anyApi4.functions.linearStatusMutations.moveIssueStatus,
|
|
1821
2066
|
{
|
|
1822
2067
|
projectId: ctx.projectId,
|
|
1823
2068
|
linearIssueId: f.linearIssueId,
|
|
@@ -1831,7 +2076,7 @@ async function claimBundle(ctx, args, bundleId, bundleData) {
|
|
|
1831
2076
|
let projectContext;
|
|
1832
2077
|
try {
|
|
1833
2078
|
const briefData = await ctx.client.query(
|
|
1834
|
-
|
|
2079
|
+
anyApi4.functions.findings.getFindingBrief,
|
|
1835
2080
|
{ findingId: primaryFinding._id }
|
|
1836
2081
|
);
|
|
1837
2082
|
projectContext = briefData?.projectContext;
|
|
@@ -1871,7 +2116,7 @@ async function claimBundle(ctx, args, bundleId, bundleData) {
|
|
|
1871
2116
|
async function getDefaultBranchForProject(ctx) {
|
|
1872
2117
|
try {
|
|
1873
2118
|
const data = await ctx.client.query(
|
|
1874
|
-
|
|
2119
|
+
anyApi4.functions.projects.getProject,
|
|
1875
2120
|
{ projectId: ctx.projectId }
|
|
1876
2121
|
);
|
|
1877
2122
|
return data?.githubDefaultBranch || "main";
|
|
@@ -1890,7 +2135,7 @@ async function setupWorktree(ctx, itemId, branchName, defaultBranch, brief, pipe
|
|
|
1890
2135
|
writeBrief(worktreePath, brief);
|
|
1891
2136
|
try {
|
|
1892
2137
|
await ctx.client.mutation(
|
|
1893
|
-
|
|
2138
|
+
anyApi4.functions.pipelineRuns.reportDaemonEvent,
|
|
1894
2139
|
{
|
|
1895
2140
|
pipelineRunId,
|
|
1896
2141
|
event: "worktree_created",
|
|
@@ -1919,14 +2164,14 @@ async function setupWorktree(ctx, itemId, branchName, defaultBranch, brief, pipe
|
|
|
1919
2164
|
};
|
|
1920
2165
|
}
|
|
1921
2166
|
function writeBrief(dir, brief) {
|
|
1922
|
-
const yapoutDir =
|
|
1923
|
-
if (!
|
|
1924
|
-
|
|
2167
|
+
const yapoutDir = join8(dir, ".yapout");
|
|
2168
|
+
if (!existsSync7(yapoutDir)) mkdirSync6(yapoutDir, { recursive: true });
|
|
2169
|
+
writeFileSync8(join8(yapoutDir, "brief.md"), brief);
|
|
1925
2170
|
}
|
|
1926
2171
|
async function reportClaimEvents(ctx, pipelineRunId, title, branchName) {
|
|
1927
2172
|
try {
|
|
1928
2173
|
await ctx.client.mutation(
|
|
1929
|
-
|
|
2174
|
+
anyApi4.functions.pipelineRuns.reportDaemonEvent,
|
|
1930
2175
|
{
|
|
1931
2176
|
pipelineRunId,
|
|
1932
2177
|
event: "daemon_claimed",
|
|
@@ -1934,7 +2179,7 @@ async function reportClaimEvents(ctx, pipelineRunId, title, branchName) {
|
|
|
1934
2179
|
}
|
|
1935
2180
|
);
|
|
1936
2181
|
await ctx.client.mutation(
|
|
1937
|
-
|
|
2182
|
+
anyApi4.functions.pipelineRuns.reportDaemonEvent,
|
|
1938
2183
|
{
|
|
1939
2184
|
pipelineRunId,
|
|
1940
2185
|
event: "branch_created",
|
|
@@ -1961,7 +2206,7 @@ function registerEventTool(server, ctx) {
|
|
|
1961
2206
|
async (args) => {
|
|
1962
2207
|
try {
|
|
1963
2208
|
await ctx.client.mutation(
|
|
1964
|
-
|
|
2209
|
+
anyApi4.functions.pipelineRuns.reportDaemonEvent,
|
|
1965
2210
|
{
|
|
1966
2211
|
pipelineRunId: args.pipelineRunId,
|
|
1967
2212
|
event: args.event,
|
|
@@ -2053,8 +2298,8 @@ async function createPullRequest(title, body, branch, base, repoFullName, cwd) {
|
|
|
2053
2298
|
}
|
|
2054
2299
|
|
|
2055
2300
|
// src/mcp/tools/ship.ts
|
|
2056
|
-
import { join as
|
|
2057
|
-
import { existsSync as
|
|
2301
|
+
import { join as join9 } from "path";
|
|
2302
|
+
import { existsSync as existsSync8, readFileSync as readFileSync6 } from "fs";
|
|
2058
2303
|
function buildCommitMessage(message, template, finding, allLinearIds) {
|
|
2059
2304
|
if (message) return message;
|
|
2060
2305
|
if (template) {
|
|
@@ -2105,9 +2350,9 @@ function registerShipTool(server, ctx) {
|
|
|
2105
2350
|
let isBundle = false;
|
|
2106
2351
|
let bundleTitle;
|
|
2107
2352
|
try {
|
|
2108
|
-
const briefPath =
|
|
2109
|
-
if (
|
|
2110
|
-
const brief =
|
|
2353
|
+
const briefPath = join9(gitCwd, ".yapout", "brief.md");
|
|
2354
|
+
if (existsSync8(briefPath)) {
|
|
2355
|
+
const brief = readFileSync6(briefPath, "utf-8");
|
|
2111
2356
|
const bundleMatch = brief.match(/^# Bundle: (.+)$/m);
|
|
2112
2357
|
if (bundleMatch) {
|
|
2113
2358
|
isBundle = true;
|
|
@@ -2218,7 +2463,7 @@ function registerShipTool(server, ctx) {
|
|
|
2218
2463
|
}
|
|
2219
2464
|
try {
|
|
2220
2465
|
await ctx.client.mutation(
|
|
2221
|
-
|
|
2466
|
+
anyApi4.functions.pipelineRuns.reportDaemonEvent,
|
|
2222
2467
|
{
|
|
2223
2468
|
pipelineRunId: args.pipelineRunId,
|
|
2224
2469
|
event: "push_completed",
|
|
@@ -2227,7 +2472,7 @@ function registerShipTool(server, ctx) {
|
|
|
2227
2472
|
);
|
|
2228
2473
|
if (prUrl) {
|
|
2229
2474
|
await ctx.client.mutation(
|
|
2230
|
-
|
|
2475
|
+
anyApi4.functions.pipelineRuns.reportDaemonEvent,
|
|
2231
2476
|
{
|
|
2232
2477
|
pipelineRunId: args.pipelineRunId,
|
|
2233
2478
|
event: "pr_opened",
|
|
@@ -2239,7 +2484,7 @@ function registerShipTool(server, ctx) {
|
|
|
2239
2484
|
}
|
|
2240
2485
|
try {
|
|
2241
2486
|
await ctx.client.mutation(
|
|
2242
|
-
|
|
2487
|
+
anyApi4.functions.pipelineRuns.completePipelineLocal,
|
|
2243
2488
|
{
|
|
2244
2489
|
pipelineRunId: args.pipelineRunId,
|
|
2245
2490
|
githubPrNumber: prNumber,
|
|
@@ -2255,7 +2500,7 @@ function registerShipTool(server, ctx) {
|
|
|
2255
2500
|
if (ctx.projectId) {
|
|
2256
2501
|
try {
|
|
2257
2502
|
await ctx.client.action(
|
|
2258
|
-
|
|
2503
|
+
anyApi4.functions.linearStatusMutations.moveIssueStatus,
|
|
2259
2504
|
{
|
|
2260
2505
|
projectId: ctx.projectId,
|
|
2261
2506
|
linearIssueId: linearId,
|
|
@@ -2267,7 +2512,7 @@ function registerShipTool(server, ctx) {
|
|
|
2267
2512
|
if (prUrl) {
|
|
2268
2513
|
try {
|
|
2269
2514
|
await ctx.client.action(
|
|
2270
|
-
|
|
2515
|
+
anyApi4.functions.linearStatusMutations.addLinearComment,
|
|
2271
2516
|
{
|
|
2272
2517
|
projectId: ctx.projectId,
|
|
2273
2518
|
linearIssueId: linearId,
|
|
@@ -2285,7 +2530,7 @@ function registerShipTool(server, ctx) {
|
|
|
2285
2530
|
result.worktreeCleaned = true;
|
|
2286
2531
|
try {
|
|
2287
2532
|
await ctx.client.mutation(
|
|
2288
|
-
|
|
2533
|
+
anyApi4.functions.pipelineRuns.reportDaemonEvent,
|
|
2289
2534
|
{
|
|
2290
2535
|
pipelineRunId: args.pipelineRunId,
|
|
2291
2536
|
event: "worktree_cleaned",
|
|
@@ -2376,7 +2621,7 @@ function registerCheckTool(server, ctx) {
|
|
|
2376
2621
|
if (args.pipelineRunId) {
|
|
2377
2622
|
try {
|
|
2378
2623
|
await ctx.client.mutation(
|
|
2379
|
-
|
|
2624
|
+
anyApi4.functions.pipelineRuns.reportDaemonEvent,
|
|
2380
2625
|
{
|
|
2381
2626
|
pipelineRunId: args.pipelineRunId,
|
|
2382
2627
|
event: "running_check",
|
|
@@ -2396,7 +2641,7 @@ function registerCheckTool(server, ctx) {
|
|
|
2396
2641
|
if (args.pipelineRunId) {
|
|
2397
2642
|
try {
|
|
2398
2643
|
await ctx.client.mutation(
|
|
2399
|
-
|
|
2644
|
+
anyApi4.functions.pipelineRuns.reportDaemonEvent,
|
|
2400
2645
|
{
|
|
2401
2646
|
pipelineRunId: args.pipelineRunId,
|
|
2402
2647
|
event: passed ? "check_passed" : "check_failed",
|
|
@@ -2428,8 +2673,8 @@ function registerCheckTool(server, ctx) {
|
|
|
2428
2673
|
|
|
2429
2674
|
// src/mcp/tools/bundle.ts
|
|
2430
2675
|
import { z as z9 } from "zod";
|
|
2431
|
-
import { join as
|
|
2432
|
-
import { existsSync as
|
|
2676
|
+
import { join as join10 } from "path";
|
|
2677
|
+
import { existsSync as existsSync9, writeFileSync as writeFileSync9, mkdirSync as mkdirSync7 } from "fs";
|
|
2433
2678
|
function registerBundleTool(server, ctx) {
|
|
2434
2679
|
server.tool(
|
|
2435
2680
|
"yapout_bundle",
|
|
@@ -2440,11 +2685,11 @@ function registerBundleTool(server, ctx) {
|
|
|
2440
2685
|
},
|
|
2441
2686
|
async (args) => {
|
|
2442
2687
|
const result = await ctx.client.mutation(
|
|
2443
|
-
|
|
2688
|
+
anyApi4.functions.bundles.createBundle,
|
|
2444
2689
|
{ leadFindingId: args.withFinding, joiningFindingId: args.findingId }
|
|
2445
2690
|
);
|
|
2446
2691
|
const bundledBrief = await ctx.client.query(
|
|
2447
|
-
|
|
2692
|
+
anyApi4.functions.bundles.getBundledBrief,
|
|
2448
2693
|
{ bundleId: result.bundleId }
|
|
2449
2694
|
);
|
|
2450
2695
|
if (!bundledBrief) {
|
|
@@ -2482,9 +2727,9 @@ function registerBundleTool(server, ctx) {
|
|
|
2482
2727
|
sections.push("## Project Context", "", bundledBrief.projectContext);
|
|
2483
2728
|
}
|
|
2484
2729
|
const combinedBrief = sections.join("\n");
|
|
2485
|
-
const yapoutDir =
|
|
2486
|
-
if (!
|
|
2487
|
-
|
|
2730
|
+
const yapoutDir = join10(ctx.cwd, ".yapout");
|
|
2731
|
+
if (!existsSync9(yapoutDir)) mkdirSync7(yapoutDir, { recursive: true });
|
|
2732
|
+
writeFileSync9(join10(yapoutDir, "brief.md"), combinedBrief);
|
|
2488
2733
|
return {
|
|
2489
2734
|
content: [
|
|
2490
2735
|
{
|
|
@@ -2541,7 +2786,7 @@ After calling this tool, you should:
|
|
|
2541
2786
|
}
|
|
2542
2787
|
try {
|
|
2543
2788
|
const result = await ctx.client.mutation(
|
|
2544
|
-
|
|
2789
|
+
anyApi4.functions.localPipeline.claimForEnrichment,
|
|
2545
2790
|
{
|
|
2546
2791
|
projectId,
|
|
2547
2792
|
...args.findingId ? { findingId: args.findingId } : {}
|
|
@@ -2601,7 +2846,7 @@ function registerGetExistingFindingsTool(server, ctx) {
|
|
|
2601
2846
|
}
|
|
2602
2847
|
try {
|
|
2603
2848
|
const findings = await ctx.client.query(
|
|
2604
|
-
|
|
2849
|
+
anyApi4.functions.localPipeline.getExistingFindingTitles,
|
|
2605
2850
|
{ projectId }
|
|
2606
2851
|
);
|
|
2607
2852
|
if (!findings || findings.length === 0) {
|
|
@@ -2703,7 +2948,7 @@ The finding transitions: enriching \u2192 enriched \u2192 ready.`,
|
|
|
2703
2948
|
async (args) => {
|
|
2704
2949
|
try {
|
|
2705
2950
|
await ctx.client.mutation(
|
|
2706
|
-
|
|
2951
|
+
anyApi4.functions.localPipeline.saveLocalEnrichment,
|
|
2707
2952
|
{
|
|
2708
2953
|
findingId: args.findingId,
|
|
2709
2954
|
title: args.title,
|
|
@@ -2718,11 +2963,11 @@ The finding transitions: enriching \u2192 enriched \u2192 ready.`,
|
|
|
2718
2963
|
}
|
|
2719
2964
|
);
|
|
2720
2965
|
await ctx.client.action(
|
|
2721
|
-
|
|
2966
|
+
anyApi4.functions.localPipeline.syncFindingToLinearLocal,
|
|
2722
2967
|
{ findingId: args.findingId }
|
|
2723
2968
|
);
|
|
2724
2969
|
const finding = await ctx.client.query(
|
|
2725
|
-
|
|
2970
|
+
anyApi4.functions.findings.getFinding,
|
|
2726
2971
|
{ findingId: args.findingId }
|
|
2727
2972
|
);
|
|
2728
2973
|
if (args.sessionId) {
|
|
@@ -2781,7 +3026,7 @@ function registerSyncToLinearTool(server, ctx) {
|
|
|
2781
3026
|
async (args) => {
|
|
2782
3027
|
try {
|
|
2783
3028
|
await ctx.client.action(
|
|
2784
|
-
|
|
3029
|
+
anyApi4.functions.localPipeline.syncFindingToLinearLocal,
|
|
2785
3030
|
{ findingId: args.findingId }
|
|
2786
3031
|
);
|
|
2787
3032
|
return {
|
|
@@ -2839,7 +3084,7 @@ function registerSubmitYapSessionTool(server, ctx) {
|
|
|
2839
3084
|
}
|
|
2840
3085
|
try {
|
|
2841
3086
|
const captureId = await ctx.client.mutation(
|
|
2842
|
-
|
|
3087
|
+
anyApi4.functions.captures.createFromYapSession,
|
|
2843
3088
|
{
|
|
2844
3089
|
projectId: ctx.projectId,
|
|
2845
3090
|
title: args.title,
|
|
@@ -3115,7 +3360,7 @@ function registerExtractFromYapTool(server, ctx) {
|
|
|
3115
3360
|
}
|
|
3116
3361
|
try {
|
|
3117
3362
|
const result = await ctx.client.mutation(
|
|
3118
|
-
|
|
3363
|
+
anyApi4.functions.captures.extractFromYapSession,
|
|
3119
3364
|
{
|
|
3120
3365
|
projectId: ctx.projectId,
|
|
3121
3366
|
title: args.sessionTitle,
|
|
@@ -3227,7 +3472,7 @@ full spec \u2014 schema changes, files to modify, edge cases, and acceptance cri
|
|
|
3227
3472
|
}
|
|
3228
3473
|
try {
|
|
3229
3474
|
const result = await ctx.client.mutation(
|
|
3230
|
-
|
|
3475
|
+
anyApi4.functions.localPipeline.decomposeIntoBundle,
|
|
3231
3476
|
{
|
|
3232
3477
|
findingId: args.findingId,
|
|
3233
3478
|
bundleDescription: args.bundleDescription,
|
|
@@ -3300,7 +3545,7 @@ The finding must be in "enriching" or "enriched" status. It will be transitioned
|
|
|
3300
3545
|
}
|
|
3301
3546
|
try {
|
|
3302
3547
|
const result = await ctx.client.mutation(
|
|
3303
|
-
|
|
3548
|
+
anyApi4.functions.findings.markDuplicate,
|
|
3304
3549
|
{
|
|
3305
3550
|
findingId: args.findingId,
|
|
3306
3551
|
duplicateOfLinearId: args.duplicateOfLinearId,
|
|
@@ -3363,7 +3608,7 @@ and issue counts so you can ask the user for confirmation before creating a new
|
|
|
3363
3608
|
}
|
|
3364
3609
|
try {
|
|
3365
3610
|
const project = await ctx.client.query(
|
|
3366
|
-
|
|
3611
|
+
anyApi4.functions.projects.getProject,
|
|
3367
3612
|
{ projectId: ctx.projectId }
|
|
3368
3613
|
);
|
|
3369
3614
|
if (!project?.linearTeamId) {
|
|
@@ -3378,7 +3623,7 @@ and issue counts so you can ask the user for confirmation before creating a new
|
|
|
3378
3623
|
};
|
|
3379
3624
|
}
|
|
3380
3625
|
const projects = await ctx.client.action(
|
|
3381
|
-
|
|
3626
|
+
anyApi4.functions.linearProjectsMutations.fetchProjectsDetailed,
|
|
3382
3627
|
{ projectId: ctx.projectId, teamId: project.linearTeamId }
|
|
3383
3628
|
);
|
|
3384
3629
|
return {
|
|
@@ -3440,7 +3685,7 @@ Optionally filter by tags, capture, or explicit finding IDs.`,
|
|
|
3440
3685
|
}
|
|
3441
3686
|
try {
|
|
3442
3687
|
const allFindings = await ctx.client.query(
|
|
3443
|
-
|
|
3688
|
+
anyApi4.functions.findings.getProjectFindings,
|
|
3444
3689
|
{ projectId }
|
|
3445
3690
|
);
|
|
3446
3691
|
let drafts = (allFindings ?? []).filter((f) => f.status === "draft");
|
|
@@ -3510,7 +3755,7 @@ When done=true, all findings have been processed.`,
|
|
|
3510
3755
|
if (args.skip && args.skipFindingId) {
|
|
3511
3756
|
try {
|
|
3512
3757
|
await ctx.client.mutation(
|
|
3513
|
-
|
|
3758
|
+
anyApi4.functions.localPipeline.releaseEnrichmentClaim,
|
|
3514
3759
|
{ findingId: args.skipFindingId }
|
|
3515
3760
|
);
|
|
3516
3761
|
updateSessionStats(args.sessionId, {
|
|
@@ -3520,7 +3765,7 @@ When done=true, all findings have been processed.`,
|
|
|
3520
3765
|
}
|
|
3521
3766
|
}
|
|
3522
3767
|
const allFindings = await ctx.client.query(
|
|
3523
|
-
|
|
3768
|
+
anyApi4.functions.findings.getProjectFindings,
|
|
3524
3769
|
{ projectId: session.projectId }
|
|
3525
3770
|
);
|
|
3526
3771
|
let drafts = (allFindings ?? []).filter(
|
|
@@ -3562,7 +3807,7 @@ When done=true, all findings have been processed.`,
|
|
|
3562
3807
|
}
|
|
3563
3808
|
const next = drafts[0];
|
|
3564
3809
|
const claimResult = await ctx.client.mutation(
|
|
3565
|
-
|
|
3810
|
+
anyApi4.functions.localPipeline.claimForEnrichment,
|
|
3566
3811
|
{ projectId: session.projectId, findingId: next._id }
|
|
3567
3812
|
);
|
|
3568
3813
|
if (!claimResult) {
|
|
@@ -3643,7 +3888,7 @@ The bundle and all its findings transition to "enriching" status.`,
|
|
|
3643
3888
|
async (args) => {
|
|
3644
3889
|
try {
|
|
3645
3890
|
const result = await ctx.client.mutation(
|
|
3646
|
-
|
|
3891
|
+
anyApi4.functions.bundles.claimBundleForEnrichment,
|
|
3647
3892
|
{ bundleId: args.bundleId }
|
|
3648
3893
|
);
|
|
3649
3894
|
if (!result) {
|
|
@@ -3702,7 +3947,7 @@ Call yapout_sync_bundle_to_linear afterwards to create the Linear project.`,
|
|
|
3702
3947
|
async (args) => {
|
|
3703
3948
|
try {
|
|
3704
3949
|
await ctx.client.mutation(
|
|
3705
|
-
|
|
3950
|
+
anyApi4.functions.bundles.saveBundleEnrichment,
|
|
3706
3951
|
{
|
|
3707
3952
|
bundleId: args.bundleId,
|
|
3708
3953
|
title: args.title,
|
|
@@ -3761,7 +4006,7 @@ Transitions: enriching \u2192 needs_input. The user sees the blockerReason and q
|
|
|
3761
4006
|
async (args) => {
|
|
3762
4007
|
try {
|
|
3763
4008
|
await ctx.client.mutation(
|
|
3764
|
-
|
|
4009
|
+
anyApi4.functions.localPipeline.blockLocalEnrichment,
|
|
3765
4010
|
{
|
|
3766
4011
|
findingId: args.findingId,
|
|
3767
4012
|
blockerReason: args.blockerReason,
|
|
@@ -3810,7 +4055,7 @@ Same semantics as yapout_block_enrichment but for an entire bundle. Bundle statu
|
|
|
3810
4055
|
async (args) => {
|
|
3811
4056
|
try {
|
|
3812
4057
|
await ctx.client.mutation(
|
|
3813
|
-
|
|
4058
|
+
anyApi4.functions.bundles.blockBundleEnrichment,
|
|
3814
4059
|
{
|
|
3815
4060
|
bundleId: args.bundleId,
|
|
3816
4061
|
blockerReason: args.blockerReason,
|
|
@@ -3878,7 +4123,7 @@ async function startMcpServer() {
|
|
|
3878
4123
|
};
|
|
3879
4124
|
const server = new McpServer({
|
|
3880
4125
|
name: "yapout",
|
|
3881
|
-
version: "0.
|
|
4126
|
+
version: "0.9.0"
|
|
3882
4127
|
});
|
|
3883
4128
|
registerInitTool(server, ctx);
|
|
3884
4129
|
registerCompactTool(server, ctx);
|
|
@@ -3910,40 +4155,40 @@ async function startMcpServer() {
|
|
|
3910
4155
|
}
|
|
3911
4156
|
|
|
3912
4157
|
// src/commands/mcp-server.ts
|
|
3913
|
-
var mcpServerCommand = new
|
|
4158
|
+
var mcpServerCommand = new Command8("mcp-server").description("Start the MCP server (used by Claude Code)").action(async () => {
|
|
3914
4159
|
await startMcpServer();
|
|
3915
4160
|
});
|
|
3916
4161
|
|
|
3917
4162
|
// src/commands/worktrees.ts
|
|
3918
|
-
import { Command as
|
|
3919
|
-
import
|
|
4163
|
+
import { Command as Command9 } from "commander";
|
|
4164
|
+
import chalk9 from "chalk";
|
|
3920
4165
|
import { resolve as resolve6 } from "path";
|
|
3921
|
-
var worktreesCommand = new
|
|
4166
|
+
var worktreesCommand = new Command9("worktrees").description("List active yapout worktrees").action(() => {
|
|
3922
4167
|
const cwd = resolve6(process.cwd());
|
|
3923
4168
|
const worktrees = listWorktrees(cwd);
|
|
3924
4169
|
if (worktrees.length === 0) {
|
|
3925
|
-
console.log(
|
|
4170
|
+
console.log(chalk9.dim("No active yapout worktrees."));
|
|
3926
4171
|
return;
|
|
3927
4172
|
}
|
|
3928
|
-
console.log(
|
|
4173
|
+
console.log(chalk9.bold("Active worktrees:\n"));
|
|
3929
4174
|
for (const wt of worktrees) {
|
|
3930
4175
|
console.log(
|
|
3931
|
-
` ${
|
|
4176
|
+
` ${chalk9.cyan(wt.path)} ${chalk9.green(wt.branch)}` + (wt.ticketId ? ` ${chalk9.dim(`(${wt.ticketId})`)}` : "")
|
|
3932
4177
|
);
|
|
3933
4178
|
}
|
|
3934
4179
|
console.log();
|
|
3935
4180
|
});
|
|
3936
4181
|
|
|
3937
4182
|
// src/commands/clean.ts
|
|
3938
|
-
import { Command as
|
|
3939
|
-
import
|
|
4183
|
+
import { Command as Command10 } from "commander";
|
|
4184
|
+
import chalk10 from "chalk";
|
|
3940
4185
|
import { resolve as resolve7 } from "path";
|
|
3941
|
-
var cleanCommand = new
|
|
4186
|
+
var cleanCommand = new Command10("clean").description("Remove worktrees for completed or failed tickets").action(async () => {
|
|
3942
4187
|
const creds = requireAuth();
|
|
3943
4188
|
const cwd = resolve7(process.cwd());
|
|
3944
4189
|
const worktrees = listWorktrees(cwd);
|
|
3945
4190
|
if (worktrees.length === 0) {
|
|
3946
|
-
console.log(
|
|
4191
|
+
console.log(chalk10.dim("No worktrees to clean."));
|
|
3947
4192
|
return;
|
|
3948
4193
|
}
|
|
3949
4194
|
const client = createConvexClient(creds.token);
|
|
@@ -3959,7 +4204,7 @@ var cleanCommand = new Command9("clean").description("Remove worktrees for compl
|
|
|
3959
4204
|
if (isStale) {
|
|
3960
4205
|
const label = ticket ? `${ticket.status}: ${ticket.title}` : "ticket not found";
|
|
3961
4206
|
console.log(
|
|
3962
|
-
|
|
4207
|
+
chalk10.dim(`Removing worktree for ${wt.ticketId} (${label})...`)
|
|
3963
4208
|
);
|
|
3964
4209
|
removeWorktree(cwd, wt.path);
|
|
3965
4210
|
cleaned++;
|
|
@@ -3968,10 +4213,10 @@ var cleanCommand = new Command9("clean").description("Remove worktrees for compl
|
|
|
3968
4213
|
}
|
|
3969
4214
|
}
|
|
3970
4215
|
if (cleaned === 0) {
|
|
3971
|
-
console.log(
|
|
4216
|
+
console.log(chalk10.dim("All worktrees are still active."));
|
|
3972
4217
|
} else {
|
|
3973
4218
|
console.log(
|
|
3974
|
-
|
|
4219
|
+
chalk10.green(
|
|
3975
4220
|
`Cleaned ${cleaned} worktree${cleaned === 1 ? "" : "s"}.`
|
|
3976
4221
|
)
|
|
3977
4222
|
);
|
|
@@ -3979,27 +4224,27 @@ var cleanCommand = new Command9("clean").description("Remove worktrees for compl
|
|
|
3979
4224
|
});
|
|
3980
4225
|
|
|
3981
4226
|
// src/commands/watch.ts
|
|
3982
|
-
import { Command as
|
|
4227
|
+
import { Command as Command11 } from "commander";
|
|
3983
4228
|
import { resolve as resolve8 } from "path";
|
|
3984
4229
|
import {
|
|
3985
|
-
readFileSync as
|
|
3986
|
-
writeFileSync as
|
|
3987
|
-
existsSync as
|
|
3988
|
-
unlinkSync as
|
|
4230
|
+
readFileSync as readFileSync7,
|
|
4231
|
+
writeFileSync as writeFileSync10,
|
|
4232
|
+
existsSync as existsSync11,
|
|
4233
|
+
unlinkSync as unlinkSync4
|
|
3989
4234
|
} from "fs";
|
|
3990
|
-
import { join as
|
|
3991
|
-
import
|
|
4235
|
+
import { join as join12 } from "path";
|
|
4236
|
+
import chalk12 from "chalk";
|
|
3992
4237
|
import { ConvexHttpClient as ConvexHttpClient3 } from "convex/browser";
|
|
3993
4238
|
|
|
3994
4239
|
// src/daemon/watcher.ts
|
|
3995
|
-
import { anyApi as
|
|
4240
|
+
import { anyApi as anyApi6 } from "convex/server";
|
|
3996
4241
|
import { execSync as execSync4 } from "child_process";
|
|
3997
|
-
import { existsSync as
|
|
3998
|
-
import { join as
|
|
4242
|
+
import { existsSync as existsSync10, mkdirSync as mkdirSync8 } from "fs";
|
|
4243
|
+
import { join as join11 } from "path";
|
|
3999
4244
|
import { hostname as osHostname } from "os";
|
|
4000
4245
|
|
|
4001
4246
|
// src/daemon/heartbeat.ts
|
|
4002
|
-
import { anyApi as
|
|
4247
|
+
import { anyApi as anyApi5 } from "convex/server";
|
|
4003
4248
|
var HEARTBEAT_INTERVAL = 3e4;
|
|
4004
4249
|
var Heartbeat = class {
|
|
4005
4250
|
client;
|
|
@@ -4027,14 +4272,14 @@ var Heartbeat = class {
|
|
|
4027
4272
|
if (currentTicketId) args.currentTicketId = currentTicketId;
|
|
4028
4273
|
if (currentBranch) args.currentBranch = currentBranch;
|
|
4029
4274
|
if (worktreePath) args.worktreePath = worktreePath;
|
|
4030
|
-
await this.client.mutation(
|
|
4275
|
+
await this.client.mutation(anyApi5.functions.agents.agentHeartbeat, args);
|
|
4031
4276
|
} catch {
|
|
4032
4277
|
}
|
|
4033
4278
|
}
|
|
4034
4279
|
};
|
|
4035
4280
|
|
|
4036
4281
|
// src/daemon/spawner.ts
|
|
4037
|
-
import { spawn } from "child_process";
|
|
4282
|
+
import { spawn as spawn2 } from "child_process";
|
|
4038
4283
|
|
|
4039
4284
|
// src/daemon/notifications.ts
|
|
4040
4285
|
var notifier = null;
|
|
@@ -4123,7 +4368,7 @@ var Spawner = class {
|
|
|
4123
4368
|
...process.env,
|
|
4124
4369
|
YAPOUT_PROJECT_ID: this.projectId
|
|
4125
4370
|
};
|
|
4126
|
-
const child =
|
|
4371
|
+
const child = spawn2("claude", ["--dangerously-skip-permissions", prompt], {
|
|
4127
4372
|
cwd: worktreePath,
|
|
4128
4373
|
stdio: ["pipe", "pipe", "pipe"],
|
|
4129
4374
|
env,
|
|
@@ -4235,7 +4480,7 @@ var Spawner = class {
|
|
|
4235
4480
|
};
|
|
4236
4481
|
|
|
4237
4482
|
// src/daemon/display.ts
|
|
4238
|
-
import
|
|
4483
|
+
import chalk11 from "chalk";
|
|
4239
4484
|
function formatElapsed(ms) {
|
|
4240
4485
|
const seconds = Math.floor(ms / 1e3);
|
|
4241
4486
|
if (seconds < 60) return `${seconds}s`;
|
|
@@ -4264,35 +4509,35 @@ function render(state) {
|
|
|
4264
4509
|
if (queuedCount > 0) statusParts.push(`${queuedCount} queued`);
|
|
4265
4510
|
const statusLine = statusParts.length > 0 ? statusParts.join(" | ") : "idle";
|
|
4266
4511
|
lines.push(
|
|
4267
|
-
`${
|
|
4512
|
+
`${chalk11.bold("yapout watch")} \u2014 ${state.projectName}`
|
|
4268
4513
|
);
|
|
4269
|
-
lines.push(`${
|
|
4514
|
+
lines.push(`${chalk11.green("Watching")} | ${statusLine}`);
|
|
4270
4515
|
lines.push("");
|
|
4271
4516
|
for (const agent of state.activeAgents) {
|
|
4272
4517
|
const elapsed = formatElapsed(now - agent.startedAt);
|
|
4273
|
-
const wt = agent.worktree ?
|
|
4518
|
+
const wt = agent.worktree ? chalk11.dim(`worktree/${agent.ticketRef.toLowerCase()}`) : "";
|
|
4274
4519
|
lines.push(
|
|
4275
|
-
` ${
|
|
4520
|
+
` ${chalk11.green("\u25CF")} ${chalk11.bold(agent.ticketRef)} ${chalk11.dim(truncate2(`"${agent.title}"`, 35))} ${chalk11.yellow(agent.phase)} ${wt} ${chalk11.dim(elapsed)}`
|
|
4276
4521
|
);
|
|
4277
4522
|
}
|
|
4278
4523
|
for (const ticket of state.queuedTickets) {
|
|
4279
4524
|
lines.push(
|
|
4280
|
-
` ${
|
|
4525
|
+
` ${chalk11.dim("\u25CB")} ${chalk11.bold(ticket.ticketRef)} ${chalk11.dim(truncate2(`"${ticket.title}"`, 35))} ${chalk11.dim("queued")}`
|
|
4281
4526
|
);
|
|
4282
4527
|
}
|
|
4283
4528
|
if (state.activeAgents.length > 0 || state.queuedTickets.length > 0) {
|
|
4284
4529
|
lines.push("");
|
|
4285
4530
|
}
|
|
4286
4531
|
if (state.recentEvents.length > 0) {
|
|
4287
|
-
lines.push(
|
|
4532
|
+
lines.push(chalk11.dim("Recent:"));
|
|
4288
4533
|
for (const event of state.recentEvents.slice(0, 8)) {
|
|
4289
4534
|
lines.push(
|
|
4290
|
-
` ${
|
|
4535
|
+
` ${chalk11.dim(formatTime(event.time))} ${event.icon} ${event.message}`
|
|
4291
4536
|
);
|
|
4292
4537
|
}
|
|
4293
4538
|
lines.push("");
|
|
4294
4539
|
}
|
|
4295
|
-
lines.push(
|
|
4540
|
+
lines.push(chalk11.dim("Ctrl+C to stop (agents will finish)"));
|
|
4296
4541
|
return lines.join("\n");
|
|
4297
4542
|
}
|
|
4298
4543
|
function clearAndRender(state) {
|
|
@@ -4334,7 +4579,7 @@ var Watcher = class {
|
|
|
4334
4579
|
);
|
|
4335
4580
|
process.exit(1);
|
|
4336
4581
|
}
|
|
4337
|
-
await this.client.mutation(
|
|
4582
|
+
await this.client.mutation(anyApi6.functions.agents.registerAgent, {
|
|
4338
4583
|
projectId: this.options.projectId,
|
|
4339
4584
|
sessionId: this.sessionId,
|
|
4340
4585
|
machineHostname: this.getHostname()
|
|
@@ -4370,7 +4615,7 @@ Waiting for ${this.spawner.activeCount} agent(s) to finish...`
|
|
|
4370
4615
|
await this.spawner.gracefulShutdown();
|
|
4371
4616
|
}
|
|
4372
4617
|
try {
|
|
4373
|
-
await this.client.mutation(
|
|
4618
|
+
await this.client.mutation(anyApi6.functions.agents.unregisterAgent, {
|
|
4374
4619
|
sessionId: this.sessionId
|
|
4375
4620
|
});
|
|
4376
4621
|
} catch {
|
|
@@ -4384,7 +4629,7 @@ Waiting for ${this.spawner.activeCount} agent(s) to finish...`
|
|
|
4384
4629
|
}
|
|
4385
4630
|
this.heartbeat.stop();
|
|
4386
4631
|
this.spawner.forceKill();
|
|
4387
|
-
this.client.mutation(
|
|
4632
|
+
this.client.mutation(anyApi6.functions.agents.unregisterAgent, {
|
|
4388
4633
|
sessionId: this.sessionId
|
|
4389
4634
|
}).catch(() => {
|
|
4390
4635
|
});
|
|
@@ -4426,7 +4671,7 @@ Waiting for ${this.spawner.activeCount} agent(s) to finish...`
|
|
|
4426
4671
|
}
|
|
4427
4672
|
async checkForEnrichmentWork(maxSlots) {
|
|
4428
4673
|
const tickets = await this.client.query(
|
|
4429
|
-
|
|
4674
|
+
anyApi6.functions.localPipeline.getUnenrichedTickets,
|
|
4430
4675
|
{ projectId: this.options.projectId }
|
|
4431
4676
|
);
|
|
4432
4677
|
if (!tickets || tickets.length === 0) return;
|
|
@@ -4455,7 +4700,7 @@ Waiting for ${this.spawner.activeCount} agent(s) to finish...`
|
|
|
4455
4700
|
}
|
|
4456
4701
|
async checkForImplementationWork(maxSlots) {
|
|
4457
4702
|
const data = await this.client.query(
|
|
4458
|
-
|
|
4703
|
+
anyApi6.functions.tickets.getLocalQueuedTickets,
|
|
4459
4704
|
{ projectId: this.options.projectId }
|
|
4460
4705
|
);
|
|
4461
4706
|
if (!data || data.ready.length === 0) return;
|
|
@@ -4487,10 +4732,10 @@ Waiting for ${this.spawner.activeCount} agent(s) to finish...`
|
|
|
4487
4732
|
}
|
|
4488
4733
|
ensureEnrichWorktree() {
|
|
4489
4734
|
const wtDir = getWorktreesDir(this.options.cwd);
|
|
4490
|
-
const enrichPath =
|
|
4491
|
-
if (
|
|
4735
|
+
const enrichPath = join11(wtDir, "_enrich");
|
|
4736
|
+
if (existsSync10(enrichPath)) return enrichPath;
|
|
4492
4737
|
try {
|
|
4493
|
-
if (!
|
|
4738
|
+
if (!existsSync10(wtDir)) mkdirSync8(wtDir, { recursive: true });
|
|
4494
4739
|
const defaultBranch = getDefaultBranch(this.options.cwd);
|
|
4495
4740
|
execSync4(
|
|
4496
4741
|
`git worktree add "${enrichPath}" origin/${defaultBranch}`,
|
|
@@ -4528,7 +4773,7 @@ Waiting for ${this.spawner.activeCount} agent(s) to finish...`
|
|
|
4528
4773
|
if (wt.ticketId) {
|
|
4529
4774
|
try {
|
|
4530
4775
|
const ticket = await this.client.query(
|
|
4531
|
-
|
|
4776
|
+
anyApi6.functions.tickets.getTicket,
|
|
4532
4777
|
{ ticketId: wt.ticketId }
|
|
4533
4778
|
);
|
|
4534
4779
|
if (ticket && (ticket.status === "failed" || ticket.status === "workflow2_done")) {
|
|
@@ -4593,38 +4838,38 @@ Waiting for ${this.spawner.activeCount} agent(s) to finish...`
|
|
|
4593
4838
|
};
|
|
4594
4839
|
|
|
4595
4840
|
// src/commands/watch.ts
|
|
4596
|
-
var
|
|
4597
|
-
var
|
|
4598
|
-
var watchCommand = new
|
|
4841
|
+
var PID_FILE2 = join12(getYapoutDir(), "watch.pid");
|
|
4842
|
+
var LOG_FILE2 = join12(getYapoutDir(), "watch.log");
|
|
4843
|
+
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
4844
|
if (opts.status) {
|
|
4600
|
-
if (
|
|
4601
|
-
const pid = parseInt(
|
|
4602
|
-
if (
|
|
4845
|
+
if (existsSync11(PID_FILE2)) {
|
|
4846
|
+
const pid = parseInt(readFileSync7(PID_FILE2, "utf-8").trim(), 10);
|
|
4847
|
+
if (isProcessRunning2(pid)) {
|
|
4603
4848
|
console.log(
|
|
4604
|
-
|
|
4849
|
+
chalk12.green("Watcher is running") + chalk12.dim(` (PID ${pid})`)
|
|
4605
4850
|
);
|
|
4606
4851
|
} else {
|
|
4607
|
-
console.log(
|
|
4608
|
-
|
|
4852
|
+
console.log(chalk12.dim("Watcher is not running (stale PID file)"));
|
|
4853
|
+
unlinkSync4(PID_FILE2);
|
|
4609
4854
|
}
|
|
4610
4855
|
} else {
|
|
4611
|
-
console.log(
|
|
4856
|
+
console.log(chalk12.dim("Watcher is not running"));
|
|
4612
4857
|
}
|
|
4613
4858
|
return;
|
|
4614
4859
|
}
|
|
4615
4860
|
if (opts.stop) {
|
|
4616
|
-
if (!
|
|
4617
|
-
console.log(
|
|
4861
|
+
if (!existsSync11(PID_FILE2)) {
|
|
4862
|
+
console.log(chalk12.dim("No watcher running"));
|
|
4618
4863
|
return;
|
|
4619
4864
|
}
|
|
4620
|
-
const pid = parseInt(
|
|
4865
|
+
const pid = parseInt(readFileSync7(PID_FILE2, "utf-8").trim(), 10);
|
|
4621
4866
|
try {
|
|
4622
4867
|
process.kill(pid, "SIGTERM");
|
|
4623
|
-
console.log(
|
|
4868
|
+
console.log(chalk12.green(`Stopped watcher (PID ${pid})`));
|
|
4624
4869
|
} catch {
|
|
4625
|
-
console.log(
|
|
4870
|
+
console.log(chalk12.dim("Watcher already stopped"));
|
|
4626
4871
|
}
|
|
4627
|
-
|
|
4872
|
+
unlinkSync4(PID_FILE2);
|
|
4628
4873
|
return;
|
|
4629
4874
|
}
|
|
4630
4875
|
const creds = requireAuth();
|
|
@@ -4632,7 +4877,7 @@ var watchCommand = new Command10("watch").description("Watch for work and spawn
|
|
|
4632
4877
|
const mapping = getProjectMapping(cwd);
|
|
4633
4878
|
if (!mapping) {
|
|
4634
4879
|
console.error(
|
|
4635
|
-
|
|
4880
|
+
chalk12.red("No project linked.") + " Run " + chalk12.cyan("yapout link") + " in a repo."
|
|
4636
4881
|
);
|
|
4637
4882
|
process.exit(1);
|
|
4638
4883
|
}
|
|
@@ -4640,16 +4885,16 @@ var watchCommand = new Command10("watch").description("Watch for work and spawn
|
|
|
4640
4885
|
const client = new ConvexHttpClient3(getConvexUrl());
|
|
4641
4886
|
client.setAuth(creds.token);
|
|
4642
4887
|
if (opts.bg) {
|
|
4643
|
-
|
|
4888
|
+
writeFileSync10(PID_FILE2, process.pid.toString());
|
|
4644
4889
|
console.log(
|
|
4645
|
-
|
|
4890
|
+
chalk12.green("Watcher started in background") + chalk12.dim(` (PID ${process.pid}, log: ${LOG_FILE2})`)
|
|
4646
4891
|
);
|
|
4647
4892
|
}
|
|
4648
|
-
console.log(
|
|
4893
|
+
console.log(chalk12.bold(`yapout watch v${"0.9.0"}`));
|
|
4649
4894
|
console.log(
|
|
4650
|
-
`Project: ${
|
|
4895
|
+
`Project: ${chalk12.green(mapping.projectName)} (${mapping.projectId})`
|
|
4651
4896
|
);
|
|
4652
|
-
console.log(
|
|
4897
|
+
console.log(chalk12.dim("Watching..."));
|
|
4653
4898
|
console.log();
|
|
4654
4899
|
const watcher = new Watcher(
|
|
4655
4900
|
{
|
|
@@ -4666,17 +4911,17 @@ var watchCommand = new Command10("watch").description("Watch for work and spawn
|
|
|
4666
4911
|
const shutdown = async () => {
|
|
4667
4912
|
if (shuttingDown) {
|
|
4668
4913
|
watcher.forceStop();
|
|
4669
|
-
if (
|
|
4914
|
+
if (existsSync11(PID_FILE2)) unlinkSync4(PID_FILE2);
|
|
4670
4915
|
process.exit(0);
|
|
4671
4916
|
}
|
|
4672
4917
|
shuttingDown = true;
|
|
4673
|
-
console.log(
|
|
4918
|
+
console.log(chalk12.dim("\nShutting down..."));
|
|
4674
4919
|
if (opts.force) {
|
|
4675
4920
|
watcher.forceStop();
|
|
4676
4921
|
} else {
|
|
4677
4922
|
await watcher.stop();
|
|
4678
4923
|
}
|
|
4679
|
-
if (
|
|
4924
|
+
if (existsSync11(PID_FILE2)) unlinkSync4(PID_FILE2);
|
|
4680
4925
|
process.exit(0);
|
|
4681
4926
|
};
|
|
4682
4927
|
process.on("SIGINT", () => {
|
|
@@ -4689,7 +4934,7 @@ var watchCommand = new Command10("watch").description("Watch for work and spawn
|
|
|
4689
4934
|
await new Promise(() => {
|
|
4690
4935
|
});
|
|
4691
4936
|
});
|
|
4692
|
-
function
|
|
4937
|
+
function isProcessRunning2(pid) {
|
|
4693
4938
|
try {
|
|
4694
4939
|
process.kill(pid, 0);
|
|
4695
4940
|
return true;
|
|
@@ -4699,88 +4944,88 @@ function isProcessRunning(pid) {
|
|
|
4699
4944
|
}
|
|
4700
4945
|
|
|
4701
4946
|
// src/commands/queue.ts
|
|
4702
|
-
import { Command as
|
|
4947
|
+
import { Command as Command12 } from "commander";
|
|
4703
4948
|
import { resolve as resolve9 } from "path";
|
|
4704
|
-
import
|
|
4705
|
-
var queueCommand = new
|
|
4949
|
+
import chalk13 from "chalk";
|
|
4950
|
+
var queueCommand = new Command12("queue").description("Show pipeline state \u2014 what's ready, blocked, and pending").action(async () => {
|
|
4706
4951
|
const creds = requireAuth();
|
|
4707
4952
|
const cwd = resolve9(process.cwd());
|
|
4708
4953
|
const mapping = getProjectMapping(cwd);
|
|
4709
4954
|
if (!mapping) {
|
|
4710
4955
|
console.error(
|
|
4711
|
-
|
|
4956
|
+
chalk13.red("No project linked.") + " Run " + chalk13.cyan("yapout link") + " in a repo."
|
|
4712
4957
|
);
|
|
4713
4958
|
process.exit(1);
|
|
4714
4959
|
}
|
|
4715
4960
|
const client = createConvexClient(creds.token);
|
|
4716
|
-
const { anyApi:
|
|
4961
|
+
const { anyApi: anyApi7 } = await import("convex/server");
|
|
4717
4962
|
const [queueData, unenriched, pending] = await Promise.all([
|
|
4718
|
-
client.query(
|
|
4963
|
+
client.query(anyApi7.functions.tickets.getLocalQueuedTickets, {
|
|
4719
4964
|
projectId: mapping.projectId
|
|
4720
4965
|
}),
|
|
4721
|
-
client.query(
|
|
4966
|
+
client.query(anyApi7.functions.localPipeline.getUnenrichedTickets, {
|
|
4722
4967
|
projectId: mapping.projectId
|
|
4723
4968
|
}),
|
|
4724
|
-
client.query(
|
|
4969
|
+
client.query(anyApi7.functions.localPipeline.getPendingSources, {
|
|
4725
4970
|
projectId: mapping.projectId
|
|
4726
4971
|
})
|
|
4727
4972
|
]);
|
|
4728
4973
|
console.log();
|
|
4729
4974
|
if (queueData?.ready && queueData.ready.length > 0) {
|
|
4730
|
-
console.log(
|
|
4975
|
+
console.log(chalk13.bold("Ready to implement:"));
|
|
4731
4976
|
for (const t of queueData.ready) {
|
|
4732
4977
|
const ref = t.linearTicketId ?? t.ticketId;
|
|
4733
4978
|
const prio = colorPriority(t.priority);
|
|
4734
4979
|
console.log(
|
|
4735
|
-
` ${
|
|
4980
|
+
` ${chalk13.bold(ref)} ${t.title.slice(0, 45).padEnd(45)} ${prio} ${chalk13.dim(t.type)}`
|
|
4736
4981
|
);
|
|
4737
4982
|
}
|
|
4738
4983
|
console.log();
|
|
4739
4984
|
}
|
|
4740
4985
|
if (queueData?.blocked && queueData.blocked.length > 0) {
|
|
4741
|
-
console.log(
|
|
4986
|
+
console.log(chalk13.bold("Blocked:"));
|
|
4742
4987
|
for (const t of queueData.blocked) {
|
|
4743
4988
|
console.log(
|
|
4744
|
-
` ${
|
|
4989
|
+
` ${chalk13.bold(t.ticketId.slice(-6))} ${t.title.slice(0, 45)} ${chalk13.red("blocked by " + t.blockedBy.map((id) => id.slice(-6)).join(", "))}`
|
|
4745
4990
|
);
|
|
4746
4991
|
}
|
|
4747
4992
|
console.log();
|
|
4748
4993
|
}
|
|
4749
4994
|
if (unenriched && unenriched.length > 0) {
|
|
4750
|
-
console.log(
|
|
4995
|
+
console.log(chalk13.bold("Needs enrichment:"));
|
|
4751
4996
|
for (const t of unenriched) {
|
|
4752
4997
|
const ref = t.ticketId;
|
|
4753
4998
|
console.log(
|
|
4754
|
-
` ${
|
|
4999
|
+
` ${chalk13.bold(ref.slice(-6))} ${t.title.slice(0, 45).padEnd(45)} ${chalk13.dim(t.priority)}`
|
|
4755
5000
|
);
|
|
4756
5001
|
}
|
|
4757
5002
|
console.log();
|
|
4758
5003
|
}
|
|
4759
5004
|
if (pending && pending.length > 0) {
|
|
4760
|
-
console.log(
|
|
5005
|
+
console.log(chalk13.bold("Pending extraction:"));
|
|
4761
5006
|
for (const t of pending) {
|
|
4762
5007
|
const ago = formatAgo(Date.now() - t.createdAt);
|
|
4763
5008
|
console.log(
|
|
4764
|
-
` "${t.meetingTitle ?? "Untitled"}" ${
|
|
5009
|
+
` "${t.meetingTitle ?? "Untitled"}" ${chalk13.dim(`(uploaded ${ago})`)}`
|
|
4765
5010
|
);
|
|
4766
5011
|
}
|
|
4767
5012
|
console.log();
|
|
4768
5013
|
}
|
|
4769
5014
|
if ((!queueData?.ready || queueData.ready.length === 0) && (!unenriched || unenriched.length === 0) && (!pending || pending.length === 0)) {
|
|
4770
|
-
console.log(
|
|
5015
|
+
console.log(chalk13.dim("Queue is empty. Upload a transcript to get started."));
|
|
4771
5016
|
console.log();
|
|
4772
5017
|
}
|
|
4773
5018
|
});
|
|
4774
5019
|
function colorPriority(p) {
|
|
4775
5020
|
switch (p) {
|
|
4776
5021
|
case "urgent":
|
|
4777
|
-
return
|
|
5022
|
+
return chalk13.red(p);
|
|
4778
5023
|
case "high":
|
|
4779
|
-
return
|
|
5024
|
+
return chalk13.yellow(p);
|
|
4780
5025
|
case "medium":
|
|
4781
|
-
return
|
|
5026
|
+
return chalk13.white(p);
|
|
4782
5027
|
case "low":
|
|
4783
|
-
return
|
|
5028
|
+
return chalk13.dim(p);
|
|
4784
5029
|
default:
|
|
4785
5030
|
return p;
|
|
4786
5031
|
}
|
|
@@ -4796,29 +5041,29 @@ function formatAgo(ms) {
|
|
|
4796
5041
|
}
|
|
4797
5042
|
|
|
4798
5043
|
// src/commands/next.ts
|
|
4799
|
-
import { Command as
|
|
5044
|
+
import { Command as Command13 } from "commander";
|
|
4800
5045
|
import { resolve as resolve10 } from "path";
|
|
4801
|
-
import { writeFileSync as
|
|
4802
|
-
import { join as
|
|
4803
|
-
import
|
|
4804
|
-
var nextCommand = new
|
|
5046
|
+
import { writeFileSync as writeFileSync11 } from "fs";
|
|
5047
|
+
import { join as join13 } from "path";
|
|
5048
|
+
import chalk14 from "chalk";
|
|
5049
|
+
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
5050
|
const creds = requireAuth();
|
|
4806
5051
|
const cwd = resolve10(process.cwd());
|
|
4807
5052
|
const mapping = getProjectMapping(cwd);
|
|
4808
5053
|
if (!mapping) {
|
|
4809
5054
|
console.error(
|
|
4810
|
-
|
|
5055
|
+
chalk14.red("No project linked.") + " Run " + chalk14.cyan("yapout link") + " in a repo."
|
|
4811
5056
|
);
|
|
4812
5057
|
process.exit(1);
|
|
4813
5058
|
}
|
|
4814
5059
|
const client = createConvexClient(creds.token);
|
|
4815
|
-
const { anyApi:
|
|
5060
|
+
const { anyApi: anyApi7 } = await import("convex/server");
|
|
4816
5061
|
const data = await client.query(
|
|
4817
|
-
|
|
5062
|
+
anyApi7.functions.tickets.getLocalQueuedTickets,
|
|
4818
5063
|
{ projectId: mapping.projectId }
|
|
4819
5064
|
);
|
|
4820
5065
|
if (!data?.ready || data.ready.length === 0) {
|
|
4821
|
-
console.log(
|
|
5066
|
+
console.log(chalk14.dim("No tickets ready for implementation."));
|
|
4822
5067
|
return;
|
|
4823
5068
|
}
|
|
4824
5069
|
const ticket = data.ready[0];
|
|
@@ -4826,32 +5071,32 @@ var nextCommand = new Command12("next").description("Claim the highest priority
|
|
|
4826
5071
|
const config = readYapoutConfig(cwd);
|
|
4827
5072
|
const defaultBranch = getDefaultBranch(cwd);
|
|
4828
5073
|
const branchName = `${config.branch_prefix}/${ref.toLowerCase().replace(/\s+/g, "-")}-${ticket.title.toLowerCase().replace(/[^a-z0-9]+/g, "-").slice(0, 40)}`;
|
|
4829
|
-
console.log(
|
|
5074
|
+
console.log(chalk14.bold(`
|
|
4830
5075
|
Claimed: ${ref} "${ticket.title}"`));
|
|
4831
5076
|
fetchOrigin(cwd);
|
|
4832
5077
|
let workDir = cwd;
|
|
4833
5078
|
if (opts.worktree) {
|
|
4834
5079
|
const { createWorktree: createWorktree2 } = await import("./worktree-ZZZIL7TK.js");
|
|
4835
5080
|
workDir = createWorktree2(cwd, ticket.ticketId, branchName, defaultBranch);
|
|
4836
|
-
console.log(`Worktree: ${
|
|
5081
|
+
console.log(`Worktree: ${chalk14.cyan(workDir)}`);
|
|
4837
5082
|
} else {
|
|
4838
5083
|
checkoutNewBranch(branchName, defaultBranch, cwd);
|
|
4839
5084
|
}
|
|
4840
|
-
console.log(`Branch: ${
|
|
5085
|
+
console.log(`Branch: ${chalk14.cyan(branchName)}`);
|
|
4841
5086
|
const brief = await client.query(
|
|
4842
|
-
|
|
5087
|
+
anyApi7.functions.tickets.getTicketBrief,
|
|
4843
5088
|
{ ticketId: ticket.ticketId }
|
|
4844
5089
|
);
|
|
4845
5090
|
if (brief) {
|
|
4846
|
-
const briefPath =
|
|
5091
|
+
const briefPath = join13(workDir, ".yapout", "brief.md");
|
|
4847
5092
|
const briefContent = formatBrief(ref, ticket, brief);
|
|
4848
|
-
|
|
4849
|
-
console.log(`Brief: ${
|
|
5093
|
+
writeFileSync11(briefPath, briefContent);
|
|
5094
|
+
console.log(`Brief: ${chalk14.cyan(briefPath)}`);
|
|
4850
5095
|
}
|
|
4851
5096
|
console.log();
|
|
4852
5097
|
console.log("Start Claude Code to implement, or run:");
|
|
4853
5098
|
console.log(
|
|
4854
|
-
|
|
5099
|
+
chalk14.cyan(
|
|
4855
5100
|
` claude --dangerously-skip-permissions "Read .yapout/brief.md, implement it, run yapout_check, then yapout_ship"`
|
|
4856
5101
|
)
|
|
4857
5102
|
);
|
|
@@ -4901,21 +5146,21 @@ function formatBrief(ref, ticket, brief) {
|
|
|
4901
5146
|
}
|
|
4902
5147
|
|
|
4903
5148
|
// src/commands/recap.ts
|
|
4904
|
-
import { Command as
|
|
5149
|
+
import { Command as Command14 } from "commander";
|
|
4905
5150
|
import { resolve as resolve11 } from "path";
|
|
4906
|
-
import
|
|
4907
|
-
var recapCommand = new
|
|
5151
|
+
import chalk15 from "chalk";
|
|
5152
|
+
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
5153
|
const creds = requireAuth();
|
|
4909
5154
|
const cwd = resolve11(process.cwd());
|
|
4910
5155
|
const mapping = getProjectMapping(cwd);
|
|
4911
5156
|
if (!mapping) {
|
|
4912
5157
|
console.error(
|
|
4913
|
-
|
|
5158
|
+
chalk15.red("No project linked.") + " Run " + chalk15.cyan("yapout link") + " in a repo."
|
|
4914
5159
|
);
|
|
4915
5160
|
process.exit(1);
|
|
4916
5161
|
}
|
|
4917
5162
|
const client = createConvexClient(creds.token);
|
|
4918
|
-
const { anyApi:
|
|
5163
|
+
const { anyApi: anyApi7 } = await import("convex/server");
|
|
4919
5164
|
const now = /* @__PURE__ */ new Date();
|
|
4920
5165
|
const todayStart = new Date(
|
|
4921
5166
|
now.getFullYear(),
|
|
@@ -4925,33 +5170,33 @@ var recapCommand = new Command13("recap").description("Show a summary of recent
|
|
|
4925
5170
|
const weekStart = todayStart - 6 * 24 * 60 * 60 * 1e3;
|
|
4926
5171
|
const since = opts.week ? weekStart : todayStart;
|
|
4927
5172
|
const data = await client.query(
|
|
4928
|
-
|
|
5173
|
+
anyApi7.functions.localPipeline.getRecentActivity,
|
|
4929
5174
|
{ projectId: mapping.projectId, since }
|
|
4930
5175
|
);
|
|
4931
5176
|
if (!data) {
|
|
4932
|
-
console.log(
|
|
5177
|
+
console.log(chalk15.dim("Could not fetch activity data."));
|
|
4933
5178
|
return;
|
|
4934
5179
|
}
|
|
4935
5180
|
const period = opts.week ? "This week" : "Today";
|
|
4936
5181
|
console.log();
|
|
4937
|
-
console.log(
|
|
5182
|
+
console.log(chalk15.bold(`${period}:`));
|
|
4938
5183
|
if (data.recentTickets.length > 0) {
|
|
4939
5184
|
for (const t of data.recentTickets) {
|
|
4940
5185
|
const ref = t.linearTicketId ?? "ticket";
|
|
4941
|
-
console.log(` ${
|
|
5186
|
+
console.log(` ${chalk15.green("\u2713")} ${ref} ${t.title}`);
|
|
4942
5187
|
}
|
|
4943
5188
|
}
|
|
4944
5189
|
if (data.recentPRs.length > 0) {
|
|
4945
5190
|
for (const p of data.recentPRs) {
|
|
4946
5191
|
const prRef = p.githubPrNumber ? `PR #${p.githubPrNumber}` : "PR";
|
|
4947
|
-
const statusColor = p.status === "opened" ?
|
|
5192
|
+
const statusColor = p.status === "opened" ? chalk15.green : p.status === "draft" ? chalk15.dim : chalk15.yellow;
|
|
4948
5193
|
console.log(
|
|
4949
5194
|
` ${statusColor("\u2191")} ${p.prTitle.slice(0, 45)} ${statusColor(prRef)} ${statusColor(p.status)}`
|
|
4950
5195
|
);
|
|
4951
5196
|
}
|
|
4952
5197
|
}
|
|
4953
5198
|
if (data.recentTickets.length === 0 && data.recentPRs.length === 0) {
|
|
4954
|
-
console.log(
|
|
5199
|
+
console.log(chalk15.dim(" No activity yet."));
|
|
4955
5200
|
}
|
|
4956
5201
|
console.log();
|
|
4957
5202
|
console.log(
|
|
@@ -4961,12 +5206,12 @@ var recapCommand = new Command13("recap").description("Show a summary of recent
|
|
|
4961
5206
|
});
|
|
4962
5207
|
|
|
4963
5208
|
// src/commands/yap.ts
|
|
4964
|
-
import { Command as
|
|
4965
|
-
import
|
|
4966
|
-
var yapCommand = new
|
|
5209
|
+
import { Command as Command15 } from "commander";
|
|
5210
|
+
import chalk16 from "chalk";
|
|
5211
|
+
var yapCommand = new Command15("yap").description(
|
|
4967
5212
|
"Start a yap session \u2014 brainstorm with an AI that knows your codebase"
|
|
4968
5213
|
).action(() => {
|
|
4969
|
-
console.log(
|
|
5214
|
+
console.log(chalk16.bold("yapout yap sessions"));
|
|
4970
5215
|
console.log();
|
|
4971
5216
|
console.log(
|
|
4972
5217
|
"Yap sessions run inside Claude \u2014 Desktop, CLI, or web \u2014 anywhere the"
|
|
@@ -4975,27 +5220,27 @@ var yapCommand = new Command14("yap").description(
|
|
|
4975
5220
|
console.log();
|
|
4976
5221
|
console.log("Just tell Claude:");
|
|
4977
5222
|
console.log(
|
|
4978
|
-
|
|
5223
|
+
chalk16.green(` "Let's have a yap session about [topic]"`)
|
|
4979
5224
|
);
|
|
4980
5225
|
console.log(
|
|
4981
|
-
|
|
5226
|
+
chalk16.green(
|
|
4982
5227
|
' "I want to brainstorm [idea] \u2014 be a skeptical QA engineer"'
|
|
4983
5228
|
)
|
|
4984
5229
|
);
|
|
4985
5230
|
console.log();
|
|
4986
|
-
console.log(
|
|
5231
|
+
console.log(chalk16.dim("Personas: tech lead, qa engineer, product owner, end user, or custom"));
|
|
4987
5232
|
console.log(
|
|
4988
|
-
|
|
5233
|
+
chalk16.dim(
|
|
4989
5234
|
"Claude will call yapout_start_yap to get instructions and yapout_submit_yap_session when done."
|
|
4990
5235
|
)
|
|
4991
5236
|
);
|
|
4992
5237
|
});
|
|
4993
5238
|
|
|
4994
5239
|
// src/commands/handle-uri.ts
|
|
4995
|
-
import { Command as
|
|
4996
|
-
import { spawn as
|
|
4997
|
-
import { platform as
|
|
4998
|
-
import
|
|
5240
|
+
import { Command as Command16 } from "commander";
|
|
5241
|
+
import { spawn as spawn3 } from "child_process";
|
|
5242
|
+
import { platform as platform3 } from "os";
|
|
5243
|
+
import chalk17 from "chalk";
|
|
4999
5244
|
var VALID_ACTIONS = ["claim", "enrich", "enrich-bulk", "enrich-bundle", "yap", "compact"];
|
|
5000
5245
|
function parseYapoutUri(raw) {
|
|
5001
5246
|
const url = new URL(raw);
|
|
@@ -5108,11 +5353,11 @@ function findProjectDir() {
|
|
|
5108
5353
|
return dirs[0];
|
|
5109
5354
|
}
|
|
5110
5355
|
function launchTerminal(cwd, claudeArgs) {
|
|
5111
|
-
const os =
|
|
5356
|
+
const os = platform3();
|
|
5112
5357
|
const claudeCmd = `claude ${claudeArgs.map(shellEscape).join(" ")}`;
|
|
5113
5358
|
if (os === "win32") {
|
|
5114
5359
|
const wtArgs = ["wt", "-d", cwd, "cmd", "/k", claudeCmd];
|
|
5115
|
-
const child =
|
|
5360
|
+
const child = spawn3("cmd", ["/c", "start", ...wtArgs], {
|
|
5116
5361
|
cwd,
|
|
5117
5362
|
stdio: "ignore",
|
|
5118
5363
|
detached: true,
|
|
@@ -5120,7 +5365,7 @@ function launchTerminal(cwd, claudeArgs) {
|
|
|
5120
5365
|
});
|
|
5121
5366
|
child.unref();
|
|
5122
5367
|
child.on("error", () => {
|
|
5123
|
-
const fallback =
|
|
5368
|
+
const fallback = spawn3(
|
|
5124
5369
|
"cmd",
|
|
5125
5370
|
["/c", "start", "cmd", "/k", claudeCmd],
|
|
5126
5371
|
{ cwd, stdio: "ignore", detached: true, shell: true }
|
|
@@ -5133,7 +5378,7 @@ function launchTerminal(cwd, claudeArgs) {
|
|
|
5133
5378
|
activate
|
|
5134
5379
|
do script "cd ${shellEscape(cwd)} && ${escaped}"
|
|
5135
5380
|
end tell`;
|
|
5136
|
-
const child =
|
|
5381
|
+
const child = spawn3("osascript", ["-e", script], {
|
|
5137
5382
|
stdio: "ignore",
|
|
5138
5383
|
detached: true
|
|
5139
5384
|
});
|
|
@@ -5148,7 +5393,7 @@ end tell`;
|
|
|
5148
5393
|
let launched = false;
|
|
5149
5394
|
for (const term of terminals) {
|
|
5150
5395
|
try {
|
|
5151
|
-
const child =
|
|
5396
|
+
const child = spawn3(term.cmd, term.args, {
|
|
5152
5397
|
stdio: "ignore",
|
|
5153
5398
|
detached: true
|
|
5154
5399
|
});
|
|
@@ -5161,44 +5406,44 @@ end tell`;
|
|
|
5161
5406
|
}
|
|
5162
5407
|
if (!launched) {
|
|
5163
5408
|
console.error(
|
|
5164
|
-
|
|
5409
|
+
chalk17.red("Could not find a terminal emulator. Install gnome-terminal, konsole, or xterm.")
|
|
5165
5410
|
);
|
|
5166
5411
|
process.exit(1);
|
|
5167
5412
|
}
|
|
5168
5413
|
}
|
|
5169
5414
|
}
|
|
5170
5415
|
function shellEscape(s) {
|
|
5171
|
-
if (
|
|
5416
|
+
if (platform3() === "win32") {
|
|
5172
5417
|
return `"${s.replace(/"/g, '""')}"`;
|
|
5173
5418
|
}
|
|
5174
5419
|
return `'${s.replace(/'/g, "'\\''")}'`;
|
|
5175
5420
|
}
|
|
5176
|
-
var handleUriCommand = new
|
|
5421
|
+
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
5422
|
try {
|
|
5178
5423
|
const parsed = parseYapoutUri(uri);
|
|
5179
5424
|
const prompt = buildPrompt(parsed);
|
|
5180
5425
|
const cwd = findProjectDir();
|
|
5181
5426
|
if (!cwd) {
|
|
5182
5427
|
console.error(
|
|
5183
|
-
|
|
5428
|
+
chalk17.red(
|
|
5184
5429
|
"No linked project found. Run `yapout init` or `yapout link` in your repo first."
|
|
5185
5430
|
)
|
|
5186
5431
|
);
|
|
5187
5432
|
process.exit(1);
|
|
5188
5433
|
}
|
|
5189
5434
|
const label = parsed.ticketId ? `${parsed.action} ${parsed.ticketId}` : parsed.action;
|
|
5190
|
-
console.log(
|
|
5435
|
+
console.log(chalk17.dim(`Launching Claude Code to ${label}...`));
|
|
5191
5436
|
launchTerminal(cwd, ["--dangerously-skip-permissions", prompt]);
|
|
5192
5437
|
setTimeout(() => process.exit(0), 500);
|
|
5193
5438
|
} catch (err) {
|
|
5194
|
-
console.error(
|
|
5439
|
+
console.error(chalk17.red(err.message));
|
|
5195
5440
|
process.exit(1);
|
|
5196
5441
|
}
|
|
5197
5442
|
});
|
|
5198
5443
|
|
|
5199
5444
|
// src/index.ts
|
|
5200
|
-
var program = new
|
|
5201
|
-
program.name("yapout").description("yapout \u2014 from meeting transcript to merged PR").version("0.
|
|
5445
|
+
var program = new Command17();
|
|
5446
|
+
program.name("yapout").description("yapout \u2014 from meeting transcript to merged PR").version("0.9.0");
|
|
5202
5447
|
program.addCommand(loginCommand);
|
|
5203
5448
|
program.addCommand(logoutCommand);
|
|
5204
5449
|
program.addCommand(initCommand);
|
|
@@ -5214,4 +5459,5 @@ program.addCommand(nextCommand);
|
|
|
5214
5459
|
program.addCommand(recapCommand);
|
|
5215
5460
|
program.addCommand(yapCommand);
|
|
5216
5461
|
program.addCommand(handleUriCommand);
|
|
5462
|
+
program.addCommand(serveCommand);
|
|
5217
5463
|
program.parse();
|