crewly 1.20.273 → 1.20.275
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/config/roles/team-leader/tl-addon.md +7 -0
- package/config/skills/agent/core/ask-owner/SKILL.md +20 -6
- package/config/skills/agent/core/ask-owner/execute.sh +18 -6
- package/config/skills/agent/core/ask-owner/execute.test.sh +19 -1
- package/config/skills/agent/core/reply/SKILL.md +11 -0
- package/config/skills/team-leader/propose-tier-change/SKILL.md +62 -0
- package/config/skills/team-leader/propose-tier-change/execute.sh +64 -0
- package/config/skills/team-leader/propose-tier-change/execute.test.sh +75 -0
- package/dist/backend/backend/src/constants.d.ts +62 -6
- package/dist/backend/backend/src/constants.d.ts.map +1 -1
- package/dist/backend/backend/src/constants.js +69 -6
- package/dist/backend/backend/src/constants.js.map +1 -1
- package/dist/backend/backend/src/controllers/request-types.d.ts +2 -0
- package/dist/backend/backend/src/controllers/request-types.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/team/team-model-tiers.controller.d.ts +41 -0
- package/dist/backend/backend/src/controllers/team/team-model-tiers.controller.d.ts.map +1 -0
- package/dist/backend/backend/src/controllers/team/team-model-tiers.controller.js +112 -0
- package/dist/backend/backend/src/controllers/team/team-model-tiers.controller.js.map +1 -0
- package/dist/backend/backend/src/controllers/team/team.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/team/team.controller.js +12 -0
- package/dist/backend/backend/src/controllers/team/team.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/team/team.routes.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/team/team.routes.js +6 -0
- package/dist/backend/backend/src/controllers/team/team.routes.js.map +1 -1
- package/dist/backend/backend/src/index.d.ts.map +1 -1
- package/dist/backend/backend/src/index.js +5 -0
- package/dist/backend/backend/src/index.js.map +1 -1
- package/dist/backend/backend/src/services/ai/prompt-builder.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/ai/prompt-builder.service.js +16 -0
- package/dist/backend/backend/src/services/ai/prompt-builder.service.js.map +1 -1
- package/dist/backend/backend/src/services/ai/prompt-modules/index.d.ts +1 -0
- package/dist/backend/backend/src/services/ai/prompt-modules/index.d.ts.map +1 -1
- package/dist/backend/backend/src/services/ai/prompt-modules/index.js +1 -0
- package/dist/backend/backend/src/services/ai/prompt-modules/index.js.map +1 -1
- package/dist/backend/backend/src/services/ai/prompt-modules/model-tiers.module.d.ts +34 -0
- package/dist/backend/backend/src/services/ai/prompt-modules/model-tiers.module.d.ts.map +1 -0
- package/dist/backend/backend/src/services/ai/prompt-modules/model-tiers.module.js +54 -0
- package/dist/backend/backend/src/services/ai/prompt-modules/model-tiers.module.js.map +1 -0
- package/dist/backend/backend/src/services/ai/prompt-modules/prompt-assembly.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/ai/prompt-modules/prompt-assembly.service.js +2 -0
- package/dist/backend/backend/src/services/ai/prompt-modules/prompt-assembly.service.js.map +1 -1
- package/dist/backend/backend/src/services/ai/prompt-modules/prompt-module.interface.d.ts +13 -0
- package/dist/backend/backend/src/services/ai/prompt-modules/prompt-module.interface.d.ts.map +1 -1
- package/dist/backend/backend/src/services/ai/prompt-modules/prompt-module.interface.js.map +1 -1
- package/dist/backend/backend/src/services/decisions/decision-card.d.ts.map +1 -1
- package/dist/backend/backend/src/services/decisions/decision-card.js +4 -2
- package/dist/backend/backend/src/services/decisions/decision-card.js.map +1 -1
- package/dist/backend/backend/src/services/decisions/decision-routing.js +1 -1
- package/dist/backend/backend/src/services/decisions/decision-routing.js.map +1 -1
- package/dist/backend/backend/src/services/decisions/decision.service.d.ts +95 -2
- package/dist/backend/backend/src/services/decisions/decision.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/decisions/decision.service.js +267 -19
- package/dist/backend/backend/src/services/decisions/decision.service.js.map +1 -1
- package/dist/backend/backend/src/services/model-tiers/model-tier.service.d.ts +251 -0
- package/dist/backend/backend/src/services/model-tiers/model-tier.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/model-tiers/model-tier.service.js +701 -0
- package/dist/backend/backend/src/services/model-tiers/model-tier.service.js.map +1 -0
- package/dist/backend/backend/src/services/model-tiers/model-tier.store.d.ts +82 -0
- package/dist/backend/backend/src/services/model-tiers/model-tier.store.d.ts.map +1 -0
- package/dist/backend/backend/src/services/model-tiers/model-tier.store.js +80 -0
- package/dist/backend/backend/src/services/model-tiers/model-tier.store.js.map +1 -0
- package/dist/backend/backend/src/services/model-tiers/model-tier.wiring.d.ts +26 -0
- package/dist/backend/backend/src/services/model-tiers/model-tier.wiring.d.ts.map +1 -0
- package/dist/backend/backend/src/services/model-tiers/model-tier.wiring.js +54 -0
- package/dist/backend/backend/src/services/model-tiers/model-tier.wiring.js.map +1 -0
- package/dist/backend/backend/src/services/model-tiers/tier-quality.d.ts +102 -0
- package/dist/backend/backend/src/services/model-tiers/tier-quality.d.ts.map +1 -0
- package/dist/backend/backend/src/services/model-tiers/tier-quality.js +116 -0
- package/dist/backend/backend/src/services/model-tiers/tier-quality.js.map +1 -0
- package/dist/backend/backend/src/services/model-tiers/tier-usage-report.d.ts +86 -0
- package/dist/backend/backend/src/services/model-tiers/tier-usage-report.d.ts.map +1 -0
- package/dist/backend/backend/src/services/model-tiers/tier-usage-report.js +148 -0
- package/dist/backend/backend/src/services/model-tiers/tier-usage-report.js.map +1 -0
- package/dist/backend/backend/src/services/open-items/open-item-extractor.d.ts +12 -3
- package/dist/backend/backend/src/services/open-items/open-item-extractor.d.ts.map +1 -1
- package/dist/backend/backend/src/services/open-items/open-item-extractor.js +125 -11
- package/dist/backend/backend/src/services/open-items/open-item-extractor.js.map +1 -1
- package/dist/backend/backend/src/services/open-items/open-items.service.d.ts +7 -7
- package/dist/backend/backend/src/services/open-items/open-items.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/open-items/open-items.service.js +12 -21
- package/dist/backend/backend/src/services/open-items/open-items.service.js.map +1 -1
- package/dist/backend/backend/src/services/open-items/open-items.wiring.d.ts.map +1 -1
- package/dist/backend/backend/src/services/open-items/open-items.wiring.js +0 -8
- package/dist/backend/backend/src/services/open-items/open-items.wiring.js.map +1 -1
- package/dist/backend/backend/src/services/skill/skill-permission.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/skill/skill-permission.service.js +1 -0
- package/dist/backend/backend/src/services/skill/skill-permission.service.js.map +1 -1
- package/dist/backend/backend/src/types/decision.types.d.ts +51 -1
- package/dist/backend/backend/src/types/decision.types.d.ts.map +1 -1
- package/dist/backend/backend/src/types/index.d.ts +20 -0
- package/dist/backend/backend/src/types/index.d.ts.map +1 -1
- package/dist/backend/backend/src/types/index.js.map +1 -1
- package/dist/backend/backend/src/utils/member-default-model.utils.d.ts +24 -8
- package/dist/backend/backend/src/utils/member-default-model.utils.d.ts.map +1 -1
- package/dist/backend/backend/src/utils/member-default-model.utils.js +33 -7
- package/dist/backend/backend/src/utils/member-default-model.utils.js.map +1 -1
- package/dist/backend/backend/src/utils/model-tier.utils.d.ts +68 -0
- package/dist/backend/backend/src/utils/model-tier.utils.d.ts.map +1 -0
- package/dist/backend/backend/src/utils/model-tier.utils.js +111 -0
- package/dist/backend/backend/src/utils/model-tier.utils.js.map +1 -0
- package/dist/backend/build-info.json +2 -2
- package/dist/cli/backend/src/constants.d.ts +62 -6
- package/dist/cli/backend/src/constants.d.ts.map +1 -1
- package/dist/cli/backend/src/constants.js +69 -6
- package/dist/cli/backend/src/constants.js.map +1 -1
- package/dist/cli/backend/src/services/ai/prompt-builder.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/ai/prompt-builder.service.js +16 -0
- package/dist/cli/backend/src/services/ai/prompt-builder.service.js.map +1 -1
- package/dist/cli/backend/src/services/ai/prompt-modules/model-tiers.module.d.ts +34 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/model-tiers.module.d.ts.map +1 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/model-tiers.module.js +54 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/model-tiers.module.js.map +1 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/prompt-assembly.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/ai/prompt-modules/prompt-assembly.service.js +2 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/prompt-assembly.service.js.map +1 -1
- package/dist/cli/backend/src/services/ai/prompt-modules/prompt-module.interface.d.ts +13 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/prompt-module.interface.d.ts.map +1 -1
- package/dist/cli/backend/src/services/ai/prompt-modules/prompt-module.interface.js.map +1 -1
- package/dist/cli/backend/src/services/decisions/decision-card.d.ts.map +1 -1
- package/dist/cli/backend/src/services/decisions/decision-card.js +4 -2
- package/dist/cli/backend/src/services/decisions/decision-card.js.map +1 -1
- package/dist/cli/backend/src/services/decisions/decision.service.d.ts +95 -2
- package/dist/cli/backend/src/services/decisions/decision.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/decisions/decision.service.js +267 -19
- package/dist/cli/backend/src/services/decisions/decision.service.js.map +1 -1
- package/dist/cli/backend/src/services/open-items/open-item-extractor.d.ts +12 -3
- package/dist/cli/backend/src/services/open-items/open-item-extractor.d.ts.map +1 -1
- package/dist/cli/backend/src/services/open-items/open-item-extractor.js +125 -11
- package/dist/cli/backend/src/services/open-items/open-item-extractor.js.map +1 -1
- package/dist/cli/backend/src/services/open-items/open-items.service.d.ts +7 -7
- package/dist/cli/backend/src/services/open-items/open-items.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/open-items/open-items.service.js +12 -21
- package/dist/cli/backend/src/services/open-items/open-items.service.js.map +1 -1
- package/dist/cli/backend/src/types/decision.types.d.ts +51 -1
- package/dist/cli/backend/src/types/decision.types.d.ts.map +1 -1
- package/dist/cli/backend/src/types/index.d.ts +20 -0
- package/dist/cli/backend/src/types/index.d.ts.map +1 -1
- package/dist/cli/backend/src/types/index.js.map +1 -1
- package/dist/cli/backend/src/utils/member-default-model.utils.d.ts +24 -8
- package/dist/cli/backend/src/utils/member-default-model.utils.d.ts.map +1 -1
- package/dist/cli/backend/src/utils/member-default-model.utils.js +33 -7
- package/dist/cli/backend/src/utils/member-default-model.utils.js.map +1 -1
- package/dist/cli/backend/src/utils/model-tier.utils.d.ts +68 -0
- package/dist/cli/backend/src/utils/model-tier.utils.d.ts.map +1 -0
- package/dist/cli/backend/src/utils/model-tier.utils.js +111 -0
- package/dist/cli/backend/src/utils/model-tier.utils.js.map +1 -0
- package/frontend/dist/assets/{index-7e5ebf78.js → index-368419df.js} +266 -266
- package/frontend/dist/index.html +1 -1
- package/package.json +1 -1
|
@@ -87,6 +87,13 @@ bash {{TL_SKILLS_PATH}}/assign-ticket/execute.sh --project {{PROJECT_PATH}} --id
|
|
|
87
87
|
```
|
|
88
88
|
Use when: A specific worker should take a specific ticket of the project backlog. The worker gets a linked WorkItem and is dispatched; when you verify that WorkItem the ticket moves to done.
|
|
89
89
|
|
|
90
|
+
#### 11. propose-tier-change — Propose model tiers and routing (only when "Optimize usage" is on)
|
|
91
|
+
```bash
|
|
92
|
+
bash {{TL_SKILLS_PATH}}/propose-tier-change/execute.sh --member "<name>" --tier weak --reason "<why>"
|
|
93
|
+
bash {{TL_SKILLS_PATH}}/propose-tier-change/execute.sh --submit
|
|
94
|
+
```
|
|
95
|
+
Use when: your weekly usage review arrives (`[MODEL TIER REVIEW]`), or you see a member's work does not need its tier. One owner card per review; nothing changes until the owner applies it.
|
|
96
|
+
|
|
90
97
|
#### Project backlog (project tickets)
|
|
91
98
|
Each project keeps its own backlog in `<project>/.crewly/tickets/` (one markdown file per ticket, tracked in git). Use the `project-tickets` skill to list, read, create and update tickets. Workers pick up `ready` tickets by themselves when idle; you decide what is `ready`, you may assign (`assign-ticket`), and you review the work through the normal verification item. Worker-created tickets land in `backlog` until you or the owner make them ready.
|
|
92
99
|
|
|
@@ -67,9 +67,14 @@ options. Use plain Yes/No only for a single question with one possible action.
|
|
|
67
67
|
|
|
68
68
|
What happens:
|
|
69
69
|
|
|
70
|
-
- The card is posted by your own Slack bot:
|
|
71
|
-
-
|
|
72
|
-
-
|
|
70
|
+
- The card is posted by your own Slack bot, in the conversation it belongs to:
|
|
71
|
+
- the owner thread you are talking in right now (the owner is waiting there);
|
|
72
|
+
- else the ticket's thread (ticket asks), else your current work's thread;
|
|
73
|
+
- top-level in your team channel only when there is no thread at all.
|
|
74
|
+
- Asking a question you already have an open card for, in the same thread / ticket, posts nothing
|
|
75
|
+
new: you get the open card back with `"reused": true`. Wait for its answer.
|
|
76
|
+
- When the owner answers one card, Crewly closes your other open cards in that thread that ask the
|
|
77
|
+
same thing (the card reads `✓ Closed — answered in D-7`); you are told which ones.
|
|
73
78
|
- The owner can answer by tapping a button, reacting (✅ default, ❌ "no", ⏰ tomorrow, 🚫 skip),
|
|
74
79
|
replying in the thread, or using the dashboard.
|
|
75
80
|
- You receive `[DECISION D-7] The owner chose "…"`. Act on it. Do not ask again.
|
|
@@ -85,13 +90,22 @@ What happens:
|
|
|
85
90
|
transcript or the file link. Listen to it (transcribe-audio) and act on it.
|
|
86
91
|
- Do not also message the owner about it. The card is the question.
|
|
87
92
|
|
|
88
|
-
Withdraw a
|
|
93
|
+
Withdraw a card you no longer need — and **right away when a card should not exist**: you posted it
|
|
94
|
+
by mistake, it was already answered in the thread, or Crewly made a card from a sentence in your
|
|
95
|
+
reply that was not a question for the owner (a line of a script, interview questions for a client,
|
|
96
|
+
a draft you quoted):
|
|
89
97
|
|
|
90
98
|
```bash
|
|
91
|
-
bash execute.sh --
|
|
99
|
+
bash execute.sh --withdraw D-7 --reason "not a question for you — interview question for the client"
|
|
100
|
+
bash execute.sh --mine # your open cards: id, question, thread
|
|
92
101
|
```
|
|
93
102
|
|
|
94
|
-
The card
|
|
103
|
+
(`--cancel` is the same.) The Slack card closes and loses its buttons: `✓ Closed — <reason>`. Do not
|
|
104
|
+
leave a wrong card open for the owner to ask about.
|
|
105
|
+
|
|
106
|
+
Crewly turns only the **last** question of your reply into a card, and only when it is a decision for
|
|
107
|
+
the owner. A question in the middle of a reply, a numbered list of questions, or questions written
|
|
108
|
+
for someone else get no card. Several decisions at once? Ask each with its own `ask-owner`.
|
|
95
109
|
|
|
96
110
|
A rejected ask (vague, missing options, etc.) comes back with an error that says what to fix.
|
|
97
111
|
|
|
@@ -13,15 +13,17 @@ Usage:
|
|
|
13
13
|
--option "Send Monday — after the review call" --option "Hold — wait for legal" \
|
|
14
14
|
--default "Hold" [--deadline 2026-10-02T12:00] [--ticket APP-12 --project P] \
|
|
15
15
|
[--sensitive email|publish|deploy|spend]
|
|
16
|
-
bash execute.sh --
|
|
17
|
-
Withdraw a
|
|
16
|
+
bash execute.sh --withdraw D-7 [--reason "posted by mistake"]
|
|
17
|
+
Withdraw a card you no longer need, or one posted by mistake
|
|
18
|
+
(--cancel is the same). The Slack card closes and loses its buttons.
|
|
19
|
+
bash execute.sh --mine List your open cards (id, question, where)
|
|
18
20
|
bash execute.sh --status D-7 Read a card: answered or not, and what the owner chose.
|
|
19
21
|
Check this before acting on anything you asked about.
|
|
20
22
|
bash execute.sh '{"question":"…","options":["A","B"],"default":"A"}'
|
|
21
23
|
EOF_USAGE
|
|
22
24
|
}
|
|
23
25
|
|
|
24
|
-
QUESTION=""; OPTIONS_JSON="[]"; DEFAULT_OPT=""; DEADLINE=""; SENSITIVE=""; TICKET=""; PROJECT=""; CANCEL=""; REASON=""; STATUS_ID=""
|
|
26
|
+
QUESTION=""; OPTIONS_JSON="[]"; DEFAULT_OPT=""; DEADLINE=""; SENSITIVE=""; TICKET=""; PROJECT=""; CANCEL=""; REASON=""; STATUS_ID=""; MINE=""
|
|
25
27
|
|
|
26
28
|
if [[ $# -gt 0 && ${1:0:1} == '{' ]]; then
|
|
27
29
|
J="$1"; shift
|
|
@@ -32,7 +34,7 @@ if [[ $# -gt 0 && ${1:0:1} == '{' ]]; then
|
|
|
32
34
|
SENSITIVE=$(printf '%s' "$J" | jq -r '.sensitive // empty')
|
|
33
35
|
TICKET=$(printf '%s' "$J" | jq -r '.ticket // empty')
|
|
34
36
|
PROJECT=$(printf '%s' "$J" | jq -r '.project // empty')
|
|
35
|
-
CANCEL=$(printf '%s' "$J" | jq -r '.cancel // empty')
|
|
37
|
+
CANCEL=$(printf '%s' "$J" | jq -r '.cancel // .withdraw // empty')
|
|
36
38
|
REASON=$(printf '%s' "$J" | jq -r '.reason // empty')
|
|
37
39
|
fi
|
|
38
40
|
|
|
@@ -46,7 +48,8 @@ while [[ $# -gt 0 ]]; do
|
|
|
46
48
|
--sensitive) [ $# -ge 2 ] || error_exit "--sensitive requires a value"; SENSITIVE="$2"; shift 2 ;;
|
|
47
49
|
--ticket|--id) [ $# -ge 2 ] || error_exit "--ticket requires a value"; TICKET="$2"; shift 2 ;;
|
|
48
50
|
--project|-p) [ $# -ge 2 ] || error_exit "--project requires a value"; PROJECT="$2"; shift 2 ;;
|
|
49
|
-
--cancel)
|
|
51
|
+
--cancel|--withdraw) [ $# -ge 2 ] || error_exit "$1 requires a decision id"; CANCEL="$2"; shift 2 ;;
|
|
52
|
+
--mine) MINE=1; shift ;;
|
|
50
53
|
--reason) [ $# -ge 2 ] || error_exit "--reason requires a value"; REASON="$2"; shift 2 ;;
|
|
51
54
|
--status) [ $# -ge 2 ] || error_exit "--status requires a decision id"; STATUS_ID="$2"; shift 2 ;;
|
|
52
55
|
--help|-h) print_usage; exit 0 ;;
|
|
@@ -69,6 +72,15 @@ if [ -n "$STATUS_ID" ]; then
|
|
|
69
72
|
exit 0
|
|
70
73
|
fi
|
|
71
74
|
|
|
75
|
+
if [ -n "$MINE" ]; then
|
|
76
|
+
[ -n "${CREWLY_SESSION_NAME:-}" ] || error_exit "--mine needs CREWLY_SESSION_NAME (your session name)"
|
|
77
|
+
api_call GET "/decisions?status=open" | jq --arg me "$CREWLY_SESSION_NAME" '{success, decisions: [(.data // [])[] | select(.asker == $me) | {
|
|
78
|
+
id, status, question, kind: (.kind // "ask-owner"), createdAt,
|
|
79
|
+
thread: (if .card then "\(.card.slackChannelId):\(.card.threadTs // .card.messageTs)" else null end)
|
|
80
|
+
}]}'
|
|
81
|
+
exit 0
|
|
82
|
+
fi
|
|
83
|
+
|
|
72
84
|
if [ -n "$CANCEL" ]; then
|
|
73
85
|
CANCEL_BODY=$(jq -n --arg r "$REASON" 'if $r != "" then {note: $r} else {} end')
|
|
74
86
|
api_call POST "/decisions/$(printf '%s' "$CANCEL" | jq -sRr @uri)/cancel" "$CANCEL_BODY" | jq '{success, decision: (.data | {id, status})}'
|
|
@@ -85,4 +97,4 @@ BODY=$(jq -n --arg q "$QUESTION" --argjson o "$OPTIONS_JSON" --arg d "$DEFAULT_O
|
|
|
85
97
|
+ (if $t != "" then {ticket: $t} else {} end)
|
|
86
98
|
+ (if $p != "" then {project: $p} else {} end)')
|
|
87
99
|
api_call POST "/decisions" "$BODY" \
|
|
88
|
-
| jq '{success, decision: (.data | {id, asker, status, deadline, posted: (.card != null), postError})}'
|
|
100
|
+
| jq '{success, decision: (.data | {id, asker, status, deadline, posted: (.card != null), postError, reused: (.reused // false)})}'
|
|
@@ -26,6 +26,11 @@ class H(BaseHTTPRequestHandler):
|
|
|
26
26
|
return self.reply(200, {'success': True, 'data': {'id': 'D-11', 'status': 'open', 'options': [{'key': 'a', 'label': 'Reply with this draft'}, {'key': 'b', 'label': 'Change the wording'}]}})
|
|
27
27
|
if self.path.startswith('/api/decisions/D-12'):
|
|
28
28
|
return self.reply(200, {'success': True, 'data': {'id': 'D-12', 'status': 'resolved', 'chosenKey': 'a', 'answeredVia': 'button', 'resolvedAt': 't', 'options': [{'key': 'a', 'label': 'Reply with this draft'}, {'key': 'b', 'label': 'Change the wording'}]}})
|
|
29
|
+
if self.path.startswith('/api/decisions?status=open'):
|
|
30
|
+
return self.reply(200, {'success': True, 'data': [
|
|
31
|
+
{'id': 'D-20', 'asker': 'dev-ann', 'status': 'open', 'question': 'Ship it?', 'kind': 'reply_question', 'createdAt': 't', 'card': {'slackChannelId': 'C1', 'messageTs': '2.2', 'threadTs': '1.1'}},
|
|
32
|
+
{'id': 'D-21', 'asker': 'dev-bob', 'status': 'open', 'question': 'Other?', 'createdAt': 't'},
|
|
33
|
+
{'id': 'D-22', 'asker': 'dev-ann', 'status': 'open', 'question': 'Top-level?', 'createdAt': 't', 'card': {'slackChannelId': 'C1', 'messageTs': '3.3'}}]})
|
|
29
34
|
return self.reply(200, {'success': True})
|
|
30
35
|
def do_POST(self):
|
|
31
36
|
n = int(self.headers.get('content-length', '0')); body = json.loads(self.rfile.read(n).decode() or '{}')
|
|
@@ -51,7 +56,7 @@ OUT=$(run --question "Send the partner email on Monday?" --option "Send Monday
|
|
|
51
56
|
check "ask: path" "$(last .path)" "/api/decisions"
|
|
52
57
|
check "ask: agent header" "$(last .agent)" "dev-ann"
|
|
53
58
|
check "ask: body" "$(last '.body | tostring')" '{"question":"Send the partner email on Monday?","options":["Send Monday — after review","Hold"],"default":"Hold","sensitive":"email","ticket":"APP-12","project":"p1"}'
|
|
54
|
-
check "ask: output" "$(printf '%s' "$OUT" | jq -c '.decision')" '{"id":"D-7","asker":"dev-ann","status":"open","deadline":"x","posted":true,"postError":null}'
|
|
59
|
+
check "ask: output" "$(printf '%s' "$OUT" | jq -c '.decision')" '{"id":"D-7","asker":"dev-ann","status":"open","deadline":"x","posted":true,"postError":null,"reused":false}'
|
|
55
60
|
|
|
56
61
|
run '{"question":"Blue or green for the logo?","options":["Blue","Green"],"default":"wait"}' >/dev/null
|
|
57
62
|
check "ask json: body" "$(last '.body | tostring')" '{"question":"Blue or green for the logo?","options":["Blue","Green"],"default":"wait"}'
|
|
@@ -66,6 +71,19 @@ check "cancel: no reason → empty body" "$(last .body | jq -c .)" '{}'
|
|
|
66
71
|
run --cancel D-7 --reason "already answered in the thread" >/dev/null
|
|
67
72
|
check "cancel: reason sent as note" "$(last .body.note)" "already answered in the thread"
|
|
68
73
|
|
|
74
|
+
# --withdraw: the same as --cancel (a card posted by mistake)
|
|
75
|
+
OUT=$(run --withdraw D-7 --reason "posted by mistake")
|
|
76
|
+
check "withdraw: path" "$(last .path)" "/api/decisions/D-7/cancel"
|
|
77
|
+
check "withdraw: reason sent as note" "$(last .body.note)" "posted by mistake"
|
|
78
|
+
check "withdraw: output" "$(printf '%s' "$OUT" | jq -c '.decision')" '{"id":"D-7","status":"cancelled"}'
|
|
79
|
+
run '{"withdraw":"D-7"}' >/dev/null
|
|
80
|
+
check "withdraw json: path" "$(last .path)" "/api/decisions/D-7/cancel"
|
|
81
|
+
|
|
82
|
+
# --mine: only the caller's open cards, with their thread
|
|
83
|
+
OUT=$(run --mine)
|
|
84
|
+
check "mine: path" "$(last .path)" "/api/decisions?status=open"
|
|
85
|
+
check "mine: own cards only" "$(printf '%s' "$OUT" | jq -c '[.decisions[] | {id, kind, thread}]')" '[{"id":"D-20","kind":"reply_question","thread":"C1:1.1"},{"id":"D-22","kind":"ask-owner","thread":"C1:3.3"}]'
|
|
86
|
+
|
|
69
87
|
# --status: an agent reads a card before acting (2026-10-03 phantom owner input)
|
|
70
88
|
OUT=$(run --status D-11)
|
|
71
89
|
check "status: path" "$(last .path)" "/api/decisions/D-11"
|
|
@@ -115,3 +115,14 @@ tells the system that you are the one replying.
|
|
|
115
115
|
command to run — nothing is dropped silently, and nothing is filed as
|
|
116
116
|
status for the orchestrator.
|
|
117
117
|
- `reply-channel`, `reply-chat` and `slack-post` keep working.
|
|
118
|
+
|
|
119
|
+
## Questions in your reply
|
|
120
|
+
|
|
121
|
+
- Crewly turns the **last** question of your reply into a tap-to-answer card when it is a decision
|
|
122
|
+
for the owner ("这样写可以吗?", "Ship it today?"). Put the one question you need answered last.
|
|
123
|
+
- Questions in the middle, numbered lists of questions, quoted drafts and questions written for
|
|
124
|
+
someone else (interview / survey questions, a script) get no card. Need several decisions? Ask
|
|
125
|
+
each with `ask-owner`.
|
|
126
|
+
- A card that should not exist (it picked up a line that was not a question for the owner): withdraw
|
|
127
|
+
it at once — `ask-owner --withdraw D-12 --reason "not a question for you"` (`ask-owner --mine`
|
|
128
|
+
lists your open cards). The card closes and loses its buttons.
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Propose Tier Change (TL)
|
|
3
|
+
description: "Propose moving a member to another model tier (strong / mid / weak) or a task routing rule, then send all proposals to the owner as one card. Only while the team's 'Optimize usage' is on. Nothing changes until the owner says yes."
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
category: management
|
|
6
|
+
skillType: claude-skill
|
|
7
|
+
assignableRoles:
|
|
8
|
+
- team-leader
|
|
9
|
+
triggers:
|
|
10
|
+
- propose tier change
|
|
11
|
+
- model tier review
|
|
12
|
+
- optimize usage
|
|
13
|
+
tags:
|
|
14
|
+
- agent
|
|
15
|
+
- management
|
|
16
|
+
- model
|
|
17
|
+
- cost
|
|
18
|
+
execution:
|
|
19
|
+
type: script
|
|
20
|
+
script:
|
|
21
|
+
file: execute.sh
|
|
22
|
+
interpreter: bash
|
|
23
|
+
timeoutMs: 30000
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
# Propose Tier Change (TL Version)
|
|
27
|
+
|
|
28
|
+
Members run on model tiers: **strong** (hard reasoning, design, reviewing others), **mid** (normal implementation and writing), **weak** (routine work: polling, checks, formatting, sorting, first-pass triage, summaries). Each tier maps to a model per runtime (Claude Code: opus / sonnet / haiku).
|
|
29
|
+
|
|
30
|
+
While the team's **Optimize usage** setting is on, you get a usage review every week (turns, context, output, estimated cost and work handled per member). Propose what should change, then submit. The owner gets **one card** with all proposals and taps Apply or Keep as is. You are told the answer.
|
|
31
|
+
|
|
32
|
+
## Usage
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
# 1. One call per member that should move
|
|
36
|
+
bash {{TL_SKILLS_PATH}}/propose-tier-change/execute.sh --member "Ella" --tier weak --reason "only polls the inbox and sorts tickets; nothing was sent back"
|
|
37
|
+
|
|
38
|
+
# 2. Routing rules for incoming work (optional)
|
|
39
|
+
bash {{TL_SKILLS_PATH}}/propose-tier-change/execute.sh --routing "polling / formatting / sorting -> Ella"
|
|
40
|
+
|
|
41
|
+
# 3. Send everything to the owner (one card). With nothing proposed, this just closes the review.
|
|
42
|
+
bash {{TL_SKILLS_PATH}}/propose-tier-change/execute.sh --submit
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
`--clear` drops the draft. Proposing the same member again replaces its earlier proposal.
|
|
46
|
+
|
|
47
|
+
## Rules
|
|
48
|
+
|
|
49
|
+
- Never change a tier or model any other way; only the owner's Apply does it.
|
|
50
|
+
- Do not lower a member whose work was often sent back. You stay at mid or above.
|
|
51
|
+
- A member with a fixed model loses it when the owner applies its tier (the card says so).
|
|
52
|
+
- A draft you do not submit is sent to the owner automatically after two hours.
|
|
53
|
+
- After a member moves down, Crewly watches its next work items; if they are sent back clearly more often, the owner is asked whether to move it back.
|
|
54
|
+
|
|
55
|
+
## Output
|
|
56
|
+
|
|
57
|
+
`{"success":true,"data":{"added":"change","change":"Ella: mid -> weak","draft":{...}}}` / `{"success":true,"data":{"submitted":true,"decisionId":"D-12",...}}`
|
|
58
|
+
|
|
59
|
+
## Related Skills
|
|
60
|
+
|
|
61
|
+
- `start-agent` / `stop-agent` — restart an idle member so an approved tier applies now
|
|
62
|
+
- `delegate-task` — route work by tier
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# propose-tier-change — a team lead proposes model-tier changes and task
|
|
3
|
+
# routing rules for its team (crewly#1173). Proposals collect in a draft;
|
|
4
|
+
# --submit sends ONE owner card with all of them. Nothing changes until the
|
|
5
|
+
# owner taps Apply. See specs/2026-10-08-model-tiers.md.
|
|
6
|
+
set -euo pipefail
|
|
7
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
8
|
+
source "${SCRIPT_DIR}/../_common/lib.sh"
|
|
9
|
+
|
|
10
|
+
print_usage() {
|
|
11
|
+
cat <<'EOF_USAGE'
|
|
12
|
+
Usage:
|
|
13
|
+
bash execute.sh --member "Ella" --tier weak --reason "only polls the inbox and sorts tickets"
|
|
14
|
+
bash execute.sh --routing "polling / formatting / sorting -> Ella"
|
|
15
|
+
bash execute.sh --submit Send the draft to the owner (one card). With nothing proposed, closes the review.
|
|
16
|
+
bash execute.sh --clear Drop the draft without sending it.
|
|
17
|
+
bash execute.sh '{"member":"Ella","tier":"weak","reason":"..."}'
|
|
18
|
+
Tiers: strong (hard reasoning, design, review), mid (normal work), weak (routine: polling, checks, formatting, sorting, triage).
|
|
19
|
+
EOF_USAGE
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
MEMBER=""; TIER=""; REASON=""; ROUTING=""; SUBMIT=""; CLEAR=""
|
|
23
|
+
|
|
24
|
+
if [[ $# -gt 0 && ${1:0:1} == '{' ]]; then
|
|
25
|
+
J="$1"; shift
|
|
26
|
+
MEMBER=$(printf '%s' "$J" | jq -r '.member // empty')
|
|
27
|
+
TIER=$(printf '%s' "$J" | jq -r '.tier // empty')
|
|
28
|
+
REASON=$(printf '%s' "$J" | jq -r '.reason // empty')
|
|
29
|
+
ROUTING=$(printf '%s' "$J" | jq -r '.routing // empty')
|
|
30
|
+
[ "$(printf '%s' "$J" | jq -r '.submit // false')" = "true" ] && SUBMIT=1
|
|
31
|
+
[ "$(printf '%s' "$J" | jq -r '.clear // false')" = "true" ] && CLEAR=1
|
|
32
|
+
fi
|
|
33
|
+
|
|
34
|
+
while [[ $# -gt 0 ]]; do
|
|
35
|
+
case "$1" in
|
|
36
|
+
--member|-m) [ $# -ge 2 ] || error_exit "--member requires a value"; MEMBER="$2"; shift 2 ;;
|
|
37
|
+
--tier|-t) [ $# -ge 2 ] || error_exit "--tier requires a value"; TIER=$(printf '%s' "$2" | tr '[:upper:]' '[:lower:]'); shift 2 ;;
|
|
38
|
+
--reason|-r) [ $# -ge 2 ] || error_exit "--reason requires a value"; REASON="$2"; shift 2 ;;
|
|
39
|
+
--routing) [ $# -ge 2 ] || error_exit "--routing requires a value"; ROUTING="$2"; shift 2 ;;
|
|
40
|
+
--submit) SUBMIT=1; shift ;;
|
|
41
|
+
--clear) CLEAR=1; shift ;;
|
|
42
|
+
--help|-h) print_usage; exit 0 ;;
|
|
43
|
+
*) error_exit "Unknown option: $1 (see --help)" ;;
|
|
44
|
+
esac
|
|
45
|
+
done
|
|
46
|
+
|
|
47
|
+
if [ -n "$CLEAR" ]; then
|
|
48
|
+
BODY='{"clear":true}'
|
|
49
|
+
elif [ -n "$SUBMIT" ]; then
|
|
50
|
+
BODY='{"submit":true}'
|
|
51
|
+
elif [ -n "$ROUTING" ]; then
|
|
52
|
+
BODY=$(jq -n --arg r "$ROUTING" '{routing: $r}')
|
|
53
|
+
else
|
|
54
|
+
require_param "member" "$MEMBER"
|
|
55
|
+
require_param "tier" "$TIER"
|
|
56
|
+
require_param "reason" "$REASON"
|
|
57
|
+
case "$TIER" in
|
|
58
|
+
strong|mid|weak) ;;
|
|
59
|
+
*) error_exit "Invalid tier '${TIER}': use strong, mid or weak" ;;
|
|
60
|
+
esac
|
|
61
|
+
BODY=$(jq -n --arg m "$MEMBER" --arg t "$TIER" --arg r "$REASON" '{member: $m, tier: $t, reason: $r}')
|
|
62
|
+
fi
|
|
63
|
+
|
|
64
|
+
api_call POST "/teams/model-tiers/proposals" "$BODY"
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Tests for TL propose-tier-change execute.sh
|
|
3
|
+
# A fake `curl` on PATH records the request body, so the real script (and the
|
|
4
|
+
# real lib.sh) run unmodified.
|
|
5
|
+
set -euo pipefail
|
|
6
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
7
|
+
EXECUTE="$SCRIPT_DIR/execute.sh"
|
|
8
|
+
PASS=0
|
|
9
|
+
FAIL=0
|
|
10
|
+
|
|
11
|
+
TMP=$(mktemp -d)
|
|
12
|
+
trap 'rm -rf "$TMP"' EXIT
|
|
13
|
+
mkdir -p "$TMP/bin"
|
|
14
|
+
cat > "$TMP/bin/curl" << 'CURL_EOF'
|
|
15
|
+
#!/bin/bash
|
|
16
|
+
method="GET"; body=""; url=""; session=""
|
|
17
|
+
while [ $# -gt 0 ]; do
|
|
18
|
+
case "$1" in
|
|
19
|
+
-X) method="$2"; shift 2 ;;
|
|
20
|
+
-d) body="$2"; shift 2 ;;
|
|
21
|
+
-H) case "$2" in "X-Agent-Session: "*) session="${2#X-Agent-Session: }" ;; esac; shift 2 ;;
|
|
22
|
+
-w) shift 2 ;;
|
|
23
|
+
-s) shift ;;
|
|
24
|
+
*) url="$1"; shift ;;
|
|
25
|
+
esac
|
|
26
|
+
done
|
|
27
|
+
case "$method $url" in
|
|
28
|
+
"POST "*/api/teams/model-tiers/proposals)
|
|
29
|
+
printf '%s' "$body" > "$FAKE_CURL_LOG"
|
|
30
|
+
printf '%s' "$session" > "$FAKE_CURL_LOG.session"
|
|
31
|
+
printf '%s\n200' '{"success":true,"data":{"ok":true}}'
|
|
32
|
+
;;
|
|
33
|
+
*)
|
|
34
|
+
printf '%s\n404' '{"error":"unknown"}'
|
|
35
|
+
;;
|
|
36
|
+
esac
|
|
37
|
+
CURL_EOF
|
|
38
|
+
chmod +x "$TMP/bin/curl"
|
|
39
|
+
|
|
40
|
+
run() {
|
|
41
|
+
: > "$TMP/body.json"
|
|
42
|
+
env PATH="$TMP/bin:$PATH" CREWLY_HOME="$TMP/home" CREWLY_SESSION_NAME="tl-session" \
|
|
43
|
+
FAKE_CURL_LOG="$TMP/body.json" bash "$EXECUTE" "$@"
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
check() {
|
|
47
|
+
local desc="$1" ok="$2"
|
|
48
|
+
if [ "$ok" = "yes" ]; then echo " PASS: $desc"; PASS=$((PASS + 1)); else echo " FAIL: $desc"; FAIL=$((FAIL + 1)); fi
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
echo "=== TL propose-tier-change tests ==="
|
|
52
|
+
|
|
53
|
+
OUT=$(run --member "Ella" --tier Weak --reason "polls only" 2>&1) && RC=0 || RC=$?
|
|
54
|
+
check "member change: succeeds" "$([ "$RC" = 0 ] && echo yes || echo no)"
|
|
55
|
+
check "member change: posts member/tier/reason" "$([ "$(jq -c . "$TMP/body.json")" = '{"member":"Ella","tier":"weak","reason":"polls only"}' ] && echo yes || echo no)"
|
|
56
|
+
check "member change: sent as the lead" "$([ "$(cat "$TMP/body.json.session")" = "tl-session" ] && echo yes || echo no)"
|
|
57
|
+
|
|
58
|
+
OUT=$(run --routing "polling -> Ella" 2>&1) && RC=0 || RC=$?
|
|
59
|
+
check "routing: posts the rule" "$([ "$RC" = 0 ] && [ "$(jq -r .routing "$TMP/body.json")" = "polling -> Ella" ] && echo yes || echo no)"
|
|
60
|
+
|
|
61
|
+
OUT=$(run --submit 2>&1) && RC=0 || RC=$?
|
|
62
|
+
check "submit: posts submit:true" "$([ "$RC" = 0 ] && [ "$(jq -r .submit "$TMP/body.json")" = "true" ] && echo yes || echo no)"
|
|
63
|
+
|
|
64
|
+
OUT=$(run '{"clear":true}' 2>&1) && RC=0 || RC=$?
|
|
65
|
+
check "json clear: posts clear:true" "$([ "$RC" = 0 ] && [ "$(jq -r .clear "$TMP/body.json")" = "true" ] && echo yes || echo no)"
|
|
66
|
+
|
|
67
|
+
OUT=$(run --member "Ella" --tier super --reason "x" 2>&1) && RC=0 || RC=$?
|
|
68
|
+
check "invalid tier: fails without a request" "$([ "$RC" != 0 ] && [ ! -s "$TMP/body.json" ] && echo "$OUT" | grep -q "Invalid tier" && echo yes || echo no)"
|
|
69
|
+
|
|
70
|
+
OUT=$(run --member "Ella" --tier weak 2>&1) && RC=0 || RC=$?
|
|
71
|
+
check "missing reason: fails" "$([ "$RC" != 0 ] && echo "$OUT" | grep -q "Missing required parameter: reason" && echo yes || echo no)"
|
|
72
|
+
|
|
73
|
+
echo ""
|
|
74
|
+
echo "Results: $PASS passed, $FAIL failed"
|
|
75
|
+
[ "$FAIL" -eq 0 ]
|
|
@@ -3296,6 +3296,52 @@ export declare const MEMBER_MODEL_DEFAULT_CONSTANTS: {
|
|
|
3296
3296
|
/** Rejections of the same task after which the reviewer is told about the upgrade option */
|
|
3297
3297
|
readonly UPGRADE_HINT_AFTER_REJECTIONS: 2;
|
|
3298
3298
|
};
|
|
3299
|
+
/**
|
|
3300
|
+
* Model tiers (crewly#1173, specs/2026-10-08-model-tiers.md): strong / mid /
|
|
3301
|
+
* weak, mapped to a concrete model per runtime. A team may override the map
|
|
3302
|
+
* (`Team.tierModels`); an explicit `TeamMember.modelId` always wins.
|
|
3303
|
+
*
|
|
3304
|
+
* A runtime with no model for `weak` uses its `mid` model (still cheaper than
|
|
3305
|
+
* the strong default). Any other unmapped tier gets no model flag: the
|
|
3306
|
+
* runtime's own default. `opencode-cli` and `crewly-agent` are unmapped (their
|
|
3307
|
+
* model ids are provider/model pairs the owner picks).
|
|
3308
|
+
*/
|
|
3309
|
+
export declare const MODEL_TIER_CONSTANTS: {
|
|
3310
|
+
/** Tiers, strongest first */
|
|
3311
|
+
readonly TIERS: readonly ["strong", "mid", "weak"];
|
|
3312
|
+
/** Global tier → model map per runtime (names each harness accepts at launch) */
|
|
3313
|
+
readonly DEFAULT_TIER_MODELS: Record<string, Partial<Record<"strong" | "mid" | "weak", string>>>;
|
|
3314
|
+
/** Store of review drafts / applied changes, under CREWLY_HOME */
|
|
3315
|
+
readonly STORE_FILE: "model-tier-reviews.json";
|
|
3316
|
+
/** Decision kind of the owner card */
|
|
3317
|
+
readonly DECISION_KIND: "model_tier_change";
|
|
3318
|
+
/** Days between automatic reviews while "Optimize usage" is on */
|
|
3319
|
+
readonly REVIEW_INTERVAL_DAYS: 7;
|
|
3320
|
+
/** Usage window the report covers (days) */
|
|
3321
|
+
readonly REPORT_WINDOW_DAYS: 7;
|
|
3322
|
+
/** How often the service checks for due reviews / guards */
|
|
3323
|
+
readonly TICK_MS: number;
|
|
3324
|
+
/** A draft nobody submitted is sent to the owner after this long */
|
|
3325
|
+
readonly DRAFT_AUTO_SUBMIT_MS: number;
|
|
3326
|
+
/** How long a tier card waits for the owner (default = keep as is) */
|
|
3327
|
+
readonly DECISION_DEADLINE_MS: number;
|
|
3328
|
+
/** Work titles listed per member in the report */
|
|
3329
|
+
readonly REPORT_MAX_TITLES: 5;
|
|
3330
|
+
/** Max characters of a reason / routing rule */
|
|
3331
|
+
readonly MAX_REASON_CHARS: 300;
|
|
3332
|
+
/** Max routing rules per proposal */
|
|
3333
|
+
readonly MAX_ROUTING_RULES: 10;
|
|
3334
|
+
/** Quality guard: settled work items needed after a lowered tier before judging */
|
|
3335
|
+
readonly GUARD_MIN_ITEMS: 5;
|
|
3336
|
+
/** Quality guard: settled items before the change used as the baseline */
|
|
3337
|
+
readonly GUARD_BASELINE_ITEMS: 10;
|
|
3338
|
+
/** Quality guard: send-back rate rise (0..1) over the baseline that counts as worse */
|
|
3339
|
+
readonly GUARD_WORSE_MARGIN: 0.2;
|
|
3340
|
+
/** Quality guard: at least this many sent-back items after the change */
|
|
3341
|
+
readonly GUARD_MIN_BAD: 2;
|
|
3342
|
+
/** Quality guard: stop watching a change after this many days */
|
|
3343
|
+
readonly GUARD_MAX_DAYS: 30;
|
|
3344
|
+
};
|
|
3299
3345
|
export declare const CHAT_CONTEXT_CONSTANTS: {
|
|
3300
3346
|
/** Whether preceding messages are included at all */
|
|
3301
3347
|
readonly ENABLED: true;
|
|
@@ -6560,7 +6606,23 @@ export declare const DECISION_CONSTANTS: {
|
|
|
6560
6606
|
readonly TICKET_DONE: "ticket done";
|
|
6561
6607
|
readonly TICKET_CANCELLED: "ticket cancelled";
|
|
6562
6608
|
readonly HANDLED_IN_THREAD: "already handled in this thread";
|
|
6609
|
+
/** `answered in D-7`: the same question, answered on another card */
|
|
6610
|
+
readonly ANSWERED_IN_PREFIX: "answered in ";
|
|
6611
|
+
/** `answered by your reply to D-7`: the owner's words on another card moved the thread on */
|
|
6612
|
+
readonly ANSWERED_BY_REPLY_PREFIX: "answered by your reply to ";
|
|
6613
|
+
/** The open item the card tracked expired (nothing happened for 7 days) */
|
|
6614
|
+
readonly STALE: "no longer needed";
|
|
6563
6615
|
};
|
|
6616
|
+
/**
|
|
6617
|
+
* Two questions with at least this character-bigram overlap, from the same
|
|
6618
|
+
* asker in the same thread / ticket / request, are one question: a new ask
|
|
6619
|
+
* reuses the open card, and an answer closes the other open ones.
|
|
6620
|
+
*/
|
|
6621
|
+
readonly SAME_OPEN_QUESTION_SIMILARITY: 0.6;
|
|
6622
|
+
/** A settled card Slack refused to update (buttons still live) is retried this often (ms) */
|
|
6623
|
+
readonly CARD_SYNC_RETRY_MS: number;
|
|
6624
|
+
/** Open cards are checked this often for what they track having closed (then withdrawn silently) (ms) */
|
|
6625
|
+
readonly MOOT_CHECK_MS: number;
|
|
6564
6626
|
};
|
|
6565
6627
|
/**
|
|
6566
6628
|
* Open items: commitments and questions agents put in their replies to the
|
|
@@ -6633,12 +6695,6 @@ export declare const OPEN_ITEMS_CONSTANTS: {
|
|
|
6633
6695
|
readonly CONTEXT_BLOCK_MAX_CHARS: 1200;
|
|
6634
6696
|
/** Max characters of the "About:" line (the owner's original ask) */
|
|
6635
6697
|
readonly CONTEXT_ABOUT_MAX_CHARS: 200;
|
|
6636
|
-
/**
|
|
6637
|
-
* A ticket thread with no activity for this long (ms) is not revived by a
|
|
6638
|
-
* question the agent asked somewhere else: the card goes where the agent's
|
|
6639
|
-
* message is, with a link to the old thread.
|
|
6640
|
-
*/
|
|
6641
|
-
readonly STALE_THREAD_MS: number;
|
|
6642
6698
|
/**
|
|
6643
6699
|
* Words that make a question point back at earlier text ("这样安排行不行?", "按这个草稿回?",
|
|
6644
6700
|
* "Does this plan work?"): its card prefers the text right before it and
|