yapout 0.5.2 → 0.8.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 +422 -116
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -28,6 +28,75 @@ import {
|
|
|
28
28
|
writeFileSync,
|
|
29
29
|
unlinkSync
|
|
30
30
|
} from "fs";
|
|
31
|
+
|
|
32
|
+
// src/lib/git.ts
|
|
33
|
+
import { execSync } from "child_process";
|
|
34
|
+
import { dirname, isAbsolute, resolve } from "path";
|
|
35
|
+
function git(args, cwd) {
|
|
36
|
+
return execSync(`git ${args}`, { cwd, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
|
|
37
|
+
}
|
|
38
|
+
function resolveRepoRoot(cwd) {
|
|
39
|
+
try {
|
|
40
|
+
const commonDir = git("rev-parse --git-common-dir", cwd);
|
|
41
|
+
const abs = isAbsolute(commonDir) ? commonDir : resolve(cwd, commonDir);
|
|
42
|
+
return dirname(abs);
|
|
43
|
+
} catch {
|
|
44
|
+
return cwd;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
function getRepoFullName(cwd) {
|
|
48
|
+
const url = git("remote get-url origin", cwd);
|
|
49
|
+
const sshMatch = url.match(/git@github\.com:(.+?)(?:\.git)?$/);
|
|
50
|
+
if (sshMatch) return sshMatch[1];
|
|
51
|
+
const httpsMatch = url.match(/github\.com\/(.+?)(?:\.git)?$/);
|
|
52
|
+
if (httpsMatch) return httpsMatch[1];
|
|
53
|
+
throw new Error(`Could not parse GitHub repo from remote URL: ${url}`);
|
|
54
|
+
}
|
|
55
|
+
function getDefaultBranch(cwd) {
|
|
56
|
+
try {
|
|
57
|
+
const ref = git("rev-parse --abbrev-ref origin/HEAD", cwd);
|
|
58
|
+
return ref.replace("origin/", "");
|
|
59
|
+
} catch {
|
|
60
|
+
try {
|
|
61
|
+
git("rev-parse --verify origin/main", cwd);
|
|
62
|
+
return "main";
|
|
63
|
+
} catch {
|
|
64
|
+
return "master";
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
function getCurrentBranch(cwd) {
|
|
69
|
+
return git("branch --show-current", cwd);
|
|
70
|
+
}
|
|
71
|
+
function fetchOrigin(cwd) {
|
|
72
|
+
git("fetch origin", cwd);
|
|
73
|
+
}
|
|
74
|
+
function checkoutNewBranch(name, base, cwd) {
|
|
75
|
+
git(`checkout -b ${name} origin/${base}`, cwd);
|
|
76
|
+
}
|
|
77
|
+
function stageAll(cwd) {
|
|
78
|
+
git("add -A", cwd);
|
|
79
|
+
try {
|
|
80
|
+
git("reset HEAD -- .yapout/", cwd);
|
|
81
|
+
} catch {
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
function commit(message, cwd) {
|
|
85
|
+
git(`commit -m "${message.replace(/"/g, '\\"')}"`, cwd);
|
|
86
|
+
return git("rev-parse HEAD", cwd);
|
|
87
|
+
}
|
|
88
|
+
function push(branch, cwd) {
|
|
89
|
+
git(`push -u origin ${branch}`, cwd);
|
|
90
|
+
}
|
|
91
|
+
function getDiffStats(base, head, cwd) {
|
|
92
|
+
try {
|
|
93
|
+
return git(`diff --stat origin/${base}...${head}`, cwd);
|
|
94
|
+
} catch {
|
|
95
|
+
return "(could not compute diff stats)";
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// src/lib/config.ts
|
|
31
100
|
import { parse as yamlParse } from "yaml";
|
|
32
101
|
var YAPOUT_DIR = join(homedir(), ".yapout");
|
|
33
102
|
function ensureYapoutDir() {
|
|
@@ -72,19 +141,46 @@ function writeProjectMappings(mappings) {
|
|
|
72
141
|
writeFileSync(PROJECTS_PATH, JSON.stringify(mappings, null, 2));
|
|
73
142
|
}
|
|
74
143
|
function getProjectMapping(dir) {
|
|
144
|
+
const root = resolveRepoRoot(dir);
|
|
75
145
|
const mappings = readProjectMappings();
|
|
76
|
-
return mappings[dir] || null;
|
|
146
|
+
return mappings[root] || mappings[dir] || null;
|
|
77
147
|
}
|
|
78
148
|
function setProjectMapping(dir, mapping) {
|
|
79
149
|
const mappings = readProjectMappings();
|
|
80
|
-
mappings[dir] = mapping;
|
|
150
|
+
mappings[resolveRepoRoot(dir)] = mapping;
|
|
81
151
|
writeProjectMappings(mappings);
|
|
82
152
|
}
|
|
83
153
|
function removeProjectMapping(dir) {
|
|
154
|
+
const root = resolveRepoRoot(dir);
|
|
84
155
|
const mappings = readProjectMappings();
|
|
85
|
-
delete mappings[
|
|
156
|
+
delete mappings[root];
|
|
157
|
+
if (root !== dir) delete mappings[dir];
|
|
86
158
|
writeProjectMappings(mappings);
|
|
87
159
|
}
|
|
160
|
+
var DEVICE_PATH = join(YAPOUT_DIR, "device.json");
|
|
161
|
+
function readDeviceIdentity() {
|
|
162
|
+
if (!existsSync(DEVICE_PATH)) return null;
|
|
163
|
+
try {
|
|
164
|
+
return JSON.parse(readFileSync(DEVICE_PATH, "utf-8"));
|
|
165
|
+
} catch {
|
|
166
|
+
return null;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
function writeDeviceIdentity(identity) {
|
|
170
|
+
ensureYapoutDir();
|
|
171
|
+
writeFileSync(DEVICE_PATH, JSON.stringify(identity, null, 2), { mode: 384 });
|
|
172
|
+
}
|
|
173
|
+
function getOrCreateDeviceIdentity(defaultName) {
|
|
174
|
+
const existing = readDeviceIdentity();
|
|
175
|
+
if (existing) return existing;
|
|
176
|
+
const identity = {
|
|
177
|
+
deviceId: typeof crypto !== "undefined" && "randomUUID" in crypto ? crypto.randomUUID() : `dev-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`,
|
|
178
|
+
name: defaultName,
|
|
179
|
+
createdAt: Date.now()
|
|
180
|
+
};
|
|
181
|
+
writeDeviceIdentity(identity);
|
|
182
|
+
return identity;
|
|
183
|
+
}
|
|
88
184
|
var WATCH_DEFAULTS = {
|
|
89
185
|
auto_enrich: true,
|
|
90
186
|
auto_implement: true,
|
|
@@ -97,7 +193,7 @@ var CONFIG_DEFAULTS = {
|
|
|
97
193
|
watch: { ...WATCH_DEFAULTS }
|
|
98
194
|
};
|
|
99
195
|
function readYapoutConfig(cwd) {
|
|
100
|
-
const configPath = join(cwd, ".yapout", "config.yml");
|
|
196
|
+
const configPath = join(resolveRepoRoot(cwd), ".yapout", "config.yml");
|
|
101
197
|
if (!existsSync(configPath)) return { ...CONFIG_DEFAULTS };
|
|
102
198
|
try {
|
|
103
199
|
const raw = yamlParse(readFileSync(configPath, "utf-8"));
|
|
@@ -179,10 +275,10 @@ function createConvexClient(token) {
|
|
|
179
275
|
}
|
|
180
276
|
|
|
181
277
|
// src/lib/protocol.ts
|
|
182
|
-
import { execSync, spawnSync } from "child_process";
|
|
278
|
+
import { execSync as execSync2, spawnSync } from "child_process";
|
|
183
279
|
import { platform, homedir as homedir2 } from "os";
|
|
184
280
|
import { mkdirSync as mkdirSync2, writeFileSync as writeFileSync2, unlinkSync as unlinkSync2 } from "fs";
|
|
185
|
-
import { join as join2, dirname } from "path";
|
|
281
|
+
import { join as join2, dirname as dirname2 } from "path";
|
|
186
282
|
function getYapoutBinPath() {
|
|
187
283
|
const os = platform();
|
|
188
284
|
try {
|
|
@@ -208,7 +304,7 @@ function registerWindows(yapoutPath) {
|
|
|
208
304
|
`reg add "${key}\\shell\\open\\command" /ve /d "${handler}" /f`
|
|
209
305
|
];
|
|
210
306
|
for (const cmd of commands) {
|
|
211
|
-
|
|
307
|
+
execSync2(cmd, { stdio: "pipe" });
|
|
212
308
|
}
|
|
213
309
|
}
|
|
214
310
|
function registerMacOS(_yapoutPath) {
|
|
@@ -361,11 +457,11 @@ on idle
|
|
|
361
457
|
end idle`;
|
|
362
458
|
writeFileSync2(tmpScript, scriptContent);
|
|
363
459
|
try {
|
|
364
|
-
|
|
460
|
+
execSync2(`rm -rf "${appPath}"`, { stdio: "pipe" });
|
|
365
461
|
} catch {
|
|
366
462
|
}
|
|
367
|
-
mkdirSync2(
|
|
368
|
-
|
|
463
|
+
mkdirSync2(dirname2(appPath), { recursive: true });
|
|
464
|
+
execSync2(`osacompile -s -o "${appPath}" "${tmpScript}"`, { stdio: "pipe" });
|
|
369
465
|
try {
|
|
370
466
|
unlinkSync2(tmpScript);
|
|
371
467
|
} catch {
|
|
@@ -381,12 +477,12 @@ end idle`;
|
|
|
381
477
|
];
|
|
382
478
|
for (const cmd of plistCommands) {
|
|
383
479
|
try {
|
|
384
|
-
|
|
480
|
+
execSync2(`/usr/libexec/PlistBuddy -c '${cmd}' "${plistPath}"`, { stdio: "pipe" });
|
|
385
481
|
} catch {
|
|
386
482
|
}
|
|
387
483
|
}
|
|
388
484
|
try {
|
|
389
|
-
|
|
485
|
+
execSync2(
|
|
390
486
|
`/System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister -R "${appPath}"`,
|
|
391
487
|
{ stdio: "pipe" }
|
|
392
488
|
);
|
|
@@ -406,7 +502,7 @@ MimeType=x-scheme-handler/yapout;
|
|
|
406
502
|
`;
|
|
407
503
|
writeFileSync2(join2(appsDir, "yapout-handler.desktop"), desktop);
|
|
408
504
|
try {
|
|
409
|
-
|
|
505
|
+
execSync2(
|
|
410
506
|
`xdg-mime default yapout-handler.desktop x-scheme-handler/yapout`,
|
|
411
507
|
{ stdio: "pipe" }
|
|
412
508
|
);
|
|
@@ -426,7 +522,7 @@ function registerProtocolHandler() {
|
|
|
426
522
|
}
|
|
427
523
|
|
|
428
524
|
// src/commands/login.ts
|
|
429
|
-
var CLI_VERSION = "0.
|
|
525
|
+
var CLI_VERSION = "0.8.0";
|
|
430
526
|
function safeReturnTo(raw) {
|
|
431
527
|
if (!raw) return null;
|
|
432
528
|
try {
|
|
@@ -438,7 +534,7 @@ function safeReturnTo(raw) {
|
|
|
438
534
|
}
|
|
439
535
|
}
|
|
440
536
|
function startCallbackServer() {
|
|
441
|
-
return new Promise((
|
|
537
|
+
return new Promise((resolve12) => {
|
|
442
538
|
let resolveData;
|
|
443
539
|
let rejectData;
|
|
444
540
|
const dataPromise = new Promise((res, rej) => {
|
|
@@ -487,7 +583,7 @@ function startCallbackServer() {
|
|
|
487
583
|
server.listen(0, () => {
|
|
488
584
|
const address = server.address();
|
|
489
585
|
const port = typeof address === "object" && address ? address.port : 0;
|
|
490
|
-
|
|
586
|
+
resolve12({ port, data: dataPromise });
|
|
491
587
|
});
|
|
492
588
|
setTimeout(() => {
|
|
493
589
|
server.close();
|
|
@@ -558,7 +654,7 @@ var logoutCommand = new Command2("logout").description("Log out of yapout").acti
|
|
|
558
654
|
|
|
559
655
|
// src/commands/link.ts
|
|
560
656
|
import { Command as Command3 } from "commander";
|
|
561
|
-
import { resolve, join as join3 } from "path";
|
|
657
|
+
import { resolve as resolve2, join as join3 } from "path";
|
|
562
658
|
import {
|
|
563
659
|
existsSync as existsSync2,
|
|
564
660
|
mkdirSync as mkdirSync3,
|
|
@@ -566,6 +662,7 @@ import {
|
|
|
566
662
|
writeFileSync as writeFileSync3,
|
|
567
663
|
appendFileSync
|
|
568
664
|
} from "fs";
|
|
665
|
+
import { hostname as hostname2 } from "os";
|
|
569
666
|
import chalk4 from "chalk";
|
|
570
667
|
|
|
571
668
|
// src/lib/auth.ts
|
|
@@ -592,9 +689,22 @@ import { select } from "@inquirer/prompts";
|
|
|
592
689
|
async function pickProject(projects) {
|
|
593
690
|
return await select({
|
|
594
691
|
message: "Select a project to link to this directory:",
|
|
595
|
-
choices: projects.map((p) =>
|
|
596
|
-
|
|
597
|
-
|
|
692
|
+
choices: projects.map((p) => {
|
|
693
|
+
const repo = p.githubRepoFullName ? ` (${p.githubRepoFullName})` : "";
|
|
694
|
+
const orgLabel = p.org ? ` [${p.org.name}]` : "";
|
|
695
|
+
return {
|
|
696
|
+
name: `${p.name}${repo}${orgLabel}`,
|
|
697
|
+
value: p
|
|
698
|
+
};
|
|
699
|
+
})
|
|
700
|
+
});
|
|
701
|
+
}
|
|
702
|
+
async function pickOrg(orgs, message = "Which org does this project belong to?") {
|
|
703
|
+
return await select({
|
|
704
|
+
message,
|
|
705
|
+
choices: orgs.map((o) => ({
|
|
706
|
+
name: `${o.name} (${o.slug}, ${o.role})`,
|
|
707
|
+
value: o
|
|
598
708
|
}))
|
|
599
709
|
});
|
|
600
710
|
}
|
|
@@ -626,7 +736,7 @@ branch_prefix: feat
|
|
|
626
736
|
`;
|
|
627
737
|
var linkCommand = new Command3("link").description("Link the current directory to a yapout project").action(async () => {
|
|
628
738
|
const creds = requireAuth();
|
|
629
|
-
const cwd =
|
|
739
|
+
const cwd = resolveRepoRoot(resolve2(process.cwd()));
|
|
630
740
|
const client = createConvexClient(creds.token);
|
|
631
741
|
let projects;
|
|
632
742
|
try {
|
|
@@ -648,6 +758,25 @@ var linkCommand = new Command3("link").description("Link the current directory t
|
|
|
648
758
|
process.exit(1);
|
|
649
759
|
}
|
|
650
760
|
const selected = await pickProject(projects);
|
|
761
|
+
const device = getOrCreateDeviceIdentity(hostname2());
|
|
762
|
+
try {
|
|
763
|
+
await client.mutation(anyApi.functions.devices.registerDevice, {
|
|
764
|
+
deviceId: device.deviceId,
|
|
765
|
+
name: device.name,
|
|
766
|
+
cliVersion: getCliVersion(),
|
|
767
|
+
machineHostname: hostname2()
|
|
768
|
+
});
|
|
769
|
+
await client.mutation(anyApi.functions.projectCheckouts.linkCheckout, {
|
|
770
|
+
projectId: selected.id,
|
|
771
|
+
deviceId: device.deviceId,
|
|
772
|
+
localPath: cwd
|
|
773
|
+
});
|
|
774
|
+
} catch (err) {
|
|
775
|
+
console.warn(
|
|
776
|
+
chalk4.yellow("Warning: failed to record this checkout \u2014 "),
|
|
777
|
+
err.message
|
|
778
|
+
);
|
|
779
|
+
}
|
|
651
780
|
setProjectMapping(cwd, {
|
|
652
781
|
projectId: selected.id,
|
|
653
782
|
projectName: selected.name,
|
|
@@ -688,23 +817,50 @@ var linkCommand = new Command3("link").description("Link the current directory t
|
|
|
688
817
|
};
|
|
689
818
|
writeFileSync3(mcpPath, JSON.stringify(mcpConfig, null, 2) + "\n");
|
|
690
819
|
const label = selected.githubRepoFullName ? `${selected.name} (${selected.githubRepoFullName})` : selected.name;
|
|
820
|
+
const orgSuffix = selected.org ? ` in ${selected.org.name}` : "";
|
|
691
821
|
console.log(
|
|
692
|
-
chalk4.green(`Linked to ${label}.`) + " Claude Code will discover yapout tools automatically."
|
|
822
|
+
chalk4.green(`Linked to ${label}${orgSuffix}.`) + " Claude Code will discover yapout tools automatically."
|
|
693
823
|
);
|
|
694
824
|
});
|
|
825
|
+
function getCliVersion() {
|
|
826
|
+
try {
|
|
827
|
+
const pkg = JSON.parse(
|
|
828
|
+
readFileSync2(join3(import.meta.dirname, "..", "package.json"), "utf-8")
|
|
829
|
+
);
|
|
830
|
+
return pkg.version ?? "unknown";
|
|
831
|
+
} catch {
|
|
832
|
+
return "unknown";
|
|
833
|
+
}
|
|
834
|
+
}
|
|
695
835
|
|
|
696
836
|
// src/commands/unlink.ts
|
|
697
837
|
import { Command as Command4 } from "commander";
|
|
698
|
-
import { resolve as
|
|
838
|
+
import { resolve as resolve3, join as join4 } from "path";
|
|
699
839
|
import { existsSync as existsSync3, readFileSync as readFileSync3, writeFileSync as writeFileSync4, rmSync } from "fs";
|
|
700
840
|
import chalk5 from "chalk";
|
|
701
|
-
var unlinkCommand = new Command4("unlink").description("Unlink the current directory from its yapout project").action(() => {
|
|
702
|
-
const cwd =
|
|
841
|
+
var unlinkCommand = new Command4("unlink").description("Unlink the current directory from its yapout project").action(async () => {
|
|
842
|
+
const cwd = resolve3(process.cwd());
|
|
703
843
|
const mapping = getProjectMapping(cwd);
|
|
704
844
|
if (!mapping) {
|
|
705
845
|
console.error(chalk5.yellow("No project linked to this directory."));
|
|
706
846
|
process.exit(1);
|
|
707
847
|
}
|
|
848
|
+
const device = readDeviceIdentity();
|
|
849
|
+
const creds = readCredentials();
|
|
850
|
+
if (device && creds) {
|
|
851
|
+
try {
|
|
852
|
+
const client = createConvexClient(creds.token);
|
|
853
|
+
await client.mutation(anyApi.functions.projectCheckouts.unlinkCheckout, {
|
|
854
|
+
projectId: mapping.projectId,
|
|
855
|
+
deviceId: device.deviceId
|
|
856
|
+
});
|
|
857
|
+
} catch (err) {
|
|
858
|
+
console.warn(
|
|
859
|
+
chalk5.yellow("Warning: failed to update server \u2014 "),
|
|
860
|
+
err.message
|
|
861
|
+
);
|
|
862
|
+
}
|
|
863
|
+
}
|
|
708
864
|
removeProjectMapping(cwd);
|
|
709
865
|
const yapoutDir = join4(cwd, ".yapout");
|
|
710
866
|
if (existsSync3(yapoutDir)) {
|
|
@@ -733,7 +889,7 @@ var unlinkCommand = new Command4("unlink").description("Unlink the current direc
|
|
|
733
889
|
|
|
734
890
|
// src/commands/status.ts
|
|
735
891
|
import { Command as Command5 } from "commander";
|
|
736
|
-
import { resolve as
|
|
892
|
+
import { resolve as resolve4 } from "path";
|
|
737
893
|
import chalk6 from "chalk";
|
|
738
894
|
var statusCommand = new Command5("status").description("Show yapout status for this directory").action(() => {
|
|
739
895
|
console.log(chalk6.bold("yapout status\n"));
|
|
@@ -755,7 +911,7 @@ var statusCommand = new Command5("status").description("Show yapout status for t
|
|
|
755
911
|
` Auth: ${chalk6.green(creds.email)} (expires in ${daysLeft} day${daysLeft === 1 ? "" : "s"})`
|
|
756
912
|
);
|
|
757
913
|
}
|
|
758
|
-
const cwd =
|
|
914
|
+
const cwd = resolve4(process.cwd());
|
|
759
915
|
const mapping = getProjectMapping(cwd);
|
|
760
916
|
if (!mapping) {
|
|
761
917
|
console.log(
|
|
@@ -771,7 +927,7 @@ var statusCommand = new Command5("status").description("Show yapout status for t
|
|
|
771
927
|
|
|
772
928
|
// src/commands/init.ts
|
|
773
929
|
import { Command as Command6 } from "commander";
|
|
774
|
-
import { resolve as
|
|
930
|
+
import { resolve as resolve5, join as join5 } from "path";
|
|
775
931
|
import {
|
|
776
932
|
existsSync as existsSync4,
|
|
777
933
|
mkdirSync as mkdirSync4,
|
|
@@ -779,66 +935,8 @@ import {
|
|
|
779
935
|
readFileSync as readFileSync4,
|
|
780
936
|
appendFileSync as appendFileSync2
|
|
781
937
|
} from "fs";
|
|
938
|
+
import { hostname as hostname3 } from "os";
|
|
782
939
|
import chalk7 from "chalk";
|
|
783
|
-
|
|
784
|
-
// src/lib/git.ts
|
|
785
|
-
import { execSync as execSync2 } from "child_process";
|
|
786
|
-
function git(args, cwd) {
|
|
787
|
-
return execSync2(`git ${args}`, { cwd, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
|
|
788
|
-
}
|
|
789
|
-
function getRepoFullName(cwd) {
|
|
790
|
-
const url = git("remote get-url origin", cwd);
|
|
791
|
-
const sshMatch = url.match(/git@github\.com:(.+?)(?:\.git)?$/);
|
|
792
|
-
if (sshMatch) return sshMatch[1];
|
|
793
|
-
const httpsMatch = url.match(/github\.com\/(.+?)(?:\.git)?$/);
|
|
794
|
-
if (httpsMatch) return httpsMatch[1];
|
|
795
|
-
throw new Error(`Could not parse GitHub repo from remote URL: ${url}`);
|
|
796
|
-
}
|
|
797
|
-
function getDefaultBranch(cwd) {
|
|
798
|
-
try {
|
|
799
|
-
const ref = git("rev-parse --abbrev-ref origin/HEAD", cwd);
|
|
800
|
-
return ref.replace("origin/", "");
|
|
801
|
-
} catch {
|
|
802
|
-
try {
|
|
803
|
-
git("rev-parse --verify origin/main", cwd);
|
|
804
|
-
return "main";
|
|
805
|
-
} catch {
|
|
806
|
-
return "master";
|
|
807
|
-
}
|
|
808
|
-
}
|
|
809
|
-
}
|
|
810
|
-
function getCurrentBranch(cwd) {
|
|
811
|
-
return git("branch --show-current", cwd);
|
|
812
|
-
}
|
|
813
|
-
function fetchOrigin(cwd) {
|
|
814
|
-
git("fetch origin", cwd);
|
|
815
|
-
}
|
|
816
|
-
function checkoutNewBranch(name, base, cwd) {
|
|
817
|
-
git(`checkout -b ${name} origin/${base}`, cwd);
|
|
818
|
-
}
|
|
819
|
-
function stageAll(cwd) {
|
|
820
|
-
git("add -A", cwd);
|
|
821
|
-
try {
|
|
822
|
-
git("reset HEAD -- .yapout/", cwd);
|
|
823
|
-
} catch {
|
|
824
|
-
}
|
|
825
|
-
}
|
|
826
|
-
function commit(message, cwd) {
|
|
827
|
-
git(`commit -m "${message.replace(/"/g, '\\"')}"`, cwd);
|
|
828
|
-
return git("rev-parse HEAD", cwd);
|
|
829
|
-
}
|
|
830
|
-
function push(branch, cwd) {
|
|
831
|
-
git(`push -u origin ${branch}`, cwd);
|
|
832
|
-
}
|
|
833
|
-
function getDiffStats(base, head, cwd) {
|
|
834
|
-
try {
|
|
835
|
-
return git(`diff --stat origin/${base}...${head}`, cwd);
|
|
836
|
-
} catch {
|
|
837
|
-
return "(could not compute diff stats)";
|
|
838
|
-
}
|
|
839
|
-
}
|
|
840
|
-
|
|
841
|
-
// src/commands/init.ts
|
|
842
940
|
var CONFIG_YAML_CONTENT2 = `# yapout local configuration
|
|
843
941
|
# See: https://docs.yapout.dev/cli/config
|
|
844
942
|
|
|
@@ -863,9 +961,9 @@ branch_prefix: feat
|
|
|
863
961
|
# {{ticket.linearTicketId}}, {{ticket.id}}
|
|
864
962
|
# commit_template: "{{ticket.type}}({{ticket.linearTicketId}}): {{ticket.title}}"
|
|
865
963
|
`;
|
|
866
|
-
var initCommand = new Command6("init").description("Create a yapout project from the current repo and link it").argument("[name]", "Project name (defaults to repo name)").action(async (name) => {
|
|
964
|
+
var initCommand = new Command6("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) => {
|
|
867
965
|
const creds = requireAuth();
|
|
868
|
-
const cwd =
|
|
966
|
+
const cwd = resolveRepoRoot(resolve5(process.cwd()));
|
|
869
967
|
let repoFullName;
|
|
870
968
|
let defaultBranch;
|
|
871
969
|
try {
|
|
@@ -880,11 +978,82 @@ var initCommand = new Command6("init").description("Create a yapout project from
|
|
|
880
978
|
}
|
|
881
979
|
const projectName = name || repoFullName.split("/")[1] || "unnamed";
|
|
882
980
|
const client = createConvexClient(creds.token);
|
|
981
|
+
let orgs;
|
|
982
|
+
try {
|
|
983
|
+
orgs = await client.query(
|
|
984
|
+
anyApi.functions.orgMembers.getMyOrgs,
|
|
985
|
+
{}
|
|
986
|
+
);
|
|
987
|
+
} catch (err) {
|
|
988
|
+
console.error(
|
|
989
|
+
chalk7.red("Failed to load your orgs."),
|
|
990
|
+
err.message
|
|
991
|
+
);
|
|
992
|
+
process.exit(1);
|
|
993
|
+
}
|
|
994
|
+
if (!orgs || orgs.length === 0) {
|
|
995
|
+
console.error(
|
|
996
|
+
chalk7.red(
|
|
997
|
+
"You aren't a member of any org. Sign in to the web app once to create your personal org, then re-run."
|
|
998
|
+
)
|
|
999
|
+
);
|
|
1000
|
+
process.exit(1);
|
|
1001
|
+
}
|
|
1002
|
+
let chosenOrgId;
|
|
1003
|
+
let chosenOrgName;
|
|
1004
|
+
if (options?.org) {
|
|
1005
|
+
const match = orgs.find((o) => o.org.slug === options.org);
|
|
1006
|
+
if (!match) {
|
|
1007
|
+
console.error(
|
|
1008
|
+
chalk7.red(`Org "${options.org}" not found among your memberships.`)
|
|
1009
|
+
);
|
|
1010
|
+
console.error(
|
|
1011
|
+
chalk7.dim(
|
|
1012
|
+
"Available: " + orgs.map((o) => o.org.slug).join(", ")
|
|
1013
|
+
)
|
|
1014
|
+
);
|
|
1015
|
+
process.exit(1);
|
|
1016
|
+
}
|
|
1017
|
+
chosenOrgId = match.org._id;
|
|
1018
|
+
chosenOrgName = match.org.name;
|
|
1019
|
+
} else if (orgs.length === 1) {
|
|
1020
|
+
chosenOrgId = orgs[0].org._id;
|
|
1021
|
+
chosenOrgName = orgs[0].org.name;
|
|
1022
|
+
console.log(
|
|
1023
|
+
chalk7.dim(`Creating in `) + chalk7.cyan(chosenOrgName)
|
|
1024
|
+
);
|
|
1025
|
+
} else {
|
|
1026
|
+
const picked = await pickOrg(
|
|
1027
|
+
orgs.map((o) => ({
|
|
1028
|
+
id: o.org._id,
|
|
1029
|
+
name: o.org.name,
|
|
1030
|
+
slug: o.org.slug,
|
|
1031
|
+
role: o.role
|
|
1032
|
+
}))
|
|
1033
|
+
);
|
|
1034
|
+
chosenOrgId = picked.id;
|
|
1035
|
+
chosenOrgName = picked.name;
|
|
1036
|
+
}
|
|
1037
|
+
const device = getOrCreateDeviceIdentity(hostname3());
|
|
1038
|
+
try {
|
|
1039
|
+
await client.mutation(anyApi.functions.devices.registerDevice, {
|
|
1040
|
+
deviceId: device.deviceId,
|
|
1041
|
+
name: device.name,
|
|
1042
|
+
cliVersion: getCliVersion2(),
|
|
1043
|
+
machineHostname: hostname3()
|
|
1044
|
+
});
|
|
1045
|
+
} catch (err) {
|
|
1046
|
+
console.warn(
|
|
1047
|
+
chalk7.yellow("Warning: device registration failed \u2014 "),
|
|
1048
|
+
err.message
|
|
1049
|
+
);
|
|
1050
|
+
}
|
|
883
1051
|
let result;
|
|
884
1052
|
try {
|
|
885
1053
|
result = await client.mutation(
|
|
886
1054
|
anyApi.functions.projects.createProjectFromCli,
|
|
887
1055
|
{
|
|
1056
|
+
orgId: chosenOrgId,
|
|
888
1057
|
name: projectName,
|
|
889
1058
|
githubRepoFullName: repoFullName,
|
|
890
1059
|
githubDefaultBranch: defaultBranch
|
|
@@ -897,6 +1066,18 @@ var initCommand = new Command6("init").description("Create a yapout project from
|
|
|
897
1066
|
);
|
|
898
1067
|
process.exit(1);
|
|
899
1068
|
}
|
|
1069
|
+
try {
|
|
1070
|
+
await client.mutation(anyApi.functions.projectCheckouts.linkCheckout, {
|
|
1071
|
+
projectId: result.projectId,
|
|
1072
|
+
deviceId: device.deviceId,
|
|
1073
|
+
localPath: cwd
|
|
1074
|
+
});
|
|
1075
|
+
} catch (err) {
|
|
1076
|
+
console.warn(
|
|
1077
|
+
chalk7.yellow("Warning: failed to record project checkout \u2014 "),
|
|
1078
|
+
err.message
|
|
1079
|
+
);
|
|
1080
|
+
}
|
|
900
1081
|
setProjectMapping(cwd, {
|
|
901
1082
|
projectId: result.projectId,
|
|
902
1083
|
projectName: result.projectName,
|
|
@@ -933,12 +1114,24 @@ var initCommand = new Command6("init").description("Create a yapout project from
|
|
|
933
1114
|
};
|
|
934
1115
|
writeFileSync5(mcpPath, JSON.stringify(mcpConfig, null, 2) + "\n");
|
|
935
1116
|
console.log(
|
|
936
|
-
chalk7.green(`Created project "${result.projectName}"`) + chalk7.dim(
|
|
1117
|
+
chalk7.green(`Created project "${result.projectName}"`) + chalk7.dim(
|
|
1118
|
+
` in ${chosenOrgName} (${repoFullName}, branch: ${defaultBranch})`
|
|
1119
|
+
)
|
|
937
1120
|
);
|
|
938
1121
|
console.log(
|
|
939
1122
|
chalk7.dim("Run ") + chalk7.cyan("yapout_compact") + chalk7.dim(" in Claude Code to generate project context.")
|
|
940
1123
|
);
|
|
941
1124
|
});
|
|
1125
|
+
function getCliVersion2() {
|
|
1126
|
+
try {
|
|
1127
|
+
const pkg = JSON.parse(
|
|
1128
|
+
readFileSync4(join5(import.meta.dirname, "..", "package.json"), "utf-8")
|
|
1129
|
+
);
|
|
1130
|
+
return pkg.version ?? "unknown";
|
|
1131
|
+
} catch {
|
|
1132
|
+
return "unknown";
|
|
1133
|
+
}
|
|
1134
|
+
}
|
|
942
1135
|
|
|
943
1136
|
// src/commands/mcp-server.ts
|
|
944
1137
|
import { Command as Command7 } from "commander";
|
|
@@ -963,8 +1156,9 @@ function registerInitTool(server, ctx) {
|
|
|
963
1156
|
linearTeamId: z.string().optional().describe("Linear team ID to associate")
|
|
964
1157
|
},
|
|
965
1158
|
async (args) => {
|
|
966
|
-
const
|
|
967
|
-
const
|
|
1159
|
+
const repoRoot = resolveRepoRoot(ctx.cwd);
|
|
1160
|
+
const repoFullName = getRepoFullName(repoRoot);
|
|
1161
|
+
const defaultBranch = getDefaultBranch(repoRoot);
|
|
968
1162
|
const projectName = args.name || repoFullName.split("/")[1] || "unnamed";
|
|
969
1163
|
const result = await ctx.client.mutation(
|
|
970
1164
|
anyApi3.functions.projects.createProjectFromCli,
|
|
@@ -977,12 +1171,12 @@ function registerInitTool(server, ctx) {
|
|
|
977
1171
|
);
|
|
978
1172
|
ctx.projectId = result.projectId;
|
|
979
1173
|
ctx.projectName = result.projectName;
|
|
980
|
-
setProjectMapping(
|
|
1174
|
+
setProjectMapping(repoRoot, {
|
|
981
1175
|
projectId: result.projectId,
|
|
982
1176
|
projectName: result.projectName,
|
|
983
1177
|
linkedAt: Date.now()
|
|
984
1178
|
});
|
|
985
|
-
const yapoutDir = join6(
|
|
1179
|
+
const yapoutDir = join6(repoRoot, ".yapout");
|
|
986
1180
|
if (!existsSync5(yapoutDir)) mkdirSync5(yapoutDir, { recursive: true });
|
|
987
1181
|
const configPath = join6(yapoutDir, "config.yml");
|
|
988
1182
|
if (!existsSync5(configPath)) {
|
|
@@ -2125,7 +2319,7 @@ function truncate(text) {
|
|
|
2125
2319
|
` + lines.slice(-MAX_OUTPUT_LINES).join("\n");
|
|
2126
2320
|
}
|
|
2127
2321
|
function runCommand(command, cwd) {
|
|
2128
|
-
return new Promise((
|
|
2322
|
+
return new Promise((resolve12) => {
|
|
2129
2323
|
const start = Date.now();
|
|
2130
2324
|
const child = exec(command, {
|
|
2131
2325
|
cwd,
|
|
@@ -2133,7 +2327,7 @@ function runCommand(command, cwd) {
|
|
|
2133
2327
|
maxBuffer: 10 * 1024 * 1024
|
|
2134
2328
|
// 10MB
|
|
2135
2329
|
}, (error, stdout, stderr) => {
|
|
2136
|
-
|
|
2330
|
+
resolve12({
|
|
2137
2331
|
exitCode: error?.code ?? (error ? 1 : 0),
|
|
2138
2332
|
stdout: truncate(stdout),
|
|
2139
2333
|
stderr: truncate(stderr),
|
|
@@ -2141,7 +2335,7 @@ function runCommand(command, cwd) {
|
|
|
2141
2335
|
});
|
|
2142
2336
|
});
|
|
2143
2337
|
child.on("error", () => {
|
|
2144
|
-
|
|
2338
|
+
resolve12({
|
|
2145
2339
|
exitCode: 1,
|
|
2146
2340
|
stdout: "",
|
|
2147
2341
|
stderr: `Command timed out after ${COMMAND_TIMEOUT_MS / 1e3}s`,
|
|
@@ -2503,6 +2697,7 @@ The finding transitions: enriching \u2192 enriched \u2192 ready.`,
|
|
|
2503
2697
|
isOversized: z11.boolean().optional().describe("Set to true if this finding is too large for a single PR"),
|
|
2504
2698
|
suggestedSplit: z11.array(z11.string()).optional().describe("If oversized: suggested sub-finding titles for breaking it down"),
|
|
2505
2699
|
nature: z11.enum(["implementable", "operational", "spike"]).optional().describe("Override the finding's nature if enrichment reveals it should be reclassified"),
|
|
2700
|
+
cloudSafe: z11.boolean().optional().describe("Set to true ONLY if this is a small mechanical change a cloud agent can ship without sandbox testing \u2014 text/copy edits, classname tweaks, single-named-constant changes, \u226430 lines, single file, no logic/type/dependency changes. Default false."),
|
|
2506
2701
|
sessionId: z11.string().optional().describe("Bulk enrichment session ID (from yapout_start_enrichment). Updates session stats.")
|
|
2507
2702
|
},
|
|
2508
2703
|
async (args) => {
|
|
@@ -2518,7 +2713,8 @@ The finding transitions: enriching \u2192 enriched \u2192 ready.`,
|
|
|
2518
2713
|
clarifications: args.clarifications,
|
|
2519
2714
|
isOversized: args.isOversized,
|
|
2520
2715
|
suggestedSplit: args.suggestedSplit,
|
|
2521
|
-
nature: args.nature
|
|
2716
|
+
nature: args.nature,
|
|
2717
|
+
cloudSafe: args.cloudSafe
|
|
2522
2718
|
}
|
|
2523
2719
|
);
|
|
2524
2720
|
await ctx.client.action(
|
|
@@ -3183,7 +3379,7 @@ and issue counts so you can ask the user for confirmation before creating a new
|
|
|
3183
3379
|
}
|
|
3184
3380
|
const projects = await ctx.client.action(
|
|
3185
3381
|
anyApi3.functions.linearProjectsMutations.fetchProjectsDetailed,
|
|
3186
|
-
{ teamId: project.linearTeamId }
|
|
3382
|
+
{ projectId: ctx.projectId, teamId: project.linearTeamId }
|
|
3187
3383
|
);
|
|
3188
3384
|
return {
|
|
3189
3385
|
content: [
|
|
@@ -3494,6 +3690,7 @@ Call yapout_sync_bundle_to_linear afterwards to create the Linear project.`,
|
|
|
3494
3690
|
enrichedDescription: z21.string().describe("Bundle-level description \u2014 the cohesive story of what this bundle delivers"),
|
|
3495
3691
|
acceptanceCriteria: z21.array(z21.string()).describe("Bundle-level acceptance criteria"),
|
|
3496
3692
|
implementationBrief: z21.string().describe("Bundle-level implementation brief \u2014 overall approach, architecture decisions, key files"),
|
|
3693
|
+
cloudSafe: z21.boolean().optional().describe("Set true ONLY if the entire bundle is small mechanical work (\u226430 lines total, single-file ideally, text/className/constant edits). Default false. If unsure, false."),
|
|
3497
3694
|
findings: z21.array(z21.object({
|
|
3498
3695
|
findingId: z21.string().describe("Finding ID"),
|
|
3499
3696
|
title: z21.string().describe("Refined finding title"),
|
|
@@ -3512,6 +3709,7 @@ Call yapout_sync_bundle_to_linear afterwards to create the Linear project.`,
|
|
|
3512
3709
|
enrichedDescription: args.enrichedDescription,
|
|
3513
3710
|
acceptanceCriteria: args.acceptanceCriteria,
|
|
3514
3711
|
implementationBrief: args.implementationBrief,
|
|
3712
|
+
cloudSafe: args.cloudSafe,
|
|
3515
3713
|
findings: args.findings.map((f) => ({
|
|
3516
3714
|
findingId: f.findingId,
|
|
3517
3715
|
title: f.title,
|
|
@@ -3543,6 +3741,113 @@ Call yapout_sync_bundle_to_linear afterwards to create the Linear project.`,
|
|
|
3543
3741
|
);
|
|
3544
3742
|
}
|
|
3545
3743
|
|
|
3744
|
+
// src/mcp/tools/block-enrichment.ts
|
|
3745
|
+
import { z as z22 } from "zod";
|
|
3746
|
+
function registerBlockEnrichmentTool(server, ctx) {
|
|
3747
|
+
server.tool(
|
|
3748
|
+
"yapout_block_enrichment",
|
|
3749
|
+
`Refuse to enrich a finding because the user has not provided enough specifics for an autonomous agent to complete the work end-to-end.
|
|
3750
|
+
|
|
3751
|
+
Use this when the finding lacks any of: target file/component, intended behavior, scope boundaries, or success criteria. Do NOT produce a half-baked enrichment "for review" \u2014 block instead. The bar for "enriched" is "another agent can ship this with zero further input."
|
|
3752
|
+
|
|
3753
|
+
The finding must currently be in "enriching" status (claimed via yapout_get_unenriched_finding).
|
|
3754
|
+
|
|
3755
|
+
Transitions: enriching \u2192 needs_input. The user sees the blockerReason and questions in the UI, adds context, and resubmits.`,
|
|
3756
|
+
{
|
|
3757
|
+
findingId: z22.string().describe("The finding ID to block (currently in 'enriching')"),
|
|
3758
|
+
blockerReason: z22.string().describe("One sentence: why this finding cannot be enriched as written. State the missing piece concretely."),
|
|
3759
|
+
blockerQuestions: z22.array(z22.string()).min(1).describe("2-5 specific questions the user must answer before enrichment can succeed. Each must be answerable in a sentence or two.")
|
|
3760
|
+
},
|
|
3761
|
+
async (args) => {
|
|
3762
|
+
try {
|
|
3763
|
+
await ctx.client.mutation(
|
|
3764
|
+
anyApi3.functions.localPipeline.blockLocalEnrichment,
|
|
3765
|
+
{
|
|
3766
|
+
findingId: args.findingId,
|
|
3767
|
+
blockerReason: args.blockerReason,
|
|
3768
|
+
blockerQuestions: args.blockerQuestions
|
|
3769
|
+
}
|
|
3770
|
+
);
|
|
3771
|
+
return {
|
|
3772
|
+
content: [
|
|
3773
|
+
{
|
|
3774
|
+
type: "text",
|
|
3775
|
+
text: JSON.stringify(
|
|
3776
|
+
{
|
|
3777
|
+
findingId: args.findingId,
|
|
3778
|
+
status: "needs_input",
|
|
3779
|
+
message: "Enrichment blocked. The user will see your questions and resubmit with more context."
|
|
3780
|
+
},
|
|
3781
|
+
null,
|
|
3782
|
+
2
|
|
3783
|
+
)
|
|
3784
|
+
}
|
|
3785
|
+
]
|
|
3786
|
+
};
|
|
3787
|
+
} catch (err) {
|
|
3788
|
+
return {
|
|
3789
|
+
content: [
|
|
3790
|
+
{
|
|
3791
|
+
type: "text",
|
|
3792
|
+
text: `Error blocking enrichment: ${err.message}`
|
|
3793
|
+
}
|
|
3794
|
+
],
|
|
3795
|
+
isError: true
|
|
3796
|
+
};
|
|
3797
|
+
}
|
|
3798
|
+
}
|
|
3799
|
+
);
|
|
3800
|
+
server.tool(
|
|
3801
|
+
"yapout_block_bundle_enrichment",
|
|
3802
|
+
`Refuse to enrich a bundle because the user has not provided enough specifics for an autonomous agent to ship it end-to-end.
|
|
3803
|
+
|
|
3804
|
+
Same semantics as yapout_block_enrichment but for an entire bundle. Bundle status transitions enriching \u2192 needs_input; child findings revert to draft.`,
|
|
3805
|
+
{
|
|
3806
|
+
bundleId: z22.string().describe("The bundle ID to block (currently in 'enriching')"),
|
|
3807
|
+
blockerReason: z22.string().describe("One sentence: why this bundle cannot be enriched."),
|
|
3808
|
+
blockerQuestions: z22.array(z22.string()).min(1).describe("2-5 specific questions the user must answer.")
|
|
3809
|
+
},
|
|
3810
|
+
async (args) => {
|
|
3811
|
+
try {
|
|
3812
|
+
await ctx.client.mutation(
|
|
3813
|
+
anyApi3.functions.bundles.blockBundleEnrichment,
|
|
3814
|
+
{
|
|
3815
|
+
bundleId: args.bundleId,
|
|
3816
|
+
blockerReason: args.blockerReason,
|
|
3817
|
+
blockerQuestions: args.blockerQuestions
|
|
3818
|
+
}
|
|
3819
|
+
);
|
|
3820
|
+
return {
|
|
3821
|
+
content: [
|
|
3822
|
+
{
|
|
3823
|
+
type: "text",
|
|
3824
|
+
text: JSON.stringify(
|
|
3825
|
+
{
|
|
3826
|
+
bundleId: args.bundleId,
|
|
3827
|
+
status: "needs_input",
|
|
3828
|
+
message: "Bundle enrichment blocked. The user will see your questions and resubmit."
|
|
3829
|
+
},
|
|
3830
|
+
null,
|
|
3831
|
+
2
|
|
3832
|
+
)
|
|
3833
|
+
}
|
|
3834
|
+
]
|
|
3835
|
+
};
|
|
3836
|
+
} catch (err) {
|
|
3837
|
+
return {
|
|
3838
|
+
content: [
|
|
3839
|
+
{
|
|
3840
|
+
type: "text",
|
|
3841
|
+
text: `Error blocking bundle enrichment: ${err.message}`
|
|
3842
|
+
}
|
|
3843
|
+
],
|
|
3844
|
+
isError: true
|
|
3845
|
+
};
|
|
3846
|
+
}
|
|
3847
|
+
}
|
|
3848
|
+
);
|
|
3849
|
+
}
|
|
3850
|
+
|
|
3546
3851
|
// src/mcp/server.ts
|
|
3547
3852
|
async function startMcpServer() {
|
|
3548
3853
|
const cwd = process.cwd();
|
|
@@ -3573,7 +3878,7 @@ async function startMcpServer() {
|
|
|
3573
3878
|
};
|
|
3574
3879
|
const server = new McpServer({
|
|
3575
3880
|
name: "yapout",
|
|
3576
|
-
version: "0.
|
|
3881
|
+
version: "0.8.0"
|
|
3577
3882
|
});
|
|
3578
3883
|
registerInitTool(server, ctx);
|
|
3579
3884
|
registerCompactTool(server, ctx);
|
|
@@ -3599,6 +3904,7 @@ async function startMcpServer() {
|
|
|
3599
3904
|
registerEnrichNextTool(server, ctx);
|
|
3600
3905
|
registerEnrichBundleTool(server, ctx);
|
|
3601
3906
|
registerSaveBundleEnrichmentTool(server, ctx);
|
|
3907
|
+
registerBlockEnrichmentTool(server, ctx);
|
|
3602
3908
|
const transport = new StdioServerTransport();
|
|
3603
3909
|
await server.connect(transport);
|
|
3604
3910
|
}
|
|
@@ -3611,9 +3917,9 @@ var mcpServerCommand = new Command7("mcp-server").description("Start the MCP ser
|
|
|
3611
3917
|
// src/commands/worktrees.ts
|
|
3612
3918
|
import { Command as Command8 } from "commander";
|
|
3613
3919
|
import chalk8 from "chalk";
|
|
3614
|
-
import { resolve as
|
|
3920
|
+
import { resolve as resolve6 } from "path";
|
|
3615
3921
|
var worktreesCommand = new Command8("worktrees").description("List active yapout worktrees").action(() => {
|
|
3616
|
-
const cwd =
|
|
3922
|
+
const cwd = resolve6(process.cwd());
|
|
3617
3923
|
const worktrees = listWorktrees(cwd);
|
|
3618
3924
|
if (worktrees.length === 0) {
|
|
3619
3925
|
console.log(chalk8.dim("No active yapout worktrees."));
|
|
@@ -3631,10 +3937,10 @@ var worktreesCommand = new Command8("worktrees").description("List active yapout
|
|
|
3631
3937
|
// src/commands/clean.ts
|
|
3632
3938
|
import { Command as Command9 } from "commander";
|
|
3633
3939
|
import chalk9 from "chalk";
|
|
3634
|
-
import { resolve as
|
|
3940
|
+
import { resolve as resolve7 } from "path";
|
|
3635
3941
|
var cleanCommand = new Command9("clean").description("Remove worktrees for completed or failed tickets").action(async () => {
|
|
3636
3942
|
const creds = requireAuth();
|
|
3637
|
-
const cwd =
|
|
3943
|
+
const cwd = resolve7(process.cwd());
|
|
3638
3944
|
const worktrees = listWorktrees(cwd);
|
|
3639
3945
|
if (worktrees.length === 0) {
|
|
3640
3946
|
console.log(chalk9.dim("No worktrees to clean."));
|
|
@@ -3674,7 +3980,7 @@ var cleanCommand = new Command9("clean").description("Remove worktrees for compl
|
|
|
3674
3980
|
|
|
3675
3981
|
// src/commands/watch.ts
|
|
3676
3982
|
import { Command as Command10 } from "commander";
|
|
3677
|
-
import { resolve as
|
|
3983
|
+
import { resolve as resolve8 } from "path";
|
|
3678
3984
|
import {
|
|
3679
3985
|
readFileSync as readFileSync6,
|
|
3680
3986
|
writeFileSync as writeFileSync9,
|
|
@@ -3909,10 +4215,10 @@ var Spawner = class {
|
|
|
3909
4215
|
if (this.agents.size === 0) return;
|
|
3910
4216
|
const timeout = 10 * 60 * 1e3;
|
|
3911
4217
|
const start = Date.now();
|
|
3912
|
-
await new Promise((
|
|
4218
|
+
await new Promise((resolve12) => {
|
|
3913
4219
|
const check = () => {
|
|
3914
4220
|
if (this.agents.size === 0 || Date.now() - start > timeout) {
|
|
3915
|
-
|
|
4221
|
+
resolve12();
|
|
3916
4222
|
return;
|
|
3917
4223
|
}
|
|
3918
4224
|
setTimeout(check, 2e3);
|
|
@@ -4322,7 +4628,7 @@ var watchCommand = new Command10("watch").description("Watch for work and spawn
|
|
|
4322
4628
|
return;
|
|
4323
4629
|
}
|
|
4324
4630
|
const creds = requireAuth();
|
|
4325
|
-
const cwd =
|
|
4631
|
+
const cwd = resolve8(process.cwd());
|
|
4326
4632
|
const mapping = getProjectMapping(cwd);
|
|
4327
4633
|
if (!mapping) {
|
|
4328
4634
|
console.error(
|
|
@@ -4339,7 +4645,7 @@ var watchCommand = new Command10("watch").description("Watch for work and spawn
|
|
|
4339
4645
|
chalk11.green("Watcher started in background") + chalk11.dim(` (PID ${process.pid}, log: ${LOG_FILE})`)
|
|
4340
4646
|
);
|
|
4341
4647
|
}
|
|
4342
|
-
console.log(chalk11.bold(`yapout watch v${"0.
|
|
4648
|
+
console.log(chalk11.bold(`yapout watch v${"0.8.0"}`));
|
|
4343
4649
|
console.log(
|
|
4344
4650
|
`Project: ${chalk11.green(mapping.projectName)} (${mapping.projectId})`
|
|
4345
4651
|
);
|
|
@@ -4394,11 +4700,11 @@ function isProcessRunning(pid) {
|
|
|
4394
4700
|
|
|
4395
4701
|
// src/commands/queue.ts
|
|
4396
4702
|
import { Command as Command11 } from "commander";
|
|
4397
|
-
import { resolve as
|
|
4703
|
+
import { resolve as resolve9 } from "path";
|
|
4398
4704
|
import chalk12 from "chalk";
|
|
4399
4705
|
var queueCommand = new Command11("queue").description("Show pipeline state \u2014 what's ready, blocked, and pending").action(async () => {
|
|
4400
4706
|
const creds = requireAuth();
|
|
4401
|
-
const cwd =
|
|
4707
|
+
const cwd = resolve9(process.cwd());
|
|
4402
4708
|
const mapping = getProjectMapping(cwd);
|
|
4403
4709
|
if (!mapping) {
|
|
4404
4710
|
console.error(
|
|
@@ -4491,13 +4797,13 @@ function formatAgo(ms) {
|
|
|
4491
4797
|
|
|
4492
4798
|
// src/commands/next.ts
|
|
4493
4799
|
import { Command as Command12 } from "commander";
|
|
4494
|
-
import { resolve as
|
|
4800
|
+
import { resolve as resolve10 } from "path";
|
|
4495
4801
|
import { writeFileSync as writeFileSync10 } from "fs";
|
|
4496
4802
|
import { join as join12 } from "path";
|
|
4497
4803
|
import chalk13 from "chalk";
|
|
4498
4804
|
var nextCommand = new Command12("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) => {
|
|
4499
4805
|
const creds = requireAuth();
|
|
4500
|
-
const cwd =
|
|
4806
|
+
const cwd = resolve10(process.cwd());
|
|
4501
4807
|
const mapping = getProjectMapping(cwd);
|
|
4502
4808
|
if (!mapping) {
|
|
4503
4809
|
console.error(
|
|
@@ -4596,11 +4902,11 @@ function formatBrief(ref, ticket, brief) {
|
|
|
4596
4902
|
|
|
4597
4903
|
// src/commands/recap.ts
|
|
4598
4904
|
import { Command as Command13 } from "commander";
|
|
4599
|
-
import { resolve as
|
|
4905
|
+
import { resolve as resolve11 } from "path";
|
|
4600
4906
|
import chalk14 from "chalk";
|
|
4601
4907
|
var recapCommand = new Command13("recap").description("Show a summary of recent yapout activity").option("--week", "Show full week summary (default: today)").action(async (opts) => {
|
|
4602
4908
|
const creds = requireAuth();
|
|
4603
|
-
const cwd =
|
|
4909
|
+
const cwd = resolve11(process.cwd());
|
|
4604
4910
|
const mapping = getProjectMapping(cwd);
|
|
4605
4911
|
if (!mapping) {
|
|
4606
4912
|
console.error(
|
|
@@ -4892,7 +5198,7 @@ var handleUriCommand = new Command15("handle-uri").description("Handle a yapout:
|
|
|
4892
5198
|
|
|
4893
5199
|
// src/index.ts
|
|
4894
5200
|
var program = new Command16();
|
|
4895
|
-
program.name("yapout").description("yapout \u2014 from meeting transcript to merged PR").version("0.
|
|
5201
|
+
program.name("yapout").description("yapout \u2014 from meeting transcript to merged PR").version("0.8.0");
|
|
4896
5202
|
program.addCommand(loginCommand);
|
|
4897
5203
|
program.addCommand(logoutCommand);
|
|
4898
5204
|
program.addCommand(initCommand);
|