@temet/cli 0.2.0 → 0.3.1

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.
Files changed (38) hide show
  1. package/dist/audit.d.ts +34 -0
  2. package/dist/audit.js +531 -0
  3. package/dist/index.js +85 -40
  4. package/dist/lib/analysis-types.d.ts +7 -0
  5. package/dist/lib/analysis-types.js +1 -0
  6. package/dist/lib/audit-tracking.d.ts +55 -0
  7. package/dist/lib/audit-tracking.js +185 -0
  8. package/dist/lib/cli-args.d.ts +22 -0
  9. package/dist/lib/cli-args.js +65 -0
  10. package/dist/lib/editorial-taxonomy.d.ts +17 -0
  11. package/dist/lib/editorial-taxonomy.js +91 -0
  12. package/dist/lib/heuristics.d.ts +15 -0
  13. package/dist/lib/heuristics.js +341 -0
  14. package/dist/lib/hook-installer.d.ts +13 -0
  15. package/dist/lib/hook-installer.js +130 -0
  16. package/dist/lib/narrator-lite.d.ts +25 -0
  17. package/dist/lib/narrator-lite.js +231 -0
  18. package/dist/lib/notifier.d.ts +9 -0
  19. package/dist/lib/notifier.js +57 -0
  20. package/dist/lib/path-resolver.d.ts +39 -0
  21. package/dist/lib/path-resolver.js +152 -0
  22. package/dist/lib/profile-report.d.ts +18 -0
  23. package/dist/lib/profile-report.js +148 -0
  24. package/dist/lib/report-writer.d.ts +7 -0
  25. package/dist/lib/report-writer.js +73 -0
  26. package/dist/lib/session-audit.d.ts +24 -0
  27. package/dist/lib/session-audit.js +94 -0
  28. package/dist/lib/session-parser.d.ts +35 -0
  29. package/dist/lib/session-parser.js +130 -0
  30. package/dist/lib/skill-mapper.d.ts +3 -0
  31. package/dist/lib/skill-mapper.js +173 -0
  32. package/dist/lib/skill-naming.d.ts +1 -0
  33. package/dist/lib/skill-naming.js +50 -0
  34. package/dist/lib/types.d.ts +17 -0
  35. package/dist/lib/types.js +2 -0
  36. package/dist/lib/workflow-detector.d.ts +11 -0
  37. package/dist/lib/workflow-detector.js +125 -0
  38. package/package.json +2 -2
