@dsh-cc/command-commit-split 0.8.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.
- package/LICENSE +201 -0
- package/README.i18n.yaml +6 -0
- package/README.md +39 -0
- package/README.zh.md +39 -0
- package/lib/index.d.ts +51 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +139 -0
- package/lib/index.js.map +1 -0
- package/lib/plan.d.ts +77 -0
- package/lib/plan.d.ts.map +1 -0
- package/lib/plan.js +229 -0
- package/lib/plan.js.map +1 -0
- package/package.json +49 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
Apache License
|
|
2
|
+
Version 2.0, January 2004
|
|
3
|
+
http://www.apache.org/licenses/
|
|
4
|
+
|
|
5
|
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
6
|
+
|
|
7
|
+
1. Definitions.
|
|
8
|
+
|
|
9
|
+
"License" shall mean the terms and conditions for use, reproduction,
|
|
10
|
+
and distribution as defined by Sections 1 through 9 of this document.
|
|
11
|
+
|
|
12
|
+
"Licensor" shall mean the copyright owner or entity authorized by
|
|
13
|
+
the copyright owner that is granting the License.
|
|
14
|
+
|
|
15
|
+
"Legal Entity" shall mean the union of the acting entity and all
|
|
16
|
+
other entities that control, are controlled by, or are under common
|
|
17
|
+
control with that entity. For the purposes of this definition,
|
|
18
|
+
"control" means (i) the power, direct or indirect, to cause the
|
|
19
|
+
direction or management of such entity, whether by contract or
|
|
20
|
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
21
|
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
22
|
+
|
|
23
|
+
"You" (or "Your") shall mean an individual or Legal Entity
|
|
24
|
+
exercising permissions granted by this License.
|
|
25
|
+
|
|
26
|
+
"Source" form shall mean the preferred form for making modifications,
|
|
27
|
+
including but not limited to software source code, documentation
|
|
28
|
+
source, and configuration files.
|
|
29
|
+
|
|
30
|
+
"Object" form shall mean any form resulting from mechanical
|
|
31
|
+
transformation or translation of a Source form, including but
|
|
32
|
+
not limited to compiled object code, generated documentation,
|
|
33
|
+
and conversions to other media types.
|
|
34
|
+
|
|
35
|
+
"Work" shall mean the work of authorship, whether in Source or
|
|
36
|
+
Object form, made available under the License, as indicated by a
|
|
37
|
+
copyright notice that is included in or attached to the work
|
|
38
|
+
(an example is provided in the Appendix below).
|
|
39
|
+
|
|
40
|
+
"Derivative Works" shall mean any work, whether in Source or Object
|
|
41
|
+
form, that is based on (or derived from) the Work and for which the
|
|
42
|
+
editorial revisions, annotations, elaborations, or other modifications
|
|
43
|
+
represent, as a whole, an original work of authorship. For the purposes
|
|
44
|
+
of this License, Derivative Works shall not include works that remain
|
|
45
|
+
separable from, or merely link (or bind by name) to the interfaces of,
|
|
46
|
+
the Work and Derivative Works thereof.
|
|
47
|
+
|
|
48
|
+
"Contribution" shall mean any work of authorship, including
|
|
49
|
+
the original version of the Work and any modifications or additions
|
|
50
|
+
to that Work or Derivative Works thereof, that is intentionally
|
|
51
|
+
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
52
|
+
or by an individual or Legal Entity authorized to submit on behalf of
|
|
53
|
+
the copyright owner. For the purposes of this definition, "submitted"
|
|
54
|
+
means any form of electronic, verbal, or written communication sent
|
|
55
|
+
to the Licensor or its representatives, including but not limited to
|
|
56
|
+
communication on electronic mailing lists, source code control systems,
|
|
57
|
+
and issue tracking systems that are managed by, or on behalf of, the
|
|
58
|
+
Licensor for the purpose of discussing and improving the Work, but
|
|
59
|
+
excluding communication that is conspicuously marked or otherwise
|
|
60
|
+
designated in writing by the copyright owner as "Not a Contribution."
|
|
61
|
+
|
|
62
|
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
63
|
+
on behalf of whom a Contribution has been received by Licensor and
|
|
64
|
+
subsequently incorporated within the Work.
|
|
65
|
+
|
|
66
|
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
67
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
68
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
69
|
+
copyright license to reproduce, prepare Derivative Works of,
|
|
70
|
+
publicly display, publicly perform, sublicense, and distribute the
|
|
71
|
+
Work and such Derivative Works in Source or Object form.
|
|
72
|
+
|
|
73
|
+
3. Grant of Patent License. Subject to the terms and conditions of
|
|
74
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
75
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
76
|
+
(except as stated in this section) patent license to make, have made,
|
|
77
|
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
78
|
+
where such license applies only to those patent claims licensable
|
|
79
|
+
by such Contributor that are necessarily infringed by their
|
|
80
|
+
Contribution(s) alone or by combination of their Contribution(s)
|
|
81
|
+
with the Work to which such Contribution(s) was submitted. If You
|
|
82
|
+
institute patent litigation against any entity (including a
|
|
83
|
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
84
|
+
or a Contribution incorporated within the Work constitutes direct
|
|
85
|
+
or contributory patent infringement, then any patent licenses
|
|
86
|
+
granted to You under this License for that Work shall terminate
|
|
87
|
+
as of the date such litigation is filed.
|
|
88
|
+
|
|
89
|
+
4. Redistribution. You may reproduce and distribute copies of the
|
|
90
|
+
Work or Derivative Works thereof in any medium, with or without
|
|
91
|
+
modifications, and in Source or Object form, provided that You
|
|
92
|
+
meet the following conditions:
|
|
93
|
+
|
|
94
|
+
(a) You must give any other recipients of the Work or
|
|
95
|
+
Derivative Works a copy of this License; and
|
|
96
|
+
|
|
97
|
+
(b) You must cause any modified files to carry prominent notices
|
|
98
|
+
stating that You changed the files; and
|
|
99
|
+
|
|
100
|
+
(c) You must retain, in the Source form of any Derivative Works
|
|
101
|
+
that You distribute, all copyright, patent, trademark, and
|
|
102
|
+
attribution notices from the Source form of the Work,
|
|
103
|
+
excluding those notices that do not pertain to any part of
|
|
104
|
+
the Derivative Works; and
|
|
105
|
+
|
|
106
|
+
(d) If the Work includes a "NOTICE" text file as part of its
|
|
107
|
+
distribution, then any Derivative Works that You distribute must
|
|
108
|
+
include a readable copy of the attribution notices contained
|
|
109
|
+
within such NOTICE file, excluding those notices that do not
|
|
110
|
+
pertain to any part of the Derivative Works, in at least one
|
|
111
|
+
of the following places: within a NOTICE text file distributed
|
|
112
|
+
as part of the Derivative Works; within the Source form or
|
|
113
|
+
documentation, if provided along with the Derivative Works; or,
|
|
114
|
+
within a display generated by the Derivative Works, if and
|
|
115
|
+
wherever such third-party notices normally appear. The contents
|
|
116
|
+
of the NOTICE file are for informational purposes only and
|
|
117
|
+
do not modify the License. You may add Your own attribution
|
|
118
|
+
notices within Derivative Works that You distribute, alongside
|
|
119
|
+
or as an addendum to the NOTICE text from the Work, provided
|
|
120
|
+
that such additional attribution notices cannot be construed
|
|
121
|
+
as modifying the License.
|
|
122
|
+
|
|
123
|
+
You may add Your own copyright statement to Your modifications and
|
|
124
|
+
may provide additional or different license terms and conditions
|
|
125
|
+
for use, reproduction, or distribution of Your modifications, or
|
|
126
|
+
for any such Derivative Works as a whole, provided Your use,
|
|
127
|
+
reproduction, and distribution of the Work otherwise complies with
|
|
128
|
+
the conditions stated in this License.
|
|
129
|
+
|
|
130
|
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
131
|
+
any Contribution intentionally submitted for inclusion in the Work
|
|
132
|
+
by You to the Licensor shall be under the terms and conditions of
|
|
133
|
+
this License, without any additional terms or conditions.
|
|
134
|
+
Notwithstanding the above, nothing herein shall supersede or modify
|
|
135
|
+
the terms of any separate license agreement you may have executed
|
|
136
|
+
with Licensor regarding such Contributions.
|
|
137
|
+
|
|
138
|
+
6. Trademarks. This License does not grant permission to use the trade
|
|
139
|
+
names, trademarks, service marks, or product names of the Licensor,
|
|
140
|
+
except as required for reasonable and customary use in describing the
|
|
141
|
+
origin of the Work and reproducing the content of the NOTICE file.
|
|
142
|
+
|
|
143
|
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
144
|
+
agreed to in writing, Licensor provides the Work (and each
|
|
145
|
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
146
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
147
|
+
implied, including, without limitation, any warranties or conditions
|
|
148
|
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
149
|
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
150
|
+
appropriateness of using or redistributing the Work and assume any
|
|
151
|
+
risks associated with Your exercise of permissions under this License.
|
|
152
|
+
|
|
153
|
+
8. Limitation of Liability. In no event and under no legal theory,
|
|
154
|
+
whether in tort (including negligence), contract, or otherwise,
|
|
155
|
+
unless required by applicable law (such as deliberate and grossly
|
|
156
|
+
negligent acts) or agreed to in writing, shall any Contributor be
|
|
157
|
+
liable to You for damages, including any direct, indirect, special,
|
|
158
|
+
incidental, or consequential damages of any character arising as a
|
|
159
|
+
result of this License or out of the use or inability to use the
|
|
160
|
+
Work (including but not limited to damages for loss of goodwill,
|
|
161
|
+
work stoppage, computer failure or malfunction, or any and all
|
|
162
|
+
other commercial damages or losses), even if such Contributor
|
|
163
|
+
has been advised of the possibility of such damages.
|
|
164
|
+
|
|
165
|
+
9. Accepting Warranty or Additional Liability. While redistributing
|
|
166
|
+
the Work or Derivative Works thereof, You may choose to offer,
|
|
167
|
+
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
168
|
+
or other liability obligations and/or rights consistent with this
|
|
169
|
+
License. However, in accepting such obligations, You may act only
|
|
170
|
+
on Your own behalf and on Your sole responsibility, not on behalf
|
|
171
|
+
of any other Contributor, and only if You agree to indemnify,
|
|
172
|
+
defend, and hold each Contributor harmless for any liability
|
|
173
|
+
incurred by, or claims asserted against, such Contributor by reason
|
|
174
|
+
of your accepting any such warranty or additional liability.
|
|
175
|
+
|
|
176
|
+
END OF TERMS AND CONDITIONS
|
|
177
|
+
|
|
178
|
+
APPENDIX: How to apply the Apache License to your work.
|
|
179
|
+
|
|
180
|
+
To apply the Apache License to your work, attach the following
|
|
181
|
+
boilerplate notice, with the fields enclosed by brackets "[]"
|
|
182
|
+
replaced with your own identifying information. (Don't include
|
|
183
|
+
the brackets!) The text should be enclosed in the appropriate
|
|
184
|
+
comment syntax for the file format. We also recommend that a
|
|
185
|
+
file or class name and description of purpose be included on the
|
|
186
|
+
same "printed page" as the copyright notice for easier
|
|
187
|
+
identification within third-party archives.
|
|
188
|
+
|
|
189
|
+
Copyright [yyyy] [name of copyright owner]
|
|
190
|
+
|
|
191
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
192
|
+
you may not use this file except in compliance with the License.
|
|
193
|
+
You may obtain a copy of the License at
|
|
194
|
+
|
|
195
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
196
|
+
|
|
197
|
+
Unless required by applicable law or agreed to in writing, software
|
|
198
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
199
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
200
|
+
See the License for the specific language governing permissions and
|
|
201
|
+
limitations under the License.
|
package/README.i18n.yaml
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each
|
|
2
|
+
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
|
3
|
+
# after editing either side, bring the other along and re-record with:
|
|
4
|
+
# pnpm check:readme --write
|
|
5
|
+
README.md: daf1f8267c0065583f79536c068f762efa5e02e9
|
|
6
|
+
README.zh.md: ebe900044eb159c459ca7280b650fdff97aaea08
|
package/README.md
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# @dsh-cc/command-commit-split
|
|
2
|
+
|
|
3
|
+
English | [中文](README.zh.md)
|
|
4
|
+
|
|
5
|
+
Advisory dry-run `/commit-split` command: it reads the working-tree change (status + staged + unstaged) through the shell service, asks the deep-reasoning lane (model alias `blueprint`, via [`@dsh-cc/side-query`](../../llm-tuning/side-query/README.md)) for an ordered atomic-commit split plan, and renders it. It **never commits** — the user (or the model, explicitly asked) executes the proposals one by one.
|
|
6
|
+
|
|
7
|
+
## Command contract
|
|
8
|
+
|
|
9
|
+
| Input | Result |
|
|
10
|
+
|---|---|
|
|
11
|
+
| `/commit-split` | Rendered split plan: ordered groups of `{ message, files, dependencyEdges }`, with the declared dependency heuristic in the footer. When the `blueprint` alias is unconfigured, a visible note reports the inherited main-model route. |
|
|
12
|
+
| `/commit-split help` | Canonical help text (trailing-`help` support via `@dsh-cc/command-usage`). |
|
|
13
|
+
|
|
14
|
+
Error sections (no plan emitted): `error: model output did not match the plan schema` for non-conforming model output, and `error: dependency cycle among groups: a → b → a` when the returned dependency edges are cyclic. Cycle detection runs in the command, never in the model.
|
|
15
|
+
|
|
16
|
+
## Data and model seams
|
|
17
|
+
|
|
18
|
+
Git data is collected exclusively through `ctx.get('shell')`'s `run` (or `exec`) with a 5s timeout, using exactly three read-only commands: `git status --porcelain`, `git diff --cached --numstat`, `git diff --numstat`. All reads complete before the side query is awaited. The command never runs the model's Bash tool.
|
|
19
|
+
|
|
20
|
+
Dependency heuristic (declared in the output footer): shared top-level directory plus textual import-reference overlap between changed files, ranking source > test > docs. Lockfiles (`pnpm-lock.yaml`, `package-lock.json`, `yarn.lock`, `bun.lockb`) are excluded from model groups into a trailing `chore(deps)` group; a lockfile-only change skips the model entirely.
|
|
21
|
+
|
|
22
|
+
## Composition
|
|
23
|
+
|
|
24
|
+
The plugin injects `commands`. A custom app mounts the owner plus this plugin:
|
|
25
|
+
|
|
26
|
+
```yaml
|
|
27
|
+
- id: commands
|
|
28
|
+
name: '@deepseek-ai/dsh-commands'
|
|
29
|
+
- id: command-commit-split
|
|
30
|
+
name: '@dsh-cc/command-commit-split'
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Model Experience
|
|
34
|
+
|
|
35
|
+
The slash input and output are absent from model requests. The split query is a one-shot side query on the `blueprint` lane (falling back to the inherited parent route with a visible note); the plan text returned to the user is presentation-only.
|
|
36
|
+
|
|
37
|
+
## Known Limitations and Deferred Work
|
|
38
|
+
|
|
39
|
+
- **Advisory only** — no staging, committing, or rewriting is performed; proposals may be imperfect when imports are dynamic or files are generated.
|
package/README.zh.md
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# @dsh-cc/command-commit-split
|
|
2
|
+
|
|
3
|
+
[English](README.md) | 中文
|
|
4
|
+
|
|
5
|
+
建议型、仅预演的 `/commit-split` 命令:通过 shell 服务读取工作区变更(status + 暂存 + 未暂存),向深度推理通道(模型别名 `blueprint`,经 [`@dsh-cc/side-query`](../../llm-tuning/side-query/README.md))请求一份按依赖排序的原子提交拆分方案并渲染输出。它**从不提交**——由用户(或明确要求的模型)逐条执行建议。
|
|
6
|
+
|
|
7
|
+
## 命令契约
|
|
8
|
+
|
|
9
|
+
| 输入 | 结果 |
|
|
10
|
+
|---|---|
|
|
11
|
+
| `/commit-split` | 渲染拆分方案:按序分组的 `{ message, files, dependencyEdges }`,页脚声明所用依赖启发式。当 `blueprint` 别名未配置时,输出可见提示说明沿用主模型路由。 |
|
|
12
|
+
| `/commit-split help` | 规范帮助文本(经 `@dsh-cc/command-usage` 支持尾部 `help` 参数)。 |
|
|
13
|
+
|
|
14
|
+
错误段落(不输出方案):模型输出不符合模式时为 `error: model output did not match the plan schema`;返回的依赖边成环时为 `error: dependency cycle among groups: a → b → a`。环检测在命令侧执行,从不交给模型。
|
|
15
|
+
|
|
16
|
+
## 数据与模型接缝
|
|
17
|
+
|
|
18
|
+
Git 数据只通过 `ctx.get('shell')` 的 `run`(或 `exec`)以 5 秒超时采集,且只使用三条只读命令:`git status --porcelain`、`git diff --cached --numstat`、`git diff --numstat`。所有读取在发起侧查询之前完成。命令绝不使用模型的 Bash 工具。
|
|
19
|
+
|
|
20
|
+
依赖启发式(在输出页脚声明):共享顶层目录加变更文件间的文本 import 引用重叠,排序 source > test > docs。锁文件(`pnpm-lock.yaml`、`package-lock.json`、`yarn.lock`、`bun.lockb`)被移出模型分组,归入末尾的 `chore(deps)` 组;纯锁文件变更完全跳过模型调用。
|
|
21
|
+
|
|
22
|
+
## 组合
|
|
23
|
+
|
|
24
|
+
插件注入 `commands`。自定义应用挂载属主与本插件:
|
|
25
|
+
|
|
26
|
+
```yaml
|
|
27
|
+
- id: commands
|
|
28
|
+
name: '@deepseek-ai/dsh-commands'
|
|
29
|
+
- id: command-commit-split
|
|
30
|
+
name: '@dsh-cc/command-commit-split'
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Model Experience
|
|
34
|
+
|
|
35
|
+
斜杠命令的输入与输出不出现在模型请求中。拆分查询是 `blueprint` 通道上的一次性侧查询(未配置时回退到继承的父路由并输出可见提示);返回给用户的方案文本仅为展示层内容。
|
|
36
|
+
|
|
37
|
+
## 已知限制与暂缓事项
|
|
38
|
+
|
|
39
|
+
- **仅提供建议** —— 不执行暂存、提交或改写;当 import 为动态或文件为生成产物时,方案可能不够准确。
|
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Advisory dry-run `/commit-split` command: collects the working-tree change
|
|
3
|
+
* through the shell service (three read-only git commands), asks the
|
|
4
|
+
* deep-reasoning lane (alias 'blueprint') for an ordered atomic-commit split
|
|
5
|
+
* plan, and renders it. It NEVER commits — the user (or the model, explicitly
|
|
6
|
+
* asked) executes proposals one by one.
|
|
7
|
+
* @module @dsh-cc/command-commit-split
|
|
8
|
+
*/
|
|
9
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
10
|
+
import type { CommandInvocation, CommandResult } from '@deepseek-ai/dsh-commands';
|
|
11
|
+
import type { SideQueryOptions, SideQueryResult } from '@dsh-cc/side-query';
|
|
12
|
+
export { buildPlan, hasNonLockfileChanges, parsePlan, orderPlan, rankOf, renderPlan, SCHEMA_ERROR, DEPS_GROUP_MESSAGE } from './plan.ts';
|
|
13
|
+
export type { PlanGroup } from './plan.ts';
|
|
14
|
+
export declare const name = "command-commit-split";
|
|
15
|
+
export declare const inject: string[];
|
|
16
|
+
/** Injected collector seam: `run: (cmd, opts) => Promise<{ stdout }>`. */
|
|
17
|
+
export type GitRun = (command: string, options?: {
|
|
18
|
+
timeout?: number;
|
|
19
|
+
}) => Promise<{
|
|
20
|
+
stdout?: string;
|
|
21
|
+
} | undefined>;
|
|
22
|
+
/** Injectable IO seams for the handler (tests inject fakes here). */
|
|
23
|
+
export interface CommitSplitIO {
|
|
24
|
+
/** Git collector seam — only ever invoked with `git status|diff` reads. */
|
|
25
|
+
run: GitRun;
|
|
26
|
+
/** Side-query seam — defaults to the real `runSideQuery`. */
|
|
27
|
+
runQuery: (ctx: Context, opts: SideQueryOptions) => Promise<SideQueryResult>;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Collect the unified staged+unstaged+untracked changed-file list through the
|
|
31
|
+
* injected `run` seam. Only these three commands are ever issued; all reads
|
|
32
|
+
* complete before the side query is awaited.
|
|
33
|
+
* @param run - the git collector seam.
|
|
34
|
+
* @returns the deduplicated changed paths (repo-relative).
|
|
35
|
+
*/
|
|
36
|
+
export declare function collectChangedPaths(run: GitRun): Promise<string[]>;
|
|
37
|
+
/**
|
|
38
|
+
* Execute `/commit-split`. All git reads complete before the side query is
|
|
39
|
+
* awaited (never interleaved). Dry-run-only: nothing is ever committed.
|
|
40
|
+
* @param ctx - the host context (`shell` service for git, `llm` for the lane).
|
|
41
|
+
* @param invocation - the command invocation.
|
|
42
|
+
* @param io - injectable seams; defaults to the real shell + runSideQuery.
|
|
43
|
+
* @returns the rendered plan, or an error section without a plan.
|
|
44
|
+
*/
|
|
45
|
+
export declare function executeCommitSplit(ctx: Context, invocation: CommandInvocation, io?: CommitSplitIO): Promise<CommandResult>;
|
|
46
|
+
/**
|
|
47
|
+
* Register the `/commit-split` command for every composed command adapter.
|
|
48
|
+
* @param ctx - context carrying the command registry.
|
|
49
|
+
*/
|
|
50
|
+
export declare function apply(ctx: Context): void;
|
|
51
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAClD,OAAO,KAAK,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAA;AAEjF,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAA;AAI3E,OAAO,EAAE,SAAS,EAAE,qBAAqB,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAA;AACxI,YAAY,EAAE,SAAS,EAAE,MAAM,WAAW,CAAA;AAE1C,eAAO,MAAM,IAAI,yBAAyB,CAAA;AAC1C,eAAO,MAAM,MAAM,UAAe,CAAA;AAiBlC,0EAA0E;AAC1E,MAAM,MAAM,MAAM,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,KAAK,OAAO,CAAC;IAAE,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAAC,CAAA;AAElH,qEAAqE;AACrE,MAAM,WAAW,aAAa;IAC5B,2EAA2E;IAC3E,GAAG,EAAE,MAAM,CAAA;IACX,6DAA6D;IAC7D,QAAQ,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,gBAAgB,KAAK,OAAO,CAAC,eAAe,CAAC,CAAA;CAC7E;AAOD;;;;;;GAMG;AACH,wBAAsB,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAuBxE;AAYD;;;;;;;GAOG;AACH,wBAAsB,kBAAkB,CACtC,GAAG,EAAE,OAAO,EACZ,UAAU,EAAE,iBAAiB,EAC7B,EAAE,GAAE,aAA8B,GACjC,OAAO,CAAC,aAAa,CAAC,CA2BxB;AAkBD;;;GAGG;AACH,wBAAgB,KAAK,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI,CAWxC"}
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Advisory dry-run `/commit-split` command: collects the working-tree change
|
|
3
|
+
* through the shell service (three read-only git commands), asks the
|
|
4
|
+
* deep-reasoning lane (alias 'blueprint') for an ordered atomic-commit split
|
|
5
|
+
* plan, and renders it. It NEVER commits — the user (or the model, explicitly
|
|
6
|
+
* asked) executes proposals one by one.
|
|
7
|
+
* @module @dsh-cc/command-commit-split
|
|
8
|
+
*/
|
|
9
|
+
import { helpable } from '@dsh-cc/command-usage';
|
|
10
|
+
import { runSideQuery } from '@dsh-cc/side-query';
|
|
11
|
+
import { buildPlan, hasNonLockfileChanges, renderPlan, SPLIT_SYSTEM_PROMPT } from "./plan.js";
|
|
12
|
+
export { buildPlan, hasNonLockfileChanges, parsePlan, orderPlan, rankOf, renderPlan, SCHEMA_ERROR, DEPS_GROUP_MESSAGE } from "./plan.js";
|
|
13
|
+
export const name = 'command-commit-split';
|
|
14
|
+
export const inject = ['commands'];
|
|
15
|
+
/** Git wall-clock budget for each read (pinned: 5s). */
|
|
16
|
+
const GIT_TIMEOUT_MS = 5000;
|
|
17
|
+
/** The deep-reasoning lane alias (plan C5). */
|
|
18
|
+
const ALIAS = 'blueprint';
|
|
19
|
+
/** The exact visible note printed when the alias is unconfigured. */
|
|
20
|
+
const INHERITED_NOTE = 'note: alias "blueprint" unconfigured; split run on the main model route';
|
|
21
|
+
/** The three exact read-only git commands (plan C5, pinned). */
|
|
22
|
+
const GIT_STATUS = 'git status --porcelain';
|
|
23
|
+
const GIT_NUMSTAT_CACHED = 'git diff --cached --numstat';
|
|
24
|
+
const GIT_NUMSTAT = 'git diff --numstat';
|
|
25
|
+
/**
|
|
26
|
+
* Collect the unified staged+unstaged+untracked changed-file list through the
|
|
27
|
+
* injected `run` seam. Only these three commands are ever issued; all reads
|
|
28
|
+
* complete before the side query is awaited.
|
|
29
|
+
* @param run - the git collector seam.
|
|
30
|
+
* @returns the deduplicated changed paths (repo-relative).
|
|
31
|
+
*/
|
|
32
|
+
export async function collectChangedPaths(run) {
|
|
33
|
+
const [status, numstatCached, numstat] = await Promise.all([
|
|
34
|
+
run(GIT_STATUS, { timeout: GIT_TIMEOUT_MS }),
|
|
35
|
+
run(GIT_NUMSTAT_CACHED, { timeout: GIT_TIMEOUT_MS }),
|
|
36
|
+
run(GIT_NUMSTAT, { timeout: GIT_TIMEOUT_MS }),
|
|
37
|
+
]);
|
|
38
|
+
const paths = new Set();
|
|
39
|
+
for (const stdout of [status?.stdout, numstatCached?.stdout, numstat?.stdout]) {
|
|
40
|
+
for (const line of (stdout ?? '').split('\n')) {
|
|
41
|
+
const trimmed = line.trim();
|
|
42
|
+
if (trimmed === '')
|
|
43
|
+
continue;
|
|
44
|
+
// `git status --porcelain` rows: `XY path` / `XY orig -> path`.
|
|
45
|
+
// `git diff --numstat` rows: `add\tdeleted\tpath`.
|
|
46
|
+
if (/^[ACDMRTUX?!]{2} /u.test(trimmed)) {
|
|
47
|
+
const path = trimmed.slice(3).split(' -> ').pop() ?? '';
|
|
48
|
+
if (path !== '')
|
|
49
|
+
paths.add(path);
|
|
50
|
+
}
|
|
51
|
+
else if (/^\d+\t\d+\t/u.test(trimmed)) {
|
|
52
|
+
const path = trimmed.split('\t')[2] ?? '';
|
|
53
|
+
if (path !== '')
|
|
54
|
+
paths.add(path);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return [...paths];
|
|
59
|
+
}
|
|
60
|
+
/** Build the user prompt listing the changed paths for the split query. */
|
|
61
|
+
function splitPrompt(changedPaths) {
|
|
62
|
+
return [
|
|
63
|
+
'Changed files (unified staged+unstaged+untracked list):',
|
|
64
|
+
...changedPaths.map(path => `- ${path}`),
|
|
65
|
+
'',
|
|
66
|
+
'Return the STRICT JSON split plan now.',
|
|
67
|
+
].join('\n');
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Execute `/commit-split`. All git reads complete before the side query is
|
|
71
|
+
* awaited (never interleaved). Dry-run-only: nothing is ever committed.
|
|
72
|
+
* @param ctx - the host context (`shell` service for git, `llm` for the lane).
|
|
73
|
+
* @param invocation - the command invocation.
|
|
74
|
+
* @param io - injectable seams; defaults to the real shell + runSideQuery.
|
|
75
|
+
* @returns the rendered plan, or an error section without a plan.
|
|
76
|
+
*/
|
|
77
|
+
export async function executeCommitSplit(ctx, invocation, io = defaultIO(ctx)) {
|
|
78
|
+
const changedPaths = await collectChangedPaths(io.run);
|
|
79
|
+
// Deterministic shortcut: lockfile-only (or empty) trees need no model call.
|
|
80
|
+
if (!hasNonLockfileChanges(changedPaths)) {
|
|
81
|
+
if (changedPaths.length === 0) {
|
|
82
|
+
return { kind: 'success', text: 'nothing to split: the working tree is clean' };
|
|
83
|
+
}
|
|
84
|
+
const built = buildPlan('[]', changedPaths);
|
|
85
|
+
return 'plan' in built
|
|
86
|
+
? { kind: 'success', text: renderPlan(built.plan) }
|
|
87
|
+
: { kind: 'error', text: built.error };
|
|
88
|
+
}
|
|
89
|
+
const result = await io.runQuery(ctx, {
|
|
90
|
+
agent: invocation.agent,
|
|
91
|
+
alias: ALIAS,
|
|
92
|
+
system: SPLIT_SYSTEM_PROMPT,
|
|
93
|
+
prompt: splitPrompt(changedPaths),
|
|
94
|
+
// Splitting is not cost-sensitive; give the deep lane room.
|
|
95
|
+
maxTokens: 2048,
|
|
96
|
+
});
|
|
97
|
+
const lines = [];
|
|
98
|
+
if (result.ok && result.inheritedRoute === true)
|
|
99
|
+
lines.push(INHERITED_NOTE);
|
|
100
|
+
if (!result.ok)
|
|
101
|
+
return { kind: 'error', text: `error: split query failed (${result.reason})` };
|
|
102
|
+
const built = buildPlan(result.text, changedPaths);
|
|
103
|
+
if ('error' in built)
|
|
104
|
+
return { kind: 'success', text: [...lines, built.error].join('\n') };
|
|
105
|
+
lines.push(renderPlan(built.plan));
|
|
106
|
+
return { kind: 'success', text: lines.join('\n') };
|
|
107
|
+
}
|
|
108
|
+
/** Default IO: the mounted shell service's run/exec and the real side query. */
|
|
109
|
+
function defaultIO(ctx) {
|
|
110
|
+
return {
|
|
111
|
+
run: gitRunFromShell(ctx),
|
|
112
|
+
runQuery: runSideQuery,
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
/** Resolve the shell service's `run` (preferred) or `exec` into a GitRun. */
|
|
116
|
+
function gitRunFromShell(ctx) {
|
|
117
|
+
const shell = ctx.get('shell');
|
|
118
|
+
const bound = shell?.run?.bind(shell) ?? shell?.exec?.bind(shell);
|
|
119
|
+
if (bound === undefined)
|
|
120
|
+
return async () => ({ stdout: '' });
|
|
121
|
+
return bound;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Register the `/commit-split` command for every composed command adapter.
|
|
125
|
+
* @param ctx - context carrying the command registry.
|
|
126
|
+
*/
|
|
127
|
+
export function apply(ctx) {
|
|
128
|
+
ctx.commands.register(helpable({
|
|
129
|
+
name: 'commit-split',
|
|
130
|
+
description: 'propose an ordered atomic-commit split of the working tree (dry-run only)',
|
|
131
|
+
input: { hint: 'renders the plan; never commits' },
|
|
132
|
+
handler: (invocation) => executeCommitSplit(ctx, invocation),
|
|
133
|
+
}, {
|
|
134
|
+
notes: [
|
|
135
|
+
'dry-run only — proposals are executed one by one by you (or the model, if you explicitly ask)',
|
|
136
|
+
],
|
|
137
|
+
}));
|
|
138
|
+
}
|
|
139
|
+
//# sourceMappingURL=index.js.map
|
package/lib/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/lib/plan.d.ts
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure plan logic for `/commit-split`: validation of the model's STRICT JSON
|
|
3
|
+
* plan, dependency-cycle detection (topological, in the command — never in
|
|
4
|
+
* the model), source > test > docs ranking, lockfile exclusion into a
|
|
5
|
+
* trailing `chore(deps)` group, and deterministic rendering.
|
|
6
|
+
* @module @dsh-cc/command-commit-split/plan
|
|
7
|
+
*/
|
|
8
|
+
/** Exact schema-error string pinned by the design (plan C5). */
|
|
9
|
+
export declare const SCHEMA_ERROR = "error: model output did not match the plan schema";
|
|
10
|
+
/** Exact cycle-error prefix pinned by the design (plan C5). */
|
|
11
|
+
export declare const CYCLE_ERROR_PREFIX = "error: dependency cycle among groups: ";
|
|
12
|
+
/** One proposed atomic commit. */
|
|
13
|
+
export interface PlanGroup {
|
|
14
|
+
/** One-line commit message (≤ 72 chars, pinned by the prompt). */
|
|
15
|
+
readonly message: string;
|
|
16
|
+
/** Unified staged+unstaged file paths belonging to this commit. */
|
|
17
|
+
readonly files: readonly string[];
|
|
18
|
+
/** `A → B` pairs between group messages: A depends on B (B first). */
|
|
19
|
+
readonly dependencyEdges: readonly string[];
|
|
20
|
+
}
|
|
21
|
+
/** The trailing lockfile-only group message, pinned by the design. */
|
|
22
|
+
export declare const DEPS_GROUP_MESSAGE = "chore(deps)";
|
|
23
|
+
/**
|
|
24
|
+
* File classification for the ranking rule (source > test > docs).
|
|
25
|
+
* @param path - repo-relative file path.
|
|
26
|
+
*/
|
|
27
|
+
export declare function rankOf(path: string): 0 | 1 | 2;
|
|
28
|
+
/**
|
|
29
|
+
* Validate the model output against the pinned STRICT schema: an array of
|
|
30
|
+
* `{ message, files, dependencyEdges }` where every file is a changed path
|
|
31
|
+
* and every edge endpoint is a group message. Anything else → schema error.
|
|
32
|
+
* @param text - raw model output.
|
|
33
|
+
* @param changedPaths - the unified changed-file list collected from git.
|
|
34
|
+
* @returns the validated groups, or `undefined` on schema mismatch.
|
|
35
|
+
*/
|
|
36
|
+
export declare function parsePlan(text: string, changedPaths: readonly string[]): PlanGroup[] | undefined;
|
|
37
|
+
/**
|
|
38
|
+
* Detect a dependency cycle over the returned edges and, when one exists,
|
|
39
|
+
* render the pinned error naming the cycle path via group messages.
|
|
40
|
+
* @param groups - validated plan groups.
|
|
41
|
+
* @returns the cycle error string, or `undefined` when acyclic.
|
|
42
|
+
*/
|
|
43
|
+
export declare function findCycle(groups: readonly PlanGroup[]): string | undefined;
|
|
44
|
+
/**
|
|
45
|
+
* Order the plan: dependency-first (Kahn's algorithm over `A → B` edges,
|
|
46
|
+
* B committed before A) with source > test > docs as the deterministic
|
|
47
|
+
* tie-break (a group ranks by its highest-ranked file).
|
|
48
|
+
* @param groups - validated, acyclic plan groups.
|
|
49
|
+
* @returns the ordered plan.
|
|
50
|
+
*/
|
|
51
|
+
export declare function orderPlan(groups: readonly PlanGroup[]): PlanGroup[];
|
|
52
|
+
/** True when at least one changed path is not a lockfile. */
|
|
53
|
+
export declare function hasNonLockfileChanges(changedPaths: readonly string[]): boolean;
|
|
54
|
+
/**
|
|
55
|
+
* Build the full plan for rendering: strip lockfiles out of the model groups,
|
|
56
|
+
* append the trailing `chore(deps)` group when lockfiles are present, and
|
|
57
|
+
* order dependency-first. Returns an error string for schema or cycle
|
|
58
|
+
* failures — in both cases no plan is emitted.
|
|
59
|
+
* @param modelText - raw model output.
|
|
60
|
+
* @param changedPaths - unified changed-file list from the collector.
|
|
61
|
+
* @returns `{ error }` or `{ plan }`, exactly one of the two.
|
|
62
|
+
*/
|
|
63
|
+
export declare function buildPlan(modelText: string, changedPaths: readonly string[]): {
|
|
64
|
+
error: string;
|
|
65
|
+
} | {
|
|
66
|
+
plan: readonly PlanGroup[];
|
|
67
|
+
};
|
|
68
|
+
/**
|
|
69
|
+
* Render the final advisory text. Dry-run-only: the footer states the
|
|
70
|
+
* declared heuristic and that nothing was committed.
|
|
71
|
+
* @param plan - ordered plan groups.
|
|
72
|
+
* @returns the multi-line advisory output.
|
|
73
|
+
*/
|
|
74
|
+
export declare function renderPlan(plan: readonly PlanGroup[]): string;
|
|
75
|
+
/** System prompt for the deep-reasoning lane (alias 'blueprint'). */
|
|
76
|
+
export declare const SPLIT_SYSTEM_PROMPT: string;
|
|
77
|
+
//# sourceMappingURL=plan.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plan.d.ts","sourceRoot":"","sources":["../src/plan.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,gEAAgE;AAChE,eAAO,MAAM,YAAY,sDAAsD,CAAA;AAC/E,+DAA+D;AAC/D,eAAO,MAAM,kBAAkB,2CAA2C,CAAA;AAE1E,kCAAkC;AAClC,MAAM,WAAW,SAAS;IACxB,kEAAkE;IAClE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,mEAAmE;IACnE,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAA;IACjC,sEAAsE;IACtE,QAAQ,CAAC,eAAe,EAAE,SAAS,MAAM,EAAE,CAAA;CAC5C;AAKD,sEAAsE;AACtE,eAAO,MAAM,kBAAkB,gBAAgB,CAAA;AAI/C;;;GAGG;AACH,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAI9C;AAuBD;;;;;;;GAOG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,YAAY,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,EAAE,GAAG,SAAS,CAwBhG;AAQD;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,MAAM,EAAE,SAAS,SAAS,EAAE,GAAG,MAAM,GAAG,SAAS,CAiC1E;AAED;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,MAAM,EAAE,SAAS,SAAS,EAAE,GAAG,SAAS,EAAE,CAkBnE;AAED,6DAA6D;AAC7D,wBAAgB,qBAAqB,CAAC,YAAY,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAE9E;AAED;;;;;;;;GAQG;AACH,wBAAgB,SAAS,CAAC,SAAS,EAAE,MAAM,EAAE,YAAY,EAAE,SAAS,MAAM,EAAE,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,SAAS,SAAS,EAAE,CAAA;CAAE,CAWhI;AASD;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,SAAS,SAAS,EAAE,GAAG,MAAM,CAY7D;AAED,qEAAqE;AACrE,eAAO,MAAM,mBAAmB,QAWrB,CAAA"}
|
package/lib/plan.js
ADDED
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure plan logic for `/commit-split`: validation of the model's STRICT JSON
|
|
3
|
+
* plan, dependency-cycle detection (topological, in the command — never in
|
|
4
|
+
* the model), source > test > docs ranking, lockfile exclusion into a
|
|
5
|
+
* trailing `chore(deps)` group, and deterministic rendering.
|
|
6
|
+
* @module @dsh-cc/command-commit-split/plan
|
|
7
|
+
*/
|
|
8
|
+
/** Exact schema-error string pinned by the design (plan C5). */
|
|
9
|
+
export const SCHEMA_ERROR = 'error: model output did not match the plan schema';
|
|
10
|
+
/** Exact cycle-error prefix pinned by the design (plan C5). */
|
|
11
|
+
export const CYCLE_ERROR_PREFIX = 'error: dependency cycle among groups: ';
|
|
12
|
+
/** Files that never join a model group; they become the trailing deps group. */
|
|
13
|
+
const LOCKFILES = new Set(['pnpm-lock.yaml', 'package-lock.json', 'yarn.lock', 'bun.lockb']);
|
|
14
|
+
/** The trailing lockfile-only group message, pinned by the design. */
|
|
15
|
+
export const DEPS_GROUP_MESSAGE = 'chore(deps)';
|
|
16
|
+
const EDGE_SEPARATOR = ' → ';
|
|
17
|
+
/**
|
|
18
|
+
* File classification for the ranking rule (source > test > docs).
|
|
19
|
+
* @param path - repo-relative file path.
|
|
20
|
+
*/
|
|
21
|
+
export function rankOf(path) {
|
|
22
|
+
if (/(^|\/)(tests?|__tests__)\//u.test(path) || /\.(test|spec)\.[cm]?[jt]sx?$/u.test(path))
|
|
23
|
+
return 1;
|
|
24
|
+
if (/\.md$/iu.test(path) || /(^|\/)docs\//u.test(path))
|
|
25
|
+
return 2;
|
|
26
|
+
return 0;
|
|
27
|
+
}
|
|
28
|
+
/** Extract the JSON array from the model text, tolerating a markdown fence. */
|
|
29
|
+
function extractJson(text) {
|
|
30
|
+
const trimmed = text.trim();
|
|
31
|
+
const fenced = /^```(?:json)?\s*\n([\s\S]*?)\n?```$/u.exec(trimmed);
|
|
32
|
+
const raw = fenced === null ? trimmed : fenced[1] ?? '';
|
|
33
|
+
try {
|
|
34
|
+
return JSON.parse(raw);
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
return undefined;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
/** Structural guard for one edge: exactly one `A → B` separator, non-empty ends. */
|
|
41
|
+
function isEdge(value) {
|
|
42
|
+
if (typeof value !== 'string')
|
|
43
|
+
return false;
|
|
44
|
+
const parts = value.split(EDGE_SEPARATOR);
|
|
45
|
+
return parts.length === 2
|
|
46
|
+
&& parts[0] !== undefined && parts[0].trim() !== ''
|
|
47
|
+
&& parts[1] !== undefined && parts[1].trim() !== '';
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Validate the model output against the pinned STRICT schema: an array of
|
|
51
|
+
* `{ message, files, dependencyEdges }` where every file is a changed path
|
|
52
|
+
* and every edge endpoint is a group message. Anything else → schema error.
|
|
53
|
+
* @param text - raw model output.
|
|
54
|
+
* @param changedPaths - the unified changed-file list collected from git.
|
|
55
|
+
* @returns the validated groups, or `undefined` on schema mismatch.
|
|
56
|
+
*/
|
|
57
|
+
export function parsePlan(text, changedPaths) {
|
|
58
|
+
const parsed = extractJson(text);
|
|
59
|
+
if (!Array.isArray(parsed))
|
|
60
|
+
return undefined;
|
|
61
|
+
const known = new Set(changedPaths);
|
|
62
|
+
const groups = [];
|
|
63
|
+
const messages = new Set();
|
|
64
|
+
for (const entry of parsed) {
|
|
65
|
+
if (typeof entry !== 'object' || entry === null)
|
|
66
|
+
return undefined;
|
|
67
|
+
const { message, files, dependencyEdges } = entry;
|
|
68
|
+
if (typeof message !== 'string' || message.trim() === '' || message.includes('\n'))
|
|
69
|
+
return undefined;
|
|
70
|
+
if (!Array.isArray(files) || files.some(f => typeof f !== 'string'))
|
|
71
|
+
return undefined;
|
|
72
|
+
if (!Array.isArray(dependencyEdges) || !dependencyEdges.every(isEdge))
|
|
73
|
+
return undefined;
|
|
74
|
+
if (!files.every(f => known.has(f)))
|
|
75
|
+
return undefined;
|
|
76
|
+
if (messages.has(message))
|
|
77
|
+
return undefined;
|
|
78
|
+
messages.add(message);
|
|
79
|
+
groups.push({ message, files, dependencyEdges });
|
|
80
|
+
}
|
|
81
|
+
for (const group of groups) {
|
|
82
|
+
for (const edge of group.dependencyEdges) {
|
|
83
|
+
const [from, to] = edge.split(EDGE_SEPARATOR);
|
|
84
|
+
if (!messages.has(from ?? '') || !messages.has(to ?? ''))
|
|
85
|
+
return undefined;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return groups;
|
|
89
|
+
}
|
|
90
|
+
/** Drop lockfiles from a group's file list; returns `undefined` when it empties. */
|
|
91
|
+
function stripLockfiles(group) {
|
|
92
|
+
const files = group.files.filter(f => !LOCKFILES.has(f));
|
|
93
|
+
return files.length === 0 ? undefined : { ...group, files };
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Detect a dependency cycle over the returned edges and, when one exists,
|
|
97
|
+
* render the pinned error naming the cycle path via group messages.
|
|
98
|
+
* @param groups - validated plan groups.
|
|
99
|
+
* @returns the cycle error string, or `undefined` when acyclic.
|
|
100
|
+
*/
|
|
101
|
+
export function findCycle(groups) {
|
|
102
|
+
const byMessage = new Map(groups.map(g => [g.message, g]));
|
|
103
|
+
const adjacency = new Map();
|
|
104
|
+
for (const group of groups) {
|
|
105
|
+
adjacency.set(group.message, group.dependencyEdges
|
|
106
|
+
.map(edge => edge.split(EDGE_SEPARATOR)[1] ?? '')
|
|
107
|
+
.filter(to => byMessage.has(to)));
|
|
108
|
+
}
|
|
109
|
+
// Iterative DFS coloring: 1 = in-stack, 2 = settled.
|
|
110
|
+
const color = new Map();
|
|
111
|
+
const path = [];
|
|
112
|
+
const visit = (node) => {
|
|
113
|
+
const state = color.get(node);
|
|
114
|
+
if (state === 1) {
|
|
115
|
+
const start = path.indexOf(node);
|
|
116
|
+
return [...path.slice(start), node].join(EDGE_SEPARATOR);
|
|
117
|
+
}
|
|
118
|
+
if (state === 2)
|
|
119
|
+
return undefined;
|
|
120
|
+
color.set(node, 1);
|
|
121
|
+
path.push(node);
|
|
122
|
+
for (const next of adjacency.get(node) ?? []) {
|
|
123
|
+
const cycle = visit(next);
|
|
124
|
+
if (cycle !== undefined)
|
|
125
|
+
return cycle;
|
|
126
|
+
}
|
|
127
|
+
path.pop();
|
|
128
|
+
color.set(node, 2);
|
|
129
|
+
return undefined;
|
|
130
|
+
};
|
|
131
|
+
for (const group of groups) {
|
|
132
|
+
const cycle = visit(group.message);
|
|
133
|
+
if (cycle !== undefined)
|
|
134
|
+
return CYCLE_ERROR_PREFIX + cycle;
|
|
135
|
+
}
|
|
136
|
+
return undefined;
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Order the plan: dependency-first (Kahn's algorithm over `A → B` edges,
|
|
140
|
+
* B committed before A) with source > test > docs as the deterministic
|
|
141
|
+
* tie-break (a group ranks by its highest-ranked file).
|
|
142
|
+
* @param groups - validated, acyclic plan groups.
|
|
143
|
+
* @returns the ordered plan.
|
|
144
|
+
*/
|
|
145
|
+
export function orderPlan(groups) {
|
|
146
|
+
const remaining = [...groups];
|
|
147
|
+
const committed = new Set();
|
|
148
|
+
const ordered = [];
|
|
149
|
+
const depsOf = (group) => group.dependencyEdges
|
|
150
|
+
.map(edge => edge.split(EDGE_SEPARATOR)[1] ?? '')
|
|
151
|
+
.filter(to => remaining.some(g => g.message === to));
|
|
152
|
+
while (remaining.length > 0) {
|
|
153
|
+
const ready = remaining.filter(g => depsOf(g).every(dep => committed.has(dep)));
|
|
154
|
+
// Acyclicity is checked before ordering, so `ready` is never empty here.
|
|
155
|
+
const next = ready.reduce((best, g) => Math.min(...g.files.map(rankOf)) < Math.min(...best.files.map(rankOf)) ? g : best);
|
|
156
|
+
ordered.push(next);
|
|
157
|
+
committed.add(next.message);
|
|
158
|
+
remaining.splice(remaining.indexOf(next), 1);
|
|
159
|
+
}
|
|
160
|
+
return ordered;
|
|
161
|
+
}
|
|
162
|
+
/** True when at least one changed path is not a lockfile. */
|
|
163
|
+
export function hasNonLockfileChanges(changedPaths) {
|
|
164
|
+
return changedPaths.some(p => !LOCKFILES.has(p));
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Build the full plan for rendering: strip lockfiles out of the model groups,
|
|
168
|
+
* append the trailing `chore(deps)` group when lockfiles are present, and
|
|
169
|
+
* order dependency-first. Returns an error string for schema or cycle
|
|
170
|
+
* failures — in both cases no plan is emitted.
|
|
171
|
+
* @param modelText - raw model output.
|
|
172
|
+
* @param changedPaths - unified changed-file list from the collector.
|
|
173
|
+
* @returns `{ error }` or `{ plan }`, exactly one of the two.
|
|
174
|
+
*/
|
|
175
|
+
export function buildPlan(modelText, changedPaths) {
|
|
176
|
+
const parsed = parsePlan(modelText, changedPaths);
|
|
177
|
+
if (parsed === undefined)
|
|
178
|
+
return { error: SCHEMA_ERROR };
|
|
179
|
+
const lockfiles = changedPaths.filter(p => LOCKFILES.has(p));
|
|
180
|
+
const kept = parsed
|
|
181
|
+
.map(stripLockfiles)
|
|
182
|
+
.filter((g) => g !== undefined);
|
|
183
|
+
if (lockfiles.length > 0)
|
|
184
|
+
kept.push({ message: DEPS_GROUP_MESSAGE, files: lockfiles, dependencyEdges: [] });
|
|
185
|
+
const cycle = findCycle(kept);
|
|
186
|
+
if (cycle !== undefined)
|
|
187
|
+
return { error: cycle };
|
|
188
|
+
return { plan: orderPlan(kept) };
|
|
189
|
+
}
|
|
190
|
+
/** Render one group's block of the plan text. */
|
|
191
|
+
function renderGroup(group, index) {
|
|
192
|
+
const lines = [`${index + 1}. ${group.message}`, ...group.files.map(f => ` - ${f}`)];
|
|
193
|
+
for (const edge of group.dependencyEdges)
|
|
194
|
+
lines.push(` ${edge}`);
|
|
195
|
+
return lines.join('\n');
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Render the final advisory text. Dry-run-only: the footer states the
|
|
199
|
+
* declared heuristic and that nothing was committed.
|
|
200
|
+
* @param plan - ordered plan groups.
|
|
201
|
+
* @returns the multi-line advisory output.
|
|
202
|
+
*/
|
|
203
|
+
export function renderPlan(plan) {
|
|
204
|
+
const lines = [
|
|
205
|
+
'proposed split plan (dry-run — nothing was committed):',
|
|
206
|
+
'',
|
|
207
|
+
...plan.map(renderGroup),
|
|
208
|
+
'',
|
|
209
|
+
'dependency heuristic (declared): shared top-level directory plus',
|
|
210
|
+
'import-reference overlap between changed files; ranking source > test > docs;',
|
|
211
|
+
'lockfiles are excluded into the trailing chore(deps) group. Execute the',
|
|
212
|
+
'proposals one by one if you agree with the split.',
|
|
213
|
+
];
|
|
214
|
+
return lines.join('\n');
|
|
215
|
+
}
|
|
216
|
+
/** System prompt for the deep-reasoning lane (alias 'blueprint'). */
|
|
217
|
+
export const SPLIT_SYSTEM_PROMPT = [
|
|
218
|
+
'You split a mixed working-tree change into ordered atomic commits.',
|
|
219
|
+
'Signals to use: shared top-level directory, and textual import-reference',
|
|
220
|
+
'overlap between changed files (an edge A→B exists iff A imports changed',
|
|
221
|
+
'file B; resolve imports relative-first). Rank source above tests above docs.',
|
|
222
|
+
'Lockfiles must never appear in a group. Reply with STRICT JSON ONLY: an',
|
|
223
|
+
'array of objects { "message", "files", "dependencyEdges" } where message is',
|
|
224
|
+
'a one-line commit message of at most 72 characters, files is a subset of the',
|
|
225
|
+
'listed changed paths, and dependencyEdges lists "A → B" strings between group',
|
|
226
|
+
'messages meaning A depends on B (B must be committed first). No markdown,',
|
|
227
|
+
'no commentary — JSON only.',
|
|
228
|
+
].join(' ');
|
|
229
|
+
//# sourceMappingURL=plan.js.map
|
package/lib/plan.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plan.js","sourceRoot":"","sources":["../src/plan.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@dsh-cc/command-commit-split",
|
|
3
|
+
"description": "Advisory dry-run /commit-split command: collects the working-tree diff and asks the deep-reasoning lane for an ordered atomic-commit split plan; never commits",
|
|
4
|
+
"version": "0.8.1",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "git+https://github.com/dsh-cc/dsh-cc.git",
|
|
8
|
+
"directory": "packages/interaction/command-commit-split"
|
|
9
|
+
},
|
|
10
|
+
"type": "module",
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"types": "./lib/index.d.ts",
|
|
14
|
+
"default": "./lib/index.js"
|
|
15
|
+
},
|
|
16
|
+
"./plan": {
|
|
17
|
+
"types": "./lib/plan.d.ts",
|
|
18
|
+
"default": "./lib/plan.js"
|
|
19
|
+
},
|
|
20
|
+
"./src/*": "./src/*",
|
|
21
|
+
"./package.json": "./package.json"
|
|
22
|
+
},
|
|
23
|
+
"files": [
|
|
24
|
+
"lib"
|
|
25
|
+
],
|
|
26
|
+
"license": "Apache-2.0",
|
|
27
|
+
"dependencies": {
|
|
28
|
+
"@dsh-cc/command-usage": "^0.8.1",
|
|
29
|
+
"@dsh-cc/side-query": "^0.8.1"
|
|
30
|
+
},
|
|
31
|
+
"peerDependencies": {
|
|
32
|
+
"@deepseek-ai/cordis": ">=0.1.5-rc.1",
|
|
33
|
+
"@deepseek-ai/dsh-agent": ">=0.1.5-rc.1",
|
|
34
|
+
"@deepseek-ai/dsh-commands": ">=0.1.5-rc.1"
|
|
35
|
+
},
|
|
36
|
+
"devDependencies": {
|
|
37
|
+
"@deepseek-ai/cordis": "link:../../../../deepseek-harness/vendor/cordis",
|
|
38
|
+
"@deepseek-ai/cordis-plugin-loader": "link:../../../../deepseek-harness/vendor/loader",
|
|
39
|
+
"@deepseek-ai/dsh-agent": "link:../../../../deepseek-harness/packages/core/agent",
|
|
40
|
+
"@deepseek-ai/dsh-commands": "link:../../../../deepseek-harness/packages/interaction/commands",
|
|
41
|
+
"@deepseek-ai/dsh-llm": "link:../../../../deepseek-harness/packages/llm/llm",
|
|
42
|
+
"@deepseek-ai/dsh-session": "link:../../../../deepseek-harness/packages/core/session",
|
|
43
|
+
"@deepseek-ai/dsh-scope": "link:../../../../deepseek-harness/packages/core/scope",
|
|
44
|
+
"vitest": "^4.1.8"
|
|
45
|
+
},
|
|
46
|
+
"publishConfig": {
|
|
47
|
+
"access": "public"
|
|
48
|
+
}
|
|
49
|
+
}
|