@gadmin2n/cli 0.0.180 → 0.0.181
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/actions/update.action.js +46 -48
- package/package.json +1 -1
package/actions/update.action.js
CHANGED
|
@@ -32,11 +32,22 @@ const types_1 = require("../lib/template-merge/types");
|
|
|
32
32
|
/* ------------------------------------------------------------------ *
|
|
33
33
|
* Config / constants
|
|
34
34
|
* ------------------------------------------------------------------ */
|
|
35
|
-
const
|
|
36
|
-
const
|
|
37
|
-
const
|
|
38
|
-
const
|
|
39
|
-
|
|
35
|
+
const CODING_AGENT_CONTEXT_REPO_HTTPS = 'https://git.tencent.com/OIT-OMC/gadmin2-coding-agent-context.git';
|
|
36
|
+
const CODING_AGENT_CONTEXT_REPO_SSH = 'git@git.tencent.com:OIT-OMC/gadmin2-coding-agent-context.git';
|
|
37
|
+
const CODING_AGENT_CONTEXT_BRANCH = 'master';
|
|
38
|
+
const CODING_AGENT_SOURCE_SUBDIR = '.';
|
|
39
|
+
/**
|
|
40
|
+
* Top-level entries in the cloned repo that must NOT be mirrored into the
|
|
41
|
+
* target agent dirs:
|
|
42
|
+
* - `.git` — clone metadata, never part of the context payload
|
|
43
|
+
* - `CLAUDE.md` — repo documentation, not part of the synced context
|
|
44
|
+
*/
|
|
45
|
+
const CODING_AGENT_SOURCE_ROOT_EXCLUDES = new Set(['.git', 'CLAUDE.md']);
|
|
46
|
+
const CODING_AGENT_TARGET_DIRS = ['.codebuddy', '.agent', '.claude'];
|
|
47
|
+
/** Human-readable label for the source location in log output. */
|
|
48
|
+
const CODING_AGENT_SOURCE_DISPLAY = CODING_AGENT_SOURCE_SUBDIR === '.'
|
|
49
|
+
? '(repo root)'
|
|
50
|
+
: `${CODING_AGENT_SOURCE_SUBDIR}/`;
|
|
40
51
|
/**
|
|
41
52
|
* Canonical formatting for "failed to materialize the base" errors.
|
|
42
53
|
* All three handlers (handleDiff/handleStatus/handleUpdate) share this so the
|
|
@@ -51,9 +62,9 @@ function formatMaterializeError(schematicsVersion, err) {
|
|
|
51
62
|
* .claude context sync (from remote git repo)
|
|
52
63
|
* ------------------------------------------------------------------ */
|
|
53
64
|
/**
|
|
54
|
-
* Shallow-clone the remote
|
|
55
|
-
* the absolute path to the
|
|
56
|
-
*
|
|
65
|
+
* Shallow-clone the remote coding-agent context repo into a temp dir and
|
|
66
|
+
* return the absolute path to the source root (`CODING_AGENT_SOURCE_SUBDIR`
|
|
67
|
+
* under the clone). Returns null on failure
|
|
57
68
|
* (e.g. no network, repo private, credentials missing, etc.).
|
|
58
69
|
*/
|
|
59
70
|
function fetchClaudeContextRepo(repoUrl, branch) {
|
|
@@ -61,16 +72,7 @@ function fetchClaudeContextRepo(repoUrl, branch) {
|
|
|
61
72
|
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'gadmin-claude-ctx-'));
|
|
62
73
|
try {
|
|
63
74
|
(0, child_process_1.execSync)(`git clone --depth 1 --branch ${branch} ${repoUrl} "${tmpDir}"`, { stdio: 'pipe' });
|
|
64
|
-
const claudeSrc = path.join(tmpDir,
|
|
65
|
-
if (!fs.existsSync(claudeSrc)) {
|
|
66
|
-
// Repo cloned, but the .claude dir is missing — treat as no-op
|
|
67
|
-
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
68
|
-
return null;
|
|
69
|
-
}
|
|
70
|
-
const rootClaudeMdSrc = path.join(tmpDir, 'CLAUDE.md');
|
|
71
|
-
const rootClaudeMd = fs.existsSync(rootClaudeMdSrc)
|
|
72
|
-
? rootClaudeMdSrc
|
|
73
|
-
: null;
|
|
75
|
+
const claudeSrc = path.join(tmpDir, CODING_AGENT_SOURCE_SUBDIR);
|
|
74
76
|
// Caller is responsible for cleaning up the parent tmpDir.
|
|
75
77
|
// We return the inner path; we stash the parent on a property so caller
|
|
76
78
|
// can clean it. To keep things simple, register a process exit cleanup
|
|
@@ -83,7 +85,7 @@ function fetchClaudeContextRepo(repoUrl, branch) {
|
|
|
83
85
|
// ignore
|
|
84
86
|
}
|
|
85
87
|
});
|
|
86
|
-
return { claudeDir: claudeSrc
|
|
88
|
+
return { claudeDir: claudeSrc };
|
|
87
89
|
}
|
|
88
90
|
catch (err) {
|
|
89
91
|
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
@@ -100,15 +102,19 @@ function fetchClaudeContextRepo(repoUrl, branch) {
|
|
|
100
102
|
* relative structure. The remote source is authoritative: existing files in
|
|
101
103
|
* `destDir` are OVERWRITTEN. Files that exist only in `destDir` (instance-only)
|
|
102
104
|
* are left untouched — this is an additive/overwriting sync, never a delete.
|
|
105
|
+
* `excludeTopLevel` names entries at the source root that are skipped
|
|
106
|
+
* entirely (e.g. `.git`, `CLAUDE.md`).
|
|
103
107
|
* Returns counts split between newly-added files and overwritten files.
|
|
104
108
|
*/
|
|
105
|
-
function copyTreeOverwrite(srcDir, destDir) {
|
|
109
|
+
function copyTreeOverwrite(srcDir, destDir, excludeTopLevel) {
|
|
106
110
|
let added = 0;
|
|
107
111
|
let updated = 0;
|
|
108
112
|
function walk(rel) {
|
|
109
113
|
const absSrc = path.join(srcDir, rel);
|
|
110
114
|
const entries = fs.readdirSync(absSrc, { withFileTypes: true });
|
|
111
115
|
for (const entry of entries) {
|
|
116
|
+
if (rel === '' && (excludeTopLevel === null || excludeTopLevel === void 0 ? void 0 : excludeTopLevel.has(entry.name)))
|
|
117
|
+
continue;
|
|
112
118
|
const childRel = rel ? path.join(rel, entry.name) : entry.name;
|
|
113
119
|
const absChildSrc = path.join(srcDir, childRel);
|
|
114
120
|
const absChildDest = path.join(destDir, childRel);
|
|
@@ -139,8 +145,8 @@ function copyTreeOverwrite(srcDir, destDir) {
|
|
|
139
145
|
* Priority (highest first):
|
|
140
146
|
* 1. CLI --coding-context-repo (full URL override)
|
|
141
147
|
* 2. CLI --coding-context-protocol (https | ssh | skip)
|
|
142
|
-
* 3. Env var
|
|
143
|
-
* 4. Env var
|
|
148
|
+
* 3. Env var GADMIN2_CODING_AGENT_CONTEXT_REPO (full URL)
|
|
149
|
+
* 4. Env var GADMIN2_CODING_AGENT_CONTEXT_PROTOCOL (https | ssh | skip)
|
|
144
150
|
* 5. --yes (auto mode): default to built-in HTTPS, no prompt
|
|
145
151
|
* 6. Interactive prompt: pick https / ssh / skip
|
|
146
152
|
*
|
|
@@ -148,7 +154,7 @@ function copyTreeOverwrite(srcDir, destDir) {
|
|
|
148
154
|
*/
|
|
149
155
|
function resolveClaudeContextSource(cliRepo, cliProtocol, autoYes) {
|
|
150
156
|
return __awaiter(this, void 0, void 0, function* () {
|
|
151
|
-
const branch = process.env.
|
|
157
|
+
const branch = process.env.GADMIN2_CODING_AGENT_CONTEXT_BRANCH || CODING_AGENT_CONTEXT_BRANCH;
|
|
152
158
|
// 1. CLI full-URL override
|
|
153
159
|
if (cliRepo) {
|
|
154
160
|
return { repo: cliRepo, branch };
|
|
@@ -158,24 +164,24 @@ function resolveClaudeContextSource(cliRepo, cliProtocol, autoYes) {
|
|
|
158
164
|
if (cliProto === 'skip')
|
|
159
165
|
return null;
|
|
160
166
|
if (cliProto === 'ssh')
|
|
161
|
-
return { repo:
|
|
167
|
+
return { repo: CODING_AGENT_CONTEXT_REPO_SSH, branch };
|
|
162
168
|
if (cliProto === 'https')
|
|
163
|
-
return { repo:
|
|
169
|
+
return { repo: CODING_AGENT_CONTEXT_REPO_HTTPS, branch };
|
|
164
170
|
// 3. Env var full-URL
|
|
165
|
-
const envRepo = process.env.
|
|
171
|
+
const envRepo = process.env.GADMIN2_CODING_AGENT_CONTEXT_REPO;
|
|
166
172
|
if (envRepo)
|
|
167
173
|
return { repo: envRepo, branch };
|
|
168
174
|
// 4. Env var protocol
|
|
169
|
-
const envProto = (process.env.
|
|
175
|
+
const envProto = (process.env.GADMIN2_CODING_AGENT_CONTEXT_PROTOCOL || '').toLowerCase();
|
|
170
176
|
if (envProto === 'skip')
|
|
171
177
|
return null;
|
|
172
178
|
if (envProto === 'ssh')
|
|
173
|
-
return { repo:
|
|
179
|
+
return { repo: CODING_AGENT_CONTEXT_REPO_SSH, branch };
|
|
174
180
|
if (envProto === 'https')
|
|
175
|
-
return { repo:
|
|
181
|
+
return { repo: CODING_AGENT_CONTEXT_REPO_HTTPS, branch };
|
|
176
182
|
// 5. CI / auto-yes mode → silent default
|
|
177
183
|
if (autoYes)
|
|
178
|
-
return { repo:
|
|
184
|
+
return { repo: CODING_AGENT_CONTEXT_REPO_HTTPS, branch };
|
|
179
185
|
// 6. Interactive prompt
|
|
180
186
|
const { proto } = yield inquirer.prompt([
|
|
181
187
|
{
|
|
@@ -183,8 +189,8 @@ function resolveClaudeContextSource(cliRepo, cliProtocol, autoYes) {
|
|
|
183
189
|
name: 'proto',
|
|
184
190
|
message: 'Choose git access method for .claude context sync:',
|
|
185
191
|
choices: [
|
|
186
|
-
{ name: `HTTPS (${
|
|
187
|
-
{ name: `SSH (${
|
|
192
|
+
{ name: `HTTPS (${CODING_AGENT_CONTEXT_REPO_HTTPS})`, value: 'https' },
|
|
193
|
+
{ name: `SSH (${CODING_AGENT_CONTEXT_REPO_SSH})`, value: 'ssh' },
|
|
188
194
|
{ name: 'Skip this stage', value: 'skip' },
|
|
189
195
|
],
|
|
190
196
|
default: 'https',
|
|
@@ -193,8 +199,8 @@ function resolveClaudeContextSource(cliRepo, cliProtocol, autoYes) {
|
|
|
193
199
|
if (proto === 'skip')
|
|
194
200
|
return null;
|
|
195
201
|
if (proto === 'ssh')
|
|
196
|
-
return { repo:
|
|
197
|
-
return { repo:
|
|
202
|
+
return { repo: CODING_AGENT_CONTEXT_REPO_SSH, branch };
|
|
203
|
+
return { repo: CODING_AGENT_CONTEXT_REPO_HTTPS, branch };
|
|
198
204
|
});
|
|
199
205
|
}
|
|
200
206
|
function syncClaudeContext(instanceDir, dryRun, source) {
|
|
@@ -202,14 +208,13 @@ function syncClaudeContext(instanceDir, dryRun, source) {
|
|
|
202
208
|
console.info(chalk.bold('\n═══════════════════════════════════════════════════'));
|
|
203
209
|
console.info(chalk.bold(' Sync .claude context'));
|
|
204
210
|
console.info(chalk.bold('═══════════════════════════════════════════════════'));
|
|
205
|
-
console.info(`${chalk.gray('Source: ')} ${source.repo} (${source.branch}) :: ${
|
|
206
|
-
console.info(`${chalk.gray('Targets:')} ${
|
|
211
|
+
console.info(`${chalk.gray('Source: ')} ${source.repo} (${source.branch}) :: ${CODING_AGENT_SOURCE_DISPLAY}`);
|
|
212
|
+
console.info(`${chalk.gray('Targets:')} ${CODING_AGENT_TARGET_DIRS.map((d) => `${d}/`).join(', ')}\n`);
|
|
207
213
|
if (dryRun) {
|
|
208
214
|
console.info(chalk.gray('(dry-run — no files written. The real run would:'));
|
|
209
215
|
console.info(chalk.gray(` 1. git clone ${source.repo} --branch ${source.branch} --depth 1 (into tmp dir)`));
|
|
210
|
-
console.info(chalk.gray(` 2. Copy <tmp>/${
|
|
211
|
-
console.info(chalk.gray(' 3.
|
|
212
|
-
console.info(chalk.gray(' 4. Files only present in target dirs (instance-only) are kept untouched)\n'));
|
|
216
|
+
console.info(chalk.gray(` 2. Copy <tmp>/${CODING_AGENT_SOURCE_SUBDIR === '.' ? '' : `${CODING_AGENT_SOURCE_SUBDIR}/`}** (excluding .git, CLAUDE.md) → each target dir, OVERWRITING same-named files`));
|
|
217
|
+
console.info(chalk.gray(' 3. Files only present in target dirs (instance-only) are kept untouched)\n'));
|
|
213
218
|
return;
|
|
214
219
|
}
|
|
215
220
|
// Real run: warn the user that same-named files will be overwritten before
|
|
@@ -222,10 +227,10 @@ function syncClaudeContext(instanceDir, dryRun, source) {
|
|
|
222
227
|
if (!fetched) {
|
|
223
228
|
return;
|
|
224
229
|
}
|
|
225
|
-
for (const targetName of
|
|
230
|
+
for (const targetName of CODING_AGENT_TARGET_DIRS) {
|
|
226
231
|
const destDir = path.join(instanceDir, targetName);
|
|
227
232
|
fs.mkdirSync(destDir, { recursive: true });
|
|
228
|
-
const { added, updated } = copyTreeOverwrite(fetched.claudeDir, destDir);
|
|
233
|
+
const { added, updated } = copyTreeOverwrite(fetched.claudeDir, destDir, CODING_AGENT_SOURCE_ROOT_EXCLUDES);
|
|
229
234
|
const summary = [];
|
|
230
235
|
if (added > 0)
|
|
231
236
|
summary.push(`${added} added`);
|
|
@@ -235,13 +240,6 @@ function syncClaudeContext(instanceDir, dryRun, source) {
|
|
|
235
240
|
summary.push('no files');
|
|
236
241
|
console.info(` ${chalk.cyan(targetName + '/')} ${summary.join(' | ')}`);
|
|
237
242
|
}
|
|
238
|
-
// Sync repo-root CLAUDE.md into the project root as AGENTS.md.
|
|
239
|
-
if (fetched.rootClaudeMd) {
|
|
240
|
-
const agentsDest = path.join(instanceDir, 'AGENTS.md');
|
|
241
|
-
const agentsExisted = fs.existsSync(agentsDest);
|
|
242
|
-
fs.copyFileSync(fetched.rootClaudeMd, agentsDest);
|
|
243
|
-
console.info(` ${chalk.cyan('AGENTS.md')} ${agentsExisted ? 'overwritten' : 'added'} (from CLAUDE.md)`);
|
|
244
|
-
}
|
|
245
243
|
console.info();
|
|
246
244
|
});
|
|
247
245
|
}
|