@paytmsupport/paytm-jarvis 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/.npmrc.example +4 -0
  2. package/ENABLE_2FA_PAYTM.md +59 -0
  3. package/NPM_PRIVATE_PUBLISH.md +149 -0
  4. package/NPM_PRO_REQUIRED.md +51 -0
  5. package/NPM_PUBLISH_GUIDE.md +138 -0
  6. package/PRIVATE_PUBLISH_GUIDE.md +112 -0
  7. package/PUBLISH_NOW.md +53 -0
  8. package/PUBLISH_PAYTM.md +48 -0
  9. package/QUICK_START_NPM_PRIVATE.md +54 -0
  10. package/QUICK_START_PRIVATE.md +72 -0
  11. package/dist/commands/compress.d.ts +3 -0
  12. package/dist/commands/compress.js +97 -0
  13. package/dist/commands/config-cmd.d.ts +1 -0
  14. package/dist/commands/config-cmd.js +84 -0
  15. package/dist/commands/diff.d.ts +1 -0
  16. package/dist/commands/diff.js +97 -0
  17. package/dist/commands/handoff.d.ts +1 -0
  18. package/dist/commands/handoff.js +151 -0
  19. package/dist/commands/hook.d.ts +1 -0
  20. package/dist/commands/hook.js +60 -0
  21. package/dist/commands/init.d.ts +1 -0
  22. package/dist/commands/init.js +49 -0
  23. package/dist/commands/log.d.ts +4 -0
  24. package/dist/commands/log.js +53 -0
  25. package/dist/commands/resume.d.ts +4 -0
  26. package/dist/commands/resume.js +44 -0
  27. package/dist/commands/save.d.ts +13 -0
  28. package/dist/commands/save.js +160 -0
  29. package/dist/commands/share.d.ts +3 -0
  30. package/dist/commands/share.js +58 -0
  31. package/dist/commands/suggest.d.ts +1 -0
  32. package/dist/commands/suggest.js +67 -0
  33. package/dist/commands/summarize.d.ts +1 -0
  34. package/dist/commands/summarize.js +122 -0
  35. package/dist/commands/watch.d.ts +3 -0
  36. package/dist/commands/watch.js +99 -0
  37. package/dist/core/ai.d.ts +17 -0
  38. package/dist/core/ai.js +55 -0
  39. package/dist/core/context.d.ts +16 -0
  40. package/dist/core/context.js +88 -0
  41. package/dist/core/git.d.ts +7 -0
  42. package/dist/core/git.js +73 -0
  43. package/dist/core/parser.d.ts +14 -0
  44. package/dist/core/parser.js +539 -0
  45. package/dist/core/parser.test.d.ts +1 -0
  46. package/dist/core/prompt.d.ts +2 -0
  47. package/dist/core/prompt.js +75 -0
  48. package/dist/core/types.d.ts +24 -0
  49. package/dist/core/types.js +2 -0
  50. package/dist/index.d.ts +2 -0
  51. package/dist/index.js +91 -0
  52. package/dist/mcp-server.d.ts +20 -0
  53. package/dist/mcp-server.js +153 -0
  54. package/dist/utils/clipboard.d.ts +5 -0
  55. package/dist/utils/clipboard.js +23 -0
  56. package/dist/utils/config.d.ts +30 -0
  57. package/dist/utils/config.js +48 -0
  58. package/package.json +54 -0