@@ -0,0 +1,125 @@
1
+ // ---------- Named Patterns ----------
2
+ const NAMED_PATTERNS = [
3
+ { tools: ["Grep", "Read", "Edit"], name: "Search-Understand-Modify" },
4
+ { tools: ["Read", "Edit", "Bash"], name: "Read-Modify-Test" },
5
+ { tools: ["Glob", "Read", "Edit"], name: "Find-Read-Edit" },
6
+ { tools: ["Read", "Edit", "Read"], name: "Read-Edit-Verify" },
7
+ { tools: ["Bash", "Read", "Edit"], name: "Run-Read-Fix" },
8
+ { tools: ["Grep", "Read", "Edit", "Bash"], name: "Search-Read-Edit-Test" },
9
+ ];
10
+ function nameWorkflow(sequence) {
11
+ for (const p of NAMED_PATTERNS) {
12
+ if (p.tools.length === sequence.length &&
13
+ p.tools.every((t, i) => t === sequence[i])) {
14
+ return p.name;
15
+ }
16
+ }
17
+ return sequence.join(" \u2192 ");
18
+ }
19
+ // ---------- Helpers ----------
20
+ /** Collapse consecutive identical tool names: [Read, Read, Read, Edit] → [Read, Edit] */
21
+ function dedup(tools) {
22
+ const result = [];
23
+ for (const t of tools) {
24
+ if (result[result.length - 1] !== t) {
25
+ result.push(t);
26
+ }
27
+ }
28
+ return result;
29
+ }
30
+ function extractToolNames(toolCalls) {
31
+ return toolCalls.map((tc) => tc.name);
32
+ }
33
+ function ngramKey(seq) {
34
+ return seq.join("::");
35
+ }
36
+ function generateNgrams(tools, n, sessionIdx, acc) {
37
+ for (let i = 0; i <= tools.length - n; i++) {
38
+ const gram = tools.slice(i, i + n);
39
+ const key = ngramKey(gram);
40
+ const existing = acc.get(key);
41
+ if (existing) {
42
+ existing.occurrences++;
43
+ existing.sessions.add(sessionIdx);
44
+ }
45
+ else {
46
+ acc.set(key, { occurrences: 1, sessions: new Set([sessionIdx]) });
47
+ }
48
+ }
49
+ }
50
+ /**
51
+ * Remove n-grams that are fully explained by a single longer qualifying n-gram.
52
+ * Uses max (not sum) of explanations from individual longer patterns to avoid
53
+ * double-counting when overlapping longer n-grams explain the same instances.
54
+ */
55
+ function collapseSubsumed(ngrams) {
56
+ const keys = [...ngrams.keys()].sort((a, b) => b.split("::").length - a.split("::").length);
57
+ const kept = new Map();
58
+ // Track the max occurrences any single longer n-gram can explain for each shorter one
59
+ const maxExplained = new Map();
60
+ for (const key of keys) {
61
+ const info = ngrams.get(key);
62
+ const explained = maxExplained.get(key) ?? 0;
63
+ // If a single longer n-gram accounts for all occurrences, skip
64
+ if (explained >= info.occurrences)
65
+ continue;
66
+ kept.set(key, info);
67
+ // Record how many occurrences this pattern can explain for each sub-sequence
68
+ const parts = key.split("::");
69
+ for (let len = parts.length - 1; len >= 3; len--) {
70
+ for (let start = 0; start <= parts.length - len; start++) {
71
+ const sub = ngramKey(parts.slice(start, start + len));
72
+ if (ngrams.has(sub)) {
73
+ const current = maxExplained.get(sub) ?? 0;
74
+ if (info.occurrences > current) {
75
+ maxExplained.set(sub, info.occurrences);
76
+ }
77
+ }
78
+ }
79
+ }
80
+ }
81
+ return kept;
82
+ }
83
+ // ---------- Main ----------
84
+ export function detectWorkflows(allToolCalls) {
85
+ if (allToolCalls.length === 0)
86
+ return [];
87
+ const ngrams = new Map();
88
+ for (let si = 0; si < allToolCalls.length; si++) {
89
+ const tools = dedup(extractToolNames(allToolCalls[si]));
90
+ for (const n of [5, 4, 3]) {
91
+ generateNgrams(tools, n, si, ngrams);
92
+ }
93
+ }
94
+ // Filter: 3+ occurrences AND 2+ distinct sessions
95
+ for (const [key, info] of ngrams) {
96
+ if (info.occurrences < 3 || info.sessions.size < 2) {
97
+ ngrams.delete(key);
98
+ }
99
+ }
100
+ const collapsed = collapseSubsumed(ngrams);
101
+ const workflows = [];
102
+ for (const [key, info] of collapsed) {
103
+ const sequence = key.split("::");
104
+ const confidence = Math.min(0.5 + info.occurrences * 0.05 + info.sessions.size * 0.1, 0.95);
105
+ workflows.push({
106
+ sequence,
107
+ occurrences: info.occurrences,
108
+ sessions: info.sessions.size,
109
+ confidence,
110
+ description: nameWorkflow(sequence),
111
+ });
112
+ }
113
+ // Sort by confidence desc
114
+ workflows.sort((a, b) => b.confidence - a.confidence);
115
+ return workflows;
116
+ }
117
+ export function workflowsToSignals(workflows) {
118
+ return workflows.map((w) => ({
119
+ type: "workflow",
120
+ skill: w.description,
121
+ confidence: w.confidence,
122
+ evidence: `Workflow [${w.sequence.join(" \u2192 ")}] detected ${w.occurrences} times across ${w.sessions} sessions`,
123
+ category: "methodology",
124
+ }));
125
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@temet/cli",
3
- "version": "0.2.0",
4
- "description": "Temet CLI for MCP configuration",
3
+ "version": "0.3.1",
4
+ "description": "Temet CLI discover the skills you already demonstrate in AI work",
5
5
  "keywords": [
6
6
  "temet",
7
7
  "mcp",