crewly 1.20.394 → 1.20.396

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 (25) hide show
  1. package/dist/backend/backend/src/constants.d.ts +35 -0
  2. package/dist/backend/backend/src/constants.d.ts.map +1 -1
  3. package/dist/backend/backend/src/constants.js +35 -0
  4. package/dist/backend/backend/src/constants.js.map +1 -1
  5. package/dist/backend/backend/src/index.d.ts.map +1 -1
  6. package/dist/backend/backend/src/index.js +23 -3
  7. package/dist/backend/backend/src/index.js.map +1 -1
  8. package/dist/backend/backend/src/services/stall/claim-check.d.ts +26 -2
  9. package/dist/backend/backend/src/services/stall/claim-check.d.ts.map +1 -1
  10. package/dist/backend/backend/src/services/stall/claim-check.js +44 -4
  11. package/dist/backend/backend/src/services/stall/claim-check.js.map +1 -1
  12. package/dist/backend/backend/src/services/wiki/wiki-knowledge-gaps.service.d.ts +198 -0
  13. package/dist/backend/backend/src/services/wiki/wiki-knowledge-gaps.service.d.ts.map +1 -0
  14. package/dist/backend/backend/src/services/wiki/wiki-knowledge-gaps.service.js +366 -0
  15. package/dist/backend/backend/src/services/wiki/wiki-knowledge-gaps.service.js.map +1 -0
  16. package/dist/backend/backend/src/services/wiki/wiki-maintenance.service.d.ts +6 -1
  17. package/dist/backend/backend/src/services/wiki/wiki-maintenance.service.d.ts.map +1 -1
  18. package/dist/backend/backend/src/services/wiki/wiki-maintenance.service.js +8 -2
  19. package/dist/backend/backend/src/services/wiki/wiki-maintenance.service.js.map +1 -1
  20. package/dist/backend/build-info.json +2 -2
  21. package/dist/cli/backend/src/constants.d.ts +35 -0
  22. package/dist/cli/backend/src/constants.d.ts.map +1 -1
  23. package/dist/cli/backend/src/constants.js +35 -0
  24. package/dist/cli/backend/src/constants.js.map +1 -1
  25. package/package.json +1 -1
