@straiffi/archon 1.2.5 → 1.2.7

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.
@@ -5,10 +5,10 @@
5
5
  <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
6
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
7
  <title>Archon</title>
8
- <script type="module" crossorigin src="/assets/index-DHJbmRpg.js"></script>
8
+ <script type="module" crossorigin src="/assets/index-D_fYmgsV.js"></script>
9
9
  <link rel="modulepreload" crossorigin href="/assets/rolldown-runtime-BYbx6iT9.js">
10
- <link rel="modulepreload" crossorigin href="/assets/badge-Bpry9xkS.js">
11
- <link rel="stylesheet" crossorigin href="/assets/index-CRirnlH7.css">
10
+ <link rel="modulepreload" crossorigin href="/assets/badge-C7tnUR1h.js">
11
+ <link rel="stylesheet" crossorigin href="/assets/index-DWMCGEsT.css">
12
12
  </head>
13
13
  <body>
14
14
  <div id="root"></div>
@@ -16,9 +16,10 @@ import { createCorsOriginResolver, parseCorsOrigins } from './lib/cors.js';
16
16
  import { branchExistsLocally, commitGitChanges, createWorktreeAsync, deleteWorktree, getBundleReviewDiffForCwd, getGitDiffData, getGitDiffFiles, getGitStatus, getGitUnifiedDiff, getProjectBranch, getProjectBranchSuggestions, getSelectedGitUnifiedDiff, listUnpushedCommitsForCwd, pullGitBranch, pushCurrentBranch, resolveExistingWorktreePath, resolveWorktreePath, summarizeTicketDiffFiles, switchProjectBranch, syncWorktreeFilesAsync, undoLatestUnpushedCommitForCwd } from './lib/git.js';
17
17
  import config from './lib/config.js';
18
18
  import { autoConfigProject, ProjectAutoConfigError } from './lib/projectAutoConfig.js';
19
+ import { analyzeRepoPath, createInitialCommit, ensureInitialCommitForWorktrees, initializeGitRepo, isInitialCommitRequiredError, } from './lib/projectRepos.js';
19
20
  import { browseRepoPath } from './lib/directoryPicker.js';
20
21
  import { resolveDesktopServerHost } from './lib/desktopServerHost.js';
21
- import { emitMobileRealtime, getMobileAccessStatus, regenerateMobilePairingChallenge, revokeMobileSession, startMobileAccess, stopMobileAccess, } from './lib/mobileAccess.js';
22
+ import { emitMobileRealtime, getMobileAccessStatus, regenerateMobilePairingChallenge, revokeMobileSession, setMobileAccessStatusChangeListener, startMobileAccess, stopMobileAccess, } from './lib/mobileAccess.js';
22
23
  import { validateDesktopMobileAccessRequest } from './lib/mobileAccessSecurity.js';
23
24
  import { refreshChatSessionUsageSnapshot, stopAllBuildAgents } from './lib/agent.js';
24
25
  import { runLightweightPrompt } from './lib/lightweightPrompt.js';
