feat(welcome): initialize a non-repo folder as a project (T-489)
Closes the new-project story (T-486). The dead-end "not a git repo" dialog now offers to initialize the folder: project.init runs git init + a non-clobbering scaffold, then opens + announces on projectCreatedChannel so the account roadblock fires — the same path a brand-new project takes. Adds initExistingProject + the `clide project init [--dir]` verb (default: the current workspace). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -7262,3 +7262,5 @@ Considerations:
|
||||
4. The text is short and does not crowd out clideContextNote.', NULL, '2026-06-28 06:15:53', '2026-06-28 06:15:53.132', '2026-06-28 06:15:53.132', NULL, 'd5caf6198c0cad2fbd79b01261659d82', 2) ON CONFLICT(hash) DO NOTHING;
|
||||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FGSQ789MDB00EQAXTXBVJDXM', 'status', 'in_progress', 'done', NULL, '2026-06-28 06:23:06', '2026-06-28 06:23:06.440', '2026-06-28 06:23:06.440', NULL, 'f6b2c96ac6770981215615c3c467d907', 2) ON CONFLICT(hash) DO NOTHING;
|
||||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FGSQ8B7WDKZ174GJDGWW0GS0', 'status', 'backlog', 'done', NULL, '2026-06-28 06:35:16', '2026-06-28 06:35:16.152', '2026-06-28 06:35:16.152', NULL, '15de4a7ee941ffa6bb5dfa762e6d7ffc', 2) ON CONFLICT(hash) DO NOTHING;
|
||||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FGSQ8YSZA5YNP1JE8SJHXWBG', 'status', 'backlog', 'done', NULL, '2026-06-28 06:41:47', '2026-06-28 06:41:47.934', '2026-06-28 06:41:47.934', NULL, 'df08fd309db50c322d5ea27267d23f7b', 2) ON CONFLICT(hash) DO NOTHING;
|
||||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FGPG4WNNH3BWDRVZXYQTW7Z0', 'status', 'backlog', 'done', NULL, '2026-06-28 06:41:47', '2026-06-28 06:41:47.971', '2026-06-28 06:41:47.971', NULL, '8e792d212a7f92e5201296ed01873607', 2) ON CONFLICT(hash) DO NOTHING;
|
||||
|
||||
@@ -9355,3 +9355,34 @@ Considerations:
|
||||
4. The text is short and does not crowd out clideContextNote.', 'backlog', 'medium', NULL, NULL, NULL, '2026-06-28 06:15:53.077', '2026-06-28 06:15:53.131', NULL, '8fca222cfd1b972d7a66ee3ddaaaf879', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FGSQ789MDB00EQAXTXBVJDXM', 'task', '06FGPG4WNNH3BWDRVZXYQTW7Z0', 'project.new backend: create dir + git init + minimal scaffold, and the clide project new CLI verb', NULL, 'done', 'medium', NULL, NULL, NULL, '2026-06-28 06:13:51.821', '2026-06-28 06:23:06.439', NULL, 'b94604117d0511c2f7b3e24746d87c46', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FGSQ8B7WDKZ174GJDGWW0GS0', 'task', '06FGPG4WNNH3BWDRVZXYQTW7Z0', 'New-project dialog: location + name -> account roadblock -> open; welcome New project action', NULL, 'done', 'medium', NULL, NULL, NULL, '2026-06-28 06:14:00.767', '2026-06-28 06:35:16.152', NULL, 'b54b32a51b09504e2b091c10ae48e9a0', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FGSQ8YSZA5YNP1JE8SJHXWBG', 'task', '06FGPG4WNNH3BWDRVZXYQTW7Z0', 'Evolve _NotARepoDialog into ''Initialize this folder as a clide project?'' (reuse the init + account flow)', NULL, 'done', 'medium', NULL, NULL, NULL, '2026-06-28 06:14:05.775', '2026-06-28 06:41:47.934', NULL, '5d85035e5b90e90e18bdeb2849f6a4ec', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FGPG4WNNH3BWDRVZXYQTW7Z0', 'story', NULL, 'New project creation flow (with Claude account roadblock)', 'clide can only OPEN existing git repos today; there is no way to create a new project, and opening a non-repo folder dead-ends at _NotARepoDialog (welcome_view.dart:633). Add a first-class new-project flow. Per the per-repo account design (T-476), the account choice is a real decision only at project birth, so account selection is the flow''s final roadblock step — existing projects never prompt (they keep their binding, or default to the main account; switch later via Settings or the pane badge).
|
||||
|
||||
## Entry points (D-6 parity)
|
||||
- Welcome view START section: a ''New project...'' action (peer of ''Open folder...'').
|
||||
- CLI: `clide project new <name> [--dir <parent>] [--account <name>]`.
|
||||
- Non-repo open: _NotARepoDialog evolves from a dead end into ''Initialize this folder as a clide project?'' → the same init + account steps.
|
||||
|
||||
## Flow
|
||||
1. Location + name — pick a parent dir (window.pickDirectory()), enter a name → target <parent>/<name>/. Validate: non-empty name, target does not already exist.
|
||||
2. Initialize — create the dir, `git init`, write a minimal non-prescriptive scaffold (a CLAUDE.md stub + .gitignore). No language/templates.
|
||||
3. Account roadblock — final screen: pick the Claude account this project runs under (registered accounts + Default + ''Add account...''). Selecting binds the new workspace (AccountRegistry.bindWorkspace + accountActionChannel); ''Add account...'' runs add + login (T-485).
|
||||
4. Open — project.open the new dir so the workspace goes live; the primary Claude pane spawns under the bound account.
|
||||
|
||||
## Reuses (already shipped under T-476)
|
||||
- Account picker + binding: account_settings_control.dart (ClaudeAccountsListControl / bindWorkspaceAccount), accountActionChannel.
|
||||
- git init: lib/src/git/ client.
|
||||
- project open: kernel.project.
|
||||
|
||||
## Acceptance
|
||||
1. ''New project...'' creates <parent>/<name>/, git-inits it, and opens it as the active workspace.
|
||||
2. The final step binds the chosen account (or Default); a fresh claude in the new project runs under that account''s CLAUDE_CONFIG_DIR.
|
||||
3. Opening an EXISTING project shows no account prompt.
|
||||
4. Opening a non-repo folder offers to initialize it (no dead end).
|
||||
5. `clide project new` mirrors the UI (D-6); every UI action has a CLI counterpart.
|
||||
6. Tests cover the dialog flow, git-init, the account-bind step, and the non-repo → init path.
|
||||
|
||||
## Out of scope
|
||||
- Language/framework templates (git init + minimal files only).
|
||||
- Remote creation (GitHub repo create) — local init only.
|
||||
- Re-homing existing projects between accounts beyond the existing Settings/badge switch.', 'done', 'medium', NULL, NULL, NULL, '2026-06-27 22:43:31.629', '2026-06-28 06:41:47.971', NULL, '01a340c5205eae82e1b2bb7efb3be179', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||||
|
||||
Reference in New Issue
Block a user