@@ -0,0 +1,53 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.logCommand = logCommand;
7
+ const chalk_1 = __importDefault(require("chalk"));
8
+ const context_1 = require("../core/context");
9
+ const git_1 = require("../core/git");
10
+ async function logCommand(options) {
11
+ if (!(await (0, context_1.isInitialized)())) {
12
+ console.log(chalk_1.default.red("✗ DevContext not initialized. Run `jarvis init` first."));
13
+ return;
14
+ }
15
+ try {
16
+ const count = parseInt(options?.count || "10", 10);
17
+ if (options?.all) {
18
+ const sessions = await (0, context_1.loadAllSessions)();
19
+ if (sessions.length === 0) {
20
+ console.log(chalk_1.default.yellow("No context entries found."));
21
+ return;
22
+ }
23
+ console.log(chalk_1.default.bold("\nAll branches:\n"));
24
+ sessions.slice(0, count).forEach((s) => {
25
+ const date = new Date(s.timestamp).toLocaleString();
26
+ console.log(` ${chalk_1.default.gray(`[${date}]`)} ${chalk_1.default.cyan(s.branch)} ${s.task}`);
27
+ });
28
+ }
29
+ else {
30
+ const branch = await (0, git_1.getCurrentBranch)();
31
+ const entries = await (0, context_1.loadBranchContext)(branch);
32
+ if (entries.length === 0) {
33
+ console.log(chalk_1.default.yellow(`No context for branch: ${branch}`));
34
+ return;
35
+ }
36
+ console.log(chalk_1.default.bold(`\nBranch: ${branch}\n`));
37
+ entries
38
+ .slice(-count)
39
+ .reverse()
40
+ .forEach((e) => {
41
+ const date = new Date(e.timestamp).toLocaleString();
42
+ console.log(` ${chalk_1.default.gray(`[${date}]`)} ${e.task}`);
43
+ if (e.currentState) {
44
+ console.log(` ${chalk_1.default.gray("└─")} ${e.currentState}`);
45
+ }
46
+ });
47
+ }
48
+ console.log();
49
+ }
50
+ catch (err) {
51
+ console.log(chalk_1.default.red(`✗ Error: ${err.message}`));
52
+ }
53
+ }
@@ -0,0 +1,4 @@
1
+ export declare function resumeCommand(options?: {
2
+ branch?: string;
3
+ stdout?: boolean;
4
+ }): Promise<void>;
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.resumeCommand = resumeCommand;
7
+ const chalk_1 = __importDefault(require("chalk"));
8
+ const context_1 = require("../core/context");
9
+ const git_1 = require("../core/git");
10
+ const prompt_1 = require("../core/prompt");
11
+ const clipboard_1 = require("../utils/clipboard");
12
+ async function resumeCommand(options) {
13
+ if (!(await (0, context_1.isInitialized)())) {
14
+ console.log(chalk_1.default.red("✗ DevContext not initialized. Run `jarvis init` first."));
15
+ return;
16
+ }
17
+ try {
18
+ const branch = options?.branch || (await (0, git_1.getCurrentBranch)());
19
+ const entries = await (0, context_1.loadBranchContext)(branch);
20
+ if (entries.length === 0) {
21
+ console.log(chalk_1.default.yellow(`⚠ No context found for branch: ${branch}`));
22
+ console.log(chalk_1.default.gray(" Run `jarvis save` to capture context first."));
23
+ return;
24
+ }
25
+ const prompt = (0, prompt_1.generatePrompt)(entries);
26
+ if (options?.stdout) {
27
+ console.log(prompt);
28
+ }
29
+ else {
30
+ const copied = await (0, clipboard_1.copyToClipboard)(prompt);
31
+ if (copied) {
32
+ console.log(chalk_1.default.green("📋 Context copied to clipboard!"));
33
+ console.log(chalk_1.default.gray(` Branch: ${branch} | ${entries.length} sessions | Paste into any AI tool`));
34
+ }
35
+ else {
36
+ // Fallback: print to stdout if clipboard failed
37
+ console.log(prompt);
38
+ }
39
+ }
40
+ }
41
+ catch (err) {
42
+ console.log(chalk_1.default.red(`✗ Error: ${err.message}`));
43
+ }
44
+ }
@@ -0,0 +1,13 @@
1
+ interface SaveOptions {
2
+ goal?: string;
3
+ approaches?: string;
4
+ decisions?: string;
5
+ state?: string;
6
+ nextSteps?: string;
7
+ blockers?: string;
8
+ assignee?: string;
9
+ handoffNote?: string;
10
+ auto?: boolean;
11
+ }
12
+ export declare function saveCommand(message?: string, options?: SaveOptions): Promise<void>;
13
+ export {};
@@ -0,0 +1,160 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.saveCommand = saveCommand;
7
+ const chalk_1 = __importDefault(require("chalk"));
8
+ const inquirer_1 = __importDefault(require("inquirer"));
9
+ const uuid_1 = require("uuid");
10
+ const context_1 = require("../core/context");
11
+ const git_1 = require("../core/git");
12
+ const parser_1 = require("../core/parser");
13
+ async function saveCommand(message, options) {
14
+ if (!(await (0, context_1.isInitialized)())) {
15
+ console.log(chalk_1.default.red("✗ DevContext not initialized. Run `jarvis init` first."));
16
+ return;
17
+ }
18
+ try {
19
+ const [branch, repo, filesChanged, filesStaged, recentCommits, author] = await Promise.all([
20
+ (0, git_1.getCurrentBranch)(),
21
+ (0, git_1.getRepoName)(),
22
+ (0, git_1.getChangedFiles)(),
23
+ (0, git_1.getStagedFiles)(),
24
+ (0, git_1.getRecentCommits)(),
25
+ (0, git_1.getAuthor)(),
26
+ ]);
27
+ let task = message || "";
28
+ let approaches = [];
29
+ let decisions = [];
30
+ let currentState = "";
31
+ let nextSteps = [];
32
+ let blockers = [];
33
+ // Check if structured flags were provided (AI agent mode)
34
+ const hasStructuredInput = options?.approaches || options?.decisions || options?.state || options?.nextSteps;
35
+ if (options?.auto) {
36
+ // Auto-extract mode — read from editor session data
37
+ console.log(chalk_1.default.gray(" Scanning editor sessions for context..."));
38
+ const cwd = process.cwd();
39
+ const extracted = await (0, parser_1.extractFromEditorSessions)(cwd);
40
+ if (extracted) {
41
+ task = message || extracted.task;
42
+ approaches = extracted.approaches;
43
+ decisions = extracted.decisions;
44
+ currentState = extracted.currentState;
45
+ nextSteps = extracted.nextSteps;
46
+ blockers = extracted.blockers;
47
+ console.log(chalk_1.default.gray(` Found context from: ${extracted.source}`));
48
+ }
49
+ else {
50
+ console.log(chalk_1.default.yellow("⚠ No editor session data found. Using message only."));
51
+ task = message || "Session (auto-extract found nothing)";
52
+ currentState = message || "";
53
+ }
54
+ }
55
+ else if (hasStructuredInput && message) {
56
+ // Programmatic mode — AI agent is passing structured context
57
+ task = message;
58
+ approaches = options?.approaches
59
+ ? options.approaches.split(";;").map((s) => s.trim()).filter(Boolean)
60
+ : [];
61
+ decisions = options?.decisions
62
+ ? options.decisions.split(";;").map((s) => s.trim()).filter(Boolean)
63
+ : [];
64
+ currentState = options?.state || message;
65
+ nextSteps = options?.nextSteps
66
+ ? options.nextSteps.split(";;").map((s) => s.trim()).filter(Boolean)
67
+ : [];
68
+ blockers = options?.blockers
69
+ ? options.blockers.split(";;").map((s) => s.trim()).filter(Boolean)
70
+ : [];
71
+ }
72
+ else if (!message) {
73
+ // Interactive mode
74
+ const answers = await inquirer_1.default.prompt([
75
+ {
76
+ type: "input",
77
+ name: "task",
78
+ message: "What were you working on?",
79
+ validate: (input) => input.length > 0 || "Task description is required",
80
+ },
81
+ {
82
+ type: "input",
83
+ name: "approaches",
84
+ message: "What approaches did you try? (comma-separated, or skip)",
85
+ default: "",
86
+ },
87
+ {
88
+ type: "input",
89
+ name: "decisions",
90
+ message: "Key decisions made? (comma-separated, or skip)",
91
+ default: "",
92
+ },
93
+ {
94
+ type: "input",
95
+ name: "currentState",
96
+ message: "Where did you leave off?",
97
+ validate: (input) => input.length > 0 || "Current state is required",
98
+ },
99
+ {
100
+ type: "input",
101
+ name: "nextSteps",
102
+ message: "What comes next? (comma-separated, or skip)",
103
+ default: "",
104
+ },
105
+ {
106
+ type: "input",
107
+ name: "blockers",
108
+ message: "Any blockers? (comma-separated, or skip)",
109
+ default: "",
110
+ },
111
+ ]);
112
+ task = answers.task;
113
+ approaches = answers.approaches
114
+ ? answers.approaches.split(",").map((s) => s.trim()).filter(Boolean)
115
+ : [];
116
+ decisions = answers.decisions
117
+ ? answers.decisions.split(",").map((s) => s.trim()).filter(Boolean)
118
+ : [];
119
+ currentState = answers.currentState;
120
+ nextSteps = answers.nextSteps
121
+ ? answers.nextSteps.split(",").map((s) => s.trim()).filter(Boolean)
122
+ : [];
123
+ blockers = answers.blockers
124
+ ? answers.blockers.split(",").map((s) => s.trim()).filter(Boolean)
125
+ : [];
126
+ }
127
+ else {
128
+ // Simple message mode
129
+ currentState = message;
130
+ }
131
+ const entry = {
132
+ id: (0, uuid_1.v4)(),
133
+ timestamp: new Date().toISOString(),
134
+ branch,
135
+ repo,
136
+ author,
137
+ task,
138
+ goal: options?.goal,
139
+ approaches,
140
+ decisions,
141
+ currentState,
142
+ nextSteps,
143
+ blockers: blockers.length > 0 ? blockers : undefined,
144
+ filesChanged,
145
+ filesStaged,
146
+ recentCommits,
147
+ assignee: options?.assignee,
148
+ handoffNote: options?.handoffNote,
149
+ };
150
+ const savedTo = await (0, context_1.saveContext)(entry);
151
+ console.log(chalk_1.default.green(`✓ Context saved for branch: ${chalk_1.default.bold(branch)}`));
152
+ console.log(chalk_1.default.gray(` ${filesChanged.length} files changed, ${recentCommits.length} recent commits captured`));
153
+ if (approaches.length > 0) {
154
+ console.log(chalk_1.default.gray(` ${approaches.length} approaches, ${decisions.length} decisions recorded`));
155
+ }
156
+ }
157
+ catch (err) {
158
+ console.log(chalk_1.default.red(`✗ Error: ${err.message}`));
159
+ }
160
+ }
@@ -0,0 +1,3 @@
1
+ export declare function shareCommand(options?: {
2
+ stop?: boolean;
3
+ }): Promise<void>;
@@ -0,0 +1,58 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.shareCommand = shareCommand;
7
+ const fs_1 = __importDefault(require("fs"));
8
+ const path_1 = __importDefault(require("path"));
9
+ const chalk_1 = __importDefault(require("chalk"));
10
+ const simple_git_1 = __importDefault(require("simple-git"));
11
+ const git_1 = require("../core/git");
12
+ const git = (0, simple_git_1.default)();
13
+ async function shareCommand(options) {
14
+ try {
15
+ const root = await (0, git_1.getRepoRoot)();
16
+ const gitignorePath = path_1.default.join(root, ".gitignore");
17
+ const devctxDir = path_1.default.join(root, ".jarvis");
18
+ if (!fs_1.default.existsSync(devctxDir)) {
19
+ console.log(chalk_1.default.red("✗ DevContext not initialized. Run `jarvis init` first."));
20
+ return;
21
+ }
22
+ if (options?.stop) {
23
+ // Add .jarvis/ back to .gitignore
24
+ const gitignoreContent = fs_1.default.existsSync(gitignorePath)
25
+ ? fs_1.default.readFileSync(gitignorePath, "utf-8")
26
+ : "";
27
+ if (!gitignoreContent.includes(".jarvis/")) {
28
+ fs_1.default.appendFileSync(gitignorePath, "\n.jarvis/\n");
29
+ }
30
+ console.log(chalk_1.default.green("✓ Stopped sharing DevContext"));
31
+ console.log(chalk_1.default.gray(" .jarvis/ added back to .gitignore"));
32
+ console.log(chalk_1.default.gray(" Note: Existing .jarvis/ files remain in git history."));
33
+ return;
34
+ }
35
+ // Remove .jarvis/ from .gitignore
36
+ if (fs_1.default.existsSync(gitignorePath)) {
37
+ let content = fs_1.default.readFileSync(gitignorePath, "utf-8");
38
+ content = content
39
+ .split("\n")
40
+ .filter((line) => line.trim() !== ".jarvis/" &&
41
+ line.trim() !== ".jarvis" &&
42
+ line.trim() !== "# DevContext - AI coding context")
43
+ .join("\n");
44
+ fs_1.default.writeFileSync(gitignorePath, content);
45
+ }
46
+ // Stage .jarvis/ and commit
47
+ await git.add([".jarvis/", ".gitignore"]);
48
+ await git.commit("chore: share DevContext with team");
49
+ console.log(chalk_1.default.green("✓ DevContext is now shared with your team!"));
50
+ console.log(chalk_1.default.gray(" .jarvis/ removed from .gitignore"));
51
+ console.log(chalk_1.default.gray(" Committed: \"chore: share DevContext with team\""));
52
+ console.log(chalk_1.default.gray("\n Push to share: git push"));
53
+ console.log(chalk_1.default.gray(" Stop sharing: jarvis share --stop"));
54
+ }
55
+ catch (err) {
56
+ console.log(chalk_1.default.red(`✗ Error: ${err.message}`));
57
+ }
58
+ }
@@ -0,0 +1 @@
1
+ export declare function suggestCommand(): Promise<void>;
@@ -0,0 +1,67 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.suggestCommand = suggestCommand;
7
+ const chalk_1 = __importDefault(require("chalk"));
8
+ const context_1 = require("../core/context");
9
+ const git_1 = require("../core/git");
10
+ const ai_1 = require("../core/ai");
11
+ async function suggestCommand() {
12
+ if (!(await (0, context_1.isInitialized)())) {
13
+ console.log(chalk_1.default.red("✗ DevContext not initialized. Run `jarvis init` first."));
14
+ return;
15
+ }
16
+ try {
17
+ const branch = await (0, git_1.getCurrentBranch)();
18
+ const entries = await (0, context_1.loadBranchContext)(branch);
19
+ const [filesChanged, recentCommits] = await Promise.all([
20
+ (0, git_1.getChangedFiles)(),
21
+ (0, git_1.getRecentCommits)(10),
22
+ ]);
23
+ if (entries.length === 0 && filesChanged.length === 0) {
24
+ console.log(chalk_1.default.yellow("⚠ No context or changes found. Nothing to analyze."));
25
+ return;
26
+ }
27
+ console.log(chalk_1.default.gray(" Analyzing codebase and context..."));
28
+ const latest = entries[entries.length - 1];
29
+ const contextSummary = latest
30
+ ? `Current task: ${latest.task}
31
+ Current state: ${latest.currentState}
32
+ Previous approaches: ${latest.approaches.join(", ") || "none"}
33
+ Previous decisions: ${latest.decisions.join(", ") || "none"}
34
+ Known blockers: ${latest.blockers?.join(", ") || "none"}
35
+ Previous next steps: ${latest.nextSteps.join(", ") || "none"}`
36
+ : "No previous context available.";
37
+ const prompt = `You are a senior developer mentor. Based on the following project context, suggest concrete next steps.
38
+
39
+ Branch: ${branch}
40
+
41
+ ${contextSummary}
42
+
43
+ Recent commits:
44
+ ${recentCommits.map((c) => `- ${c}`).join("\n")}
45
+
46
+ Currently changed files: ${filesChanged.join(", ") || "none"}
47
+
48
+ Provide 3-5 specific, actionable next steps. For each step, briefly explain WHY it's important. Format as a numbered list.`;
49
+ const result = await (0, ai_1.callAI)([
50
+ {
51
+ role: "system",
52
+ content: "You are a helpful senior developer. Be concise and actionable.",
53
+ },
54
+ { role: "user", content: prompt },
55
+ ]);
56
+ if (result.error) {
57
+ console.log(chalk_1.default.red(`✗ ${result.error}`));
58
+ return;
59
+ }
60
+ console.log(chalk_1.default.bold.cyan("\n💡 Suggested Next Steps\n"));
61
+ console.log(result.content);
62
+ console.log();
63
+ }
64
+ catch (err) {
65
+ console.log(chalk_1.default.red(`✗ Error: ${err.message}`));
66
+ }
67
+ }
@@ -0,0 +1 @@
1
+ export declare function summarizeCommand(): Promise<void>;
@@ -0,0 +1,122 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.summarizeCommand = summarizeCommand;
7
+ const chalk_1 = __importDefault(require("chalk"));
8
+ const uuid_1 = require("uuid");
9
+ const context_1 = require("../core/context");
10
+ const git_1 = require("../core/git");
11
+ const ai_1 = require("../core/ai");
12
+ const simple_git_1 = __importDefault(require("simple-git"));
13
+ const git = (0, simple_git_1.default)();
14
+ async function summarizeCommand() {
15
+ if (!(await (0, context_1.isInitialized)())) {
16
+ console.log(chalk_1.default.red("✗ DevContext not initialized. Run `jarvis init` first."));
17
+ return;
18
+ }
19
+ try {
20
+ console.log(chalk_1.default.gray(" Analyzing git changes..."));
21
+ const [branch, repo, filesChanged, filesStaged, recentCommits, author] = await Promise.all([
22
+ (0, git_1.getCurrentBranch)(),
23
+ (0, git_1.getRepoName)(),
24
+ (0, git_1.getChangedFiles)(),
25
+ (0, git_1.getStagedFiles)(),
26
+ (0, git_1.getRecentCommits)(10),
27
+ (0, git_1.getAuthor)(),
28
+ ]);
29
+ // Get git diff for context
30
+ let diffSummary = "";
31
+ try {
32
+ const diff = await git.diff(["--stat"]);
33
+ diffSummary = diff.slice(0, 2000); // cap at 2k chars
34
+ }
35
+ catch {
36
+ diffSummary = "No diff available";
37
+ }
38
+ const prompt = `You are a developer assistant. Based on the following git activity, generate a concise coding context summary.
39
+
40
+ Repository: ${repo}
41
+ Branch: ${branch}
42
+ Author: ${author}
43
+
44
+ Recent commits:
45
+ ${recentCommits.map((c) => `- ${c}`).join("\n")}
46
+
47
+ Files changed: ${filesChanged.join(", ") || "none"}
48
+ Files staged: ${filesStaged.join(", ") || "none"}
49
+
50
+ Diff summary:
51
+ ${diffSummary}
52
+
53
+ Generate a JSON response with:
54
+ {
55
+ "task": "one-line description of what's being worked on",
56
+ "approaches": ["approach 1", "approach 2"],
57
+ "decisions": ["decision 1"],
58
+ "currentState": "where things currently stand",
59
+ "nextSteps": ["step 1", "step 2"]
60
+ }
61
+
62
+ Be concise. Only include approaches/decisions if they're clearly evident from the commits and changes.`;
63
+ console.log(chalk_1.default.gray(" Generating AI summary..."));
64
+ const result = await (0, ai_1.callAI)([
65
+ { role: "system", content: "You are a helpful developer assistant. Always respond with valid JSON." },
66
+ { role: "user", content: prompt },
67
+ ]);
68
+ if (result.error) {
69
+ console.log(chalk_1.default.red(`✗ ${result.error}`));
70
+ return;
71
+ }
72
+ // Parse AI response
73
+ let parsed;
74
+ try {
75
+ // Extract JSON from potential markdown code blocks
76
+ const jsonMatch = result.content.match(/```(?:json)?\s*([\s\S]*?)```/) ||
77
+ [null, result.content];
78
+ parsed = JSON.parse(jsonMatch[1].trim());
79
+ }
80
+ catch {
81
+ console.log(chalk_1.default.yellow("⚠ Could not parse AI response. Saving raw summary."));
82
+ parsed = {
83
+ task: result.content.slice(0, 200),
84
+ approaches: [],
85
+ decisions: [],
86
+ currentState: result.content,
87
+ nextSteps: [],
88
+ };
89
+ }
90
+ const entry = {
91
+ id: (0, uuid_1.v4)(),
92
+ timestamp: new Date().toISOString(),
93
+ branch,
94
+ repo,
95
+ author,
96
+ task: parsed.task || "AI-generated summary",
97
+ approaches: parsed.approaches || [],
98
+ decisions: parsed.decisions || [],
99
+ currentState: parsed.currentState || "",
100
+ nextSteps: parsed.nextSteps || [],
101
+ filesChanged,
102
+ filesStaged,
103
+ recentCommits,
104
+ };
105
+ await (0, context_1.saveContext)(entry);
106
+ console.log(chalk_1.default.green(`\n✓ AI-generated context saved for branch: ${chalk_1.default.bold(branch)}`));
107
+ console.log(chalk_1.default.cyan(`\n Task: ${entry.task}`));
108
+ if (entry.currentState) {
109
+ console.log(chalk_1.default.gray(` State: ${entry.currentState}`));
110
+ }
111
+ if (entry.decisions.length > 0) {
112
+ entry.decisions.forEach((d) => console.log(chalk_1.default.gray(` Decision: ${d}`)));
113
+ }
114
+ if (entry.nextSteps.length > 0) {
115
+ console.log(chalk_1.default.gray(` Next steps: ${entry.nextSteps.join(", ")}`));
116
+ }
117
+ console.log();
118
+ }
119
+ catch (err) {
120
+ console.log(chalk_1.default.red(`✗ Error: ${err.message}`));
121
+ }
122
+ }
@@ -0,0 +1,3 @@
1
+ export declare function watchCommand(options?: {
2
+ interval?: string;
3
+ }): Promise<void>;
@@ -0,0 +1,99 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.watchCommand = watchCommand;
7
+ const chalk_1 = __importDefault(require("chalk"));
8
+ const chokidar_1 = __importDefault(require("chokidar"));
9
+ const uuid_1 = require("uuid");
10
+ const context_1 = require("../core/context");
11
+ const git_1 = require("../core/git");
12
+ const parser_1 = require("../core/parser");
13
+ const config_1 = require("../utils/config");
14
+ async function watchCommand(options) {
15
+ if (!(await (0, context_1.isInitialized)())) {
16
+ console.log(chalk_1.default.red("✗ DevContext not initialized. Run `jarvis init` first."));
17
+ return;
18
+ }
19
+ try {
20
+ const config = await (0, config_1.loadConfig)();
21
+ const intervalMinutes = parseInt(options?.interval || String(config.watchInterval), 10);
22
+ const intervalMs = intervalMinutes * 60 * 1000;
23
+ const root = await (0, git_1.getRepoRoot)();
24
+ const devctxDir = await (0, context_1.getDevCtxDir)();
25
+ let changeCount = 0;
26
+ let lastSave = Date.now();
27
+ console.log(chalk_1.default.green("👁 Watch mode started"));
28
+ console.log(chalk_1.default.gray(` Auto-save every ${intervalMinutes} minutes when changes detected`));
29
+ console.log(chalk_1.default.gray(` Watching: ${root}`));
30
+ console.log(chalk_1.default.gray(" Press Ctrl+C to stop\n"));
31
+ const watcher = chokidar_1.default.watch(root, {
32
+ ignored: [
33
+ /(^|[\/\\])\../, // dotfiles
34
+ "**/node_modules/**",
35
+ "**/dist/**",
36
+ "**/build/**",
37
+ "**/.jarvis/**",
38
+ "**/package-lock.json",
39
+ ],
40
+ persistent: true,
41
+ ignoreInitial: true,
42
+ });
43
+ watcher.on("all", (_event, _filePath) => {
44
+ changeCount++;
45
+ });
46
+ // Periodic auto-save
47
+ const timer = setInterval(async () => {
48
+ if (changeCount === 0)
49
+ return;
50
+ try {
51
+ const [branch, repo, filesChanged, filesStaged, recentCommits, author] = await Promise.all([
52
+ (0, git_1.getCurrentBranch)(),
53
+ (0, git_1.getRepoName)(),
54
+ (0, git_1.getChangedFiles)(),
55
+ (0, git_1.getStagedFiles)(),
56
+ (0, git_1.getRecentCommits)(),
57
+ (0, git_1.getAuthor)(),
58
+ ]);
59
+ // Try to enrich from editor session data
60
+ const chatContext = await (0, parser_1.extractFromEditorSessions)(root);
61
+ const entry = {
62
+ id: (0, uuid_1.v4)(),
63
+ timestamp: new Date().toISOString(),
64
+ branch,
65
+ repo,
66
+ author,
67
+ task: chatContext?.task || `Auto-captured: ${changeCount} file changes`,
68
+ approaches: chatContext?.approaches || [],
69
+ decisions: chatContext?.decisions || [],
70
+ currentState: `${changeCount} files changed since last auto-save`,
71
+ nextSteps: chatContext?.nextSteps || [],
72
+ filesChanged,
73
+ filesStaged,
74
+ recentCommits,
75
+ };
76
+ await (0, context_1.saveContext)(entry);
77
+ const now = new Date();
78
+ console.log(chalk_1.default.gray(` [${now.toLocaleTimeString()}] Auto-saved: ${changeCount} changes on ${branch}`));
79
+ changeCount = 0;
80
+ lastSave = Date.now();
81
+ }
82
+ catch (err) {
83
+ console.log(chalk_1.default.yellow(` ⚠ Auto-save failed: ${err.message}`));
84
+ }
85
+ }, intervalMs);
86
+ // Graceful shutdown
87
+ const cleanup = () => {
88
+ clearInterval(timer);
89
+ watcher.close();
90
+ console.log(chalk_1.default.gray("\n Watch mode stopped."));
91
+ process.exit(0);
92
+ };
93
+ process.on("SIGINT", cleanup);
94
+ process.on("SIGTERM", cleanup);
95
+ }
96
+ catch (err) {
97
+ console.log(chalk_1.default.red(`✗ Error: ${err.message}`));
98
+ }
99
+ }
@@ -0,0 +1,17 @@
1
+ interface ChatMessage {
2
+ role: "system" | "user" | "assistant";
3
+ content: string;
4
+ }
5
+ interface AIResponse {
6
+ content: string;
7
+ error?: string;
8
+ }
9
+ /**
10
+ * Call an OpenAI-compatible chat completions API.
11
+ * Works with OpenAI, Ollama, LM Studio, together.ai, etc.
12
+ */
13
+ export declare function callAI(messages: ChatMessage[], options?: {
14
+ maxTokens?: number;
15
+ temperature?: number;
16
+ }): Promise<AIResponse>;
17
+ export {};