@dezkareid/osddt 1.11.1 → 1.11.3

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/dist/index.js CHANGED
@@ -3,10 +3,10 @@ import { Command } from 'commander';
3
3
  import fs from 'fs-extra';
4
4
  import path from 'path';
5
5
  import { fileURLToPath } from 'url';
6
+ import { execSync } from 'child_process';
6
7
  import select from '@inquirer/select';
7
8
  import checkbox from '@inquirer/checkbox';
8
9
  import input from '@inquirer/input';
9
- import { execSync } from 'child_process';
10
10
  import readline from 'readline';
11
11
 
12
12
  function getRepoPreamble(npxCommand) {
@@ -716,39 +716,8 @@ function checkGitVersion() {
716
716
  return { label: 'Git version >= 2.5', passed: false, detail: 'git not found or not executable' };
717
717
  }
718
718
  }
719
- function checkNotAWorktree(cwd) {
720
- try {
721
- const gitCommonDir = execSync('git rev-parse --git-common-dir', { cwd, encoding: 'utf-8' }).trim();
722
- const gitDir = execSync('git rev-parse --git-dir', { cwd, encoding: 'utf-8' }).trim();
723
- const isWorktree = gitDir !== gitCommonDir && gitDir !== '.git';
724
- return {
725
- label: 'Current directory is not a worktree',
726
- passed: !isWorktree,
727
- detail: isWorktree
728
- ? `This directory is itself a worktree (git-dir: ${gitDir}). Run setup from the main repository.`
729
- : 'OK',
730
- };
731
- }
732
- catch {
733
- return { label: 'Current directory is not a worktree', passed: false, detail: 'Not inside a git repository' };
734
- }
735
- }
736
- async function checkTargetWritable(cwd) {
737
- let targetBase;
738
- try {
739
- const repoRoot = execSync('git rev-parse --show-toplevel', { cwd, encoding: 'utf-8' }).trim();
740
- const rcPath = path.join(repoRoot, '.osddtrc');
741
- if (await fs.pathExists(rcPath)) {
742
- const rc = await fs.readJson(rcPath);
743
- targetBase = rc.worktreeBase ?? path.dirname(repoRoot);
744
- }
745
- else {
746
- targetBase = path.dirname(repoRoot);
747
- }
748
- }
749
- catch {
750
- return { label: 'Worktree target directory is writable', passed: false, detail: 'Could not resolve repo root' };
751
- }
719
+ async function checkTargetWritable(barePath) {
720
+ const targetBase = path.dirname(barePath);
752
721
  try {
753
722
  await fs.access(targetBase, fs.constants.W_OK);
754
723
  return { label: 'Worktree target directory is writable', passed: true, detail: `${targetBase} is writable` };
@@ -757,10 +726,9 @@ async function checkTargetWritable(cwd) {
757
726
  return { label: 'Worktree target directory is writable', passed: false, detail: `${targetBase} is not writable` };
758
727
  }
759
728
  }
760
- async function initStateFile(cwd) {
729
+ async function initStateFile(barePath) {
761
730
  try {
762
- const repoRoot = execSync('git rev-parse --show-toplevel', { cwd, encoding: 'utf-8' }).trim();
763
- const stateFile = path.join(path.dirname(repoRoot), '.osddt-worktrees');
731
+ const stateFile = path.join(path.dirname(barePath), '.osddt-worktrees');
764
732
  if (!(await fs.pathExists(stateFile))) {
765
733
  await fs.writeJson(stateFile, [], { spaces: 2 });
766
734
  console.log(` ✓ Initialized worktree state file: ${stateFile}`);
@@ -780,11 +748,10 @@ function printCheckResult(result) {
780
748
  console.log(` → ${result.detail}`);
781
749
  }
782
750
  }
783
- async function runWorktreeChecks(cwd) {
751
+ async function runWorktreeChecks(barePath) {
784
752
  const results = [
785
753
  checkGitVersion(),
786
- checkNotAWorktree(cwd),
787
- await checkTargetWritable(cwd),
754
+ await checkTargetWritable(barePath),
788
755
  ];
789
756
  for (const result of results) {
790
757
  printCheckResult(result);
@@ -857,16 +824,25 @@ async function writeAgentFiles(cwd, agents, npxCommand) {
857
824
  console.log('');
858
825
  }
859
826
  }
860
- async function setupWorktreeEnvironment(cwd, _worktreeRepository) {
827
+ function cloneBareRepository(cwd, repositoryUrl) {
828
+ const barePath = path.join(cwd, '.bare');
829
+ console.log(`Cloning bare repository into ${barePath} ...\n`);
830
+ execSync(`git clone --bare "${repositoryUrl}" "${barePath}"`, { stdio: 'inherit' });
831
+ console.log('');
832
+ return barePath;
833
+ }
834
+ async function setupWorktreeEnvironment(cwd, worktreeRepository) {
835
+ const barePath = cloneBareRepository(cwd, worktreeRepository);
861
836
  console.log('Checking environment for git worktree support...\n');
862
- const allPassed = await runWorktreeChecks(cwd);
837
+ const allPassed = await runWorktreeChecks(barePath);
863
838
  console.log('');
864
839
  if (!allPassed) {
865
840
  console.log('Some checks failed. Resolve the issues above before using the worktree workflow.');
866
841
  process.exit(1);
867
842
  }
868
- await initStateFile(cwd);
843
+ await initStateFile(barePath);
869
844
  console.log('');
845
+ return barePath;
870
846
  }
871
847
  async function runSetup(cwd, rawAgents, rawRepoType, rawWorktreeRepository) {
872
848
  const agents = rawAgents !== undefined ? parseAgents(rawAgents) : await askAgents();
@@ -878,8 +854,9 @@ async function runSetup(cwd, rawAgents, rawRepoType, rawWorktreeRepository) {
878
854
  const worktreeRepository = rawWorktreeRepository !== undefined ? rawWorktreeRepository : (await askWorktreeUrl()) || undefined;
879
855
  if (rawWorktreeRepository === undefined)
880
856
  console.log('');
857
+ let barePath;
881
858
  if (worktreeRepository) {
882
- await setupWorktreeEnvironment(cwd);
859
+ barePath = await setupWorktreeEnvironment(cwd, worktreeRepository);
883
860
  }
884
861
  const npxCommand = await resolveNpxCommand(cwd);
885
862
  console.log('Setting up OSDDT command files...\n');
@@ -887,6 +864,8 @@ async function runSetup(cwd, rawAgents, rawRepoType, rawWorktreeRepository) {
887
864
  const config = { repoType, agents };
888
865
  if (worktreeRepository)
889
866
  config['worktree-repository'] = worktreeRepository;
867
+ if (barePath)
868
+ config['bare-path'] = barePath;
890
869
  await writeConfig(cwd, config);
891
870
  console.log('\nSetup complete!');
892
871
  console.log('Commands created: osddt.spec, osddt.plan, osddt.tasks, osddt.implement');
@@ -938,7 +917,13 @@ function todayPrefix() {
938
917
  const dd = String(now.getDate()).padStart(2, '0');
939
918
  return `${yyyy}-${mm}-${dd}`;
940
919
  }
941
- function resolveRepoRoot$2(cwd) {
920
+ async function resolveRepoRoot$2(cwd) {
921
+ const rcPath = path.join(cwd, '.osddtrc');
922
+ if (await fs.pathExists(rcPath)) {
923
+ const rc = await fs.readJson(rcPath);
924
+ if (rc['bare-path'])
925
+ return rc['bare-path'];
926
+ }
942
927
  return execSync('git rev-parse --show-toplevel', { cwd, encoding: 'utf-8' }).trim();
943
928
  }
944
929
  function stateFilePath$2(repoRoot) {
@@ -957,7 +942,7 @@ async function runDone(featureName, cwd, worktree) {
957
942
  console.log(`Moved: working-on/${featureName} → done/${destName}`);
958
943
  if (!worktree)
959
944
  return;
960
- const repoRoot = resolveRepoRoot$2(process.cwd());
945
+ const repoRoot = await resolveRepoRoot$2(process.cwd());
961
946
  const stateFile = stateFilePath$2(repoRoot);
962
947
  if (!(await fs.pathExists(stateFile))) {
963
948
  console.error(`Warning: .osddt-worktrees not found at ${stateFile}. Skipping worktree cleanup.`);
@@ -1125,9 +1110,6 @@ function contextCommand() {
1125
1110
  return cmd;
1126
1111
  }
1127
1112
 
1128
- function resolveRepoRoot$1(cwd) {
1129
- return execSync('git rev-parse --show-toplevel', { cwd, encoding: 'utf-8' }).trim();
1130
- }
1131
1113
  function repoName(repoRoot) {
1132
1114
  return path.basename(repoRoot);
1133
1115
  }
@@ -1169,6 +1151,15 @@ async function prompt(question) {
1169
1151
  });
1170
1152
  });
1171
1153
  }
1154
+ async function resolveRepoRoot$1(cwd) {
1155
+ const rcPath = path.join(cwd, '.osddtrc');
1156
+ if (await fs.pathExists(rcPath)) {
1157
+ const rc = await fs.readJson(rcPath);
1158
+ if (rc['bare-path'])
1159
+ return rc['bare-path'];
1160
+ }
1161
+ return execSync('git rev-parse --show-toplevel', { cwd, encoding: 'utf-8' }).trim();
1162
+ }
1172
1163
  async function createWorktree(branch, worktreePath, repoRoot) {
1173
1164
  if (await fs.pathExists(worktreePath)) {
1174
1165
  console.log(`\nDirectory already exists at: ${worktreePath}`);
@@ -1196,15 +1187,15 @@ async function createWorktree(branch, worktreePath, repoRoot) {
1196
1187
  }
1197
1188
  async function runStartWorktree(featureName, options) {
1198
1189
  const cwd = process.cwd();
1199
- const repoRoot = resolveRepoRoot$1(cwd);
1190
+ const repoRoot = await resolveRepoRoot$1(cwd);
1200
1191
  const branch = `feat/${featureName}`;
1201
1192
  // Read .osddtrc
1202
- const rcPath = path.join(repoRoot, '.osddtrc');
1193
+ const rcPath = path.join(cwd, '.osddtrc');
1203
1194
  let rc = { repoType: 'single' };
1204
1195
  if (await fs.pathExists(rcPath)) {
1205
1196
  rc = await fs.readJson(rcPath);
1206
1197
  }
1207
- // Resolve worktree path
1198
+ // Resolve worktree path — base is parent of repoRoot (i.e. cwd when using .bare)
1208
1199
  const base = rc.worktreeBase ?? path.dirname(repoRoot);
1209
1200
  const worktreePath = path.join(base, `${repoName(repoRoot)}-${featureName}`);
1210
1201
  // Check state file for existing entry
@@ -1256,14 +1247,20 @@ function startWorktreeCommand() {
1256
1247
  return cmd;
1257
1248
  }
1258
1249
 
1259
- function resolveRepoRoot(cwd) {
1250
+ async function resolveRepoRoot(cwd) {
1251
+ const rcPath = path.join(cwd, '.osddtrc');
1252
+ if (await fs.pathExists(rcPath)) {
1253
+ const rc = await fs.readJson(rcPath);
1254
+ if (rc['bare-path'])
1255
+ return rc['bare-path'];
1256
+ }
1260
1257
  return execSync('git rev-parse --show-toplevel', { cwd, encoding: 'utf-8' }).trim();
1261
1258
  }
1262
1259
  function stateFilePath(repoRoot) {
1263
1260
  return path.join(path.dirname(repoRoot), '.osddt-worktrees');
1264
1261
  }
1265
1262
  async function runWorktreeInfo(featureName) {
1266
- const repoRoot = resolveRepoRoot(process.cwd());
1263
+ const repoRoot = await resolveRepoRoot(process.cwd());
1267
1264
  const stateFile = stateFilePath(repoRoot);
1268
1265
  if (!(await fs.pathExists(stateFile))) {
1269
1266
  console.error(`No .osddt-worktrees file found at: ${stateFile}`);
@@ -4,8 +4,7 @@ export interface CheckResult {
4
4
  detail: string;
5
5
  }
6
6
  export declare function checkGitVersion(): CheckResult;
7
- export declare function checkNotAWorktree(cwd: string): CheckResult;
8
- export declare function checkTargetWritable(cwd: string): Promise<CheckResult>;
9
- export declare function initStateFile(cwd: string): Promise<void>;
7
+ export declare function checkTargetWritable(barePath: string): Promise<CheckResult>;
8
+ export declare function initStateFile(barePath: string): Promise<void>;
10
9
  export declare function printCheckResult(result: CheckResult): void;
11
- export declare function runWorktreeChecks(cwd: string): Promise<boolean>;
10
+ export declare function runWorktreeChecks(barePath: string): Promise<boolean>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dezkareid/osddt",
3
- "version": "1.11.1",
3
+ "version": "1.11.3",
4
4
  "description": "Package for Spec-Driven Development workflow",
5
5
  "keywords": [
6
6
  "spec-driven",