@@ -43,7 +44,7 @@ import { createGitHubPullRequest, findOpenGitHubPullRequest, findOpenGitHubPullR
43
44
  import { importJiraIssue, JiraApiError, validateJiraConnection } from './lib/integrations/jira.js';
44
45
  import { JiraPlanningReferenceError, resolveJiraPlanningDescription } from './lib/integrations/planning.js';
45
46
  import { getBundlePullRequestRecord, hasOpenBundlePullRequest, serializeBundlePullRequest, shouldSyncBundlePullRequest, upsertBundlePullRequest, } from './lib/bundlePullRequests.js';
46
- import { countInboundProjectLinks, getEffectiveProject, getProjectById, getProjectTicketStats, hasProjectRunIde, listProjects, replaceProjectLinks, serializeProject, updateProjectActiveTarget, validateProjectPayload, validateRepoPath, } from './lib/projects.js';
47
+ import { countInboundProjectLinks, getEffectiveProject, getProjectById, getProjectTicketStats, hasProjectRunIde, listProjects, replaceProjectLinks, serializeProject, updateProjectActiveTarget, validateProjectPayload, } from './lib/projects.js';
47
48
  import { getActiveRunStatus, getActiveRunStatusForProject, getPreviewStatusForProject, hasRunConfig, isRunning, openIde, openTicketIdeInWorkspace, resolveProjectRunContextKey, runSetupCommandsInWorkspace, runTicketInWorkspace, stopAllTickets, stopTicket } from './lib/run.js';
48
49
  import { clearAllTestSessions, createTestSession, deleteTestSession, discoverTestsForSession, doesTestFileExistForSession, findProjectTestCommand, getTestSession, isTestSelectionSupported, startTestSessionRun, stopTestSessionRun } from './lib/testSessions.js';
49
50
  import { getBundleBuildBlockerResponse, shouldStartBundleBuildNow, transitionTicketState, } from './lib/ticketWorkflowOperations.js';
@@ -122,6 +123,7 @@ const prepareBundleWorkspace = async (bundle, project, options = {}) => {
122
123
  const workspacePath = resolveWorktreePath(branch, project);
123
124
  let setupCompleted = false;
124
125
  try {
126
+ ensureInitialCommitForWorktrees(project.repo_path);
125
127
  await createWorktreeAsync(branch, project, { baseBranch: options.baseBranch ?? null });
126
128
  await syncWorktreeFilesAsync(branch, project);
127
129
  await runSetupCommandsInWorkspace(project, workspacePath);
@@ -263,6 +265,9 @@ io.emit = ((event, ...args) => {
263
265
  emitMobileRealtime(event, args[0]);
264
266
  return result;
265
267
  });
268
+ setMobileAccessStatusChangeListener(status => {
269
+ io.emit('mobile-access:status', status);
270
+ });
266
271
  app.use(cors({ origin: CORS_ORIGIN_RESOLVER }));
267
272
  const hasOwn = (value, key) => Object.prototype.hasOwnProperty.call(value, key);
268
273
  const resolveRequestedSkills = (value) => normalizeSkillNames(value);
@@ -2787,7 +2792,7 @@ app.post('/bundles', async (req, res) => {
2787
2792
  }
2788
2793
  catch (error) {
2789
2794
  deleteBundle(bundle.id, result.project.id);
2790
- return res.status(500).json({
2795
+ return res.status(isInitialCommitRequiredError(error) ? 409 : 500).json({
2791
2796
  error: `Unable to prepare the bundle worktree for branch "${bundle.branch}": ${getErrorMessage(error)}`,
2792
2797
  });
2793
2798
  }
@@ -2990,20 +2995,47 @@ app.post('/projects/validate-repo-path', (req, res) => {
2990
2995
  if (typeof req.body?.repo_path !== 'string' || req.body.repo_path.trim() === '') {
2991
2996
  return res.status(400).json({ error: 'repo_path must be a non-empty string' });
2992
2997
  }
2993
- const repoResult = validateRepoPath(req.body.repo_path);
2994
- if ('error' in repoResult) {
2998
+ const repoAnalysis = analyzeRepoPath(req.body.repo_path, { allowInitialization: true });
2999
+ if (repoAnalysis.kind === 'invalid') {
2995
3000
  return res.json({
2996
3001
  valid: false,
2997
3002
  repo_root: null,
2998
- error: repoResult.error,
3003
+ error: repoAnalysis.error,
3004
+ will_initialize: false,
3005
+ has_initial_commit: null,
3006
+ });
3007
+ }
3008
+ if (repoAnalysis.kind === 'initializable') {
3009
+ return res.json({
3010
+ valid: false,
3011
+ repo_root: null,
3012
+ error: null,
3013
+ will_initialize: true,
3014
+ has_initial_commit: null,
2999
3015
  });
3000
3016
  }
3001
3017
  return res.json({
3002
3018
  valid: true,
3003
- repo_root: repoResult.value,
3019
+ repo_root: repoAnalysis.repoRoot,
3004
3020
  error: null,
3021
+ will_initialize: false,
3022
+ has_initial_commit: repoAnalysis.hasInitialCommit,
3005
3023
  });
3006
3024
  });
3025
+ app.post('/projects/:id/create-initial-commit', (req, res) => {
3026
+ const project = getProjectById(req.params.id);
3027
+ if (!project) {
3028
+ return res.status(404).json({ error: 'Not found' });
3029
+ }
3030
+ try {
3031
+ createInitialCommit(project.repo_path);
3032
+ }
3033
+ catch (error) {
3034
+ return res.status(409).json({ error: getErrorMessage(error) || 'Unable to create the initial commit right now.' });
3035
+ }
3036
+ const updatedProject = getProjectById(project.id);
3037
+ return res.json(serializeProject(updatedProject ?? null));
3038
+ });
3007
3039
  app.post('/projects/browse-repo-path', (_req, res) => {
3008
3040
  const browseResult = browseRepoPath();
3009
3041
  if (browseResult.status === 'cancelled') {
@@ -3353,12 +3385,23 @@ app.get('/projects', (_req, res) => {
3353
3385
  res.json(projects.map(serializeProject));
3354
3386
  });
3355
3387
  app.post('/projects', (req, res) => {
3356
- const validation = validateProjectPayload(asProjectPayload(req.body));
3388
+ const validation = validateProjectPayload(asProjectPayload(req.body), { allowRepoInitialization: true });
3357
3389
  if ('error' in validation) {
3358
3390
  return res.status(400).json({ error: validation.error });
3359
3391
  }
3360
3392
  const projectCount = Number(db.prepare('SELECT COUNT(*) AS count FROM projects').get()?.count ?? 0);
3361
3393
  const { name, repo_path, linked_project_ids, run_setup, run_services, test_commands, run_ide, preview_service_name, preview_path, preview_capability_mode, helper_model, helper_variant, commit_message_rules, auto_park_stale_tickets, memory_enabled, worktree_sync, } = validation.values;
3394
+ if (!repo_path) {
3395
+ return res.status(400).json({ error: 'repo_path must be a non-empty string' });
3396
+ }
3397
+ let normalizedRepoPath = repo_path;
3398
+ try {
3399
+ const initializedRepo = initializeGitRepo(repo_path);
3400
+ normalizedRepoPath = initializedRepo.repoRoot;
3401
+ }
3402
+ catch (error) {
3403
+ return res.status(400).json({ error: getErrorMessage(error) || 'Unable to initialize the project repository.' });
3404
+ }
3362
3405
  const id = randomUUID();
3363
3406
  db.prepare(`
3364
3407
  INSERT INTO projects (
@@ -3380,7 +3423,7 @@ app.post('/projects', (req, res) => {
3380
3423
  worktree_sync
3381
3424
  )
3382
3425
  VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
3383
- `).run(id, name, repo_path, run_setup, run_services, test_commands, run_ide ?? null, preview_service_name ?? null, preview_path ?? null, preview_capability_mode ?? null, helper_model ?? null, helper_variant ?? null, commit_message_rules ?? null, auto_park_stale_tickets ?? 0, memory_enabled ?? 0, worktree_sync ?? null);
3426
+ `).run(id, name, normalizedRepoPath, run_setup, run_services, test_commands, run_ide ?? null, preview_service_name ?? null, preview_path ?? null, preview_capability_mode ?? null, helper_model ?? null, helper_variant ?? null, commit_message_rules ?? null, auto_park_stale_tickets ?? 0, memory_enabled ?? 0, worktree_sync ?? null);
3384
3427
  replaceProjectLinks(id, linked_project_ids ?? []);
3385
3428
  ensureProjectRootBundle(id);
3386
3429
  if (projectCount === 0) {