@team-ai/teamai-cli 0.30.1 → 0.30.2
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 +140 -25
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -61820,6 +61820,39 @@ function mergeWorkspaceBindings(existing2, incoming, canonicalKey) {
|
|
|
61820
61820
|
if (!base.ideType) base.ideType = existing2.ideType ?? incoming.ideType;
|
|
61821
61821
|
return base;
|
|
61822
61822
|
}
|
|
61823
|
+
function workspaceEnrollmentsOf(config) {
|
|
61824
|
+
return config.workspaceEnrollments ??= {};
|
|
61825
|
+
}
|
|
61826
|
+
async function inferWorkspaceEnrollments(config) {
|
|
61827
|
+
const inferred = {};
|
|
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;
|
|
61855
|
+
}
|
|
61823
61856
|
async function loadLocalAgentConfig(options2 = {}) {
|
|
61824
61857
|
const fileConfig = await readJson(getConfigPath());
|
|
61825
61858
|
if (fileConfig && "disabled" in fileConfig && fileConfig.disabled === true) return null;
|
|
@@ -61827,8 +61860,14 @@ async function loadLocalAgentConfig(options2 = {}) {
|
|
|
61827
61860
|
const config = {
|
|
61828
61861
|
...fileConfig,
|
|
61829
61862
|
endpoint: normalizeEndpoint(fileConfig.endpoint),
|
|
61863
|
+
workspaceEnrollments: fileConfig.workspaceEnrollments ?? {},
|
|
61830
61864
|
workspaceBindings: fileConfig.workspaceBindings ?? {}
|
|
61831
61865
|
};
|
|
61866
|
+
let enrollmentMigrationChanged = false;
|
|
61867
|
+
if (fileConfig.workspaceEnrollments === void 0) {
|
|
61868
|
+
config.workspaceEnrollments = await inferWorkspaceEnrollments(config);
|
|
61869
|
+
enrollmentMigrationChanged = true;
|
|
61870
|
+
}
|
|
61832
61871
|
const removedLegacyPaths = [];
|
|
61833
61872
|
for (const [wsPath, binding] of Object.entries(config.workspaceBindings)) {
|
|
61834
61873
|
if ("groupId" in binding && !("projectId" in binding)) {
|
|
@@ -61857,7 +61896,14 @@ async function loadLocalAgentConfig(options2 = {}) {
|
|
|
61857
61896
|
migrated[canonicalKey] = mergeWorkspaceBindings(migrated[canonicalKey], binding, canonicalKey);
|
|
61858
61897
|
}
|
|
61859
61898
|
config.workspaceBindings = migrated;
|
|
61860
|
-
|
|
61899
|
+
const migratedEnrollments = {};
|
|
61900
|
+
for (const [wsPath, enrollment] of Object.entries(config.workspaceEnrollments)) {
|
|
61901
|
+
const canonicalKey = await canonicalizeWorkspacePath(wsPath);
|
|
61902
|
+
if (canonicalKey !== wsPath || migratedEnrollments[canonicalKey]) migrationChanged = true;
|
|
61903
|
+
migratedEnrollments[canonicalKey] ??= enrollment;
|
|
61904
|
+
}
|
|
61905
|
+
config.workspaceEnrollments = migratedEnrollments;
|
|
61906
|
+
if ((migrationChanged || enrollmentMigrationChanged) && !options2.dryRun) {
|
|
61861
61907
|
await saveLocalAgentConfig(config);
|
|
61862
61908
|
}
|
|
61863
61909
|
return config;
|
|
@@ -61872,6 +61918,7 @@ async function loadLocalAgentConfig(options2 = {}) {
|
|
|
61872
61918
|
endpoint,
|
|
61873
61919
|
token,
|
|
61874
61920
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
61921
|
+
workspaceEnrollments: {},
|
|
61875
61922
|
workspaceBindings: {}
|
|
61876
61923
|
};
|
|
61877
61924
|
if (options2.dryRun) return backfilled;
|
|
@@ -61889,6 +61936,7 @@ async function loadLocalAgentConfig(options2 = {}) {
|
|
|
61889
61936
|
endpoint: normalizeEndpoint(envEndpoint),
|
|
61890
61937
|
token: process.env.TEAMAI_API_TOKEN ?? process.env.TEAMAI_TOKEN,
|
|
61891
61938
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
61939
|
+
workspaceEnrollments: {},
|
|
61892
61940
|
workspaceBindings: {}
|
|
61893
61941
|
};
|
|
61894
61942
|
}
|
|
@@ -61896,6 +61944,7 @@ async function saveLocalAgentConfig(config) {
|
|
|
61896
61944
|
await writeJsonAtomic(getConfigPath(), {
|
|
61897
61945
|
...config,
|
|
61898
61946
|
endpoint: normalizeEndpoint(config.endpoint),
|
|
61947
|
+
workspaceEnrollments: config.workspaceEnrollments ?? {},
|
|
61899
61948
|
workspaceBindings: config.workspaceBindings ?? {}
|
|
61900
61949
|
});
|
|
61901
61950
|
}
|
|
@@ -62302,6 +62351,10 @@ async function persistWorkspaceBinding(config, cwd, resolvedPath, projectId, pro
|
|
|
62302
62351
|
}
|
|
62303
62352
|
await saveLocalAgentConfig(config);
|
|
62304
62353
|
}
|
|
62354
|
+
async function enrollWorkspace(config, resolvedPath) {
|
|
62355
|
+
const enrollments = workspaceEnrollmentsOf(config);
|
|
62356
|
+
enrollments[resolvedPath] ??= { enrolledAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
62357
|
+
}
|
|
62305
62358
|
async function inheritWorktreeBinding(config, cwd, resolvedPath) {
|
|
62306
62359
|
const anchors = await resolveAnchors(cwd);
|
|
62307
62360
|
if (!anchors || anchors.projectAnchor === anchors.workspaceRoot) return false;
|
|
@@ -62321,6 +62374,11 @@ async function bindWorkspaceToProject(workspacePath, projectId) {
|
|
|
62321
62374
|
if (!config) {
|
|
62322
62375
|
throw new Error("HTTP local agent is not initialized. Run `teamai init --http <ENDPOINT> --token <API_TOKEN>` first.");
|
|
62323
62376
|
}
|
|
62377
|
+
if (!workspaceEnrollmentsOf(config)[workspacePath]) {
|
|
62378
|
+
throw new Error(
|
|
62379
|
+
"Current workspace is not enrolled. Run `teamai init --http <ENDPOINT> --token <API_TOKEN>` here first."
|
|
62380
|
+
);
|
|
62381
|
+
}
|
|
62324
62382
|
const projects = await fetchUserProjects(config);
|
|
62325
62383
|
const project = projectId ? projects.find((item) => item.id === projectId) : await promptForProjectBinding(workspacePath, projects);
|
|
62326
62384
|
if (!project) return null;
|
|
@@ -62334,6 +62392,7 @@ async function bindWorkspaceToProject(workspacePath, projectId) {
|
|
|
62334
62392
|
return binding;
|
|
62335
62393
|
}
|
|
62336
62394
|
async function ensureWorkspaceBinding(config, workspacePath, sessionId, cwd) {
|
|
62395
|
+
if (!workspaceEnrollmentsOf(config)[workspacePath]) return;
|
|
62337
62396
|
if (config.workspaceBindings[workspacePath]) return;
|
|
62338
62397
|
if (await inheritWorktreeBinding(config, cwd, workspacePath)) return;
|
|
62339
62398
|
const markerKey = sessionId || `ppid-${process.ppid}`;
|
|
@@ -62382,6 +62441,7 @@ function isBindPromptTool(tool) {
|
|
|
62382
62441
|
return kind === "codebuddy" || kind === "workbuddy";
|
|
62383
62442
|
}
|
|
62384
62443
|
async function emitBindingHint(config, workspacePath, sessionId, cwd) {
|
|
62444
|
+
if (!workspaceEnrollmentsOf(config)[workspacePath]) return;
|
|
62385
62445
|
if (config.workspaceBindings[workspacePath]) return;
|
|
62386
62446
|
if (await inheritWorktreeBinding(config, cwd, workspacePath)) return;
|
|
62387
62447
|
const markerKey = sessionId || `ppid-${process.ppid}`;
|
|
@@ -62581,9 +62641,14 @@ async function scanModelsFromDisk(tool, workspacePath) {
|
|
|
62581
62641
|
}
|
|
62582
62642
|
async function pruneDeadWorkspaceBindings(config) {
|
|
62583
62643
|
let changed = false;
|
|
62584
|
-
|
|
62644
|
+
const allPaths = /* @__PURE__ */ new Set([
|
|
62645
|
+
...Object.keys(config.workspaceBindings),
|
|
62646
|
+
...Object.keys(workspaceEnrollmentsOf(config))
|
|
62647
|
+
]);
|
|
62648
|
+
for (const workspacePath of allPaths) {
|
|
62585
62649
|
if (await isUserHomeDir(workspacePath)) {
|
|
62586
62650
|
delete config.workspaceBindings[workspacePath];
|
|
62651
|
+
delete workspaceEnrollmentsOf(config)[workspacePath];
|
|
62587
62652
|
changed = true;
|
|
62588
62653
|
continue;
|
|
62589
62654
|
}
|
|
@@ -62592,6 +62657,7 @@ async function pruneDeadWorkspaceBindings(config) {
|
|
|
62592
62657
|
} catch (error2) {
|
|
62593
62658
|
if (error2.code === "ENOENT") {
|
|
62594
62659
|
delete config.workspaceBindings[workspacePath];
|
|
62660
|
+
delete workspaceEnrollmentsOf(config)[workspacePath];
|
|
62595
62661
|
changed = true;
|
|
62596
62662
|
} else {
|
|
62597
62663
|
log.debug(
|
|
@@ -62604,19 +62670,26 @@ async function pruneDeadWorkspaceBindings(config) {
|
|
|
62604
62670
|
}
|
|
62605
62671
|
function stampWorkspaceTool(config, currentPath, tool) {
|
|
62606
62672
|
if (!currentPath) return false;
|
|
62673
|
+
const enrollment = workspaceEnrollmentsOf(config)[currentPath];
|
|
62674
|
+
if (!enrollment) return false;
|
|
62607
62675
|
const binding = config.workspaceBindings[currentPath];
|
|
62608
|
-
if (!binding) return false;
|
|
62609
62676
|
const normalized = normalizeAgentType(tool);
|
|
62610
|
-
|
|
62611
|
-
|
|
62612
|
-
|
|
62677
|
+
let changed = false;
|
|
62678
|
+
if (enrollment.ideType !== normalized) {
|
|
62679
|
+
enrollment.ideType = normalized;
|
|
62680
|
+
changed = true;
|
|
62681
|
+
}
|
|
62682
|
+
if (binding && binding.ideType !== normalized) {
|
|
62683
|
+
binding.ideType = normalized;
|
|
62684
|
+
changed = true;
|
|
62685
|
+
}
|
|
62686
|
+
return changed;
|
|
62613
62687
|
}
|
|
62614
62688
|
function selectToolWorkspaces(config, currentPath, currentTool) {
|
|
62615
|
-
|
|
62616
|
-
|
|
62617
|
-
return Array.from(paths).filter((wsPath) => {
|
|
62689
|
+
return Object.keys(workspaceEnrollmentsOf(config)).filter((wsPath) => {
|
|
62690
|
+
const enrollment = workspaceEnrollmentsOf(config)[wsPath];
|
|
62618
62691
|
const b2 = config.workspaceBindings[wsPath];
|
|
62619
|
-
const wsTool =
|
|
62692
|
+
const wsTool = enrollment.ideType ?? b2?.ideType ?? (wsPath === currentPath ? currentTool : void 0);
|
|
62620
62693
|
return wsTool === currentTool;
|
|
62621
62694
|
});
|
|
62622
62695
|
}
|
|
@@ -62676,9 +62749,9 @@ async function buildReportPayload(config, context) {
|
|
|
62676
62749
|
const workspace = {
|
|
62677
62750
|
path: wsPath,
|
|
62678
62751
|
name: path76.basename(wsPath),
|
|
62679
|
-
ide_type: currentTool
|
|
62680
|
-
project_id: wsBinding?.projectId
|
|
62752
|
+
ide_type: currentTool
|
|
62681
62753
|
};
|
|
62754
|
+
if (wsBinding && wsBinding.projectId > 0) workspace.project_id = wsBinding.projectId;
|
|
62682
62755
|
if (wsScope.skills.length > 0) workspace.skills = wsScope.skills;
|
|
62683
62756
|
if (wsScope.rules.length > 0) workspace.rules = wsScope.rules;
|
|
62684
62757
|
const wsMcps = await scanMcpFromManifest("project", tool, wsPath);
|
|
@@ -62707,7 +62780,7 @@ async function buildSyncPayload(config, context) {
|
|
|
62707
62780
|
path: wsPath,
|
|
62708
62781
|
name: path76.basename(wsPath),
|
|
62709
62782
|
ide_type: currentTool,
|
|
62710
|
-
project_id: wsBinding
|
|
62783
|
+
...wsBinding && wsBinding.projectId > 0 ? { project_id: wsBinding.projectId } : {}
|
|
62711
62784
|
};
|
|
62712
62785
|
});
|
|
62713
62786
|
}
|
|
@@ -63779,9 +63852,9 @@ async function applyModelConfig(config, command, context) {
|
|
|
63779
63852
|
if (scope === "project" && !workspacePath) {
|
|
63780
63853
|
throw new Error("apply_model_config: workspace command is missing workspace_path");
|
|
63781
63854
|
}
|
|
63782
|
-
if (workspacePath && config
|
|
63855
|
+
if (workspacePath && workspaceEnrollmentsOf(config)[workspacePath] === void 0) {
|
|
63783
63856
|
throw new Error(
|
|
63784
|
-
`apply_model_config: workspace "${path76.basename(workspacePath)}" is not
|
|
63857
|
+
`apply_model_config: workspace "${path76.basename(workspacePath)}" is not enrolled`
|
|
63785
63858
|
);
|
|
63786
63859
|
}
|
|
63787
63860
|
if (agentKind === "claude" && workspacePath) {
|
|
@@ -64301,6 +64374,24 @@ async function runMcpCommand(config, command, context) {
|
|
|
64301
64374
|
return command.version;
|
|
64302
64375
|
}
|
|
64303
64376
|
async function executeCommand(config, command, context) {
|
|
64377
|
+
if (normalizeScope(command.scope) === "project") {
|
|
64378
|
+
const workspacePath2 = await resolveWorkspacePath(command.workspace_path ?? context.cwd);
|
|
64379
|
+
if (!workspacePath2) throw new Error(`${command.type ?? "workspace command"} is missing workspace_path`);
|
|
64380
|
+
if (!workspaceEnrollmentsOf(config)[workspacePath2]) {
|
|
64381
|
+
throw new Error(`Workspace is not enrolled for TeamAI management: ${workspacePath2}`);
|
|
64382
|
+
}
|
|
64383
|
+
if (command.project_id !== void 0) {
|
|
64384
|
+
if (!Number.isInteger(command.project_id) || command.project_id <= 0) {
|
|
64385
|
+
throw new Error(`Workspace command has invalid project_id: ${command.project_id}`);
|
|
64386
|
+
}
|
|
64387
|
+
const binding = config.workspaceBindings[workspacePath2];
|
|
64388
|
+
if (!binding || binding.projectId !== command.project_id) {
|
|
64389
|
+
throw new Error(
|
|
64390
|
+
`Workspace project binding does not match command project_id ${command.project_id}: ${workspacePath2}`
|
|
64391
|
+
);
|
|
64392
|
+
}
|
|
64393
|
+
}
|
|
64394
|
+
}
|
|
64304
64395
|
if (command.type === "apply_model_config") {
|
|
64305
64396
|
await applyModelConfig(config, command, context);
|
|
64306
64397
|
return;
|
|
@@ -64379,9 +64470,9 @@ async function reportAndSyncLocalAgent(context) {
|
|
|
64379
64470
|
async function syncLocalAgent(context) {
|
|
64380
64471
|
const config = await loadLocalAgentConfig();
|
|
64381
64472
|
if (!config) return false;
|
|
64473
|
+
const workspacePath = await resolveWorkspacePath(context.cwd);
|
|
64382
64474
|
if (isBindPromptEnabled() && isBindPromptTool(context.tool)) {
|
|
64383
|
-
|
|
64384
|
-
if (workspacePath) {
|
|
64475
|
+
if (workspacePath && workspaceEnrollmentsOf(config)[workspacePath]) {
|
|
64385
64476
|
const sid = context.event?.sessionId;
|
|
64386
64477
|
if (context.event?.type === "session_start") {
|
|
64387
64478
|
await ensureWorkspaceBinding(config, workspacePath, sid, context.cwd);
|
|
@@ -64404,8 +64495,7 @@ async function syncLocalAgent(context) {
|
|
|
64404
64495
|
await maybeReconcilePlugins(context);
|
|
64405
64496
|
}
|
|
64406
64497
|
const pruned = await pruneDeadWorkspaceBindings(config);
|
|
64407
|
-
const
|
|
64408
|
-
const stamped = stampWorkspaceTool(config, currentPath, context.tool ?? "workbuddy");
|
|
64498
|
+
const stamped = stampWorkspaceTool(config, workspacePath, context.tool ?? "workbuddy");
|
|
64409
64499
|
if (pruned || stamped) {
|
|
64410
64500
|
await saveLocalAgentConfig(config);
|
|
64411
64501
|
}
|
|
@@ -64577,17 +64667,20 @@ async function initLocalAgentHttp(options2) {
|
|
|
64577
64667
|
throw new Error("HTTP endpoint is required.");
|
|
64578
64668
|
}
|
|
64579
64669
|
const existing2 = await loadLocalAgentConfig();
|
|
64580
|
-
if (existing2 && !options2.force) {
|
|
64581
|
-
throw new Error("HTTP local agent is
|
|
64670
|
+
if (existing2 && !options2.force && normalizeEndpoint(existing2.endpoint) !== endpoint) {
|
|
64671
|
+
throw new Error("HTTP local agent is initialized with another endpoint. Re-run with --force to overwrite.");
|
|
64582
64672
|
}
|
|
64583
64673
|
const config = {
|
|
64584
64674
|
endpoint,
|
|
64585
|
-
token: options2.token,
|
|
64675
|
+
token: options2.token ?? existing2?.token,
|
|
64586
64676
|
createdAt: existing2?.createdAt ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
64677
|
+
workspaceEnrollments: existing2?.workspaceEnrollments ?? {},
|
|
64587
64678
|
workspaceBindings: existing2?.workspaceBindings ?? {},
|
|
64588
64679
|
userGroupId: existing2?.userGroupId,
|
|
64589
64680
|
userGroupName: existing2?.userGroupName
|
|
64590
64681
|
};
|
|
64682
|
+
const workspacePath = await resolveWorkspacePath(options2.workspacePath ?? process.cwd());
|
|
64683
|
+
if (workspacePath) await enrollWorkspace(config, workspacePath);
|
|
64591
64684
|
await ensureDir(getLocalAgentHome());
|
|
64592
64685
|
await saveLocalAgentConfig(config);
|
|
64593
64686
|
if (options2.token) {
|
|
@@ -64829,7 +64922,18 @@ async function bindCurrentProject(options2) {
|
|
|
64829
64922
|
if (!config) {
|
|
64830
64923
|
throw new Error("Local agent not initialized. Run `teamai init --http` first.");
|
|
64831
64924
|
}
|
|
64832
|
-
|
|
64925
|
+
if (!workspaceEnrollmentsOf(config)[workspacePath]) {
|
|
64926
|
+
throw new Error(
|
|
64927
|
+
"Current workspace is not enrolled. Run `teamai init --http <ENDPOINT> --token <API_TOKEN>` here first."
|
|
64928
|
+
);
|
|
64929
|
+
}
|
|
64930
|
+
await persistWorkspaceBinding(
|
|
64931
|
+
config,
|
|
64932
|
+
options2?.cwd ?? process.cwd(),
|
|
64933
|
+
workspacePath,
|
|
64934
|
+
0,
|
|
64935
|
+
"__skipped__"
|
|
64936
|
+
);
|
|
64833
64937
|
log.info(`\u5DF2\u8DF3\u8FC7\u7ED1\u5B9A\uFF0C\u4EE5\u540E\u4E0D\u518D\u63D0\u793A\u6B64\u5DE5\u4F5C\u533A\u3002`);
|
|
64834
64938
|
return;
|
|
64835
64939
|
}
|
|
@@ -65995,7 +66099,13 @@ async function initHttp(url, options2) {
|
|
|
65995
66099
|
await reconcileHooksForInit(teamConfig, localConfig2, filterAgents2);
|
|
65996
66100
|
const { initLocalAgentHttp: initLocalAgentHttp2 } = await Promise.resolve().then(() => (init_local_agent(), local_agent_exports));
|
|
65997
66101
|
try {
|
|
65998
|
-
await initLocalAgentHttp2({
|
|
66102
|
+
await initLocalAgentHttp2({
|
|
66103
|
+
endpoint: url,
|
|
66104
|
+
token: options2.token,
|
|
66105
|
+
force: options2.force,
|
|
66106
|
+
filterAgents: filterAgents2,
|
|
66107
|
+
workspacePath: projectRoot ?? process.cwd()
|
|
66108
|
+
});
|
|
65999
66109
|
} catch (e) {
|
|
66000
66110
|
log.debug(`Local agent init: ${e.message}`);
|
|
66001
66111
|
}
|
|
@@ -106694,7 +106804,12 @@ async function sourceAddHttp(endpoint, options2) {
|
|
|
106694
106804
|
return;
|
|
106695
106805
|
}
|
|
106696
106806
|
const { initLocalAgentHttp: initLocalAgentHttp2 } = await Promise.resolve().then(() => (init_local_agent(), local_agent_exports));
|
|
106697
|
-
await initLocalAgentHttp2({
|
|
106807
|
+
await initLocalAgentHttp2({
|
|
106808
|
+
endpoint: trimmed2,
|
|
106809
|
+
token: options2.token,
|
|
106810
|
+
force: true,
|
|
106811
|
+
workspacePath: mainConfig?.projectRoot ?? process.cwd()
|
|
106812
|
+
});
|
|
106698
106813
|
log.success(`HTTP source added (${trimmed2}).`);
|
|
106699
106814
|
log.info("It will report/sync on the next AI session (via the hook-dispatch hook already installed).");
|
|
106700
106815
|
}
|