teamai-cli 0.16.6 → 0.16.7
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/index.js +348 -110
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -128,11 +128,6 @@ function getStatePath(scope, projectRoot) {
|
|
|
128
128
|
function getPushignorePath() {
|
|
129
129
|
return path2.join(process.env.HOME ?? "", ".teamai", "pushignore");
|
|
130
130
|
}
|
|
131
|
-
function isWikiEnabled() {
|
|
132
|
-
if (process.env.TEAMAI_WIKI_DISABLED === "1" || process.env.TEAMAI_WIKI_DISABLED === "true") return false;
|
|
133
|
-
if (process.env.TEAMAI_WIKI_ENABLED === "0" || process.env.TEAMAI_WIKI_ENABLED === "false") return false;
|
|
134
|
-
return true;
|
|
135
|
-
}
|
|
136
131
|
var ToolPathsSchema, ScopeEnum, SharingConfigSchema, SourceConfigSchema, SOURCE_PULL_TTL_MS, TEAMAI_SOURCES_DIR, TeamaiConfigSchema, MemberConfigSchema, LocalConfigSchema, StateSchema, TEAMAI_HOME, TEAMAI_CONFIG_PATH, TEAMAI_STATE_PATH, TEAMAI_TOKEN_PATH, TEAMAI_UPDATE_LOCK_PATH, TEAMAI_RULES_START, TEAMAI_RULES_END, TEAMAI_HOOK_DESCRIPTION_PREFIX, TEAMAI_ENV_START, TEAMAI_ENV_END, TEAMAI_CULTURE_START, TEAMAI_CULTURE_END, TEAMAI_CLAUDEMD_START, TEAMAI_CLAUDEMD_END, SKILL_NAME_REGEX, TEAMAI_USAGE_PATH, TEAMAI_KNOWN_SKILLS_PATH, TEAMAI_PUSHIGNORE_PATH, TEAMAI_SESSIONS_DIR, UsageEventSchema, DASHBOARD_EVENTS_DIR, DASHBOARD_EVENTS_PATH, DASHBOARD_DEFAULT_PORT, DASHBOARD_IDLE_TIMEOUT_MS, DASHBOARD_STALE_TIMEOUT_MS, DASHBOARD_COMPACTION_THRESHOLD, DASHBOARD_STOPPED_DISPLAY_MS, DASHBOARD_PID_CHECK_INTERVAL_MS, CONTRIBUTE_BASE_THRESHOLD, CONTRIBUTE_SMART_THRESHOLD, CONTRIBUTE_SCORE_CACHE_MS, CONTRIBUTE_SESSIONS_DIR, LEARNINGS_LOCAL_DIR, SEARCH_INDEX_PATH, VOTES_LOCAL_DIR, CultureCompanySchema, CultureTeamSchema, CultureFrontmatterSchema;
|
|
137
132
|
var init_types = __esm({
|
|
138
133
|
"src/types.ts"() {
|
|
@@ -812,119 +807,80 @@ var init_config = __esm({
|
|
|
812
807
|
});
|
|
813
808
|
|
|
814
809
|
// src/hooks.ts
|
|
810
|
+
var hooks_exports = {};
|
|
811
|
+
__export(hooks_exports, {
|
|
812
|
+
CLAUDE_TO_CURSOR_EVENTS: () => CLAUDE_TO_CURSOR_EVENTS,
|
|
813
|
+
TEAMAI_HOOK_SUBCOMMANDS: () => TEAMAI_HOOK_SUBCOMMANDS,
|
|
814
|
+
TEAMAI_LEGACY_HOOK_SUBCOMMANDS: () => TEAMAI_LEGACY_HOOK_SUBCOMMANDS,
|
|
815
|
+
injectHooks: () => injectHooks,
|
|
816
|
+
injectHooksToAllTools: () => injectHooksToAllTools,
|
|
817
|
+
removeHooks: () => removeHooks
|
|
818
|
+
});
|
|
815
819
|
import path6 from "path";
|
|
816
|
-
function
|
|
817
|
-
|
|
818
|
-
}
|
|
819
|
-
function getTrackSlashCommand(tool) {
|
|
820
|
-
return `bash -lc "teamai track-slash --stdin --tool ${tool} 2>/dev/null" || true`;
|
|
821
|
-
}
|
|
822
|
-
function getDashboardReportCommand(tool) {
|
|
823
|
-
return `bash -lc "teamai dashboard-report --stdin --tool ${tool} 2>/dev/null" || true`;
|
|
824
|
-
}
|
|
825
|
-
function getAutoRecallCommand(tool) {
|
|
826
|
-
return `bash -lc "teamai auto-recall --stdin 2>/dev/null" || true`;
|
|
827
|
-
}
|
|
828
|
-
function getContributeCheckCommand(tool) {
|
|
829
|
-
return `bash -lc "teamai contribute-check --stdin --tool ${tool} 2>/dev/null" || true`;
|
|
820
|
+
function getDispatchCommand(event, tool, matcher) {
|
|
821
|
+
const matcherArg = matcher && matcher !== "*" ? ` --matcher ${matcher}` : "";
|
|
822
|
+
return `bash -lc "teamai hook-dispatch ${event} --tool ${tool}${matcherArg} 2>/dev/null" || true`;
|
|
830
823
|
}
|
|
831
824
|
function getClaudeHooks(tool) {
|
|
832
825
|
return [
|
|
826
|
+
// ─── SessionStart: single dispatcher handles pull + dashboard-report ────
|
|
833
827
|
{
|
|
834
828
|
eventType: "SessionStart",
|
|
835
|
-
descriptionKeyword: "
|
|
829
|
+
descriptionKeyword: "Hook dispatch session-start",
|
|
836
830
|
hook: {
|
|
837
831
|
matcher: "*",
|
|
838
|
-
hooks: [{ type: "command", command:
|
|
839
|
-
description: `${TEAMAI_HOOK_DESCRIPTION_PREFIX}
|
|
832
|
+
hooks: [{ type: "command", command: getDispatchCommand("session-start", tool) }],
|
|
833
|
+
description: `${TEAMAI_HOOK_DESCRIPTION_PREFIX} Hook dispatch session-start`
|
|
840
834
|
}
|
|
841
835
|
},
|
|
836
|
+
// ─── Stop: single dispatcher handles update + contribute-check + dashboard-report ────
|
|
842
837
|
{
|
|
843
838
|
eventType: "Stop",
|
|
844
|
-
descriptionKeyword: "
|
|
839
|
+
descriptionKeyword: "Hook dispatch stop",
|
|
845
840
|
hook: {
|
|
846
841
|
matcher: "*",
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
hooks: [{ type: "command", command: TEAMAI_UPDATE_COMMAND, timeout: 10 }],
|
|
850
|
-
description: `${TEAMAI_HOOK_DESCRIPTION_PREFIX} Auto-update on session end`
|
|
842
|
+
hooks: [{ type: "command", command: getDispatchCommand("stop", tool) }],
|
|
843
|
+
description: `${TEAMAI_HOOK_DESCRIPTION_PREFIX} Hook dispatch stop`
|
|
851
844
|
}
|
|
852
845
|
},
|
|
853
|
-
// ───
|
|
846
|
+
// ─── PostToolUse (*): dashboard-report ────
|
|
854
847
|
{
|
|
855
|
-
eventType: "
|
|
856
|
-
descriptionKeyword: "
|
|
848
|
+
eventType: "PostToolUse",
|
|
849
|
+
descriptionKeyword: "Hook dispatch post-tool-use wildcard",
|
|
857
850
|
hook: {
|
|
858
851
|
matcher: "*",
|
|
859
|
-
hooks: [{ type: "command", command:
|
|
860
|
-
description: `${TEAMAI_HOOK_DESCRIPTION_PREFIX}
|
|
852
|
+
hooks: [{ type: "command", command: getDispatchCommand("post-tool-use", tool) }],
|
|
853
|
+
description: `${TEAMAI_HOOK_DESCRIPTION_PREFIX} Hook dispatch post-tool-use wildcard`
|
|
861
854
|
}
|
|
862
855
|
},
|
|
856
|
+
// ─── PostToolUse (Skill): track ────
|
|
863
857
|
{
|
|
864
858
|
eventType: "PostToolUse",
|
|
865
|
-
descriptionKeyword: "
|
|
859
|
+
descriptionKeyword: "Hook dispatch post-tool-use Skill",
|
|
866
860
|
hook: {
|
|
867
861
|
matcher: "Skill",
|
|
868
|
-
hooks: [{ type: "command", command:
|
|
869
|
-
description: `${TEAMAI_HOOK_DESCRIPTION_PREFIX}
|
|
862
|
+
hooks: [{ type: "command", command: getDispatchCommand("post-tool-use", tool, "Skill") }],
|
|
863
|
+
description: `${TEAMAI_HOOK_DESCRIPTION_PREFIX} Hook dispatch post-tool-use Skill`
|
|
870
864
|
}
|
|
871
865
|
},
|
|
872
|
-
|
|
873
|
-
eventType: "UserPromptSubmit",
|
|
874
|
-
descriptionKeyword: "Track slash",
|
|
875
|
-
hook: {
|
|
876
|
-
matcher: "*",
|
|
877
|
-
hooks: [{ type: "command", command: getTrackSlashCommand(tool) }],
|
|
878
|
-
description: `${TEAMAI_HOOK_DESCRIPTION_PREFIX} Track slash command usage`
|
|
879
|
-
}
|
|
880
|
-
},
|
|
881
|
-
// ─── Auto-recall (search knowledge base on search tools + Bash errors) ────────
|
|
882
|
-
// Split into 4 precise matchers to avoid spawning a process for tools that
|
|
883
|
-
// would immediately exit (auto-recall only handles Bash/Grep/WebSearch/WebFetch).
|
|
866
|
+
// ─── PostToolUse (Bash/Grep/WebSearch/WebFetch): auto-recall ────
|
|
884
867
|
...["Bash", "Grep", "WebSearch", "WebFetch"].map((matcher) => ({
|
|
885
868
|
eventType: "PostToolUse",
|
|
886
|
-
descriptionKeyword: `
|
|
869
|
+
descriptionKeyword: `Hook dispatch post-tool-use ${matcher}`,
|
|
887
870
|
hook: {
|
|
888
871
|
matcher,
|
|
889
|
-
hooks: [{ type: "command", command:
|
|
890
|
-
description: `${TEAMAI_HOOK_DESCRIPTION_PREFIX}
|
|
872
|
+
hooks: [{ type: "command", command: getDispatchCommand("post-tool-use", tool, matcher) }],
|
|
873
|
+
description: `${TEAMAI_HOOK_DESCRIPTION_PREFIX} Hook dispatch post-tool-use ${matcher}`
|
|
891
874
|
}
|
|
892
875
|
})),
|
|
893
|
-
// ───
|
|
894
|
-
{
|
|
895
|
-
eventType: "SessionStart",
|
|
896
|
-
descriptionKeyword: "Dashboard report",
|
|
897
|
-
hook: {
|
|
898
|
-
matcher: "*",
|
|
899
|
-
hooks: [{ type: "command", command: getDashboardReportCommand(tool) }],
|
|
900
|
-
description: `${TEAMAI_HOOK_DESCRIPTION_PREFIX} Dashboard report on session start`
|
|
901
|
-
}
|
|
902
|
-
},
|
|
903
|
-
{
|
|
904
|
-
eventType: "Stop",
|
|
905
|
-
descriptionKeyword: "Dashboard stop",
|
|
906
|
-
hook: {
|
|
907
|
-
matcher: "*",
|
|
908
|
-
hooks: [{ type: "command", command: getDashboardReportCommand(tool) }],
|
|
909
|
-
description: `${TEAMAI_HOOK_DESCRIPTION_PREFIX} Dashboard report on session stop`
|
|
910
|
-
}
|
|
911
|
-
},
|
|
912
|
-
{
|
|
913
|
-
eventType: "PostToolUse",
|
|
914
|
-
descriptionKeyword: "Dashboard tool",
|
|
915
|
-
hook: {
|
|
916
|
-
matcher: "*",
|
|
917
|
-
hooks: [{ type: "command", command: getDashboardReportCommand(tool) }],
|
|
918
|
-
description: `${TEAMAI_HOOK_DESCRIPTION_PREFIX} Dashboard report on tool use`
|
|
919
|
-
}
|
|
920
|
-
},
|
|
876
|
+
// ─── UserPromptSubmit: track-slash + dashboard-report ────
|
|
921
877
|
{
|
|
922
878
|
eventType: "UserPromptSubmit",
|
|
923
|
-
descriptionKeyword: "
|
|
879
|
+
descriptionKeyword: "Hook dispatch prompt-submit",
|
|
924
880
|
hook: {
|
|
925
881
|
matcher: "*",
|
|
926
|
-
hooks: [{ type: "command", command:
|
|
927
|
-
description: `${TEAMAI_HOOK_DESCRIPTION_PREFIX}
|
|
882
|
+
hooks: [{ type: "command", command: getDispatchCommand("prompt-submit", tool) }],
|
|
883
|
+
description: `${TEAMAI_HOOK_DESCRIPTION_PREFIX} Hook dispatch prompt-submit`
|
|
928
884
|
}
|
|
929
885
|
}
|
|
930
886
|
];
|
|
@@ -932,26 +888,22 @@ function getClaudeHooks(tool) {
|
|
|
932
888
|
function buildCursorHooks(tool) {
|
|
933
889
|
return {
|
|
934
890
|
sessionStart: [
|
|
935
|
-
{ command:
|
|
936
|
-
{ command: getDashboardReportCommand(tool), timeout: 10 }
|
|
891
|
+
{ command: getDispatchCommand("session-start", tool), timeout: 60 }
|
|
937
892
|
],
|
|
938
893
|
stop: [
|
|
939
|
-
{ command:
|
|
940
|
-
{ command: getDashboardReportCommand(tool), timeout: 10 },
|
|
941
|
-
{ command: getContributeCheckCommand(tool), timeout: 10 }
|
|
894
|
+
{ command: getDispatchCommand("stop", tool), timeout: 15 }
|
|
942
895
|
],
|
|
943
896
|
postToolUse: [
|
|
944
|
-
{ command:
|
|
945
|
-
{ command:
|
|
897
|
+
{ command: getDispatchCommand("post-tool-use", tool), timeout: 10 },
|
|
898
|
+
{ command: getDispatchCommand("post-tool-use", tool, "Skill"), timeout: 10, matcher: "Skill" },
|
|
946
899
|
...["Bash", "Grep", "WebSearch", "WebFetch"].map((matcher) => ({
|
|
947
|
-
command:
|
|
948
|
-
timeout:
|
|
900
|
+
command: getDispatchCommand("post-tool-use", tool, matcher),
|
|
901
|
+
timeout: 10,
|
|
949
902
|
matcher
|
|
950
903
|
}))
|
|
951
904
|
],
|
|
952
905
|
beforeSubmitPrompt: [
|
|
953
|
-
{ command:
|
|
954
|
-
{ command: getDashboardReportCommand(tool), timeout: 10 }
|
|
906
|
+
{ command: getDispatchCommand("prompt-submit", tool), timeout: 10 }
|
|
955
907
|
]
|
|
956
908
|
};
|
|
957
909
|
}
|
|
@@ -1068,6 +1020,22 @@ async function injectCursorHooks(hooksPath, tool) {
|
|
|
1068
1020
|
}
|
|
1069
1021
|
const desiredHooks = buildCursorHooks(tool);
|
|
1070
1022
|
let changed = false;
|
|
1023
|
+
for (const event of Object.keys(hooksJson.hooks)) {
|
|
1024
|
+
const entries = hooksJson.hooks[event];
|
|
1025
|
+
const filtered = entries.filter((h) => {
|
|
1026
|
+
if (!isTeamaiHookCommand(h.command)) return true;
|
|
1027
|
+
const subcmd = extractTeamaiSubcommand(h.command);
|
|
1028
|
+
return subcmd === "hook-dispatch";
|
|
1029
|
+
});
|
|
1030
|
+
if (filtered.length !== entries.length) {
|
|
1031
|
+
changed = true;
|
|
1032
|
+
if (filtered.length === 0) {
|
|
1033
|
+
delete hooksJson.hooks[event];
|
|
1034
|
+
} else {
|
|
1035
|
+
hooksJson.hooks[event] = filtered;
|
|
1036
|
+
}
|
|
1037
|
+
}
|
|
1038
|
+
}
|
|
1071
1039
|
const desiredEvents = new Set(Object.keys(desiredHooks));
|
|
1072
1040
|
for (const event of Object.keys(hooksJson.hooks)) {
|
|
1073
1041
|
if (desiredEvents.has(event)) continue;
|
|
@@ -1161,16 +1129,21 @@ async function injectHooksToAllTools(toolPaths, baseDir) {
|
|
|
1161
1129
|
}
|
|
1162
1130
|
}
|
|
1163
1131
|
}
|
|
1164
|
-
var
|
|
1132
|
+
var TEAMAI_HOOK_SUBCOMMANDS, TEAMAI_LEGACY_HOOK_SUBCOMMANDS, CLAUDE_TO_CURSOR_EVENTS, CURSOR_TOOLS, TEAMAI_COMMAND_MARKERS;
|
|
1165
1133
|
var init_hooks = __esm({
|
|
1166
1134
|
"src/hooks.ts"() {
|
|
1167
1135
|
"use strict";
|
|
1168
1136
|
init_fs();
|
|
1169
1137
|
init_logger();
|
|
1170
1138
|
init_types();
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1139
|
+
TEAMAI_HOOK_SUBCOMMANDS = ["hook-dispatch"];
|
|
1140
|
+
TEAMAI_LEGACY_HOOK_SUBCOMMANDS = ["pull", "update", "track", "track-slash", "dashboard-report", "contribute-check", "auto-recall"];
|
|
1141
|
+
CLAUDE_TO_CURSOR_EVENTS = {
|
|
1142
|
+
SessionStart: "sessionStart",
|
|
1143
|
+
Stop: "stop",
|
|
1144
|
+
PostToolUse: "postToolUse",
|
|
1145
|
+
UserPromptSubmit: "beforeSubmitPrompt"
|
|
1146
|
+
};
|
|
1174
1147
|
CURSOR_TOOLS = /* @__PURE__ */ new Set(["cursor"]);
|
|
1175
1148
|
TEAMAI_COMMAND_MARKERS = [
|
|
1176
1149
|
"teamai pull",
|
|
@@ -2401,6 +2374,10 @@ async function init(options) {
|
|
|
2401
2374
|
if (options.scope === "project" || options.scope === "user") {
|
|
2402
2375
|
scope = options.scope;
|
|
2403
2376
|
} else {
|
|
2377
|
+
const userPath = getTeamaiHome("user");
|
|
2378
|
+
const projectPath = getTeamaiHome("project", process.cwd());
|
|
2379
|
+
log.info(` user \u2192 ${userPath}/`);
|
|
2380
|
+
log.info(` project \u2192 ${projectPath}/`);
|
|
2404
2381
|
const scopeAnswer = await askQuestion("Scope [user/project] (default: user): ", "user");
|
|
2405
2382
|
if (scopeAnswer.toLowerCase() === "project") {
|
|
2406
2383
|
scope = "project";
|
|
@@ -2935,7 +2912,7 @@ function getBuiltinSkillsDir() {
|
|
|
2935
2912
|
const distDir = path12.dirname(new URL(import.meta.url).pathname);
|
|
2936
2913
|
return path12.join(distDir, "..", "skills");
|
|
2937
2914
|
}
|
|
2938
|
-
async function deployBuiltinSkills(teamConfig, localConfig
|
|
2915
|
+
async function deployBuiltinSkills(teamConfig, localConfig) {
|
|
2939
2916
|
const builtinDir = getBuiltinSkillsDir();
|
|
2940
2917
|
if (!await pathExists(builtinDir)) {
|
|
2941
2918
|
log.debug("No built-in skills directory found, skipping deployment");
|
|
@@ -2955,8 +2932,6 @@ async function deployBuiltinSkills(teamConfig, localConfig, options) {
|
|
|
2955
2932
|
}
|
|
2956
2933
|
}
|
|
2957
2934
|
if (skillNames.length === 0) return 0;
|
|
2958
|
-
const filteredSkills = options?.skipWiki ? skillNames.filter((name) => name !== "teamai-wiki") : skillNames;
|
|
2959
|
-
if (filteredSkills.length === 0) return 0;
|
|
2960
2935
|
const baseDir = localConfig ? resolveBaseDir(localConfig) : process.env.HOME ?? "";
|
|
2961
2936
|
let deployed = 0;
|
|
2962
2937
|
for (const [tool, toolPath] of Object.entries(teamConfig.toolPaths)) {
|
|
@@ -2966,7 +2941,7 @@ async function deployBuiltinSkills(teamConfig, localConfig, options) {
|
|
|
2966
2941
|
continue;
|
|
2967
2942
|
}
|
|
2968
2943
|
const targetSkillsDir = path12.join(baseDir, toolPath.skills);
|
|
2969
|
-
for (const skillName of
|
|
2944
|
+
for (const skillName of skillNames) {
|
|
2970
2945
|
const srcDir = path12.join(builtinDir, skillName);
|
|
2971
2946
|
const destDir = path12.join(targetSkillsDir, skillName);
|
|
2972
2947
|
try {
|
|
@@ -4709,7 +4684,7 @@ async function push(options) {
|
|
|
4709
4684
|
log.debug(`Pre-push sync skipped: ${e.message}`);
|
|
4710
4685
|
}
|
|
4711
4686
|
const spin = spinner("Scanning local resources...").start();
|
|
4712
|
-
const pushableTypes =
|
|
4687
|
+
const pushableTypes = ["skills", "rules", "env", "wiki"];
|
|
4713
4688
|
const allItems = [];
|
|
4714
4689
|
for (const type of pushableTypes) {
|
|
4715
4690
|
const handler = getHandler(type);
|
|
@@ -4987,7 +4962,6 @@ var init_push = __esm({
|
|
|
4987
4962
|
init_logger();
|
|
4988
4963
|
init_resources();
|
|
4989
4964
|
init_skills();
|
|
4990
|
-
init_types();
|
|
4991
4965
|
init_roles();
|
|
4992
4966
|
init_prompt();
|
|
4993
4967
|
init_fs();
|
|
@@ -6023,8 +5997,7 @@ async function pullForScope(localConfig, options) {
|
|
|
6023
5997
|
}
|
|
6024
5998
|
const tagsConfig = await loadTagsConfig(localConfig.repo.localPath);
|
|
6025
5999
|
const subscribedTags = localConfig.subscribedTags;
|
|
6026
|
-
const
|
|
6027
|
-
const resourceTypes = wikiEnabled ? ["skills", "rules", "docs", "env", "wiki"] : ["skills", "rules", "docs", "env"];
|
|
6000
|
+
const resourceTypes = ["skills", "rules", "docs", "env", "wiki"];
|
|
6028
6001
|
let totalSynced = 0;
|
|
6029
6002
|
let desiredSkillNames = null;
|
|
6030
6003
|
let knownRepoSkillNames = null;
|
|
@@ -6287,7 +6260,7 @@ async function pullForScope(localConfig, options) {
|
|
|
6287
6260
|
if (!options.dryRun) {
|
|
6288
6261
|
try {
|
|
6289
6262
|
const { deployBuiltinSkills: deployBuiltinSkills2 } = await Promise.resolve().then(() => (init_builtin_skills(), builtin_skills_exports));
|
|
6290
|
-
const deployed = await deployBuiltinSkills2(freshConfig, localConfig
|
|
6263
|
+
const deployed = await deployBuiltinSkills2(freshConfig, localConfig);
|
|
6291
6264
|
if (deployed > 0) {
|
|
6292
6265
|
log.debug(`[${scopeLabel}] Deployed ${deployed} built-in skill(s)`);
|
|
6293
6266
|
}
|
|
@@ -6423,7 +6396,27 @@ async function collectClaudemdFiles(repoPath, roleContext) {
|
|
|
6423
6396
|
}
|
|
6424
6397
|
return contents;
|
|
6425
6398
|
}
|
|
6399
|
+
async function autoMigrateHooksIfNeeded() {
|
|
6400
|
+
const home = process.env.HOME ?? "";
|
|
6401
|
+
const primarySettings = path26.join(home, ".claude", "settings.json");
|
|
6402
|
+
if (!await pathExists(primarySettings)) return;
|
|
6403
|
+
const content = await readFileSafe(primarySettings);
|
|
6404
|
+
if (!content) return;
|
|
6405
|
+
if (content.includes("hook-dispatch")) return;
|
|
6406
|
+
if (!content.includes("teamai")) return;
|
|
6407
|
+
log.debug("Auto-migrating hooks to dispatch format...");
|
|
6408
|
+
const { autoDetectInit: autoDetectInit2 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
6409
|
+
const { injectHooksToAllTools: injectHooksToAllTools2 } = await Promise.resolve().then(() => (init_hooks(), hooks_exports));
|
|
6410
|
+
const { localConfig, teamConfig } = await autoDetectInit2();
|
|
6411
|
+
const baseDir = resolveBaseDir(localConfig);
|
|
6412
|
+
await injectHooksToAllTools2(teamConfig.toolPaths, baseDir);
|
|
6413
|
+
log.debug("Hooks migrated to dispatch format");
|
|
6414
|
+
}
|
|
6426
6415
|
async function pull(options) {
|
|
6416
|
+
try {
|
|
6417
|
+
await autoMigrateHooksIfNeeded();
|
|
6418
|
+
} catch {
|
|
6419
|
+
}
|
|
6427
6420
|
let userConfig = null;
|
|
6428
6421
|
try {
|
|
6429
6422
|
userConfig = await loadLocalConfigForScope("user");
|
|
@@ -6745,10 +6738,6 @@ async function status(options) {
|
|
|
6745
6738
|
for (const [type, count] of Object.entries(counts)) {
|
|
6746
6739
|
console.log(` ${type}: ${count}`);
|
|
6747
6740
|
}
|
|
6748
|
-
if (!isWikiEnabled()) {
|
|
6749
|
-
console.log("");
|
|
6750
|
-
log.info("\u2139 Wiki: disabled (TEAMAI_WIKI_DISABLED=1) \u2014 wiki routing handled by external plugin");
|
|
6751
|
-
}
|
|
6752
6741
|
console.log("");
|
|
6753
6742
|
log.info("Local resources not yet pushed:");
|
|
6754
6743
|
let anyNew = false;
|
|
@@ -6915,7 +6904,6 @@ var init_status = __esm({
|
|
|
6915
6904
|
init_skills();
|
|
6916
6905
|
init_known_agents();
|
|
6917
6906
|
init_agent_skills();
|
|
6918
|
-
init_types();
|
|
6919
6907
|
}
|
|
6920
6908
|
});
|
|
6921
6909
|
|
|
@@ -11081,6 +11069,252 @@ var init_auto_recall = __esm({
|
|
|
11081
11069
|
}
|
|
11082
11070
|
});
|
|
11083
11071
|
|
|
11072
|
+
// src/hook-dispatch.ts
|
|
11073
|
+
function withTimeout(promise, ms, handlerName) {
|
|
11074
|
+
return new Promise((resolve, reject) => {
|
|
11075
|
+
const timer = setTimeout(() => {
|
|
11076
|
+
reject(new Error(`Handler "${handlerName}" exceeded timeout of ${ms}ms`));
|
|
11077
|
+
}, ms);
|
|
11078
|
+
promise.then(
|
|
11079
|
+
(val) => {
|
|
11080
|
+
clearTimeout(timer);
|
|
11081
|
+
resolve(val);
|
|
11082
|
+
},
|
|
11083
|
+
(err) => {
|
|
11084
|
+
clearTimeout(timer);
|
|
11085
|
+
reject(err);
|
|
11086
|
+
}
|
|
11087
|
+
);
|
|
11088
|
+
});
|
|
11089
|
+
}
|
|
11090
|
+
function createDispatcher(config) {
|
|
11091
|
+
return {
|
|
11092
|
+
async dispatch(event, matcher, stdin, tool) {
|
|
11093
|
+
const matched = config.handlers.filter((reg) => {
|
|
11094
|
+
if (reg.event !== event) return false;
|
|
11095
|
+
return reg.matcher === "*" || reg.matcher === matcher;
|
|
11096
|
+
});
|
|
11097
|
+
const settled = await Promise.allSettled(
|
|
11098
|
+
matched.map((reg) => {
|
|
11099
|
+
const timeoutMs = reg.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
11100
|
+
return withTimeout(reg.handler.execute(stdin, tool), timeoutMs, reg.handler.name);
|
|
11101
|
+
})
|
|
11102
|
+
);
|
|
11103
|
+
let output = null;
|
|
11104
|
+
const errors = [];
|
|
11105
|
+
for (let i = 0; i < settled.length; i++) {
|
|
11106
|
+
const result = settled[i];
|
|
11107
|
+
const handlerName = matched[i].handler.name;
|
|
11108
|
+
if (result.status === "rejected") {
|
|
11109
|
+
errors.push({
|
|
11110
|
+
handlerName,
|
|
11111
|
+
error: result.reason instanceof Error ? result.reason : new Error(String(result.reason))
|
|
11112
|
+
});
|
|
11113
|
+
} else if (result.status === "fulfilled" && result.value != null) {
|
|
11114
|
+
if (output === null) {
|
|
11115
|
+
output = result.value;
|
|
11116
|
+
}
|
|
11117
|
+
}
|
|
11118
|
+
}
|
|
11119
|
+
return { output, errors };
|
|
11120
|
+
}
|
|
11121
|
+
};
|
|
11122
|
+
}
|
|
11123
|
+
var DEFAULT_TIMEOUT_MS;
|
|
11124
|
+
var init_hook_dispatch = __esm({
|
|
11125
|
+
"src/hook-dispatch.ts"() {
|
|
11126
|
+
"use strict";
|
|
11127
|
+
DEFAULT_TIMEOUT_MS = 6e4;
|
|
11128
|
+
}
|
|
11129
|
+
});
|
|
11130
|
+
|
|
11131
|
+
// src/hook-handlers.ts
|
|
11132
|
+
function buildHandlerRegistry() {
|
|
11133
|
+
return [
|
|
11134
|
+
// ─── SessionStart ─────────────────────────────────
|
|
11135
|
+
{ event: "session-start", matcher: "*", handler: pullHandler, timeoutMs: PULL_TIMEOUT_MS },
|
|
11136
|
+
{ event: "session-start", matcher: "*", handler: dashboardReportHandler, timeoutMs: DASHBOARD_TIMEOUT_MS },
|
|
11137
|
+
// ─── Stop ─────────────────────────────────────────
|
|
11138
|
+
{ event: "stop", matcher: "*", handler: updateHandler, timeoutMs: UPDATE_TIMEOUT_MS },
|
|
11139
|
+
{ event: "stop", matcher: "*", handler: contributeCheckHandler, timeoutMs: CONTRIBUTE_CHECK_TIMEOUT_MS },
|
|
11140
|
+
{ event: "stop", matcher: "*", handler: dashboardReportHandler, timeoutMs: DASHBOARD_TIMEOUT_MS },
|
|
11141
|
+
// ─── PostToolUse ──────────────────────────────────
|
|
11142
|
+
{ event: "post-tool-use", matcher: "*", handler: dashboardReportHandler, timeoutMs: DASHBOARD_TIMEOUT_MS },
|
|
11143
|
+
{ event: "post-tool-use", matcher: "Skill", handler: trackHandler, timeoutMs: TRACK_TIMEOUT_MS },
|
|
11144
|
+
...["Bash", "Grep", "WebSearch", "WebFetch"].map((m) => ({
|
|
11145
|
+
event: "post-tool-use",
|
|
11146
|
+
matcher: m,
|
|
11147
|
+
handler: autoRecallHandler,
|
|
11148
|
+
timeoutMs: AUTO_RECALL_TIMEOUT_MS
|
|
11149
|
+
})),
|
|
11150
|
+
// ─── UserPromptSubmit ─────────────────────────────
|
|
11151
|
+
{ event: "prompt-submit", matcher: "*", handler: trackSlashHandler, timeoutMs: TRACK_TIMEOUT_MS },
|
|
11152
|
+
{ event: "prompt-submit", matcher: "*", handler: dashboardReportHandler, timeoutMs: DASHBOARD_TIMEOUT_MS }
|
|
11153
|
+
];
|
|
11154
|
+
}
|
|
11155
|
+
var PULL_TIMEOUT_MS, UPDATE_TIMEOUT_MS, TRACK_TIMEOUT_MS, DASHBOARD_TIMEOUT_MS, CONTRIBUTE_CHECK_TIMEOUT_MS, AUTO_RECALL_TIMEOUT_MS, pullHandler, updateHandler, dashboardReportHandler, trackHandler, trackSlashHandler, contributeCheckHandler, autoRecallHandler;
|
|
11156
|
+
var init_hook_handlers = __esm({
|
|
11157
|
+
"src/hook-handlers.ts"() {
|
|
11158
|
+
"use strict";
|
|
11159
|
+
PULL_TIMEOUT_MS = 6e4;
|
|
11160
|
+
UPDATE_TIMEOUT_MS = 1e4;
|
|
11161
|
+
TRACK_TIMEOUT_MS = 5e3;
|
|
11162
|
+
DASHBOARD_TIMEOUT_MS = 5e3;
|
|
11163
|
+
CONTRIBUTE_CHECK_TIMEOUT_MS = 1e4;
|
|
11164
|
+
AUTO_RECALL_TIMEOUT_MS = 1e4;
|
|
11165
|
+
pullHandler = {
|
|
11166
|
+
name: "pull",
|
|
11167
|
+
async execute(_stdin, _tool) {
|
|
11168
|
+
const { pull: pull2 } = await Promise.resolve().then(() => (init_pull(), pull_exports));
|
|
11169
|
+
await pull2({ silent: true });
|
|
11170
|
+
return null;
|
|
11171
|
+
}
|
|
11172
|
+
};
|
|
11173
|
+
updateHandler = {
|
|
11174
|
+
name: "update",
|
|
11175
|
+
async execute(_stdin, _tool) {
|
|
11176
|
+
const { doUpdate: doUpdate2 } = await Promise.resolve().then(() => (init_update(), update_exports));
|
|
11177
|
+
await doUpdate2();
|
|
11178
|
+
return null;
|
|
11179
|
+
}
|
|
11180
|
+
};
|
|
11181
|
+
dashboardReportHandler = {
|
|
11182
|
+
name: "dashboard-report",
|
|
11183
|
+
async execute(stdin, tool) {
|
|
11184
|
+
const { parseHookEvent: parseHookEvent2, appendEvent: appendEvent2, compactEvents: compactEvents2 } = await Promise.resolve().then(() => (init_dashboard_collector(), dashboard_collector_exports));
|
|
11185
|
+
const raw = JSON.stringify(stdin);
|
|
11186
|
+
const event = await parseHookEvent2(raw, tool);
|
|
11187
|
+
if (event) {
|
|
11188
|
+
await appendEvent2(event);
|
|
11189
|
+
compactEvents2().catch(() => {
|
|
11190
|
+
});
|
|
11191
|
+
}
|
|
11192
|
+
return null;
|
|
11193
|
+
}
|
|
11194
|
+
};
|
|
11195
|
+
trackHandler = {
|
|
11196
|
+
name: "track",
|
|
11197
|
+
async execute(stdin, tool) {
|
|
11198
|
+
const { extractSkillName: extractSkillName2, isValidSkillName: isValidSkillName2, appendUsageEvent: appendUsageEvent2, updateKnownSkills: updateKnownSkills2 } = await Promise.resolve().then(() => (init_usage_tracker(), usage_tracker_exports));
|
|
11199
|
+
const toolName = stdin.tool_name;
|
|
11200
|
+
if (typeof toolName !== "string") return null;
|
|
11201
|
+
const toolInput = stdin.tool_input;
|
|
11202
|
+
if (!toolInput || typeof toolInput !== "object") return null;
|
|
11203
|
+
let skillName = null;
|
|
11204
|
+
let toolSource = tool;
|
|
11205
|
+
if (toolName === "Skill") {
|
|
11206
|
+
skillName = extractSkillName2(toolInput);
|
|
11207
|
+
} else if (toolName === "Read") {
|
|
11208
|
+
const filePath = (typeof toolInput.file_path === "string" ? toolInput.file_path : null) ?? (typeof toolInput.path === "string" ? toolInput.path : null);
|
|
11209
|
+
if (typeof filePath === "string" && /\/SKILL\.md$/i.test(filePath)) {
|
|
11210
|
+
skillName = extractSkillName2({ skill: filePath });
|
|
11211
|
+
toolSource = "cursor";
|
|
11212
|
+
}
|
|
11213
|
+
} else {
|
|
11214
|
+
return null;
|
|
11215
|
+
}
|
|
11216
|
+
if (!skillName || !isValidSkillName2(skillName)) return null;
|
|
11217
|
+
await appendUsageEvent2({ skill: skillName, timestamp: (/* @__PURE__ */ new Date()).toISOString(), tool: toolSource });
|
|
11218
|
+
await updateKnownSkills2(skillName);
|
|
11219
|
+
return null;
|
|
11220
|
+
}
|
|
11221
|
+
};
|
|
11222
|
+
trackSlashHandler = {
|
|
11223
|
+
name: "track-slash",
|
|
11224
|
+
async execute(stdin, tool) {
|
|
11225
|
+
const { extractSkillName: extractSkillName2, isValidSkillName: isValidSkillName2, appendUsageEvent: appendUsageEvent2, updateKnownSkills: updateKnownSkills2 } = await Promise.resolve().then(() => (init_usage_tracker(), usage_tracker_exports));
|
|
11226
|
+
const prompt = stdin.prompt;
|
|
11227
|
+
if (typeof prompt !== "string" || !prompt.startsWith("/")) return null;
|
|
11228
|
+
const match = prompt.match(/^\/([\w-]+)/);
|
|
11229
|
+
if (!match) return null;
|
|
11230
|
+
const skillName = match[1];
|
|
11231
|
+
if (!isValidSkillName2(skillName)) return null;
|
|
11232
|
+
await appendUsageEvent2({ skill: skillName, timestamp: (/* @__PURE__ */ new Date()).toISOString(), tool });
|
|
11233
|
+
await updateKnownSkills2(skillName);
|
|
11234
|
+
return null;
|
|
11235
|
+
}
|
|
11236
|
+
};
|
|
11237
|
+
contributeCheckHandler = {
|
|
11238
|
+
name: "contribute-check",
|
|
11239
|
+
async execute(stdin, _tool) {
|
|
11240
|
+
const { contributeCheckForSession: contributeCheckForSession2 } = await Promise.resolve().then(() => (init_contribute_check(), contribute_check_exports));
|
|
11241
|
+
const sessionId = typeof stdin.session_id === "string" ? stdin.session_id : null;
|
|
11242
|
+
if (!sessionId) return null;
|
|
11243
|
+
const { hint } = await contributeCheckForSession2(sessionId);
|
|
11244
|
+
if (hint) {
|
|
11245
|
+
return JSON.stringify({ stopReason: hint });
|
|
11246
|
+
}
|
|
11247
|
+
return null;
|
|
11248
|
+
}
|
|
11249
|
+
};
|
|
11250
|
+
autoRecallHandler = {
|
|
11251
|
+
name: "auto-recall",
|
|
11252
|
+
async execute(stdin, _tool) {
|
|
11253
|
+
const { autoRecall: autoRecall2 } = await Promise.resolve().then(() => (init_auto_recall(), auto_recall_exports));
|
|
11254
|
+
let capturedOutput = null;
|
|
11255
|
+
const originalWrite = process.stdout.write.bind(process.stdout);
|
|
11256
|
+
process.stdout.write = ((chunk) => {
|
|
11257
|
+
if (typeof chunk === "string") {
|
|
11258
|
+
capturedOutput = chunk;
|
|
11259
|
+
} else if (Buffer.isBuffer(chunk)) {
|
|
11260
|
+
capturedOutput = chunk.toString();
|
|
11261
|
+
}
|
|
11262
|
+
return true;
|
|
11263
|
+
});
|
|
11264
|
+
try {
|
|
11265
|
+
await autoRecall2();
|
|
11266
|
+
} finally {
|
|
11267
|
+
process.stdout.write = originalWrite;
|
|
11268
|
+
}
|
|
11269
|
+
return capturedOutput;
|
|
11270
|
+
}
|
|
11271
|
+
};
|
|
11272
|
+
}
|
|
11273
|
+
});
|
|
11274
|
+
|
|
11275
|
+
// src/hook-dispatch-cli.ts
|
|
11276
|
+
var hook_dispatch_cli_exports = {};
|
|
11277
|
+
__export(hook_dispatch_cli_exports, {
|
|
11278
|
+
hookDispatchCli: () => hookDispatchCli
|
|
11279
|
+
});
|
|
11280
|
+
async function readStdin4() {
|
|
11281
|
+
if (process.stdin.isTTY) return "";
|
|
11282
|
+
const chunks = [];
|
|
11283
|
+
for await (const chunk of process.stdin) {
|
|
11284
|
+
chunks.push(chunk);
|
|
11285
|
+
}
|
|
11286
|
+
return Buffer.concat(chunks).toString("utf-8");
|
|
11287
|
+
}
|
|
11288
|
+
async function hookDispatchCli(event, tool, matcher) {
|
|
11289
|
+
const raw = await readStdin4();
|
|
11290
|
+
let stdin = {};
|
|
11291
|
+
if (raw.trim()) {
|
|
11292
|
+
try {
|
|
11293
|
+
stdin = JSON.parse(raw);
|
|
11294
|
+
} catch {
|
|
11295
|
+
log.debug(`hook-dispatch: failed to parse STDIN JSON for event=${event}`);
|
|
11296
|
+
return;
|
|
11297
|
+
}
|
|
11298
|
+
}
|
|
11299
|
+
const registry = buildHandlerRegistry();
|
|
11300
|
+
const dispatcher = createDispatcher({ handlers: registry });
|
|
11301
|
+
const result = await dispatcher.dispatch(event, matcher, stdin, tool);
|
|
11302
|
+
for (const err of result.errors) {
|
|
11303
|
+
log.debug(`hook-dispatch: handler "${err.handlerName}" failed: ${err.error.message}`);
|
|
11304
|
+
}
|
|
11305
|
+
if (result.output) {
|
|
11306
|
+
process.stdout.write(result.output);
|
|
11307
|
+
}
|
|
11308
|
+
}
|
|
11309
|
+
var init_hook_dispatch_cli = __esm({
|
|
11310
|
+
"src/hook-dispatch-cli.ts"() {
|
|
11311
|
+
"use strict";
|
|
11312
|
+
init_hook_dispatch();
|
|
11313
|
+
init_hook_handlers();
|
|
11314
|
+
init_logger();
|
|
11315
|
+
}
|
|
11316
|
+
});
|
|
11317
|
+
|
|
11084
11318
|
// src/index.ts
|
|
11085
11319
|
init_logger();
|
|
11086
11320
|
import { createRequire as createRequire2 } from "module";
|
|
@@ -11357,5 +11591,9 @@ program.command("auto-recall").description("Auto-recall team knowledge on tool e
|
|
|
11357
11591
|
await autoRecall2();
|
|
11358
11592
|
}
|
|
11359
11593
|
});
|
|
11594
|
+
program.command("hook-dispatch <event>").description("Unified hook dispatcher \u2014 handles all teamai hooks for a given event in one process").option("--tool <name>", "Tool identifier (e.g. claude, claude-internal, cursor)").option("--matcher <matcher>", "Hook matcher for PostToolUse (e.g. Skill, Bash)").action(async (event, cmdOpts) => {
|
|
11595
|
+
const { hookDispatchCli: hookDispatchCli2 } = await Promise.resolve().then(() => (init_hook_dispatch_cli(), hook_dispatch_cli_exports));
|
|
11596
|
+
await hookDispatchCli2(event, cmdOpts.tool ?? "claude", cmdOpts.matcher ?? "*");
|
|
11597
|
+
});
|
|
11360
11598
|
program.parse();
|
|
11361
11599
|
//# sourceMappingURL=index.js.map
|