@@ -30,12 +30,32 @@ export interface TeammateClaim {
30
30
  * @returns Patterns that match a claim about that teammate
31
31
  */
32
32
  export declare function claimPatternsFor(name: string): RegExp[];
33
+ /**
34
+ * Where a sentence first claims the named teammate, or -1.
35
+ *
36
+ * @param sentence - One sentence of the post
37
+ * @param patterns - The claim patterns for one name
38
+ * @returns Index of the earliest match, or -1 when none matches
39
+ */
40
+ export declare function claimIndex(sentence: string, patterns: readonly RegExp[]): number;
41
+ /**
42
+ * Whether the words before the hand-off make it a plan for later rather than
43
+ * a claim about now: "你看过说可以,我再交给 Dex", "会随这次一起交给 Dex",
44
+ * "once you approve, I'll hand it to Dana" (crewly#1427 item 5). Only the
45
+ * text before the match counts — "交给 Pia 了,你点一下看看" stays a claim.
46
+ *
47
+ * @param sentence - One sentence of the post
48
+ * @param at - Where the claim match starts
49
+ * @returns True when the sentence announces a future or conditional hand-off
50
+ */
51
+ export declare function isPlannedHandOff(sentence: string, at: number): boolean;
33
52
  /**
34
53
  * Claims in an agent's post that a named teammate is doing the work.
35
54
  *
36
55
  * A member is matched by its display name (not the speaker itself); each
37
- * member is reported once, with the first sentence that claims it. Questions
38
- * and negated sentences ("不是 Pia 在做") are skipped.
56
+ * member is reported once, with the first sentence that claims it. Questions,
57
+ * negated sentences ("不是 Pia 在做") and planned hand-offs ("你说可以我再交给
58
+ * Pia") are skipped.
39
59
  *
40
60
  * @param text - The agent's post
41
61
  * @param members - The speaker's teammates (name + session)
@@ -52,6 +72,10 @@ export declare function detectTeammateClaims(text: string, members: readonly Cla
52
72
  /**
53
73
  * The one line the speaker gets when nothing is assigned to the teammate.
54
74
  *
75
+ * The last clause exists because of 2026-10-23: four false nudges each made
76
+ * the agent post a "说明一下,现在没有交给 Dex" note in the owner's thread.
77
+ * A harness check must never produce owner-visible text.
78
+ *
55
79
  * @param memberName - The teammate as named
56
80
  * @param sentence - The claiming sentence
57
81
  * @returns Nudge text
@@ -1 +1 @@
1
- {"version":3,"file":"claim-check.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/stall/claim-check.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAOH,qCAAqC;AACrC,MAAM,WAAW,eAAe;IAC/B,iDAAiD;IACjD,IAAI,EAAE,MAAM,CAAC;IACb,oBAAoB;IACpB,OAAO,EAAE,MAAM,CAAC;CAChB;AAED,iCAAiC;AACjC,MAAM,WAAW,aAAa;IAC7B,6BAA6B;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,0BAA0B;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,4DAA4D;IAC5D,QAAQ,EAAE,MAAM,CAAC;CACjB;AAkBD;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAYvD;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,eAAe,EAAE,EAAE,OAAO,EAAE,MAAM,GAAG,aAAa,EAAE,CAmBxH;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAK3E"}
1
+ {"version":3,"file":"claim-check.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/stall/claim-check.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAOH,qCAAqC;AACrC,MAAM,WAAW,eAAe;IAC/B,iDAAiD;IACjD,IAAI,EAAE,MAAM,CAAC;IACb,oBAAoB;IACpB,OAAO,EAAE,MAAM,CAAC;CAChB;AAED,iCAAiC;AACjC,MAAM,WAAW,aAAa;IAC7B,6BAA6B;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,0BAA0B;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,4DAA4D;IAC5D,QAAQ,EAAE,MAAM,CAAC;CACjB;AAkBD;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAYvD;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CAOhF;AAED;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAGtE;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,eAAe,EAAE,EAAE,OAAO,EAAE,MAAM,GAAG,aAAa,EAAE,CAqBxH;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,cAAc,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAO3E"}
@@ -42,12 +42,43 @@ export function claimPatternsFor(name) {
42
42
  new RegExp(`\\b${C.CLAIM_EN_BEFORE_NAME}\\s+${n}${b}`, 'iu'),
43
43
  ];
44
44
  }
45
+ /**
46
+ * Where a sentence first claims the named teammate, or -1.
47
+ *
48
+ * @param sentence - One sentence of the post
49
+ * @param patterns - The claim patterns for one name
50
+ * @returns Index of the earliest match, or -1 when none matches
51
+ */
52
+ export function claimIndex(sentence, patterns) {
53
+ let at = -1;
54
+ for (const re of patterns) {
55
+ const m = re.exec(sentence);
56
+ if (m && (at === -1 || m.index < at))
57
+ at = m.index;
58
+ }
59
+ return at;
60
+ }
61
+ /**
62
+ * Whether the words before the hand-off make it a plan for later rather than
63
+ * a claim about now: "你看过说可以,我再交给 Dex", "会随这次一起交给 Dex",
64
+ * "once you approve, I'll hand it to Dana" (crewly#1427 item 5). Only the
65
+ * text before the match counts — "交给 Pia 了,你点一下看看" stays a claim.
66
+ *
67
+ * @param sentence - One sentence of the post
68
+ * @param at - Where the claim match starts
69
+ * @returns True when the sentence announces a future or conditional hand-off
70
+ */
71
+ export function isPlannedHandOff(sentence, at) {
72
+ const before = sentence.slice(0, Math.max(0, at));
73
+ return C.CLAIM_PLAN_ZH.test(before) || C.CLAIM_PLAN_EN.test(before);
74
+ }
45
75
  /**
46
76
  * Claims in an agent's post that a named teammate is doing the work.
47
77
  *
48
78
  * A member is matched by its display name (not the speaker itself); each
49
- * member is reported once, with the first sentence that claims it. Questions
50
- * and negated sentences ("不是 Pia 在做") are skipped.
79
+ * member is reported once, with the first sentence that claims it. Questions,
80
+ * negated sentences ("不是 Pia 在做") and planned hand-offs ("你说可以我再交给
81
+ * Pia") are skipped.
51
82
  *
52
83
  * @param text - The agent's post
53
84
  * @param members - The speaker's teammates (name + session)
@@ -75,7 +106,10 @@ export function detectTeammateClaims(text, members, speaker) {
75
106
  if (!s || QUESTION_END.test(s) || NEGATED.test(s))
76
107
  continue;
77
108
  for (const { m, res } of patterns) {
78
- if (seen.has(m.session) || !res.some((re) => re.test(s)))
109
+ if (seen.has(m.session))
110
+ continue;
111
+ const at = claimIndex(s, res);
112
+ if (at === -1 || isPlannedHandOff(s, at))
79
113
  continue;
80
114
  seen.add(m.session);
81
115
  const one = s.replace(/\s+/g, ' ');
@@ -87,12 +121,18 @@ export function detectTeammateClaims(text, members, speaker) {
87
121
  /**
88
122
  * The one line the speaker gets when nothing is assigned to the teammate.
89
123
  *
124
+ * The last clause exists because of 2026-10-23: four false nudges each made
125
+ * the agent post a "说明一下,现在没有交给 Dex" note in the owner's thread.
126
+ * A harness check must never produce owner-visible text.
127
+ *
90
128
  * @param memberName - The teammate as named
91
129
  * @param sentence - The claiming sentence
92
130
  * @returns Nudge text
93
131
  */
94
132
  export function claimNudgeText(memberName, sentence) {
95
133
  return (`${C.CLAIM_CHECK_TAG} You told the owner ${memberName} is doing it ("${sentence}"); nothing is assigned to ${memberName} ` +
96
- `(no work item or ticket for ${memberName} within ${Math.round(C.CLAIM_CHECK_WINDOW_MS / 60_000)} minutes of that reply). Delegate it now, or correct the thread.`);
134
+ `(no work item or ticket for ${memberName} within ${Math.round(C.CLAIM_CHECK_WINDOW_MS / 60_000)} minutes of that reply). ` +
135
+ `Delegate it now, or fix the wording in your next reply if you misspoke. If it was only a plan for later, do nothing — ` +
136
+ `and never post about this note in the owner's thread.`);
97
137
  }
