From e0fe173a375665f2c28c31aae4f2755e497a81cb Mon Sep 17 00:00:00 2001 From: barry <91018388+barry166@users.noreply.github.com> Date: Sun, 21 Jun 2026 17:37:52 +0800 Subject: [PATCH] Keep project-id display formatting from drifting across CLI commands status and reset both rendered the same shortened project id with separate\nmagic numbers. Centralizing the display helper keeps the output stable\nwhile giving future display-length changes one place to land.\n\nConstraint: Output format must stay first-12-chars plus ellipsis\nRejected: Leave duplicate slice literals in place | easy to drift on the next display tweak\nConfidence: high\nScope-risk: narrow\nReversibility: clean\nDirective: Reuse shortProjectId for any future user-facing project-id truncation\nTested: npm run typecheck --workspace @agentctxhq/agentctx\nTested: npm run build --workspace @agentctxhq/agentctx\nTested: npx biome check packages/agentctx/src/storage/namespace.ts packages/agentctx/src/cli/status.ts packages/agentctx/src/cli/reset.ts packages/agentctx/test/storage/namespace.test.ts\nTested: npx vitest run test/storage/namespace.test.ts\nNot-tested: Full workspace test suite --- packages/agentctx/src/cli/reset.ts | 4 ++-- packages/agentctx/src/cli/status.ts | 4 ++-- packages/agentctx/src/storage/namespace.ts | 5 +++++ packages/agentctx/test/storage/namespace.test.ts | 10 ++++++++++ 4 files changed, 19 insertions(+), 4 deletions(-) diff --git a/packages/agentctx/src/cli/reset.ts b/packages/agentctx/src/cli/reset.ts index 53d1d9a..6b39e2f 100644 --- a/packages/agentctx/src/cli/reset.ts +++ b/packages/agentctx/src/cli/reset.ts @@ -9,7 +9,7 @@ import { existsSync } from "node:fs"; import { parseArgs } from "node:util"; import { openDatabase } from "../storage/db.js"; import { countProjectRecords, deleteProjectData } from "../storage/maintenance.js"; -import { resolveProjectId } from "../storage/namespace.js"; +import { resolveProjectId, shortProjectId } from "../storage/namespace.js"; import type { CliEnv } from "./env.js"; export const RESET_USAGE = `Usage: agentctx reset [options] @@ -58,7 +58,7 @@ export async function runReset(env: CliEnv, args: string[]): Promise { const result = deleteProjectData(db, projectId); env.io.out( `✓ deleted ${result.records} record(s), ${result.nodes} node(s), ` + - `${result.edges} edge(s), ${result.sessions} session(s) for project ${projectId.slice(0, 12)}…`, + `${result.edges} edge(s), ${result.sessions} session(s) for project ${shortProjectId(projectId)}`, ); } finally { db.close(); diff --git a/packages/agentctx/src/cli/status.ts b/packages/agentctx/src/cli/status.ts index bd38c81..ca462f7 100644 --- a/packages/agentctx/src/cli/status.ts +++ b/packages/agentctx/src/cli/status.ts @@ -10,7 +10,7 @@ import { existsSync } from "node:fs"; import { parseArgs } from "node:util"; import { loadConfig } from "../config.js"; import { openDatabase } from "../storage/db.js"; -import { resolveProjectId } from "../storage/namespace.js"; +import { resolveProjectId, shortProjectId } from "../storage/namespace.js"; import { GLOBAL_VISIBLE_SQL } from "../storage/records.js"; import { RECORD_TYPES } from "../storage/types.js"; import type { CliEnv } from "./env.js"; @@ -50,7 +50,7 @@ export async function runStatus(env: CliEnv, args: string[]): Promise { const all = sessionTotals(db, null); const config = loadConfig(env.configPath); - env.io.out(`agentctx status — project ${projectId.slice(0, 12)}… (${env.cwd})`); + env.io.out(`agentctx status — project ${shortProjectId(projectId)} (${env.cwd})`); env.io.out(""); env.io.out("Context records (active):"); let total = 0; diff --git a/packages/agentctx/src/storage/namespace.ts b/packages/agentctx/src/storage/namespace.ts index 902e925..5d85c4c 100644 --- a/packages/agentctx/src/storage/namespace.ts +++ b/packages/agentctx/src/storage/namespace.ts @@ -11,6 +11,7 @@ import { createHash } from "node:crypto"; import { resolve } from "node:path"; export { GLOBAL_PROJECT_ID } from "./types.js"; +export const PROJECT_ID_DISPLAY_LEN = 12; /** * Normalize a git remote URL to a canonical `host/path` form: unifies @@ -69,6 +70,10 @@ export function resolveProjectId(cwd: string = process.cwd()): string { return projectIdFromPath(repoRoot ?? cwd); } +export function shortProjectId(projectId: string): string { + return `${projectId.slice(0, PROJECT_ID_DISPLAY_LEN)}…`; +} + function git(args: string[], cwd: string): string | null { try { const out = execFileSync("git", args, { diff --git a/packages/agentctx/test/storage/namespace.test.ts b/packages/agentctx/test/storage/namespace.test.ts index ab50b8c..661502b 100644 --- a/packages/agentctx/test/storage/namespace.test.ts +++ b/packages/agentctx/test/storage/namespace.test.ts @@ -1,8 +1,10 @@ import { describe, expect, it } from "vitest"; import { + PROJECT_ID_DISPLAY_LEN, normalizeGitRemoteUrl, projectIdFromPath, projectIdFromRemote, + shortProjectId, } from "../../src/storage/namespace.js"; describe("normalizeGitRemoteUrl", () => { @@ -47,3 +49,11 @@ describe("project ids", () => { expect(fromPath).not.toBe(projectIdFromRemote("github.com/org/repo")); }); }); + +describe("shortProjectId", () => { + it("renders the first 12 hex chars plus an ellipsis", () => { + const projectId = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"; + expect(shortProjectId(projectId)).toBe("0123456789ab…"); + expect(shortProjectId(projectId)).toHaveLength(PROJECT_ID_DISPLAY_LEN + 1); + }); +});