jvcs 1.4.4 → 1.4.6
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.
|
File without changes
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
const AppState = require("./state")
|
|
2
|
+
const getDiff = require("./diffEngine")
|
|
3
|
+
const chalk = require("chalk")
|
|
4
|
+
const { checkGlobalConfig, getGlobalConfig, checkforjvcs } = require("./utility")
|
|
5
|
+
|
|
6
|
+
async function diff(mode, options = {}) {
|
|
7
|
+
|
|
8
|
+
if(!checkGlobalConfig()) {
|
|
9
|
+
console.log(chalk.red("No existing session found. Please login or signup."))
|
|
10
|
+
console.log(chalk.green("jvcs --help for help"))
|
|
11
|
+
return
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
let configData = getGlobalConfig()
|
|
15
|
+
|
|
16
|
+
if(!configData) {
|
|
17
|
+
console.log(chalk.red("No existing session found. Please login or signup."))
|
|
18
|
+
console.log(chalk.green("jvcs --help for help"))
|
|
19
|
+
return
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
if(!checkforjvcs()) {
|
|
23
|
+
console.log(chalk.red("Repository is not initialized or is deleted. Please create it."))
|
|
24
|
+
return
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
try {
|
|
28
|
+
|
|
29
|
+
const files = getDiff(mode, options)
|
|
30
|
+
if(!files || files.length === 0) {
|
|
31
|
+
console.log(chalk.yellow("No differences found."))
|
|
32
|
+
return
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const appState = new AppState (mode, files)
|
|
36
|
+
startUI(appState)
|
|
37
|
+
}
|
|
38
|
+
catch(error) {
|
|
39
|
+
console.log(chalk.red("Diff Error: " + (error.message || error)))
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
module.exports = diff
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import fs from "fs"
|
|
2
|
+
import path from "path"
|
|
3
|
+
|
|
4
|
+
const JVCS_ROOT = path.join(process.cwd(), ".jvcs")
|
|
5
|
+
|
|
6
|
+
const IGNORE_FOLDERS = [
|
|
7
|
+
".jvcs",
|
|
8
|
+
"node_modules",
|
|
9
|
+
".git"
|
|
10
|
+
]
|
|
11
|
+
|
|
12
|
+
const IGNORE_FILES = [
|
|
13
|
+
".DS_Store",
|
|
14
|
+
"jvcs_hashcode.json",
|
|
15
|
+
"meta.json",
|
|
16
|
+
"HEAD",
|
|
17
|
+
"config.json"
|
|
18
|
+
]
|
|
19
|
+
|
|
20
|
+
function fileExists(filepath) {
|
|
21
|
+
return fs.existsSync(filepath)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function readFileSafe(filepath) {
|
|
25
|
+
|
|
26
|
+
if(!fileExists(filepath)) return ""
|
|
27
|
+
return fs.readFileSync(filepath, "utf-8")
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function shouldIgnoreFile(fileName) {
|
|
31
|
+
return IGNORE_FILES.includes(fileName)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function shouldIgnoreFolder(folderName) {
|
|
35
|
+
return IGNORE_FOLDERS.includes(folderName)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function loadStageSnapshot() {
|
|
39
|
+
const stagePath = path.join(JVCS_ROOT, "staging")
|
|
40
|
+
return loadDirectoryRecursive(stagePath)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function loadDirectoryRecursive(dirPath, baseDir = dirPath, snapshot = {}) {
|
|
44
|
+
|
|
45
|
+
if(!fileExists(dirPath)) return snapshot
|
|
46
|
+
|
|
47
|
+
const entries = fs.readdirSync(dirPath)
|
|
48
|
+
|
|
49
|
+
for(const entry of entries) {
|
|
50
|
+
if(shouldIgnoreFile(entry)) continue
|
|
51
|
+
if(shouldIgnoreFolder(entry)) continue
|
|
52
|
+
|
|
53
|
+
const fullPath = path.join(dirPath, entry)
|
|
54
|
+
const stat = fs.statSync(fullPath)
|
|
55
|
+
|
|
56
|
+
if(stat.isDirectory()) {
|
|
57
|
+
loadDirectoryRecursive(fullPath, baseDir, snapshot)
|
|
58
|
+
}
|
|
59
|
+
else if (stat.isFile()) {
|
|
60
|
+
const relativePath = path.relative(baseDir, fullPath)
|
|
61
|
+
snapshot[relativePath] = readFileSafe(fullPath)
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return snapshot
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function loadWorkingDirectorySnapshot() {
|
|
69
|
+
return loadDirectoryRecursive(process.cwd(), process.cwd())
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function calculateLineDiff(leftContent, rightContent) {
|
|
73
|
+
|
|
74
|
+
const leftLines = leftContent.split("\n")
|
|
75
|
+
const rightLines = rightContent.split("\n")
|
|
76
|
+
|
|
77
|
+
let added = 0
|
|
78
|
+
let removed = 0
|
|
79
|
+
|
|
80
|
+
const max = Math.max(leftLines.length, rightLines.length)
|
|
81
|
+
|
|
82
|
+
for (let i = 0; i < max; i++) {
|
|
83
|
+
if (leftLines[i] !== rightLines[i]) {
|
|
84
|
+
if(leftLines[i] === undefined) {
|
|
85
|
+
added++
|
|
86
|
+
}
|
|
87
|
+
else if(rightLines[i] === undefined) {
|
|
88
|
+
removed++
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
added++
|
|
92
|
+
removed++
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return { added, removed }
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function buildDiffObject(filePath, leftContent, rightContent) {
|
|
101
|
+
let status = "modified"
|
|
102
|
+
|
|
103
|
+
if(!leftContent && rightContent) {
|
|
104
|
+
status = "added"
|
|
105
|
+
}
|
|
106
|
+
else if(leftContent && !rightContent) {
|
|
107
|
+
status = "deleted"
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return {
|
|
111
|
+
path: filePath,
|
|
112
|
+
status,
|
|
113
|
+
leftContent,
|
|
114
|
+
rightContent,
|
|
115
|
+
stats: calculateLineDiff(leftContent, rightContent)
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function getDiff(mode, options = {}) {
|
|
120
|
+
|
|
121
|
+
let leftSnapshot = {}
|
|
122
|
+
let rightSnapshot = {}
|
|
123
|
+
|
|
124
|
+
if(mode === "commit-vs-commit") {
|
|
125
|
+
const { commitA, commitB } = options
|
|
126
|
+
|
|
127
|
+
if(!commitA || !commitB) {
|
|
128
|
+
throw new Error("commit-vs-commit requires commitA and commitB")
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
leftSnapshot = loadCommitSnapshot(commitA)
|
|
132
|
+
rightSnapshot = loadCommitSnapshot(commitB)
|
|
133
|
+
}
|
|
134
|
+
else if(mode === "commit-vs-stage") {
|
|
135
|
+
const { commitId } = options
|
|
136
|
+
|
|
137
|
+
if(!commitId) {
|
|
138
|
+
throw new Error("commit-vs-stage requires commitId")
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
leftSnapshot = loadCommitSnapshot(commitId)
|
|
142
|
+
rightSnapshot = loadStageSnapshot()
|
|
143
|
+
}
|
|
144
|
+
else if(mode === "stage-vs-cwd") {
|
|
145
|
+
leftSnapshot = loadStageSnapshot()
|
|
146
|
+
rightSnapshot = loadWorkingDirectorySnapshot()
|
|
147
|
+
}
|
|
148
|
+
else {
|
|
149
|
+
throw new Error("Invalid diff mode")
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const allFiles = new Set([
|
|
153
|
+
...Object.keys(leftSnapshot),
|
|
154
|
+
...Object.keys(rightSnapshot)
|
|
155
|
+
])
|
|
156
|
+
|
|
157
|
+
const diffResults = []
|
|
158
|
+
|
|
159
|
+
for (const filePath of allFiles) {
|
|
160
|
+
const leftContent = leftSnapshot[filePath] || ""
|
|
161
|
+
const rightContent = rightSnapshot[filePath] || ""
|
|
162
|
+
|
|
163
|
+
if(leftContent !== rightContent) {
|
|
164
|
+
diffResults.push(
|
|
165
|
+
buildDiffObject(filePath, leftContent, rightContent)
|
|
166
|
+
)
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
return diffResults
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
module.exports = getDiff
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
class AppState {
|
|
2
|
+
|
|
3
|
+
constructor(mode, files) {
|
|
4
|
+
this.mode = mode
|
|
5
|
+
this.files = files || []
|
|
6
|
+
this.screen = "FILE_LIST"
|
|
7
|
+
this.selectedIndex = 0
|
|
8
|
+
this.activeTab = 0
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
selectFile(index) {
|
|
12
|
+
this.selectedIndex = index
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
switchTab(tabIndex) {
|
|
16
|
+
this.activeTab = tabIndex
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
goToFileView() {
|
|
20
|
+
this.screen = "FILE_VIEW"
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
goToListView() {
|
|
24
|
+
this.screen = "FILE_LIST"
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
getCurrentFile() {
|
|
28
|
+
return this.files[this.selectedIndex]
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
module.exports = AppState
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
const blessed = require("blessed")
|
|
2
|
+
|
|
3
|
+
function startUI(state) {
|
|
4
|
+
|
|
5
|
+
const screen = blessed.screen({
|
|
6
|
+
smartCSR: true,
|
|
7
|
+
title: "JVCS Diff Viewer"
|
|
8
|
+
})
|
|
9
|
+
|
|
10
|
+
// ---------------------------------------
|
|
11
|
+
// HEADER
|
|
12
|
+
// ---------------------------------------
|
|
13
|
+
|
|
14
|
+
const header = blessed.box({
|
|
15
|
+
top: 0,
|
|
16
|
+
height: 1,
|
|
17
|
+
width: "100%",
|
|
18
|
+
content: ` JVCS DIFF VIEW (${state.mode}) | ↑↓ Navigate | Enter Open | Esc Back | Tab Switch | Q Quit `,
|
|
19
|
+
style: {
|
|
20
|
+
fg: "black",
|
|
21
|
+
bg: "cyan"
|
|
22
|
+
}
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
screen.append(header)
|
|
26
|
+
|
|
27
|
+
// ---------------------------------------
|
|
28
|
+
// FILE LIST VIEW
|
|
29
|
+
// ---------------------------------------
|
|
30
|
+
|
|
31
|
+
const fileList = blessed.list({
|
|
32
|
+
top: 1,
|
|
33
|
+
left: 0,
|
|
34
|
+
width: "100%",
|
|
35
|
+
height: "100%-1",
|
|
36
|
+
keys: true,
|
|
37
|
+
vi: true,
|
|
38
|
+
border: "line",
|
|
39
|
+
label: " Changed Files ",
|
|
40
|
+
style: {
|
|
41
|
+
selected: {
|
|
42
|
+
bg: "blue"
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
screen.append(fileList)
|
|
48
|
+
|
|
49
|
+
function renderFileList() {
|
|
50
|
+
const items = state.files.map((file, index) => {
|
|
51
|
+
return `${file.status.toUpperCase()} ${file.path}`
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
fileList.setItems(items)
|
|
55
|
+
fileList.select(state.selectedIndex)
|
|
56
|
+
fileList.focus()
|
|
57
|
+
screen.render()
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// ---------------------------------------
|
|
61
|
+
// FILE VIEW (3 PANELS)
|
|
62
|
+
// ---------------------------------------
|
|
63
|
+
|
|
64
|
+
const leftBox = blessed.box({
|
|
65
|
+
top: 1,
|
|
66
|
+
left: 0,
|
|
67
|
+
width: "33%",
|
|
68
|
+
height: "100%-1",
|
|
69
|
+
border: "line",
|
|
70
|
+
label: " LEFT ",
|
|
71
|
+
scrollable: true,
|
|
72
|
+
alwaysScroll: true,
|
|
73
|
+
keys: true,
|
|
74
|
+
vi: true
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
const rightBox = blessed.box({
|
|
78
|
+
top: 1,
|
|
79
|
+
left: "33%",
|
|
80
|
+
width: "34%",
|
|
81
|
+
height: "100%-1",
|
|
82
|
+
border: "line",
|
|
83
|
+
label: " RIGHT ",
|
|
84
|
+
scrollable: true,
|
|
85
|
+
alwaysScroll: true,
|
|
86
|
+
keys: true,
|
|
87
|
+
vi: true
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
const aiBox = blessed.box({
|
|
91
|
+
top: 1,
|
|
92
|
+
left: "67%",
|
|
93
|
+
width: "33%",
|
|
94
|
+
height: "100%-1",
|
|
95
|
+
border: "line",
|
|
96
|
+
label: " AI ANALYSIS ",
|
|
97
|
+
scrollable: true,
|
|
98
|
+
alwaysScroll: true,
|
|
99
|
+
keys: true,
|
|
100
|
+
vi: true
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
function renderFileView() {
|
|
104
|
+
|
|
105
|
+
const file = state.getCurrentFile()
|
|
106
|
+
if (!file) return
|
|
107
|
+
|
|
108
|
+
leftBox.setContent(file.leftContent || "")
|
|
109
|
+
rightBox.setContent(file.rightContent || "")
|
|
110
|
+
|
|
111
|
+
aiBox.setContent(`
|
|
112
|
+
Summary:
|
|
113
|
+
Changes detected in file.
|
|
114
|
+
|
|
115
|
+
Status: ${file.status}
|
|
116
|
+
|
|
117
|
+
Lines Added: ${file.stats.added}
|
|
118
|
+
Lines Removed: ${file.stats.removed}
|
|
119
|
+
|
|
120
|
+
(Real AI analysis will appear here later)
|
|
121
|
+
`)
|
|
122
|
+
|
|
123
|
+
screen.append(leftBox)
|
|
124
|
+
screen.append(rightBox)
|
|
125
|
+
screen.append(aiBox)
|
|
126
|
+
|
|
127
|
+
updateActiveTabHighlight()
|
|
128
|
+
|
|
129
|
+
screen.render()
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function destroyFileView() {
|
|
133
|
+
leftBox.detach()
|
|
134
|
+
rightBox.detach()
|
|
135
|
+
aiBox.detach()
|
|
136
|
+
screen.render()
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function updateActiveTabHighlight() {
|
|
140
|
+
|
|
141
|
+
leftBox.style.border.fg = "white"
|
|
142
|
+
rightBox.style.border.fg = "white"
|
|
143
|
+
aiBox.style.border.fg = "white"
|
|
144
|
+
|
|
145
|
+
if (state.activeTab === 0) {
|
|
146
|
+
leftBox.style.border.fg = "yellow"
|
|
147
|
+
leftBox.focus()
|
|
148
|
+
}
|
|
149
|
+
else if (state.activeTab === 1) {
|
|
150
|
+
rightBox.style.border.fg = "yellow"
|
|
151
|
+
rightBox.focus()
|
|
152
|
+
}
|
|
153
|
+
else {
|
|
154
|
+
aiBox.style.border.fg = "yellow"
|
|
155
|
+
aiBox.focus()
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
screen.render()
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// ---------------------------------------
|
|
162
|
+
// KEYBOARD CONTROLS
|
|
163
|
+
// ---------------------------------------
|
|
164
|
+
|
|
165
|
+
screen.key(["q", "C-c"], () => {
|
|
166
|
+
return process.exit(0)
|
|
167
|
+
})
|
|
168
|
+
|
|
169
|
+
// Navigate list
|
|
170
|
+
fileList.key(["up"], () => {
|
|
171
|
+
if (state.selectedIndex > 0) {
|
|
172
|
+
state.selectFile(state.selectedIndex - 1)
|
|
173
|
+
renderFileList()
|
|
174
|
+
}
|
|
175
|
+
})
|
|
176
|
+
|
|
177
|
+
fileList.key(["down"], () => {
|
|
178
|
+
if (state.selectedIndex < state.files.length - 1) {
|
|
179
|
+
state.selectFile(state.selectedIndex + 1)
|
|
180
|
+
renderFileList()
|
|
181
|
+
}
|
|
182
|
+
})
|
|
183
|
+
|
|
184
|
+
// Enter → Open file view
|
|
185
|
+
fileList.key(["enter"], () => {
|
|
186
|
+
state.goToFileView()
|
|
187
|
+
fileList.detach()
|
|
188
|
+
renderFileView()
|
|
189
|
+
})
|
|
190
|
+
|
|
191
|
+
// ESC → Back to list
|
|
192
|
+
screen.key(["escape"], () => {
|
|
193
|
+
if (state.screen === "FILE_VIEW") {
|
|
194
|
+
state.goToListView()
|
|
195
|
+
destroyFileView()
|
|
196
|
+
screen.append(fileList)
|
|
197
|
+
renderFileList()
|
|
198
|
+
}
|
|
199
|
+
})
|
|
200
|
+
|
|
201
|
+
// TAB → switch active panel
|
|
202
|
+
screen.key(["tab"], () => {
|
|
203
|
+
if (state.screen === "FILE_VIEW") {
|
|
204
|
+
state.switchTab((state.activeTab + 1) % 3)
|
|
205
|
+
updateActiveTabHighlight()
|
|
206
|
+
}
|
|
207
|
+
})
|
|
208
|
+
|
|
209
|
+
// ---------------------------------------
|
|
210
|
+
// INITIAL RENDER
|
|
211
|
+
// ---------------------------------------
|
|
212
|
+
|
|
213
|
+
renderFileList()
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
module.exports = startUI
|
package/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
1
|
+
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
const yargs = require("yargs");
|
|
4
4
|
const { hideBin } = require("yargs/helpers");
|
|
@@ -16,6 +16,7 @@ const pushCmd = require("./controllers/push");
|
|
|
16
16
|
const statusCmd = require("./controllers/status")
|
|
17
17
|
const revertCmd = require("./controllers/revert")
|
|
18
18
|
const cloneCmd = require("./controllers/clone")
|
|
19
|
+
const diff = require("./controllers/diff-engine/diff")
|
|
19
20
|
// file changed
|
|
20
21
|
|
|
21
22
|
yargs(hideBin(process.argv))
|
|
@@ -157,6 +158,65 @@ yargs(hideBin(process.argv))
|
|
|
157
158
|
}
|
|
158
159
|
}
|
|
159
160
|
)
|
|
161
|
+
.command(
|
|
162
|
+
"diff",
|
|
163
|
+
chalk.blue(`
|
|
164
|
+
Compare different states of your repository.
|
|
165
|
+
|
|
166
|
+
Modes:
|
|
167
|
+
stage-vs-cwd
|
|
168
|
+
commit-vs-stage
|
|
169
|
+
commit-vs-commit
|
|
170
|
+
|
|
171
|
+
Example:
|
|
172
|
+
jvcs diff --mode stage-vs-cwd
|
|
173
|
+
jvcs diff --mode commit-vs-stage --commitId <id>
|
|
174
|
+
jvcs diff --mode commit-vs-commit --commitA <id> --commitB <id>
|
|
175
|
+
`),
|
|
176
|
+
(yargs) => {
|
|
177
|
+
return yargs
|
|
178
|
+
.option("mode", {
|
|
179
|
+
type: "string",
|
|
180
|
+
describe: "Diff mode",
|
|
181
|
+
choices: ["stage-vs-cwd", "commit-vs-stage", "commit-vs-commit"],
|
|
182
|
+
demandOption: true
|
|
183
|
+
})
|
|
184
|
+
.option("commitId", {
|
|
185
|
+
type: "string",
|
|
186
|
+
describe: "Commit ID (for commit-vs-stage)"
|
|
187
|
+
})
|
|
188
|
+
.option("commitA", {
|
|
189
|
+
type: "string",
|
|
190
|
+
describe: "First commit ID (for commit-vs-commit)"
|
|
191
|
+
})
|
|
192
|
+
.option("commitB", {
|
|
193
|
+
type: "string",
|
|
194
|
+
describe: "Second commit ID (for commit-vs-commit)"
|
|
195
|
+
})
|
|
196
|
+
},
|
|
197
|
+
async (argv) => {
|
|
198
|
+
try {
|
|
199
|
+
const { mode, commitId, commitA, commitB } = argv
|
|
200
|
+
|
|
201
|
+
if(mode === "commit-vs-stage" && !commitId) {
|
|
202
|
+
throw new Error("commit-vs-stage requires --commitId")
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
if(mode === "commit-vs-commit" && (!commitA || !commitB)) {
|
|
206
|
+
throw new Error("commit-vs-commit requires --commitA and --commitB")
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
await diff(mode, {
|
|
210
|
+
commitId,
|
|
211
|
+
commitA,
|
|
212
|
+
commitB
|
|
213
|
+
})
|
|
214
|
+
}
|
|
215
|
+
catch (error) {
|
|
216
|
+
console.log(chalk.red(error.message || error))
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
)
|
|
160
220
|
.command(
|
|
161
221
|
"revert <commitId>",
|
|
162
222
|
chalk.blue("Replace your working directory with specific commit you made previously"),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "jvcs",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.6",
|
|
4
4
|
"bin": {
|
|
5
5
|
"jvcs": "index.js"
|
|
6
6
|
},
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
"author": "",
|
|
9
9
|
"license": "ISC",
|
|
10
10
|
"dependencies": {
|
|
11
|
+
"blessed": "^0.1.81",
|
|
11
12
|
"chalk": "^4.1.2",
|
|
12
13
|
"dotenv": "^17.2.3",
|
|
13
14
|
"googleapis": "^164.1.0",
|