wendkeep 0.75.3 → 0.76.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/CHANGELOG.md +33 -0
- package/README.en.md +4 -1
- package/README.md +4 -1
- package/docs/en/commands/context.md +88 -0
- package/docs/en/commands/getting-started.md +3 -1
- package/docs/en/commands/maintenance-and-diagnostics.md +3 -0
- package/docs/en/commands/worktrees.md +93 -0
- package/docs/pt-BR/commands/context.md +86 -0
- package/docs/pt-BR/commands/getting-started.md +3 -1
- package/docs/pt-BR/commands/maintenance-and-diagnostics.md +2 -0
- package/docs/pt-BR/commands/worktrees.md +91 -0
- package/hooks/flow-protected-policy.mjs +1 -1
- package/hooks/project-scope.mjs +51 -6
- package/package.json +2 -1
- package/packages/cli/src/index.mjs +25 -3
- package/packages/vault/src/index.mjs +1 -0
- package/packages/vault/src/project-vault.mjs +25 -2
- package/packages/vault/src/worktree-metadata.mjs +274 -0
- package/src/context.mjs +297 -0
- package/src/doctor.mjs +8 -0
- package/src/init.mjs +6 -0
- package/src/sync.mjs +4 -1
- package/src/worktree.mjs +708 -0
package/src/context.mjs
ADDED
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
import { spawnSync } from 'node:child_process';
|
|
2
|
+
import { isAbsolute, resolve } from 'node:path';
|
|
3
|
+
import {
|
|
4
|
+
mutateSessionRegistry,
|
|
5
|
+
readSessionRegistry,
|
|
6
|
+
} from '../hooks/obsidian-common.mjs';
|
|
7
|
+
import {
|
|
8
|
+
captureProjectScope,
|
|
9
|
+
compareProjectScopes,
|
|
10
|
+
concurrentScopeConflicts,
|
|
11
|
+
scopeForRegistry,
|
|
12
|
+
} from '../hooks/project-scope.mjs';
|
|
13
|
+
|
|
14
|
+
export const CONTEXT_HELP = `wendkeep context <subcommand>
|
|
15
|
+
|
|
16
|
+
switch <branch> [--create] [--session <id>] [--project <path>] [--vault <path>] [--json]
|
|
17
|
+
|
|
18
|
+
Switches Git branch and the causal session scope together inside the same worktree.
|
|
19
|
+
Without --session, exactly one active session must match the current scope.
|
|
20
|
+
`;
|
|
21
|
+
|
|
22
|
+
const VALUE_OPTIONS = new Set(['--project', '--vault', '--session']);
|
|
23
|
+
const FLAG_OPTIONS = new Set(['--create', '--json']);
|
|
24
|
+
|
|
25
|
+
function contextError(code, message) {
|
|
26
|
+
const error = new Error(message);
|
|
27
|
+
error.code = code;
|
|
28
|
+
return error;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function optionValue(argv, name) {
|
|
32
|
+
const index = argv.indexOf(name);
|
|
33
|
+
if (index >= 0) return argv[index + 1] || '';
|
|
34
|
+
return argv.find((item) => item.startsWith(`${name}=`))?.slice(name.length + 1) || '';
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function positionals(argv) {
|
|
38
|
+
const result = [];
|
|
39
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
40
|
+
const value = argv[index];
|
|
41
|
+
if (VALUE_OPTIONS.has(value)) { index += 1; continue; }
|
|
42
|
+
if ([...VALUE_OPTIONS].some((name) => value.startsWith(`${name}=`))) continue;
|
|
43
|
+
if (FLAG_OPTIONS.has(value)) continue;
|
|
44
|
+
if (value.startsWith('--')) throw contextError('WENDKEEP_CONTEXT_ARGS', `opção desconhecida: ${value}`);
|
|
45
|
+
result.push(value);
|
|
46
|
+
}
|
|
47
|
+
return result;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function validateArgv(argv) {
|
|
51
|
+
const seen = new Set();
|
|
52
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
53
|
+
const value = argv[index];
|
|
54
|
+
if (FLAG_OPTIONS.has(value)) {
|
|
55
|
+
if (seen.has(value)) throw contextError('WENDKEEP_CONTEXT_ARGS', `opção duplicada: ${value}`);
|
|
56
|
+
seen.add(value);
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
if (VALUE_OPTIONS.has(value)) {
|
|
60
|
+
if (seen.has(value)) throw contextError('WENDKEEP_CONTEXT_ARGS', `opção duplicada: ${value}`);
|
|
61
|
+
seen.add(value);
|
|
62
|
+
const next = argv[index + 1];
|
|
63
|
+
if (!next || next.startsWith('--')) throw contextError('WENDKEEP_CONTEXT_ARGS', `${value} requer um valor`);
|
|
64
|
+
index += 1;
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
if (value.startsWith('--')) {
|
|
68
|
+
const name = value.split('=', 1)[0];
|
|
69
|
+
if (!VALUE_OPTIONS.has(name)) throw contextError('WENDKEEP_CONTEXT_ARGS', `opção desconhecida: ${name}`);
|
|
70
|
+
if (seen.has(name)) throw contextError('WENDKEEP_CONTEXT_ARGS', `opção duplicada: ${name}`);
|
|
71
|
+
seen.add(name);
|
|
72
|
+
if (!value.slice(name.length + 1)) throw contextError('WENDKEEP_CONTEXT_ARGS', `${name} requer um valor`);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function vaultOf(argv) {
|
|
78
|
+
const raw = optionValue(argv, '--vault') || process.env.OBSIDIAN_VAULT_PATH;
|
|
79
|
+
if (!raw) throw contextError('WENDKEEP_CONTEXT_VAULT', 'binding de Vault ausente; use --vault <path>');
|
|
80
|
+
return isAbsolute(raw) ? raw : resolve(process.cwd(), raw);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function projectOf(argv) {
|
|
84
|
+
const raw = optionValue(argv, '--project') || process.cwd();
|
|
85
|
+
return isAbsolute(raw) ? raw : resolve(process.cwd(), raw);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function git(projectRoot, args, spawn = spawnSync) {
|
|
89
|
+
const result = spawn('git', args, { cwd: projectRoot, encoding: 'utf8', windowsHide: true });
|
|
90
|
+
if (result.error || result.status !== 0) {
|
|
91
|
+
const detail = String(result.stderr || result.error?.message || 'falhou').trim();
|
|
92
|
+
throw contextError('WENDKEEP_CONTEXT_GIT', `git ${args.join(' ')}: ${detail}`);
|
|
93
|
+
}
|
|
94
|
+
return String(result.stdout || '').trim();
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function actualScope(projectRoot, expected, sessionId, spawn) {
|
|
98
|
+
return captureProjectScope({
|
|
99
|
+
input: { cwd: projectRoot },
|
|
100
|
+
projectRoot: expected?.projectRoot || projectRoot,
|
|
101
|
+
projectId: expected?.projectId || '',
|
|
102
|
+
provider: expected?.provider || '',
|
|
103
|
+
sessionId,
|
|
104
|
+
targetCwd: projectRoot,
|
|
105
|
+
spawn,
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function matchingSessionIds(registry, projectRoot, spawn) {
|
|
110
|
+
const matches = [];
|
|
111
|
+
for (const [sessionId, entry] of Object.entries(registry.sessions || {})) {
|
|
112
|
+
if (entry?.status !== 'active' || entry.project_scope_conflict === true || !entry?.project_scope) continue;
|
|
113
|
+
const actual = actualScope(projectRoot, entry.project_scope, sessionId, spawn);
|
|
114
|
+
if (compareProjectScopes(entry.project_scope, actual).ok) matches.push(sessionId);
|
|
115
|
+
}
|
|
116
|
+
return matches;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function contextRevision(entry) {
|
|
120
|
+
return Number.isSafeInteger(entry?.context_revision) && entry.context_revision >= 0
|
|
121
|
+
? entry.context_revision : 0;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function resolveSessionId(vaultBase, projectRoot, requested, spawn) {
|
|
125
|
+
const registry = readSessionRegistry(vaultBase);
|
|
126
|
+
if (requested) {
|
|
127
|
+
const entry = registry.sessions?.[requested];
|
|
128
|
+
if (!entry || entry.status !== 'active') {
|
|
129
|
+
throw contextError('WENDKEEP_CONTEXT_SESSION', `sessão ativa não encontrada: ${requested}`);
|
|
130
|
+
}
|
|
131
|
+
return { sessionId: requested, revision: contextRevision(entry) };
|
|
132
|
+
}
|
|
133
|
+
const matches = matchingSessionIds(registry, projectRoot, spawn);
|
|
134
|
+
if (matches.length !== 1) {
|
|
135
|
+
throw contextError(
|
|
136
|
+
'WENDKEEP_CONTEXT_AMBIGUOUS',
|
|
137
|
+
`${matches.length} sessões ativas correspondem à scope atual; informe --session <id>.`,
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
return {
|
|
141
|
+
sessionId: matches[0],
|
|
142
|
+
revision: contextRevision(registry.sessions[matches[0]]),
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function rollbackGit(projectRoot, previous, createdBranch, spawn) {
|
|
147
|
+
const args = previous.branch.startsWith('detached:')
|
|
148
|
+
? ['switch', '--detach', previous.head]
|
|
149
|
+
: ['switch', previous.branch];
|
|
150
|
+
git(projectRoot, args, spawn);
|
|
151
|
+
if (createdBranch) git(projectRoot, ['branch', '-D', createdBranch], spawn);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export function switchSessionContext({
|
|
155
|
+
vaultBase,
|
|
156
|
+
projectRoot = process.cwd(),
|
|
157
|
+
branch,
|
|
158
|
+
create = false,
|
|
159
|
+
sessionId = '',
|
|
160
|
+
spawn = spawnSync,
|
|
161
|
+
mutateRegistry = mutateSessionRegistry,
|
|
162
|
+
now = () => new Date(),
|
|
163
|
+
} = {}) {
|
|
164
|
+
const target = String(branch || '').trim();
|
|
165
|
+
if (!target) throw contextError('WENDKEEP_CONTEXT_ARGS', 'switch requer <branch>');
|
|
166
|
+
git(projectRoot, ['check-ref-format', '--branch', target], spawn);
|
|
167
|
+
const selected = resolveSessionId(vaultBase, projectRoot, sessionId, spawn);
|
|
168
|
+
const selectedSessionId = selected.sessionId;
|
|
169
|
+
let switched = false;
|
|
170
|
+
let previous = null;
|
|
171
|
+
|
|
172
|
+
try {
|
|
173
|
+
return mutateRegistry(vaultBase, (registry) => {
|
|
174
|
+
const entry = registry.sessions?.[selectedSessionId];
|
|
175
|
+
if (!entry || entry.status !== 'active') {
|
|
176
|
+
throw contextError('WENDKEEP_CONTEXT_SESSION', `sessão ativa não encontrada: ${selectedSessionId}`);
|
|
177
|
+
}
|
|
178
|
+
if (entry.project_scope_conflict === true || !entry.project_scope) {
|
|
179
|
+
throw contextError('WENDKEEP_CONTEXT_SCOPE_CONFLICT', 'a sessão possui scope ausente ou conflitante');
|
|
180
|
+
}
|
|
181
|
+
const currentRevision = contextRevision(entry);
|
|
182
|
+
if (currentRevision !== selected.revision) {
|
|
183
|
+
throw contextError(
|
|
184
|
+
'WENDKEEP_CONTEXT_CAS_MISMATCH',
|
|
185
|
+
`context_revision mudou de ${selected.revision} para ${currentRevision}; repita com estado fresco`,
|
|
186
|
+
);
|
|
187
|
+
}
|
|
188
|
+
const expected = entry.project_scope;
|
|
189
|
+
const actual = actualScope(projectRoot, expected, selectedSessionId, spawn);
|
|
190
|
+
const comparison = compareProjectScopes(expected, actual);
|
|
191
|
+
if (!comparison.ok) {
|
|
192
|
+
throw contextError(
|
|
193
|
+
'WENDKEEP_CONTEXT_SCOPE_MISMATCH',
|
|
194
|
+
`scope atual diverge da reserva (${comparison.mismatches.join(', ')})`,
|
|
195
|
+
);
|
|
196
|
+
}
|
|
197
|
+
if (actual.branch === target && !create) {
|
|
198
|
+
return {
|
|
199
|
+
status: 'unchanged', session_id: selectedSessionId, branch: target,
|
|
200
|
+
head: actual.head, revision: currentRevision,
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
previous = { branch: actual.branch, head: actual.head };
|
|
205
|
+
git(projectRoot, create ? ['switch', '-c', target] : ['switch', target], spawn);
|
|
206
|
+
switched = true;
|
|
207
|
+
const next = actualScope(projectRoot, expected, selectedSessionId, spawn);
|
|
208
|
+
const identity = compareProjectScopes({ ...expected, branch: next.branch }, next);
|
|
209
|
+
if (!identity.ok || next.branch !== target || next.worktree !== actual.worktree) {
|
|
210
|
+
const mismatches = [...identity.mismatches, ...(next.branch === target ? [] : ['scope.branch'])];
|
|
211
|
+
throw contextError(
|
|
212
|
+
'WENDKEEP_CONTEXT_IDENTITY_CHANGED',
|
|
213
|
+
`a transição saiu da identidade reservada (${[...new Set(mismatches)].join(', ')})`,
|
|
214
|
+
);
|
|
215
|
+
}
|
|
216
|
+
const conflicts = concurrentScopeConflicts(
|
|
217
|
+
next,
|
|
218
|
+
Object.entries(registry.sessions || {}).filter(([, candidate]) => candidate?.status === 'active'),
|
|
219
|
+
selectedSessionId,
|
|
220
|
+
);
|
|
221
|
+
if (conflicts.length) {
|
|
222
|
+
throw contextError(
|
|
223
|
+
'WENDKEEP_CONTEXT_CONFLICT',
|
|
224
|
+
`o destino conflita com ${conflicts.length} contexto(s) ativo(s): ${conflicts.map((item) => item.sessionId).join(', ')}`,
|
|
225
|
+
);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
const revision = currentRevision + 1;
|
|
229
|
+
const at = now().toISOString();
|
|
230
|
+
const transition = {
|
|
231
|
+
revision,
|
|
232
|
+
operation: create ? 'create' : 'switch',
|
|
233
|
+
from: { branch: actual.branch, head: actual.head },
|
|
234
|
+
to: { branch: next.branch, head: next.head },
|
|
235
|
+
worktree: next.worktree,
|
|
236
|
+
at,
|
|
237
|
+
};
|
|
238
|
+
const {
|
|
239
|
+
project_scope_conflict: _conflict,
|
|
240
|
+
project_scope_conflict_fields: _conflictFields,
|
|
241
|
+
project_scope_observed: _observed,
|
|
242
|
+
...preserved
|
|
243
|
+
} = entry;
|
|
244
|
+
registry.sessions[selectedSessionId] = {
|
|
245
|
+
...preserved,
|
|
246
|
+
project_scope: scopeForRegistry(next, { authorizedActions: expected.authorizedActions }),
|
|
247
|
+
context_revision: revision,
|
|
248
|
+
context_transitions: [...(Array.isArray(entry.context_transitions) ? entry.context_transitions : []), transition],
|
|
249
|
+
last_seen: at,
|
|
250
|
+
updated_at: at,
|
|
251
|
+
};
|
|
252
|
+
return {
|
|
253
|
+
status: 'switched', session_id: selectedSessionId, branch: next.branch,
|
|
254
|
+
head: next.head, revision, transition,
|
|
255
|
+
};
|
|
256
|
+
});
|
|
257
|
+
} catch (error) {
|
|
258
|
+
if (switched && previous) {
|
|
259
|
+
try {
|
|
260
|
+
rollbackGit(projectRoot, previous, create ? target : '', spawn);
|
|
261
|
+
} catch (rollbackError) {
|
|
262
|
+
throw contextError(
|
|
263
|
+
'WENDKEEP_CONTEXT_ROLLBACK_FAILED',
|
|
264
|
+
`${error.code || 'WENDKEEP_CONTEXT_FAILED'}: ${error.message}; rollback: ${rollbackError.message}`,
|
|
265
|
+
);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
throw error;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
function output(result, json) {
|
|
273
|
+
if (json) process.stdout.write(`${JSON.stringify(result)}\n`);
|
|
274
|
+
else process.stdout.write(`context ${result.status}: ${result.branch} (session ${result.session_id}; revision ${result.revision})\n`);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
export function runContext(argv = []) {
|
|
278
|
+
try {
|
|
279
|
+
validateArgv(argv);
|
|
280
|
+
const [sub, branch, ...extra] = positionals(argv);
|
|
281
|
+
if (sub !== 'switch' || !branch || extra.length) {
|
|
282
|
+
throw contextError('WENDKEEP_CONTEXT_ARGS', 'use: wendkeep context switch <branch> [--create] [--session <id>]');
|
|
283
|
+
}
|
|
284
|
+
const result = switchSessionContext({
|
|
285
|
+
vaultBase: vaultOf(argv),
|
|
286
|
+
projectRoot: projectOf(argv),
|
|
287
|
+
branch,
|
|
288
|
+
create: argv.includes('--create'),
|
|
289
|
+
sessionId: optionValue(argv, '--session'),
|
|
290
|
+
});
|
|
291
|
+
output(result, argv.includes('--json'));
|
|
292
|
+
return 0;
|
|
293
|
+
} catch (error) {
|
|
294
|
+
process.stderr.write(`wendkeep context: ${error.code || 'WENDKEEP_CONTEXT_FAILED'}: ${error.message}\n`);
|
|
295
|
+
return 2;
|
|
296
|
+
}
|
|
297
|
+
}
|
package/src/doctor.mjs
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
// harness integrity check (hooks/harness-doctor.mjs). Exits 1 on any error.
|
|
3
3
|
import { resolve } from 'node:path';
|
|
4
4
|
import { checkHarness, checkVaultLinks, checkSessionActivity, checkStackedFrontmatter, renderStackedFrontmatterLines, checkUnpricedModels, renderUnpricedModelLines, checkStaleDerivedSections, renderStaleDerivedSectionLines, checkSessionObservability, renderSessionObservabilityLines } from '../hooks/harness-doctor.mjs';
|
|
5
|
+
import { diagnoseManagedWorktrees } from './worktree.mjs';
|
|
5
6
|
import { runVaultHealth } from '../hooks/vault-health.mjs';
|
|
6
7
|
import { checkSyncDefs } from './sync-defs.mjs';
|
|
7
8
|
import { resolveProjectVault } from './project-vault.mjs';
|
|
@@ -133,6 +134,12 @@ export function runDoctor(argv) {
|
|
|
133
134
|
for (const item of repairable) process.stdout.write(` → ${item}\n`);
|
|
134
135
|
for (const w of warnings) process.stdout.write(` ! ${w}\n`);
|
|
135
136
|
|
|
137
|
+
const worktrees = diagnoseManagedWorktrees({ startDir: projectRoot });
|
|
138
|
+
process.stdout.write(`\n[worktrees] ${worktrees.initialized ? `${worktrees.issues.length} problema(s)` : 'não inicializado'}\n`);
|
|
139
|
+
for (const issue of worktrees.issues) {
|
|
140
|
+
process.stdout.write(` → ${issue.slug}: ${issue.errorCode} — ${issue.repair}\n`);
|
|
141
|
+
}
|
|
142
|
+
|
|
136
143
|
// 3. Link/graph health — órfãos que o grafo do Obsidian mostraria, com o comando de reparo.
|
|
137
144
|
const links = checkVaultLinks(vaultBase);
|
|
138
145
|
const graphLabel = links.graphColors === true ? 'com cores' : links.graphColors === false ? 'sem cores' : 'sem graph.json';
|
|
@@ -181,6 +188,7 @@ export function runDoctor(argv) {
|
|
|
181
188
|
|| attention.length
|
|
182
189
|
|| repairable.length
|
|
183
190
|
|| warnings.length
|
|
191
|
+
|| worktrees.issues.length
|
|
184
192
|
|| links.derivedOrphans
|
|
185
193
|
|| links.artifactOrphans
|
|
186
194
|
|| links.graphColors === false
|
package/src/init.mjs
CHANGED
|
@@ -40,6 +40,7 @@ import { seedDotcontext, globalHasDotcontext, resolveDotcontextSkipMcp, renderSe
|
|
|
40
40
|
import { adoptSpecsState, ensureSpecsReadme, SPECS_STATE_FILE } from '../hooks/spec-core.mjs';
|
|
41
41
|
import { bindProjectVault, readProjectBinding } from './project-vault.mjs';
|
|
42
42
|
import { seedMemoryV2 } from './memory.mjs';
|
|
43
|
+
import { installVscodeWorktreeTasks } from './worktree.mjs';
|
|
43
44
|
import {
|
|
44
45
|
DEFAULT_OPERATING_PROFILE,
|
|
45
46
|
normalizeOperatingProfile,
|
|
@@ -67,6 +68,7 @@ function parseArgs(argv) {
|
|
|
67
68
|
else if (a === '--force') args.force = true;
|
|
68
69
|
else if (a === '--no-companions') args.noCompanions = true;
|
|
69
70
|
else if (a === '--no-colors') args.noColors = true;
|
|
71
|
+
else if (a === '--vscode-worktree-tasks') args.vscodeWorktreeTasks = true;
|
|
70
72
|
else if (a === '--dotcontext-mcp') args.dotcontextMcp = argv[++i];
|
|
71
73
|
else if (a.startsWith('--dotcontext-mcp=')) args.dotcontextMcp = a.slice(17);
|
|
72
74
|
else if (a === '--dotcontext-hooks') args.dotcontextHooks = argv[++i];
|
|
@@ -480,6 +482,10 @@ export async function runInit(argv) {
|
|
|
480
482
|
?? (existingBinding ? undefined : DEFAULT_OPERATING_PROFILE);
|
|
481
483
|
const configPatch = profile === undefined ? {} : setOperatingProfile({}, profile);
|
|
482
484
|
bindProjectVault({ projectRoot: projectPath, vaultPath, configPatch });
|
|
485
|
+
if (args.vscodeWorktreeTasks) {
|
|
486
|
+
const tasks = installVscodeWorktreeTasks({ projectRoot: projectPath });
|
|
487
|
+
log(`VS Code worktree tasks: ${tasks.state} (${tasks.path})`);
|
|
488
|
+
}
|
|
483
489
|
|
|
484
490
|
// Companion plugins/MCP selection. --no-companions wins; --companions <csv> is
|
|
485
491
|
// explicit; an interactive TTY gets a multi-choice prompt (context-mode pre-checked);
|
package/src/sync.mjs
CHANGED
|
@@ -26,7 +26,10 @@ export async function runSync(argv) {
|
|
|
26
26
|
const profileRaw = opt(argv, '--profile');
|
|
27
27
|
const profileArgs = hasProfile ? ['--profile', profileRaw] : [];
|
|
28
28
|
const projectPath = resolve(projectRaw && !projectRaw.startsWith('--') ? projectRaw : process.cwd());
|
|
29
|
-
const passthrough = argv.filter((a) => a === '--yes'
|
|
29
|
+
const passthrough = argv.filter((a) => a === '--yes'
|
|
30
|
+
|| a === '-y'
|
|
31
|
+
|| a === '--force'
|
|
32
|
+
|| a === '--vscode-worktree-tasks');
|
|
30
33
|
|
|
31
34
|
// 1. init — idempotente: refaz a fiação sem sobrescrever o que já está configurado.
|
|
32
35
|
step(1, 'init');
|