teamai-cli 0.16.5 → 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 +343 -91
- package/package.json +3 -3
- package/skills/teamai-wiki/SKILL.md +5 -5
package/dist/index.js
CHANGED
|
@@ -807,119 +807,80 @@ var init_config = __esm({
|
|
|
807
807
|
});
|
|
808
808
|
|
|
809
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
|
+
});
|
|
810
819
|
import path6 from "path";
|
|
811
|
-
function
|
|
812
|
-
|
|
813
|
-
}
|
|
814
|
-
function getTrackSlashCommand(tool) {
|
|
815
|
-
return `bash -lc "teamai track-slash --stdin --tool ${tool} 2>/dev/null" || true`;
|
|
816
|
-
}
|
|
817
|
-
function getDashboardReportCommand(tool) {
|
|
818
|
-
return `bash -lc "teamai dashboard-report --stdin --tool ${tool} 2>/dev/null" || true`;
|
|
819
|
-
}
|
|
820
|
-
function getAutoRecallCommand(tool) {
|
|
821
|
-
return `bash -lc "teamai auto-recall --stdin 2>/dev/null" || true`;
|
|
822
|
-
}
|
|
823
|
-
function getContributeCheckCommand(tool) {
|
|
824
|
-
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`;
|
|
825
823
|
}
|
|
826
824
|
function getClaudeHooks(tool) {
|
|
827
825
|
return [
|
|
826
|
+
// ─── SessionStart: single dispatcher handles pull + dashboard-report ────
|
|
828
827
|
{
|
|
829
828
|
eventType: "SessionStart",
|
|
830
|
-
descriptionKeyword: "
|
|
829
|
+
descriptionKeyword: "Hook dispatch session-start",
|
|
831
830
|
hook: {
|
|
832
831
|
matcher: "*",
|
|
833
|
-
hooks: [{ type: "command", command:
|
|
834
|
-
description: `${TEAMAI_HOOK_DESCRIPTION_PREFIX}
|
|
832
|
+
hooks: [{ type: "command", command: getDispatchCommand("session-start", tool) }],
|
|
833
|
+
description: `${TEAMAI_HOOK_DESCRIPTION_PREFIX} Hook dispatch session-start`
|
|
835
834
|
}
|
|
836
835
|
},
|
|
836
|
+
// ─── Stop: single dispatcher handles update + contribute-check + dashboard-report ────
|
|
837
837
|
{
|
|
838
838
|
eventType: "Stop",
|
|
839
|
-
descriptionKeyword: "
|
|
839
|
+
descriptionKeyword: "Hook dispatch stop",
|
|
840
840
|
hook: {
|
|
841
841
|
matcher: "*",
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
hooks: [{ type: "command", command: TEAMAI_UPDATE_COMMAND, timeout: 10 }],
|
|
845
|
-
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`
|
|
846
844
|
}
|
|
847
845
|
},
|
|
848
|
-
// ───
|
|
846
|
+
// ─── PostToolUse (*): dashboard-report ────
|
|
849
847
|
{
|
|
850
|
-
eventType: "
|
|
851
|
-
descriptionKeyword: "
|
|
848
|
+
eventType: "PostToolUse",
|
|
849
|
+
descriptionKeyword: "Hook dispatch post-tool-use wildcard",
|
|
852
850
|
hook: {
|
|
853
851
|
matcher: "*",
|
|
854
|
-
hooks: [{ type: "command", command:
|
|
855
|
-
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`
|
|
856
854
|
}
|
|
857
855
|
},
|
|
856
|
+
// ─── PostToolUse (Skill): track ────
|
|
858
857
|
{
|
|
859
858
|
eventType: "PostToolUse",
|
|
860
|
-
descriptionKeyword: "
|
|
859
|
+
descriptionKeyword: "Hook dispatch post-tool-use Skill",
|
|
861
860
|
hook: {
|
|
862
861
|
matcher: "Skill",
|
|
863
|
-
hooks: [{ type: "command", command:
|
|
864
|
-
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`
|
|
865
864
|
}
|
|
866
865
|
},
|
|
867
|
-
|
|
868
|
-
eventType: "UserPromptSubmit",
|
|
869
|
-
descriptionKeyword: "Track slash",
|
|
870
|
-
hook: {
|
|
871
|
-
matcher: "*",
|
|
872
|
-
hooks: [{ type: "command", command: getTrackSlashCommand(tool) }],
|
|
873
|
-
description: `${TEAMAI_HOOK_DESCRIPTION_PREFIX} Track slash command usage`
|
|
874
|
-
}
|
|
875
|
-
},
|
|
876
|
-
// ─── Auto-recall (search knowledge base on search tools + Bash errors) ────────
|
|
877
|
-
// Split into 4 precise matchers to avoid spawning a process for tools that
|
|
878
|
-
// would immediately exit (auto-recall only handles Bash/Grep/WebSearch/WebFetch).
|
|
866
|
+
// ─── PostToolUse (Bash/Grep/WebSearch/WebFetch): auto-recall ────
|
|
879
867
|
...["Bash", "Grep", "WebSearch", "WebFetch"].map((matcher) => ({
|
|
880
868
|
eventType: "PostToolUse",
|
|
881
|
-
descriptionKeyword: `
|
|
869
|
+
descriptionKeyword: `Hook dispatch post-tool-use ${matcher}`,
|
|
882
870
|
hook: {
|
|
883
871
|
matcher,
|
|
884
|
-
hooks: [{ type: "command", command:
|
|
885
|
-
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}`
|
|
886
874
|
}
|
|
887
875
|
})),
|
|
888
|
-
// ───
|
|
889
|
-
{
|
|
890
|
-
eventType: "SessionStart",
|
|
891
|
-
descriptionKeyword: "Dashboard report",
|
|
892
|
-
hook: {
|
|
893
|
-
matcher: "*",
|
|
894
|
-
hooks: [{ type: "command", command: getDashboardReportCommand(tool) }],
|
|
895
|
-
description: `${TEAMAI_HOOK_DESCRIPTION_PREFIX} Dashboard report on session start`
|
|
896
|
-
}
|
|
897
|
-
},
|
|
898
|
-
{
|
|
899
|
-
eventType: "Stop",
|
|
900
|
-
descriptionKeyword: "Dashboard stop",
|
|
901
|
-
hook: {
|
|
902
|
-
matcher: "*",
|
|
903
|
-
hooks: [{ type: "command", command: getDashboardReportCommand(tool) }],
|
|
904
|
-
description: `${TEAMAI_HOOK_DESCRIPTION_PREFIX} Dashboard report on session stop`
|
|
905
|
-
}
|
|
906
|
-
},
|
|
907
|
-
{
|
|
908
|
-
eventType: "PostToolUse",
|
|
909
|
-
descriptionKeyword: "Dashboard tool",
|
|
910
|
-
hook: {
|
|
911
|
-
matcher: "*",
|
|
912
|
-
hooks: [{ type: "command", command: getDashboardReportCommand(tool) }],
|
|
913
|
-
description: `${TEAMAI_HOOK_DESCRIPTION_PREFIX} Dashboard report on tool use`
|
|
914
|
-
}
|
|
915
|
-
},
|
|
876
|
+
// ─── UserPromptSubmit: track-slash + dashboard-report ────
|
|
916
877
|
{
|
|
917
878
|
eventType: "UserPromptSubmit",
|
|
918
|
-
descriptionKeyword: "
|
|
879
|
+
descriptionKeyword: "Hook dispatch prompt-submit",
|
|
919
880
|
hook: {
|
|
920
881
|
matcher: "*",
|
|
921
|
-
hooks: [{ type: "command", command:
|
|
922
|
-
description: `${TEAMAI_HOOK_DESCRIPTION_PREFIX}
|
|
882
|
+
hooks: [{ type: "command", command: getDispatchCommand("prompt-submit", tool) }],
|
|
883
|
+
description: `${TEAMAI_HOOK_DESCRIPTION_PREFIX} Hook dispatch prompt-submit`
|
|
923
884
|
}
|
|
924
885
|
}
|
|
925
886
|
];
|
|
@@ -927,26 +888,22 @@ function getClaudeHooks(tool) {
|
|
|
927
888
|
function buildCursorHooks(tool) {
|
|
928
889
|
return {
|
|
929
890
|
sessionStart: [
|
|
930
|
-
{ command:
|
|
931
|
-
{ command: getDashboardReportCommand(tool), timeout: 10 }
|
|
891
|
+
{ command: getDispatchCommand("session-start", tool), timeout: 60 }
|
|
932
892
|
],
|
|
933
893
|
stop: [
|
|
934
|
-
{ command:
|
|
935
|
-
{ command: getDashboardReportCommand(tool), timeout: 10 },
|
|
936
|
-
{ command: getContributeCheckCommand(tool), timeout: 10 }
|
|
894
|
+
{ command: getDispatchCommand("stop", tool), timeout: 15 }
|
|
937
895
|
],
|
|
938
896
|
postToolUse: [
|
|
939
|
-
{ command:
|
|
940
|
-
{ command:
|
|
897
|
+
{ command: getDispatchCommand("post-tool-use", tool), timeout: 10 },
|
|
898
|
+
{ command: getDispatchCommand("post-tool-use", tool, "Skill"), timeout: 10, matcher: "Skill" },
|
|
941
899
|
...["Bash", "Grep", "WebSearch", "WebFetch"].map((matcher) => ({
|
|
942
|
-
command:
|
|
943
|
-
timeout:
|
|
900
|
+
command: getDispatchCommand("post-tool-use", tool, matcher),
|
|
901
|
+
timeout: 10,
|
|
944
902
|
matcher
|
|
945
903
|
}))
|
|
946
904
|
],
|
|
947
905
|
beforeSubmitPrompt: [
|
|
948
|
-
{ command:
|
|
949
|
-
{ command: getDashboardReportCommand(tool), timeout: 10 }
|
|
906
|
+
{ command: getDispatchCommand("prompt-submit", tool), timeout: 10 }
|
|
950
907
|
]
|
|
951
908
|
};
|
|
952
909
|
}
|
|
@@ -1063,6 +1020,22 @@ async function injectCursorHooks(hooksPath, tool) {
|
|
|
1063
1020
|
}
|
|
1064
1021
|
const desiredHooks = buildCursorHooks(tool);
|
|
1065
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
|
+
}
|
|
1066
1039
|
const desiredEvents = new Set(Object.keys(desiredHooks));
|
|
1067
1040
|
for (const event of Object.keys(hooksJson.hooks)) {
|
|
1068
1041
|
if (desiredEvents.has(event)) continue;
|
|
@@ -1156,16 +1129,21 @@ async function injectHooksToAllTools(toolPaths, baseDir) {
|
|
|
1156
1129
|
}
|
|
1157
1130
|
}
|
|
1158
1131
|
}
|
|
1159
|
-
var
|
|
1132
|
+
var TEAMAI_HOOK_SUBCOMMANDS, TEAMAI_LEGACY_HOOK_SUBCOMMANDS, CLAUDE_TO_CURSOR_EVENTS, CURSOR_TOOLS, TEAMAI_COMMAND_MARKERS;
|
|
1160
1133
|
var init_hooks = __esm({
|
|
1161
1134
|
"src/hooks.ts"() {
|
|
1162
1135
|
"use strict";
|
|
1163
1136
|
init_fs();
|
|
1164
1137
|
init_logger();
|
|
1165
1138
|
init_types();
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
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
|
+
};
|
|
1169
1147
|
CURSOR_TOOLS = /* @__PURE__ */ new Set(["cursor"]);
|
|
1170
1148
|
TEAMAI_COMMAND_MARKERS = [
|
|
1171
1149
|
"teamai pull",
|
|
@@ -2396,6 +2374,10 @@ async function init(options) {
|
|
|
2396
2374
|
if (options.scope === "project" || options.scope === "user") {
|
|
2397
2375
|
scope = options.scope;
|
|
2398
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}/`);
|
|
2399
2381
|
const scopeAnswer = await askQuestion("Scope [user/project] (default: user): ", "user");
|
|
2400
2382
|
if (scopeAnswer.toLowerCase() === "project") {
|
|
2401
2383
|
scope = "project";
|
|
@@ -6414,7 +6396,27 @@ async function collectClaudemdFiles(repoPath, roleContext) {
|
|
|
6414
6396
|
}
|
|
6415
6397
|
return contents;
|
|
6416
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
|
+
}
|
|
6417
6415
|
async function pull(options) {
|
|
6416
|
+
try {
|
|
6417
|
+
await autoMigrateHooksIfNeeded();
|
|
6418
|
+
} catch {
|
|
6419
|
+
}
|
|
6418
6420
|
let userConfig = null;
|
|
6419
6421
|
try {
|
|
6420
6422
|
userConfig = await loadLocalConfigForScope("user");
|
|
@@ -11067,6 +11069,252 @@ var init_auto_recall = __esm({
|
|
|
11067
11069
|
}
|
|
11068
11070
|
});
|
|
11069
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
|
+
|
|
11070
11318
|
// src/index.ts
|
|
11071
11319
|
init_logger();
|
|
11072
11320
|
import { createRequire as createRequire2 } from "module";
|
|
@@ -11343,5 +11591,9 @@ program.command("auto-recall").description("Auto-recall team knowledge on tool e
|
|
|
11343
11591
|
await autoRecall2();
|
|
11344
11592
|
}
|
|
11345
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
|
+
});
|
|
11346
11598
|
program.parse();
|
|
11347
11599
|
//# sourceMappingURL=index.js.map
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "teamai-cli",
|
|
3
|
-
"version": "0.16.
|
|
3
|
+
"version": "0.16.7",
|
|
4
4
|
"description": "TeamAI — the team harness for AI agents (skill sync + shared knowledge base, powered by Git)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
|
-
"teamai": "
|
|
7
|
+
"teamai": "dist/index.js"
|
|
8
8
|
},
|
|
9
9
|
"files": [
|
|
10
10
|
"dist/**/*.js",
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
},
|
|
30
30
|
"repository": {
|
|
31
31
|
"type": "git",
|
|
32
|
-
"url": "https://github.com/Tencent/teamai-cli.git"
|
|
32
|
+
"url": "git+https://github.com/Tencent/teamai-cli.git"
|
|
33
33
|
},
|
|
34
34
|
"homepage": "https://github.com/Tencent/teamai-cli#readme",
|
|
35
35
|
"bugs": {
|
|
@@ -243,10 +243,10 @@ When invoked, first determine the subcommand (init/ingest/query/lint/status/expo
|
|
|
243
243
|
|
|
244
244
|
#### Step 1 — Parse arguments
|
|
245
245
|
|
|
246
|
-
- `WIKI_DIR`:
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
246
|
+
- `WIKI_DIR`: 根据当前项目的 teamai scope 决定:
|
|
247
|
+
- 读取 `<projectRoot>/.teamai/config.yaml` 中的 `scope` 字段
|
|
248
|
+
- **project scope** → `<projectRoot>/.teamai/wiki/`
|
|
249
|
+
- **user scope**(或无项目配置时)→ `~/.teamai/wiki/`
|
|
250
250
|
- `SOURCE_DIR`: 可选的 `dir` 参数
|
|
251
251
|
|
|
252
252
|
如果 `WIKI_DIR` 已经存在且包含 `_metadata.json`,提示用户已经初始化过,询问是否要重新初始化。
|
|
@@ -1009,7 +1009,7 @@ Wiki exported to: <path>
|
|
|
1009
1009
|
8. **_metadata.json 是真相来源** — 页面列表、文件哈希、链接图都以此为准。
|
|
1010
1010
|
9. **命名一致性** — 文件名 kebab-case,标题 Title Case 或人类可读中文。
|
|
1011
1011
|
10. **幂等性** — 重复 ingest 同一源目录应产生相同结果(不会重复创建页面)。
|
|
1012
|
-
11. **wiki
|
|
1012
|
+
11. **wiki 路径** — 读取 `<projectRoot>/.teamai/config.yaml` 的 `scope` 字段:project scope 用 `<projectRoot>/.teamai/wiki/`,user scope 用 `~/.teamai/wiki/`。与 teamai push/pull 的 `WikiHandler.getSharedWikiDir()` 逻辑对齐。
|
|
1013
1013
|
12. **Obsidian 兼容** — 所有 `[[links]]` 使用 Obsidian 格式,方便用户在 Obsidian 中直接浏览。
|
|
1014
1014
|
13. **语言** — Wiki 页面内容默认使用中文撰写,技术术语保持英文原文。
|
|
1015
1015
|
14. **智能分类** — LLM 根据内容自动判断页面归属哪个分类目录,无需用户指定。
|