@vemdev/cli 0.1.51 → 0.1.53
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 +994 -611
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -32,7 +32,7 @@ import "./chunk-VL6CJCOB.js";
|
|
|
32
32
|
import "./chunk-PZ5AY32C.js";
|
|
33
33
|
|
|
34
34
|
// src/index.ts
|
|
35
|
-
import
|
|
35
|
+
import chalk19 from "chalk";
|
|
36
36
|
import { Command } from "commander";
|
|
37
37
|
|
|
38
38
|
// src/commands/agent.ts
|
|
@@ -349,7 +349,7 @@ async function hasNonVemChanges() {
|
|
|
349
349
|
const root = await getRepoRoot();
|
|
350
350
|
const status = execSync("git status --porcelain", { cwd: root }).toString().trim();
|
|
351
351
|
if (!status) return false;
|
|
352
|
-
return status.split("\n").map((line) => normalizeStatusPath(line)).some((
|
|
352
|
+
return status.split("\n").map((line) => normalizeStatusPath(line)).some((path4) => path4.length > 0 && !path4.startsWith(".vem/"));
|
|
353
353
|
} catch (_e) {
|
|
354
354
|
return false;
|
|
355
355
|
}
|
|
@@ -480,13 +480,13 @@ async function detectVemUpdateInOutput(vemDir) {
|
|
|
480
480
|
}
|
|
481
481
|
}
|
|
482
482
|
async function readStdin() {
|
|
483
|
-
return new Promise((
|
|
483
|
+
return new Promise((resolve3, reject) => {
|
|
484
484
|
let data = "";
|
|
485
485
|
process.stdin.setEncoding("utf-8");
|
|
486
486
|
process.stdin.on("data", (chunk) => {
|
|
487
487
|
data += chunk;
|
|
488
488
|
});
|
|
489
|
-
process.stdin.on("end", () =>
|
|
489
|
+
process.stdin.on("end", () => resolve3(data));
|
|
490
490
|
process.stdin.on("error", reject);
|
|
491
491
|
});
|
|
492
492
|
}
|
|
@@ -897,8 +897,9 @@ var TASK_STATUS_ORDER = {
|
|
|
897
897
|
"in-review": 0,
|
|
898
898
|
"in-progress": 1,
|
|
899
899
|
todo: 2,
|
|
900
|
-
|
|
901
|
-
|
|
900
|
+
ready: 3,
|
|
901
|
+
blocked: 4,
|
|
902
|
+
done: 5
|
|
902
903
|
};
|
|
903
904
|
var debugAgentSync = (...messages) => {
|
|
904
905
|
if (process.env.VEM_DEBUG !== "1") return;
|
|
@@ -1235,8 +1236,8 @@ var syncParsedTaskUpdatesToRemote = async (configService, update, result) => {
|
|
|
1235
1236
|
...patch.parent_id !== void 0 ? { parent_id: patch.parent_id } : {},
|
|
1236
1237
|
...patch.subtask_order !== void 0 ? { subtask_order: patch.subtask_order } : {},
|
|
1237
1238
|
...patch.due_at !== void 0 ? { due_at: patch.due_at } : {},
|
|
1238
|
-
raw_vem_update: update,
|
|
1239
|
-
cli_version: "0.1.
|
|
1239
|
+
raw_vem_update: JSON.parse(JSON.stringify(update)),
|
|
1240
|
+
cli_version: "0.1.53"
|
|
1240
1241
|
});
|
|
1241
1242
|
const taskContextPatch = buildRemoteTaskContextPatch(patch, updatedTask);
|
|
1242
1243
|
if (taskContextPatch) {
|
|
@@ -1881,7 +1882,7 @@ Start by reading .vem/task_context.md and .vem/current_context.md for task and p
|
|
|
1881
1882
|
});
|
|
1882
1883
|
let startError = null;
|
|
1883
1884
|
let exitCode = null;
|
|
1884
|
-
await new Promise((
|
|
1885
|
+
await new Promise((resolve3) => {
|
|
1885
1886
|
child.on("exit", (code, signal) => {
|
|
1886
1887
|
exitCode = code;
|
|
1887
1888
|
if (code === null && signal) {
|
|
@@ -1893,11 +1894,11 @@ Start by reading .vem/task_context.md and .vem/current_context.md for task and p
|
|
|
1893
1894
|
process.kill(-child.pid, "SIGTERM");
|
|
1894
1895
|
} catch {
|
|
1895
1896
|
}
|
|
1896
|
-
|
|
1897
|
+
resolve3();
|
|
1897
1898
|
});
|
|
1898
1899
|
child.on("error", (err) => {
|
|
1899
1900
|
startError = err;
|
|
1900
|
-
|
|
1901
|
+
resolve3();
|
|
1901
1902
|
});
|
|
1902
1903
|
});
|
|
1903
1904
|
const capturedError = startError;
|
|
@@ -1922,17 +1923,17 @@ Start by reading .vem/task_context.md and .vem/current_context.md for task and p
|
|
|
1922
1923
|
VEM_AGENT_NAME: agentName
|
|
1923
1924
|
}
|
|
1924
1925
|
});
|
|
1925
|
-
const shellResult = await new Promise((
|
|
1926
|
+
const shellResult = await new Promise((resolve3) => {
|
|
1926
1927
|
shellChild.on("exit", (code) => {
|
|
1927
1928
|
try {
|
|
1928
1929
|
process.kill(-shellChild.pid, "SIGTERM");
|
|
1929
1930
|
} catch {
|
|
1930
1931
|
}
|
|
1931
|
-
|
|
1932
|
+
resolve3({ exitCode: code, error: null });
|
|
1932
1933
|
});
|
|
1933
1934
|
shellChild.on(
|
|
1934
1935
|
"error",
|
|
1935
|
-
(err) =>
|
|
1936
|
+
(err) => resolve3({ exitCode: null, error: err })
|
|
1936
1937
|
);
|
|
1937
1938
|
});
|
|
1938
1939
|
if (shellResult.error) {
|
|
@@ -2797,26 +2798,407 @@ function registerCycleCommands(program2) {
|
|
|
2797
2798
|
});
|
|
2798
2799
|
}
|
|
2799
2800
|
|
|
2801
|
+
// src/commands/instructions.ts
|
|
2802
|
+
import * as fs2 from "fs/promises";
|
|
2803
|
+
import * as path from "path";
|
|
2804
|
+
import chalk10 from "chalk";
|
|
2805
|
+
import prompts5 from "prompts";
|
|
2806
|
+
async function getRepoRoot2() {
|
|
2807
|
+
const { execSync: execSync4 } = await import("child_process");
|
|
2808
|
+
try {
|
|
2809
|
+
return execSync4("git rev-parse --show-toplevel", { encoding: "utf-8" }).trim();
|
|
2810
|
+
} catch {
|
|
2811
|
+
return process.cwd();
|
|
2812
|
+
}
|
|
2813
|
+
}
|
|
2814
|
+
async function readLocalInstructions() {
|
|
2815
|
+
const repoRoot = await getRepoRoot2();
|
|
2816
|
+
const result = [];
|
|
2817
|
+
for (const relativePath of KNOWN_AGENT_INSTRUCTION_FILES) {
|
|
2818
|
+
const absPath = path.join(repoRoot, relativePath);
|
|
2819
|
+
try {
|
|
2820
|
+
const content = await fs2.readFile(absPath, "utf-8");
|
|
2821
|
+
result.push({ path: relativePath, content });
|
|
2822
|
+
} catch {
|
|
2823
|
+
}
|
|
2824
|
+
}
|
|
2825
|
+
return result;
|
|
2826
|
+
}
|
|
2827
|
+
function registerInstructionCommands(program2) {
|
|
2828
|
+
const instructionsCmd = program2.command("instructions").alias("instr").description("Manage and sync agent instruction files");
|
|
2829
|
+
instructionsCmd.command("pull").description(
|
|
2830
|
+
"Pull the latest instructions from the cloud and write them to local files"
|
|
2831
|
+
).option("-f, --force", "Overwrite local files without prompt").action(async (options) => {
|
|
2832
|
+
await trackCommandUsage("instructions.pull");
|
|
2833
|
+
try {
|
|
2834
|
+
const configService = new ConfigService();
|
|
2835
|
+
const key = await ensureAuthenticated(configService);
|
|
2836
|
+
const projectId = await configService.getProjectId();
|
|
2837
|
+
if (!projectId) {
|
|
2838
|
+
console.error(
|
|
2839
|
+
chalk10.red(
|
|
2840
|
+
"Error: No project linked. Run `vem link <projectId>` first."
|
|
2841
|
+
)
|
|
2842
|
+
);
|
|
2843
|
+
process.exitCode = 1;
|
|
2844
|
+
return;
|
|
2845
|
+
}
|
|
2846
|
+
console.log(chalk10.blue("\u2B07 Fetching instructions from cloud..."));
|
|
2847
|
+
const res = await fetch(
|
|
2848
|
+
`${API_URL}/projects/${projectId}/instructions`,
|
|
2849
|
+
{
|
|
2850
|
+
headers: {
|
|
2851
|
+
Authorization: `Bearer ${key}`,
|
|
2852
|
+
...await buildDeviceHeaders(configService)
|
|
2853
|
+
}
|
|
2854
|
+
}
|
|
2855
|
+
);
|
|
2856
|
+
if (!res.ok) {
|
|
2857
|
+
const data2 = await res.json().catch(() => ({}));
|
|
2858
|
+
throw new Error(
|
|
2859
|
+
`API Error ${res.status}: ${data2.error || res.statusText}`
|
|
2860
|
+
);
|
|
2861
|
+
}
|
|
2862
|
+
const data = await res.json();
|
|
2863
|
+
const instructions = data.instructions ?? [];
|
|
2864
|
+
if (instructions.length === 0) {
|
|
2865
|
+
console.log(
|
|
2866
|
+
chalk10.yellow("No instructions configured for this project.")
|
|
2867
|
+
);
|
|
2868
|
+
return;
|
|
2869
|
+
}
|
|
2870
|
+
const repoRoot = await getRepoRoot2();
|
|
2871
|
+
let written = 0;
|
|
2872
|
+
let skipped = 0;
|
|
2873
|
+
for (const entry of instructions) {
|
|
2874
|
+
if (typeof entry.path !== "string" || typeof entry.content !== "string")
|
|
2875
|
+
continue;
|
|
2876
|
+
if (!entry.content.trim()) continue;
|
|
2877
|
+
const dest = path.resolve(repoRoot, entry.path);
|
|
2878
|
+
const resolvedRoot = path.resolve(repoRoot);
|
|
2879
|
+
if (!dest.startsWith(`${resolvedRoot}${path.sep}`) && dest !== resolvedRoot) {
|
|
2880
|
+
console.warn(
|
|
2881
|
+
chalk10.yellow(`Skipping unsafe path: ${entry.path}`)
|
|
2882
|
+
);
|
|
2883
|
+
continue;
|
|
2884
|
+
}
|
|
2885
|
+
if (!options.force) {
|
|
2886
|
+
const fileExists = await fs2.access(dest).then(() => true).catch(() => false);
|
|
2887
|
+
if (fileExists) {
|
|
2888
|
+
const { overwrite } = await prompts5({
|
|
2889
|
+
type: "confirm",
|
|
2890
|
+
name: "overwrite",
|
|
2891
|
+
message: `File ${entry.path} (${dest}) already exists. Overwrite?`,
|
|
2892
|
+
initial: false
|
|
2893
|
+
});
|
|
2894
|
+
if (!overwrite) {
|
|
2895
|
+
console.log(chalk10.yellow(` \u2298 Skipped ${entry.path}`));
|
|
2896
|
+
skipped++;
|
|
2897
|
+
continue;
|
|
2898
|
+
}
|
|
2899
|
+
}
|
|
2900
|
+
}
|
|
2901
|
+
await fs2.mkdir(path.dirname(dest), { recursive: true });
|
|
2902
|
+
await fs2.writeFile(dest, entry.content, "utf-8");
|
|
2903
|
+
console.log(chalk10.green(` \u2714 ${entry.path}`));
|
|
2904
|
+
written++;
|
|
2905
|
+
}
|
|
2906
|
+
const skippedMsg = skipped > 0 ? `, ${skipped} skipped` : "";
|
|
2907
|
+
console.log(
|
|
2908
|
+
chalk10.green(`
|
|
2909
|
+
\u2714 Pulled ${written} instruction file(s)${skippedMsg}.
|
|
2910
|
+
`)
|
|
2911
|
+
);
|
|
2912
|
+
} catch (error) {
|
|
2913
|
+
console.error(
|
|
2914
|
+
chalk10.red("\n\u2716 Instructions pull failed:"),
|
|
2915
|
+
error instanceof Error ? error.message : String(error)
|
|
2916
|
+
);
|
|
2917
|
+
process.exitCode = 1;
|
|
2918
|
+
}
|
|
2919
|
+
});
|
|
2920
|
+
instructionsCmd.command("push").description("Push local instruction files to the cloud").option("-m, --message <msg>", "Commit message for this version").action(async (options) => {
|
|
2921
|
+
await trackCommandUsage("instructions.push");
|
|
2922
|
+
try {
|
|
2923
|
+
const configService = new ConfigService();
|
|
2924
|
+
const key = await ensureAuthenticated(configService);
|
|
2925
|
+
const projectId = await configService.getProjectId();
|
|
2926
|
+
if (!projectId) {
|
|
2927
|
+
console.error(
|
|
2928
|
+
chalk10.red(
|
|
2929
|
+
"Error: No project linked. Run `vem link <projectId>` first."
|
|
2930
|
+
)
|
|
2931
|
+
);
|
|
2932
|
+
process.exitCode = 1;
|
|
2933
|
+
return;
|
|
2934
|
+
}
|
|
2935
|
+
const localInstructions = await readLocalInstructions();
|
|
2936
|
+
if (localInstructions.length === 0) {
|
|
2937
|
+
console.log(
|
|
2938
|
+
chalk10.yellow(
|
|
2939
|
+
"No instruction files found locally. Looked for:"
|
|
2940
|
+
)
|
|
2941
|
+
);
|
|
2942
|
+
for (const f of KNOWN_AGENT_INSTRUCTION_FILES) {
|
|
2943
|
+
console.log(chalk10.gray(` ${f}`));
|
|
2944
|
+
}
|
|
2945
|
+
return;
|
|
2946
|
+
}
|
|
2947
|
+
console.log(
|
|
2948
|
+
chalk10.blue(
|
|
2949
|
+
`\u2B06 Pushing ${localInstructions.length} instruction file(s)...`
|
|
2950
|
+
)
|
|
2951
|
+
);
|
|
2952
|
+
const res = await fetch(
|
|
2953
|
+
`${API_URL}/projects/${projectId}/instructions`,
|
|
2954
|
+
{
|
|
2955
|
+
method: "PUT",
|
|
2956
|
+
headers: {
|
|
2957
|
+
"Content-Type": "application/json",
|
|
2958
|
+
Authorization: `Bearer ${key}`,
|
|
2959
|
+
...await buildDeviceHeaders(configService)
|
|
2960
|
+
},
|
|
2961
|
+
body: JSON.stringify({
|
|
2962
|
+
instructions: localInstructions,
|
|
2963
|
+
commit_message: options.message
|
|
2964
|
+
})
|
|
2965
|
+
}
|
|
2966
|
+
);
|
|
2967
|
+
if (!res.ok) {
|
|
2968
|
+
const data2 = await res.json().catch(() => ({}));
|
|
2969
|
+
throw new Error(
|
|
2970
|
+
`API Error ${res.status}: ${data2.error || res.statusText}`
|
|
2971
|
+
);
|
|
2972
|
+
}
|
|
2973
|
+
const data = await res.json();
|
|
2974
|
+
for (const entry of localInstructions) {
|
|
2975
|
+
console.log(chalk10.green(` \u2714 ${entry.path}`));
|
|
2976
|
+
}
|
|
2977
|
+
const versionNote = data.version_number ? ` (saved as v${data.version_number})` : "";
|
|
2978
|
+
console.log(
|
|
2979
|
+
chalk10.green(`
|
|
2980
|
+
\u2714 Instructions pushed${versionNote}.
|
|
2981
|
+
`)
|
|
2982
|
+
);
|
|
2983
|
+
} catch (error) {
|
|
2984
|
+
console.error(
|
|
2985
|
+
chalk10.red("\n\u2716 Instructions push failed:"),
|
|
2986
|
+
error instanceof Error ? error.message : String(error)
|
|
2987
|
+
);
|
|
2988
|
+
process.exitCode = 1;
|
|
2989
|
+
}
|
|
2990
|
+
});
|
|
2991
|
+
instructionsCmd.command("status").description(
|
|
2992
|
+
"Check if local instruction files are in sync with the cloud"
|
|
2993
|
+
).action(async () => {
|
|
2994
|
+
await trackCommandUsage("instructions.status");
|
|
2995
|
+
try {
|
|
2996
|
+
const configService = new ConfigService();
|
|
2997
|
+
const key = await ensureAuthenticated(configService);
|
|
2998
|
+
const projectId = await configService.getProjectId();
|
|
2999
|
+
if (!projectId) {
|
|
3000
|
+
console.error(
|
|
3001
|
+
chalk10.red(
|
|
3002
|
+
"Error: No project linked. Run `vem link <projectId>` first."
|
|
3003
|
+
)
|
|
3004
|
+
);
|
|
3005
|
+
process.exitCode = 1;
|
|
3006
|
+
return;
|
|
3007
|
+
}
|
|
3008
|
+
const [localInstructions, cloudRes] = await Promise.all([
|
|
3009
|
+
readLocalInstructions(),
|
|
3010
|
+
fetch(`${API_URL}/projects/${projectId}/instructions`, {
|
|
3011
|
+
headers: {
|
|
3012
|
+
Authorization: `Bearer ${key}`,
|
|
3013
|
+
...await buildDeviceHeaders(configService)
|
|
3014
|
+
}
|
|
3015
|
+
})
|
|
3016
|
+
]);
|
|
3017
|
+
if (!cloudRes.ok) {
|
|
3018
|
+
const data = await cloudRes.json().catch(() => ({}));
|
|
3019
|
+
throw new Error(
|
|
3020
|
+
`API Error ${cloudRes.status}: ${data.error || cloudRes.statusText}`
|
|
3021
|
+
);
|
|
3022
|
+
}
|
|
3023
|
+
const cloudData = await cloudRes.json();
|
|
3024
|
+
const cloudInstructions = cloudData.instructions ?? [];
|
|
3025
|
+
const localMap = new Map(localInstructions.map((e) => [e.path, e.content]));
|
|
3026
|
+
const cloudMap = new Map(cloudInstructions.map((e) => [e.path, e.content]));
|
|
3027
|
+
const allPaths = /* @__PURE__ */ new Set([...localMap.keys(), ...cloudMap.keys()]);
|
|
3028
|
+
let inSync = true;
|
|
3029
|
+
console.log(chalk10.bold("\nInstruction file sync status:\n"));
|
|
3030
|
+
for (const filePath of [...allPaths].sort()) {
|
|
3031
|
+
const local = localMap.get(filePath);
|
|
3032
|
+
const cloud = cloudMap.get(filePath);
|
|
3033
|
+
if (local === void 0) {
|
|
3034
|
+
console.log(
|
|
3035
|
+
chalk10.yellow(` \u2193 ${filePath}`) + chalk10.gray(" (cloud only \u2014 run `vem instructions pull`)")
|
|
3036
|
+
);
|
|
3037
|
+
inSync = false;
|
|
3038
|
+
} else if (cloud === void 0) {
|
|
3039
|
+
console.log(
|
|
3040
|
+
chalk10.cyan(` \u2191 ${filePath}`) + chalk10.gray(" (local only \u2014 run `vem instructions push`)")
|
|
3041
|
+
);
|
|
3042
|
+
inSync = false;
|
|
3043
|
+
} else if (local !== cloud) {
|
|
3044
|
+
console.log(
|
|
3045
|
+
chalk10.magenta(` \u2260 ${filePath}`) + chalk10.gray(" (differs \u2014 run pull or push to sync)")
|
|
3046
|
+
);
|
|
3047
|
+
inSync = false;
|
|
3048
|
+
} else {
|
|
3049
|
+
console.log(chalk10.green(` \u2714 ${filePath}`) + chalk10.gray(" (in sync)"));
|
|
3050
|
+
}
|
|
3051
|
+
}
|
|
3052
|
+
if (allPaths.size === 0) {
|
|
3053
|
+
console.log(chalk10.gray(" No instructions configured."));
|
|
3054
|
+
}
|
|
3055
|
+
console.log(
|
|
3056
|
+
inSync ? chalk10.green("\n\u2714 All instruction files are in sync.\n") : chalk10.yellow("\n\u26A0 Some instruction files are out of sync.\n")
|
|
3057
|
+
);
|
|
3058
|
+
} catch (error) {
|
|
3059
|
+
console.error(
|
|
3060
|
+
chalk10.red("\n\u2716 Instructions status check failed:"),
|
|
3061
|
+
error instanceof Error ? error.message : String(error)
|
|
3062
|
+
);
|
|
3063
|
+
process.exitCode = 1;
|
|
3064
|
+
}
|
|
3065
|
+
});
|
|
3066
|
+
instructionsCmd.command("versions").description("List instruction version history from the cloud").option("-n, --limit <n>", "Maximum number of versions to show", "20").action(async (options) => {
|
|
3067
|
+
await trackCommandUsage("instructions.versions");
|
|
3068
|
+
try {
|
|
3069
|
+
const configService = new ConfigService();
|
|
3070
|
+
const key = await ensureAuthenticated(configService);
|
|
3071
|
+
const projectId = await configService.getProjectId();
|
|
3072
|
+
if (!projectId) {
|
|
3073
|
+
console.error(
|
|
3074
|
+
chalk10.red(
|
|
3075
|
+
"Error: No project linked. Run `vem link <projectId>` first."
|
|
3076
|
+
)
|
|
3077
|
+
);
|
|
3078
|
+
process.exitCode = 1;
|
|
3079
|
+
return;
|
|
3080
|
+
}
|
|
3081
|
+
const limit = Math.min(
|
|
3082
|
+
100,
|
|
3083
|
+
Math.max(1, Number.parseInt(options.limit ?? "20", 10) || 20)
|
|
3084
|
+
);
|
|
3085
|
+
const res = await fetch(
|
|
3086
|
+
`${API_URL}/projects/${projectId}/instructions/versions?limit=${limit}`,
|
|
3087
|
+
{
|
|
3088
|
+
headers: {
|
|
3089
|
+
Authorization: `Bearer ${key}`,
|
|
3090
|
+
...await buildDeviceHeaders(configService)
|
|
3091
|
+
}
|
|
3092
|
+
}
|
|
3093
|
+
);
|
|
3094
|
+
if (!res.ok) {
|
|
3095
|
+
const data2 = await res.json().catch(() => ({}));
|
|
3096
|
+
throw new Error(
|
|
3097
|
+
`API Error ${res.status}: ${data2.error || res.statusText}`
|
|
3098
|
+
);
|
|
3099
|
+
}
|
|
3100
|
+
const data = await res.json();
|
|
3101
|
+
const versions = data.versions ?? [];
|
|
3102
|
+
if (versions.length === 0) {
|
|
3103
|
+
console.log(chalk10.yellow("No instruction versions found."));
|
|
3104
|
+
return;
|
|
3105
|
+
}
|
|
3106
|
+
console.log(chalk10.bold("\nInstruction Version History:\n"));
|
|
3107
|
+
for (const [index, version] of versions.entries()) {
|
|
3108
|
+
const isLatest = index === 0;
|
|
3109
|
+
const date = new Date(version.created_at).toLocaleString();
|
|
3110
|
+
const tag = isLatest ? chalk10.green(" [current]") : "";
|
|
3111
|
+
const msg = version.commit_message ? chalk10.gray(` \u2014 ${version.commit_message}`) : "";
|
|
3112
|
+
const author = version.author ? chalk10.gray(` by ${version.author}`) : "";
|
|
3113
|
+
console.log(
|
|
3114
|
+
` ${chalk10.bold(`v${version.version_number}`)}${tag}${msg}${author}`
|
|
3115
|
+
);
|
|
3116
|
+
console.log(chalk10.gray(` ${date} \xB7 id: ${version.id}`));
|
|
3117
|
+
}
|
|
3118
|
+
console.log();
|
|
3119
|
+
} catch (error) {
|
|
3120
|
+
console.error(
|
|
3121
|
+
chalk10.red("\n\u2716 Failed to fetch versions:"),
|
|
3122
|
+
error instanceof Error ? error.message : String(error)
|
|
3123
|
+
);
|
|
3124
|
+
process.exitCode = 1;
|
|
3125
|
+
}
|
|
3126
|
+
});
|
|
3127
|
+
instructionsCmd.command("revert <versionId>").description("Revert instructions to a specific version by version ID").action(async (versionId) => {
|
|
3128
|
+
await trackCommandUsage("instructions.revert");
|
|
3129
|
+
try {
|
|
3130
|
+
const configService = new ConfigService();
|
|
3131
|
+
const key = await ensureAuthenticated(configService);
|
|
3132
|
+
const projectId = await configService.getProjectId();
|
|
3133
|
+
if (!projectId) {
|
|
3134
|
+
console.error(
|
|
3135
|
+
chalk10.red(
|
|
3136
|
+
"Error: No project linked. Run `vem link <projectId>` first."
|
|
3137
|
+
)
|
|
3138
|
+
);
|
|
3139
|
+
process.exitCode = 1;
|
|
3140
|
+
return;
|
|
3141
|
+
}
|
|
3142
|
+
console.log(
|
|
3143
|
+
chalk10.blue(`\u27F2 Reverting instructions to version ${versionId}...`)
|
|
3144
|
+
);
|
|
3145
|
+
const res = await fetch(
|
|
3146
|
+
`${API_URL}/projects/${projectId}/instructions/versions/${versionId}/revert`,
|
|
3147
|
+
{
|
|
3148
|
+
method: "POST",
|
|
3149
|
+
headers: {
|
|
3150
|
+
Authorization: `Bearer ${key}`,
|
|
3151
|
+
...await buildDeviceHeaders(configService)
|
|
3152
|
+
}
|
|
3153
|
+
}
|
|
3154
|
+
);
|
|
3155
|
+
if (!res.ok) {
|
|
3156
|
+
const data2 = await res.json().catch(() => ({}));
|
|
3157
|
+
throw new Error(
|
|
3158
|
+
`API Error ${res.status}: ${data2.error || res.statusText}`
|
|
3159
|
+
);
|
|
3160
|
+
}
|
|
3161
|
+
const data = await res.json();
|
|
3162
|
+
console.log(
|
|
3163
|
+
chalk10.green(
|
|
3164
|
+
`\u2714 Reverted to v${data.reverted_from} (new version: v${data.version_number})`
|
|
3165
|
+
)
|
|
3166
|
+
);
|
|
3167
|
+
console.log(
|
|
3168
|
+
chalk10.gray(
|
|
3169
|
+
" Run `vem instructions pull` to update local files."
|
|
3170
|
+
)
|
|
3171
|
+
);
|
|
3172
|
+
} catch (error) {
|
|
3173
|
+
console.error(
|
|
3174
|
+
chalk10.red("\n\u2716 Revert failed:"),
|
|
3175
|
+
error instanceof Error ? error.message : String(error)
|
|
3176
|
+
);
|
|
3177
|
+
process.exitCode = 1;
|
|
3178
|
+
}
|
|
3179
|
+
});
|
|
3180
|
+
}
|
|
3181
|
+
|
|
2800
3182
|
// src/commands/maintenance.ts
|
|
2801
3183
|
import { execSync as execSync3 } from "child_process";
|
|
2802
|
-
import
|
|
2803
|
-
import
|
|
2804
|
-
import
|
|
3184
|
+
import path2 from "path";
|
|
3185
|
+
import chalk11 from "chalk";
|
|
3186
|
+
import fs3 from "fs-extra";
|
|
2805
3187
|
function registerMaintenanceCommands(program2) {
|
|
2806
3188
|
const getCurrentStateFromLocalCache = async () => {
|
|
2807
3189
|
try {
|
|
2808
3190
|
const vemDir = await getVemDir();
|
|
2809
|
-
const currentStatePath =
|
|
2810
|
-
if (!await
|
|
2811
|
-
return await
|
|
3191
|
+
const currentStatePath = path2.join(vemDir, CURRENT_STATE_FILE);
|
|
3192
|
+
if (!await fs3.pathExists(currentStatePath)) return "";
|
|
3193
|
+
return await fs3.readFile(currentStatePath, "utf-8");
|
|
2812
3194
|
} catch {
|
|
2813
3195
|
return "";
|
|
2814
3196
|
}
|
|
2815
3197
|
};
|
|
2816
3198
|
const writeCurrentStateToLocalCache = async (content) => {
|
|
2817
3199
|
const vemDir = await getVemDir();
|
|
2818
|
-
const currentStatePath =
|
|
2819
|
-
await
|
|
3200
|
+
const currentStatePath = path2.join(vemDir, CURRENT_STATE_FILE);
|
|
3201
|
+
await fs3.writeFile(currentStatePath, content, "utf-8");
|
|
2820
3202
|
};
|
|
2821
3203
|
const resolveRemoteProjectAuth = async () => {
|
|
2822
3204
|
const configService = new ConfigService();
|
|
@@ -2836,21 +3218,21 @@ function registerMaintenanceCommands(program2) {
|
|
|
2836
3218
|
try {
|
|
2837
3219
|
if (!options.context || !options.decision) {
|
|
2838
3220
|
console.error(
|
|
2839
|
-
|
|
3221
|
+
chalk11.red("\n\u2716 Both --context and --decision are required.\n")
|
|
2840
3222
|
);
|
|
2841
|
-
console.log(
|
|
3223
|
+
console.log(chalk11.gray("Example:"));
|
|
2842
3224
|
console.log(
|
|
2843
|
-
|
|
3225
|
+
chalk11.gray(' vem decision add "Use Zod for validation" \\')
|
|
2844
3226
|
);
|
|
2845
3227
|
console.log(
|
|
2846
|
-
|
|
3228
|
+
chalk11.gray(' --context "Need runtime type checking" \\')
|
|
2847
3229
|
);
|
|
2848
3230
|
console.log(
|
|
2849
|
-
|
|
3231
|
+
chalk11.gray(
|
|
2850
3232
|
' --decision "Chose Zod over Yup for better TypeScript inference" \\'
|
|
2851
3233
|
)
|
|
2852
3234
|
);
|
|
2853
|
-
console.log(
|
|
3235
|
+
console.log(chalk11.gray(" --tasks TASK-042,TASK-043"));
|
|
2854
3236
|
return;
|
|
2855
3237
|
}
|
|
2856
3238
|
const relatedTasks = options.tasks ? options.tasks.split(",").map((t) => t.trim()).filter(Boolean) : void 0;
|
|
@@ -2890,20 +3272,20 @@ function registerMaintenanceCommands(program2) {
|
|
|
2890
3272
|
relatedTasks
|
|
2891
3273
|
);
|
|
2892
3274
|
console.log(
|
|
2893
|
-
|
|
3275
|
+
chalk11.green(
|
|
2894
3276
|
`
|
|
2895
3277
|
\u2714 Decision recorded${savedToCloud ? " (cloud + local cache)" : " (local cache)"}: ${title}`
|
|
2896
3278
|
)
|
|
2897
3279
|
);
|
|
2898
3280
|
if (relatedTasks && relatedTasks.length > 0) {
|
|
2899
3281
|
console.log(
|
|
2900
|
-
|
|
3282
|
+
chalk11.gray(` Related tasks: ${relatedTasks.join(", ")}`)
|
|
2901
3283
|
);
|
|
2902
3284
|
}
|
|
2903
3285
|
console.log();
|
|
2904
3286
|
} catch (error) {
|
|
2905
3287
|
console.error(
|
|
2906
|
-
|
|
3288
|
+
chalk11.red(`
|
|
2907
3289
|
\u2716 Failed to record decision: ${error.message}
|
|
2908
3290
|
`)
|
|
2909
3291
|
);
|
|
@@ -2926,13 +3308,13 @@ function registerMaintenanceCommands(program2) {
|
|
|
2926
3308
|
);
|
|
2927
3309
|
if (response.ok) {
|
|
2928
3310
|
const payload = await response.json();
|
|
2929
|
-
console.log(
|
|
2930
|
-
console.log(
|
|
3311
|
+
console.log(chalk11.bold("\nProject Context"));
|
|
3312
|
+
console.log(chalk11.gray(`Source: ${payload.source || "db"}`));
|
|
2931
3313
|
console.log(payload.context || "");
|
|
2932
|
-
console.log(
|
|
3314
|
+
console.log(chalk11.bold("\nCurrent State"));
|
|
2933
3315
|
console.log(payload.current_state || "");
|
|
2934
3316
|
if (payload.decisions && payload.decisions.trim().length > 0) {
|
|
2935
|
-
console.log(
|
|
3317
|
+
console.log(chalk11.bold("\nDecisions"));
|
|
2936
3318
|
console.log(payload.decisions);
|
|
2937
3319
|
}
|
|
2938
3320
|
console.log("");
|
|
@@ -2944,14 +3326,14 @@ function registerMaintenanceCommands(program2) {
|
|
|
2944
3326
|
configService.getContext(),
|
|
2945
3327
|
getCurrentStateFromLocalCache()
|
|
2946
3328
|
]);
|
|
2947
|
-
console.log(
|
|
3329
|
+
console.log(chalk11.bold("\nProject Context (local cache)"));
|
|
2948
3330
|
console.log(context || "");
|
|
2949
|
-
console.log(
|
|
3331
|
+
console.log(chalk11.bold("\nCurrent State (local cache)"));
|
|
2950
3332
|
console.log(currentState || "");
|
|
2951
3333
|
console.log("");
|
|
2952
3334
|
} catch (error) {
|
|
2953
3335
|
console.error(
|
|
2954
|
-
|
|
3336
|
+
chalk11.red(`
|
|
2955
3337
|
\u2716 Failed to read context: ${error.message}
|
|
2956
3338
|
`)
|
|
2957
3339
|
);
|
|
@@ -2961,7 +3343,7 @@ function registerMaintenanceCommands(program2) {
|
|
|
2961
3343
|
try {
|
|
2962
3344
|
if (options.context === void 0 && options.currentState === void 0) {
|
|
2963
3345
|
console.error(
|
|
2964
|
-
|
|
3346
|
+
chalk11.red(
|
|
2965
3347
|
"\n\u2716 Provide at least one of --context or --current-state.\n"
|
|
2966
3348
|
)
|
|
2967
3349
|
);
|
|
@@ -2990,7 +3372,7 @@ function registerMaintenanceCommands(program2) {
|
|
|
2990
3372
|
} else {
|
|
2991
3373
|
const payload = await response.json().catch(() => ({}));
|
|
2992
3374
|
console.log(
|
|
2993
|
-
|
|
3375
|
+
chalk11.yellow(
|
|
2994
3376
|
`Cloud context update failed; continuing with local cache only: ${payload.error || response.statusText}`
|
|
2995
3377
|
)
|
|
2996
3378
|
);
|
|
@@ -3004,7 +3386,7 @@ function registerMaintenanceCommands(program2) {
|
|
|
3004
3386
|
await writeCurrentStateToLocalCache(options.currentState);
|
|
3005
3387
|
}
|
|
3006
3388
|
console.log(
|
|
3007
|
-
|
|
3389
|
+
chalk11.green(
|
|
3008
3390
|
`
|
|
3009
3391
|
\u2714 Context updated${savedToCloud ? " (cloud + local cache)" : " (local cache)"}
|
|
3010
3392
|
`
|
|
@@ -3012,7 +3394,7 @@ function registerMaintenanceCommands(program2) {
|
|
|
3012
3394
|
);
|
|
3013
3395
|
} catch (error) {
|
|
3014
3396
|
console.error(
|
|
3015
|
-
|
|
3397
|
+
chalk11.red(`
|
|
3016
3398
|
\u2716 Failed to update context: ${error.message}
|
|
3017
3399
|
`)
|
|
3018
3400
|
);
|
|
@@ -3027,50 +3409,50 @@ function registerMaintenanceCommands(program2) {
|
|
|
3027
3409
|
console.log(JSON.stringify(result, null, 2));
|
|
3028
3410
|
return;
|
|
3029
3411
|
}
|
|
3030
|
-
console.log(
|
|
3031
|
-
console.log(
|
|
3412
|
+
console.log(chalk11.bold("\nVEM Diff (local vs. cloud)"));
|
|
3413
|
+
console.log(chalk11.gray("\u2500".repeat(50)));
|
|
3032
3414
|
if (result.tasks.added.length > 0 || result.tasks.modified.length > 0) {
|
|
3033
|
-
console.log(
|
|
3415
|
+
console.log(chalk11.bold("\nTasks:"));
|
|
3034
3416
|
for (const id of result.tasks.added) {
|
|
3035
|
-
console.log(
|
|
3417
|
+
console.log(chalk11.green(` + ${id} (new)`));
|
|
3036
3418
|
}
|
|
3037
3419
|
for (const mod of result.tasks.modified) {
|
|
3038
|
-
console.log(
|
|
3420
|
+
console.log(chalk11.yellow(` ~ ${mod.id} (${mod.changes})`));
|
|
3039
3421
|
}
|
|
3040
3422
|
}
|
|
3041
3423
|
if (result.decisions.added.length > 0) {
|
|
3042
|
-
console.log(
|
|
3424
|
+
console.log(chalk11.bold("\nDecisions:"));
|
|
3043
3425
|
console.log(
|
|
3044
|
-
|
|
3426
|
+
chalk11.green(` + ${result.decisions.added.length} new decisions`)
|
|
3045
3427
|
);
|
|
3046
3428
|
}
|
|
3047
3429
|
if (result.changelog.added.length > 0) {
|
|
3048
|
-
console.log(
|
|
3430
|
+
console.log(chalk11.bold("\nChangelog:"));
|
|
3049
3431
|
console.log(
|
|
3050
|
-
|
|
3432
|
+
chalk11.green(` + ${result.changelog.added.length} new entries`)
|
|
3051
3433
|
);
|
|
3052
3434
|
}
|
|
3053
3435
|
if (result.currentState.changed) {
|
|
3054
|
-
console.log(
|
|
3436
|
+
console.log(chalk11.bold("\nCurrent State:"));
|
|
3055
3437
|
console.log(
|
|
3056
|
-
|
|
3438
|
+
chalk11.yellow(
|
|
3057
3439
|
` ~ Modified locally (${result.currentState.lineCount} lines)`
|
|
3058
3440
|
)
|
|
3059
3441
|
);
|
|
3060
3442
|
}
|
|
3061
|
-
console.log(
|
|
3443
|
+
console.log(chalk11.gray(`
|
|
3062
3444
|
${"\u2500".repeat(50)}`));
|
|
3063
3445
|
console.log(
|
|
3064
|
-
|
|
3446
|
+
chalk11.bold(`Summary: ${result.summary.totalChanges} changes`)
|
|
3065
3447
|
);
|
|
3066
3448
|
if (result.summary.totalChanges > 0) {
|
|
3067
|
-
console.log(
|
|
3449
|
+
console.log(chalk11.gray("Run: vem push\n"));
|
|
3068
3450
|
} else {
|
|
3069
|
-
console.log(
|
|
3451
|
+
console.log(chalk11.gray("No changes to push\n"));
|
|
3070
3452
|
}
|
|
3071
3453
|
} catch (error) {
|
|
3072
3454
|
console.error(
|
|
3073
|
-
|
|
3455
|
+
chalk11.red(`
|
|
3074
3456
|
\u2716 Failed to generate diff: ${error.message}
|
|
3075
3457
|
`)
|
|
3076
3458
|
);
|
|
@@ -3088,8 +3470,8 @@ ${"\u2500".repeat(50)}`));
|
|
|
3088
3470
|
);
|
|
3089
3471
|
return;
|
|
3090
3472
|
}
|
|
3091
|
-
console.log(
|
|
3092
|
-
console.log(
|
|
3473
|
+
console.log(chalk11.bold("\nVEM Health Check"));
|
|
3474
|
+
console.log(chalk11.gray("\u2500".repeat(50)));
|
|
3093
3475
|
let hasErrors = false;
|
|
3094
3476
|
let hasWarnings = false;
|
|
3095
3477
|
for (const result of results) {
|
|
@@ -3097,36 +3479,36 @@ ${"\u2500".repeat(50)}`));
|
|
|
3097
3479
|
let color;
|
|
3098
3480
|
if (result.status === "pass") {
|
|
3099
3481
|
icon = "\u2713";
|
|
3100
|
-
color =
|
|
3482
|
+
color = chalk11.green;
|
|
3101
3483
|
} else if (result.status === "warn") {
|
|
3102
3484
|
icon = "\u26A0";
|
|
3103
|
-
color =
|
|
3485
|
+
color = chalk11.yellow;
|
|
3104
3486
|
hasWarnings = true;
|
|
3105
3487
|
} else {
|
|
3106
3488
|
icon = "\u2717";
|
|
3107
|
-
color =
|
|
3489
|
+
color = chalk11.red;
|
|
3108
3490
|
hasErrors = true;
|
|
3109
3491
|
}
|
|
3110
3492
|
console.log(color(`${icon} ${result.name}`));
|
|
3111
|
-
console.log(
|
|
3493
|
+
console.log(chalk11.gray(` ${result.message}`));
|
|
3112
3494
|
if (result.fix) {
|
|
3113
|
-
console.log(
|
|
3495
|
+
console.log(chalk11.gray(` \u2192 ${result.fix}`));
|
|
3114
3496
|
}
|
|
3115
3497
|
}
|
|
3116
|
-
console.log(
|
|
3498
|
+
console.log(chalk11.gray("\u2500".repeat(50)));
|
|
3117
3499
|
if (hasErrors) {
|
|
3118
|
-
console.log(
|
|
3500
|
+
console.log(chalk11.red("\n\u2717 Issues found that need attention\n"));
|
|
3119
3501
|
process.exit(2);
|
|
3120
3502
|
} else if (hasWarnings) {
|
|
3121
|
-
console.log(
|
|
3503
|
+
console.log(chalk11.yellow("\n\u26A0 Minor issues found\n"));
|
|
3122
3504
|
process.exit(1);
|
|
3123
3505
|
} else {
|
|
3124
|
-
console.log(
|
|
3506
|
+
console.log(chalk11.green("\n\u2713 All checks passed\n"));
|
|
3125
3507
|
process.exit(0);
|
|
3126
3508
|
}
|
|
3127
3509
|
} catch (error) {
|
|
3128
3510
|
console.error(
|
|
3129
|
-
|
|
3511
|
+
chalk11.red(`
|
|
3130
3512
|
\u2716 Failed to run health checks: ${error.message}
|
|
3131
3513
|
`)
|
|
3132
3514
|
);
|
|
@@ -3141,15 +3523,15 @@ ${"\u2500".repeat(50)}`));
|
|
|
3141
3523
|
const projectId = await configService.getProjectId();
|
|
3142
3524
|
if (!key || !projectId) {
|
|
3143
3525
|
console.error(
|
|
3144
|
-
|
|
3526
|
+
chalk11.red("\n\u2716 Authentication or project link missing.\n")
|
|
3145
3527
|
);
|
|
3146
3528
|
return;
|
|
3147
3529
|
}
|
|
3148
|
-
console.log(
|
|
3530
|
+
console.log(chalk11.blue("Analyzing local changes..."));
|
|
3149
3531
|
const diffCmd = options.staged ? "git diff --cached" : "git diff HEAD";
|
|
3150
3532
|
const diff = execSync3(diffCmd).toString();
|
|
3151
3533
|
if (!diff.trim()) {
|
|
3152
|
-
console.log(
|
|
3534
|
+
console.log(chalk11.yellow("No changes detected to summarize."));
|
|
3153
3535
|
return;
|
|
3154
3536
|
}
|
|
3155
3537
|
const res = await fetch(`${API_URL}/projects/${projectId}/summarize`, {
|
|
@@ -3166,37 +3548,37 @@ ${"\u2500".repeat(50)}`));
|
|
|
3166
3548
|
throw new Error(data.error || "Summarization request failed");
|
|
3167
3549
|
}
|
|
3168
3550
|
const { suggestions } = await res.json();
|
|
3169
|
-
console.log(
|
|
3170
|
-
console.log(
|
|
3551
|
+
console.log(chalk11.bold("\n\u2728 AI-Suggested Memory Updates"));
|
|
3552
|
+
console.log(chalk11.gray("\u2500".repeat(50)));
|
|
3171
3553
|
if (suggestions.changelog) {
|
|
3172
|
-
console.log(
|
|
3554
|
+
console.log(chalk11.cyan("\n[Changelog]"));
|
|
3173
3555
|
console.log(suggestions.changelog);
|
|
3174
3556
|
}
|
|
3175
3557
|
if (suggestions.decisions?.length > 0) {
|
|
3176
|
-
console.log(
|
|
3558
|
+
console.log(chalk11.cyan("\n[Decisions]"));
|
|
3177
3559
|
suggestions.decisions.forEach((d) => {
|
|
3178
|
-
console.log(
|
|
3179
|
-
console.log(
|
|
3560
|
+
console.log(chalk11.bold(`- ${d.title}`));
|
|
3561
|
+
console.log(chalk11.gray(` ${d.decision}`));
|
|
3180
3562
|
});
|
|
3181
3563
|
}
|
|
3182
3564
|
if (suggestions.context_updates) {
|
|
3183
|
-
console.log(
|
|
3565
|
+
console.log(chalk11.cyan("\n[Context Updates]"));
|
|
3184
3566
|
console.log(suggestions.context_updates);
|
|
3185
3567
|
}
|
|
3186
3568
|
if (suggestions.current_state_updates) {
|
|
3187
|
-
console.log(
|
|
3569
|
+
console.log(chalk11.cyan("\n[Current State Updates]"));
|
|
3188
3570
|
console.log(suggestions.current_state_updates);
|
|
3189
3571
|
}
|
|
3190
|
-
console.log(
|
|
3572
|
+
console.log(chalk11.gray(`
|
|
3191
3573
|
${"\u2500".repeat(50)}`));
|
|
3192
3574
|
console.log(
|
|
3193
|
-
|
|
3575
|
+
chalk11.gray(
|
|
3194
3576
|
"Tip: Use these suggestions to update your .vem/ files before pushing.\n"
|
|
3195
3577
|
)
|
|
3196
3578
|
);
|
|
3197
3579
|
} catch (error) {
|
|
3198
3580
|
console.error(
|
|
3199
|
-
|
|
3581
|
+
chalk11.red(`
|
|
3200
3582
|
\u2716 Failed to generate summary: ${error.message}
|
|
3201
3583
|
`)
|
|
3202
3584
|
);
|
|
@@ -3205,8 +3587,8 @@ ${"\u2500".repeat(50)}`));
|
|
|
3205
3587
|
}
|
|
3206
3588
|
|
|
3207
3589
|
// src/commands/project.ts
|
|
3208
|
-
import
|
|
3209
|
-
import
|
|
3590
|
+
import chalk12 from "chalk";
|
|
3591
|
+
import prompts6 from "prompts";
|
|
3210
3592
|
async function runInteractiveLinkFlow(apiKey, configService) {
|
|
3211
3593
|
let projectId;
|
|
3212
3594
|
let projectOrgId = await configService.getProjectOrgId();
|
|
@@ -3220,7 +3602,7 @@ async function runInteractiveLinkFlow(apiKey, configService) {
|
|
|
3220
3602
|
});
|
|
3221
3603
|
if (!res.ok) {
|
|
3222
3604
|
console.error(
|
|
3223
|
-
|
|
3605
|
+
chalk12.red(`
|
|
3224
3606
|
\u2716 Failed to fetch projects: ${res.statusText}
|
|
3225
3607
|
`)
|
|
3226
3608
|
);
|
|
@@ -3272,7 +3654,7 @@ async function runInteractiveLinkFlow(apiKey, configService) {
|
|
|
3272
3654
|
);
|
|
3273
3655
|
const choices = [
|
|
3274
3656
|
{
|
|
3275
|
-
title:
|
|
3657
|
+
title: chalk12.green("+ Create New Project"),
|
|
3276
3658
|
value: CREATE_NEW,
|
|
3277
3659
|
description: `Create a new project in ${workspace.label}`
|
|
3278
3660
|
}
|
|
@@ -3287,19 +3669,19 @@ async function runInteractiveLinkFlow(apiKey, configService) {
|
|
|
3287
3669
|
}
|
|
3288
3670
|
} else {
|
|
3289
3671
|
choices.push({
|
|
3290
|
-
title:
|
|
3672
|
+
title: chalk12.gray("No projects yet"),
|
|
3291
3673
|
value: "NO_PROJECTS",
|
|
3292
3674
|
disabled: true
|
|
3293
3675
|
});
|
|
3294
3676
|
}
|
|
3295
3677
|
if (allowBack) {
|
|
3296
3678
|
choices.push({
|
|
3297
|
-
title:
|
|
3679
|
+
title: chalk12.gray("\u2190 Back"),
|
|
3298
3680
|
value: BACK
|
|
3299
3681
|
});
|
|
3300
3682
|
}
|
|
3301
3683
|
const message = workspace.isPersonal ? "Select a personal project to link:" : `Select a project in ${workspace.label}:`;
|
|
3302
|
-
const response = await
|
|
3684
|
+
const response = await prompts6({
|
|
3303
3685
|
type: "select",
|
|
3304
3686
|
name: "projectId",
|
|
3305
3687
|
message,
|
|
@@ -3309,7 +3691,7 @@ async function runInteractiveLinkFlow(apiKey, configService) {
|
|
|
3309
3691
|
if (!selectedProjectId) return { type: "cancel" };
|
|
3310
3692
|
if (selectedProjectId === BACK) return { type: "back" };
|
|
3311
3693
|
if (selectedProjectId === CREATE_NEW) {
|
|
3312
|
-
const projectInput = await
|
|
3694
|
+
const projectInput = await prompts6({
|
|
3313
3695
|
type: "text",
|
|
3314
3696
|
name: "name",
|
|
3315
3697
|
message: `Enter project name for ${workspace.label}:`,
|
|
@@ -3339,7 +3721,7 @@ async function runInteractiveLinkFlow(apiKey, configService) {
|
|
|
3339
3721
|
const err = await createRes.json().catch(() => ({}));
|
|
3340
3722
|
if (createRes.status === 403) {
|
|
3341
3723
|
console.error(
|
|
3342
|
-
|
|
3724
|
+
chalk12.red(
|
|
3343
3725
|
`
|
|
3344
3726
|
\u2716 Check failed: ${err.error || "Tier limit reached"}
|
|
3345
3727
|
`
|
|
@@ -3347,7 +3729,7 @@ async function runInteractiveLinkFlow(apiKey, configService) {
|
|
|
3347
3729
|
);
|
|
3348
3730
|
} else if (createRes.status === 409) {
|
|
3349
3731
|
console.error(
|
|
3350
|
-
|
|
3732
|
+
chalk12.red(
|
|
3351
3733
|
`
|
|
3352
3734
|
\u2716 ${err.error || "Failed to create project: Already exists."}
|
|
3353
3735
|
`
|
|
@@ -3355,7 +3737,7 @@ async function runInteractiveLinkFlow(apiKey, configService) {
|
|
|
3355
3737
|
);
|
|
3356
3738
|
} else {
|
|
3357
3739
|
console.error(
|
|
3358
|
-
|
|
3740
|
+
chalk12.red(
|
|
3359
3741
|
`
|
|
3360
3742
|
\u2716 Failed to create project: ${err.error || createRes.statusText}
|
|
3361
3743
|
`
|
|
@@ -3365,7 +3747,7 @@ async function runInteractiveLinkFlow(apiKey, configService) {
|
|
|
3365
3747
|
return { type: "cancel" };
|
|
3366
3748
|
}
|
|
3367
3749
|
const { project } = await createRes.json();
|
|
3368
|
-
console.log(
|
|
3750
|
+
console.log(chalk12.green(`
|
|
3369
3751
|
\u2714 Project created: ${project.id}`));
|
|
3370
3752
|
return {
|
|
3371
3753
|
type: "selected",
|
|
@@ -3387,19 +3769,19 @@ async function runInteractiveLinkFlow(apiKey, configService) {
|
|
|
3387
3769
|
const personalWorkspace = workspaceChoices.find((item) => item.isPersonal);
|
|
3388
3770
|
const activeWorkspace = personalWorkspace || workspaceChoices[0];
|
|
3389
3771
|
if (!activeWorkspace) {
|
|
3390
|
-
console.log(
|
|
3772
|
+
console.log(chalk12.yellow("\nNo available workspaces found.\n"));
|
|
3391
3773
|
return null;
|
|
3392
3774
|
}
|
|
3393
3775
|
const selection = await chooseProjectForWorkspace(activeWorkspace, false);
|
|
3394
3776
|
if (selection.type !== "selected") {
|
|
3395
|
-
console.log(
|
|
3777
|
+
console.log(chalk12.yellow("\nOperation cancelled.\n"));
|
|
3396
3778
|
return null;
|
|
3397
3779
|
}
|
|
3398
3780
|
projectId = selection.projectId;
|
|
3399
3781
|
projectOrgId = selection.orgId || projectOrgId;
|
|
3400
3782
|
} else {
|
|
3401
3783
|
while (!projectId) {
|
|
3402
|
-
const workspaceResponse = await
|
|
3784
|
+
const workspaceResponse = await prompts6({
|
|
3403
3785
|
type: "select",
|
|
3404
3786
|
name: "workspaceId",
|
|
3405
3787
|
message: "Select personal or organization workspace:",
|
|
@@ -3410,12 +3792,12 @@ async function runInteractiveLinkFlow(apiKey, configService) {
|
|
|
3410
3792
|
});
|
|
3411
3793
|
const selectedWorkspaceId = workspaceResponse.workspaceId;
|
|
3412
3794
|
if (!selectedWorkspaceId) {
|
|
3413
|
-
console.log(
|
|
3795
|
+
console.log(chalk12.yellow("\nOperation cancelled.\n"));
|
|
3414
3796
|
return null;
|
|
3415
3797
|
}
|
|
3416
3798
|
const selectedWorkspace = workspaceMap.get(selectedWorkspaceId);
|
|
3417
3799
|
if (!selectedWorkspace) {
|
|
3418
|
-
console.log(
|
|
3800
|
+
console.log(chalk12.yellow("\nOperation cancelled.\n"));
|
|
3419
3801
|
return null;
|
|
3420
3802
|
}
|
|
3421
3803
|
const selection = await chooseProjectForWorkspace(
|
|
@@ -3423,7 +3805,7 @@ async function runInteractiveLinkFlow(apiKey, configService) {
|
|
|
3423
3805
|
true
|
|
3424
3806
|
);
|
|
3425
3807
|
if (selection.type === "cancel") {
|
|
3426
|
-
console.log(
|
|
3808
|
+
console.log(chalk12.yellow("\nOperation cancelled.\n"));
|
|
3427
3809
|
return null;
|
|
3428
3810
|
}
|
|
3429
3811
|
if (selection.type === "back") {
|
|
@@ -3458,14 +3840,14 @@ async function runInteractiveLinkFlow(apiKey, configService) {
|
|
|
3458
3840
|
if (!patchRes.ok) {
|
|
3459
3841
|
const err = await patchRes.text().catch(() => "");
|
|
3460
3842
|
console.log(
|
|
3461
|
-
|
|
3843
|
+
chalk12.yellow(
|
|
3462
3844
|
` \u26A0 Warning: Failed to update server-side repo URL: ${err || patchRes.statusText}`
|
|
3463
3845
|
)
|
|
3464
3846
|
);
|
|
3465
3847
|
}
|
|
3466
3848
|
} catch (_err) {
|
|
3467
3849
|
console.log(
|
|
3468
|
-
|
|
3850
|
+
chalk12.yellow(" \u26A0 Warning: Could not reach server to update repo URL.")
|
|
3469
3851
|
);
|
|
3470
3852
|
}
|
|
3471
3853
|
if (repoUrl === "REMOVE" || !repoUrl) {
|
|
@@ -3479,14 +3861,14 @@ async function runInteractiveLinkFlow(apiKey, configService) {
|
|
|
3479
3861
|
await installGitHook({ promptIfMissing: false, quiet: true });
|
|
3480
3862
|
if (!repoUrl || repoUrl === "REMOVE") {
|
|
3481
3863
|
console.log(
|
|
3482
|
-
|
|
3864
|
+
chalk12.yellow(
|
|
3483
3865
|
"\n\u26A0 For full advantage of vem (automatic indexing, code search, and PR summaries), you should link a repo origin."
|
|
3484
3866
|
)
|
|
3485
3867
|
);
|
|
3486
3868
|
} else {
|
|
3487
|
-
console.log(
|
|
3869
|
+
console.log(chalk12.gray(`Repo: ${repoUrl}`));
|
|
3488
3870
|
}
|
|
3489
|
-
console.log(
|
|
3871
|
+
console.log(chalk12.green(`
|
|
3490
3872
|
\u2714 Linked to project ${projectId}
|
|
3491
3873
|
`));
|
|
3492
3874
|
return projectId;
|
|
@@ -3505,7 +3887,7 @@ function registerProjectCommands(program2) {
|
|
|
3505
3887
|
projectId = await configService.getProjectId();
|
|
3506
3888
|
if (!projectId) {
|
|
3507
3889
|
console.error(
|
|
3508
|
-
|
|
3890
|
+
chalk12.red(
|
|
3509
3891
|
"\n\u2716 Not linked to any project. Link a project first or provide a projectId.\n"
|
|
3510
3892
|
)
|
|
3511
3893
|
);
|
|
@@ -3516,7 +3898,7 @@ function registerProjectCommands(program2) {
|
|
|
3516
3898
|
const check = await validateProject(projectId, apiKey, configService);
|
|
3517
3899
|
if (!check.valid) {
|
|
3518
3900
|
console.error(
|
|
3519
|
-
|
|
3901
|
+
chalk12.red(
|
|
3520
3902
|
`
|
|
3521
3903
|
\u2716 Project ${projectId} not found. It may have been deleted or you may not have access.
|
|
3522
3904
|
`
|
|
@@ -3553,14 +3935,14 @@ function registerProjectCommands(program2) {
|
|
|
3553
3935
|
if (!res.ok) {
|
|
3554
3936
|
const err = await res.text().catch(() => "");
|
|
3555
3937
|
console.log(
|
|
3556
|
-
|
|
3938
|
+
chalk12.yellow(
|
|
3557
3939
|
` \u26A0 Warning: Failed to update server-side repo URL: ${err || res.statusText}`
|
|
3558
3940
|
)
|
|
3559
3941
|
);
|
|
3560
3942
|
}
|
|
3561
3943
|
} catch (_err) {
|
|
3562
3944
|
console.log(
|
|
3563
|
-
|
|
3945
|
+
chalk12.yellow(
|
|
3564
3946
|
" \u26A0 Warning: Could not reach server to update repo URL."
|
|
3565
3947
|
)
|
|
3566
3948
|
);
|
|
@@ -3577,39 +3959,39 @@ function registerProjectCommands(program2) {
|
|
|
3577
3959
|
await installGitHook({ promptIfMissing: false, quiet: true });
|
|
3578
3960
|
if (options.reset) {
|
|
3579
3961
|
if (repoUrl === "REMOVE") {
|
|
3580
|
-
console.log(
|
|
3962
|
+
console.log(chalk12.green("\n\u2714 Repository binding removed."));
|
|
3581
3963
|
console.log(
|
|
3582
|
-
|
|
3964
|
+
chalk12.yellow(
|
|
3583
3965
|
"\u26A0 For full advantage of vem (automatic indexing, code search, and PR summaries), you should link a repo origin."
|
|
3584
3966
|
)
|
|
3585
3967
|
);
|
|
3586
3968
|
} else if (repoUrl) {
|
|
3587
3969
|
console.log(
|
|
3588
|
-
|
|
3970
|
+
chalk12.green(`
|
|
3589
3971
|
\u2714 Repository binding updated to: ${repoUrl}`)
|
|
3590
3972
|
);
|
|
3591
3973
|
}
|
|
3592
3974
|
} else {
|
|
3593
3975
|
if (!repoUrl || repoUrl === "REMOVE") {
|
|
3594
3976
|
console.log(
|
|
3595
|
-
|
|
3977
|
+
chalk12.yellow(
|
|
3596
3978
|
"\n\u26A0 For full advantage of vem (automatic indexing, code search, and PR summaries), you should link a repo origin."
|
|
3597
3979
|
)
|
|
3598
3980
|
);
|
|
3599
3981
|
} else {
|
|
3600
|
-
console.log(
|
|
3982
|
+
console.log(chalk12.gray(`Repo: ${repoUrl}`));
|
|
3601
3983
|
}
|
|
3602
3984
|
}
|
|
3603
3985
|
if (!options.reset) {
|
|
3604
|
-
console.log(
|
|
3986
|
+
console.log(chalk12.green(`
|
|
3605
3987
|
\u2714 Linked to project ${projectId}
|
|
3606
3988
|
`));
|
|
3607
3989
|
}
|
|
3608
3990
|
} catch (error) {
|
|
3609
3991
|
if (error instanceof Error) {
|
|
3610
|
-
console.error(
|
|
3992
|
+
console.error(chalk12.red("\n\u2716 Link Failed:"), error.message);
|
|
3611
3993
|
} else {
|
|
3612
|
-
console.error(
|
|
3994
|
+
console.error(chalk12.red("\n\u2716 Link Failed:"), String(error));
|
|
3613
3995
|
}
|
|
3614
3996
|
}
|
|
3615
3997
|
});
|
|
@@ -3618,7 +4000,7 @@ function registerProjectCommands(program2) {
|
|
|
3618
4000
|
const configService = new ConfigService();
|
|
3619
4001
|
const projectId = await configService.getProjectId();
|
|
3620
4002
|
if (!projectId) {
|
|
3621
|
-
console.log(
|
|
4003
|
+
console.log(chalk12.yellow("\n\u26A0 Not linked to any project.\n"));
|
|
3622
4004
|
return;
|
|
3623
4005
|
}
|
|
3624
4006
|
const apiKey = await ensureAuthenticated(configService);
|
|
@@ -3637,25 +4019,25 @@ function registerProjectCommands(program2) {
|
|
|
3637
4019
|
}
|
|
3638
4020
|
} catch (_) {
|
|
3639
4021
|
}
|
|
3640
|
-
const response = await
|
|
4022
|
+
const response = await prompts6({
|
|
3641
4023
|
type: "confirm",
|
|
3642
4024
|
name: "confirmed",
|
|
3643
|
-
message: `Are you sure you want to unlink from project ${
|
|
4025
|
+
message: `Are you sure you want to unlink from project ${chalk12.bold(projectName)} (${projectId})?`,
|
|
3644
4026
|
initial: false
|
|
3645
4027
|
});
|
|
3646
4028
|
if (response.confirmed) {
|
|
3647
4029
|
await configService.setProjectId(null);
|
|
3648
4030
|
await configService.setProjectOrgId(null);
|
|
3649
4031
|
await configService.setLinkedRemote(null);
|
|
3650
|
-
console.log(
|
|
4032
|
+
console.log(chalk12.green("\n\u2714 Unlinked from project.\n"));
|
|
3651
4033
|
} else {
|
|
3652
|
-
console.log(
|
|
4034
|
+
console.log(chalk12.yellow("\nOperation cancelled.\n"));
|
|
3653
4035
|
}
|
|
3654
4036
|
} catch (error) {
|
|
3655
4037
|
if (error instanceof Error) {
|
|
3656
|
-
console.error(
|
|
4038
|
+
console.error(chalk12.red("\n\u2716 Unlink Failed:"), error.message);
|
|
3657
4039
|
} else {
|
|
3658
|
-
console.error(
|
|
4040
|
+
console.error(chalk12.red("\n\u2716 Unlink Failed:"), String(error));
|
|
3659
4041
|
}
|
|
3660
4042
|
}
|
|
3661
4043
|
});
|
|
@@ -3666,18 +4048,18 @@ function registerProjectCommands(program2) {
|
|
|
3666
4048
|
const resolvedProjectId = projectId || await configService.getProjectId();
|
|
3667
4049
|
if (!resolvedProjectId) {
|
|
3668
4050
|
console.error(
|
|
3669
|
-
|
|
4051
|
+
chalk12.red("\n\u2716 Project not linked. Run `vem link` first.\n")
|
|
3670
4052
|
);
|
|
3671
4053
|
process.exit(1);
|
|
3672
4054
|
}
|
|
3673
4055
|
const projectUrl = `${WEB_URL}/project/${resolvedProjectId}`;
|
|
3674
|
-
console.log(
|
|
4056
|
+
console.log(chalk12.blue(`
|
|
3675
4057
|
\u{1F310} Opening: ${projectUrl}
|
|
3676
4058
|
`));
|
|
3677
4059
|
openBrowser(projectUrl);
|
|
3678
4060
|
} catch (error) {
|
|
3679
4061
|
console.error(
|
|
3680
|
-
|
|
4062
|
+
chalk12.red("\n\u2716 Failed to open project:"),
|
|
3681
4063
|
error?.message ?? String(error)
|
|
3682
4064
|
);
|
|
3683
4065
|
}
|
|
@@ -3687,10 +4069,10 @@ function registerProjectCommands(program2) {
|
|
|
3687
4069
|
// src/commands/runner.ts
|
|
3688
4070
|
import { execFileSync, spawn as spawn3 } from "child_process";
|
|
3689
4071
|
import { existsSync } from "fs";
|
|
3690
|
-
import { dirname, resolve } from "path";
|
|
3691
|
-
import
|
|
4072
|
+
import { dirname as dirname2, resolve as resolve2 } from "path";
|
|
4073
|
+
import chalk13 from "chalk";
|
|
3692
4074
|
function sleep(ms) {
|
|
3693
|
-
return new Promise((
|
|
4075
|
+
return new Promise((resolve3) => setTimeout(resolve3, ms));
|
|
3694
4076
|
}
|
|
3695
4077
|
function getCliEntrypoint() {
|
|
3696
4078
|
const entry = process.argv[1];
|
|
@@ -3716,7 +4098,7 @@ function runGitIn(cwd, args, options) {
|
|
|
3716
4098
|
function hasDirtyWorktree() {
|
|
3717
4099
|
return runGit(["status", "--porcelain"]).trim().length > 0;
|
|
3718
4100
|
}
|
|
3719
|
-
function
|
|
4101
|
+
function getRepoRoot3() {
|
|
3720
4102
|
return runGit(["rev-parse", "--show-toplevel"]);
|
|
3721
4103
|
}
|
|
3722
4104
|
function commandExists(command) {
|
|
@@ -3760,7 +4142,7 @@ function getAvailableAgentCommands(selectedAgent, sandbox) {
|
|
|
3760
4142
|
return knownAvailable;
|
|
3761
4143
|
}
|
|
3762
4144
|
function getRunnerCapabilities(agent, sandbox = true, agentPinned = false) {
|
|
3763
|
-
const repoRoot =
|
|
4145
|
+
const repoRoot = getRepoRoot3();
|
|
3764
4146
|
let branch = null;
|
|
3765
4147
|
try {
|
|
3766
4148
|
branch = runGit(["rev-parse", "--abbrev-ref", "HEAD"]);
|
|
@@ -3790,20 +4172,20 @@ function checkDockerAvailable() {
|
|
|
3790
4172
|
execFileSync("docker", ["info"], { stdio: "ignore" });
|
|
3791
4173
|
} catch {
|
|
3792
4174
|
console.error(
|
|
3793
|
-
|
|
4175
|
+
chalk13.red("\u2717 Docker is not running or not installed.")
|
|
3794
4176
|
);
|
|
3795
4177
|
console.error(
|
|
3796
|
-
|
|
4178
|
+
chalk13.yellow(
|
|
3797
4179
|
" The vem runner requires Docker to run agents in a secure sandbox."
|
|
3798
4180
|
)
|
|
3799
4181
|
);
|
|
3800
4182
|
console.error(
|
|
3801
|
-
|
|
4183
|
+
chalk13.gray(
|
|
3802
4184
|
" Install Docker Desktop: https://www.docker.com/products/docker-desktop/"
|
|
3803
4185
|
)
|
|
3804
4186
|
);
|
|
3805
4187
|
console.error(
|
|
3806
|
-
|
|
4188
|
+
chalk13.gray(
|
|
3807
4189
|
" Or run without sandbox (no isolation): vem runner --unsafe"
|
|
3808
4190
|
)
|
|
3809
4191
|
);
|
|
@@ -3813,28 +4195,28 @@ function checkDockerAvailable() {
|
|
|
3813
4195
|
var SANDBOX_IMAGE_NAME = "vem-sandbox:latest";
|
|
3814
4196
|
function getSandboxImageDir() {
|
|
3815
4197
|
const cliDist = getCliEntrypoint();
|
|
3816
|
-
const distDir =
|
|
4198
|
+
const distDir = dirname2(cliDist);
|
|
3817
4199
|
const candidates = [
|
|
3818
|
-
|
|
3819
|
-
|
|
3820
|
-
|
|
4200
|
+
resolve2(distDir, "Dockerfile.sandbox"),
|
|
4201
|
+
resolve2(distDir, "..", "Dockerfile.sandbox"),
|
|
4202
|
+
resolve2(distDir, "..", "..", "apps", "cli", "Dockerfile.sandbox")
|
|
3821
4203
|
];
|
|
3822
4204
|
for (const candidate of candidates) {
|
|
3823
4205
|
if (existsSync(candidate)) {
|
|
3824
|
-
return
|
|
4206
|
+
return dirname2(candidate);
|
|
3825
4207
|
}
|
|
3826
4208
|
}
|
|
3827
4209
|
throw new Error("Dockerfile.sandbox not found. Ensure the vem CLI is installed correctly.");
|
|
3828
4210
|
}
|
|
3829
4211
|
function buildSandboxImage() {
|
|
3830
|
-
console.log(
|
|
4212
|
+
console.log(chalk13.cyan(" Building sandbox Docker image (first use)..."));
|
|
3831
4213
|
const contextDir = getSandboxImageDir();
|
|
3832
4214
|
execFileSync(
|
|
3833
4215
|
"docker",
|
|
3834
4216
|
["build", "-t", SANDBOX_IMAGE_NAME, "-f", "Dockerfile.sandbox", "."],
|
|
3835
4217
|
{ cwd: contextDir, stdio: "inherit" }
|
|
3836
4218
|
);
|
|
3837
|
-
console.log(
|
|
4219
|
+
console.log(chalk13.green(" \u2713 Sandbox image built."));
|
|
3838
4220
|
}
|
|
3839
4221
|
function ensureSandboxImage() {
|
|
3840
4222
|
try {
|
|
@@ -3853,7 +4235,7 @@ function collectSandboxCredentials(agent) {
|
|
|
3853
4235
|
if (agent === "claude") {
|
|
3854
4236
|
addFromEnv("ANTHROPIC_API_KEY");
|
|
3855
4237
|
if (!creds.ANTHROPIC_API_KEY) {
|
|
3856
|
-
console.error(
|
|
4238
|
+
console.error(chalk13.red(`\u2717 ANTHROPIC_API_KEY is not set. Required for --agent claude.`));
|
|
3857
4239
|
process.exit(1);
|
|
3858
4240
|
}
|
|
3859
4241
|
} else if (agent === "copilot" || agent === "gh") {
|
|
@@ -3868,20 +4250,20 @@ function collectSandboxCredentials(agent) {
|
|
|
3868
4250
|
}
|
|
3869
4251
|
}
|
|
3870
4252
|
if (!creds.GITHUB_TOKEN) {
|
|
3871
|
-
console.error(
|
|
3872
|
-
console.error(
|
|
4253
|
+
console.error(chalk13.red(`\u2717 GitHub token not found. Required for --agent copilot.`));
|
|
4254
|
+
console.error(chalk13.gray(" Set GITHUB_TOKEN env var or run: gh auth login"));
|
|
3873
4255
|
process.exit(1);
|
|
3874
4256
|
}
|
|
3875
4257
|
} else if (agent === "gemini") {
|
|
3876
4258
|
addFromEnv("GEMINI_API_KEY");
|
|
3877
4259
|
if (!creds.GEMINI_API_KEY) {
|
|
3878
|
-
console.error(
|
|
4260
|
+
console.error(chalk13.red(`\u2717 GEMINI_API_KEY is not set. Required for --agent gemini.`));
|
|
3879
4261
|
process.exit(1);
|
|
3880
4262
|
}
|
|
3881
4263
|
} else if (agent === "codex") {
|
|
3882
4264
|
addFromEnv("OPENAI_API_KEY");
|
|
3883
4265
|
if (!creds.OPENAI_API_KEY) {
|
|
3884
|
-
console.error(
|
|
4266
|
+
console.error(chalk13.red(`\u2717 OPENAI_API_KEY is not set. Required for --agent codex.`));
|
|
3885
4267
|
process.exit(1);
|
|
3886
4268
|
}
|
|
3887
4269
|
}
|
|
@@ -3934,14 +4316,14 @@ function getCommitHashesSince(baseHash) {
|
|
|
3934
4316
|
const output = runGit(["rev-list", `${baseHash}..HEAD`]);
|
|
3935
4317
|
return output.split("\n").map((entry) => entry.trim()).filter(Boolean);
|
|
3936
4318
|
}
|
|
3937
|
-
async function apiRequest(configService, apiKey,
|
|
4319
|
+
async function apiRequest(configService, apiKey, path4, init) {
|
|
3938
4320
|
const headers = {
|
|
3939
4321
|
Authorization: `Bearer ${apiKey}`,
|
|
3940
4322
|
"Content-Type": "application/json",
|
|
3941
4323
|
...await buildDeviceHeaders(configService),
|
|
3942
4324
|
...init?.headers ?? {}
|
|
3943
4325
|
};
|
|
3944
|
-
return fetch(`${API_URL}${
|
|
4326
|
+
return fetch(`${API_URL}${path4}`, { ...init, headers });
|
|
3945
4327
|
}
|
|
3946
4328
|
async function appendRunLogs(configService, apiKey, runId, entries) {
|
|
3947
4329
|
if (entries.length === 0) return;
|
|
@@ -3982,7 +4364,7 @@ async function completeTaskRunWithRetry(configService, apiKey, runId, payload, a
|
|
|
3982
4364
|
}
|
|
3983
4365
|
async function executeClaimedRun(input) {
|
|
3984
4366
|
const { configService, apiKey, projectId, agent, useSandbox, agentPinned, run } = input;
|
|
3985
|
-
const repoRoot =
|
|
4367
|
+
const repoRoot = getRepoRoot3();
|
|
3986
4368
|
let sequence = 1;
|
|
3987
4369
|
let heartbeatTimer = null;
|
|
3988
4370
|
let cancellationRequested = false;
|
|
@@ -4092,11 +4474,11 @@ async function executeClaimedRun(input) {
|
|
|
4092
4474
|
]);
|
|
4093
4475
|
});
|
|
4094
4476
|
const result = await new Promise(
|
|
4095
|
-
(
|
|
4096
|
-
child.on("exit", (code, signal) =>
|
|
4477
|
+
(resolve3) => {
|
|
4478
|
+
child.on("exit", (code, signal) => resolve3({ code, signal }));
|
|
4097
4479
|
child.on("error", (error) => {
|
|
4098
4480
|
completionError = error.message;
|
|
4099
|
-
|
|
4481
|
+
resolve3({ code: null, signal: null });
|
|
4100
4482
|
});
|
|
4101
4483
|
}
|
|
4102
4484
|
);
|
|
@@ -4182,7 +4564,7 @@ ${run.user_prompt.trim()}` : "Triggered from VEM web.",
|
|
|
4182
4564
|
}
|
|
4183
4565
|
async function executeClaimedRunInSandbox(input) {
|
|
4184
4566
|
const { configService, apiKey, projectId, agent, run, credentials } = input;
|
|
4185
|
-
const repoRoot =
|
|
4567
|
+
const repoRoot = getRepoRoot3();
|
|
4186
4568
|
let sequence = 1;
|
|
4187
4569
|
let heartbeatTimer = null;
|
|
4188
4570
|
let worktreePath = null;
|
|
@@ -4216,7 +4598,7 @@ async function executeClaimedRunInSandbox(input) {
|
|
|
4216
4598
|
if (existsSync(worktreePath)) {
|
|
4217
4599
|
execFileSync("rm", ["-rf", worktreePath], { stdio: "ignore" });
|
|
4218
4600
|
}
|
|
4219
|
-
console.log(
|
|
4601
|
+
console.log(chalk13.gray(` Cloning ${baseBranch} \u2192 ${worktreePath}`));
|
|
4220
4602
|
execFileSync("git", [
|
|
4221
4603
|
"clone",
|
|
4222
4604
|
"--quiet",
|
|
@@ -4335,9 +4717,9 @@ async function executeClaimedRunInSandbox(input) {
|
|
|
4335
4717
|
};
|
|
4336
4718
|
dockerProcess.stdout?.on("data", (d) => streamLogs("stdout", d));
|
|
4337
4719
|
dockerProcess.stderr?.on("data", (d) => streamLogs("stderr", d));
|
|
4338
|
-
exitCode = await new Promise((
|
|
4339
|
-
dockerProcess.once("exit", (code) =>
|
|
4340
|
-
dockerProcess.once("error", () =>
|
|
4720
|
+
exitCode = await new Promise((resolve3) => {
|
|
4721
|
+
dockerProcess.once("exit", (code) => resolve3(code ?? 1));
|
|
4722
|
+
dockerProcess.once("error", () => resolve3(1));
|
|
4341
4723
|
});
|
|
4342
4724
|
if (heartbeatTimer) {
|
|
4343
4725
|
clearInterval(heartbeatTimer);
|
|
@@ -4428,7 +4810,7 @@ async function appendTerminalLogs(configService, apiKey, sessionId, entries) {
|
|
|
4428
4810
|
}
|
|
4429
4811
|
async function executeClaimedTerminalSession(input) {
|
|
4430
4812
|
const { configService, apiKey, projectId, agent, useSandbox, agentPinned, session } = input;
|
|
4431
|
-
const repoRoot =
|
|
4813
|
+
const repoRoot = getRepoRoot3();
|
|
4432
4814
|
let sequence = 2;
|
|
4433
4815
|
let heartbeatTimer = null;
|
|
4434
4816
|
let completionStatus = "failed";
|
|
@@ -4488,11 +4870,11 @@ $ ${session.command}
|
|
|
4488
4870
|
]);
|
|
4489
4871
|
});
|
|
4490
4872
|
const result = await new Promise(
|
|
4491
|
-
(
|
|
4492
|
-
child.on("exit", (code, signal) =>
|
|
4873
|
+
(resolve3) => {
|
|
4874
|
+
child.on("exit", (code, signal) => resolve3({ code, signal }));
|
|
4493
4875
|
child.on("error", (error) => {
|
|
4494
4876
|
completionError = error.message;
|
|
4495
|
-
|
|
4877
|
+
resolve3({ code: null, signal: null });
|
|
4496
4878
|
});
|
|
4497
4879
|
}
|
|
4498
4880
|
);
|
|
@@ -4566,12 +4948,12 @@ function registerRunnerCommands(program2) {
|
|
|
4566
4948
|
const agentPinned = optionSource === "cli";
|
|
4567
4949
|
const modeLabel = useSandbox ? "sandbox (Docker)" : "unsafe (direct)";
|
|
4568
4950
|
console.log(
|
|
4569
|
-
|
|
4951
|
+
chalk13.cyan(
|
|
4570
4952
|
`Starting paired runner for project ${projectId} using agent "${agent}" [${modeLabel}]...`
|
|
4571
4953
|
)
|
|
4572
4954
|
);
|
|
4573
4955
|
if (!useSandbox) {
|
|
4574
|
-
console.log(
|
|
4956
|
+
console.log(chalk13.yellow(" \u26A0 Running in unsafe mode \u2014 agent has full host access."));
|
|
4575
4957
|
}
|
|
4576
4958
|
let shouldStop = false;
|
|
4577
4959
|
let consecutiveErrors = 0;
|
|
@@ -4689,14 +5071,14 @@ function registerRunnerCommands(program2) {
|
|
|
4689
5071
|
}
|
|
4690
5072
|
|
|
4691
5073
|
// src/commands/search.ts
|
|
4692
|
-
import
|
|
5074
|
+
import chalk14 from "chalk";
|
|
4693
5075
|
function registerSearchCommands(program2) {
|
|
4694
5076
|
program2.command("search <query>").description("Search project memory (tasks, context, decisions)").action(async (query) => {
|
|
4695
5077
|
await trackCommandUsage("search");
|
|
4696
5078
|
try {
|
|
4697
5079
|
const configService = new ConfigService();
|
|
4698
5080
|
const key = await ensureAuthenticated(configService);
|
|
4699
|
-
console.log(
|
|
5081
|
+
console.log(chalk14.blue(`\u{1F50D} Searching for "${query}"...`));
|
|
4700
5082
|
const res = await fetch(
|
|
4701
5083
|
`${API_URL}/search?q=${encodeURIComponent(query)}`,
|
|
4702
5084
|
{
|
|
@@ -4709,14 +5091,14 @@ function registerSearchCommands(program2) {
|
|
|
4709
5091
|
if (!res.ok) {
|
|
4710
5092
|
if (res.status === 401) {
|
|
4711
5093
|
console.error(
|
|
4712
|
-
|
|
5094
|
+
chalk14.red("Error: Unauthorized. Your API Key is invalid.")
|
|
4713
5095
|
);
|
|
4714
5096
|
return;
|
|
4715
5097
|
}
|
|
4716
5098
|
if (res.status === 403) {
|
|
4717
5099
|
const errorData = await res.json().catch(() => ({}));
|
|
4718
5100
|
console.error(
|
|
4719
|
-
|
|
5101
|
+
chalk14.red(
|
|
4720
5102
|
errorData.error || "Device limit reached. Disconnect a device or upgrade your plan."
|
|
4721
5103
|
)
|
|
4722
5104
|
);
|
|
@@ -4727,36 +5109,36 @@ function registerSearchCommands(program2) {
|
|
|
4727
5109
|
}
|
|
4728
5110
|
const data = await res.json();
|
|
4729
5111
|
if (!data.results || data.results.length === 0) {
|
|
4730
|
-
console.log(
|
|
5112
|
+
console.log(chalk14.yellow("No results found."));
|
|
4731
5113
|
return;
|
|
4732
5114
|
}
|
|
4733
|
-
console.log(
|
|
5115
|
+
console.log(chalk14.green(`
|
|
4734
5116
|
Found ${data.results.length} results:
|
|
4735
5117
|
`));
|
|
4736
5118
|
data.results.forEach((item, i) => {
|
|
4737
|
-
const typeLabel =
|
|
5119
|
+
const typeLabel = chalk14.gray(
|
|
4738
5120
|
`[${item.type?.toUpperCase() || "UNKNOWN"}]`
|
|
4739
5121
|
);
|
|
4740
5122
|
console.log(
|
|
4741
|
-
`${i + 1}. ${typeLabel} ${
|
|
5123
|
+
`${i + 1}. ${typeLabel} ${chalk14.bold(item.title || "Untitled")}`
|
|
4742
5124
|
);
|
|
4743
5125
|
if (item.content) {
|
|
4744
5126
|
console.log(
|
|
4745
|
-
|
|
5127
|
+
chalk14.gray(
|
|
4746
5128
|
` ${item.content.substring(0, 100).replace(/\n/g, " ")}...`
|
|
4747
5129
|
)
|
|
4748
5130
|
);
|
|
4749
5131
|
}
|
|
4750
5132
|
if (item.score) {
|
|
4751
|
-
console.log(
|
|
5133
|
+
console.log(chalk14.gray(` Score: ${item.score.toFixed(2)}`));
|
|
4752
5134
|
}
|
|
4753
5135
|
console.log("");
|
|
4754
5136
|
});
|
|
4755
5137
|
} catch (error) {
|
|
4756
5138
|
if (error instanceof Error) {
|
|
4757
|
-
console.error(
|
|
5139
|
+
console.error(chalk14.red("\n\u2716 Search Failed:"), error.message);
|
|
4758
5140
|
} else {
|
|
4759
|
-
console.error(
|
|
5141
|
+
console.error(chalk14.red("\n\u2716 Search Failed:"), String(error));
|
|
4760
5142
|
}
|
|
4761
5143
|
}
|
|
4762
5144
|
});
|
|
@@ -4765,7 +5147,7 @@ Found ${data.results.length} results:
|
|
|
4765
5147
|
try {
|
|
4766
5148
|
const cleanedQuestion = typeof question === "string" ? question.trim() : "";
|
|
4767
5149
|
if (!cleanedQuestion) {
|
|
4768
|
-
console.error(
|
|
5150
|
+
console.error(chalk14.red("\n\u2716 Question is required.\n"));
|
|
4769
5151
|
return;
|
|
4770
5152
|
}
|
|
4771
5153
|
const configService = new ConfigService();
|
|
@@ -4773,11 +5155,11 @@ Found ${data.results.length} results:
|
|
|
4773
5155
|
const projectId = await configService.getProjectId();
|
|
4774
5156
|
if (!projectId) {
|
|
4775
5157
|
console.error(
|
|
4776
|
-
|
|
5158
|
+
chalk14.red("\n\u2716 Project not linked. Run `vem link` first.\n")
|
|
4777
5159
|
);
|
|
4778
5160
|
return;
|
|
4779
5161
|
}
|
|
4780
|
-
console.log(
|
|
5162
|
+
console.log(chalk14.blue(`Asking: "${cleanedQuestion}"...`));
|
|
4781
5163
|
const payload = {
|
|
4782
5164
|
question: cleanedQuestion
|
|
4783
5165
|
};
|
|
@@ -4803,14 +5185,14 @@ Found ${data.results.length} results:
|
|
|
4803
5185
|
}
|
|
4804
5186
|
const data = await res.json();
|
|
4805
5187
|
if (data.answer) {
|
|
4806
|
-
console.log(
|
|
5188
|
+
console.log(chalk14.green("\nAnswer:\n"));
|
|
4807
5189
|
console.log(data.answer.trim());
|
|
4808
5190
|
} else {
|
|
4809
|
-
console.log(
|
|
5191
|
+
console.log(chalk14.yellow("\nNo answer generated."));
|
|
4810
5192
|
}
|
|
4811
5193
|
const repoUrl = await getGitRemote();
|
|
4812
5194
|
if (data.citations && data.citations.length > 0) {
|
|
4813
|
-
console.log(
|
|
5195
|
+
console.log(chalk14.green("\nCitations:"));
|
|
4814
5196
|
data.citations.forEach((cite, idx) => {
|
|
4815
5197
|
const source = data.sources?.find((s) => s.id === cite.id);
|
|
4816
5198
|
let label = cite.id;
|
|
@@ -4830,14 +5212,14 @@ Found ${data.results.length} results:
|
|
|
4830
5212
|
}
|
|
4831
5213
|
const note = cite.reason ? ` - ${cite.reason}` : "";
|
|
4832
5214
|
if (link) {
|
|
4833
|
-
console.log(
|
|
5215
|
+
console.log(chalk14.gray(`${idx + 1}. ${label} (${link})${note}`));
|
|
4834
5216
|
} else {
|
|
4835
|
-
console.log(
|
|
5217
|
+
console.log(chalk14.gray(`${idx + 1}. ${label}${note}`));
|
|
4836
5218
|
}
|
|
4837
5219
|
});
|
|
4838
5220
|
}
|
|
4839
5221
|
if (data.sources && data.sources.length > 0) {
|
|
4840
|
-
console.log(
|
|
5222
|
+
console.log(chalk14.green("\nSources:"));
|
|
4841
5223
|
data.sources.forEach((source, idx) => {
|
|
4842
5224
|
const details = [];
|
|
4843
5225
|
if (source.type) details.push(source.type.toUpperCase());
|
|
@@ -4846,28 +5228,28 @@ Found ${data.results.length} results:
|
|
|
4846
5228
|
details.push(source.commit_hash.slice(0, 7));
|
|
4847
5229
|
if (source.task_id) details.push(source.task_id);
|
|
4848
5230
|
const header = [source.id, ...details].filter(Boolean).join(" \u2022 ");
|
|
4849
|
-
console.log(
|
|
5231
|
+
console.log(chalk14.gray(`${idx + 1}. ${header || "SOURCE"}`));
|
|
4850
5232
|
if (source.title) {
|
|
4851
|
-
console.log(
|
|
5233
|
+
console.log(chalk14.gray(` ${source.title}`));
|
|
4852
5234
|
} else if (source.description) {
|
|
4853
|
-
console.log(
|
|
5235
|
+
console.log(chalk14.gray(` ${source.description}`));
|
|
4854
5236
|
}
|
|
4855
5237
|
});
|
|
4856
5238
|
}
|
|
4857
5239
|
} catch (error) {
|
|
4858
5240
|
if (error instanceof Error) {
|
|
4859
|
-
console.error(
|
|
5241
|
+
console.error(chalk14.red("\n\u2716 Ask Failed:"), error.message);
|
|
4860
5242
|
} else {
|
|
4861
|
-
console.error(
|
|
5243
|
+
console.error(chalk14.red("\n\u2716 Ask Failed:"), String(error));
|
|
4862
5244
|
}
|
|
4863
5245
|
}
|
|
4864
5246
|
});
|
|
4865
5247
|
}
|
|
4866
5248
|
|
|
4867
5249
|
// src/commands/sessions.ts
|
|
4868
|
-
import
|
|
5250
|
+
import chalk15 from "chalk";
|
|
4869
5251
|
import Table2 from "cli-table3";
|
|
4870
|
-
import
|
|
5252
|
+
import prompts7 from "prompts";
|
|
4871
5253
|
function formatDate(iso) {
|
|
4872
5254
|
if (!iso) return "\u2014";
|
|
4873
5255
|
const d = new Date(iso);
|
|
@@ -4906,22 +5288,22 @@ function registerSessionsCommands(program2) {
|
|
|
4906
5288
|
const limit = Number.parseInt(opts.limit, 10) || 20;
|
|
4907
5289
|
sessions = sessions.slice(0, limit);
|
|
4908
5290
|
if (sessions.length === 0) {
|
|
4909
|
-
console.log(
|
|
5291
|
+
console.log(chalk15.gray("No agent sessions found for this repository."));
|
|
4910
5292
|
return;
|
|
4911
5293
|
}
|
|
4912
5294
|
const sourceColor = (src) => {
|
|
4913
|
-
if (src === "copilot") return
|
|
4914
|
-
if (src === "claude") return
|
|
4915
|
-
if (src === "gemini") return
|
|
4916
|
-
return
|
|
5295
|
+
if (src === "copilot") return chalk15.blue(src);
|
|
5296
|
+
if (src === "claude") return chalk15.yellow(src);
|
|
5297
|
+
if (src === "gemini") return chalk15.cyan(src);
|
|
5298
|
+
return chalk15.gray(src);
|
|
4917
5299
|
};
|
|
4918
5300
|
const table = new Table2({
|
|
4919
5301
|
head: [
|
|
4920
|
-
|
|
4921
|
-
|
|
4922
|
-
|
|
4923
|
-
|
|
4924
|
-
|
|
5302
|
+
chalk15.bold("Source"),
|
|
5303
|
+
chalk15.bold("ID"),
|
|
5304
|
+
chalk15.bold("Summary"),
|
|
5305
|
+
chalk15.bold("Branch"),
|
|
5306
|
+
chalk15.bold("Updated")
|
|
4925
5307
|
],
|
|
4926
5308
|
colWidths: [10, 12, 42, 18, 18],
|
|
4927
5309
|
style: { head: [], border: ["gray"] }
|
|
@@ -4929,17 +5311,17 @@ function registerSessionsCommands(program2) {
|
|
|
4929
5311
|
for (const s of sessions) {
|
|
4930
5312
|
table.push([
|
|
4931
5313
|
sourceColor(s.source),
|
|
4932
|
-
|
|
4933
|
-
s.summary ||
|
|
4934
|
-
|
|
4935
|
-
|
|
5314
|
+
chalk15.gray(`${s.id.slice(0, 8)}\u2026`),
|
|
5315
|
+
s.summary || chalk15.gray("(no summary)"),
|
|
5316
|
+
chalk15.cyan(s.branch || "\u2014"),
|
|
5317
|
+
chalk15.gray(formatDate(s.updated_at))
|
|
4936
5318
|
]);
|
|
4937
5319
|
}
|
|
4938
5320
|
console.log(table.toString());
|
|
4939
5321
|
console.log(
|
|
4940
|
-
|
|
5322
|
+
chalk15.gray(
|
|
4941
5323
|
`
|
|
4942
|
-
Showing ${sessions.length} session(s). Use ${
|
|
5324
|
+
Showing ${sessions.length} session(s). Use ${chalk15.white("vem sessions import <id>")} to import a session into project memory.`
|
|
4943
5325
|
)
|
|
4944
5326
|
);
|
|
4945
5327
|
});
|
|
@@ -4951,12 +5333,12 @@ Showing ${sessions.length} session(s). Use ${chalk14.white("vem sessions import
|
|
|
4951
5333
|
const all = await listAllAgentSessions(gitRoot);
|
|
4952
5334
|
const match = all.find((s) => s.id.startsWith(id));
|
|
4953
5335
|
if (!match) {
|
|
4954
|
-
console.error(
|
|
5336
|
+
console.error(chalk15.red(`No session found matching prefix: ${id}`));
|
|
4955
5337
|
process.exit(1);
|
|
4956
5338
|
}
|
|
4957
5339
|
session = match;
|
|
4958
5340
|
console.log(
|
|
4959
|
-
|
|
5341
|
+
chalk15.gray(`Resolved to ${match.source} session: ${match.id}`)
|
|
4960
5342
|
);
|
|
4961
5343
|
} else {
|
|
4962
5344
|
const all = await listAllAgentSessions(gitRoot);
|
|
@@ -4981,34 +5363,34 @@ Showing ${sessions.length} session(s). Use ${chalk14.white("vem sessions import
|
|
|
4981
5363
|
}
|
|
4982
5364
|
}
|
|
4983
5365
|
if (!session) {
|
|
4984
|
-
console.error(
|
|
5366
|
+
console.error(chalk15.red(`Session not found: ${id}`));
|
|
4985
5367
|
process.exit(1);
|
|
4986
5368
|
}
|
|
4987
|
-
console.log(
|
|
4988
|
-
console.log(
|
|
4989
|
-
console.log(
|
|
4990
|
-
console.log(
|
|
4991
|
-
console.log(
|
|
5369
|
+
console.log(chalk15.bold("\n\u{1F4CB} Session Summary"));
|
|
5370
|
+
console.log(chalk15.white(` ID: ${session.id}`));
|
|
5371
|
+
console.log(chalk15.white(` Source: ${session.source}`));
|
|
5372
|
+
console.log(chalk15.white(` Branch: ${session.branch || "\u2014"}`));
|
|
5373
|
+
console.log(chalk15.white(` Updated: ${formatDate(session.updated_at)}`));
|
|
4992
5374
|
console.log(
|
|
4993
|
-
|
|
5375
|
+
chalk15.white(` Summary: ${session.summary || "(no summary)"}`)
|
|
4994
5376
|
);
|
|
4995
5377
|
if (session.intents.length > 0) {
|
|
4996
|
-
console.log(
|
|
5378
|
+
console.log(chalk15.bold("\n\u{1F3AF} Intents recorded in this session:"));
|
|
4997
5379
|
for (const intent of session.intents) {
|
|
4998
|
-
console.log(
|
|
5380
|
+
console.log(chalk15.gray(` \u2022 ${intent}`));
|
|
4999
5381
|
}
|
|
5000
5382
|
}
|
|
5001
5383
|
if (session.user_messages.length > 0) {
|
|
5002
|
-
console.log(
|
|
5384
|
+
console.log(chalk15.bold("\n\u{1F4AC} First user message:"));
|
|
5003
5385
|
const preview = session.user_messages[0].slice(0, 200);
|
|
5004
5386
|
console.log(
|
|
5005
|
-
|
|
5387
|
+
chalk15.gray(
|
|
5006
5388
|
` ${preview}${session.user_messages[0].length > 200 ? "\u2026" : ""}`
|
|
5007
5389
|
)
|
|
5008
5390
|
);
|
|
5009
5391
|
}
|
|
5010
5392
|
console.log();
|
|
5011
|
-
const { addChangelog } = await
|
|
5393
|
+
const { addChangelog } = await prompts7({
|
|
5012
5394
|
type: "confirm",
|
|
5013
5395
|
name: "addChangelog",
|
|
5014
5396
|
message: "Add session summary as a changelog entry?",
|
|
@@ -5023,7 +5405,7 @@ Showing ${sessions.length} session(s). Use ${chalk14.white("vem sessions import
|
|
|
5023
5405
|
`- ${changelogEntry}`,
|
|
5024
5406
|
gitHash ? { commitHash: gitHash } : void 0
|
|
5025
5407
|
);
|
|
5026
|
-
console.log(
|
|
5408
|
+
console.log(chalk15.green("\u2713 Changelog entry added."));
|
|
5027
5409
|
}
|
|
5028
5410
|
const taskService2 = new TaskService();
|
|
5029
5411
|
const tasks = await taskService2.getTasks();
|
|
@@ -5031,14 +5413,14 @@ Showing ${sessions.length} session(s). Use ${chalk14.white("vem sessions import
|
|
|
5031
5413
|
(t) => !t.deleted_at && t.status !== "done"
|
|
5032
5414
|
);
|
|
5033
5415
|
if (activeTasks.length > 0) {
|
|
5034
|
-
const { linkTask } = await
|
|
5416
|
+
const { linkTask } = await prompts7({
|
|
5035
5417
|
type: "confirm",
|
|
5036
5418
|
name: "linkTask",
|
|
5037
5419
|
message: "Link this session to an active task (add evidence)?",
|
|
5038
5420
|
initial: false
|
|
5039
5421
|
});
|
|
5040
5422
|
if (linkTask) {
|
|
5041
|
-
const { taskId } = await
|
|
5423
|
+
const { taskId } = await prompts7({
|
|
5042
5424
|
type: "select",
|
|
5043
5425
|
name: "taskId",
|
|
5044
5426
|
message: "Which task?",
|
|
@@ -5065,20 +5447,20 @@ Showing ${sessions.length} session(s). Use ${chalk14.white("vem sessions import
|
|
|
5065
5447
|
...sessionRef ? { sessions: [...existingSessions, sessionRef] } : {}
|
|
5066
5448
|
});
|
|
5067
5449
|
console.log(
|
|
5068
|
-
|
|
5450
|
+
chalk15.green(`\u2713 Linked to task ${taskId} with evidence.`)
|
|
5069
5451
|
);
|
|
5070
5452
|
}
|
|
5071
5453
|
}
|
|
5072
5454
|
}
|
|
5073
|
-
console.log(
|
|
5455
|
+
console.log(chalk15.bold("\n\u2705 Done."));
|
|
5074
5456
|
});
|
|
5075
5457
|
}
|
|
5076
5458
|
|
|
5077
5459
|
// src/commands/setup.ts
|
|
5078
|
-
import
|
|
5079
|
-
import
|
|
5080
|
-
import
|
|
5081
|
-
import
|
|
5460
|
+
import path3 from "path";
|
|
5461
|
+
import chalk16 from "chalk";
|
|
5462
|
+
import fs4 from "fs-extra";
|
|
5463
|
+
import prompts8 from "prompts";
|
|
5082
5464
|
var COMMAND_BASELINE = [
|
|
5083
5465
|
"quickstart",
|
|
5084
5466
|
"agent",
|
|
@@ -5112,9 +5494,9 @@ All AI agents in this repository must use \`vem\` and follow the working rules.
|
|
|
5112
5494
|
`;
|
|
5113
5495
|
async function ensureVemGitignoreEntry() {
|
|
5114
5496
|
const repoRoot = await getRepoRoot();
|
|
5115
|
-
const gitignorePath =
|
|
5116
|
-
if (!await
|
|
5117
|
-
await
|
|
5497
|
+
const gitignorePath = path3.join(repoRoot, ".gitignore");
|
|
5498
|
+
if (!await fs4.pathExists(gitignorePath)) {
|
|
5499
|
+
await fs4.writeFile(
|
|
5118
5500
|
gitignorePath,
|
|
5119
5501
|
`${REQUIRED_GITIGNORE_ENTRIES.join("\n")}
|
|
5120
5502
|
`,
|
|
@@ -5122,7 +5504,7 @@ async function ensureVemGitignoreEntry() {
|
|
|
5122
5504
|
);
|
|
5123
5505
|
return;
|
|
5124
5506
|
}
|
|
5125
|
-
const content = await
|
|
5507
|
+
const content = await fs4.readFile(gitignorePath, "utf-8");
|
|
5126
5508
|
const entries = content.split(/\r?\n/).map((line) => line.trim());
|
|
5127
5509
|
const missingEntries = REQUIRED_GITIGNORE_ENTRIES.filter(
|
|
5128
5510
|
(entry) => !entries.includes(entry)
|
|
@@ -5131,7 +5513,7 @@ async function ensureVemGitignoreEntry() {
|
|
|
5131
5513
|
return;
|
|
5132
5514
|
}
|
|
5133
5515
|
const separator = content.endsWith("\n") ? "" : "\n";
|
|
5134
|
-
await
|
|
5516
|
+
await fs4.appendFile(
|
|
5135
5517
|
gitignorePath,
|
|
5136
5518
|
`${separator}${missingEntries.join("\n")}
|
|
5137
5519
|
`,
|
|
@@ -5142,15 +5524,15 @@ async function ensureAgentInstructionPolicy() {
|
|
|
5142
5524
|
const repoRoot = await getRepoRoot();
|
|
5143
5525
|
const existingFiles = [];
|
|
5144
5526
|
for (const file of KNOWN_AGENT_INSTRUCTION_FILES) {
|
|
5145
|
-
if (await
|
|
5527
|
+
if (await fs4.pathExists(path3.join(repoRoot, file))) {
|
|
5146
5528
|
existingFiles.push(file);
|
|
5147
5529
|
}
|
|
5148
5530
|
}
|
|
5149
5531
|
let createdAgentsFile = false;
|
|
5150
5532
|
let targets = [];
|
|
5151
5533
|
if (existingFiles.length === 0) {
|
|
5152
|
-
await
|
|
5153
|
-
|
|
5534
|
+
await fs4.writeFile(
|
|
5535
|
+
path3.join(repoRoot, "AGENTS.md"),
|
|
5154
5536
|
"# AGENTS\n\nThis repository uses `vem` for agent workflows.\n",
|
|
5155
5537
|
"utf-8"
|
|
5156
5538
|
);
|
|
@@ -5163,13 +5545,13 @@ async function ensureAgentInstructionPolicy() {
|
|
|
5163
5545
|
}
|
|
5164
5546
|
const updatedFiles = [];
|
|
5165
5547
|
for (const relativePath of targets) {
|
|
5166
|
-
const absolutePath =
|
|
5167
|
-
const content = await
|
|
5548
|
+
const absolutePath = path3.join(repoRoot, relativePath);
|
|
5549
|
+
const content = await fs4.readFile(absolutePath, "utf-8");
|
|
5168
5550
|
if (content.includes(VEM_AGENT_ENFORCEMENT_MARKER)) {
|
|
5169
5551
|
continue;
|
|
5170
5552
|
}
|
|
5171
5553
|
const separator = content.endsWith("\n") ? "" : "\n";
|
|
5172
|
-
await
|
|
5554
|
+
await fs4.appendFile(
|
|
5173
5555
|
absolutePath,
|
|
5174
5556
|
`${separator}
|
|
5175
5557
|
${VEM_AGENT_ENFORCEMENT_BLOCK}`,
|
|
@@ -5186,13 +5568,13 @@ async function collectAgentInstructionPayload() {
|
|
|
5186
5568
|
const repoRoot = await getRepoRoot();
|
|
5187
5569
|
const payload = [];
|
|
5188
5570
|
for (const relativePath of KNOWN_AGENT_INSTRUCTION_FILES) {
|
|
5189
|
-
const absolutePath =
|
|
5190
|
-
if (!await
|
|
5191
|
-
const stat2 = await
|
|
5571
|
+
const absolutePath = path3.join(repoRoot, relativePath);
|
|
5572
|
+
if (!await fs4.pathExists(absolutePath)) continue;
|
|
5573
|
+
const stat2 = await fs4.stat(absolutePath);
|
|
5192
5574
|
if (!stat2.isFile()) continue;
|
|
5193
5575
|
payload.push({
|
|
5194
5576
|
path: relativePath,
|
|
5195
|
-
content: await
|
|
5577
|
+
content: await fs4.readFile(absolutePath, "utf-8")
|
|
5196
5578
|
});
|
|
5197
5579
|
}
|
|
5198
5580
|
return payload;
|
|
@@ -5228,40 +5610,40 @@ var formatRelativeTime = (timestamp) => {
|
|
|
5228
5610
|
};
|
|
5229
5611
|
var renderUsageInsights = (stats, detailed = false) => {
|
|
5230
5612
|
const entries = getSortedCommandEntries(stats);
|
|
5231
|
-
console.log(
|
|
5613
|
+
console.log(chalk16.bold("\n\u{1F4C8} Command Insights\n"));
|
|
5232
5614
|
if (entries.length === 0) {
|
|
5233
|
-
console.log(
|
|
5234
|
-
console.log(
|
|
5615
|
+
console.log(chalk16.gray(" No command usage recorded yet."));
|
|
5616
|
+
console.log(chalk16.gray(" Start with: vem quickstart"));
|
|
5235
5617
|
return;
|
|
5236
5618
|
}
|
|
5237
5619
|
const rows = detailed ? entries : entries.slice(0, 6);
|
|
5238
|
-
console.log(
|
|
5620
|
+
console.log(chalk16.gray(` Commands tracked: ${entries.length}`));
|
|
5239
5621
|
rows.forEach(([command, count], index) => {
|
|
5240
5622
|
console.log(
|
|
5241
|
-
` ${
|
|
5623
|
+
` ${chalk16.gray(`${index + 1}.`)} ${chalk16.white(command)} ${chalk16.gray(`(${count})`)}`
|
|
5242
5624
|
);
|
|
5243
5625
|
});
|
|
5244
5626
|
if (!detailed && entries.length > rows.length) {
|
|
5245
|
-
console.log(
|
|
5627
|
+
console.log(chalk16.gray(` ...and ${entries.length - rows.length} more`));
|
|
5246
5628
|
}
|
|
5247
5629
|
const neverUsed = COMMAND_BASELINE.filter(
|
|
5248
5630
|
(command) => (stats.commandCounts[command] || 0) === 0
|
|
5249
5631
|
);
|
|
5250
5632
|
if (neverUsed.length > 0) {
|
|
5251
|
-
console.log(
|
|
5633
|
+
console.log(chalk16.gray("\n Suggested next commands:"));
|
|
5252
5634
|
neverUsed.slice(0, 3).forEach((command) => {
|
|
5253
|
-
console.log(` ${
|
|
5635
|
+
console.log(` ${chalk16.cyan(command)}`);
|
|
5254
5636
|
});
|
|
5255
5637
|
}
|
|
5256
5638
|
if (stats.lastPush) {
|
|
5257
5639
|
console.log(
|
|
5258
|
-
|
|
5640
|
+
chalk16.gray(`
|
|
5259
5641
|
Last push: ${formatRelativeTime(stats.lastPush)}`)
|
|
5260
5642
|
);
|
|
5261
5643
|
}
|
|
5262
5644
|
if (stats.lastAgentRun) {
|
|
5263
5645
|
console.log(
|
|
5264
|
-
|
|
5646
|
+
chalk16.gray(
|
|
5265
5647
|
` Last agent session: ${formatRelativeTime(stats.lastAgentRun)}`
|
|
5266
5648
|
)
|
|
5267
5649
|
);
|
|
@@ -5272,18 +5654,18 @@ function registerSetupCommands(program2) {
|
|
|
5272
5654
|
try {
|
|
5273
5655
|
if (await hasUncommittedChanges()) {
|
|
5274
5656
|
console.log(
|
|
5275
|
-
|
|
5657
|
+
chalk16.yellow(
|
|
5276
5658
|
"\n\u26A0 Uncommitted changes detected in this workspace.\n"
|
|
5277
5659
|
)
|
|
5278
5660
|
);
|
|
5279
|
-
const proceed = await
|
|
5661
|
+
const proceed = await prompts8({
|
|
5280
5662
|
type: "confirm",
|
|
5281
5663
|
name: "confirmInit",
|
|
5282
5664
|
message: "Continue with `vem init` anyway?",
|
|
5283
5665
|
initial: false
|
|
5284
5666
|
});
|
|
5285
5667
|
if (!proceed.confirmInit) {
|
|
5286
|
-
console.log(
|
|
5668
|
+
console.log(chalk16.yellow("Initialization cancelled.\n"));
|
|
5287
5669
|
return;
|
|
5288
5670
|
}
|
|
5289
5671
|
}
|
|
@@ -5294,19 +5676,19 @@ function registerSetupCommands(program2) {
|
|
|
5294
5676
|
const initHash = await computeVemHash();
|
|
5295
5677
|
await configService.setLastSyncedVemHash(initHash);
|
|
5296
5678
|
const agentInstructions = await ensureAgentInstructionPolicy();
|
|
5297
|
-
console.log(
|
|
5679
|
+
console.log(chalk16.green(`
|
|
5298
5680
|
\u2714 vem initialized at ${dir}
|
|
5299
5681
|
`));
|
|
5300
5682
|
if (agentInstructions.createdAgentsFile) {
|
|
5301
5683
|
console.log(
|
|
5302
|
-
|
|
5684
|
+
chalk16.gray(
|
|
5303
5685
|
"Created AGENTS.md because no agent instruction files were found."
|
|
5304
5686
|
)
|
|
5305
5687
|
);
|
|
5306
5688
|
}
|
|
5307
5689
|
if (agentInstructions.updatedFiles.length > 0) {
|
|
5308
5690
|
console.log(
|
|
5309
|
-
|
|
5691
|
+
chalk16.gray(
|
|
5310
5692
|
`Updated agent instructions: ${agentInstructions.updatedFiles.join(", ")}`
|
|
5311
5693
|
)
|
|
5312
5694
|
);
|
|
@@ -5316,7 +5698,7 @@ function registerSetupCommands(program2) {
|
|
|
5316
5698
|
const apiKey = await tryAuthenticatedKey(configService);
|
|
5317
5699
|
let resolvedProjectId = projectId;
|
|
5318
5700
|
if (apiKey && !projectId) {
|
|
5319
|
-
const { doLink } = await
|
|
5701
|
+
const { doLink } = await prompts8({
|
|
5320
5702
|
type: "confirm",
|
|
5321
5703
|
name: "doLink",
|
|
5322
5704
|
message: "Link this repo to a vem cloud project now?",
|
|
@@ -5330,11 +5712,11 @@ function registerSetupCommands(program2) {
|
|
|
5330
5712
|
);
|
|
5331
5713
|
} catch (err) {
|
|
5332
5714
|
const msg = err instanceof Error ? err.message : String(err);
|
|
5333
|
-
console.log(
|
|
5715
|
+
console.log(chalk16.yellow(`\u26A0 Link skipped: ${msg}`));
|
|
5334
5716
|
}
|
|
5335
5717
|
} else {
|
|
5336
5718
|
console.log(
|
|
5337
|
-
|
|
5719
|
+
chalk16.gray(
|
|
5338
5720
|
"Tip: Run `vem link` at any time to connect this repo to a project."
|
|
5339
5721
|
)
|
|
5340
5722
|
);
|
|
@@ -5348,43 +5730,43 @@ function registerSetupCommands(program2) {
|
|
|
5348
5730
|
apiKey
|
|
5349
5731
|
);
|
|
5350
5732
|
console.log(
|
|
5351
|
-
|
|
5733
|
+
chalk16.gray(
|
|
5352
5734
|
`Synced ${syncedCount} agent instruction file${syncedCount === 1 ? "" : "s"} to cloud memory.`
|
|
5353
5735
|
)
|
|
5354
5736
|
);
|
|
5355
5737
|
} catch (error) {
|
|
5356
5738
|
const message = error instanceof Error ? error.message : String(error);
|
|
5357
5739
|
console.log(
|
|
5358
|
-
|
|
5740
|
+
chalk16.yellow(`\u26A0 Agent instruction sync skipped: ${message}`)
|
|
5359
5741
|
);
|
|
5360
5742
|
}
|
|
5361
5743
|
} else if (!apiKey) {
|
|
5362
5744
|
console.log(
|
|
5363
|
-
|
|
5745
|
+
chalk16.gray(
|
|
5364
5746
|
"Tip: Use the web dashboard project settings to run reindexing after `vem login` + `vem link`."
|
|
5365
5747
|
)
|
|
5366
5748
|
);
|
|
5367
5749
|
}
|
|
5368
5750
|
} catch (error) {
|
|
5369
|
-
console.error(
|
|
5751
|
+
console.error(chalk16.red("\n\u2716 Failed to initialize vem:"), error);
|
|
5370
5752
|
process.exit(1);
|
|
5371
5753
|
}
|
|
5372
5754
|
});
|
|
5373
5755
|
program2.command("quickstart").description("Interactive guide to powerful VEM workflows").action(async () => {
|
|
5374
5756
|
await trackCommandUsage("quickstart");
|
|
5375
|
-
console.log(
|
|
5757
|
+
console.log(chalk16.bold.cyan("\n\u{1F680} VEM Quickstart Guide\n"));
|
|
5376
5758
|
console.log("Let's set up a powerful agent-driven workflow!\n");
|
|
5377
5759
|
const configService = new ConfigService();
|
|
5378
5760
|
if (!await isVemInitialized()) {
|
|
5379
|
-
console.log(
|
|
5380
|
-
const initResponse = await
|
|
5761
|
+
console.log(chalk16.yellow("Step 1: Initialize VEM\n"));
|
|
5762
|
+
const initResponse = await prompts8({
|
|
5381
5763
|
type: "confirm",
|
|
5382
5764
|
name: "init",
|
|
5383
5765
|
message: "Initialize .vem/ in this repository?",
|
|
5384
5766
|
initial: true
|
|
5385
5767
|
});
|
|
5386
5768
|
if (!initResponse.init) {
|
|
5387
|
-
console.log(
|
|
5769
|
+
console.log(chalk16.yellow("Quickstart cancelled."));
|
|
5388
5770
|
return;
|
|
5389
5771
|
}
|
|
5390
5772
|
try {
|
|
@@ -5393,13 +5775,13 @@ function registerSetupCommands(program2) {
|
|
|
5393
5775
|
await ensureVemGitignoreEntry();
|
|
5394
5776
|
const initHash = await computeVemHash();
|
|
5395
5777
|
await configService.setLastSyncedVemHash(initHash);
|
|
5396
|
-
console.log(
|
|
5778
|
+
console.log(chalk16.green("\u2713 VEM initialized\n"));
|
|
5397
5779
|
} catch (error) {
|
|
5398
|
-
console.error(
|
|
5780
|
+
console.error(chalk16.red("Failed to initialize:"), error.message);
|
|
5399
5781
|
return;
|
|
5400
5782
|
}
|
|
5401
5783
|
} else {
|
|
5402
|
-
console.log(
|
|
5784
|
+
console.log(chalk16.green("\u2713 VEM already initialized\n"));
|
|
5403
5785
|
}
|
|
5404
5786
|
let isAuthenticated = false;
|
|
5405
5787
|
try {
|
|
@@ -5409,52 +5791,52 @@ function registerSetupCommands(program2) {
|
|
|
5409
5791
|
isAuthenticated = false;
|
|
5410
5792
|
}
|
|
5411
5793
|
if (!isAuthenticated) {
|
|
5412
|
-
console.log(
|
|
5794
|
+
console.log(chalk16.yellow("Step 2: Authenticate\n"));
|
|
5413
5795
|
console.log("Get your API key from: https://vem.dev/keys\n");
|
|
5414
|
-
const authResponse = await
|
|
5796
|
+
const authResponse = await prompts8({
|
|
5415
5797
|
type: "text",
|
|
5416
5798
|
name: "apiKey",
|
|
5417
5799
|
message: "Paste your API key:"
|
|
5418
5800
|
});
|
|
5419
5801
|
if (!authResponse.apiKey) {
|
|
5420
|
-
console.log(
|
|
5802
|
+
console.log(chalk16.yellow("Quickstart cancelled."));
|
|
5421
5803
|
return;
|
|
5422
5804
|
}
|
|
5423
5805
|
await configService.setApiKey(authResponse.apiKey);
|
|
5424
|
-
console.log(
|
|
5806
|
+
console.log(chalk16.green("\u2713 Authenticated\n"));
|
|
5425
5807
|
} else {
|
|
5426
|
-
console.log(
|
|
5808
|
+
console.log(chalk16.green("\u2713 Already authenticated\n"));
|
|
5427
5809
|
}
|
|
5428
5810
|
const projectId = await configService.getProjectId().catch(() => null);
|
|
5429
5811
|
if (!projectId) {
|
|
5430
|
-
console.log(
|
|
5812
|
+
console.log(chalk16.yellow("Step 3: Link to project\n"));
|
|
5431
5813
|
console.log("This connects your local .vem/ to cloud sync.\n");
|
|
5432
|
-
const linkResponse = await
|
|
5814
|
+
const linkResponse = await prompts8({
|
|
5433
5815
|
type: "confirm",
|
|
5434
5816
|
name: "link",
|
|
5435
5817
|
message: "Link to a project now?",
|
|
5436
5818
|
initial: true
|
|
5437
5819
|
});
|
|
5438
5820
|
if (linkResponse.link) {
|
|
5439
|
-
console.log(
|
|
5440
|
-
console.log(
|
|
5821
|
+
console.log(chalk16.cyan("\nRun: vem link"));
|
|
5822
|
+
console.log(chalk16.gray("(You can select or create a project)\n"));
|
|
5441
5823
|
}
|
|
5442
5824
|
} else {
|
|
5443
|
-
console.log(
|
|
5825
|
+
console.log(chalk16.green(`\u2713 Linked to project: ${projectId}
|
|
5444
5826
|
`));
|
|
5445
5827
|
}
|
|
5446
|
-
console.log(
|
|
5828
|
+
console.log(chalk16.bold.cyan("\n\u{1F4CB} Task-Driven Workflow\n"));
|
|
5447
5829
|
console.log(
|
|
5448
5830
|
"Tasks help you track work and provide context to AI agents.\n"
|
|
5449
5831
|
);
|
|
5450
|
-
const taskResponse = await
|
|
5832
|
+
const taskResponse = await prompts8({
|
|
5451
5833
|
type: "confirm",
|
|
5452
5834
|
name: "createTask",
|
|
5453
5835
|
message: "Create your first task?",
|
|
5454
5836
|
initial: true
|
|
5455
5837
|
});
|
|
5456
5838
|
if (taskResponse.createTask) {
|
|
5457
|
-
const taskDetails = await
|
|
5839
|
+
const taskDetails = await prompts8([
|
|
5458
5840
|
{
|
|
5459
5841
|
type: "text",
|
|
5460
5842
|
name: "title",
|
|
@@ -5473,53 +5855,53 @@ function registerSetupCommands(program2) {
|
|
|
5473
5855
|
taskDetails.description || "",
|
|
5474
5856
|
"medium"
|
|
5475
5857
|
);
|
|
5476
|
-
console.log(
|
|
5858
|
+
console.log(chalk16.green(`
|
|
5477
5859
|
\u2713 Created task: ${task.id}`));
|
|
5478
5860
|
}
|
|
5479
5861
|
}
|
|
5480
|
-
console.log(
|
|
5862
|
+
console.log(chalk16.bold.cyan("\n\u{1F916} Agent-Driven Development\n"));
|
|
5481
5863
|
console.log("The 'vem agent' command wraps AI tools with:\n");
|
|
5482
5864
|
console.log(" \u2022 Automatic context injection");
|
|
5483
5865
|
console.log(" \u2022 Task tracking");
|
|
5484
5866
|
console.log(" \u2022 Strict memory enforcement");
|
|
5485
5867
|
console.log(" \u2022 Validation workflows\n");
|
|
5486
|
-
const agentResponse = await
|
|
5868
|
+
const agentResponse = await prompts8({
|
|
5487
5869
|
type: "confirm",
|
|
5488
5870
|
name: "launchAgent",
|
|
5489
5871
|
message: "Launch an agent session now?",
|
|
5490
5872
|
initial: false
|
|
5491
5873
|
});
|
|
5492
5874
|
if (agentResponse.launchAgent) {
|
|
5493
|
-
console.log(
|
|
5494
|
-
console.log(
|
|
5875
|
+
console.log(chalk16.cyan("\n\u{1F680} Launching agent...\n"));
|
|
5876
|
+
console.log(chalk16.white("Run: vem agent\n"));
|
|
5495
5877
|
}
|
|
5496
|
-
console.log(
|
|
5878
|
+
console.log(chalk16.bold.cyan("\n\u2728 Quick Reference\n"));
|
|
5497
5879
|
console.log(
|
|
5498
|
-
|
|
5880
|
+
chalk16.white(" vem agent") + chalk16.gray(" # Start AI-assisted work")
|
|
5499
5881
|
);
|
|
5500
5882
|
console.log(
|
|
5501
|
-
|
|
5883
|
+
chalk16.white(" vem task list") + chalk16.gray(" # View tasks")
|
|
5502
5884
|
);
|
|
5503
5885
|
console.log(
|
|
5504
|
-
|
|
5886
|
+
chalk16.white(" vem task add") + chalk16.gray(" # Create task")
|
|
5505
5887
|
);
|
|
5506
5888
|
console.log(
|
|
5507
|
-
|
|
5889
|
+
chalk16.white(" vem push") + chalk16.gray(" # Sync to cloud")
|
|
5508
5890
|
);
|
|
5509
5891
|
console.log(
|
|
5510
|
-
|
|
5892
|
+
chalk16.white(" vem search") + chalk16.gray(" # Query memory")
|
|
5511
5893
|
);
|
|
5512
5894
|
console.log(
|
|
5513
|
-
|
|
5895
|
+
chalk16.white(" vem status") + chalk16.gray(" # Check power score\n")
|
|
5514
5896
|
);
|
|
5515
|
-
console.log(
|
|
5897
|
+
console.log(chalk16.green("\u{1F389} You're ready to use VEM powerfully!\n"));
|
|
5516
5898
|
});
|
|
5517
5899
|
program2.command("status").description("Show current project status").action(async () => {
|
|
5518
5900
|
await trackCommandUsage("status");
|
|
5519
5901
|
try {
|
|
5520
5902
|
await ensureVemFiles();
|
|
5521
5903
|
const configService = new ConfigService();
|
|
5522
|
-
console.log(
|
|
5904
|
+
console.log(chalk16.bold("\n\u{1F4CA} vem Status\n"));
|
|
5523
5905
|
const apiKey = await configService.getApiKey();
|
|
5524
5906
|
if (apiKey) {
|
|
5525
5907
|
try {
|
|
@@ -5532,28 +5914,28 @@ function registerSetupCommands(program2) {
|
|
|
5532
5914
|
if (response.ok) {
|
|
5533
5915
|
const data = await response.json();
|
|
5534
5916
|
console.log(
|
|
5535
|
-
`Login Status: ${
|
|
5917
|
+
`Login Status: ${chalk16.green("Logged In")} (User: ${data.userId})`
|
|
5536
5918
|
);
|
|
5537
5919
|
console.log(
|
|
5538
|
-
|
|
5920
|
+
chalk16.gray(" (Run `vem logout` to sign out)")
|
|
5539
5921
|
);
|
|
5540
5922
|
} else {
|
|
5541
5923
|
console.log(
|
|
5542
|
-
`Login Status: ${
|
|
5924
|
+
`Login Status: ${chalk16.red(
|
|
5543
5925
|
"Invalid Session"
|
|
5544
5926
|
)} (Run \`vem login\` to fix)`
|
|
5545
5927
|
);
|
|
5546
5928
|
}
|
|
5547
5929
|
} catch (_err) {
|
|
5548
5930
|
console.log(
|
|
5549
|
-
`Login Status: ${
|
|
5931
|
+
`Login Status: ${chalk16.yellow(
|
|
5550
5932
|
"Logged In (Offline/Unverified)"
|
|
5551
5933
|
)} (Cannot reach API)`
|
|
5552
5934
|
);
|
|
5553
5935
|
}
|
|
5554
5936
|
} else {
|
|
5555
5937
|
console.log(
|
|
5556
|
-
`Login Status: ${
|
|
5938
|
+
`Login Status: ${chalk16.red(
|
|
5557
5939
|
"Not Logged In"
|
|
5558
5940
|
)} (Run \`vem login\` options)`
|
|
5559
5941
|
);
|
|
@@ -5568,25 +5950,25 @@ function registerSetupCommands(program2) {
|
|
|
5568
5950
|
);
|
|
5569
5951
|
if (check.valid) {
|
|
5570
5952
|
const label = check.name ? `${check.name} (${projectId})` : projectId;
|
|
5571
|
-
console.log(`Linked Project: ${
|
|
5953
|
+
console.log(`Linked Project: ${chalk16.green(label)}`);
|
|
5572
5954
|
} else {
|
|
5573
5955
|
console.log(
|
|
5574
|
-
`Linked Project: ${
|
|
5956
|
+
`Linked Project: ${chalk16.red(projectId)} ${chalk16.red("(not found \u2014 project may have been deleted)")}`
|
|
5575
5957
|
);
|
|
5576
5958
|
console.log(
|
|
5577
|
-
|
|
5959
|
+
chalk16.gray(
|
|
5578
5960
|
" Run `vem unlink` then `vem link` to fix."
|
|
5579
5961
|
)
|
|
5580
5962
|
);
|
|
5581
5963
|
}
|
|
5582
5964
|
} else {
|
|
5583
5965
|
console.log(
|
|
5584
|
-
`Linked Project: ${
|
|
5966
|
+
`Linked Project: ${chalk16.yellow(projectId)} (unverified \u2014 not logged in)`
|
|
5585
5967
|
);
|
|
5586
5968
|
}
|
|
5587
5969
|
} else {
|
|
5588
5970
|
console.log(
|
|
5589
|
-
`Linked Project: ${
|
|
5971
|
+
`Linked Project: ${chalk16.yellow("Not Linked")} (Run \`vem link\`)`
|
|
5590
5972
|
);
|
|
5591
5973
|
}
|
|
5592
5974
|
try {
|
|
@@ -5599,17 +5981,17 @@ function registerSetupCommands(program2) {
|
|
|
5599
5981
|
).length;
|
|
5600
5982
|
console.log(`
|
|
5601
5983
|
Local Tasks:`);
|
|
5602
|
-
console.log(` Open: ${
|
|
5603
|
-
console.log(` Completed: ${
|
|
5984
|
+
console.log(` Open: ${chalk16.yellow(active)}`);
|
|
5985
|
+
console.log(` Completed: ${chalk16.green(completed)}`);
|
|
5604
5986
|
} catch (_err) {
|
|
5605
5987
|
console.log(
|
|
5606
5988
|
`
|
|
5607
|
-
Local Tasks: ${
|
|
5989
|
+
Local Tasks: ${chalk16.gray("Not initialized (Run `vem init`)")}`
|
|
5608
5990
|
);
|
|
5609
5991
|
}
|
|
5610
5992
|
const stats = await metricsService.getStats();
|
|
5611
|
-
console.log(
|
|
5612
|
-
const scoreColor = stats.powerScore >= 70 ?
|
|
5993
|
+
console.log(chalk16.bold("\n\u26A1 Power Feature Usage\n"));
|
|
5994
|
+
const scoreColor = stats.powerScore >= 70 ? chalk16.green : stats.powerScore >= 40 ? chalk16.yellow : chalk16.gray;
|
|
5613
5995
|
console.log(` Power Score: ${scoreColor(`${stats.powerScore}/100`)}`);
|
|
5614
5996
|
const features = [
|
|
5615
5997
|
{
|
|
@@ -5643,34 +6025,34 @@ Local Tasks: ${chalk15.gray("Not initialized (Run `vem init`)")}`
|
|
|
5643
6025
|
points: 5
|
|
5644
6026
|
}
|
|
5645
6027
|
];
|
|
5646
|
-
console.log(
|
|
6028
|
+
console.log(chalk16.gray("\n Features:"));
|
|
5647
6029
|
for (const feature of features) {
|
|
5648
|
-
const icon = feature.used ?
|
|
5649
|
-
const name = feature.used ?
|
|
5650
|
-
const pts = feature.used ?
|
|
6030
|
+
const icon = feature.used ? chalk16.green("\u2713") : chalk16.gray("\u25CB");
|
|
6031
|
+
const name = feature.used ? chalk16.white(feature.name) : chalk16.gray(feature.name);
|
|
6032
|
+
const pts = feature.used ? chalk16.green(`+${feature.points}`) : chalk16.gray(`+${feature.points}`);
|
|
5651
6033
|
console.log(` ${icon} ${name} ${pts}`);
|
|
5652
6034
|
}
|
|
5653
6035
|
if (stats.powerScore < 40) {
|
|
5654
6036
|
console.log(
|
|
5655
|
-
|
|
6037
|
+
chalk16.yellow(
|
|
5656
6038
|
"\n \u{1F4A1} Tip: Try 'vem agent' to unlock powerful workflows"
|
|
5657
6039
|
)
|
|
5658
6040
|
);
|
|
5659
6041
|
} else if (stats.powerScore < 70) {
|
|
5660
6042
|
console.log(
|
|
5661
|
-
|
|
6043
|
+
chalk16.cyan(
|
|
5662
6044
|
"\n \u{1F4A1} You're on your way! Keep using task-driven workflows"
|
|
5663
6045
|
)
|
|
5664
6046
|
);
|
|
5665
6047
|
} else {
|
|
5666
6048
|
console.log(
|
|
5667
|
-
|
|
6049
|
+
chalk16.green("\n \u{1F389} Excellent! You're using VEM like a pro")
|
|
5668
6050
|
);
|
|
5669
6051
|
}
|
|
5670
6052
|
if (stats.lastAgentRun) {
|
|
5671
6053
|
const timeSince = Date.now() - stats.lastAgentRun;
|
|
5672
6054
|
const days = Math.floor(timeSince / (1e3 * 60 * 60 * 24));
|
|
5673
|
-
console.log(
|
|
6055
|
+
console.log(chalk16.bold("\n\u{1F4C5} Recent Activity\n"));
|
|
5674
6056
|
console.log(
|
|
5675
6057
|
` Last agent session: ${days === 0 ? "today" : `${days} days ago`}`
|
|
5676
6058
|
);
|
|
@@ -5678,7 +6060,7 @@ Local Tasks: ${chalk15.gray("Not initialized (Run `vem init`)")}`
|
|
|
5678
6060
|
renderUsageInsights(stats, false);
|
|
5679
6061
|
console.log("");
|
|
5680
6062
|
} catch (error) {
|
|
5681
|
-
console.error(
|
|
6063
|
+
console.error(chalk16.red("\n\u2716 Failed to check status:"), error.message);
|
|
5682
6064
|
}
|
|
5683
6065
|
});
|
|
5684
6066
|
program2.command("insights").description("Show detailed usage metrics and workflow insights").option("--json", "Output raw usage metrics as JSON").action(async (options) => {
|
|
@@ -5690,19 +6072,19 @@ Local Tasks: ${chalk15.gray("Not initialized (Run `vem init`)")}`
|
|
|
5690
6072
|
console.log(JSON.stringify(stats, null, 2));
|
|
5691
6073
|
return;
|
|
5692
6074
|
}
|
|
5693
|
-
console.log(
|
|
5694
|
-
console.log(`Power Score: ${
|
|
6075
|
+
console.log(chalk16.bold("\n\u{1F4CA} vem Insights\n"));
|
|
6076
|
+
console.log(`Power Score: ${chalk16.cyan(`${stats.powerScore}/100`)}`);
|
|
5695
6077
|
renderUsageInsights(stats, true);
|
|
5696
6078
|
console.log("");
|
|
5697
6079
|
} catch (error) {
|
|
5698
|
-
console.error(
|
|
6080
|
+
console.error(chalk16.red("\n\u2716 Failed to load insights:"), error.message);
|
|
5699
6081
|
}
|
|
5700
6082
|
});
|
|
5701
6083
|
}
|
|
5702
6084
|
|
|
5703
6085
|
// src/commands/sync.ts
|
|
5704
|
-
import { readFile as
|
|
5705
|
-
import
|
|
6086
|
+
import { readFile as readFile6 } from "fs/promises";
|
|
6087
|
+
import chalk17 from "chalk";
|
|
5706
6088
|
import Table3 from "cli-table3";
|
|
5707
6089
|
function registerSyncCommands(program2) {
|
|
5708
6090
|
program2.command("push").description("Push local snapshot to cloud").option(
|
|
@@ -5715,7 +6097,7 @@ function registerSyncCommands(program2) {
|
|
|
5715
6097
|
const projectId = await configService.getProjectId();
|
|
5716
6098
|
if (!projectId) {
|
|
5717
6099
|
console.error(
|
|
5718
|
-
|
|
6100
|
+
chalk17.red(
|
|
5719
6101
|
"Error: Project not linked. Run `vem link <projectId>` before pushing snapshots."
|
|
5720
6102
|
)
|
|
5721
6103
|
);
|
|
@@ -5728,7 +6110,7 @@ function registerSyncCommands(program2) {
|
|
|
5728
6110
|
const gitHash = getGitHash();
|
|
5729
6111
|
if (!gitHash) {
|
|
5730
6112
|
console.error(
|
|
5731
|
-
|
|
6113
|
+
chalk17.red(
|
|
5732
6114
|
"Error: git HEAD not found. Create at least one commit before running `vem push`."
|
|
5733
6115
|
)
|
|
5734
6116
|
);
|
|
@@ -5740,25 +6122,25 @@ function registerSyncCommands(program2) {
|
|
|
5740
6122
|
if (!hasChanges && !options.force) {
|
|
5741
6123
|
const lastPushTime = lastPush.gitHash ? "previously" : "never";
|
|
5742
6124
|
console.log(
|
|
5743
|
-
|
|
6125
|
+
chalk17.gray(
|
|
5744
6126
|
`\u2714 No changes since last push (git HEAD and .vem unchanged). Last push: ${lastPushTime}`
|
|
5745
6127
|
)
|
|
5746
6128
|
);
|
|
5747
|
-
console.log(
|
|
6129
|
+
console.log(chalk17.gray(" Use --force to push anyway."));
|
|
5748
6130
|
return;
|
|
5749
6131
|
}
|
|
5750
|
-
console.log(
|
|
6132
|
+
console.log(chalk17.blue("\u{1F4E6} Packing snapshot..."));
|
|
5751
6133
|
const snapshot = await syncService.pack();
|
|
5752
6134
|
const snapshotHash = computeSnapshotHash(snapshot);
|
|
5753
6135
|
const targetLabel = `linked project ${projectId}`;
|
|
5754
6136
|
if (options.dryRun) {
|
|
5755
|
-
console.log(
|
|
5756
|
-
console.log(
|
|
5757
|
-
console.log(
|
|
5758
|
-
console.log(
|
|
5759
|
-
console.log(
|
|
6137
|
+
console.log(chalk17.cyan("\n\u{1F4CB} Dry Run Preview\n"));
|
|
6138
|
+
console.log(chalk17.white(`Target: ${targetLabel}`));
|
|
6139
|
+
console.log(chalk17.white(`Git Hash: ${gitHash}`));
|
|
6140
|
+
console.log(chalk17.white(`Snapshot Hash: ${snapshotHash}`));
|
|
6141
|
+
console.log(chalk17.white(`Base Version: ${baseVersion || "none"}`));
|
|
5760
6142
|
console.log(
|
|
5761
|
-
|
|
6143
|
+
chalk17.white(
|
|
5762
6144
|
"Verification: pending until Git webhook matches git hash + snapshot hash"
|
|
5763
6145
|
)
|
|
5764
6146
|
);
|
|
@@ -5766,29 +6148,29 @@ function registerSyncCommands(program2) {
|
|
|
5766
6148
|
const decisionCount = snapshot.decisions?.length || 0;
|
|
5767
6149
|
const changelogCount = snapshot.changelog?.length || 0;
|
|
5768
6150
|
const agentInstructionCount = snapshot.agent_instructions?.length || 0;
|
|
5769
|
-
console.log(
|
|
6151
|
+
console.log(chalk17.white(`
|
|
5770
6152
|
Snapshot Contents:`));
|
|
5771
|
-
console.log(
|
|
5772
|
-
console.log(
|
|
5773
|
-
console.log(
|
|
6153
|
+
console.log(chalk17.gray(` Tasks: ${taskCount}`));
|
|
6154
|
+
console.log(chalk17.gray(` Decisions (chars): ${decisionCount}`));
|
|
6155
|
+
console.log(chalk17.gray(` Changelog (chars): ${changelogCount}`));
|
|
5774
6156
|
console.log(
|
|
5775
|
-
|
|
6157
|
+
chalk17.gray(` Context: ${snapshot.context ? "yes" : "no"}`)
|
|
5776
6158
|
);
|
|
5777
6159
|
console.log(
|
|
5778
|
-
|
|
6160
|
+
chalk17.gray(
|
|
5779
6161
|
` Current state: ${snapshot.current_state ? "yes" : "no"}`
|
|
5780
6162
|
)
|
|
5781
6163
|
);
|
|
5782
6164
|
console.log(
|
|
5783
|
-
|
|
6165
|
+
chalk17.gray(
|
|
5784
6166
|
` Agent instructions: ${agentInstructionCount} file${agentInstructionCount === 1 ? "" : "s"}`
|
|
5785
6167
|
)
|
|
5786
6168
|
);
|
|
5787
|
-
console.log(
|
|
5788
|
-
console.log(
|
|
6169
|
+
console.log(chalk17.cyan("\n\u2714 Dry run complete. No changes pushed.\n"));
|
|
6170
|
+
console.log(chalk17.gray(" Run without --dry-run to push for real."));
|
|
5789
6171
|
return;
|
|
5790
6172
|
}
|
|
5791
|
-
console.log(
|
|
6173
|
+
console.log(chalk17.blue(`\u{1F680} Pushing to cloud (${targetLabel})...`));
|
|
5792
6174
|
const commits = await getCommits(50);
|
|
5793
6175
|
const payload = {
|
|
5794
6176
|
...snapshot,
|
|
@@ -5804,12 +6186,12 @@ Snapshot Contents:`));
|
|
|
5804
6186
|
const expectedRepoUrl = result.data.expected_repo_url;
|
|
5805
6187
|
const actualRepo = repoUrl || "(no git remote)";
|
|
5806
6188
|
console.log(
|
|
5807
|
-
|
|
6189
|
+
chalk17.yellow(
|
|
5808
6190
|
`Project is linked to ${expectedRepoUrl}. Local repo is ${actualRepo}. Retrying using the linked project only...`
|
|
5809
6191
|
)
|
|
5810
6192
|
);
|
|
5811
6193
|
console.log(
|
|
5812
|
-
|
|
6194
|
+
chalk17.blue(
|
|
5813
6195
|
`\u{1F680} Pushing to cloud (linked repo ${expectedRepoUrl})...`
|
|
5814
6196
|
)
|
|
5815
6197
|
);
|
|
@@ -5823,7 +6205,7 @@ Snapshot Contents:`));
|
|
|
5823
6205
|
await configService.setLastSyncedVemHash(vemHash);
|
|
5824
6206
|
}
|
|
5825
6207
|
console.log(
|
|
5826
|
-
|
|
6208
|
+
chalk17.green(
|
|
5827
6209
|
`
|
|
5828
6210
|
\u2714 Snapshot pushed! Version: ${result.data.version || "v1"}
|
|
5829
6211
|
`
|
|
@@ -5835,12 +6217,12 @@ Snapshot Contents:`));
|
|
|
5835
6217
|
});
|
|
5836
6218
|
if (archivedCount > 0) {
|
|
5837
6219
|
console.log(
|
|
5838
|
-
|
|
6220
|
+
chalk17.green(`\u2714 Archived ${archivedCount} completed tasks.`)
|
|
5839
6221
|
);
|
|
5840
6222
|
}
|
|
5841
6223
|
} catch (err) {
|
|
5842
6224
|
console.error(
|
|
5843
|
-
|
|
6225
|
+
chalk17.yellow(
|
|
5844
6226
|
`\u26A0 Failed to archive completed tasks: ${err instanceof Error ? err.message : String(err)}`
|
|
5845
6227
|
)
|
|
5846
6228
|
);
|
|
@@ -5852,7 +6234,7 @@ Snapshot Contents:`));
|
|
|
5852
6234
|
if (data.latest_version) {
|
|
5853
6235
|
const latest = data.latest_version || "unknown";
|
|
5854
6236
|
console.error(
|
|
5855
|
-
|
|
6237
|
+
chalk17.yellow(
|
|
5856
6238
|
`Conflict: local base version ${baseVersion || "none"} does not match latest ${latest}. Pull the latest snapshot (\`vem pull\`) or re-run push from the latest memory state.`
|
|
5857
6239
|
)
|
|
5858
6240
|
);
|
|
@@ -5862,18 +6244,18 @@ Snapshot Contents:`));
|
|
|
5862
6244
|
const expectedRepoUrl = data.expected_repo_url;
|
|
5863
6245
|
const actualRepo = repoUrl || "(no git remote)";
|
|
5864
6246
|
console.error(
|
|
5865
|
-
|
|
6247
|
+
chalk17.yellow(
|
|
5866
6248
|
`Project is linked to ${expectedRepoUrl}, local repo is ${actualRepo}. Update your git remote or re-link the project, then retry.`
|
|
5867
6249
|
)
|
|
5868
6250
|
);
|
|
5869
6251
|
return;
|
|
5870
6252
|
}
|
|
5871
|
-
console.error(
|
|
6253
|
+
console.error(chalk17.yellow(data.error || "Conflict detected."));
|
|
5872
6254
|
return;
|
|
5873
6255
|
}
|
|
5874
6256
|
if (result.status === 403) {
|
|
5875
6257
|
console.error(
|
|
5876
|
-
|
|
6258
|
+
chalk17.red(
|
|
5877
6259
|
result.error || "Device limit reached. Disconnect a device or upgrade your plan."
|
|
5878
6260
|
)
|
|
5879
6261
|
);
|
|
@@ -5881,26 +6263,26 @@ Snapshot Contents:`));
|
|
|
5881
6263
|
}
|
|
5882
6264
|
if (result.status === 404) {
|
|
5883
6265
|
console.error(
|
|
5884
|
-
|
|
6266
|
+
chalk17.red(
|
|
5885
6267
|
result.error || "Project not found. It may have been deleted. Run `vem unlink` then `vem link` to reconnect."
|
|
5886
6268
|
)
|
|
5887
6269
|
);
|
|
5888
6270
|
return;
|
|
5889
6271
|
}
|
|
5890
6272
|
console.log(
|
|
5891
|
-
|
|
6273
|
+
chalk17.yellow(
|
|
5892
6274
|
`
|
|
5893
6275
|
\u26A0 Push failed (${result.error}). Queuing snapshot for later...`
|
|
5894
6276
|
)
|
|
5895
6277
|
);
|
|
5896
6278
|
const id = await syncService.enqueue(payload);
|
|
5897
|
-
console.log(
|
|
6279
|
+
console.log(chalk17.gray(`Queued as ${id}`));
|
|
5898
6280
|
}
|
|
5899
6281
|
} catch (error) {
|
|
5900
6282
|
if (error instanceof Error) {
|
|
5901
|
-
console.error(
|
|
6283
|
+
console.error(chalk17.red("\n\u2716 Push Failed:"), error.message);
|
|
5902
6284
|
} else {
|
|
5903
|
-
console.error(
|
|
6285
|
+
console.error(chalk17.red("\n\u2716 Push Failed:"), String(error));
|
|
5904
6286
|
}
|
|
5905
6287
|
}
|
|
5906
6288
|
});
|
|
@@ -5911,12 +6293,12 @@ Snapshot Contents:`));
|
|
|
5911
6293
|
const projectId = await configService.getProjectId();
|
|
5912
6294
|
if (await isVemDirty(configService) && !options.force) {
|
|
5913
6295
|
console.error(
|
|
5914
|
-
|
|
6296
|
+
chalk17.yellow(
|
|
5915
6297
|
"\u26A0 Local .vem memory has unsynced changes. Pulling will overwrite it."
|
|
5916
6298
|
)
|
|
5917
6299
|
);
|
|
5918
6300
|
console.log(
|
|
5919
|
-
|
|
6301
|
+
chalk17.gray(
|
|
5920
6302
|
"Push your snapshot first, or use `vem pull --force` to proceed."
|
|
5921
6303
|
)
|
|
5922
6304
|
);
|
|
@@ -5925,7 +6307,7 @@ Snapshot Contents:`));
|
|
|
5925
6307
|
const repoUrl = projectId ? null : await getGitRemote();
|
|
5926
6308
|
if (!repoUrl && !projectId) {
|
|
5927
6309
|
console.error(
|
|
5928
|
-
|
|
6310
|
+
chalk17.red(
|
|
5929
6311
|
"Error: Could not detect git remote URL or linked project. Run `vem link <projectId>` or set a git remote."
|
|
5930
6312
|
)
|
|
5931
6313
|
);
|
|
@@ -5933,7 +6315,7 @@ Snapshot Contents:`));
|
|
|
5933
6315
|
}
|
|
5934
6316
|
const targetLabel = repoUrl || projectId || "project";
|
|
5935
6317
|
console.log(
|
|
5936
|
-
|
|
6318
|
+
chalk17.blue(`\u2B07 Finding latest snapshot for ${targetLabel}...`)
|
|
5937
6319
|
);
|
|
5938
6320
|
const query = new URLSearchParams();
|
|
5939
6321
|
if (repoUrl) query.set("repo_url", repoUrl);
|
|
@@ -5948,10 +6330,10 @@ Snapshot Contents:`));
|
|
|
5948
6330
|
const data2 = await res.json().catch(() => ({}));
|
|
5949
6331
|
if (res.status === 404) {
|
|
5950
6332
|
const message = typeof data2.error === "string" ? data2.error : "Project not found. It may have been deleted. Run `vem unlink` then `vem link` to reconnect.";
|
|
5951
|
-
console.log(
|
|
6333
|
+
console.log(chalk17.yellow(message));
|
|
5952
6334
|
if (message.toLowerCase().includes("no snapshots")) {
|
|
5953
6335
|
console.log(
|
|
5954
|
-
|
|
6336
|
+
chalk17.gray(
|
|
5955
6337
|
"Tip: push a snapshot first (`vem push`) and wait for verification if needed."
|
|
5956
6338
|
)
|
|
5957
6339
|
);
|
|
@@ -5961,18 +6343,18 @@ Snapshot Contents:`));
|
|
|
5961
6343
|
if (res.status === 409) {
|
|
5962
6344
|
if (data2.expected_repo_url) {
|
|
5963
6345
|
console.error(
|
|
5964
|
-
|
|
6346
|
+
chalk17.yellow(
|
|
5965
6347
|
`Repo URL mismatch. Expected ${data2.expected_repo_url}. Update your git remote or project settings, then retry.`
|
|
5966
6348
|
)
|
|
5967
6349
|
);
|
|
5968
6350
|
return;
|
|
5969
6351
|
}
|
|
5970
|
-
console.error(
|
|
6352
|
+
console.error(chalk17.yellow(data2.error || "Conflict detected."));
|
|
5971
6353
|
return;
|
|
5972
6354
|
}
|
|
5973
6355
|
if (res.status === 403) {
|
|
5974
6356
|
console.error(
|
|
5975
|
-
|
|
6357
|
+
chalk17.red(
|
|
5976
6358
|
data2.error || "Device limit reached. Disconnect a device or upgrade your plan."
|
|
5977
6359
|
)
|
|
5978
6360
|
);
|
|
@@ -5984,10 +6366,10 @@ Snapshot Contents:`));
|
|
|
5984
6366
|
}
|
|
5985
6367
|
const data = await res.json();
|
|
5986
6368
|
if (!data.snapshot) {
|
|
5987
|
-
console.log(
|
|
6369
|
+
console.log(chalk17.yellow("No snapshot data in response."));
|
|
5988
6370
|
return;
|
|
5989
6371
|
}
|
|
5990
|
-
console.log(
|
|
6372
|
+
console.log(chalk17.blue("\u{1F4E6} Unpacking snapshot..."));
|
|
5991
6373
|
await syncService.unpack(data.snapshot);
|
|
5992
6374
|
const localHash = await computeVemHash();
|
|
5993
6375
|
await configService.setLastSyncedVemHash(localHash);
|
|
@@ -5995,15 +6377,15 @@ Snapshot Contents:`));
|
|
|
5995
6377
|
await configService.setLastVersion(data.version);
|
|
5996
6378
|
}
|
|
5997
6379
|
console.log(
|
|
5998
|
-
|
|
6380
|
+
chalk17.green(`
|
|
5999
6381
|
\u2714 Synced to version ${data.version || "unknown"}
|
|
6000
6382
|
`)
|
|
6001
6383
|
);
|
|
6002
6384
|
} catch (error) {
|
|
6003
6385
|
if (error instanceof Error) {
|
|
6004
|
-
console.error(
|
|
6386
|
+
console.error(chalk17.red("\n\u2716 Pull Failed:"), error.message);
|
|
6005
6387
|
} else {
|
|
6006
|
-
console.error(
|
|
6388
|
+
console.error(chalk17.red("\n\u2716 Pull Failed:"), String(error));
|
|
6007
6389
|
}
|
|
6008
6390
|
}
|
|
6009
6391
|
});
|
|
@@ -6017,9 +6399,9 @@ Snapshot Contents:`));
|
|
|
6017
6399
|
await showWorkflowHint("pack");
|
|
6018
6400
|
} catch (error) {
|
|
6019
6401
|
if (error instanceof Error) {
|
|
6020
|
-
console.error(
|
|
6402
|
+
console.error(chalk17.red("\n\u2716 Pack Failed:"), error.message);
|
|
6021
6403
|
} else {
|
|
6022
|
-
console.error(
|
|
6404
|
+
console.error(chalk17.red("\n\u2716 Pack Failed:"), String(error));
|
|
6023
6405
|
}
|
|
6024
6406
|
}
|
|
6025
6407
|
});
|
|
@@ -6028,12 +6410,12 @@ Snapshot Contents:`));
|
|
|
6028
6410
|
try {
|
|
6029
6411
|
let input = "";
|
|
6030
6412
|
if (options.file) {
|
|
6031
|
-
input = await
|
|
6413
|
+
input = await readFile6(options.file, "utf-8");
|
|
6032
6414
|
} else if (!process.stdin.isTTY) {
|
|
6033
6415
|
input = await readStdin();
|
|
6034
6416
|
} else {
|
|
6035
6417
|
console.error(
|
|
6036
|
-
|
|
6418
|
+
chalk17.red(
|
|
6037
6419
|
"Provide a vem_update block via --file or pipe it into stdin."
|
|
6038
6420
|
)
|
|
6039
6421
|
);
|
|
@@ -6042,66 +6424,66 @@ Snapshot Contents:`));
|
|
|
6042
6424
|
}
|
|
6043
6425
|
const update = parseVemUpdateBlock(input);
|
|
6044
6426
|
const result = await applyVemUpdate(update);
|
|
6045
|
-
console.log(
|
|
6427
|
+
console.log(chalk17.green("\n\u2714 vem update applied\n"));
|
|
6046
6428
|
if (result.updatedTasks.length > 0) {
|
|
6047
6429
|
console.log(
|
|
6048
|
-
|
|
6430
|
+
chalk17.gray(
|
|
6049
6431
|
`Updated tasks: ${result.updatedTasks.map((task) => task.id).join(", ")}`
|
|
6050
6432
|
)
|
|
6051
6433
|
);
|
|
6052
6434
|
}
|
|
6053
6435
|
if (result.newTasks.length > 0) {
|
|
6054
6436
|
console.log(
|
|
6055
|
-
|
|
6437
|
+
chalk17.gray(
|
|
6056
6438
|
`New tasks: ${result.newTasks.map((task) => task.id).join(", ")}`
|
|
6057
6439
|
)
|
|
6058
6440
|
);
|
|
6059
6441
|
}
|
|
6060
6442
|
if (result.changelogLines.length > 0) {
|
|
6061
6443
|
console.log(
|
|
6062
|
-
|
|
6444
|
+
chalk17.gray(`Changelog entries: ${result.changelogLines.length}`)
|
|
6063
6445
|
);
|
|
6064
6446
|
}
|
|
6065
6447
|
if (result.newCycles.length > 0) {
|
|
6066
6448
|
console.log(
|
|
6067
|
-
|
|
6449
|
+
chalk17.gray(
|
|
6068
6450
|
`New cycles: ${result.newCycles.map((c) => c.name).join(", ")}`
|
|
6069
6451
|
)
|
|
6070
6452
|
);
|
|
6071
6453
|
}
|
|
6072
6454
|
if (result.decisionsAppended) {
|
|
6073
|
-
console.log(
|
|
6455
|
+
console.log(chalk17.gray("Decisions updated."));
|
|
6074
6456
|
}
|
|
6075
6457
|
if (result.currentStateUpdated) {
|
|
6076
|
-
console.log(
|
|
6458
|
+
console.log(chalk17.gray("Current state updated."));
|
|
6077
6459
|
} else {
|
|
6078
6460
|
console.log(
|
|
6079
|
-
|
|
6461
|
+
chalk17.yellow(
|
|
6080
6462
|
"No current_state provided; CURRENT_STATE.md was left unchanged."
|
|
6081
6463
|
)
|
|
6082
6464
|
);
|
|
6083
6465
|
}
|
|
6084
6466
|
if (result.contextUpdated) {
|
|
6085
|
-
console.log(
|
|
6467
|
+
console.log(chalk17.gray("Context updated."));
|
|
6086
6468
|
}
|
|
6087
6469
|
const configService = new ConfigService();
|
|
6088
6470
|
await syncParsedTaskUpdatesToRemote(configService, update, result).catch(
|
|
6089
6471
|
(err) => {
|
|
6090
6472
|
console.error(
|
|
6091
|
-
|
|
6473
|
+
chalk17.yellow("[vem finalize] syncParsed failed:"),
|
|
6092
6474
|
err instanceof Error ? err.message : String(err)
|
|
6093
6475
|
);
|
|
6094
6476
|
}
|
|
6095
6477
|
);
|
|
6096
6478
|
const synced = await syncProjectMemoryToRemote().catch(() => false);
|
|
6097
6479
|
if (synced) {
|
|
6098
|
-
console.log(
|
|
6480
|
+
console.log(chalk17.gray("\u2714 Synced to cloud."));
|
|
6099
6481
|
}
|
|
6100
6482
|
} catch (error) {
|
|
6101
6483
|
if (error instanceof Error) {
|
|
6102
|
-
console.error(
|
|
6484
|
+
console.error(chalk17.red("\n\u2716 Finalize Failed:"), error.message);
|
|
6103
6485
|
} else {
|
|
6104
|
-
console.error(
|
|
6486
|
+
console.error(chalk17.red("\n\u2716 Finalize Failed:"), String(error));
|
|
6105
6487
|
}
|
|
6106
6488
|
process.exitCode = 1;
|
|
6107
6489
|
}
|
|
@@ -6114,7 +6496,7 @@ Snapshot Contents:`));
|
|
|
6114
6496
|
for (const item of queue2) {
|
|
6115
6497
|
await syncService.removeFromQueue(item.id);
|
|
6116
6498
|
}
|
|
6117
|
-
console.log(
|
|
6499
|
+
console.log(chalk17.green("\n\u2714 Queue cleared\n"));
|
|
6118
6500
|
return;
|
|
6119
6501
|
}
|
|
6120
6502
|
if (options.retry) {
|
|
@@ -6124,10 +6506,10 @@ Snapshot Contents:`));
|
|
|
6124
6506
|
}
|
|
6125
6507
|
const queue = await syncService.getQueue();
|
|
6126
6508
|
if (queue.length === 0) {
|
|
6127
|
-
console.log(
|
|
6509
|
+
console.log(chalk17.gray("\nOffline queue is empty.\n"));
|
|
6128
6510
|
return;
|
|
6129
6511
|
}
|
|
6130
|
-
console.log(
|
|
6512
|
+
console.log(chalk17.bold(`
|
|
6131
6513
|
\u{1F4E6} Offline Queue (${queue.length} items)
|
|
6132
6514
|
`));
|
|
6133
6515
|
const table = new Table3({
|
|
@@ -6137,7 +6519,7 @@ Snapshot Contents:`));
|
|
|
6137
6519
|
queue.forEach((item) => {
|
|
6138
6520
|
const date = new Date(parseInt(item.id.split("-")[0], 10));
|
|
6139
6521
|
table.push([
|
|
6140
|
-
|
|
6522
|
+
chalk17.gray(item.id),
|
|
6141
6523
|
date.toLocaleString(),
|
|
6142
6524
|
item.payload.repo_url || "unknown",
|
|
6143
6525
|
item.payload.base_version || "none"
|
|
@@ -6145,10 +6527,10 @@ Snapshot Contents:`));
|
|
|
6145
6527
|
});
|
|
6146
6528
|
console.log(table.toString());
|
|
6147
6529
|
console.log(
|
|
6148
|
-
|
|
6530
|
+
chalk17.gray("\nUse `vem queue --retry` to push these snapshots.\n")
|
|
6149
6531
|
);
|
|
6150
6532
|
} catch (error) {
|
|
6151
|
-
console.error(
|
|
6533
|
+
console.error(chalk17.red("Queue Error:"), error.message);
|
|
6152
6534
|
}
|
|
6153
6535
|
});
|
|
6154
6536
|
program2.command("archive").description("Archive old memory files to keep context small").option("--all", "Archive decisions, changelogs, and tasks").option("--decisions", "Archive decisions only").option("--changelog", "Archive changelog only").option("--tasks", "Archive completed tasks only").option(
|
|
@@ -6166,9 +6548,9 @@ Snapshot Contents:`));
|
|
|
6166
6548
|
const keepCount = options.keep ?? 20;
|
|
6167
6549
|
const olderThanDays = options.olderThan ?? 30;
|
|
6168
6550
|
const all = options.all || !options.decisions && !options.changelog && !options.tasks;
|
|
6169
|
-
console.log(
|
|
6551
|
+
console.log(chalk17.bold("\n\u{1F5C4}\uFE0F Archiving Memory...\n"));
|
|
6170
6552
|
console.log(
|
|
6171
|
-
|
|
6553
|
+
chalk17.gray(
|
|
6172
6554
|
`Criteria: Keep ${keepCount} items OR younger than ${olderThanDays} days.`
|
|
6173
6555
|
)
|
|
6174
6556
|
);
|
|
@@ -6179,9 +6561,9 @@ Snapshot Contents:`));
|
|
|
6179
6561
|
olderThanDays
|
|
6180
6562
|
});
|
|
6181
6563
|
if (count > 0) {
|
|
6182
|
-
console.log(
|
|
6564
|
+
console.log(chalk17.green(`\u2714 Archived ${count} decision(s)`));
|
|
6183
6565
|
} else {
|
|
6184
|
-
console.log(
|
|
6566
|
+
console.log(chalk17.gray("Decisions: Nothing to archive"));
|
|
6185
6567
|
}
|
|
6186
6568
|
}
|
|
6187
6569
|
if (all || options.changelog) {
|
|
@@ -6191,9 +6573,9 @@ Snapshot Contents:`));
|
|
|
6191
6573
|
olderThanDays
|
|
6192
6574
|
});
|
|
6193
6575
|
if (count > 0) {
|
|
6194
|
-
console.log(
|
|
6576
|
+
console.log(chalk17.green(`\u2714 Archived ${count} changelog entry(s)`));
|
|
6195
6577
|
} else {
|
|
6196
|
-
console.log(
|
|
6578
|
+
console.log(chalk17.gray("Changelog: Nothing to archive"));
|
|
6197
6579
|
}
|
|
6198
6580
|
}
|
|
6199
6581
|
if (all || options.tasks) {
|
|
@@ -6202,17 +6584,17 @@ Snapshot Contents:`));
|
|
|
6202
6584
|
olderThanDays
|
|
6203
6585
|
});
|
|
6204
6586
|
if (count > 0) {
|
|
6205
|
-
console.log(
|
|
6587
|
+
console.log(chalk17.green(`\u2714 Archived ${count} completed task(s)`));
|
|
6206
6588
|
} else {
|
|
6207
|
-
console.log(
|
|
6589
|
+
console.log(chalk17.gray("Tasks: Nothing to archive"));
|
|
6208
6590
|
}
|
|
6209
6591
|
}
|
|
6210
6592
|
console.log("");
|
|
6211
6593
|
} catch (error) {
|
|
6212
6594
|
if (error instanceof Error) {
|
|
6213
|
-
console.error(
|
|
6595
|
+
console.error(chalk17.red("\n\u2716 Archive Failed:"), error.message);
|
|
6214
6596
|
} else {
|
|
6215
|
-
console.error(
|
|
6597
|
+
console.error(chalk17.red("\n\u2716 Archive Failed:"), String(error));
|
|
6216
6598
|
}
|
|
6217
6599
|
process.exit(1);
|
|
6218
6600
|
}
|
|
@@ -6220,29 +6602,29 @@ Snapshot Contents:`));
|
|
|
6220
6602
|
}
|
|
6221
6603
|
|
|
6222
6604
|
// src/commands/task.ts
|
|
6223
|
-
import
|
|
6605
|
+
import chalk18 from "chalk";
|
|
6224
6606
|
import Table4 from "cli-table3";
|
|
6225
|
-
import
|
|
6607
|
+
import prompts9 from "prompts";
|
|
6226
6608
|
function registerTaskCommands(program2) {
|
|
6227
6609
|
const taskCmd = program2.command("task").description("Manage tasks");
|
|
6228
6610
|
const formatTaskStatusLabel = (status, deletedAt) => {
|
|
6229
|
-
if (deletedAt) return
|
|
6611
|
+
if (deletedAt) return chalk18.red("DELETED");
|
|
6230
6612
|
switch (status) {
|
|
6231
6613
|
case "ready":
|
|
6232
|
-
return
|
|
6614
|
+
return chalk18.cyan("READY");
|
|
6233
6615
|
case "in-review":
|
|
6234
|
-
return
|
|
6616
|
+
return chalk18.magenta("IN REVW");
|
|
6235
6617
|
case "in-progress":
|
|
6236
|
-
return
|
|
6618
|
+
return chalk18.blue("IN PROG");
|
|
6237
6619
|
case "blocked":
|
|
6238
|
-
return
|
|
6620
|
+
return chalk18.yellow("BLOCKED");
|
|
6239
6621
|
case "done":
|
|
6240
|
-
return
|
|
6622
|
+
return chalk18.green("DONE");
|
|
6241
6623
|
default:
|
|
6242
|
-
return
|
|
6624
|
+
return chalk18.gray("TODO");
|
|
6243
6625
|
}
|
|
6244
6626
|
};
|
|
6245
|
-
const formatTaskPriority = (priority) => priority === "high" || priority === "critical" ?
|
|
6627
|
+
const formatTaskPriority = (priority) => priority === "high" || priority === "critical" ? chalk18.red(priority) : chalk18.white(priority || "");
|
|
6246
6628
|
const ADD_TASK_BACK_VALUE = "__vem_back__";
|
|
6247
6629
|
const ADD_TASK_PRIORITIES = ["low", "medium", "high", "critical"];
|
|
6248
6630
|
const TASK_STATUS_VALUES = /* @__PURE__ */ new Set([
|
|
@@ -6626,7 +7008,7 @@ function registerTaskCommands(program2) {
|
|
|
6626
7008
|
validate
|
|
6627
7009
|
}) => {
|
|
6628
7010
|
let cancelled = false;
|
|
6629
|
-
const response = await
|
|
7011
|
+
const response = await prompts9(
|
|
6630
7012
|
{
|
|
6631
7013
|
type: "text",
|
|
6632
7014
|
name: "value",
|
|
@@ -6668,7 +7050,7 @@ function registerTaskCommands(program2) {
|
|
|
6668
7050
|
allowBack = false
|
|
6669
7051
|
}) => {
|
|
6670
7052
|
let cancelled = false;
|
|
6671
|
-
const response = await
|
|
7053
|
+
const response = await prompts9(
|
|
6672
7054
|
{
|
|
6673
7055
|
type: "select",
|
|
6674
7056
|
name: "value",
|
|
@@ -6705,7 +7087,7 @@ function registerTaskCommands(program2) {
|
|
|
6705
7087
|
const validStatuses = /* @__PURE__ */ new Set(["todo", "ready", "in-review", "in-progress", "blocked", "done"]);
|
|
6706
7088
|
if (status && !validStatuses.has(status)) {
|
|
6707
7089
|
console.error(
|
|
6708
|
-
|
|
7090
|
+
chalk18.red(
|
|
6709
7091
|
`Invalid status "${status}". Use: todo, ready, in-review, in-progress, blocked, done.`
|
|
6710
7092
|
)
|
|
6711
7093
|
);
|
|
@@ -6723,29 +7105,29 @@ function registerTaskCommands(program2) {
|
|
|
6723
7105
|
style: { head: ["cyan"] }
|
|
6724
7106
|
});
|
|
6725
7107
|
const fmtMs = (ms) => {
|
|
6726
|
-
if (!ms) return
|
|
7108
|
+
if (!ms) return chalk18.gray("-");
|
|
6727
7109
|
const days = Math.floor(ms / 864e5);
|
|
6728
7110
|
const hrs = Math.floor(ms % 864e5 / 36e5);
|
|
6729
|
-
return days > 0 ?
|
|
7111
|
+
return days > 0 ? chalk18.white(`${days}d ${hrs}h`) : chalk18.white(`${hrs}h`);
|
|
6730
7112
|
};
|
|
6731
7113
|
filtered.forEach((t) => {
|
|
6732
7114
|
if (showFlow) {
|
|
6733
7115
|
const cycleTime = t.started_at && t.status === "done" ? Date.now() - new Date(t.started_at).getTime() : void 0;
|
|
6734
7116
|
table.push([
|
|
6735
|
-
|
|
7117
|
+
chalk18.white(t.id),
|
|
6736
7118
|
formatTaskStatusLabel(t.status, t.deleted_at),
|
|
6737
7119
|
t.title,
|
|
6738
|
-
t.cycle_id ?
|
|
6739
|
-
t.impact_score !== void 0 ?
|
|
6740
|
-
|
|
7120
|
+
t.cycle_id ? chalk18.cyan(t.cycle_id) : chalk18.gray("-"),
|
|
7121
|
+
t.impact_score !== void 0 ? chalk18.yellow(String(Math.round(t.impact_score))) : chalk18.gray("-"),
|
|
7122
|
+
chalk18.gray(t.assignee || "-"),
|
|
6741
7123
|
formatTaskPriority(t.priority)
|
|
6742
7124
|
]);
|
|
6743
7125
|
} else {
|
|
6744
7126
|
table.push([
|
|
6745
|
-
|
|
7127
|
+
chalk18.white(t.id),
|
|
6746
7128
|
formatTaskStatusLabel(t.status, t.deleted_at),
|
|
6747
7129
|
t.title,
|
|
6748
|
-
|
|
7130
|
+
chalk18.gray(t.assignee || "-"),
|
|
6749
7131
|
formatTaskPriority(t.priority)
|
|
6750
7132
|
]);
|
|
6751
7133
|
}
|
|
@@ -6756,7 +7138,7 @@ function registerTaskCommands(program2) {
|
|
|
6756
7138
|
const parentId = options.parent;
|
|
6757
7139
|
const parent = await taskService.getTask(parentId);
|
|
6758
7140
|
if (!parent) {
|
|
6759
|
-
console.error(
|
|
7141
|
+
console.error(chalk18.red(`
|
|
6760
7142
|
\u2716 Task ${parentId} not found.
|
|
6761
7143
|
`));
|
|
6762
7144
|
process.exitCode = 1;
|
|
@@ -6774,16 +7156,16 @@ function registerTaskCommands(program2) {
|
|
|
6774
7156
|
style: { head: ["cyan"] }
|
|
6775
7157
|
});
|
|
6776
7158
|
parentTable.push([
|
|
6777
|
-
|
|
7159
|
+
chalk18.white(parent.id),
|
|
6778
7160
|
formatTaskStatusLabel(parent.status),
|
|
6779
7161
|
parent.title,
|
|
6780
|
-
|
|
7162
|
+
chalk18.gray(parent.assignee || "-"),
|
|
6781
7163
|
formatTaskPriority(parent.priority)
|
|
6782
7164
|
]);
|
|
6783
|
-
console.log(
|
|
7165
|
+
console.log(chalk18.bold("\nParent Task"));
|
|
6784
7166
|
console.log(parentTable.toString());
|
|
6785
7167
|
if (subtasks.length === 0) {
|
|
6786
|
-
console.log(
|
|
7168
|
+
console.log(chalk18.gray("\nNo subtasks found."));
|
|
6787
7169
|
return;
|
|
6788
7170
|
}
|
|
6789
7171
|
const subtaskTable = new Table4({
|
|
@@ -6792,15 +7174,15 @@ function registerTaskCommands(program2) {
|
|
|
6792
7174
|
});
|
|
6793
7175
|
subtasks.forEach((t) => {
|
|
6794
7176
|
subtaskTable.push([
|
|
6795
|
-
|
|
7177
|
+
chalk18.white(t.id),
|
|
6796
7178
|
formatTaskStatusLabel(t.status),
|
|
6797
7179
|
t.title,
|
|
6798
|
-
|
|
7180
|
+
chalk18.gray(t.assignee || "-"),
|
|
6799
7181
|
formatTaskPriority(t.priority),
|
|
6800
7182
|
typeof t.subtask_order === "number" ? `#${t.subtask_order}` : "-"
|
|
6801
7183
|
]);
|
|
6802
7184
|
});
|
|
6803
|
-
console.log(
|
|
7185
|
+
console.log(chalk18.bold("\nSubtasks"));
|
|
6804
7186
|
console.log(subtaskTable.toString());
|
|
6805
7187
|
});
|
|
6806
7188
|
taskCmd.command("details").description("Show task details").requiredOption("--id <id>", "Task ID").action(async (options) => {
|
|
@@ -6813,77 +7195,77 @@ function registerTaskCommands(program2) {
|
|
|
6813
7195
|
const localTask = await taskService.getTask(options.id);
|
|
6814
7196
|
const task = remoteTask ?? localTask;
|
|
6815
7197
|
if (!task) {
|
|
6816
|
-
console.error(
|
|
7198
|
+
console.error(chalk18.red(`
|
|
6817
7199
|
\u2716 Task ${options.id} not found.
|
|
6818
7200
|
`));
|
|
6819
7201
|
process.exitCode = 1;
|
|
6820
7202
|
return;
|
|
6821
7203
|
}
|
|
6822
|
-
console.log(
|
|
7204
|
+
console.log(chalk18.bold(`
|
|
6823
7205
|
\u{1F4CB} Task Details: ${task.id}
|
|
6824
7206
|
`));
|
|
6825
|
-
console.log(`${
|
|
7207
|
+
console.log(`${chalk18.cyan("Title:")} ${task.title}`);
|
|
6826
7208
|
console.log(
|
|
6827
|
-
`${
|
|
7209
|
+
`${chalk18.cyan("Status:")} ${task.status.toUpperCase()}`
|
|
6828
7210
|
);
|
|
6829
7211
|
console.log(
|
|
6830
|
-
`${
|
|
7212
|
+
`${chalk18.cyan("Priority:")} ${(task.priority || "medium").toUpperCase()}`
|
|
6831
7213
|
);
|
|
6832
7214
|
if (task.assignee) {
|
|
6833
|
-
console.log(`${
|
|
7215
|
+
console.log(`${chalk18.cyan("Assignee:")} ${task.assignee}`);
|
|
6834
7216
|
}
|
|
6835
7217
|
if (task.github_issue_number) {
|
|
6836
7218
|
console.log(
|
|
6837
|
-
`${
|
|
7219
|
+
`${chalk18.cyan("GitHub Issue:")} #${task.github_issue_number}`
|
|
6838
7220
|
);
|
|
6839
7221
|
}
|
|
6840
7222
|
if (task.tags && task.tags.length > 0) {
|
|
6841
|
-
console.log(`${
|
|
7223
|
+
console.log(`${chalk18.cyan("Tags:")} ${task.tags.join(", ")}`);
|
|
6842
7224
|
}
|
|
6843
7225
|
if (task.type) {
|
|
6844
|
-
console.log(`${
|
|
7226
|
+
console.log(`${chalk18.cyan("Type:")} ${task.type}`);
|
|
6845
7227
|
}
|
|
6846
7228
|
if (typeof task.estimate_hours === "number") {
|
|
6847
|
-
console.log(`${
|
|
7229
|
+
console.log(`${chalk18.cyan("Estimate:")} ${task.estimate_hours}h`);
|
|
6848
7230
|
}
|
|
6849
7231
|
if (task.depends_on && task.depends_on.length > 0) {
|
|
6850
7232
|
console.log(
|
|
6851
|
-
`${
|
|
7233
|
+
`${chalk18.cyan("Depends On:")} ${task.depends_on.join(", ")}`
|
|
6852
7234
|
);
|
|
6853
7235
|
}
|
|
6854
7236
|
if (task.blocked_by && task.blocked_by.length > 0) {
|
|
6855
7237
|
console.log(
|
|
6856
|
-
`${
|
|
7238
|
+
`${chalk18.cyan("Blocked By:")} ${task.blocked_by.join(", ")}`
|
|
6857
7239
|
);
|
|
6858
7240
|
}
|
|
6859
7241
|
if (task.recurrence_rule) {
|
|
6860
|
-
console.log(`${
|
|
7242
|
+
console.log(`${chalk18.cyan("Recurrence:")} ${task.recurrence_rule}`);
|
|
6861
7243
|
}
|
|
6862
7244
|
if (task.owner_id) {
|
|
6863
|
-
console.log(`${
|
|
7245
|
+
console.log(`${chalk18.cyan("Owner:")} ${task.owner_id}`);
|
|
6864
7246
|
}
|
|
6865
7247
|
if (task.reviewer_id) {
|
|
6866
|
-
console.log(`${
|
|
7248
|
+
console.log(`${chalk18.cyan("Reviewer:")} ${task.reviewer_id}`);
|
|
6867
7249
|
}
|
|
6868
7250
|
if (task.deleted_at) {
|
|
6869
|
-
console.log(`${
|
|
7251
|
+
console.log(`${chalk18.cyan("Deleted At:")} ${task.deleted_at}`);
|
|
6870
7252
|
}
|
|
6871
7253
|
if (task.parent_id) {
|
|
6872
|
-
console.log(`${
|
|
7254
|
+
console.log(`${chalk18.cyan("Parent Task:")} ${task.parent_id}`);
|
|
6873
7255
|
}
|
|
6874
7256
|
if (typeof task.subtask_order === "number") {
|
|
6875
|
-
console.log(`${
|
|
7257
|
+
console.log(`${chalk18.cyan("Subtask Order:")} #${task.subtask_order}`);
|
|
6876
7258
|
}
|
|
6877
7259
|
if (task.due_at) {
|
|
6878
|
-
console.log(`${
|
|
7260
|
+
console.log(`${chalk18.cyan("Due At:")} ${task.due_at}`);
|
|
6879
7261
|
}
|
|
6880
7262
|
const createdAt = task.created_at ?? localTask?.created_at ?? "N/A";
|
|
6881
7263
|
const updatedAt = task.updated_at ?? localTask?.updated_at ?? "N/A";
|
|
6882
|
-
console.log(`${
|
|
6883
|
-
console.log(`${
|
|
7264
|
+
console.log(`${chalk18.cyan("Created At:")} ${createdAt}`);
|
|
7265
|
+
console.log(`${chalk18.cyan("Updated At:")} ${updatedAt}`);
|
|
6884
7266
|
if (task.description) {
|
|
6885
7267
|
console.log(`
|
|
6886
|
-
${
|
|
7268
|
+
${chalk18.cyan("Description:")}
|
|
6887
7269
|
${task.description}`);
|
|
6888
7270
|
}
|
|
6889
7271
|
const remoteContext = await getRemoteTaskContext(task.id);
|
|
@@ -6892,22 +7274,22 @@ ${task.description}`);
|
|
|
6892
7274
|
const relatedDecisionSource = task.related_decisions && task.related_decisions.length > 0 ? task.related_decisions : localTask?.related_decisions ?? [];
|
|
6893
7275
|
const relatedDecisions = relatedDecisionSource.map((entry) => entry.trim()).filter(Boolean);
|
|
6894
7276
|
console.log(`
|
|
6895
|
-
${
|
|
7277
|
+
${chalk18.cyan("Context:")}`);
|
|
6896
7278
|
if (effectiveTaskContextSummary) {
|
|
6897
|
-
console.log(
|
|
7279
|
+
console.log(chalk18.gray(" Summary:"));
|
|
6898
7280
|
console.log(` ${effectiveTaskContextSummary}`);
|
|
6899
7281
|
}
|
|
6900
7282
|
if (effectiveTaskContext) {
|
|
6901
|
-
console.log(
|
|
7283
|
+
console.log(chalk18.gray(" Full context:"));
|
|
6902
7284
|
console.log(` ${effectiveTaskContext}`);
|
|
6903
7285
|
}
|
|
6904
7286
|
if (!effectiveTaskContextSummary && !effectiveTaskContext) {
|
|
6905
|
-
console.log(
|
|
7287
|
+
console.log(chalk18.gray(" No context recorded."));
|
|
6906
7288
|
}
|
|
6907
7289
|
console.log(`
|
|
6908
|
-
${
|
|
7290
|
+
${chalk18.cyan("Decisions:")}`);
|
|
6909
7291
|
if (relatedDecisions.length === 0) {
|
|
6910
|
-
console.log(
|
|
7292
|
+
console.log(chalk18.gray(" No related decisions."));
|
|
6911
7293
|
} else {
|
|
6912
7294
|
for (const decision of relatedDecisions) {
|
|
6913
7295
|
console.log(` - ${decision}`);
|
|
@@ -6915,25 +7297,25 @@ ${chalk17.cyan("Decisions:")}`);
|
|
|
6915
7297
|
}
|
|
6916
7298
|
if (task.evidence && task.evidence.length > 0) {
|
|
6917
7299
|
console.log(`
|
|
6918
|
-
${
|
|
7300
|
+
${chalk18.cyan("Evidence:")}`);
|
|
6919
7301
|
task.evidence.forEach((e) => {
|
|
6920
7302
|
console.log(` - ${e}`);
|
|
6921
7303
|
});
|
|
6922
7304
|
}
|
|
6923
7305
|
if (task.actions && task.actions.length > 0) {
|
|
6924
7306
|
console.log(`
|
|
6925
|
-
${
|
|
7307
|
+
${chalk18.cyan("Actions:")}`);
|
|
6926
7308
|
task.actions.forEach((a) => {
|
|
6927
7309
|
const type = a.type.replace(/_/g, " ").toUpperCase();
|
|
6928
7310
|
console.log(
|
|
6929
|
-
` ${
|
|
7311
|
+
` ${chalk18.gray(`[${a.created_at}]`)} ${chalk18.bold(type)}${a.reasoning ? `: ${a.reasoning}` : ""}`
|
|
6930
7312
|
);
|
|
6931
7313
|
});
|
|
6932
7314
|
}
|
|
6933
7315
|
console.log("");
|
|
6934
7316
|
} catch (error) {
|
|
6935
7317
|
console.error(
|
|
6936
|
-
|
|
7318
|
+
chalk18.red(`
|
|
6937
7319
|
\u2716 Failed to get task details: ${error.message}
|
|
6938
7320
|
`)
|
|
6939
7321
|
);
|
|
@@ -6949,7 +7331,7 @@ ${chalk17.cyan("Actions:")}`);
|
|
|
6949
7331
|
const localTask = await taskService.getTask(id);
|
|
6950
7332
|
const task = remoteTask ?? localTask;
|
|
6951
7333
|
if (!task) {
|
|
6952
|
-
console.error(
|
|
7334
|
+
console.error(chalk18.red(`Task ${id} not found.`));
|
|
6953
7335
|
return;
|
|
6954
7336
|
}
|
|
6955
7337
|
const remoteContext = await getRemoteTaskContext(id);
|
|
@@ -6958,16 +7340,16 @@ ${chalk17.cyan("Actions:")}`);
|
|
|
6958
7340
|
const currentContext = remoteContext?.task_context ?? task.task_context ?? "";
|
|
6959
7341
|
if (currentContext.trim().length > 0) {
|
|
6960
7342
|
console.log(`
|
|
6961
|
-
${
|
|
7343
|
+
${chalk18.cyan("Task Context:")}
|
|
6962
7344
|
${currentContext}`);
|
|
6963
7345
|
} else {
|
|
6964
|
-
console.log(
|
|
7346
|
+
console.log(chalk18.yellow("\nNo task context found.\n"));
|
|
6965
7347
|
}
|
|
6966
7348
|
const currentSummary = remoteContext?.task_context_summary ?? task.task_context_summary ?? "";
|
|
6967
7349
|
if (currentSummary.trim().length > 0) {
|
|
6968
7350
|
console.log(
|
|
6969
7351
|
`
|
|
6970
|
-
${
|
|
7352
|
+
${chalk18.cyan("Task Context Summary:")}
|
|
6971
7353
|
${currentSummary}
|
|
6972
7354
|
`
|
|
6973
7355
|
);
|
|
@@ -6989,7 +7371,7 @@ ${currentSummary}
|
|
|
6989
7371
|
await taskService.updateTask(id, { task_context: nextContext });
|
|
6990
7372
|
}
|
|
6991
7373
|
console.log(
|
|
6992
|
-
|
|
7374
|
+
chalk18.green(
|
|
6993
7375
|
`
|
|
6994
7376
|
\u2714 Updated context for ${id}${remoteUpdated ? " (cloud + local cache)" : " (local cache)"}
|
|
6995
7377
|
`
|
|
@@ -6997,7 +7379,7 @@ ${currentSummary}
|
|
|
6997
7379
|
);
|
|
6998
7380
|
} catch (error) {
|
|
6999
7381
|
console.error(
|
|
7000
|
-
|
|
7382
|
+
chalk18.red(`Failed to update task context: ${error.message}`)
|
|
7001
7383
|
);
|
|
7002
7384
|
}
|
|
7003
7385
|
});
|
|
@@ -7007,7 +7389,7 @@ ${currentSummary}
|
|
|
7007
7389
|
const key = await tryAuthenticatedKey(configService);
|
|
7008
7390
|
const projectId = await configService.getProjectId();
|
|
7009
7391
|
if (!assignee && key && projectId) {
|
|
7010
|
-
console.log(
|
|
7392
|
+
console.log(chalk18.blue("Fetching assignable users..."));
|
|
7011
7393
|
const res = await fetch(
|
|
7012
7394
|
`${API_URL}/projects/${projectId}/collaborators`,
|
|
7013
7395
|
{
|
|
@@ -7027,7 +7409,7 @@ ${currentSummary}
|
|
|
7027
7409
|
}))
|
|
7028
7410
|
];
|
|
7029
7411
|
if (choices.length > 0) {
|
|
7030
|
-
const response = await
|
|
7412
|
+
const response = await prompts9({
|
|
7031
7413
|
type: "select",
|
|
7032
7414
|
name: "assignee",
|
|
7033
7415
|
message: "Select assignee:",
|
|
@@ -7038,7 +7420,7 @@ ${currentSummary}
|
|
|
7038
7420
|
}
|
|
7039
7421
|
}
|
|
7040
7422
|
if (!assignee) {
|
|
7041
|
-
const response = await
|
|
7423
|
+
const response = await prompts9({
|
|
7042
7424
|
type: "text",
|
|
7043
7425
|
name: "assignee",
|
|
7044
7426
|
message: "Enter assignee (User ID or GitHub username):"
|
|
@@ -7046,20 +7428,20 @@ ${currentSummary}
|
|
|
7046
7428
|
assignee = response.assignee;
|
|
7047
7429
|
}
|
|
7048
7430
|
if (!assignee) {
|
|
7049
|
-
console.log(
|
|
7431
|
+
console.log(chalk18.yellow("No assignee provided."));
|
|
7050
7432
|
return;
|
|
7051
7433
|
}
|
|
7052
7434
|
await taskService.updateTask(id, { assignee });
|
|
7053
|
-
console.log(
|
|
7435
|
+
console.log(chalk18.green(`
|
|
7054
7436
|
\u2714 Task ${id} assigned to ${assignee}
|
|
7055
7437
|
`));
|
|
7056
7438
|
if (key && projectId) {
|
|
7057
7439
|
console.log(
|
|
7058
|
-
|
|
7440
|
+
chalk18.gray("Tip: Run `vem push` to sync assignment to cloud.")
|
|
7059
7441
|
);
|
|
7060
7442
|
}
|
|
7061
7443
|
} catch (error) {
|
|
7062
|
-
console.error(
|
|
7444
|
+
console.error(chalk18.red(`Failed to assign task: ${error.message}`));
|
|
7063
7445
|
}
|
|
7064
7446
|
});
|
|
7065
7447
|
taskCmd.command("add [title]").description("Create a new task (interactive when title is omitted)").option(
|
|
@@ -7095,9 +7477,9 @@ ${currentSummary}
|
|
|
7095
7477
|
if (!process.stdin.isTTY) {
|
|
7096
7478
|
throw new Error("Title is required in non-interactive mode.");
|
|
7097
7479
|
}
|
|
7098
|
-
console.log(
|
|
7480
|
+
console.log(chalk18.cyan("\nTask creation wizard"));
|
|
7099
7481
|
console.log(
|
|
7100
|
-
|
|
7482
|
+
chalk18.gray(
|
|
7101
7483
|
"Fill required fields first, then optional fields. Type :back to go back."
|
|
7102
7484
|
)
|
|
7103
7485
|
);
|
|
@@ -7111,7 +7493,7 @@ ${currentSummary}
|
|
|
7111
7493
|
optional: false
|
|
7112
7494
|
});
|
|
7113
7495
|
if (prompt.kind === "cancel") {
|
|
7114
|
-
console.log(
|
|
7496
|
+
console.log(chalk18.yellow("Task creation cancelled."));
|
|
7115
7497
|
return;
|
|
7116
7498
|
}
|
|
7117
7499
|
if (prompt.kind === "next") {
|
|
@@ -7130,7 +7512,7 @@ ${currentSummary}
|
|
|
7130
7512
|
allowBack: true
|
|
7131
7513
|
});
|
|
7132
7514
|
if (priorityPrompt.kind === "cancel") {
|
|
7133
|
-
console.log(
|
|
7515
|
+
console.log(chalk18.yellow("Task creation cancelled."));
|
|
7134
7516
|
return;
|
|
7135
7517
|
}
|
|
7136
7518
|
if (priorityPrompt.kind === "back") {
|
|
@@ -7156,7 +7538,7 @@ ${currentSummary}
|
|
|
7156
7538
|
}
|
|
7157
7539
|
);
|
|
7158
7540
|
if (optionalMode.kind === "cancel") {
|
|
7159
|
-
console.log(
|
|
7541
|
+
console.log(chalk18.yellow("Task creation cancelled."));
|
|
7160
7542
|
return;
|
|
7161
7543
|
}
|
|
7162
7544
|
if (optionalMode.kind === "back") {
|
|
@@ -7170,7 +7552,7 @@ ${currentSummary}
|
|
|
7170
7552
|
allowBack: true
|
|
7171
7553
|
});
|
|
7172
7554
|
if (priorityPrompt.kind === "cancel") {
|
|
7173
|
-
console.log(
|
|
7555
|
+
console.log(chalk18.yellow("Task creation cancelled."));
|
|
7174
7556
|
return;
|
|
7175
7557
|
}
|
|
7176
7558
|
if (priorityPrompt.kind === "back") {
|
|
@@ -7180,7 +7562,7 @@ ${currentSummary}
|
|
|
7180
7562
|
optional: false
|
|
7181
7563
|
});
|
|
7182
7564
|
if (titlePrompt.kind !== "next") {
|
|
7183
|
-
console.log(
|
|
7565
|
+
console.log(chalk18.yellow("Task creation cancelled."));
|
|
7184
7566
|
return;
|
|
7185
7567
|
}
|
|
7186
7568
|
taskTitle = titlePrompt.value;
|
|
@@ -7194,7 +7576,7 @@ ${currentSummary}
|
|
|
7194
7576
|
allowBack: false
|
|
7195
7577
|
});
|
|
7196
7578
|
if (retryPriorityPrompt.kind !== "next") {
|
|
7197
|
-
console.log(
|
|
7579
|
+
console.log(chalk18.yellow("Task creation cancelled."));
|
|
7198
7580
|
return;
|
|
7199
7581
|
}
|
|
7200
7582
|
priorityInput = retryPriorityPrompt.value;
|
|
@@ -7340,7 +7722,7 @@ ${currentSummary}
|
|
|
7340
7722
|
validate: field.validate
|
|
7341
7723
|
});
|
|
7342
7724
|
if (prompt.kind === "cancel") {
|
|
7343
|
-
console.log(
|
|
7725
|
+
console.log(chalk18.yellow("Task creation cancelled."));
|
|
7344
7726
|
return;
|
|
7345
7727
|
}
|
|
7346
7728
|
if (prompt.kind === "back") {
|
|
@@ -7358,7 +7740,7 @@ ${currentSummary}
|
|
|
7358
7740
|
allowBack: true
|
|
7359
7741
|
});
|
|
7360
7742
|
if (gatePrompt.kind === "cancel") {
|
|
7361
|
-
console.log(
|
|
7743
|
+
console.log(chalk18.yellow("Task creation cancelled."));
|
|
7362
7744
|
return;
|
|
7363
7745
|
}
|
|
7364
7746
|
if (gatePrompt.kind === "next" && gatePrompt.value === "skip") {
|
|
@@ -7375,7 +7757,7 @@ ${currentSummary}
|
|
|
7375
7757
|
allowBack: true
|
|
7376
7758
|
});
|
|
7377
7759
|
if (priorityPrompt.kind === "cancel") {
|
|
7378
|
-
console.log(
|
|
7760
|
+
console.log(chalk18.yellow("Task creation cancelled."));
|
|
7379
7761
|
return;
|
|
7380
7762
|
}
|
|
7381
7763
|
if (priorityPrompt.kind === "back") {
|
|
@@ -7385,7 +7767,7 @@ ${currentSummary}
|
|
|
7385
7767
|
optional: false
|
|
7386
7768
|
});
|
|
7387
7769
|
if (titlePrompt.kind !== "next") {
|
|
7388
|
-
console.log(
|
|
7770
|
+
console.log(chalk18.yellow("Task creation cancelled."));
|
|
7389
7771
|
return;
|
|
7390
7772
|
}
|
|
7391
7773
|
taskTitle = titlePrompt.value;
|
|
@@ -7420,14 +7802,14 @@ ${currentSummary}
|
|
|
7420
7802
|
const taskType = normalizedType === "feature" || normalizedType === "bug" || normalizedType === "chore" || normalizedType === "spike" || normalizedType === "enabler" ? normalizedType : void 0;
|
|
7421
7803
|
let validationSteps = parseCommaList(validationInput);
|
|
7422
7804
|
if (validationSteps === void 0 && process.stdin.isTTY && !validationInput && !runWizard) {
|
|
7423
|
-
const wantsValidation = await
|
|
7805
|
+
const wantsValidation = await prompts9({
|
|
7424
7806
|
type: "confirm",
|
|
7425
7807
|
name: "add",
|
|
7426
7808
|
message: "Add validation steps for this task?",
|
|
7427
7809
|
initial: false
|
|
7428
7810
|
});
|
|
7429
7811
|
if (wantsValidation.add) {
|
|
7430
|
-
const response = await
|
|
7812
|
+
const response = await prompts9({
|
|
7431
7813
|
type: "text",
|
|
7432
7814
|
name: "steps",
|
|
7433
7815
|
message: 'Enter validation steps (comma-separated, e.g. "pnpm build, pnpm test"):'
|
|
@@ -7489,14 +7871,14 @@ ${currentSummary}
|
|
|
7489
7871
|
);
|
|
7490
7872
|
}
|
|
7491
7873
|
console.log(
|
|
7492
|
-
|
|
7874
|
+
chalk18.green(
|
|
7493
7875
|
`
|
|
7494
7876
|
\u2714 Task created: ${remoteTask.id} (cloud + local cache)
|
|
7495
7877
|
`
|
|
7496
7878
|
)
|
|
7497
7879
|
);
|
|
7498
7880
|
console.log(
|
|
7499
|
-
|
|
7881
|
+
chalk18.gray(
|
|
7500
7882
|
`Tip: Start working with AI context via \`vem agent --task ${remoteTask.id}\``
|
|
7501
7883
|
)
|
|
7502
7884
|
);
|
|
@@ -7526,17 +7908,17 @@ ${currentSummary}
|
|
|
7526
7908
|
}
|
|
7527
7909
|
);
|
|
7528
7910
|
console.log(
|
|
7529
|
-
|
|
7911
|
+
chalk18.green(`
|
|
7530
7912
|
\u2714 Task created: ${task.id} (local cache)
|
|
7531
7913
|
`)
|
|
7532
7914
|
);
|
|
7533
7915
|
console.log(
|
|
7534
|
-
|
|
7916
|
+
chalk18.gray(
|
|
7535
7917
|
`Tip: Start working with AI context via \`vem agent --task ${task.id}\``
|
|
7536
7918
|
)
|
|
7537
7919
|
);
|
|
7538
7920
|
} catch (error) {
|
|
7539
|
-
console.error(
|
|
7921
|
+
console.error(chalk18.red(`Failed to create task: ${error.message}`));
|
|
7540
7922
|
}
|
|
7541
7923
|
});
|
|
7542
7924
|
taskCmd.command("update <id>").description("Update task metadata").option("--tags <tags>", "Comma-separated tags").option("--type <type>", "Task type (feature, bug, chore, spike, enabler)").option("--estimate-hours <hours>", "Estimated hours (e.g. 2.5)").option("--depends-on <ids>", "Comma-separated task IDs").option("--blocked-by <ids>", "Comma-separated task IDs").option("--recurrence <rule>", "Recurrence rule (weekly, monthly, cron)").option("--owner <id>", "Owner ID").option("--reviewer <id>", "Reviewer ID").option("--parent <id>", "Parent task ID").option("--order <number>", "Subtask order").option("--due-at <iso>", "Due date ISO string (YYYY-MM-DD)").option(
|
|
@@ -7596,7 +7978,7 @@ ${currentSummary}
|
|
|
7596
7978
|
}
|
|
7597
7979
|
if (remoteUpdated) {
|
|
7598
7980
|
console.log(
|
|
7599
|
-
|
|
7981
|
+
chalk18.green(
|
|
7600
7982
|
`
|
|
7601
7983
|
\u2714 Task ${id} updated${localTask ? " (cloud + local cache)" : " (cloud)"}
|
|
7602
7984
|
`
|
|
@@ -7609,11 +7991,11 @@ ${currentSummary}
|
|
|
7609
7991
|
`Task ${id} not found in cloud or local cache. Verify the ID and project link.`
|
|
7610
7992
|
);
|
|
7611
7993
|
}
|
|
7612
|
-
console.log(
|
|
7994
|
+
console.log(chalk18.green(`
|
|
7613
7995
|
\u2714 Task ${id} updated (local cache)
|
|
7614
7996
|
`));
|
|
7615
7997
|
} catch (error) {
|
|
7616
|
-
console.error(
|
|
7998
|
+
console.error(chalk18.red(`Failed to update task: ${error.message}`));
|
|
7617
7999
|
}
|
|
7618
8000
|
});
|
|
7619
8001
|
taskCmd.command("done [id]").description("Mark a task as complete").option(
|
|
@@ -7635,13 +8017,13 @@ ${currentSummary}
|
|
|
7635
8017
|
);
|
|
7636
8018
|
if (inProgress.length === 0) {
|
|
7637
8019
|
console.error(
|
|
7638
|
-
|
|
8020
|
+
chalk18.yellow(
|
|
7639
8021
|
"No tasks in progress. Provide an ID explicitly or start a task first."
|
|
7640
8022
|
)
|
|
7641
8023
|
);
|
|
7642
8024
|
return;
|
|
7643
8025
|
}
|
|
7644
|
-
const response = await
|
|
8026
|
+
const response = await prompts9({
|
|
7645
8027
|
type: "select",
|
|
7646
8028
|
name: "id",
|
|
7647
8029
|
message: "Select a task to complete:",
|
|
@@ -7651,7 +8033,7 @@ ${currentSummary}
|
|
|
7651
8033
|
}))
|
|
7652
8034
|
});
|
|
7653
8035
|
if (!response.id) {
|
|
7654
|
-
console.log(
|
|
8036
|
+
console.log(chalk18.yellow("Operation cancelled."));
|
|
7655
8037
|
return;
|
|
7656
8038
|
}
|
|
7657
8039
|
id = response.id;
|
|
@@ -7663,14 +8045,14 @@ ${currentSummary}
|
|
|
7663
8045
|
const localTask = await taskService.getTask(id);
|
|
7664
8046
|
const task = remoteTask ?? localTask;
|
|
7665
8047
|
if (!task) {
|
|
7666
|
-
console.error(
|
|
8048
|
+
console.error(chalk18.red(`Task ${id} not found.`));
|
|
7667
8049
|
return;
|
|
7668
8050
|
}
|
|
7669
8051
|
const evidence = parseCommaList(options.evidence) ?? [];
|
|
7670
8052
|
const actorName = resolveActorName(options.actor);
|
|
7671
8053
|
let contextSummary = options.contextSummary;
|
|
7672
8054
|
if (!contextSummary && task.task_context && process.stdin.isTTY) {
|
|
7673
|
-
const summary = await
|
|
8055
|
+
const summary = await prompts9({
|
|
7674
8056
|
type: "text",
|
|
7675
8057
|
name: "text",
|
|
7676
8058
|
message: "Task has context. Provide a brief summary to keep after completion (optional):"
|
|
@@ -7690,7 +8072,7 @@ ${currentSummary}
|
|
|
7690
8072
|
}
|
|
7691
8073
|
const confirmed = [];
|
|
7692
8074
|
for (const step of requiredValidation) {
|
|
7693
|
-
const response = await
|
|
8075
|
+
const response = await prompts9({
|
|
7694
8076
|
type: "confirm",
|
|
7695
8077
|
name: "done",
|
|
7696
8078
|
message: `Validation step completed? ${step}`,
|
|
@@ -7698,7 +8080,7 @@ ${currentSummary}
|
|
|
7698
8080
|
});
|
|
7699
8081
|
if (!response.done) {
|
|
7700
8082
|
console.log(
|
|
7701
|
-
|
|
8083
|
+
chalk18.yellow(
|
|
7702
8084
|
"Task completion cancelled. Complete all validation steps first."
|
|
7703
8085
|
)
|
|
7704
8086
|
);
|
|
@@ -7745,7 +8127,7 @@ ${currentSummary}
|
|
|
7745
8127
|
}
|
|
7746
8128
|
if (remoteUpdated || remoteContextUpdated) {
|
|
7747
8129
|
console.log(
|
|
7748
|
-
|
|
8130
|
+
chalk18.green(
|
|
7749
8131
|
`
|
|
7750
8132
|
\u2714 Task ${id} marked as DONE${localTask ? " (cloud + local cache)" : " (cloud)"}
|
|
7751
8133
|
`
|
|
@@ -7759,12 +8141,12 @@ ${currentSummary}
|
|
|
7759
8141
|
);
|
|
7760
8142
|
}
|
|
7761
8143
|
console.log(
|
|
7762
|
-
|
|
8144
|
+
chalk18.green(`
|
|
7763
8145
|
\u2714 Task ${id} marked as DONE (local cache)
|
|
7764
8146
|
`)
|
|
7765
8147
|
);
|
|
7766
8148
|
} catch (error) {
|
|
7767
|
-
console.error(
|
|
8149
|
+
console.error(chalk18.red(`Failed to complete task: ${error.message}`));
|
|
7768
8150
|
}
|
|
7769
8151
|
});
|
|
7770
8152
|
taskCmd.command("start [id]").description("Start working on a task (set status to in-progress)").option("-r, --reasoning <reasoning>", "Reasoning for starting the task").option("--actor <name>", "Actor name").action(async (id, options) => {
|
|
@@ -7776,10 +8158,10 @@ ${currentSummary}
|
|
|
7776
8158
|
(t) => t.status === "todo" && !t.deleted_at
|
|
7777
8159
|
);
|
|
7778
8160
|
if (todoTasks.length === 0) {
|
|
7779
|
-
console.error(
|
|
8161
|
+
console.error(chalk18.yellow("No tasks in TODO status to start."));
|
|
7780
8162
|
return;
|
|
7781
8163
|
}
|
|
7782
|
-
const response = await
|
|
8164
|
+
const response = await prompts9({
|
|
7783
8165
|
type: "select",
|
|
7784
8166
|
name: "id",
|
|
7785
8167
|
message: "Select a task to start:",
|
|
@@ -7789,7 +8171,7 @@ ${currentSummary}
|
|
|
7789
8171
|
}))
|
|
7790
8172
|
});
|
|
7791
8173
|
if (!response.id) {
|
|
7792
|
-
console.log(
|
|
8174
|
+
console.log(chalk18.yellow("Operation cancelled."));
|
|
7793
8175
|
return;
|
|
7794
8176
|
}
|
|
7795
8177
|
id = response.id;
|
|
@@ -7801,15 +8183,15 @@ ${currentSummary}
|
|
|
7801
8183
|
const localTask = await taskService.getTask(id);
|
|
7802
8184
|
const task = remoteTask ?? localTask;
|
|
7803
8185
|
if (!task) {
|
|
7804
|
-
console.error(
|
|
8186
|
+
console.error(chalk18.red(`Task ${id} not found.`));
|
|
7805
8187
|
return;
|
|
7806
8188
|
}
|
|
7807
8189
|
if (task.status === "in-progress") {
|
|
7808
|
-
console.log(
|
|
8190
|
+
console.log(chalk18.yellow(`Task ${id} is already in progress.`));
|
|
7809
8191
|
return;
|
|
7810
8192
|
}
|
|
7811
8193
|
if (task.status === "done") {
|
|
7812
|
-
console.error(
|
|
8194
|
+
console.error(chalk18.red(`Task ${id} is already completed.`));
|
|
7813
8195
|
return;
|
|
7814
8196
|
}
|
|
7815
8197
|
const reasoning = options.reasoning || "Started working on task";
|
|
@@ -7867,7 +8249,7 @@ ${currentSummary}
|
|
|
7867
8249
|
}
|
|
7868
8250
|
if (remoteUpdated) {
|
|
7869
8251
|
console.log(
|
|
7870
|
-
|
|
8252
|
+
chalk18.green(
|
|
7871
8253
|
`
|
|
7872
8254
|
\u2714 Task ${id} is now IN PROGRESS${localTask ? " (cloud + local cache)" : " (cloud)"}
|
|
7873
8255
|
`
|
|
@@ -7881,12 +8263,12 @@ ${currentSummary}
|
|
|
7881
8263
|
);
|
|
7882
8264
|
}
|
|
7883
8265
|
console.log(
|
|
7884
|
-
|
|
8266
|
+
chalk18.green(`
|
|
7885
8267
|
\u2714 Task ${id} is now IN PROGRESS (local cache)
|
|
7886
8268
|
`)
|
|
7887
8269
|
);
|
|
7888
8270
|
} catch (error) {
|
|
7889
|
-
console.error(
|
|
8271
|
+
console.error(chalk18.red(`Failed to start task: ${error.message}`));
|
|
7890
8272
|
}
|
|
7891
8273
|
});
|
|
7892
8274
|
taskCmd.command("block <id>").description("Mark a task as blocked").option("-r, --reasoning <reasoning>", "Reason for blocking (required)").option("--blocked-by <ids>", "Comma-separated task IDs blocking this task").option("--actor <name>", "Actor name").action(async (id, options) => {
|
|
@@ -7898,16 +8280,16 @@ ${currentSummary}
|
|
|
7898
8280
|
const localTask = await taskService.getTask(id);
|
|
7899
8281
|
const task = remoteTask ?? localTask;
|
|
7900
8282
|
if (!task) {
|
|
7901
|
-
console.error(
|
|
8283
|
+
console.error(chalk18.red(`Task ${id} not found.`));
|
|
7902
8284
|
return;
|
|
7903
8285
|
}
|
|
7904
8286
|
if (task.status === "done") {
|
|
7905
|
-
console.error(
|
|
8287
|
+
console.error(chalk18.red(`Cannot block a completed task.`));
|
|
7906
8288
|
return;
|
|
7907
8289
|
}
|
|
7908
8290
|
if (!options.reasoning) {
|
|
7909
8291
|
console.error(
|
|
7910
|
-
|
|
8292
|
+
chalk18.red(
|
|
7911
8293
|
"Reasoning is required when blocking a task. Use -r or --reasoning."
|
|
7912
8294
|
)
|
|
7913
8295
|
);
|
|
@@ -7931,7 +8313,7 @@ ${currentSummary}
|
|
|
7931
8313
|
}
|
|
7932
8314
|
if (remoteUpdated) {
|
|
7933
8315
|
console.log(
|
|
7934
|
-
|
|
8316
|
+
chalk18.yellow(
|
|
7935
8317
|
`
|
|
7936
8318
|
\u26A0 Task ${id} is now BLOCKED${localTask ? " (cloud + local cache)" : " (cloud)"}
|
|
7937
8319
|
`
|
|
@@ -7945,12 +8327,12 @@ ${currentSummary}
|
|
|
7945
8327
|
);
|
|
7946
8328
|
}
|
|
7947
8329
|
console.log(
|
|
7948
|
-
|
|
8330
|
+
chalk18.yellow(`
|
|
7949
8331
|
\u26A0 Task ${id} is now BLOCKED (local cache)
|
|
7950
8332
|
`)
|
|
7951
8333
|
);
|
|
7952
8334
|
} catch (error) {
|
|
7953
|
-
console.error(
|
|
8335
|
+
console.error(chalk18.red(`Failed to block task: ${error.message}`));
|
|
7954
8336
|
}
|
|
7955
8337
|
});
|
|
7956
8338
|
taskCmd.command("unblock <id>").description("Unblock a task (set status back to todo)").option("-r, --reasoning <reasoning>", "Reason for unblocking").option("--actor <name>", "Actor name").action(async (id, options) => {
|
|
@@ -7962,12 +8344,12 @@ ${currentSummary}
|
|
|
7962
8344
|
const localTask = await taskService.getTask(id);
|
|
7963
8345
|
const task = remoteTask ?? localTask;
|
|
7964
8346
|
if (!task) {
|
|
7965
|
-
console.error(
|
|
8347
|
+
console.error(chalk18.red(`Task ${id} not found.`));
|
|
7966
8348
|
return;
|
|
7967
8349
|
}
|
|
7968
8350
|
if (task.status !== "blocked") {
|
|
7969
8351
|
console.log(
|
|
7970
|
-
|
|
8352
|
+
chalk18.yellow(`Task ${id} is not blocked (status: ${task.status}).`)
|
|
7971
8353
|
);
|
|
7972
8354
|
return;
|
|
7973
8355
|
}
|
|
@@ -7989,7 +8371,7 @@ ${currentSummary}
|
|
|
7989
8371
|
}
|
|
7990
8372
|
if (remoteUpdated) {
|
|
7991
8373
|
console.log(
|
|
7992
|
-
|
|
8374
|
+
chalk18.green(
|
|
7993
8375
|
`
|
|
7994
8376
|
\u2714 Task ${id} is now unblocked (TODO)${localTask ? " (cloud + local cache)" : " (cloud)"}
|
|
7995
8377
|
`
|
|
@@ -8003,12 +8385,12 @@ ${currentSummary}
|
|
|
8003
8385
|
);
|
|
8004
8386
|
}
|
|
8005
8387
|
console.log(
|
|
8006
|
-
|
|
8388
|
+
chalk18.green(`
|
|
8007
8389
|
\u2714 Task ${id} is now unblocked (TODO) (local cache)
|
|
8008
8390
|
`)
|
|
8009
8391
|
);
|
|
8010
8392
|
} catch (error) {
|
|
8011
|
-
console.error(
|
|
8393
|
+
console.error(chalk18.red(`Failed to unblock task: ${error.message}`));
|
|
8012
8394
|
}
|
|
8013
8395
|
});
|
|
8014
8396
|
taskCmd.command("delete <id>").description("Soft delete a task").option("-r, --reasoning <reasoning>", "Reasoning for deletion").action(async (id, options) => {
|
|
@@ -8020,7 +8402,7 @@ ${currentSummary}
|
|
|
8020
8402
|
const localTask = await taskService.getTask(id);
|
|
8021
8403
|
const task = remoteTask ?? localTask;
|
|
8022
8404
|
if (!task) {
|
|
8023
|
-
console.error(
|
|
8405
|
+
console.error(chalk18.red(`Task ${id} not found.`));
|
|
8024
8406
|
return;
|
|
8025
8407
|
}
|
|
8026
8408
|
const deletedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -8036,7 +8418,7 @@ ${currentSummary}
|
|
|
8036
8418
|
}
|
|
8037
8419
|
if (remoteUpdated) {
|
|
8038
8420
|
console.log(
|
|
8039
|
-
|
|
8421
|
+
chalk18.green(
|
|
8040
8422
|
`
|
|
8041
8423
|
\u2714 Task ${id} soft deleted${localTask ? " (cloud + local cache)" : " (cloud)"}
|
|
8042
8424
|
`
|
|
@@ -8049,11 +8431,11 @@ ${currentSummary}
|
|
|
8049
8431
|
`Task ${id} not found in cloud or local cache. Verify the ID and project link.`
|
|
8050
8432
|
);
|
|
8051
8433
|
}
|
|
8052
|
-
console.log(
|
|
8434
|
+
console.log(chalk18.green(`
|
|
8053
8435
|
\u2714 Task ${id} soft deleted (local cache)
|
|
8054
8436
|
`));
|
|
8055
8437
|
} catch (error) {
|
|
8056
|
-
console.error(
|
|
8438
|
+
console.error(chalk18.red(`Failed to delete task: ${error.message}`));
|
|
8057
8439
|
}
|
|
8058
8440
|
});
|
|
8059
8441
|
program2.command("delete <id>").description("Soft delete a task").option("-r, --reasoning <reasoning>", "Reasoning for deletion").action(async (id, options) => {
|
|
@@ -8065,7 +8447,7 @@ ${currentSummary}
|
|
|
8065
8447
|
const localTask = await taskService.getTask(id);
|
|
8066
8448
|
const task = remoteTask ?? localTask;
|
|
8067
8449
|
if (!task) {
|
|
8068
|
-
console.error(
|
|
8450
|
+
console.error(chalk18.red(`Task ${id} not found.`));
|
|
8069
8451
|
return;
|
|
8070
8452
|
}
|
|
8071
8453
|
const deletedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -8081,7 +8463,7 @@ ${currentSummary}
|
|
|
8081
8463
|
}
|
|
8082
8464
|
if (remoteUpdated) {
|
|
8083
8465
|
console.log(
|
|
8084
|
-
|
|
8466
|
+
chalk18.green(
|
|
8085
8467
|
`
|
|
8086
8468
|
\u2714 Task ${id} soft deleted${localTask ? " (cloud + local cache)" : " (cloud)"}
|
|
8087
8469
|
`
|
|
@@ -8094,11 +8476,11 @@ ${currentSummary}
|
|
|
8094
8476
|
`Task ${id} not found in cloud or local cache. Verify the ID and project link.`
|
|
8095
8477
|
);
|
|
8096
8478
|
}
|
|
8097
|
-
console.log(
|
|
8479
|
+
console.log(chalk18.green(`
|
|
8098
8480
|
\u2714 Task ${id} soft deleted (local cache)
|
|
8099
8481
|
`));
|
|
8100
8482
|
} catch (error) {
|
|
8101
|
-
console.error(
|
|
8483
|
+
console.error(chalk18.red(`Failed to delete task: ${error.message}`));
|
|
8102
8484
|
}
|
|
8103
8485
|
});
|
|
8104
8486
|
taskCmd.command("sessions <id>").description("Show all agent sessions attached to a task").action(async (id) => {
|
|
@@ -8106,17 +8488,17 @@ ${currentSummary}
|
|
|
8106
8488
|
try {
|
|
8107
8489
|
const task = await taskService.getTask(id);
|
|
8108
8490
|
if (!task) {
|
|
8109
|
-
console.error(
|
|
8491
|
+
console.error(chalk18.red(`Task ${id} not found.`));
|
|
8110
8492
|
return;
|
|
8111
8493
|
}
|
|
8112
8494
|
const sessions = task.sessions || [];
|
|
8113
8495
|
if (sessions.length === 0) {
|
|
8114
8496
|
console.log(
|
|
8115
|
-
|
|
8497
|
+
chalk18.yellow(`
|
|
8116
8498
|
No agent sessions attached to ${id} yet.`)
|
|
8117
8499
|
);
|
|
8118
8500
|
console.log(
|
|
8119
|
-
|
|
8501
|
+
chalk18.gray(
|
|
8120
8502
|
` Run "vem task start ${id}" to attach the current session.
|
|
8121
8503
|
`
|
|
8122
8504
|
)
|
|
@@ -8124,23 +8506,23 @@ No agent sessions attached to ${id} yet.`)
|
|
|
8124
8506
|
return;
|
|
8125
8507
|
}
|
|
8126
8508
|
console.log(
|
|
8127
|
-
|
|
8509
|
+
chalk18.bold(`
|
|
8128
8510
|
\u{1F517} Sessions attached to ${id}: ${task.title}
|
|
8129
8511
|
`)
|
|
8130
8512
|
);
|
|
8131
8513
|
const table = new Table4({
|
|
8132
8514
|
head: ["Source", "Session ID", "Started", "Summary"].map(
|
|
8133
|
-
(h) =>
|
|
8515
|
+
(h) => chalk18.white.bold(h)
|
|
8134
8516
|
),
|
|
8135
8517
|
colWidths: [10, 20, 18, 50],
|
|
8136
8518
|
style: { border: ["gray"] }
|
|
8137
8519
|
});
|
|
8138
8520
|
for (const s of sessions) {
|
|
8139
|
-
const sourceColor = s.source === "copilot" ?
|
|
8521
|
+
const sourceColor = s.source === "copilot" ? chalk18.blue : s.source === "claude" ? chalk18.magenta : chalk18.green;
|
|
8140
8522
|
table.push([
|
|
8141
8523
|
sourceColor(s.source),
|
|
8142
|
-
|
|
8143
|
-
|
|
8524
|
+
chalk18.gray(`${s.id.slice(0, 16)}\u2026`),
|
|
8525
|
+
chalk18.white(
|
|
8144
8526
|
new Date(s.started_at).toLocaleDateString(void 0, {
|
|
8145
8527
|
month: "short",
|
|
8146
8528
|
day: "numeric",
|
|
@@ -8148,14 +8530,14 @@ No agent sessions attached to ${id} yet.`)
|
|
|
8148
8530
|
minute: "2-digit"
|
|
8149
8531
|
})
|
|
8150
8532
|
),
|
|
8151
|
-
|
|
8533
|
+
chalk18.gray(s.summary?.slice(0, 48) || "\u2014")
|
|
8152
8534
|
]);
|
|
8153
8535
|
}
|
|
8154
8536
|
console.log(table.toString());
|
|
8155
8537
|
console.log();
|
|
8156
8538
|
} catch (error) {
|
|
8157
8539
|
console.error(
|
|
8158
|
-
|
|
8540
|
+
chalk18.red(`Failed to show task sessions: ${error.message}`)
|
|
8159
8541
|
);
|
|
8160
8542
|
}
|
|
8161
8543
|
});
|
|
@@ -8167,50 +8549,50 @@ No agent sessions attached to ${id} yet.`)
|
|
|
8167
8549
|
if (id) {
|
|
8168
8550
|
const task = await taskService.getTask(id);
|
|
8169
8551
|
if (!task) {
|
|
8170
|
-
console.error(
|
|
8552
|
+
console.error(chalk18.red(`Task ${id} not found.`));
|
|
8171
8553
|
return;
|
|
8172
8554
|
}
|
|
8173
8555
|
const metrics = await taskService.getFlowMetrics(id);
|
|
8174
8556
|
const fmtMs = (ms) => {
|
|
8175
|
-
if (!ms) return
|
|
8557
|
+
if (!ms) return chalk18.gray("\u2014");
|
|
8176
8558
|
const days = Math.floor(ms / 864e5);
|
|
8177
8559
|
const hrs = Math.floor(ms % 864e5 / 36e5);
|
|
8178
8560
|
const mins = Math.floor(ms % 36e5 / 6e4);
|
|
8179
|
-
if (days > 0) return
|
|
8180
|
-
if (hrs > 0) return
|
|
8181
|
-
return
|
|
8561
|
+
if (days > 0) return chalk18.white(`${days}d ${hrs}h`);
|
|
8562
|
+
if (hrs > 0) return chalk18.white(`${hrs}h ${mins}m`);
|
|
8563
|
+
return chalk18.white(`${mins}m`);
|
|
8182
8564
|
};
|
|
8183
|
-
console.log(
|
|
8565
|
+
console.log(chalk18.bold(`
|
|
8184
8566
|
\u23F1 Flow Metrics: ${id} \u2014 ${task.title}
|
|
8185
8567
|
`));
|
|
8186
|
-
console.log(` ${
|
|
8187
|
-
console.log(` ${
|
|
8568
|
+
console.log(` ${chalk18.gray("Lead time (created \u2192 done):")} ${fmtMs(metrics.lead_time_ms)}`);
|
|
8569
|
+
console.log(` ${chalk18.gray("Cycle time (started \u2192 done):")} ${fmtMs(metrics.cycle_time_ms)}`);
|
|
8188
8570
|
if (Object.keys(metrics.time_in_status).length > 0) {
|
|
8189
|
-
console.log(
|
|
8571
|
+
console.log(chalk18.gray("\n Time in each status:"));
|
|
8190
8572
|
for (const [status, ms] of Object.entries(metrics.time_in_status)) {
|
|
8191
|
-
console.log(` ${
|
|
8573
|
+
console.log(` ${chalk18.cyan(status.padEnd(12))} ${fmtMs(ms)}`);
|
|
8192
8574
|
}
|
|
8193
8575
|
}
|
|
8194
8576
|
console.log();
|
|
8195
8577
|
} else {
|
|
8196
8578
|
const summary = await taskService.getProjectFlowSummary();
|
|
8197
8579
|
const fmtMs = (ms) => {
|
|
8198
|
-
if (!ms) return
|
|
8580
|
+
if (!ms) return chalk18.gray("\u2014");
|
|
8199
8581
|
const days = Math.floor(ms / 864e5);
|
|
8200
8582
|
const hrs = Math.floor(ms % 864e5 / 36e5);
|
|
8201
|
-
if (days > 0) return
|
|
8202
|
-
return
|
|
8583
|
+
if (days > 0) return chalk18.white(`${days}d ${hrs}h`);
|
|
8584
|
+
return chalk18.white(`${hrs}h`);
|
|
8203
8585
|
};
|
|
8204
|
-
console.log(
|
|
8205
|
-
console.log(` ${
|
|
8206
|
-
console.log(` ${
|
|
8207
|
-
console.log(` ${
|
|
8208
|
-
console.log(` ${
|
|
8209
|
-
console.log(` ${
|
|
8586
|
+
console.log(chalk18.bold("\n\u{1F4CA} Project Flow Summary\n"));
|
|
8587
|
+
console.log(` ${chalk18.gray("WIP (active tasks):")} ${chalk18.yellow(String(summary.wip_count))}`);
|
|
8588
|
+
console.log(` ${chalk18.gray("Throughput (last 7d):")} ${chalk18.white(String(summary.throughput_last_7d))} tasks`);
|
|
8589
|
+
console.log(` ${chalk18.gray("Throughput (last 30d):")} ${chalk18.white(String(summary.throughput_last_30d))} tasks`);
|
|
8590
|
+
console.log(` ${chalk18.gray("Avg cycle time:")} ${fmtMs(summary.avg_cycle_time_ms)}`);
|
|
8591
|
+
console.log(` ${chalk18.gray("Avg lead time:")} ${fmtMs(summary.avg_lead_time_ms)}`);
|
|
8210
8592
|
console.log();
|
|
8211
8593
|
}
|
|
8212
8594
|
} catch (error) {
|
|
8213
|
-
console.error(
|
|
8595
|
+
console.error(chalk18.red(`Failed to get flow metrics: ${error.message}`));
|
|
8214
8596
|
}
|
|
8215
8597
|
});
|
|
8216
8598
|
taskCmd.command("score [id]").description("Show or set the impact score (0-100) for a task").option("--set <score>", "Set impact score manually (0-100)").option("-r, --reasoning <reasoning>", "Reasoning for score change").action(async (id, options) => {
|
|
@@ -8222,7 +8604,7 @@ No agent sessions attached to ${id} yet.`)
|
|
|
8222
8604
|
(t) => t.impact_score === void 0 && t.status !== "done" && !t.deleted_at
|
|
8223
8605
|
);
|
|
8224
8606
|
if (unscored.length === 0) {
|
|
8225
|
-
console.log(
|
|
8607
|
+
console.log(chalk18.green("\n\u2714 All active tasks have impact scores.\n"));
|
|
8226
8608
|
return;
|
|
8227
8609
|
}
|
|
8228
8610
|
const table = new Table4({
|
|
@@ -8232,28 +8614,28 @@ No agent sessions attached to ${id} yet.`)
|
|
|
8232
8614
|
const all = tasks.filter((t) => t.status !== "done" && !t.deleted_at);
|
|
8233
8615
|
for (const t of all) {
|
|
8234
8616
|
table.push([
|
|
8235
|
-
|
|
8617
|
+
chalk18.white(t.id),
|
|
8236
8618
|
t.title,
|
|
8237
8619
|
formatTaskPriority(t.priority),
|
|
8238
|
-
t.impact_score !== void 0 ?
|
|
8620
|
+
t.impact_score !== void 0 ? chalk18.yellow(String(Math.round(t.impact_score))) : chalk18.gray("\u2014")
|
|
8239
8621
|
]);
|
|
8240
8622
|
}
|
|
8241
|
-
console.log(
|
|
8623
|
+
console.log(chalk18.bold("\n\u{1F3AF} Impact Scores\n"));
|
|
8242
8624
|
console.log(table.toString());
|
|
8243
|
-
console.log(
|
|
8625
|
+
console.log(chalk18.gray(`
|
|
8244
8626
|
Unscored: ${unscored.length} task(s). Use: vem task score <id> --set <0-100>
|
|
8245
8627
|
`));
|
|
8246
8628
|
return;
|
|
8247
8629
|
}
|
|
8248
8630
|
const task = await taskService.getTask(id);
|
|
8249
8631
|
if (!task) {
|
|
8250
|
-
console.error(
|
|
8632
|
+
console.error(chalk18.red(`Task ${id} not found.`));
|
|
8251
8633
|
return;
|
|
8252
8634
|
}
|
|
8253
8635
|
if (options.set !== void 0) {
|
|
8254
8636
|
const score = Number.parseFloat(options.set);
|
|
8255
8637
|
if (Number.isNaN(score) || score < 0 || score > 100) {
|
|
8256
|
-
console.error(
|
|
8638
|
+
console.error(chalk18.red("Score must be a number between 0 and 100."));
|
|
8257
8639
|
process.exitCode = 1;
|
|
8258
8640
|
return;
|
|
8259
8641
|
}
|
|
@@ -8261,18 +8643,18 @@ No agent sessions attached to ${id} yet.`)
|
|
|
8261
8643
|
impact_score: score,
|
|
8262
8644
|
reasoning: options.reasoning
|
|
8263
8645
|
});
|
|
8264
|
-
console.log(
|
|
8646
|
+
console.log(chalk18.green(`
|
|
8265
8647
|
\u2714 Impact score for ${id} set to ${score}
|
|
8266
8648
|
`));
|
|
8267
8649
|
} else {
|
|
8268
|
-
console.log(
|
|
8650
|
+
console.log(chalk18.bold(`
|
|
8269
8651
|
\u{1F3AF} ${id}: ${task.title}`));
|
|
8270
|
-
console.log(` Impact score: ${task.impact_score !== void 0 ?
|
|
8271
|
-
console.log(
|
|
8652
|
+
console.log(` Impact score: ${task.impact_score !== void 0 ? chalk18.yellow(String(Math.round(task.impact_score))) : chalk18.gray("not set")}`);
|
|
8653
|
+
console.log(chalk18.gray(` Set with: vem task score ${id} --set <0-100>
|
|
8272
8654
|
`));
|
|
8273
8655
|
}
|
|
8274
8656
|
} catch (error) {
|
|
8275
|
-
console.error(
|
|
8657
|
+
console.error(chalk18.red(`Failed to manage score: ${error.message}`));
|
|
8276
8658
|
}
|
|
8277
8659
|
});
|
|
8278
8660
|
taskCmd.command("ready [id]").description("Mark a task as ready (refined and ready to start)").option("-r, --reasoning <reasoning>", "Reasoning for marking ready").option("--actor <name>", "Actor name").action(async (id, options) => {
|
|
@@ -8284,10 +8666,10 @@ No agent sessions attached to ${id} yet.`)
|
|
|
8284
8666
|
(t) => t.status === "todo" && !t.deleted_at
|
|
8285
8667
|
);
|
|
8286
8668
|
if (todos.length === 0) {
|
|
8287
|
-
console.error(
|
|
8669
|
+
console.error(chalk18.yellow("No todo tasks found."));
|
|
8288
8670
|
return;
|
|
8289
8671
|
}
|
|
8290
|
-
const response = await
|
|
8672
|
+
const response = await prompts9({
|
|
8291
8673
|
type: "select",
|
|
8292
8674
|
name: "value",
|
|
8293
8675
|
message: "Which task is ready to start?",
|
|
@@ -8305,11 +8687,11 @@ No agent sessions attached to ${id} yet.`)
|
|
|
8305
8687
|
reasoning: options.reasoning || "Marked as refined and ready to start.",
|
|
8306
8688
|
actor: actorName
|
|
8307
8689
|
});
|
|
8308
|
-
console.log(
|
|
8690
|
+
console.log(chalk18.cyan(`
|
|
8309
8691
|
\u2714 Task ${id} marked as ready
|
|
8310
8692
|
`));
|
|
8311
8693
|
} catch (error) {
|
|
8312
|
-
console.error(
|
|
8694
|
+
console.error(chalk18.red(`Failed to mark task ready: ${error.message}`));
|
|
8313
8695
|
}
|
|
8314
8696
|
});
|
|
8315
8697
|
}
|
|
@@ -8362,25 +8744,25 @@ async function initServerMonitoring(config) {
|
|
|
8362
8744
|
await initServerMonitoring({
|
|
8363
8745
|
dsn: "https://ed007f2c213d0aa07c1be256ca51750c@o4510863861612544.ingest.de.sentry.io/4510863921774672",
|
|
8364
8746
|
environment: process.env.NODE_ENV || "production",
|
|
8365
|
-
release: "0.1.
|
|
8747
|
+
release: "0.1.53",
|
|
8366
8748
|
serviceName: "cli"
|
|
8367
8749
|
});
|
|
8368
8750
|
var program = new Command();
|
|
8369
|
-
program.name("vem").description("vem Project Memory CLI").version("0.1.
|
|
8751
|
+
program.name("vem").description("vem Project Memory CLI").version("0.1.53").addHelpText(
|
|
8370
8752
|
"after",
|
|
8371
8753
|
`
|
|
8372
|
-
${
|
|
8373
|
-
${
|
|
8374
|
-
${
|
|
8375
|
-
${
|
|
8754
|
+
${chalk19.bold("\n\u26A1 Power Workflows:")}
|
|
8755
|
+
${chalk19.cyan("vem agent")} Start AI-assisted work (${chalk19.bold("recommended")})
|
|
8756
|
+
${chalk19.cyan("vem quickstart")} Interactive setup wizard
|
|
8757
|
+
${chalk19.cyan("vem status")} Check your power feature usage
|
|
8376
8758
|
|
|
8377
|
-
${
|
|
8378
|
-
1. ${
|
|
8379
|
-
2. ${
|
|
8380
|
-
3. ${
|
|
8381
|
-
4. ${
|
|
8759
|
+
${chalk19.bold("\u{1F4A1} Getting Started:")}
|
|
8760
|
+
1. ${chalk19.white("vem init")} Initialize memory
|
|
8761
|
+
2. ${chalk19.white("vem login")} Authenticate
|
|
8762
|
+
3. ${chalk19.white("vem link")} Connect to project
|
|
8763
|
+
4. ${chalk19.white("vem agent")} Start working with AI
|
|
8382
8764
|
|
|
8383
|
-
${
|
|
8765
|
+
${chalk19.gray("For full command list: vem --help")}
|
|
8384
8766
|
`
|
|
8385
8767
|
);
|
|
8386
8768
|
program.hook("preAction", async (_thisCommand, actionCommand) => {
|
|
@@ -8398,7 +8780,7 @@ program.hook("preAction", async (_thisCommand, actionCommand) => {
|
|
|
8398
8780
|
}
|
|
8399
8781
|
if (!await isVemInitialized()) {
|
|
8400
8782
|
console.error(
|
|
8401
|
-
|
|
8783
|
+
chalk19.red("\n\u2716 vem is not initialized. Run `vem init` first.\n")
|
|
8402
8784
|
);
|
|
8403
8785
|
process.exit(1);
|
|
8404
8786
|
}
|
|
@@ -8414,12 +8796,13 @@ registerSearchCommands(program);
|
|
|
8414
8796
|
registerAgentCommands(program);
|
|
8415
8797
|
registerMaintenanceCommands(program);
|
|
8416
8798
|
registerSessionsCommands(program);
|
|
8799
|
+
registerInstructionCommands(program);
|
|
8417
8800
|
await trackHelpUsageFromArgv(process.argv.slice(2));
|
|
8418
8801
|
try {
|
|
8419
8802
|
program.parse();
|
|
8420
8803
|
} catch (error) {
|
|
8421
8804
|
NodeSentry.captureException(error);
|
|
8422
|
-
console.error(
|
|
8805
|
+
console.error(chalk19.red("\n\u2716 An unexpected error occurred."));
|
|
8423
8806
|
if (process.env.NODE_ENV === "development") {
|
|
8424
8807
|
console.error(error);
|
|
8425
8808
|
}
|