Address PR review feedback (#1741)

- Close first TaskStore before creating second in interactive registration (P1)
- Revert defaultWorkflowId default to undefined; set explicitly in onboarding only (P1)
- Add alpha-only filter + 2-char min to interactive prefix input (P2)
- Move suggestTaskPrefix to @fusion/core, share between CLI and dashboard (P2)
- Fix suggestTaskPrefix JSDoc to match implementation (P2)
This commit is contained in:
gsxdsm
2026-06-24 10:45:21 -07:00
parent 9a7c0c6154
commit aae76cecc3
5 changed files with 25 additions and 17 deletions

View File

@@ -18,6 +18,7 @@ import {
writeProjectIdentity,
detectWorkspaceRepos,
saveWorkspaceConfig,
suggestTaskPrefix,
type RegisteredProject,
type TaskStore,
} from "@fusion/core";
@@ -537,19 +538,6 @@ export function suggestProjectName(path: string): string {
return parts[parts.length - 1] || "unnamed";
}
/**
* FNXC:TaskPrefix 2026-06-24-18:00:
* Derive a task prefix from a project name by taking the first 2-4 uppercase
* letters. Falls back to "FN" for short names. Used as the suggested default
* during project onboarding so each project gets a recognizable prefix.
*/
export function suggestTaskPrefix(projectName: string): string {
const cleaned = projectName.replace(/[^a-zA-Z]/g, "").toUpperCase();
if (cleaned.length >= 2 && cleaned.length <= 4) return cleaned;
if (cleaned.length > 4) return cleaned.slice(0, 4);
return "FN";
}
/**
* Resolve absolute path and validate it exists.
*/
@@ -698,6 +686,7 @@ export async function registerProjectInteractive(
// Persist workspaceMode in config.json so it's visible/toggleable in the dashboard
await store.updateSettings({ workspaceMode: true });
}
await store.close();
console.log(` ✓ Initialized fn at ${absPath}`);
} else {
throw new ProjectResolutionError(
@@ -772,7 +761,8 @@ export async function registerProjectInteractive(
const rl = createInterface({ input: process.stdin, output: process.stdout });
const prefixInput = await rl.question(`\n Task prefix [${suggestedPrefix}]: `);
rl.close();
const prefix = prefixInput.trim().toUpperCase() || suggestedPrefix;
const rawPrefix = prefixInput.trim().toUpperCase().replace(/[^A-Z]/g, "");
const prefix = rawPrefix.length >= 2 ? rawPrefix : suggestedPrefix;
await store.updateSettings({
taskPrefix: prefix,

View File

@@ -1957,3 +1957,4 @@ export {
clearSyncPassphrase,
hasSyncPassphraseConfigured,
} from "./secrets-sync-passphrase.js";
export { suggestTaskPrefix } from "./task-prefix.js";

View File

@@ -258,7 +258,7 @@ export const DEFAULT_GLOBAL_SETTINGS = {
export const DEFAULT_PROJECT_SETTINGS = {
globalPause: false,
globalPauseReason: undefined,
defaultWorkflowId: "builtin:coding",
defaultWorkflowId: undefined,
enabledBuiltinWorkflowIds: undefined,
approvedWorkflowCliCommands: undefined,
approvedCliAutonomyAdapters: undefined,

View File

@@ -0,0 +1,17 @@
/**
* FNXC:TaskPrefix 2026-06-24-18:00:
* Derive a task prefix from a project name. Strips non-alpha characters, uppercases,
* and takes the first 2-4 characters. Falls back to "FN" for names with fewer than
* 2 letters. Used during project onboarding (CLI and dashboard) so each project gets
* a recognizable prefix for task IDs (e.g. "MYPR" for "my-project").
*
* Note: the result is the first 2-4 letters of the cleaned (alpha-only, uppercased)
* name, NOT the initials of each word. For "my-project" the result is "MYPR"
* (first 4 of "MYPROJECT"), not "MP".
*/
export function suggestTaskPrefix(projectName: string): string {
const cleaned = projectName.replace(/[^a-zA-Z]/g, "").toUpperCase();
if (cleaned.length >= 2 && cleaned.length <= 4) return cleaned;
if (cleaned.length > 4) return cleaned.slice(0, 4);
return "FN";
}

View File

@@ -382,10 +382,10 @@ export const registerProjectRoutes: ApiRouteRegistrar = (ctx) => {
*/
if (activeProjectWithOutcome.outcome === "registered") {
try {
const { TaskStore } = await import("@fusion/core");
const { TaskStore, suggestTaskPrefix } = await import("@fusion/core");
const store = new TaskStore(normalizedPath);
await store.init();
const prefix = normalizedName.replace(/[^a-zA-Z]/g, "").toUpperCase().slice(0, 4) || "FN";
const prefix = suggestTaskPrefix(normalizedName);
await store.updateSettings({
taskPrefix: prefix,
defaultWorkflowId: "builtin:coding",