@team-ai/teamai-cli 0.30.2 → 0.30.4
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/cli.js +47 -100
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -61809,49 +61809,26 @@ async function canonicalizeWorkspacePath(value) {
|
|
|
61809
61809
|
}
|
|
61810
61810
|
function mergeWorkspaceBindings(existing2, incoming, canonicalKey) {
|
|
61811
61811
|
if (!existing2) return incoming;
|
|
61812
|
-
const
|
|
61813
|
-
const
|
|
61812
|
+
const rank2 = (binding) => binding.projectId > 0 ? 2 : binding.projectName === "__skipped__" ? 1 : 0;
|
|
61813
|
+
const existingRank = rank2(existing2);
|
|
61814
|
+
const incomingRank = rank2(incoming);
|
|
61815
|
+
const existingReal = existingRank === 2;
|
|
61816
|
+
const incomingReal = incomingRank === 2;
|
|
61814
61817
|
if (existingReal && incomingReal && existing2.projectId !== incoming.projectId) {
|
|
61815
61818
|
log.warn(
|
|
61816
61819
|
`local-agent: workspace ${canonicalKey} has conflicting project bindings (${existing2.projectId} vs ${incoming.projectId}); keeping ${existing2.projectId}`
|
|
61817
61820
|
);
|
|
61818
61821
|
}
|
|
61819
|
-
const base =
|
|
61822
|
+
const base = existingRank >= incomingRank ? { ...existing2 } : { ...incoming };
|
|
61823
|
+
base.enrolledAt ??= existing2.enrolledAt ?? incoming.enrolledAt;
|
|
61820
61824
|
if (!base.ideType) base.ideType = existing2.ideType ?? incoming.ideType;
|
|
61821
61825
|
return base;
|
|
61822
61826
|
}
|
|
61823
|
-
function
|
|
61824
|
-
return config.
|
|
61827
|
+
function isWorkspaceEnrolled(config, workspacePath) {
|
|
61828
|
+
return config.workspaceBindings[workspacePath]?.enrolledAt !== void 0;
|
|
61825
61829
|
}
|
|
61826
|
-
|
|
61827
|
-
|
|
61828
|
-
const add = async (workspacePath, enrolledAt = config.createdAt, ideType) => {
|
|
61829
|
-
const canonical2 = await canonicalizeWorkspacePath(workspacePath);
|
|
61830
|
-
inferred[canonical2] ??= { enrolledAt, ...ideType ? { ideType } : {} };
|
|
61831
|
-
};
|
|
61832
|
-
for (const [workspacePath, binding] of Object.entries(config.workspaceBindings)) {
|
|
61833
|
-
if (binding.projectId > 0) await add(workspacePath, binding.boundAt, binding.ideType);
|
|
61834
|
-
}
|
|
61835
|
-
const manifest = await readJson(getManifestPath());
|
|
61836
|
-
for (const key of Object.keys(manifest?.scopes ?? {})) {
|
|
61837
|
-
const parsed = parseScopeKey(key);
|
|
61838
|
-
if (parsed.scope === "project" && parsed.workspacePath) await add(parsed.workspacePath);
|
|
61839
|
-
}
|
|
61840
|
-
const models = await readJson(getModelManifestPath());
|
|
61841
|
-
for (const workspacePath of Object.keys(models?.workspaceModels ?? {})) await add(workspacePath);
|
|
61842
|
-
const projectHomes = await listDirs(path76.join(getTeamaiHomePath(), "projects")).catch(() => []);
|
|
61843
|
-
const mcpOwnershipFiles = [
|
|
61844
|
-
path76.join(getTeamaiHomePath(), "managed-local-mcp.json"),
|
|
61845
|
-
...projectHomes.map((dir) => path76.join(getTeamaiHomePath(), "projects", dir, "managed-local-mcp.json"))
|
|
61846
|
-
];
|
|
61847
|
-
for (const file of mcpOwnershipFiles) {
|
|
61848
|
-
const records2 = await readJson(file);
|
|
61849
|
-
for (const [key, owned] of Object.entries(records2 ?? {})) {
|
|
61850
|
-
const match = /^[^:]+:local:(.+)$/.exec(key);
|
|
61851
|
-
if (match?.[1] && owned.length > 0) await add(match[1]);
|
|
61852
|
-
}
|
|
61853
|
-
}
|
|
61854
|
-
return inferred;
|
|
61830
|
+
function hasWorkspaceBindingDecision(binding) {
|
|
61831
|
+
return Boolean(binding && (binding.projectId > 0 || binding.projectName === "__skipped__"));
|
|
61855
61832
|
}
|
|
61856
61833
|
async function loadLocalAgentConfig(options2 = {}) {
|
|
61857
61834
|
const fileConfig = await readJson(getConfigPath());
|
|
@@ -61860,14 +61837,8 @@ async function loadLocalAgentConfig(options2 = {}) {
|
|
|
61860
61837
|
const config = {
|
|
61861
61838
|
...fileConfig,
|
|
61862
61839
|
endpoint: normalizeEndpoint(fileConfig.endpoint),
|
|
61863
|
-
workspaceEnrollments: fileConfig.workspaceEnrollments ?? {},
|
|
61864
61840
|
workspaceBindings: fileConfig.workspaceBindings ?? {}
|
|
61865
61841
|
};
|
|
61866
|
-
let enrollmentMigrationChanged = false;
|
|
61867
|
-
if (fileConfig.workspaceEnrollments === void 0) {
|
|
61868
|
-
config.workspaceEnrollments = await inferWorkspaceEnrollments(config);
|
|
61869
|
-
enrollmentMigrationChanged = true;
|
|
61870
|
-
}
|
|
61871
61842
|
const removedLegacyPaths = [];
|
|
61872
61843
|
for (const [wsPath, binding] of Object.entries(config.workspaceBindings)) {
|
|
61873
61844
|
if ("groupId" in binding && !("projectId" in binding)) {
|
|
@@ -61875,20 +61846,15 @@ async function loadLocalAgentConfig(options2 = {}) {
|
|
|
61875
61846
|
removedLegacyPaths.push(wsPath);
|
|
61876
61847
|
}
|
|
61877
61848
|
}
|
|
61849
|
+
let migrationChanged = removedLegacyPaths.length > 0;
|
|
61878
61850
|
if (removedLegacyPaths.length > 0 && options2.dryRun) {
|
|
61879
61851
|
log.info(`[dry-run] Would remove ${removedLegacyPaths.length} legacy group-based workspace binding(s).`);
|
|
61880
61852
|
} else if (removedLegacyPaths.length > 0) {
|
|
61881
61853
|
log.warn(
|
|
61882
61854
|
`Removed ${removedLegacyPaths.length} legacy group-based workspace binding(s); you will be prompted to re-bind on the next session.`
|
|
61883
61855
|
);
|
|
61884
|
-
try {
|
|
61885
|
-
await saveLocalAgentConfig(config);
|
|
61886
|
-
} catch (e) {
|
|
61887
|
-
log.debug(`local-agent: failed to persist binding cleanup: ${e.message}`);
|
|
61888
|
-
}
|
|
61889
61856
|
}
|
|
61890
61857
|
const migrated = {};
|
|
61891
|
-
let migrationChanged = false;
|
|
61892
61858
|
for (const [wsPath, binding] of Object.entries(config.workspaceBindings)) {
|
|
61893
61859
|
const canonicalKey = await canonicalizeWorkspacePath(wsPath);
|
|
61894
61860
|
if (canonicalKey !== wsPath) migrationChanged = true;
|
|
@@ -61896,14 +61862,14 @@ async function loadLocalAgentConfig(options2 = {}) {
|
|
|
61896
61862
|
migrated[canonicalKey] = mergeWorkspaceBindings(migrated[canonicalKey], binding, canonicalKey);
|
|
61897
61863
|
}
|
|
61898
61864
|
config.workspaceBindings = migrated;
|
|
61899
|
-
|
|
61900
|
-
|
|
61901
|
-
|
|
61902
|
-
|
|
61903
|
-
|
|
61865
|
+
if (fileConfig.workspaceStateVersion !== 1) {
|
|
61866
|
+
for (const binding of Object.values(config.workspaceBindings)) {
|
|
61867
|
+
if (binding.projectId > 0) binding.enrolledAt ??= binding.boundAt;
|
|
61868
|
+
}
|
|
61869
|
+
config.workspaceStateVersion = 1;
|
|
61870
|
+
migrationChanged = true;
|
|
61904
61871
|
}
|
|
61905
|
-
|
|
61906
|
-
if ((migrationChanged || enrollmentMigrationChanged) && !options2.dryRun) {
|
|
61872
|
+
if (migrationChanged && !options2.dryRun) {
|
|
61907
61873
|
await saveLocalAgentConfig(config);
|
|
61908
61874
|
}
|
|
61909
61875
|
return config;
|
|
@@ -61918,7 +61884,7 @@ async function loadLocalAgentConfig(options2 = {}) {
|
|
|
61918
61884
|
endpoint,
|
|
61919
61885
|
token,
|
|
61920
61886
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
61921
|
-
|
|
61887
|
+
workspaceStateVersion: 1,
|
|
61922
61888
|
workspaceBindings: {}
|
|
61923
61889
|
};
|
|
61924
61890
|
if (options2.dryRun) return backfilled;
|
|
@@ -61936,7 +61902,7 @@ async function loadLocalAgentConfig(options2 = {}) {
|
|
|
61936
61902
|
endpoint: normalizeEndpoint(envEndpoint),
|
|
61937
61903
|
token: process.env.TEAMAI_API_TOKEN ?? process.env.TEAMAI_TOKEN,
|
|
61938
61904
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
61939
|
-
|
|
61905
|
+
workspaceStateVersion: 1,
|
|
61940
61906
|
workspaceBindings: {}
|
|
61941
61907
|
};
|
|
61942
61908
|
}
|
|
@@ -61944,7 +61910,7 @@ async function saveLocalAgentConfig(config) {
|
|
|
61944
61910
|
await writeJsonAtomic(getConfigPath(), {
|
|
61945
61911
|
...config,
|
|
61946
61912
|
endpoint: normalizeEndpoint(config.endpoint),
|
|
61947
|
-
|
|
61913
|
+
workspaceStateVersion: 1,
|
|
61948
61914
|
workspaceBindings: config.workspaceBindings ?? {}
|
|
61949
61915
|
});
|
|
61950
61916
|
}
|
|
@@ -62352,14 +62318,15 @@ async function persistWorkspaceBinding(config, cwd, resolvedPath, projectId, pro
|
|
|
62352
62318
|
await saveLocalAgentConfig(config);
|
|
62353
62319
|
}
|
|
62354
62320
|
async function enrollWorkspace(config, resolvedPath) {
|
|
62355
|
-
const
|
|
62356
|
-
|
|
62321
|
+
const enrolledAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
62322
|
+
const binding = config.workspaceBindings[resolvedPath];
|
|
62323
|
+
config.workspaceBindings[resolvedPath] = binding ? { ...binding, enrolledAt: binding.enrolledAt ?? enrolledAt } : { projectId: 0, boundAt: enrolledAt, enrolledAt };
|
|
62357
62324
|
}
|
|
62358
62325
|
async function inheritWorktreeBinding(config, cwd, resolvedPath) {
|
|
62359
62326
|
const anchors = await resolveAnchors(cwd);
|
|
62360
62327
|
if (!anchors || anchors.projectAnchor === anchors.workspaceRoot) return false;
|
|
62361
62328
|
const anchorBinding = config.workspaceBindings[anchors.projectAnchor];
|
|
62362
|
-
if (!anchorBinding) return false;
|
|
62329
|
+
if (!hasWorkspaceBindingDecision(anchorBinding)) return false;
|
|
62363
62330
|
config.workspaceBindings[resolvedPath] = {
|
|
62364
62331
|
...config.workspaceBindings[resolvedPath],
|
|
62365
62332
|
projectId: anchorBinding.projectId,
|
|
@@ -62374,7 +62341,7 @@ async function bindWorkspaceToProject(workspacePath, projectId) {
|
|
|
62374
62341
|
if (!config) {
|
|
62375
62342
|
throw new Error("HTTP local agent is not initialized. Run `teamai init --http <ENDPOINT> --token <API_TOKEN>` first.");
|
|
62376
62343
|
}
|
|
62377
|
-
if (!
|
|
62344
|
+
if (!isWorkspaceEnrolled(config, workspacePath)) {
|
|
62378
62345
|
throw new Error(
|
|
62379
62346
|
"Current workspace is not enrolled. Run `teamai init --http <ENDPOINT> --token <API_TOKEN>` here first."
|
|
62380
62347
|
);
|
|
@@ -62392,8 +62359,8 @@ async function bindWorkspaceToProject(workspacePath, projectId) {
|
|
|
62392
62359
|
return binding;
|
|
62393
62360
|
}
|
|
62394
62361
|
async function ensureWorkspaceBinding(config, workspacePath, sessionId, cwd) {
|
|
62395
|
-
if (!
|
|
62396
|
-
if (config.workspaceBindings[workspacePath]) return;
|
|
62362
|
+
if (!isWorkspaceEnrolled(config, workspacePath)) return;
|
|
62363
|
+
if (hasWorkspaceBindingDecision(config.workspaceBindings[workspacePath])) return;
|
|
62397
62364
|
if (await inheritWorktreeBinding(config, cwd, workspacePath)) return;
|
|
62398
62365
|
const markerKey = sessionId || `ppid-${process.ppid}`;
|
|
62399
62366
|
const hintMarker = path76.join(os9.tmpdir(), `teamai-bind-session-${markerKey}`);
|
|
@@ -62441,8 +62408,8 @@ function isBindPromptTool(tool) {
|
|
|
62441
62408
|
return kind === "codebuddy" || kind === "workbuddy";
|
|
62442
62409
|
}
|
|
62443
62410
|
async function emitBindingHint(config, workspacePath, sessionId, cwd) {
|
|
62444
|
-
if (!
|
|
62445
|
-
if (config.workspaceBindings[workspacePath]) return;
|
|
62411
|
+
if (!isWorkspaceEnrolled(config, workspacePath)) return;
|
|
62412
|
+
if (hasWorkspaceBindingDecision(config.workspaceBindings[workspacePath])) return;
|
|
62446
62413
|
if (await inheritWorktreeBinding(config, cwd, workspacePath)) return;
|
|
62447
62414
|
const markerKey = sessionId || `ppid-${process.ppid}`;
|
|
62448
62415
|
const hintMarker = path76.join(os9.tmpdir(), `teamai-bind-hint-${markerKey}`);
|
|
@@ -62641,14 +62608,9 @@ async function scanModelsFromDisk(tool, workspacePath) {
|
|
|
62641
62608
|
}
|
|
62642
62609
|
async function pruneDeadWorkspaceBindings(config) {
|
|
62643
62610
|
let changed = false;
|
|
62644
|
-
const
|
|
62645
|
-
...Object.keys(config.workspaceBindings),
|
|
62646
|
-
...Object.keys(workspaceEnrollmentsOf(config))
|
|
62647
|
-
]);
|
|
62648
|
-
for (const workspacePath of allPaths) {
|
|
62611
|
+
for (const workspacePath of Object.keys(config.workspaceBindings)) {
|
|
62649
62612
|
if (await isUserHomeDir(workspacePath)) {
|
|
62650
62613
|
delete config.workspaceBindings[workspacePath];
|
|
62651
|
-
delete workspaceEnrollmentsOf(config)[workspacePath];
|
|
62652
62614
|
changed = true;
|
|
62653
62615
|
continue;
|
|
62654
62616
|
}
|
|
@@ -62657,7 +62619,6 @@ async function pruneDeadWorkspaceBindings(config) {
|
|
|
62657
62619
|
} catch (error2) {
|
|
62658
62620
|
if (error2.code === "ENOENT") {
|
|
62659
62621
|
delete config.workspaceBindings[workspacePath];
|
|
62660
|
-
delete workspaceEnrollmentsOf(config)[workspacePath];
|
|
62661
62622
|
changed = true;
|
|
62662
62623
|
} else {
|
|
62663
62624
|
log.debug(
|
|
@@ -62670,26 +62631,18 @@ async function pruneDeadWorkspaceBindings(config) {
|
|
|
62670
62631
|
}
|
|
62671
62632
|
function stampWorkspaceTool(config, currentPath, tool) {
|
|
62672
62633
|
if (!currentPath) return false;
|
|
62673
|
-
const enrollment = workspaceEnrollmentsOf(config)[currentPath];
|
|
62674
|
-
if (!enrollment) return false;
|
|
62675
62634
|
const binding = config.workspaceBindings[currentPath];
|
|
62635
|
+
if (!binding?.enrolledAt) return false;
|
|
62676
62636
|
const normalized = normalizeAgentType(tool);
|
|
62677
|
-
|
|
62678
|
-
|
|
62679
|
-
|
|
62680
|
-
changed = true;
|
|
62681
|
-
}
|
|
62682
|
-
if (binding && binding.ideType !== normalized) {
|
|
62683
|
-
binding.ideType = normalized;
|
|
62684
|
-
changed = true;
|
|
62685
|
-
}
|
|
62686
|
-
return changed;
|
|
62637
|
+
if (binding.ideType === normalized) return false;
|
|
62638
|
+
binding.ideType = normalized;
|
|
62639
|
+
return true;
|
|
62687
62640
|
}
|
|
62688
62641
|
function selectToolWorkspaces(config, currentPath, currentTool) {
|
|
62689
|
-
return Object.keys(
|
|
62690
|
-
const enrollment = workspaceEnrollmentsOf(config)[wsPath];
|
|
62642
|
+
return Object.keys(config.workspaceBindings).filter((wsPath) => {
|
|
62691
62643
|
const b2 = config.workspaceBindings[wsPath];
|
|
62692
|
-
|
|
62644
|
+
if (!b2.enrolledAt) return false;
|
|
62645
|
+
const wsTool = b2.ideType ?? (wsPath === currentPath ? currentTool : void 0);
|
|
62693
62646
|
return wsTool === currentTool;
|
|
62694
62647
|
});
|
|
62695
62648
|
}
|
|
@@ -62751,7 +62704,7 @@ async function buildReportPayload(config, context) {
|
|
|
62751
62704
|
name: path76.basename(wsPath),
|
|
62752
62705
|
ide_type: currentTool
|
|
62753
62706
|
};
|
|
62754
|
-
if (wsBinding
|
|
62707
|
+
if (wsBinding.projectId > 0) workspace.project_id = wsBinding.projectId;
|
|
62755
62708
|
if (wsScope.skills.length > 0) workspace.skills = wsScope.skills;
|
|
62756
62709
|
if (wsScope.rules.length > 0) workspace.rules = wsScope.rules;
|
|
62757
62710
|
const wsMcps = await scanMcpFromManifest("project", tool, wsPath);
|
|
@@ -62780,7 +62733,7 @@ async function buildSyncPayload(config, context) {
|
|
|
62780
62733
|
path: wsPath,
|
|
62781
62734
|
name: path76.basename(wsPath),
|
|
62782
62735
|
ide_type: currentTool,
|
|
62783
|
-
...wsBinding
|
|
62736
|
+
...wsBinding.projectId > 0 ? { project_id: wsBinding.projectId } : {}
|
|
62784
62737
|
};
|
|
62785
62738
|
});
|
|
62786
62739
|
}
|
|
@@ -63852,7 +63805,7 @@ async function applyModelConfig(config, command, context) {
|
|
|
63852
63805
|
if (scope === "project" && !workspacePath) {
|
|
63853
63806
|
throw new Error("apply_model_config: workspace command is missing workspace_path");
|
|
63854
63807
|
}
|
|
63855
|
-
if (workspacePath &&
|
|
63808
|
+
if (workspacePath && !isWorkspaceEnrolled(config, workspacePath)) {
|
|
63856
63809
|
throw new Error(
|
|
63857
63810
|
`apply_model_config: workspace "${path76.basename(workspacePath)}" is not enrolled`
|
|
63858
63811
|
);
|
|
@@ -64377,7 +64330,7 @@ async function executeCommand(config, command, context) {
|
|
|
64377
64330
|
if (normalizeScope(command.scope) === "project") {
|
|
64378
64331
|
const workspacePath2 = await resolveWorkspacePath(command.workspace_path ?? context.cwd);
|
|
64379
64332
|
if (!workspacePath2) throw new Error(`${command.type ?? "workspace command"} is missing workspace_path`);
|
|
64380
|
-
if (!
|
|
64333
|
+
if (!isWorkspaceEnrolled(config, workspacePath2)) {
|
|
64381
64334
|
throw new Error(`Workspace is not enrolled for TeamAI management: ${workspacePath2}`);
|
|
64382
64335
|
}
|
|
64383
64336
|
if (command.project_id !== void 0) {
|
|
@@ -64472,7 +64425,7 @@ async function syncLocalAgent(context) {
|
|
|
64472
64425
|
if (!config) return false;
|
|
64473
64426
|
const workspacePath = await resolveWorkspacePath(context.cwd);
|
|
64474
64427
|
if (isBindPromptEnabled() && isBindPromptTool(context.tool)) {
|
|
64475
|
-
if (workspacePath &&
|
|
64428
|
+
if (workspacePath && isWorkspaceEnrolled(config, workspacePath)) {
|
|
64476
64429
|
const sid = context.event?.sessionId;
|
|
64477
64430
|
if (context.event?.type === "session_start") {
|
|
64478
64431
|
await ensureWorkspaceBinding(config, workspacePath, sid, context.cwd);
|
|
@@ -64674,7 +64627,7 @@ async function initLocalAgentHttp(options2) {
|
|
|
64674
64627
|
endpoint,
|
|
64675
64628
|
token: options2.token ?? existing2?.token,
|
|
64676
64629
|
createdAt: existing2?.createdAt ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
64677
|
-
|
|
64630
|
+
workspaceStateVersion: 1,
|
|
64678
64631
|
workspaceBindings: existing2?.workspaceBindings ?? {},
|
|
64679
64632
|
userGroupId: existing2?.userGroupId,
|
|
64680
64633
|
userGroupName: existing2?.userGroupName
|
|
@@ -64922,18 +64875,12 @@ async function bindCurrentProject(options2) {
|
|
|
64922
64875
|
if (!config) {
|
|
64923
64876
|
throw new Error("Local agent not initialized. Run `teamai init --http` first.");
|
|
64924
64877
|
}
|
|
64925
|
-
if (!
|
|
64878
|
+
if (!isWorkspaceEnrolled(config, workspacePath)) {
|
|
64926
64879
|
throw new Error(
|
|
64927
64880
|
"Current workspace is not enrolled. Run `teamai init --http <ENDPOINT> --token <API_TOKEN>` here first."
|
|
64928
64881
|
);
|
|
64929
64882
|
}
|
|
64930
|
-
await persistWorkspaceBinding(
|
|
64931
|
-
config,
|
|
64932
|
-
options2?.cwd ?? process.cwd(),
|
|
64933
|
-
workspacePath,
|
|
64934
|
-
0,
|
|
64935
|
-
"__skipped__"
|
|
64936
|
-
);
|
|
64883
|
+
await persistWorkspaceBinding(config, options2?.cwd ?? process.cwd(), workspacePath, 0, "__skipped__");
|
|
64937
64884
|
log.info(`\u5DF2\u8DF3\u8FC7\u7ED1\u5B9A\uFF0C\u4EE5\u540E\u4E0D\u518D\u63D0\u793A\u6B64\u5DE5\u4F5C\u533A\u3002`);
|
|
64938
64885
|
return;
|
|
64939
64886
|
}
|