dsh-git-changes 0.0.0-stage → 0.1.1

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 (140) hide show
  1. package/LICENSE +21 -0
  2. package/README.en.md +119 -0
  3. package/README.md +137 -2
  4. package/THIRD_PARTY_NOTICES.md +12 -0
  5. package/assets/vendor/monaco/LICENSE +21 -0
  6. package/assets/vendor/monaco/ThirdPartyNotices.txt +448 -0
  7. package/assets/vendor/monaco/vs/base/browser/ui/codicons/codicon/codicon.ttf +0 -0
  8. package/assets/vendor/monaco/vs/base/common/worker/simpleWorker.nls.js +7 -0
  9. package/assets/vendor/monaco/vs/base/common/worker/simpleWorker.nls.zh-cn.js +7 -0
  10. package/assets/vendor/monaco/vs/base/worker/workerMain.js +26 -0
  11. package/assets/vendor/monaco/vs/basic-languages/abap/abap.js +10 -0
  12. package/assets/vendor/monaco/vs/basic-languages/apex/apex.js +10 -0
  13. package/assets/vendor/monaco/vs/basic-languages/azcli/azcli.js +10 -0
  14. package/assets/vendor/monaco/vs/basic-languages/bat/bat.js +10 -0
  15. package/assets/vendor/monaco/vs/basic-languages/bicep/bicep.js +11 -0
  16. package/assets/vendor/monaco/vs/basic-languages/cameligo/cameligo.js +10 -0
  17. package/assets/vendor/monaco/vs/basic-languages/clojure/clojure.js +10 -0
  18. package/assets/vendor/monaco/vs/basic-languages/coffee/coffee.js +10 -0
  19. package/assets/vendor/monaco/vs/basic-languages/cpp/cpp.js +10 -0
  20. package/assets/vendor/monaco/vs/basic-languages/csharp/csharp.js +10 -0
  21. package/assets/vendor/monaco/vs/basic-languages/csp/csp.js +10 -0
  22. package/assets/vendor/monaco/vs/basic-languages/css/css.js +12 -0
  23. package/assets/vendor/monaco/vs/basic-languages/cypher/cypher.js +10 -0
  24. package/assets/vendor/monaco/vs/basic-languages/dart/dart.js +10 -0
  25. package/assets/vendor/monaco/vs/basic-languages/dockerfile/dockerfile.js +10 -0
  26. package/assets/vendor/monaco/vs/basic-languages/ecl/ecl.js +10 -0
  27. package/assets/vendor/monaco/vs/basic-languages/elixir/elixir.js +10 -0
  28. package/assets/vendor/monaco/vs/basic-languages/flow9/flow9.js +10 -0
  29. package/assets/vendor/monaco/vs/basic-languages/freemarker2/freemarker2.js +12 -0
  30. package/assets/vendor/monaco/vs/basic-languages/fsharp/fsharp.js +10 -0
  31. package/assets/vendor/monaco/vs/basic-languages/go/go.js +10 -0
  32. package/assets/vendor/monaco/vs/basic-languages/graphql/graphql.js +10 -0
  33. package/assets/vendor/monaco/vs/basic-languages/handlebars/handlebars.js +10 -0
  34. package/assets/vendor/monaco/vs/basic-languages/hcl/hcl.js +10 -0
  35. package/assets/vendor/monaco/vs/basic-languages/html/html.js +10 -0
  36. package/assets/vendor/monaco/vs/basic-languages/ini/ini.js +10 -0
  37. package/assets/vendor/monaco/vs/basic-languages/java/java.js +10 -0
  38. package/assets/vendor/monaco/vs/basic-languages/javascript/javascript.js +10 -0
  39. package/assets/vendor/monaco/vs/basic-languages/julia/julia.js +10 -0
  40. package/assets/vendor/monaco/vs/basic-languages/kotlin/kotlin.js +10 -0
  41. package/assets/vendor/monaco/vs/basic-languages/less/less.js +11 -0
  42. package/assets/vendor/monaco/vs/basic-languages/lexon/lexon.js +10 -0
  43. package/assets/vendor/monaco/vs/basic-languages/liquid/liquid.js +10 -0
  44. package/assets/vendor/monaco/vs/basic-languages/lua/lua.js +10 -0
  45. package/assets/vendor/monaco/vs/basic-languages/m3/m3.js +10 -0
  46. package/assets/vendor/monaco/vs/basic-languages/markdown/markdown.js +10 -0
  47. package/assets/vendor/monaco/vs/basic-languages/mdx/mdx.js +10 -0
  48. package/assets/vendor/monaco/vs/basic-languages/mips/mips.js +10 -0
  49. package/assets/vendor/monaco/vs/basic-languages/msdax/msdax.js +10 -0
  50. package/assets/vendor/monaco/vs/basic-languages/mysql/mysql.js +10 -0
  51. package/assets/vendor/monaco/vs/basic-languages/objective-c/objective-c.js +10 -0
  52. package/assets/vendor/monaco/vs/basic-languages/pascal/pascal.js +10 -0
  53. package/assets/vendor/monaco/vs/basic-languages/pascaligo/pascaligo.js +10 -0
  54. package/assets/vendor/monaco/vs/basic-languages/perl/perl.js +10 -0
  55. package/assets/vendor/monaco/vs/basic-languages/pgsql/pgsql.js +10 -0
  56. package/assets/vendor/monaco/vs/basic-languages/php/php.js +10 -0
  57. package/assets/vendor/monaco/vs/basic-languages/pla/pla.js +10 -0
  58. package/assets/vendor/monaco/vs/basic-languages/postiats/postiats.js +10 -0
  59. package/assets/vendor/monaco/vs/basic-languages/powerquery/powerquery.js +10 -0
  60. package/assets/vendor/monaco/vs/basic-languages/powershell/powershell.js +10 -0
  61. package/assets/vendor/monaco/vs/basic-languages/protobuf/protobuf.js +11 -0
  62. package/assets/vendor/monaco/vs/basic-languages/pug/pug.js +10 -0
  63. package/assets/vendor/monaco/vs/basic-languages/python/python.js +10 -0
  64. package/assets/vendor/monaco/vs/basic-languages/qsharp/qsharp.js +10 -0
  65. package/assets/vendor/monaco/vs/basic-languages/r/r.js +10 -0
  66. package/assets/vendor/monaco/vs/basic-languages/razor/razor.js +10 -0
  67. package/assets/vendor/monaco/vs/basic-languages/redis/redis.js +10 -0
  68. package/assets/vendor/monaco/vs/basic-languages/redshift/redshift.js +10 -0
  69. package/assets/vendor/monaco/vs/basic-languages/restructuredtext/restructuredtext.js +10 -0
  70. package/assets/vendor/monaco/vs/basic-languages/ruby/ruby.js +10 -0
  71. package/assets/vendor/monaco/vs/basic-languages/rust/rust.js +10 -0
  72. package/assets/vendor/monaco/vs/basic-languages/sb/sb.js +10 -0
  73. package/assets/vendor/monaco/vs/basic-languages/scala/scala.js +10 -0
  74. package/assets/vendor/monaco/vs/basic-languages/scheme/scheme.js +10 -0
  75. package/assets/vendor/monaco/vs/basic-languages/scss/scss.js +12 -0
  76. package/assets/vendor/monaco/vs/basic-languages/shell/shell.js +10 -0
  77. package/assets/vendor/monaco/vs/basic-languages/solidity/solidity.js +10 -0
  78. package/assets/vendor/monaco/vs/basic-languages/sophia/sophia.js +10 -0
  79. package/assets/vendor/monaco/vs/basic-languages/sparql/sparql.js +10 -0
  80. package/assets/vendor/monaco/vs/basic-languages/sql/sql.js +10 -0
  81. package/assets/vendor/monaco/vs/basic-languages/st/st.js +10 -0
  82. package/assets/vendor/monaco/vs/basic-languages/swift/swift.js +13 -0
  83. package/assets/vendor/monaco/vs/basic-languages/systemverilog/systemverilog.js +10 -0
  84. package/assets/vendor/monaco/vs/basic-languages/tcl/tcl.js +10 -0
  85. package/assets/vendor/monaco/vs/basic-languages/twig/twig.js +10 -0
  86. package/assets/vendor/monaco/vs/basic-languages/typescript/typescript.js +10 -0
  87. package/assets/vendor/monaco/vs/basic-languages/vb/vb.js +10 -0
  88. package/assets/vendor/monaco/vs/basic-languages/wgsl/wgsl.js +307 -0
  89. package/assets/vendor/monaco/vs/basic-languages/xml/xml.js +10 -0
  90. package/assets/vendor/monaco/vs/basic-languages/yaml/yaml.js +10 -0
  91. package/assets/vendor/monaco/vs/editor/editor.main.css +6 -0
  92. package/assets/vendor/monaco/vs/editor/editor.main.js +744 -0
  93. package/assets/vendor/monaco/vs/editor/editor.main.nls.js +28 -0
  94. package/assets/vendor/monaco/vs/editor/editor.main.nls.zh-cn.js +30 -0
  95. package/assets/vendor/monaco/vs/language/css/cssMode.js +13 -0
  96. package/assets/vendor/monaco/vs/language/css/cssWorker.js +81 -0
  97. package/assets/vendor/monaco/vs/language/html/htmlMode.js +13 -0
  98. package/assets/vendor/monaco/vs/language/html/htmlWorker.js +453 -0
  99. package/assets/vendor/monaco/vs/language/json/jsonMode.js +15 -0
  100. package/assets/vendor/monaco/vs/language/json/jsonWorker.js +36 -0
  101. package/assets/vendor/monaco/vs/language/typescript/tsMode.js +20 -0
  102. package/assets/vendor/monaco/vs/language/typescript/tsWorker.js +37016 -0
  103. package/assets/vendor/monaco/vs/loader.js +10 -0
  104. package/cordis.patch.yml +3 -0
  105. package/docs/images/git-changes-diff.png +0 -0
  106. package/docs/regression-checklist.md +47 -0
  107. package/icon.svg +10 -0
  108. package/lib/client.js +9418 -0
  109. package/lib/host/assets.js +161 -0
  110. package/lib/host/commit-message.js +158 -0
  111. package/lib/host/files-index.js +206 -0
  112. package/lib/host/git-write.js +194 -0
  113. package/lib/host/git.js +1147 -0
  114. package/lib/host/lsp.js +842 -0
  115. package/lib/host/routes.js +976 -0
  116. package/lib/host/session.js +84 -0
  117. package/lib/host/util.js +107 -0
  118. package/lib/index.js +33 -0
  119. package/licenses/dsh-vscode-mode-LICENSE +21 -0
  120. package/licenses/vscode-theme-seti-LICENSE +21 -0
  121. package/licenses/vscode-theme-seti-ThirdPartyNotices.txt +32 -0
  122. package/locale/en.json +6 -0
  123. package/locale/zh.json +6 -0
  124. package/package.json +65 -4
  125. package/src/client/00-const.js +79 -0
  126. package/src/client/05-utils.js +277 -0
  127. package/src/client/10-i18n.js +548 -0
  128. package/src/client/12-vscode-icons.js +460 -0
  129. package/src/client/15-theme.js +509 -0
  130. package/src/client/20-monaco.js +1404 -0
  131. package/src/client/22-lsp.js +592 -0
  132. package/src/client/25-tree.js +563 -0
  133. package/src/client/28-changes.js +1163 -0
  134. package/src/client/30-page.js +2259 -0
  135. package/src/client/35-pill.js +185 -0
  136. package/src/client/40-commands.js +248 -0
  137. package/src/client/45-css.js +357 -0
  138. package/src/client/47-pickers.js +457 -0
  139. package/src/client/50-apply.js +207 -0
  140. package/src/client/99-footer.js +62 -0
