@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.
- package/.npmrc.example +4 -0
- package/ENABLE_2FA_PAYTM.md +59 -0
- package/NPM_PRIVATE_PUBLISH.md +149 -0
- package/NPM_PRO_REQUIRED.md +51 -0
- package/NPM_PUBLISH_GUIDE.md +138 -0
- package/PRIVATE_PUBLISH_GUIDE.md +112 -0
- package/PUBLISH_NOW.md +53 -0
- package/PUBLISH_PAYTM.md +48 -0
- package/QUICK_START_NPM_PRIVATE.md +54 -0
- package/QUICK_START_PRIVATE.md +72 -0
- package/dist/commands/compress.d.ts +3 -0
- package/dist/commands/compress.js +97 -0
- package/dist/commands/config-cmd.d.ts +1 -0
- package/dist/commands/config-cmd.js +84 -0
- package/dist/commands/diff.d.ts +1 -0
- package/dist/commands/diff.js +97 -0
- package/dist/commands/handoff.d.ts +1 -0
- package/dist/commands/handoff.js +151 -0
- package/dist/commands/hook.d.ts +1 -0
- package/dist/commands/hook.js +60 -0
- package/dist/commands/init.d.ts +1 -0
- package/dist/commands/init.js +49 -0
- package/dist/commands/log.d.ts +4 -0
- package/dist/commands/log.js +53 -0
- package/dist/commands/resume.d.ts +4 -0
- package/dist/commands/resume.js +44 -0
- package/dist/commands/save.d.ts +13 -0
- package/dist/commands/save.js +160 -0
- package/dist/commands/share.d.ts +3 -0
- package/dist/commands/share.js +58 -0
- package/dist/commands/suggest.d.ts +1 -0
- package/dist/commands/suggest.js +67 -0
- package/dist/commands/summarize.d.ts +1 -0
- package/dist/commands/summarize.js +122 -0
- package/dist/commands/watch.d.ts +3 -0
- package/dist/commands/watch.js +99 -0
- package/dist/core/ai.d.ts +17 -0
- package/dist/core/ai.js +55 -0
- package/dist/core/context.d.ts +16 -0
- package/dist/core/context.js +88 -0
- package/dist/core/git.d.ts +7 -0
- package/dist/core/git.js +73 -0
- package/dist/core/parser.d.ts +14 -0
- package/dist/core/parser.js +539 -0
- package/dist/core/parser.test.d.ts +1 -0
- package/dist/core/prompt.d.ts +2 -0
- package/dist/core/prompt.js +75 -0
- package/dist/core/types.d.ts +24 -0
- package/dist/core/types.js +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +91 -0
- package/dist/mcp-server.d.ts +20 -0
- package/dist/mcp-server.js +153 -0
- package/dist/utils/clipboard.d.ts +5 -0
- package/dist/utils/clipboard.js +23 -0
- package/dist/utils/config.d.ts +30 -0
- package/dist/utils/config.js +48 -0
- 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,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,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,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 {};
|