98
138
  //# sourceMappingURL=claim-check.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"claim-check.js","sourceRoot":"","sources":["../../../../../../backend/src/services/stall/claim-check.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"claim-check.js","sourceRoot":"","sources":["../../../../../../backend/src/services/stall/claim-check.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,198 @@
1
+ /**
2
+ * WikiKnowledgeGapsService — turns the week's zero-hit queries into a page
3
+ * and one piece of work for the team lead (#914 P1).
4
+ *
5
+ * `wiki-query` and `recall` append every query to `llm-curated/usage.jsonl`,
6
+ * including the ones that found nothing. The bookkeep report listed five of
7
+ * them, and nobody read the bookkeep report. Once per ISO week, from the
8
+ * maintenance daily pass, this service:
9
+ *
10
+ * 1. reads the window's ledger events and keeps the misses (`miss` or an
11
+ * empty hit list);
12
+ * 2. folds them by normalised query text into distinct gaps — how often,
13
+ * who asked, first and last time — and drops a gap the vault answered
14
+ * later in the window (the same question later returned hits);
15
+ * 3. writes `llm-curated/gaps/<week>.md` through the normal ingest path
16
+ * (frontmatter, index line, history) — replaced, not appended, when the
17
+ * same week is compiled again;
18
+ * 4. hands the vault's team lead (the orchestrator for the global vault)
19
+ * one WorkItem to decide, per gap, whether it deserves a page. Never
20
+ * when the lead is dormant: a chore is not worth a wake.
21
+ *
22
+ * No LLM. A short query (`QUERY_MIN_CHARS`) is a stray token and ignored; a
23
+ * long one (`QUERY_MAX_CHARS`) is pasted text, counted but not listed.
24
+ *
25
+ * @module services/wiki/wiki-knowledge-gaps.service
26
+ */
27
+ import { type WorkItem } from '../../types/v2/work-item.types.js';
28
+ import { WikiIngestService } from './wiki-ingest.service.js';
29
+ import { WikiUsageService, type WikiUsageEvent } from './wiki-usage.service.js';
30
+ /** One distinct unanswered question. */
31
+ export interface KnowledgeGap {
32
+ /** The query as first asked (original casing, whitespace collapsed). */
33
+ query: string;
34
+ /** Times it was asked and found nothing in the window. */
35
+ count: number;
36
+ /** Agents that asked, most frequent first (capped). */
37
+ agents: string[];
38
+ /** Retrieval paths it came through (`recall`, `wiki-query`, …). */
39
+ via: string[];
40
+ /** ISO time of the first and last miss. */
41
+ firstAt: string;
42
+ lastAt: string;
43
+ }
44
+ /** Outcome of folding a window's events. */
45
+ export interface KnowledgeGapRollup {
46
+ /** Every ledger event in the window. */
47
+ queries: number;
48
+ /** Events that found nothing. */
49
+ misses: number;
50
+ /** Distinct gaps, most-asked first (capped at `MAX_GAPS_PER_PAGE`). */
51
+ gaps: KnowledgeGap[];
52
+ /** Distinct gaps before the cap. */
53
+ distinct: number;
54
+ /** Misses whose query looked like pasted text (longer than `QUERY_MAX_CHARS`). */
55
+ pastedText: number;
56
+ /** Distinct questions that missed first and were answered later in the window. */
57
+ answeredLater: number;
58
+ }
59
+ /** The pool slice this service needs. */
60
+ export interface KnowledgeGapsPool {
61
+ addToPool(workItem: WorkItem): Promise<void>;
62
+ }
63
+ /** Construction options. */
64
+ export interface WikiKnowledgeGapsOptions {
65
+ ingest?: WikiIngestService;
66
+ usage?: WikiUsageService;
67
+ /** Where the lead's review WorkItem goes. Omit to write the page only. */
68
+ pool?: KnowledgeGapsPool;
69
+ /** Team lead for a vault; `null` falls back to `fallbackTarget`. */
70
+ resolveTarget?: (vaultPath: string) => Promise<string | null>;
71
+ /** Whether a target may be given work now; default: always. */
72
+ isTargetAwake?: (sessionName: string) => Promise<boolean>;
73
+ /** Target when no lead resolves (default: the orchestrator). */
74
+ fallbackTarget?: string;
75
+ }
76
+ /** Options for {@link WikiKnowledgeGapsService.compile}. */
77
+ export interface WikiKnowledgeGapsCompileOptions {
78
+ /** Report only; write nothing (page, state or WorkItem). */
79
+ dryRun?: boolean;
80
+ /** Clock (tests). */
81
+ now?: number;
82
+ /** Window override (tests). */
83
+ windowDays?: number;
84
+ /** Compile even when this week was already compiled (the page is replaced; no second WorkItem). */
85
+ force?: boolean;
86
+ }
87
+ /** Outcome of one vault's compile. */
88
+ export interface WikiKnowledgeGapsResult {
89
+ vaultPath: string;
90
+ /** ISO week the page is for. */
91
+ week: string;
92
+ /** False when nothing was (or would be) written. */
93
+ compiled: boolean;
94
+ reason?: 'not_due' | 'no_queries' | 'no_gaps' | 'ingest_refused';
95
+ rollup: KnowledgeGapRollup;
96
+ /** Vault-relative page (planned in a dry run). */
97
+ pagePath?: string;
98
+ /** Lead WorkItem created this run. */
99
+ workItemId?: string;
100
+ /** Who the WorkItem went to (or would go to). */
101
+ target?: string;
102
+ /** Why no WorkItem was created although the page was. */
103
+ workItemSkipped?: 'no_pool' | 'target_dormant' | 'already_raised' | 'dry_run';
104
+ dryRun: boolean;
105
+ }
106
+ /**
107
+ * Normalise a query for grouping: case, whitespace, trailing punctuation.
108
+ *
109
+ * @param query - Raw query text
110
+ * @returns Grouping key
111
+ */
112
+ export declare function gapKey(query: string): string;
113
+ /**
114
+ * Fold a window's ledger events into distinct gaps. Pure.
115
+ *
116
+ * @param events - Ledger events, any order
117
+ * @returns Counts and the distinct gaps, most-asked first then most recent
118
+ *
119
+ * @example
120
+ * ```typescript
121
+ * const r = rollupGaps(events);
122
+ * // r.gaps[0] === { query: 'refund policy', count: 3, agents: ['kai'], … }
123
+ * ```
124
+ */
125
+ export declare function rollupGaps(events: readonly WikiUsageEvent[]): KnowledgeGapRollup;
126
+ /**
127
+ * Weekly knowledge-gap pages per vault. Singleton apart from the per-vault
128
+ * state file; tests construct their own.
129
+ */
130
+ export declare class WikiKnowledgeGapsService {
131
+ private static instance;
132
+ private readonly logger;
133
+ private readonly ingest;
134
+ private readonly usage;
135
+ private readonly pool;
136
+ private readonly resolveTarget;
137
+ private readonly isTargetAwake;
138
+ private readonly fallbackTarget;
139
+ constructor(opts?: WikiKnowledgeGapsOptions);
140
+ static getInstance(): WikiKnowledgeGapsService;
141
+ /** Wire the production instance (built with a pool and a lead resolver). */
142
+ static setInstance(next: WikiKnowledgeGapsService | null): void;
143
+ /** Test-only reset. */
144
+ static _resetForTesting(): void;
145
+ /**
146
+ * Compile one vault's gap page for the current ISO week, once per week.
147
+ *
148
+ * @param vaultPath - Vault root
149
+ * @param opts - Dry run, clock, window and force
150
+ * @returns What was (or would be) written
151
+ *
152
+ * @example
153
+ * ```typescript
154
+ * const r = await WikiKnowledgeGapsService.getInstance().compile(vault);
155
+ * // r.compiled && r.pagePath === 'llm-curated/gaps/2026-W43.md'
156
+ * ```
157
+ */
158
+ compile(vaultPath: string, opts?: WikiKnowledgeGapsCompileOptions): Promise<WikiKnowledgeGapsResult>;
159
+ /**
160
+ * Compile every vault in a list; failures are logged per vault.
161
+ *
162
+ * @param vaults - Vault roots
163
+ * @param opts - Passed to {@link compile}
164
+ * @returns One result per vault that did not throw
165
+ */
166
+ compileAll(vaults: readonly string[], opts?: WikiKnowledgeGapsCompileOptions): Promise<WikiKnowledgeGapsResult[]>;
167
+ /**
168
+ * Markdown body: a dated heading with the counts, one bullet per gap
169
+ * (query, times asked, who, last asked, path), then what the lead does
170
+ * with it.
171
+ *
172
+ * @param rollup - Folded gaps
173
+ * @param now - Epoch ms of the run
174
+ * @param windowDays - Window the counts cover
175
+ * @returns Markdown
176
+ */
177
+ renderBody(rollup: KnowledgeGapRollup, now: number, windowDays: number): string;
178
+ /**
179
+ * The lead's review WorkItem: title with the vault and the count, the
180
+ * rendered page as the brief.
181
+ */
182
+ private buildWorkItem;
183
+ /** Who reviews a vault's gaps: its team lead, else the fallback. */
184
+ private targetFor;
185
+ /** Errors count as dormant: a chore is never worth risking a wake. */
186
+ private targetAwake;
187
+ private statePath;
188
+ private readState;
189
+ private writeState;
190
+ }
191
+ /**
192
+ * Short human label for a vault: the project or team folder it belongs to.
193
+ *
194
+ * @param vaultPath - `<project>/.crewly/wiki`, `~/.crewly/teams/<id>/wiki` or `~/.crewly/global-wiki`
195
+ * @returns `crewly`, `<team-id>` or `global`
196
+ */
197
+ export declare function vaultLabel(vaultPath: string): string;
198
+ //# sourceMappingURL=wiki-knowledge-gaps.service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wiki-knowledge-gaps.service.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/wiki/wiki-knowledge-gaps.service.ts"],"names":[],"mappings":"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"}