@@ -0,0 +1,194 @@
1
+ /**
2
+ * git 写操作(暂存 / 取消暂存 / 提交 / 推送)。
3
+ *
4
+ * 只暴露固定语义的函数,不接受任意 git 参数透传。所有命令走 argv 数组,
5
+ * 路径由路由层完成 safeRelativePath + realpath + withinRoot 校验后传入。
6
+ *
7
+ * 与只读层的关键差异:写操作必须使用「完整进程环境」,否则子进程拿不到
8
+ * HOME / PATH,git 读不到 ~/.gitconfig 中的身份与 SSH/凭据配置。
9
+ */
10
+ import { GitRunner } from './git.js'
11
+
12
+ /** 暂存/取消暂存/提交的超时。 */
13
+ const WRITE_TIMEOUT_MS = 15000
14
+ /** 推送单独放宽(网络慢、大仓库)。 */
15
+ const PUSH_TIMEOUT_MS = 120000
16
+ /** 错误详情保留长度。 */
17
+ const STDERR_LIMIT = 400
18
+ /** 允许的最大提交信息长度。 */
19
+ const COMMIT_MESSAGE_MAX = 5000
20
+
21
+ /**
22
+ * 写操作子进程环境:完整进程环境 + 禁用交互式提示与可选锁。
23
+ * @returns {Record<string, string | undefined>}
24
+ */
25
+ export function writeEnvironment() {
26
+ return {
27
+ ...process.env,
28
+ GIT_TERMINAL_PROMPT: '0',
29
+ GIT_OPTIONAL_LOCKS: '0',
30
+ LC_ALL: 'C',
31
+ }
32
+ }
33
+
34
+ /**
35
+ * 写操作环境:默认完整进程环境,测试可覆盖。
36
+ * @param {{env?: Record<string, string | undefined>}} request
37
+ */
38
+ function environmentOf(request) {
39
+ return { ...writeEnvironment(), ...(request.env || {}) }
40
+ }
41
+
42
+ /**
43
+ * 创建懒加载的写操作 runner(超时按 push 上限设置)。
44
+ * @param {object} ctx Host context
45
+ * @param {string | null | Promise<string | null>} executable 已解析的 git 路径
46
+ * @returns {() => Promise<GitRunner | null>}
47
+ */
48
+ export function createWriteGit(ctx, executable) {
49
+ let pending
50
+ return () => {
51
+ pending ??= Promise.resolve(executable).then((exe) => (exe
52
+ ? new GitRunner(ctx.subprocess, exe, { timeoutMs: PUSH_TIMEOUT_MS, outputMaxBytes: 8 * 1024 * 1024 })
53
+ : null))
54
+ return pending
55
+ }
56
+ }
57
+
58
+ /**
59
+ * 统一失败形状。
60
+ * @param {string} code 机器可读错误码
61
+ * @param {string} [detail] stderr 摘要
62
+ */
63
+ function fail(code, detail) {
64
+ return { ok: false, code, detail: String(detail || '').slice(0, STDERR_LIMIT) }
65
+ }
66
+
67
+ /**
68
+ * 构造 literal pathspec,避免文件名中的 `*`、`?` 等被当成通配符。
69
+ * @param {string} path 仓库相对路径
70
+ */
71
+ function pathspec(path) {
72
+ return ':(literal)' + path
73
+ }
74
+
75
+ /**
76
+ * 暂存一个或多个文件,或暂存全部(`all`)。
77
+ * @param {GitRunner} git 写 runner
78
+ * @param {{cwd:string, paths?:string[], all?:boolean, signal?:AbortSignal}} request
79
+ * @returns {Promise<{ok:true} | {ok:false, code:string, detail:string}>}
80
+ */
81
+ export async function stagePaths(git, request) {
82
+ const args = ['add', '-A', '--']
83
+ if (request.all) args.push('.')
84
+ else args.push(...(request.paths || []).map(pathspec))
85
+ const result = await git.run(args, { cwd: request.cwd, signal: request.signal, env: environmentOf(request) })
86
+ if (result.exitCode !== 0) return fail('stage-failed', result.stderr)
87
+ return { ok: true }
88
+ }
89
+
90
+ /**
91
+ * 取消暂存一个或多个文件(恢复到工作区,不丢改动)。
92
+ * HEAD 不存在(unborn 分支)时 `git restore --staged` 不可用,退化为
93
+ * `git rm --cached -r`。
94
+ * @param {GitRunner} git 写 runner
95
+ * @param {{cwd:string, paths?:string[], all?:boolean, signal?:AbortSignal}} request
96
+ */
97
+ export async function unstagePaths(git, request) {
98
+ const { cwd, signal } = request
99
+ const env = environmentOf(request)
100
+ const head = await git.run(['rev-parse', '--verify', '--quiet', 'HEAD'], { cwd, signal, env })
101
+ const unborn = head.exitCode !== 0
102
+ const target = request.all ? ['.'] : (request.paths || []).map(pathspec)
103
+ const args = unborn
104
+ ? ['rm', '--cached', '-r', '--', ...target]
105
+ : ['restore', '--staged', '--', ...target]
106
+ const result = await git.run(args, { cwd, signal, env })
107
+ if (result.exitCode !== 0) return fail('unstage-failed', result.stderr)
108
+ return { ok: true }
109
+ }
110
+
111
+ /**
112
+ * 放弃改动:已跟踪文件恢复到 index(未暂存)或 HEAD(已暂存),
113
+ * 未跟踪文件直接删除。不可撤销,由客户端二次确认。
114
+ * @param {GitRunner} git 写 runner
115
+ * @param {{cwd:string, paths?:string[], untrackedPaths?:string[], scope?:'staged'|'unstaged', signal?:AbortSignal}} request
116
+ * @returns {Promise<{ok:true} | {ok:false, code:string, detail:string}>}
117
+ */
118
+ export async function discardPaths(git, request) {
119
+ const { cwd, signal } = request
120
+ const env = environmentOf(request)
121
+ const scope = request.scope === 'staged' ? 'staged' : 'unstaged'
122
+ const tracked = (request.paths || []).map(pathspec)
123
+ if (tracked.length > 0) {
124
+ const args = scope === 'staged'
125
+ ? ['restore', '--source=HEAD', '--staged', '--worktree', '--', ...tracked]
126
+ : ['restore', '--worktree', '--', ...tracked]
127
+ const result = await git.run(args, { cwd, signal, env })
128
+ if (result.exitCode !== 0) return fail('discard-failed', result.stderr)
129
+ }
130
+ const untracked = (request.untrackedPaths || []).map(pathspec)
131
+ if (untracked.length > 0) {
132
+ const result = await git.run(['clean', '-f', '-d', '--', ...untracked], { cwd, signal, env })
133
+ if (result.exitCode !== 0) return fail('discard-failed', result.stderr)
134
+ }
135
+ if (tracked.length === 0 && untracked.length === 0) return fail('empty-selection')
136
+ return { ok: true }
137
+ }
138
+
139
+ /**
140
+ * 提交暂存内容。
141
+ * @param {GitRunner} git 写 runner
142
+ * @param {{cwd:string, message:string, signal?:AbortSignal}} request
143
+ * @returns {Promise<{ok:true, sha:string|null} | {ok:false, code:string, detail:string}>}
144
+ */
145
+ export async function commitChanges(git, request) {
146
+ const { cwd, signal } = request
147
+ const env = environmentOf(request)
148
+ const message = String(request.message || '').trim()
149
+ if (message.length === 0) return fail('empty-message', 'Commit message is required.')
150
+ if (message.length > COMMIT_MESSAGE_MAX) return fail('invalid-message', 'Commit message is too long.')
151
+ if (message.startsWith('-')) return fail('invalid-message', 'Commit message must not start with "-".')
152
+
153
+ const status = await git.run(['status', '--porcelain'], { cwd, signal, env })
154
+ if (status.exitCode !== 0) return fail('commit-failed', status.stderr)
155
+ const hasStaged = status.stdout
156
+ .split('\n')
157
+ .some((line) => line.length > 1 && line[0] !== ' ' && line[0] !== '?')
158
+ if (!hasStaged) return fail('nothing-staged', '没有暂存的改动可提交。')
159
+
160
+ const result = await git.run(['commit', '-m', message], { cwd, signal, env })
161
+ if (result.exitCode !== 0) {
162
+ if (/Author identity unknown|Please tell me who you are|unable to auto-detect email address/i.test(result.stderr)) {
163
+ return fail('identity-missing', 'git user.name / user.email 未配置。')
164
+ }
165
+ if (/nothing added to commit|no changes added to commit/i.test(result.stderr)) {
166
+ return fail('nothing-staged', '没有暂存的改动可提交。')
167
+ }
168
+ return fail('commit-failed', result.stderr)
169
+ }
170
+ const sha = await git.run(['rev-parse', 'HEAD'], { cwd, signal, env })
171
+ return { ok: true, sha: sha.exitCode === 0 ? sha.stdout.trim() : null }
172
+ }
173
+
174
+ /**
175
+ * 推送当前分支。永不 force,不自动创建上游。
176
+ * @param {GitRunner} git 写 runner
177
+ * @param {{cwd:string, signal?:AbortSignal}} request
178
+ * @returns {Promise<{ok:true, branch:string} | {ok:false, code:string, detail:string}>}
179
+ */
180
+ export async function pushCurrentBranch(git, request) {
181
+ const { cwd, signal } = request
182
+ const env = environmentOf(request)
183
+ const head = await git.run(['rev-parse', '--abbrev-ref', 'HEAD'], { cwd, signal, env })
184
+ if (head.exitCode !== 0) return fail('push-failed', head.stderr)
185
+ const branch = head.stdout.trim()
186
+ if (!branch || branch === 'HEAD') return fail('detached-head', '当前处于 detached HEAD,无法推送。')
187
+ const upstream = await git.run(['rev-parse', '--abbrev-ref', '--symbolic-full-name', '@{u}'], { cwd, signal, env })
188
+ if (upstream.exitCode !== 0 || upstream.stdout.trim() === '') {
189
+ return fail('no-upstream', '当前分支没有上游,请先执行 git push -u origin ' + branch)
190
+ }
191
+ const result = await git.run(['push'], { cwd, signal, env })
192
+ if (result.exitCode !== 0) return fail('push-failed', result.stderr)
193
+ return { ok: true, branch }
194
+ }