crewly 1.20.318 → 1.20.320
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/hooks/destructive-git-guard/guard.mjs +210 -0
- package/config/hooks/install-hooks.sh +6 -0
- package/config/hooks/pre-commit +29 -0
- package/config/skills/_conventions/skill-lint.allowlist.json +127 -0
- package/config/skills/_conventions/skill-lint.ts +66 -0
- package/config/skills/agent/core/publish-app/SKILL.md +30 -2
- package/config/skills/agent/core/publish-app/execute.sh +21 -3
- package/config/skills/agent/core/publish-app/execute.test.sh +9 -0
- package/config/skills/agent/core/report-status/SKILL.md +2 -0
- package/config/skills/team-leader/decompose-goal/SKILL.md +20 -6
- package/config/skills/team-leader/decompose-goal/execute.sh +66 -5
- package/config/skills/team-leader/decompose-goal/execute.test.sh +92 -0
- package/config/sops/common/dev-process-tiers.md +1 -1
- package/config/sops/common/writing-for-agents.md +45 -0
- package/config/sops/developer/debugging.md +53 -0
- package/config/sops/developer/git-workflow.md +4 -0
- package/config/sops/developer/testing-requirements.md +14 -0
- package/dist/backend/backend/src/constants.d.ts +81 -1
- package/dist/backend/backend/src/constants.d.ts.map +1 -1
- package/dist/backend/backend/src/constants.js +82 -0
- package/dist/backend/backend/src/constants.js.map +1 -1
- package/dist/backend/backend/src/controllers/apps/apps.controller.d.ts +4 -0
- package/dist/backend/backend/src/controllers/apps/apps.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/apps/apps.controller.js +9 -0
- package/dist/backend/backend/src/controllers/apps/apps.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/apps/apps.routes.d.ts +2 -0
- package/dist/backend/backend/src/controllers/apps/apps.routes.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/apps/apps.routes.js +5 -1
- package/dist/backend/backend/src/controllers/apps/apps.routes.js.map +1 -1
- package/dist/backend/backend/src/controllers/slack/slack.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/slack/slack.controller.js +11 -0
- package/dist/backend/backend/src/controllers/slack/slack.controller.js.map +1 -1
- package/dist/backend/backend/src/index.d.ts.map +1 -1
- package/dist/backend/backend/src/index.js +3 -0
- package/dist/backend/backend/src/index.js.map +1 -1
- package/dist/backend/backend/src/services/agent/agent-registration.service.d.ts +9 -0
- package/dist/backend/backend/src/services/agent/agent-registration.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/agent/agent-registration.service.js +41 -1
- package/dist/backend/backend/src/services/agent/agent-registration.service.js.map +1 -1
- package/dist/backend/backend/src/services/agent/control-plane-guard.service.d.ts +4 -1
- package/dist/backend/backend/src/services/agent/control-plane-guard.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/agent/control-plane-guard.service.js +11 -2
- package/dist/backend/backend/src/services/agent/control-plane-guard.service.js.map +1 -1
- package/dist/backend/backend/src/services/agent/destructive-git-guard.service.d.ts +21 -0
- package/dist/backend/backend/src/services/agent/destructive-git-guard.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/agent/destructive-git-guard.service.js +40 -0
- package/dist/backend/backend/src/services/agent/destructive-git-guard.service.js.map +1 -0
- package/dist/backend/backend/src/services/agent/follow-through.wiring.d.ts.map +1 -1
- package/dist/backend/backend/src/services/agent/follow-through.wiring.js +42 -14
- package/dist/backend/backend/src/services/agent/follow-through.wiring.js.map +1 -1
- package/dist/backend/backend/src/services/agent/fresh-task-conversation.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/agent/fresh-task-conversation.service.js +5 -1
- package/dist/backend/backend/src/services/agent/fresh-task-conversation.service.js.map +1 -1
- package/dist/backend/backend/src/services/agent/handover-pointers.d.ts +70 -0
- package/dist/backend/backend/src/services/agent/handover-pointers.d.ts.map +1 -0
- package/dist/backend/backend/src/services/agent/handover-pointers.js +122 -0
- package/dist/backend/backend/src/services/agent/handover-pointers.js.map +1 -0
- package/dist/backend/backend/src/services/agent/runtime-session-recovery.d.ts.map +1 -1
- package/dist/backend/backend/src/services/agent/runtime-session-recovery.js +6 -3
- package/dist/backend/backend/src/services/agent/runtime-session-recovery.js.map +1 -1
- package/dist/backend/backend/src/services/apps/apps.service.d.ts +40 -0
- package/dist/backend/backend/src/services/apps/apps.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/apps/apps.service.js +54 -0
- package/dist/backend/backend/src/services/apps/apps.service.js.map +1 -1
- package/dist/backend/backend/src/services/decisions/decision-routing.d.ts +4 -1
- package/dist/backend/backend/src/services/decisions/decision-routing.d.ts.map +1 -1
- package/dist/backend/backend/src/services/decisions/decision-routing.js +11 -7
- package/dist/backend/backend/src/services/decisions/decision-routing.js.map +1 -1
- package/dist/backend/backend/src/services/decisions/decision.service.d.ts +6 -0
- package/dist/backend/backend/src/services/decisions/decision.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/decisions/decision.service.js +17 -2
- package/dist/backend/backend/src/services/decisions/decision.service.js.map +1 -1
- package/dist/backend/backend/src/services/decisions/decision.wiring.d.ts.map +1 -1
- package/dist/backend/backend/src/services/decisions/decision.wiring.js +20 -1
- package/dist/backend/backend/src/services/decisions/decision.wiring.js.map +1 -1
- package/dist/backend/backend/src/services/decisions/recurring-change-handoff.d.ts +81 -0
- package/dist/backend/backend/src/services/decisions/recurring-change-handoff.d.ts.map +1 -0
- package/dist/backend/backend/src/services/decisions/recurring-change-handoff.js +132 -0
- package/dist/backend/backend/src/services/decisions/recurring-change-handoff.js.map +1 -0
- package/dist/backend/backend/src/services/messaging/owner-thread-sentinel.service.d.ts +14 -0
- package/dist/backend/backend/src/services/messaging/owner-thread-sentinel.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/messaging/owner-thread-sentinel.service.js +67 -13
- package/dist/backend/backend/src/services/messaging/owner-thread-sentinel.service.js.map +1 -1
- package/dist/backend/backend/src/services/open-items/open-item-card.d.ts +25 -1
- package/dist/backend/backend/src/services/open-items/open-item-card.d.ts.map +1 -1
- package/dist/backend/backend/src/services/open-items/open-item-card.js +108 -1
- package/dist/backend/backend/src/services/open-items/open-item-card.js.map +1 -1
- package/dist/backend/backend/src/services/open-items/open-item-extractor.d.ts +2 -0
- 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 +21 -1
- 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 +12 -1
- 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 +54 -4
- package/dist/backend/backend/src/services/open-items/open-items.service.js.map +1 -1
- package/dist/backend/backend/src/services/runtime-fallback/runtime-fallback.wiring.d.ts.map +1 -1
- package/dist/backend/backend/src/services/runtime-fallback/runtime-fallback.wiring.js +3 -2
- package/dist/backend/backend/src/services/runtime-fallback/runtime-fallback.wiring.js.map +1 -1
- package/dist/backend/backend/src/services/session/tui-input-guard.js +1 -1
- package/dist/backend/backend/src/services/session/tui-input-guard.js.map +1 -1
- package/dist/backend/backend/src/services/v3/ticket-intake.service.d.ts +41 -0
- package/dist/backend/backend/src/services/v3/ticket-intake.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/v3/ticket-intake.service.js +117 -0
- package/dist/backend/backend/src/services/v3/ticket-intake.service.js.map +1 -1
- package/dist/backend/build-info.json +2 -2
- package/dist/cli/backend/src/constants.d.ts +81 -1
- package/dist/cli/backend/src/constants.d.ts.map +1 -1
- package/dist/cli/backend/src/constants.js +82 -0
- package/dist/cli/backend/src/constants.js.map +1 -1
- package/dist/cli/backend/src/services/agent/agent-registration.service.d.ts +9 -0
- package/dist/cli/backend/src/services/agent/agent-registration.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/agent/agent-registration.service.js +41 -1
- package/dist/cli/backend/src/services/agent/agent-registration.service.js.map +1 -1
- package/dist/cli/backend/src/services/agent/control-plane-guard.service.d.ts +4 -1
- package/dist/cli/backend/src/services/agent/control-plane-guard.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/agent/control-plane-guard.service.js +11 -2
- package/dist/cli/backend/src/services/agent/control-plane-guard.service.js.map +1 -1
- package/dist/cli/backend/src/services/agent/destructive-git-guard.service.d.ts +21 -0
- package/dist/cli/backend/src/services/agent/destructive-git-guard.service.d.ts.map +1 -0
- package/dist/cli/backend/src/services/agent/destructive-git-guard.service.js +40 -0
- package/dist/cli/backend/src/services/agent/destructive-git-guard.service.js.map +1 -0
- package/dist/cli/backend/src/services/agent/fresh-task-conversation.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/agent/fresh-task-conversation.service.js +5 -1
- package/dist/cli/backend/src/services/agent/fresh-task-conversation.service.js.map +1 -1
- package/dist/cli/backend/src/services/agent/handover-pointers.d.ts +70 -0
- package/dist/cli/backend/src/services/agent/handover-pointers.d.ts.map +1 -0
- package/dist/cli/backend/src/services/agent/handover-pointers.js +122 -0
- package/dist/cli/backend/src/services/agent/handover-pointers.js.map +1 -0
- package/dist/cli/backend/src/services/agent/runtime-session-recovery.d.ts.map +1 -1
- package/dist/cli/backend/src/services/agent/runtime-session-recovery.js +6 -3
- package/dist/cli/backend/src/services/agent/runtime-session-recovery.js.map +1 -1
- package/dist/cli/backend/src/services/decisions/decision.service.d.ts +6 -0
- package/dist/cli/backend/src/services/decisions/decision.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/decisions/decision.service.js +17 -2
- package/dist/cli/backend/src/services/decisions/decision.service.js.map +1 -1
- package/dist/cli/backend/src/services/messaging/owner-thread-sentinel.service.d.ts +14 -0
- package/dist/cli/backend/src/services/messaging/owner-thread-sentinel.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/messaging/owner-thread-sentinel.service.js +67 -13
- package/dist/cli/backend/src/services/messaging/owner-thread-sentinel.service.js.map +1 -1
- package/dist/cli/backend/src/services/open-items/open-item-card.d.ts +25 -1
- package/dist/cli/backend/src/services/open-items/open-item-card.d.ts.map +1 -1
- package/dist/cli/backend/src/services/open-items/open-item-card.js +108 -1
- package/dist/cli/backend/src/services/open-items/open-item-card.js.map +1 -1
- package/dist/cli/backend/src/services/open-items/open-item-extractor.d.ts +2 -0
- 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 +21 -1
- 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 +12 -1
- 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 +54 -4
- package/dist/cli/backend/src/services/open-items/open-items.service.js.map +1 -1
- package/dist/cli/backend/src/services/session/tui-input-guard.js +1 -1
- package/dist/cli/backend/src/services/session/tui-input-guard.js.map +1 -1
- package/dist/cli/backend/src/services/v3/ticket-intake.service.d.ts +41 -0
- package/dist/cli/backend/src/services/v3/ticket-intake.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/v3/ticket-intake.service.js +117 -0
- package/dist/cli/backend/src/services/v3/ticket-intake.service.js.map +1 -1
- package/package.json +1 -1
|
@@ -13,17 +13,19 @@ source "${SCRIPT_DIR}/../_common/lib.sh"
|
|
|
13
13
|
# (the [TICKET:TKT-123 <id>] line of the message being worked on). Also
|
|
14
14
|
# accepted as `"requestId"` in the JSON.
|
|
15
15
|
REQUEST_ID=""
|
|
16
|
+
DRY_RUN=0
|
|
16
17
|
POSITIONAL=()
|
|
17
18
|
while [[ $# -gt 0 ]]; do
|
|
18
19
|
case "$1" in
|
|
19
20
|
--request-id|-R) REQUEST_ID="${2:-}"; shift 2 ;;
|
|
21
|
+
--dry-run) DRY_RUN=1; shift ;;
|
|
20
22
|
*) POSITIONAL+=("$1"); shift ;;
|
|
21
23
|
esac
|
|
22
24
|
done
|
|
23
25
|
set -- "${POSITIONAL[@]+"${POSITIONAL[@]}"}"
|
|
24
26
|
|
|
25
27
|
INPUT=$(read_json_input "${1:-}")
|
|
26
|
-
[ -z "$INPUT" ] && error_exit "Usage: execute.sh '{\"objective\":\"Build auth module\",\"projectPath\":\"/path/to/project\",\"requestId\":\"<ticket id, optional>\",\"tasks\":[{\"title\":\"...\",\"description\":\"...\",\"requiredRole\":\"developer\",\"acceptanceCriteria\":\"...\",\"priority\":\"high\"}]}' [--request-id <id>]"
|
|
28
|
+
[ -z "$INPUT" ] && error_exit "Usage: execute.sh '{\"objective\":\"Build auth module\",\"projectPath\":\"/path/to/project\",\"requestId\":\"<ticket id, optional>\",\"tasks\":[{\"title\":\"...\",\"description\":\"...\",\"requiredRole\":\"developer\",\"acceptanceCriteria\":\"...\",\"priority\":\"high\"}]}' [--request-id <id>] [--dry-run] (optional per task: \"blockedBy\":[<index or title>, ...])"
|
|
27
29
|
|
|
28
30
|
OBJECTIVE=$(printf '%s' "$INPUT" | jq -r '.objective // empty')
|
|
29
31
|
PROJECT_PATH=$(printf '%s' "$INPUT" | jq -r '.projectPath // empty')
|
|
@@ -39,11 +41,52 @@ if [ "$TASK_COUNT" = "0" ]; then
|
|
|
39
41
|
error_exit "tasks array must contain at least one task"
|
|
40
42
|
fi
|
|
41
43
|
|
|
44
|
+
# Blocking edges: tasks[].blockedBy lists tasks of this same call (0-based
|
|
45
|
+
# index or exact title). Resolve to indexes, reject unknown/ambiguous
|
|
46
|
+
# references and cycles (a self-reference is a cycle) BEFORE creating anything, and derive a creation order
|
|
47
|
+
# in which every blocker comes first.
|
|
48
|
+
PLAN=$(printf '%s' "$TASKS" | jq -c '
|
|
49
|
+
. as $t
|
|
50
|
+
| [ to_entries[] | (.value.blockedBy // []) | map(
|
|
51
|
+
if type == "number" then (if . >= 0 and . < ($t | length) and . == floor then . else null end)
|
|
52
|
+
elif type == "string" then (. as $s | [$t | to_entries[] | select(.value.title == $s) | .key] | if length == 1 then .[0] else null end)
|
|
53
|
+
else null end) ] as $deps
|
|
54
|
+
| ([ $deps | to_entries[] | select(.value | any(. == null)) | .key ]) as $bad
|
|
55
|
+
| { deps: $deps, bad: $bad }
|
|
56
|
+
| . as $p
|
|
57
|
+
| ($p.deps | length) as $n
|
|
58
|
+
| ({ done: [], rem: [range(0; $n)], stuck: false }
|
|
59
|
+
| until((.rem | length) == 0 or .stuck;
|
|
60
|
+
. as $s
|
|
61
|
+
| [ $s.rem[] | . as $i | select($p.deps[$i] | all(. as $d | any($s.done[]; . == $d))) ] as $ready
|
|
62
|
+
| if ($ready | length) == 0 then .stuck = true else (.done += $ready | .rem -= $ready) end)) as $o
|
|
63
|
+
| { deps: $p.deps, bad: $p.bad, order: $o.done, cyclic: $o.rem }')
|
|
64
|
+
BAD=$(printf '%s' "$PLAN" | jq -c '.bad')
|
|
65
|
+
CYCLIC=$(printf '%s' "$PLAN" | jq -c '.cyclic')
|
|
66
|
+
if [ "$BAD" != "[]" ]; then
|
|
67
|
+
error_exit "blockedBy has an unknown, ambiguous or invalid reference in task index(es) ${BAD}; nothing created"
|
|
68
|
+
fi
|
|
69
|
+
if [ "$CYCLIC" != "[]" ]; then
|
|
70
|
+
error_exit "blockedBy forms a cycle among task index(es) ${CYCLIC}; nothing created"
|
|
71
|
+
fi
|
|
72
|
+
|
|
73
|
+
if [ "$DRY_RUN" = "1" ]; then
|
|
74
|
+
printf '%s' "$TASKS" | jq -c --argjson plan "$PLAN" --arg objective "$OBJECTIVE" '
|
|
75
|
+
. as $t
|
|
76
|
+
| { dryRun: true, objective: $objective, tasks: [ $plan.order[] | . as $i | {
|
|
77
|
+
index: $i, title: $t[$i].title,
|
|
78
|
+
blockedBy: [ $plan.deps[$i][] | $t[.].title ],
|
|
79
|
+
delivers: ($t[$i].description // "") } ] }'
|
|
80
|
+
exit 0
|
|
81
|
+
fi
|
|
82
|
+
|
|
42
83
|
CREATED_TASKS="[]"
|
|
43
84
|
ERRORS="[]"
|
|
85
|
+
# index -> WorkItem id, for resolving blockedBy into dependsOn
|
|
86
|
+
declare -a CREATED_ID_BY_INDEX=()
|
|
44
87
|
|
|
45
|
-
# Create each sub-task via the task-
|
|
46
|
-
for i in $(
|
|
88
|
+
# Create each sub-task via the task-pool API, blockers first
|
|
89
|
+
for i in $(printf '%s' "$PLAN" | jq -r '.order[]'); do
|
|
47
90
|
TASK_TITLE=$(echo "$TASKS" | jq -r ".[$i].title // empty")
|
|
48
91
|
TASK_DESC=$(echo "$TASKS" | jq -r ".[$i].description // empty")
|
|
49
92
|
TASK_ROLE=$(echo "$TASKS" | jq -r ".[$i].requiredRole // \"developer\"")
|
|
@@ -55,6 +98,21 @@ for i in $(seq 0 $((TASK_COUNT - 1))); do
|
|
|
55
98
|
continue
|
|
56
99
|
fi
|
|
57
100
|
|
|
101
|
+
# Resolve blockers to WorkItem ids; a blocker that failed to create blocks this task too.
|
|
102
|
+
DEPENDS_ON="[]"
|
|
103
|
+
DEP_FAILED=0
|
|
104
|
+
for d in $(printf '%s' "$PLAN" | jq -r ".deps[$i][]"); do
|
|
105
|
+
if [ -n "${CREATED_ID_BY_INDEX[$d]:-}" ]; then
|
|
106
|
+
DEPENDS_ON=$(echo "$DEPENDS_ON" | jq --arg id "${CREATED_ID_BY_INDEX[$d]}" '. + [$id]')
|
|
107
|
+
else
|
|
108
|
+
DEP_FAILED=1
|
|
109
|
+
fi
|
|
110
|
+
done
|
|
111
|
+
if [ "$DEP_FAILED" = "1" ]; then
|
|
112
|
+
ERRORS=$(echo "$ERRORS" | jq --arg msg "Skipped (a blocker was not created): ${TASK_TITLE}" '. + [$msg]')
|
|
113
|
+
continue
|
|
114
|
+
fi
|
|
115
|
+
|
|
58
116
|
# Compose the brief markdown for the WorkItem.
|
|
59
117
|
BRIEF="${TASK_DESC}"
|
|
60
118
|
[ -n "$TASK_CRITERIA" ] && BRIEF="${BRIEF}
|
|
@@ -83,13 +141,14 @@ Required role: ${TASK_ROLE}"
|
|
|
83
141
|
--arg role "$TASK_ROLE" \
|
|
84
142
|
--arg priority "$TASK_PRIORITY" \
|
|
85
143
|
--arg requestId "$REQUEST_ID" \
|
|
144
|
+
--argjson dependsOn "$DEPENDS_ON" \
|
|
86
145
|
'{
|
|
87
146
|
title: $title,
|
|
88
147
|
type: "delegate",
|
|
89
148
|
owner: "system",
|
|
90
149
|
briefMarkdown: $brief,
|
|
91
150
|
metadata: { projectPath: $projectPath, milestone: $milestone, requiredRole: $role, priority: $priority }
|
|
92
|
-
} + (if $requestId != "" then {requestId: $requestId} else {} end)')
|
|
151
|
+
} + (if $requestId != "" then {requestId: $requestId} else {} end) + (if ($dependsOn | length) > 0 then {dependsOn: $dependsOn} else {} end)')
|
|
93
152
|
|
|
94
153
|
# No envelope: addItem reads req.body directly as the CreateWorkItemInput.
|
|
95
154
|
CREATE_BODY="$WORK_ITEM"
|
|
@@ -97,12 +156,14 @@ Required role: ${TASK_ROLE}"
|
|
|
97
156
|
CREATED_ID=$(echo "$CREATE_RESULT" | jq -r '.data.id // .workItem.id // empty' 2>/dev/null || true)
|
|
98
157
|
|
|
99
158
|
if [ -n "$CREATED_ID" ]; then
|
|
159
|
+
CREATED_ID_BY_INDEX[$i]="$CREATED_ID"
|
|
100
160
|
CREATED_TASKS=$(echo "$CREATED_TASKS" | jq \
|
|
101
161
|
--arg title "$TASK_TITLE" \
|
|
102
162
|
--arg role "$TASK_ROLE" \
|
|
103
163
|
--arg id "$CREATED_ID" \
|
|
104
164
|
--arg priority "$TASK_PRIORITY" \
|
|
105
|
-
|
|
165
|
+
--argjson dependsOn "$DEPENDS_ON" \
|
|
166
|
+
'. + [{title: $title, requiredRole: $role, workItemId: $id, priority: $priority} + (if ($dependsOn | length) > 0 then {dependsOn: $dependsOn} else {} end)]')
|
|
106
167
|
else
|
|
107
168
|
ERRORS=$(echo "$ERRORS" | jq --arg msg "Failed to create WorkItem: ${TASK_TITLE}" '. + [$msg]')
|
|
108
169
|
fi
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Tests for decompose-goal (TL) — run with: bash execute.test.sh
|
|
3
|
+
# A python HTTP stub plays the backend; asserts the POST /task-pool/add bodies.
|
|
4
|
+
set -u
|
|
5
|
+
HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
6
|
+
EXEC="$HERE/execute.sh"
|
|
7
|
+
PASS=0; FAIL=0
|
|
8
|
+
check() {
|
|
9
|
+
local name="$1"; local got="$2"; local want="$3"
|
|
10
|
+
if [ "$got" = "$want" ]; then PASS=$((PASS+1)); else FAIL=$((FAIL+1)); echo "FAIL: $name"; echo " want: $want"; echo " got: $got"; fi
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
PORT=18843
|
|
14
|
+
STUB_LOG="$(mktemp)"; export STUB_LOG; export STUB_PORT="$PORT"
|
|
15
|
+
python3 -u <<'PY' >/dev/null 2>&1 &
|
|
16
|
+
from http.server import BaseHTTPRequestHandler, HTTPServer
|
|
17
|
+
import json, os
|
|
18
|
+
LOG = os.environ['STUB_LOG']; PORT = int(os.environ['STUB_PORT'])
|
|
19
|
+
N = [0]
|
|
20
|
+
class H(BaseHTTPRequestHandler):
|
|
21
|
+
def reply(self, code, obj):
|
|
22
|
+
self.send_response(code); self.send_header('Content-Type', 'application/json'); self.end_headers()
|
|
23
|
+
self.wfile.write(json.dumps(obj).encode())
|
|
24
|
+
def do_GET(self):
|
|
25
|
+
return self.reply(200, {'ok': True})
|
|
26
|
+
def do_POST(self):
|
|
27
|
+
n = int(self.headers.get('content-length', '0')); body = json.loads(self.rfile.read(n).decode() or '{}')
|
|
28
|
+
if not self.path.endswith('/task-pool/add'):
|
|
29
|
+
return self.reply(200, {'success': True})
|
|
30
|
+
with open(LOG, 'a') as f: f.write(json.dumps(body) + '\n')
|
|
31
|
+
if body.get('title') == 'Fails':
|
|
32
|
+
return self.reply(500, {'success': False})
|
|
33
|
+
return self.reply(200, {'success': True, 'data': {'id': 'wi-' + body['title']}})
|
|
34
|
+
def log_message(self, *a, **k): pass
|
|
35
|
+
HTTPServer(('127.0.0.1', PORT), H).serve_forever()
|
|
36
|
+
PY
|
|
37
|
+
STUB_PID=$!
|
|
38
|
+
disown "$STUB_PID" 2>/dev/null || true
|
|
39
|
+
trap 'kill "$STUB_PID" >/dev/null 2>&1; rm -f "$STUB_LOG"' EXIT
|
|
40
|
+
for i in $(seq 1 30); do curl -s -o /dev/null -m 0.2 "http://127.0.0.1:${PORT}/" 2>/dev/null && break; sleep 0.1; done
|
|
41
|
+
|
|
42
|
+
run() { CREWLY_SESSION_NAME=tl-sam CREWLY_API_URL="http://127.0.0.1:${PORT}" bash "$EXEC" "$@" 2>&1; }
|
|
43
|
+
posts() { wc -l < "$STUB_LOG" | tr -d ' '; }
|
|
44
|
+
|
|
45
|
+
# 1. No blockedBy: unchanged behaviour, no dependsOn on the wire.
|
|
46
|
+
: > "$STUB_LOG"
|
|
47
|
+
OUT=$(run '{"objective":"O","tasks":[{"title":"A","description":"a"},{"title":"B","description":"b"}]}')
|
|
48
|
+
check "plain: two created" "$(printf '%s' "$OUT" | jq -r .tasksCreated)" "2"
|
|
49
|
+
check "plain: no dependsOn" "$(jq -c 'has("dependsOn")' "$STUB_LOG" | sort -u)" "false"
|
|
50
|
+
|
|
51
|
+
# 2. Dependency chain (titles and indexes mixed), listed out of order: blockers are created first.
|
|
52
|
+
: > "$STUB_LOG"
|
|
53
|
+
OUT=$(run '{"objective":"Auth","tasks":[
|
|
54
|
+
{"title":"UI","description":"u","blockedBy":["API"]},
|
|
55
|
+
{"title":"Schema","description":"s"},
|
|
56
|
+
{"title":"API","description":"a","blockedBy":[1]},
|
|
57
|
+
{"title":"E2E","description":"e","blockedBy":["UI","API"]}]}')
|
|
58
|
+
check "chain: all created" "$(printf '%s' "$OUT" | jq -r .tasksCreated)" "4"
|
|
59
|
+
check "chain: creation order" "$(jq -r .title "$STUB_LOG" | paste -sd, -)" "Schema,API,UI,E2E"
|
|
60
|
+
check "chain: API depends on Schema" "$(jq -c 'select(.title=="API") | .dependsOn' "$STUB_LOG")" '["wi-Schema"]'
|
|
61
|
+
check "chain: UI depends on API" "$(jq -c 'select(.title=="UI") | .dependsOn' "$STUB_LOG")" '["wi-API"]'
|
|
62
|
+
check "chain: E2E depends on API and UI" "$(jq -c 'select(.title=="E2E") | .dependsOn | sort' "$STUB_LOG")" '["wi-API","wi-UI"]'
|
|
63
|
+
check "chain: Schema has no dependsOn" "$(jq -c 'select(.title=="Schema") | has("dependsOn")' "$STUB_LOG")" "false"
|
|
64
|
+
|
|
65
|
+
# 3. Cycle / unknown / self reference: error, nothing created.
|
|
66
|
+
: > "$STUB_LOG"
|
|
67
|
+
OUT=$(run '{"objective":"O","tasks":[{"title":"A","description":"a","blockedBy":["B"]},{"title":"B","description":"b","blockedBy":["A"]}]}')
|
|
68
|
+
check "cycle: error" "$(printf '%s' "$OUT" | grep -c 'cycle')" "1"
|
|
69
|
+
check "cycle: nothing created" "$(posts)" "0"
|
|
70
|
+
OUT=$(run '{"objective":"O","tasks":[{"title":"A","description":"a","blockedBy":["Nope"]}]}')
|
|
71
|
+
check "unknown title: error" "$(printf '%s' "$OUT" | grep -c 'unknown')" "1"
|
|
72
|
+
OUT=$(run '{"objective":"O","tasks":[{"title":"A","description":"a","blockedBy":[5]}]}')
|
|
73
|
+
check "index out of range: error" "$(printf '%s' "$OUT" | grep -c 'unknown')" "1"
|
|
74
|
+
OUT=$(run '{"objective":"O","tasks":[{"title":"A","description":"a","blockedBy":[0]}]}')
|
|
75
|
+
check "self reference: error" "$(printf '%s' "$OUT" | grep -c 'cycle')" "1"
|
|
76
|
+
check "errors: nothing created" "$(posts)" "0"
|
|
77
|
+
|
|
78
|
+
# 4. A blocker that fails to create also blocks its dependents from being created.
|
|
79
|
+
: > "$STUB_LOG"
|
|
80
|
+
OUT=$(run '{"objective":"O","tasks":[{"title":"Fails","description":"f"},{"title":"After","description":"x","blockedBy":["Fails"]}]}')
|
|
81
|
+
check "failed blocker: success false" "$(printf '%s' "$OUT" | jq -r .success)" "false"
|
|
82
|
+
check "failed blocker: dependent skipped" "$(grep -c '"After"' "$STUB_LOG")" "0"
|
|
83
|
+
|
|
84
|
+
# 5. --dry-run prints the breakdown, creates nothing.
|
|
85
|
+
: > "$STUB_LOG"
|
|
86
|
+
OUT=$(run '{"objective":"O","tasks":[{"title":"B","description":"b","blockedBy":["A"]},{"title":"A","description":"a"}]}' --dry-run)
|
|
87
|
+
check "dry-run: order" "$(printf '%s' "$OUT" | jq -c '[.tasks[] | .title]')" '["A","B"]'
|
|
88
|
+
check "dry-run: blockedBy titles" "$(printf '%s' "$OUT" | jq -c '.tasks[1].blockedBy')" '["A"]'
|
|
89
|
+
check "dry-run: nothing created" "$(posts)" "0"
|
|
90
|
+
|
|
91
|
+
echo "decompose-goal: ${PASS} passed, ${FAIL} failed"
|
|
92
|
+
[ "$FAIL" -eq 0 ]
|
|
@@ -99,7 +99,7 @@ If two rules disagree, the higher tier wins.
|
|
|
99
99
|
4. One TL or senior reviewer + one peer reviewer.
|
|
100
100
|
5. CHANGELOG entry if user-visible.
|
|
101
101
|
6. Manual smoke test of the changed flow before merge.
|
|
102
|
-
7.
|
|
102
|
+
7. Merge Danger filled in on the PR (Door + Blast radius). A one-way door needs the rollback rehearsal from Tier 3. One-way = data migration, deletion, published artifact (npm, docker, deploy), outbound message.
|
|
103
103
|
|
|
104
104
|
**Skipped vs Release Path:**
|
|
105
105
|
- No staged rollout (merge-and-deploy together).
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: common-writing-for-agents
|
|
3
|
+
version: 1
|
|
4
|
+
createdAt: 2026-10-13T00:00:00Z
|
|
5
|
+
updatedAt: 2026-10-13T00:00:00Z
|
|
6
|
+
createdBy: system
|
|
7
|
+
type: norm
|
|
8
|
+
role: all
|
|
9
|
+
category: quality
|
|
10
|
+
priority: 8
|
|
11
|
+
title: Writing for Agents
|
|
12
|
+
description: How to word skills, prompts, roles and SOPs so agents act on them at low context cost
|
|
13
|
+
triggers:
|
|
14
|
+
- write skill
|
|
15
|
+
- write prompt
|
|
16
|
+
- skill description
|
|
17
|
+
- author sop
|
|
18
|
+
- role prompt
|
|
19
|
+
- steering text
|
|
20
|
+
tags:
|
|
21
|
+
- authoring
|
|
22
|
+
- prompts
|
|
23
|
+
- skills
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
# Writing for Agents
|
|
27
|
+
|
|
28
|
+
Long form: mattpocock/skills `writing-for-agents`. Skill descriptions and always-loaded steering text cost context on every turn. Check new text against these six points. `skill-lint` (config/skills/_conventions) enforces the mechanical ones.
|
|
29
|
+
|
|
30
|
+
1. **Pointer wording decides when material is read.** Front-load the leading word of a description. One trigger per branch; synonyms of one trigger are one branch written twice. Cut identity the body already carries.
|
|
31
|
+
2. **End every step on a completion criterion.** The agent must be able to tell done from not-done. The best criteria are checkable and exhaustive ("the command exits 0", not "make sure it works").
|
|
32
|
+
3. **Say what to do, not what to avoid.** A prohibition puts the forbidden behavior into context and makes it more available. Prefer "Run the check, then report its exit code" over "NEVER report without checking".
|
|
33
|
+
4. **Do not restate the environment.** A doc that copies `package.json` scripts or config is a cache that goes stale. Cache only what cannot be found by looking; point to the file otherwise.
|
|
34
|
+
5. **Hunt no-ops.** If the model already does it by default, the sentence costs load and changes nothing. Keep a sentence only if removing it would change behavior (the same test for #877 rule cleanup).
|
|
35
|
+
6. **Keep emphasis rare.** Capitals and HARD RULE lose force when everything has them.
|
|
36
|
+
|
|
37
|
+
## Example (real skill: `agent/core/publish-app`)
|
|
38
|
+
|
|
39
|
+
Before (612 chars, why-it-works history and edge cases in the pointer):
|
|
40
|
+
|
|
41
|
+
> Publish a small web app (HTML/JS) you wrote to https://apps.crewlyai.com/<appId> so the owner can open it on their phone. Creates the app the first time, uploads a new version each time after (same app for the same directory), supports rollback, and can post an "Open app" card to the owner (...). Can ask the owner to make an app public, or to publish it as a template on the Crewly Marketplace (...). The owner's edits, comments on elements, and anonymous visitors' submissions on a public app, come back to you as an [APP CHANGES] message.
|
|
42
|
+
|
|
43
|
+
After (under 200 chars, one trigger, detail moves to the SKILL.md body):
|
|
44
|
+
|
|
45
|
+
> Publish an HTML/JS app you wrote to apps.crewlyai.com so the owner can open it on their phone. Also: new version, rollback, make public.
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: dev-debugging
|
|
3
|
+
version: 1
|
|
4
|
+
createdAt: 2026-10-13T00:00:00Z
|
|
5
|
+
updatedAt: 2026-10-13T00:00:00Z
|
|
6
|
+
createdBy: system
|
|
7
|
+
type: sop
|
|
8
|
+
role: developer
|
|
9
|
+
category: debugging
|
|
10
|
+
priority: 9
|
|
11
|
+
title: Debugging
|
|
12
|
+
description: How to debug a failure — a red-capable loop first, ranked falsifiable hypotheses, tagged debug logs, cleanup
|
|
13
|
+
triggers:
|
|
14
|
+
- debug
|
|
15
|
+
- failing test
|
|
16
|
+
- bug
|
|
17
|
+
- regression
|
|
18
|
+
- flaky
|
|
19
|
+
- broken
|
|
20
|
+
- repro
|
|
21
|
+
tags:
|
|
22
|
+
- debugging
|
|
23
|
+
- testing
|
|
24
|
+
- quality
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
# Debugging
|
|
28
|
+
|
|
29
|
+
Long form: mattpocock/skills `diagnosing-bugs`. Redact secrets in every command and artifact you show.
|
|
30
|
+
|
|
31
|
+
## 1. Loop first
|
|
32
|
+
|
|
33
|
+
Name **one command** you have already run at least once that shows the user's exact symptom (red-capable), is deterministic, fast and runnable by you. If you are reading code to build a theory before this command exists, stop and build the command.
|
|
34
|
+
|
|
35
|
+
## 2. Reproduce and minimise
|
|
36
|
+
|
|
37
|
+
Cut inputs one at a time. Done when every remaining element is load-bearing.
|
|
38
|
+
|
|
39
|
+
## 3. Hypotheses
|
|
40
|
+
|
|
41
|
+
Write 3-5 ranked hypotheses before testing any. Each is falsifiable: "If X is the cause, then changing Y makes the bug disappear." If you cannot state the prediction, it is a guess. Test one at a time.
|
|
42
|
+
|
|
43
|
+
## 4. Instrument
|
|
44
|
+
|
|
45
|
+
Tag every debug log with a unique prefix, e.g. `[DEBUG-a4f2]`, so cleanup is one grep. Untagged logs survive; tagged logs die. If no correct seam exists to test the bug, that is itself the finding.
|
|
46
|
+
|
|
47
|
+
## 5. Fix with a regression test
|
|
48
|
+
|
|
49
|
+
Turn the loop into a test. See it fail first, then fix (see `testing-requirements`: red before green).
|
|
50
|
+
|
|
51
|
+
## 6. Clean up
|
|
52
|
+
|
|
53
|
+
`grep -rn "\[DEBUG-" .` returns nothing. The pre-commit hook rejects a staged `[DEBUG-` line.
|
|
@@ -85,6 +85,10 @@ git worktree remove /tmp/crewly-{ticket-name}-{owner}
|
|
|
85
85
|
|
|
86
86
|
**Solo work exception:** if you are the only developer active in the team and you're not parking work for parallel review, working directly in the main repo is acceptable. The worktree pattern is required only when there is a real risk of branch-state collision.
|
|
87
87
|
|
|
88
|
+
## Destructive Git Is Blocked
|
|
89
|
+
|
|
90
|
+
A hook blocks these in your Bash tool: force-push (`--force`, `-f`, `--force-with-lease`, `+ref`), any push to `main`/`master`, `reset --hard`, `clean -f`, `branch -D`, `checkout .`, `restore .`. Plain `git push origin feat/x` is fine. Instead: `git stash -u` before discarding, `branch -d` for merged branches, push a normal commit and open a PR. If you truly need one, ask your team lead. Limit: interpreter one-liners and variable-built commands are not seen.
|
|
91
|
+
|
|
88
92
|
## Before Pushing
|
|
89
93
|
|
|
90
94
|
1. Run `npm run typecheck`
|
|
@@ -56,6 +56,20 @@ describe('ComponentName', () => {
|
|
|
56
56
|
- No test interdependencies
|
|
57
57
|
- Clean up after tests
|
|
58
58
|
|
|
59
|
+
When a test fails and the cause is unclear, follow the `debugging` SOP (red-capable loop first).
|
|
60
|
+
|
|
61
|
+
## Anti-patterns
|
|
62
|
+
|
|
63
|
+
Coverage percentage rewards all three. Avoid them.
|
|
64
|
+
|
|
65
|
+
- **Tautological**: the assertion recomputes the expected value the way the code does (`expect(add(a, b)).toBe(a + b)`). Tell: it can never disagree with the code. Take expected values from a literal, a worked example or the spec. Prove a test is not tautological with the mutation check: break the code on purpose and see the test fail.
|
|
66
|
+
- **Implementation-coupled**: the test checks how (private calls, call order), not what. Tell: it breaks on a refactor that changes no behavior.
|
|
67
|
+
- **Horizontal slicing**: all tests first, then all code. Tell: many tests, none ever seen red. Work one test, one implementation, repeat. **Red before green**: see the new test fail before the fix.
|
|
68
|
+
|
|
69
|
+
## Seams
|
|
70
|
+
|
|
71
|
+
Test at agreed seams (public function, API route, CLI entry), not at every internal. For each seam write one line: what it catches and what it misses.
|
|
72
|
+
|
|
59
73
|
## Coverage Goals
|
|
60
74
|
|
|
61
75
|
- Minimum 80% for new code
|
|
@@ -1040,7 +1040,7 @@ export declare const CONTROL_PLANE_GUARD_CONSTANTS: {
|
|
|
1040
1040
|
/** Files under CREWLY_HOME that agents must not read with the built-in tools either. */
|
|
1041
1041
|
readonly CREWLY_HOME_READ_DENIED_FILES: readonly ["api-token"];
|
|
1042
1042
|
/** Write-protected directories under the install root (whole subtree). */
|
|
1043
|
-
readonly INSTALL_DIRS: readonly ["config/skills/orchestrator/stop-agent", "config/skills/orchestrator/start-agent", "config/skills/orchestrator/terminate-agent", "config/skills/orchestrator/stop-team", "config/skills/orchestrator/start-team", "config/skills/orchestrator/restart-crewly", "config/hooks/control-plane-guard", "config/hooks/agent-status", "config/hooks/subagent-guard", "config/hooks/credential-guard", "config/hooks/live-checkout-guard", "dist"];
|
|
1043
|
+
readonly INSTALL_DIRS: readonly ["config/skills/orchestrator/stop-agent", "config/skills/orchestrator/start-agent", "config/skills/orchestrator/terminate-agent", "config/skills/orchestrator/stop-team", "config/skills/orchestrator/start-team", "config/skills/orchestrator/restart-crewly", "config/hooks/control-plane-guard", "config/hooks/agent-status", "config/hooks/subagent-guard", "config/hooks/credential-guard", "config/hooks/live-checkout-guard", "config/hooks/destructive-git-guard", "dist"];
|
|
1044
1044
|
/** Write-protected files under the install root. */
|
|
1045
1045
|
readonly INSTALL_FILES: readonly ["config/skills/_common/lib.sh"];
|
|
1046
1046
|
/** Write-protected directories under the agent's project path (whole subtree). */
|
|
@@ -1063,6 +1063,21 @@ export declare const LIVE_CHECKOUT_GUARD_CONSTANTS: {
|
|
|
1063
1063
|
/** Codex tools the hook is attached to (shell, plus its patch tool). */
|
|
1064
1064
|
readonly CODEX_MATCHER: "Bash|apply_patch|Edit|Write";
|
|
1065
1065
|
};
|
|
1066
|
+
/**
|
|
1067
|
+
* Destructive-git guard: blocks force-push, push to main/master, reset --hard,
|
|
1068
|
+
* clean -f, branch -D, checkout . and restore . in an agent's Bash tool, so an
|
|
1069
|
+
* agent cannot destroy its own unmerged work.
|
|
1070
|
+
*/
|
|
1071
|
+
export declare const DESTRUCTIVE_GIT_GUARD_CONSTANTS: {
|
|
1072
|
+
/** Backend env var; `0` turns the guard off for sessions launched by this backend (the owner/TL override). */
|
|
1073
|
+
readonly KILL_SWITCH_ENV: "CREWLY_DESTRUCTIVE_GIT_GUARD";
|
|
1074
|
+
/** Value of KILL_SWITCH_ENV that disables the guard. */
|
|
1075
|
+
readonly KILL_SWITCH_OFF_VALUE: "0";
|
|
1076
|
+
/** The hook script (node), relative to the install root. */
|
|
1077
|
+
readonly HOOK_SCRIPT: "config/hooks/destructive-git-guard/guard.mjs";
|
|
1078
|
+
/** Claude Code tool the hook is attached to. */
|
|
1079
|
+
readonly CLAUDE_MATCHER: "Bash";
|
|
1080
|
+
};
|
|
1066
1081
|
/**
|
|
1067
1082
|
* Credential guard (specs/2026-10-04-agent-credential-isolation.md, layer 2):
|
|
1068
1083
|
* a pre-tool hook, on every runtime that has one, that refuses an agent's
|
|
@@ -1482,6 +1497,14 @@ export declare const TUI_INPUT_GUARD: {
|
|
|
1482
1497
|
readonly RULE_STALE_PREFIX_MIN_CHARS: 40;
|
|
1483
1498
|
/** Most status/footer lines allowed below an input box */
|
|
1484
1499
|
readonly FOOTER_MAX_LINES: 6;
|
|
1500
|
+
/**
|
|
1501
|
+
* Most rows below the bottom rule when searching for a Claude Code /
|
|
1502
|
+
* Antigravity box. Claude Code lists background agents and shells under
|
|
1503
|
+
* the box, so a busy session can have well over FOOTER_MAX_LINES rows
|
|
1504
|
+
* there (crewly#1113). Only the box search uses this; turn-signal reading
|
|
1505
|
+
* keeps FOOTER_MAX_LINES.
|
|
1506
|
+
*/
|
|
1507
|
+
readonly BOX_FOOTER_MAX_LINES: 14;
|
|
1485
1508
|
/** Most lines an input box may span */
|
|
1486
1509
|
readonly MAX_BOX_LINES: 60;
|
|
1487
1510
|
/**
|
|
@@ -3300,6 +3323,20 @@ export declare const ORC_CONVERSATION_CONSTANTS: {
|
|
|
3300
3323
|
/** Most of an earlier handover carried into a new one when the source conversation is unreadable */
|
|
3301
3324
|
readonly CHAINED_HANDOVER_MAX_CHARS: 16000;
|
|
3302
3325
|
};
|
|
3326
|
+
/** Pointer header (open work, suggested skills) written at the top of a handover file. */
|
|
3327
|
+
export declare const HANDOVER_POINTERS_CONSTANTS: {
|
|
3328
|
+
/** Task pool file under CREWLY_HOME (dir, file) */
|
|
3329
|
+
readonly POOL_DIR: "task-pool";
|
|
3330
|
+
readonly POOL_FILE: "pool.json";
|
|
3331
|
+
/** WorkItem statuses that count as still open for the agent */
|
|
3332
|
+
readonly OPEN_STATUSES: readonly string[];
|
|
3333
|
+
readonly MAX_OPEN_WORK: 15;
|
|
3334
|
+
readonly MAX_LINKS: 10;
|
|
3335
|
+
readonly TITLE_CHARS: 80;
|
|
3336
|
+
/** Markers around the header, so a chained handover can strip it */
|
|
3337
|
+
readonly START_MARK: "<!-- handover-pointers -->";
|
|
3338
|
+
readonly END_MARK: "<!-- /handover-pointers -->";
|
|
3339
|
+
};
|
|
3303
3340
|
/**
|
|
3304
3341
|
* Fresh conversation per new task for Claude Code team members (never the
|
|
3305
3342
|
* orchestrator): before a work item with a different root than the last one
|
|
@@ -5847,6 +5884,8 @@ export declare const TICKET_CONSTANTS: {
|
|
|
5847
5884
|
* still takes follow-ups into that ticket instead of opening a new one.
|
|
5848
5885
|
*/
|
|
5849
5886
|
readonly RECENT_TICKET_MS: number;
|
|
5887
|
+
/** A chase matches only tickets with activity in this window */
|
|
5888
|
+
readonly CHASE_MATCH_WINDOW_MS: number;
|
|
5850
5889
|
/**
|
|
5851
5890
|
* In a DM (every message is top level) a reply this soon after the
|
|
5852
5891
|
* conversation's latest ticket activity is a follow-up to that ticket.
|
|
@@ -6797,6 +6836,12 @@ export declare const DECISION_CONSTANTS: {
|
|
|
6797
6836
|
* (specs/2026-10-02-decision-card-thread-answers.md §2) (ms)
|
|
6798
6837
|
*/
|
|
6799
6838
|
readonly WAIT_REMINDER_DELAY_MS: number;
|
|
6839
|
+
/**
|
|
6840
|
+
* `wait` default: a card still unanswered this long after its one reminder
|
|
6841
|
+
* (a lifted reply question: after the deadline notice, it never gets a
|
|
6842
|
+
* reminder) expires instead of staying open for days (#1243) (ms)
|
|
6843
|
+
*/
|
|
6844
|
+
readonly WAIT_EXPIRE_AFTER_REMINDER_MS: number;
|
|
6800
6845
|
/** Max characters of a withdrawn card's reason ("Closed — <reason>") */
|
|
6801
6846
|
readonly CLOSED_REASON_MAX_CHARS: 120;
|
|
6802
6847
|
/** Withdraw reasons the harness itself uses (cancelWhere notes) */
|
|
@@ -6880,6 +6925,18 @@ export declare const OPEN_ITEMS_CONSTANTS: {
|
|
|
6880
6925
|
readonly YES_LABEL: "Yes";
|
|
6881
6926
|
readonly NO_LABEL: "No";
|
|
6882
6927
|
readonly REPLY_LABEL: "Reply in thread";
|
|
6928
|
+
/** A lifted question shorter than this (characters) gets its subject prepended (#1242) */
|
|
6929
|
+
readonly QUESTION_MIN_CHARS: 20;
|
|
6930
|
+
/** Still shorter than this after the subject was added (characters): too vague for a card, tracked without one */
|
|
6931
|
+
readonly QUESTION_VAGUE_CHARS: 12;
|
|
6932
|
+
/** Suffix of the option the agent recommended */
|
|
6933
|
+
readonly RECOMMENDED_SUFFIX: " (recommended)";
|
|
6934
|
+
/** A sentence that recommends something ("我推荐 A", "I recommend B") */
|
|
6935
|
+
readonly RECOMMENDATION_PATTERN: RegExp;
|
|
6936
|
+
/** A recommendation that argues against doing it ("不建议", "don't recommend") */
|
|
6937
|
+
readonly RECOMMENDATION_NEGATIVE_PATTERN: RegExp;
|
|
6938
|
+
/** A project ticket id named in a promise ("CE-16"); the work done under it fulfils the promise wherever it ran (crewly#1037) */
|
|
6939
|
+
readonly PROJECT_TICKET_REF_PATTERN: RegExp;
|
|
6883
6940
|
/** `WorkItem.metadata` key of a follow-up WorkItem */
|
|
6884
6941
|
readonly FOLLOW_UP_METADATA_KEY: "openItemFollowUp";
|
|
6885
6942
|
/**
|
|
@@ -7677,6 +7734,11 @@ export declare const OWNER_THREAD_SENTINEL_CONSTANTS: {
|
|
|
7677
7734
|
readonly DEADLINE_FACTOR: 1.5;
|
|
7678
7735
|
/** Floor of a promise deadline (ms) */
|
|
7679
7736
|
readonly MIN_DEADLINE_MS: number;
|
|
7737
|
+
/**
|
|
7738
|
+
* A promise with no stated time ("做好发到 #x", "I'll post the result") is
|
|
7739
|
+
* overdue after this much silence from the agent in the thread (#1240) (ms)
|
|
7740
|
+
*/
|
|
7741
|
+
readonly NO_ETA_SILENCE_MS: number;
|
|
7680
7742
|
/** Longest promise the sentinel times (longer ones are not timed) */
|
|
7681
7743
|
readonly MAX_PROMISE_MINUTES: number;
|
|
7682
7744
|
/** Slot freeing / idle stop spare an agent whose owner message or promise is this recent */
|
|
@@ -8281,4 +8343,22 @@ export declare const CANVAS_CONSTANTS: {
|
|
|
8281
8343
|
/** A Chrome session counts as the agent's browser while it was active this recently (ms) */
|
|
8282
8344
|
readonly BROWSER_ACTIVE_MS: number;
|
|
8283
8345
|
};
|
|
8346
|
+
/**
|
|
8347
|
+
* Hand-off of an owner-approved change to a recurring job to the agent that
|
|
8348
|
+
* runs it (crewly#1137).
|
|
8349
|
+
*/
|
|
8350
|
+
export declare const RECURRING_CHANGE_HANDOFF_CONSTANTS: {
|
|
8351
|
+
/** Share of the schedule's name/title terms the decision text must contain */
|
|
8352
|
+
readonly MIN_COVERAGE: 0.6;
|
|
8353
|
+
/** Distinct terms the decision and the schedule must share */
|
|
8354
|
+
readonly MIN_SHARED_TERMS: 2;
|
|
8355
|
+
/** ...or this many shared terms whatever the coverage (labels mixing two languages) */
|
|
8356
|
+
readonly SURE_SHARED_TERMS: 3;
|
|
8357
|
+
/** Terms shorter than this (Latin words) are noise */
|
|
8358
|
+
readonly MIN_WORD_CHARS: 3;
|
|
8359
|
+
/** `WorkItem.metadata` marker on the hand-off WorkItem */
|
|
8360
|
+
readonly METADATA_KEY: "recurringChangeHandoff";
|
|
8361
|
+
/** Option labels / answers that decline a change (nothing to hand off) */
|
|
8362
|
+
readonly DECLINE_PATTERN: RegExp;
|
|
8363
|
+
};
|
|
8284
8364
|
//# sourceMappingURL=constants.d.ts.map
|