omegon 0.6.0
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/.gitattributes +3 -0
- package/AGENTS.md +16 -0
- package/LICENSE +15 -0
- package/README.md +289 -0
- package/bin/pi.mjs +30 -0
- package/extensions/00-secrets/index.ts +1126 -0
- package/extensions/01-auth/auth.ts +401 -0
- package/extensions/01-auth/index.ts +289 -0
- package/extensions/auto-compact.ts +42 -0
- package/extensions/bootstrap/deps.ts +291 -0
- package/extensions/bootstrap/index.ts +811 -0
- package/extensions/chronos/chronos.sh +487 -0
- package/extensions/chronos/index.ts +148 -0
- package/extensions/cleave/assessment.ts +754 -0
- package/extensions/cleave/bridge.ts +31 -0
- package/extensions/cleave/conflicts.ts +250 -0
- package/extensions/cleave/dispatcher.ts +808 -0
- package/extensions/cleave/guardrails.ts +426 -0
- package/extensions/cleave/index.ts +3121 -0
- package/extensions/cleave/lifecycle-emitter.ts +20 -0
- package/extensions/cleave/openspec.ts +811 -0
- package/extensions/cleave/planner.ts +260 -0
- package/extensions/cleave/review.ts +579 -0
- package/extensions/cleave/skills.ts +355 -0
- package/extensions/cleave/types.ts +261 -0
- package/extensions/cleave/workspace.ts +861 -0
- package/extensions/cleave/worktree.ts +243 -0
- package/extensions/core-renderers.ts +253 -0
- package/extensions/dashboard/context-gauge.ts +58 -0
- package/extensions/dashboard/file-watch.ts +14 -0
- package/extensions/dashboard/footer.ts +1145 -0
- package/extensions/dashboard/git.ts +185 -0
- package/extensions/dashboard/index.ts +478 -0
- package/extensions/dashboard/memory-audit.ts +34 -0
- package/extensions/dashboard/overlay-data.ts +705 -0
- package/extensions/dashboard/overlay.ts +365 -0
- package/extensions/dashboard/render-utils.ts +54 -0
- package/extensions/dashboard/types.ts +191 -0
- package/extensions/dashboard/uri-helper.ts +45 -0
- package/extensions/debug.ts +69 -0
- package/extensions/defaults.ts +282 -0
- package/extensions/design-tree/dashboard-state.ts +161 -0
- package/extensions/design-tree/design-card.ts +362 -0
- package/extensions/design-tree/index.ts +2130 -0
- package/extensions/design-tree/lifecycle-emitter.ts +41 -0
- package/extensions/design-tree/tree.ts +1607 -0
- package/extensions/design-tree/types.ts +163 -0
- package/extensions/distill.ts +127 -0
- package/extensions/effort/index.ts +395 -0
- package/extensions/effort/tiers.ts +146 -0
- package/extensions/effort/types.ts +105 -0
- package/extensions/lib/git-state.ts +227 -0
- package/extensions/lib/local-models.ts +157 -0
- package/extensions/lib/model-preferences.ts +51 -0
- package/extensions/lib/model-routing.ts +720 -0
- package/extensions/lib/operator-fallback.ts +205 -0
- package/extensions/lib/operator-profile.ts +360 -0
- package/extensions/lib/slash-command-bridge.ts +253 -0
- package/extensions/lib/typebox-helpers.ts +16 -0
- package/extensions/local-inference/index.ts +727 -0
- package/extensions/mcp-bridge/README.md +220 -0
- package/extensions/mcp-bridge/index.ts +951 -0
- package/extensions/mcp-bridge/lib.ts +365 -0
- package/extensions/mcp-bridge/mcp.json +3 -0
- package/extensions/mcp-bridge/package.json +11 -0
- package/extensions/model-budget.ts +752 -0
- package/extensions/offline-driver.ts +403 -0
- package/extensions/openspec/archive-gate.ts +164 -0
- package/extensions/openspec/branch-cleanup.ts +64 -0
- package/extensions/openspec/dashboard-state.ts +50 -0
- package/extensions/openspec/index.ts +1917 -0
- package/extensions/openspec/lifecycle-emitter.ts +65 -0
- package/extensions/openspec/lifecycle-files.ts +70 -0
- package/extensions/openspec/lifecycle.ts +50 -0
- package/extensions/openspec/reconcile.ts +187 -0
- package/extensions/openspec/spec.ts +1385 -0
- package/extensions/openspec/types.ts +98 -0
- package/extensions/project-memory/DESIGN-global-mind.md +198 -0
- package/extensions/project-memory/README.md +202 -0
- package/extensions/project-memory/api-types.ts +382 -0
- package/extensions/project-memory/compaction-policy.ts +29 -0
- package/extensions/project-memory/core.ts +164 -0
- package/extensions/project-memory/embeddings.ts +230 -0
- package/extensions/project-memory/extraction-v2.ts +861 -0
- package/extensions/project-memory/factstore.ts +2177 -0
- package/extensions/project-memory/index.ts +3459 -0
- package/extensions/project-memory/injection-metrics.ts +91 -0
- package/extensions/project-memory/jsonl-io.ts +12 -0
- package/extensions/project-memory/lifecycle.ts +331 -0
- package/extensions/project-memory/migration.ts +293 -0
- package/extensions/project-memory/package.json +9 -0
- package/extensions/project-memory/sci-renderers.ts +7 -0
- package/extensions/project-memory/template.ts +103 -0
- package/extensions/project-memory/triggers.ts +52 -0
- package/extensions/project-memory/types.ts +102 -0
- package/extensions/render/composition/fonts/Inter-Bold.ttf +0 -0
- package/extensions/render/composition/fonts/Inter-Regular.ttf +0 -0
- package/extensions/render/composition/fonts/Tomorrow-Bold.ttf +0 -0
- package/extensions/render/composition/fonts/Tomorrow-Regular.ttf +0 -0
- package/extensions/render/composition/package-lock.json +534 -0
- package/extensions/render/composition/package.json +22 -0
- package/extensions/render/composition/render.mjs +246 -0
- package/extensions/render/composition/test-comp.tsx +87 -0
- package/extensions/render/composition/types.ts +24 -0
- package/extensions/render/excalidraw/UPSTREAM.md +81 -0
- package/extensions/render/excalidraw/elements.ts +764 -0
- package/extensions/render/excalidraw/index.ts +66 -0
- package/extensions/render/excalidraw/types.ts +223 -0
- package/extensions/render/excalidraw-renderer/pyproject.toml +8 -0
- package/extensions/render/excalidraw-renderer/render_excalidraw.py +182 -0
- package/extensions/render/excalidraw-renderer/render_template.html +59 -0
- package/extensions/render/index.ts +830 -0
- package/extensions/render/native-diagrams/index.ts +57 -0
- package/extensions/render/native-diagrams/motifs.ts +542 -0
- package/extensions/render/native-diagrams/raster.ts +8 -0
- package/extensions/render/native-diagrams/scene.ts +75 -0
- package/extensions/render/native-diagrams/spec.ts +204 -0
- package/extensions/render/native-diagrams/svg.ts +116 -0
- package/extensions/sci-ui.ts +304 -0
- package/extensions/session-log.ts +174 -0
- package/extensions/shared-state.ts +146 -0
- package/extensions/spinner-verbs.ts +91 -0
- package/extensions/style.ts +281 -0
- package/extensions/terminal-title.ts +191 -0
- package/extensions/tool-profile/index.ts +291 -0
- package/extensions/tool-profile/profiles.ts +290 -0
- package/extensions/types.d.ts +9 -0
- package/extensions/vault/index.ts +185 -0
- package/extensions/version-check.ts +90 -0
- package/extensions/view/index.ts +859 -0
- package/extensions/view/uri-resolver.ts +148 -0
- package/extensions/web-search/index.ts +182 -0
- package/extensions/web-search/providers.ts +121 -0
- package/extensions/web-ui/index.ts +110 -0
- package/extensions/web-ui/server.ts +265 -0
- package/extensions/web-ui/state.ts +462 -0
- package/extensions/web-ui/static/index.html +145 -0
- package/extensions/web-ui/types.ts +284 -0
- package/package.json +76 -0
- package/prompts/init.md +75 -0
- package/prompts/new-repo.md +54 -0
- package/prompts/oci-login.md +56 -0
- package/prompts/status.md +50 -0
- package/settings.json +4 -0
- package/skills/cleave/SKILL.md +218 -0
- package/skills/git/SKILL.md +209 -0
- package/skills/git/_reference/ci-validation.md +204 -0
- package/skills/oci/SKILL.md +338 -0
- package/skills/openspec/SKILL.md +346 -0
- package/skills/pi-extensions/SKILL.md +191 -0
- package/skills/pi-tui/SKILL.md +517 -0
- package/skills/python/SKILL.md +189 -0
- package/skills/rust/SKILL.md +268 -0
- package/skills/security/SKILL.md +206 -0
- package/skills/style/SKILL.md +264 -0
- package/skills/typescript/SKILL.md +225 -0
- package/skills/vault/SKILL.md +102 -0
- package/themes/alpharius-legacy.json +85 -0
- package/themes/alpharius.conf +59 -0
- package/themes/alpharius.json +88 -0
|
@@ -0,0 +1,487 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# chronos.sh - Comprehensive date and time context
|
|
3
|
+
# Outputs structured date context to eliminate AI date calculation errors
|
|
4
|
+
# Cross-platform: macOS (BSD date) and Linux (GNU date)
|
|
5
|
+
|
|
6
|
+
set -uo pipefail
|
|
7
|
+
|
|
8
|
+
# Detect date command flavor
|
|
9
|
+
if date --version >/dev/null 2>&1; then
|
|
10
|
+
DATE_FLAVOR="gnu"
|
|
11
|
+
else
|
|
12
|
+
DATE_FLAVOR="bsd"
|
|
13
|
+
fi
|
|
14
|
+
|
|
15
|
+
# Helper: add/subtract days from a date
|
|
16
|
+
# Usage: date_add "2026-01-25" -3 -> outputs date 3 days earlier
|
|
17
|
+
date_add() {
|
|
18
|
+
local base_date=$1
|
|
19
|
+
local days=$2
|
|
20
|
+
if [[ "$DATE_FLAVOR" == "gnu" ]]; then
|
|
21
|
+
date -d "$base_date $days days" "+%Y-%m-%d"
|
|
22
|
+
else
|
|
23
|
+
# BSD date: convert to epoch, add seconds, convert back
|
|
24
|
+
local epoch=$(date -j -f "%Y-%m-%d" "$base_date" "+%s" 2>/dev/null)
|
|
25
|
+
local new_epoch=$((epoch + days * 86400))
|
|
26
|
+
date -r "$new_epoch" "+%Y-%m-%d"
|
|
27
|
+
fi
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
# Helper: format date as "Mon D"
|
|
31
|
+
format_short() {
|
|
32
|
+
local ymd=$1
|
|
33
|
+
local month=$(echo "$ymd" | cut -d'-' -f2)
|
|
34
|
+
local day=$(echo "$ymd" | cut -d'-' -f3 | sed 's/^0//')
|
|
35
|
+
case $month in
|
|
36
|
+
01) mon="Jan" ;; 02) mon="Feb" ;; 03) mon="Mar" ;;
|
|
37
|
+
04) mon="Apr" ;; 05) mon="May" ;; 06) mon="Jun" ;;
|
|
38
|
+
07) mon="Jul" ;; 08) mon="Aug" ;; 09) mon="Sep" ;;
|
|
39
|
+
10) mon="Oct" ;; 11) mon="Nov" ;; 12) mon="Dec" ;;
|
|
40
|
+
esac
|
|
41
|
+
echo "$mon $day"
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
# Helper: get epoch from date string
|
|
45
|
+
date_to_epoch() {
|
|
46
|
+
local ymd=$1
|
|
47
|
+
if [[ "$DATE_FLAVOR" == "gnu" ]]; then
|
|
48
|
+
date -d "$ymd" "+%s"
|
|
49
|
+
else
|
|
50
|
+
date -j -f "%Y-%m-%d" "$ymd" "+%s" 2>/dev/null
|
|
51
|
+
fi
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
# Helper: resolve a relative date expression
|
|
55
|
+
resolve_relative() {
|
|
56
|
+
local expr=$1
|
|
57
|
+
if [[ "$DATE_FLAVOR" == "gnu" ]]; then
|
|
58
|
+
date -d "$expr" "+%Y-%m-%d" 2>/dev/null
|
|
59
|
+
else
|
|
60
|
+
# BSD: handle common expressions manually
|
|
61
|
+
case "$expr" in
|
|
62
|
+
*"days ago")
|
|
63
|
+
local n=$(echo "$expr" | grep -oE '[0-9]+')
|
|
64
|
+
date_add "$TODAY" "-$n"
|
|
65
|
+
;;
|
|
66
|
+
*"days from now"|*"days ahead")
|
|
67
|
+
local n=$(echo "$expr" | grep -oE '[0-9]+')
|
|
68
|
+
date_add "$TODAY" "$n"
|
|
69
|
+
;;
|
|
70
|
+
"yesterday")
|
|
71
|
+
date_add "$TODAY" "-1"
|
|
72
|
+
;;
|
|
73
|
+
"tomorrow")
|
|
74
|
+
date_add "$TODAY" "1"
|
|
75
|
+
;;
|
|
76
|
+
"next Monday"|"next monday")
|
|
77
|
+
local days_ahead=$(( (8 - DOW_NUM) % 7 ))
|
|
78
|
+
[[ $days_ahead -eq 0 ]] && days_ahead=7
|
|
79
|
+
date_add "$TODAY" "$days_ahead"
|
|
80
|
+
;;
|
|
81
|
+
"next Friday"|"next friday")
|
|
82
|
+
local target=5
|
|
83
|
+
local days_ahead=$(( (target - DOW_NUM + 7) % 7 ))
|
|
84
|
+
[[ $days_ahead -eq 0 ]] && days_ahead=7
|
|
85
|
+
date_add "$TODAY" "$days_ahead"
|
|
86
|
+
;;
|
|
87
|
+
"last Monday"|"last monday")
|
|
88
|
+
local days_back=$(( (DOW_NUM - 1 + 7) % 7 ))
|
|
89
|
+
[[ $days_back -eq 0 ]] && days_back=7
|
|
90
|
+
date_add "$TODAY" "-$days_back"
|
|
91
|
+
;;
|
|
92
|
+
"last Friday"|"last friday")
|
|
93
|
+
local target=5
|
|
94
|
+
local days_back=$(( (DOW_NUM - target + 7) % 7 ))
|
|
95
|
+
[[ $days_back -eq 0 ]] && days_back=7
|
|
96
|
+
date_add "$TODAY" "-$days_back"
|
|
97
|
+
;;
|
|
98
|
+
*"weeks ago")
|
|
99
|
+
local n=$(echo "$expr" | grep -oE '[0-9]+')
|
|
100
|
+
date_add "$TODAY" "-$((n * 7))"
|
|
101
|
+
;;
|
|
102
|
+
*"months ago")
|
|
103
|
+
local n=$(echo "$expr" | grep -oE '[0-9]+')
|
|
104
|
+
local y=$(echo "$TODAY" | cut -d'-' -f1)
|
|
105
|
+
local m=$(echo "$TODAY" | cut -d'-' -f2 | sed 's/^0//')
|
|
106
|
+
local d=$(echo "$TODAY" | cut -d'-' -f3)
|
|
107
|
+
m=$((m - n))
|
|
108
|
+
while [[ $m -le 0 ]]; do
|
|
109
|
+
m=$((m + 12))
|
|
110
|
+
y=$((y - 1))
|
|
111
|
+
done
|
|
112
|
+
printf "%04d-%02d-%s" "$y" "$m" "$d"
|
|
113
|
+
;;
|
|
114
|
+
*)
|
|
115
|
+
echo "ERROR: Cannot parse '$expr' on BSD date. Use GNU date for complex expressions." >&2
|
|
116
|
+
return 1
|
|
117
|
+
;;
|
|
118
|
+
esac
|
|
119
|
+
fi
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
# Get today's info
|
|
123
|
+
TODAY=$(date "+%Y-%m-%d")
|
|
124
|
+
TODAY_DOW=$(date "+%A")
|
|
125
|
+
DOW_NUM=$(date "+%u") # 1=Monday, 7=Sunday
|
|
126
|
+
|
|
127
|
+
# ---- Subcommand functions ----
|
|
128
|
+
|
|
129
|
+
compute_week() {
|
|
130
|
+
DAYS_SINCE_MON=$((DOW_NUM - 1))
|
|
131
|
+
CURR_MON=$(date_add "$TODAY" "-$DAYS_SINCE_MON")
|
|
132
|
+
CURR_FRI=$(date_add "$CURR_MON" "4")
|
|
133
|
+
|
|
134
|
+
PREV_MON=$(date_add "$CURR_MON" "-7")
|
|
135
|
+
PREV_FRI=$(date_add "$PREV_MON" "4")
|
|
136
|
+
|
|
137
|
+
# Extract years for range formatting
|
|
138
|
+
CURR_MON_YEAR=$(echo "$CURR_MON" | cut -d'-' -f1)
|
|
139
|
+
CURR_FRI_YEAR=$(echo "$CURR_FRI" | cut -d'-' -f1)
|
|
140
|
+
PREV_MON_YEAR=$(echo "$PREV_MON" | cut -d'-' -f1)
|
|
141
|
+
PREV_FRI_YEAR=$(echo "$PREV_FRI" | cut -d'-' -f1)
|
|
142
|
+
|
|
143
|
+
# Format short dates
|
|
144
|
+
CURR_MON_FMT=$(format_short "$CURR_MON")
|
|
145
|
+
CURR_FRI_FMT=$(format_short "$CURR_FRI")
|
|
146
|
+
PREV_MON_FMT=$(format_short "$PREV_MON")
|
|
147
|
+
PREV_FRI_FMT=$(format_short "$PREV_FRI")
|
|
148
|
+
|
|
149
|
+
# Build range strings (handle year boundaries)
|
|
150
|
+
if [ "$CURR_MON_YEAR" = "$CURR_FRI_YEAR" ]; then
|
|
151
|
+
CURR_WEEK_RANGE="$CURR_MON_FMT - $CURR_FRI_FMT, $CURR_FRI_YEAR"
|
|
152
|
+
else
|
|
153
|
+
CURR_WEEK_RANGE="$CURR_MON_FMT, $CURR_MON_YEAR - $CURR_FRI_FMT, $CURR_FRI_YEAR"
|
|
154
|
+
fi
|
|
155
|
+
|
|
156
|
+
if [ "$PREV_MON_YEAR" = "$PREV_FRI_YEAR" ]; then
|
|
157
|
+
PREV_WEEK_RANGE="$PREV_MON_FMT - $PREV_FRI_FMT, $PREV_FRI_YEAR"
|
|
158
|
+
else
|
|
159
|
+
PREV_WEEK_RANGE="$PREV_MON_FMT, $PREV_MON_YEAR - $PREV_FRI_FMT, $PREV_FRI_YEAR"
|
|
160
|
+
fi
|
|
161
|
+
|
|
162
|
+
echo "DATE_CONTEXT:"
|
|
163
|
+
echo " TODAY: $TODAY ($TODAY_DOW)"
|
|
164
|
+
echo " CURR_WEEK_START: $CURR_MON (Monday)"
|
|
165
|
+
echo " CURR_WEEK_END: $CURR_FRI (Friday)"
|
|
166
|
+
echo " CURR_WEEK_RANGE: $CURR_WEEK_RANGE"
|
|
167
|
+
echo " PREV_WEEK_START: $PREV_MON (Monday)"
|
|
168
|
+
echo " PREV_WEEK_END: $PREV_FRI (Friday)"
|
|
169
|
+
echo " PREV_WEEK_RANGE: $PREV_WEEK_RANGE"
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
compute_month() {
|
|
173
|
+
local year=$(echo "$TODAY" | cut -d'-' -f1)
|
|
174
|
+
local month=$(echo "$TODAY" | cut -d'-' -f2 | sed 's/^0//')
|
|
175
|
+
|
|
176
|
+
# Current month boundaries
|
|
177
|
+
local curr_month_start
|
|
178
|
+
curr_month_start=$(printf "%04d-%02d-01" "$year" "$month")
|
|
179
|
+
|
|
180
|
+
# Next month first day, then subtract 1 day for end of current month
|
|
181
|
+
local next_month=$((month + 1))
|
|
182
|
+
local next_year=$year
|
|
183
|
+
if [[ $next_month -gt 12 ]]; then
|
|
184
|
+
next_month=1
|
|
185
|
+
next_year=$((year + 1))
|
|
186
|
+
fi
|
|
187
|
+
local next_month_start
|
|
188
|
+
next_month_start=$(printf "%04d-%02d-01" "$next_year" "$next_month")
|
|
189
|
+
local curr_month_end
|
|
190
|
+
curr_month_end=$(date_add "$next_month_start" "-1")
|
|
191
|
+
|
|
192
|
+
# Previous month boundaries
|
|
193
|
+
local prev_month=$((month - 1))
|
|
194
|
+
local prev_year=$year
|
|
195
|
+
if [[ $prev_month -lt 1 ]]; then
|
|
196
|
+
prev_month=12
|
|
197
|
+
prev_year=$((year - 1))
|
|
198
|
+
fi
|
|
199
|
+
local prev_month_start
|
|
200
|
+
prev_month_start=$(printf "%04d-%02d-01" "$prev_year" "$prev_month")
|
|
201
|
+
local prev_month_end
|
|
202
|
+
prev_month_end=$(date_add "$curr_month_start" "-1")
|
|
203
|
+
|
|
204
|
+
local curr_month_fmt
|
|
205
|
+
curr_month_fmt=$(format_short "$curr_month_start")
|
|
206
|
+
local curr_month_end_fmt
|
|
207
|
+
curr_month_end_fmt=$(format_short "$curr_month_end")
|
|
208
|
+
local prev_month_fmt
|
|
209
|
+
prev_month_fmt=$(format_short "$prev_month_start")
|
|
210
|
+
local prev_month_end_fmt
|
|
211
|
+
prev_month_end_fmt=$(format_short "$prev_month_end")
|
|
212
|
+
|
|
213
|
+
echo "MONTH_CONTEXT:"
|
|
214
|
+
echo " TODAY: $TODAY ($TODAY_DOW)"
|
|
215
|
+
echo " CURR_MONTH_START: $curr_month_start"
|
|
216
|
+
echo " CURR_MONTH_END: $curr_month_end"
|
|
217
|
+
echo " CURR_MONTH_RANGE: $curr_month_fmt - $curr_month_end_fmt, $year"
|
|
218
|
+
echo " PREV_MONTH_START: $prev_month_start"
|
|
219
|
+
echo " PREV_MONTH_END: $prev_month_end"
|
|
220
|
+
echo " PREV_MONTH_RANGE: $prev_month_fmt, $prev_year - $prev_month_end_fmt, $year"
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
compute_quarter() {
|
|
224
|
+
local year=$(echo "$TODAY" | cut -d'-' -f1)
|
|
225
|
+
local month=$(echo "$TODAY" | cut -d'-' -f2 | sed 's/^0//')
|
|
226
|
+
|
|
227
|
+
# Calendar quarter (Q1=Jan-Mar, Q2=Apr-Jun, Q3=Jul-Sep, Q4=Oct-Dec)
|
|
228
|
+
local quarter=$(( (month - 1) / 3 + 1 ))
|
|
229
|
+
local q_start_month=$(( (quarter - 1) * 3 + 1 ))
|
|
230
|
+
local q_end_month=$(( quarter * 3 ))
|
|
231
|
+
local q_start
|
|
232
|
+
q_start=$(printf "%04d-%02d-01" "$year" "$q_start_month")
|
|
233
|
+
|
|
234
|
+
# Quarter end: first day of next quarter minus 1
|
|
235
|
+
local next_q_month=$(( q_end_month + 1 ))
|
|
236
|
+
local next_q_year=$year
|
|
237
|
+
if [[ $next_q_month -gt 12 ]]; then
|
|
238
|
+
next_q_month=1
|
|
239
|
+
next_q_year=$((year + 1))
|
|
240
|
+
fi
|
|
241
|
+
local next_q_start
|
|
242
|
+
next_q_start=$(printf "%04d-%02d-01" "$next_q_year" "$next_q_month")
|
|
243
|
+
local q_end
|
|
244
|
+
q_end=$(date_add "$next_q_start" "-1")
|
|
245
|
+
|
|
246
|
+
# Fiscal year (Oct-Sep): FY starts in October of previous calendar year
|
|
247
|
+
local fy_year
|
|
248
|
+
local fy_start fy_end
|
|
249
|
+
if [[ $month -ge 10 ]]; then
|
|
250
|
+
fy_year=$((year + 1))
|
|
251
|
+
fy_start="$year-10-01"
|
|
252
|
+
fy_end="$fy_year-09-30"
|
|
253
|
+
else
|
|
254
|
+
fy_year=$year
|
|
255
|
+
fy_start="$((year - 1))-10-01"
|
|
256
|
+
fy_end="$year-09-30"
|
|
257
|
+
fi
|
|
258
|
+
|
|
259
|
+
# Fiscal quarter
|
|
260
|
+
local fy_month_offset
|
|
261
|
+
if [[ $month -ge 10 ]]; then
|
|
262
|
+
fy_month_offset=$((month - 10 + 1))
|
|
263
|
+
else
|
|
264
|
+
fy_month_offset=$((month + 3))
|
|
265
|
+
fi
|
|
266
|
+
local fq=$(( (fy_month_offset - 1) / 3 + 1 ))
|
|
267
|
+
|
|
268
|
+
echo "QUARTER_CONTEXT:"
|
|
269
|
+
echo " TODAY: $TODAY ($TODAY_DOW)"
|
|
270
|
+
echo " CALENDAR_QUARTER: Q$quarter $year"
|
|
271
|
+
echo " QUARTER_START: $q_start"
|
|
272
|
+
echo " QUARTER_END: $q_end"
|
|
273
|
+
echo " FISCAL_YEAR: FY$fy_year (Oct-Sep)"
|
|
274
|
+
echo " FISCAL_QUARTER: FQ$fq"
|
|
275
|
+
echo " FY_START: $fy_start"
|
|
276
|
+
echo " FY_END: $fy_end"
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
compute_relative() {
|
|
280
|
+
local expr=$1
|
|
281
|
+
local resolved
|
|
282
|
+
resolved=$(resolve_relative "$expr")
|
|
283
|
+
if [[ $? -ne 0 || -z "$resolved" ]]; then
|
|
284
|
+
echo "RELATIVE_DATE:"
|
|
285
|
+
echo " ERROR: Could not resolve '$expr'"
|
|
286
|
+
return 1
|
|
287
|
+
fi
|
|
288
|
+
|
|
289
|
+
local resolved_dow
|
|
290
|
+
if [[ "$DATE_FLAVOR" == "gnu" ]]; then
|
|
291
|
+
resolved_dow=$(date -d "$resolved" "+%A")
|
|
292
|
+
else
|
|
293
|
+
local epoch=$(date_to_epoch "$resolved")
|
|
294
|
+
resolved_dow=$(date -r "$epoch" "+%A")
|
|
295
|
+
fi
|
|
296
|
+
|
|
297
|
+
echo "RELATIVE_DATE:"
|
|
298
|
+
echo " EXPRESSION: $expr"
|
|
299
|
+
echo " RESOLVED: $resolved ($resolved_dow)"
|
|
300
|
+
echo " TODAY: $TODAY ($TODAY_DOW)"
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
compute_iso() {
|
|
304
|
+
local iso_week iso_year day_of_year
|
|
305
|
+
if [[ "$DATE_FLAVOR" == "gnu" ]]; then
|
|
306
|
+
iso_week=$(date -d "$TODAY" "+%V")
|
|
307
|
+
iso_year=$(date -d "$TODAY" "+%G")
|
|
308
|
+
day_of_year=$(date -d "$TODAY" "+%j")
|
|
309
|
+
else
|
|
310
|
+
iso_week=$(date -j -f "%Y-%m-%d" "$TODAY" "+%V" 2>/dev/null)
|
|
311
|
+
iso_year=$(date -j -f "%Y-%m-%d" "$TODAY" "+%G" 2>/dev/null || echo "$TODAY" | cut -d'-' -f1)
|
|
312
|
+
day_of_year=$(date -j -f "%Y-%m-%d" "$TODAY" "+%j" 2>/dev/null)
|
|
313
|
+
fi
|
|
314
|
+
|
|
315
|
+
echo "ISO_CONTEXT:"
|
|
316
|
+
echo " TODAY: $TODAY ($TODAY_DOW)"
|
|
317
|
+
echo " ISO_WEEK: W$iso_week"
|
|
318
|
+
echo " ISO_YEAR: $iso_year"
|
|
319
|
+
echo " ISO_WEEKDATE: $iso_year-W$iso_week-$DOW_NUM"
|
|
320
|
+
echo " DAY_OF_YEAR: $day_of_year"
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
compute_epoch() {
|
|
324
|
+
local epoch
|
|
325
|
+
if [[ "$DATE_FLAVOR" == "gnu" ]]; then
|
|
326
|
+
epoch=$(date "+%s")
|
|
327
|
+
else
|
|
328
|
+
epoch=$(date "+%s")
|
|
329
|
+
fi
|
|
330
|
+
local millis="${epoch}000"
|
|
331
|
+
|
|
332
|
+
echo "EPOCH_CONTEXT:"
|
|
333
|
+
echo " TODAY: $TODAY ($TODAY_DOW)"
|
|
334
|
+
echo " UNIX_SECONDS: $epoch"
|
|
335
|
+
echo " UNIX_MILLIS: $millis"
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
compute_tz() {
|
|
339
|
+
local tz_abbrev tz_offset
|
|
340
|
+
tz_abbrev=$(date "+%Z")
|
|
341
|
+
tz_offset=$(date "+%z")
|
|
342
|
+
|
|
343
|
+
echo "TIMEZONE_CONTEXT:"
|
|
344
|
+
echo " TODAY: $TODAY ($TODAY_DOW)"
|
|
345
|
+
echo " TIMEZONE: $tz_abbrev"
|
|
346
|
+
echo " UTC_OFFSET: $tz_offset"
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
compute_range() {
|
|
350
|
+
local date1=$1
|
|
351
|
+
local date2=$2
|
|
352
|
+
|
|
353
|
+
# Validate date formats
|
|
354
|
+
if ! echo "$date1" | grep -qE '^[0-9]{4}-[0-9]{2}-[0-9]{2}$'; then
|
|
355
|
+
echo "RANGE_ERROR: Invalid date format '$date1'. Use YYYY-MM-DD." >&2
|
|
356
|
+
return 1
|
|
357
|
+
fi
|
|
358
|
+
if ! echo "$date2" | grep -qE '^[0-9]{4}-[0-9]{2}-[0-9]{2}$'; then
|
|
359
|
+
echo "RANGE_ERROR: Invalid date format '$date2'. Use YYYY-MM-DD." >&2
|
|
360
|
+
return 1
|
|
361
|
+
fi
|
|
362
|
+
|
|
363
|
+
local epoch1 epoch2
|
|
364
|
+
epoch1=$(date_to_epoch "$date1")
|
|
365
|
+
epoch2=$(date_to_epoch "$date2")
|
|
366
|
+
|
|
367
|
+
if [[ -z "$epoch1" || -z "$epoch2" ]]; then
|
|
368
|
+
echo "RANGE_ERROR: Could not parse dates." >&2
|
|
369
|
+
return 1
|
|
370
|
+
fi
|
|
371
|
+
|
|
372
|
+
local diff_seconds=$((epoch2 - epoch1))
|
|
373
|
+
local calendar_days=$((diff_seconds / 86400))
|
|
374
|
+
|
|
375
|
+
# Count business days (Mon-Fri)
|
|
376
|
+
local business_days=0
|
|
377
|
+
local current="$date1"
|
|
378
|
+
local step=1
|
|
379
|
+
if [[ $calendar_days -lt 0 ]]; then
|
|
380
|
+
step=-1
|
|
381
|
+
calendar_days=$(( -calendar_days ))
|
|
382
|
+
fi
|
|
383
|
+
|
|
384
|
+
local i=0
|
|
385
|
+
while [[ $i -lt $calendar_days ]]; do
|
|
386
|
+
local dow
|
|
387
|
+
if [[ "$DATE_FLAVOR" == "gnu" ]]; then
|
|
388
|
+
dow=$(date -d "$current" "+%u")
|
|
389
|
+
else
|
|
390
|
+
local e=$(date_to_epoch "$current")
|
|
391
|
+
dow=$(date -r "$e" "+%u")
|
|
392
|
+
fi
|
|
393
|
+
# Count if weekday (Mon=1 through Fri=5)
|
|
394
|
+
if [[ $dow -ge 1 && $dow -le 5 ]]; then
|
|
395
|
+
business_days=$((business_days + 1))
|
|
396
|
+
fi
|
|
397
|
+
current=$(date_add "$current" "$step")
|
|
398
|
+
i=$((i + 1))
|
|
399
|
+
done
|
|
400
|
+
|
|
401
|
+
echo "RANGE_CONTEXT:"
|
|
402
|
+
echo " FROM: $date1"
|
|
403
|
+
echo " TO: $date2"
|
|
404
|
+
echo " CALENDAR_DAYS: $calendar_days"
|
|
405
|
+
echo " BUSINESS_DAYS: $business_days"
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
usage() {
|
|
409
|
+
echo "Usage: chronos.sh [SUBCOMMAND] [ARGS]"
|
|
410
|
+
echo ""
|
|
411
|
+
echo "Subcommands:"
|
|
412
|
+
echo " (none), week Week boundaries (DATE_CONTEXT block)"
|
|
413
|
+
echo " month Current/previous month boundaries"
|
|
414
|
+
echo " quarter Calendar quarter, fiscal year (Oct-Sep)"
|
|
415
|
+
echo " relative \"expr\" Resolve relative date expression"
|
|
416
|
+
echo " iso ISO week number, year, day-of-year"
|
|
417
|
+
echo " epoch Unix timestamp (seconds and milliseconds)"
|
|
418
|
+
echo " tz Timezone abbreviation and UTC offset"
|
|
419
|
+
echo " range D1 D2 Calendar and business days between dates"
|
|
420
|
+
echo " all All of the above combined"
|
|
421
|
+
echo ""
|
|
422
|
+
echo "Examples:"
|
|
423
|
+
echo " chronos.sh # Week context (default)"
|
|
424
|
+
echo " chronos.sh month # Month boundaries"
|
|
425
|
+
echo " chronos.sh quarter # Quarter and fiscal year"
|
|
426
|
+
echo " chronos.sh relative \"3 days ago\" # Resolve expression"
|
|
427
|
+
echo " chronos.sh range 2026-01-01 2026-02-01"
|
|
428
|
+
echo " chronos.sh all # Everything"
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
# ---- Main dispatch ----
|
|
432
|
+
|
|
433
|
+
case "${1:-week}" in
|
|
434
|
+
-h|--help)
|
|
435
|
+
usage
|
|
436
|
+
;;
|
|
437
|
+
week|"")
|
|
438
|
+
compute_week
|
|
439
|
+
;;
|
|
440
|
+
month)
|
|
441
|
+
compute_month
|
|
442
|
+
;;
|
|
443
|
+
quarter)
|
|
444
|
+
compute_quarter
|
|
445
|
+
;;
|
|
446
|
+
relative)
|
|
447
|
+
if [[ -z "${2:-}" ]]; then
|
|
448
|
+
echo "Usage: chronos.sh relative \"expression\"" >&2
|
|
449
|
+
exit 1
|
|
450
|
+
fi
|
|
451
|
+
compute_relative "$2"
|
|
452
|
+
;;
|
|
453
|
+
iso)
|
|
454
|
+
compute_iso
|
|
455
|
+
;;
|
|
456
|
+
epoch)
|
|
457
|
+
compute_epoch
|
|
458
|
+
;;
|
|
459
|
+
tz)
|
|
460
|
+
compute_tz
|
|
461
|
+
;;
|
|
462
|
+
range)
|
|
463
|
+
if [[ -z "${2:-}" || -z "${3:-}" ]]; then
|
|
464
|
+
echo "Usage: chronos.sh range YYYY-MM-DD YYYY-MM-DD" >&2
|
|
465
|
+
exit 1
|
|
466
|
+
fi
|
|
467
|
+
compute_range "$2" "$3"
|
|
468
|
+
;;
|
|
469
|
+
all)
|
|
470
|
+
compute_week
|
|
471
|
+
echo ""
|
|
472
|
+
compute_month
|
|
473
|
+
echo ""
|
|
474
|
+
compute_quarter
|
|
475
|
+
echo ""
|
|
476
|
+
compute_iso
|
|
477
|
+
echo ""
|
|
478
|
+
compute_epoch
|
|
479
|
+
echo ""
|
|
480
|
+
compute_tz
|
|
481
|
+
;;
|
|
482
|
+
*)
|
|
483
|
+
echo "Unknown subcommand: $1" >&2
|
|
484
|
+
usage >&2
|
|
485
|
+
exit 1
|
|
486
|
+
;;
|
|
487
|
+
esac
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* chronos — Authoritative date and time context from system clock
|
|
3
|
+
*
|
|
4
|
+
* Registers a `chronos` tool that executes the chronos.sh script and returns
|
|
5
|
+
* structured date context. Eliminates AI date calculation errors by providing
|
|
6
|
+
* an authoritative source of truth from the system clock.
|
|
7
|
+
*
|
|
8
|
+
* Also registers a `/chronos` command for interactive use.
|
|
9
|
+
*
|
|
10
|
+
* Subcommands: week (default), month, quarter, relative, iso, epoch, tz, range, all
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { existsSync } from "node:fs";
|
|
14
|
+
import { join } from "node:path";
|
|
15
|
+
import { StringEnum } from "../lib/typebox-helpers";
|
|
16
|
+
import type { ExtensionAPI } from "@cwilson613/pi-coding-agent";
|
|
17
|
+
import { Type } from "@sinclair/typebox";
|
|
18
|
+
|
|
19
|
+
const CHRONOS_SH = join(import.meta.dirname ?? __dirname, "chronos.sh");
|
|
20
|
+
|
|
21
|
+
const SUBCOMMANDS = ["week", "month", "quarter", "relative", "iso", "epoch", "tz", "range", "all"] as const;
|
|
22
|
+
|
|
23
|
+
export default function chronosExtension(pi: ExtensionAPI) {
|
|
24
|
+
|
|
25
|
+
// Ensure the script exists and is executable
|
|
26
|
+
if (!existsSync(CHRONOS_SH)) {
|
|
27
|
+
// Fail silently at load — the tool will report the error at call time
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// ------------------------------------------------------------------
|
|
31
|
+
// chronos tool — callable by the LLM
|
|
32
|
+
// ------------------------------------------------------------------
|
|
33
|
+
pi.registerTool({
|
|
34
|
+
name: "chronos",
|
|
35
|
+
label: "Chronos",
|
|
36
|
+
description:
|
|
37
|
+
"Get authoritative date and time context from the system clock. " +
|
|
38
|
+
"Use before any date calculations, weekly/monthly reporting, relative date references, " +
|
|
39
|
+
"quarter boundaries, or epoch timestamps. Eliminates AI date calculation errors.\n\n" +
|
|
40
|
+
"Subcommands:\n" +
|
|
41
|
+
" week (default) — Current/previous week boundaries (Mon-Fri)\n" +
|
|
42
|
+
" month — Current/previous month boundaries\n" +
|
|
43
|
+
" quarter — Calendar quarter, fiscal year (Oct-Sep)\n" +
|
|
44
|
+
" relative — Resolve expression like '3 days ago', 'next Monday'\n" +
|
|
45
|
+
" iso — ISO 8601 week number, year, day-of-year\n" +
|
|
46
|
+
" epoch — Unix timestamp (seconds and milliseconds)\n" +
|
|
47
|
+
" tz — Timezone abbreviation and UTC offset\n" +
|
|
48
|
+
" range — Calendar and business days between two dates\n" +
|
|
49
|
+
" all — All of the above combined",
|
|
50
|
+
promptSnippet:
|
|
51
|
+
"Authoritative date/time from system clock — use before any date calculations, reporting, or relative date references",
|
|
52
|
+
promptGuidelines: [
|
|
53
|
+
"Call chronos before any date math, weekly/monthly reporting, relative dates, or quarter references — never calculate dates manually",
|
|
54
|
+
],
|
|
55
|
+
|
|
56
|
+
parameters: Type.Object({
|
|
57
|
+
subcommand: Type.Optional(
|
|
58
|
+
StringEnum(SUBCOMMANDS, { description: "Subcommand (default: week)" })
|
|
59
|
+
),
|
|
60
|
+
expression: Type.Optional(
|
|
61
|
+
Type.String({ description: "For 'relative': date expression (e.g. '3 days ago', 'next Monday')" })
|
|
62
|
+
),
|
|
63
|
+
from_date: Type.Optional(
|
|
64
|
+
Type.String({ description: "For 'range': start date YYYY-MM-DD" })
|
|
65
|
+
),
|
|
66
|
+
to_date: Type.Optional(
|
|
67
|
+
Type.String({ description: "For 'range': end date YYYY-MM-DD" })
|
|
68
|
+
),
|
|
69
|
+
}),
|
|
70
|
+
|
|
71
|
+
async execute(_toolCallId, params, signal, _onUpdate, _ctx) {
|
|
72
|
+
if (!existsSync(CHRONOS_SH)) {
|
|
73
|
+
throw new Error(
|
|
74
|
+
`chronos.sh not found at ${CHRONOS_SH}. ` +
|
|
75
|
+
`Expected alongside the chronos skill.`
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const sub = params.subcommand || "week";
|
|
80
|
+
const args = [CHRONOS_SH, sub];
|
|
81
|
+
|
|
82
|
+
if (sub === "relative") {
|
|
83
|
+
if (!params.expression) {
|
|
84
|
+
throw new Error("The 'relative' subcommand requires an 'expression' parameter (e.g. '3 days ago').");
|
|
85
|
+
}
|
|
86
|
+
args.push(params.expression);
|
|
87
|
+
} else if (sub === "range") {
|
|
88
|
+
if (!params.from_date || !params.to_date) {
|
|
89
|
+
throw new Error("The 'range' subcommand requires both 'from_date' and 'to_date' (YYYY-MM-DD).");
|
|
90
|
+
}
|
|
91
|
+
args.push(params.from_date, params.to_date);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const result = await pi.exec("bash", args, { signal, timeout: 10_000 });
|
|
95
|
+
|
|
96
|
+
if (result.code !== 0) {
|
|
97
|
+
throw new Error(`chronos.sh failed (exit ${result.code}):\n${result.stderr || result.stdout}`);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return {
|
|
101
|
+
content: [{ type: "text", text: result.stdout.trim() }],
|
|
102
|
+
details: { subcommand: sub },
|
|
103
|
+
};
|
|
104
|
+
},
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
// ------------------------------------------------------------------
|
|
108
|
+
// /chronos command — interactive shortcut
|
|
109
|
+
// ------------------------------------------------------------------
|
|
110
|
+
pi.registerCommand("chronos", {
|
|
111
|
+
description: "Show date/time context (usage: /chronos [week|month|quarter|iso|epoch|tz|all])",
|
|
112
|
+
getArgumentCompletions: (prefix: string) => {
|
|
113
|
+
const items = SUBCOMMANDS.map((s) => ({ value: s, label: s }));
|
|
114
|
+
const filtered = items.filter((i) => i.value.startsWith(prefix || ""));
|
|
115
|
+
return filtered.length > 0 ? filtered : null;
|
|
116
|
+
},
|
|
117
|
+
handler: async (args, _ctx) => {
|
|
118
|
+
const sub = (args || "").trim() || "week";
|
|
119
|
+
|
|
120
|
+
if (!existsSync(CHRONOS_SH)) {
|
|
121
|
+
pi.sendMessage({
|
|
122
|
+
customType: "view",
|
|
123
|
+
content: `❌ chronos.sh not found at \`${CHRONOS_SH}\``,
|
|
124
|
+
display: true,
|
|
125
|
+
});
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const cliArgs = [CHRONOS_SH, sub];
|
|
130
|
+
const result = await pi.exec("bash", cliArgs, { timeout: 10_000 });
|
|
131
|
+
|
|
132
|
+
if (result.code !== 0) {
|
|
133
|
+
pi.sendMessage({
|
|
134
|
+
customType: "view",
|
|
135
|
+
content: `❌ chronos.sh failed:\n\`\`\`\n${result.stderr || result.stdout}\n\`\`\``,
|
|
136
|
+
display: true,
|
|
137
|
+
});
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
pi.sendMessage({
|
|
142
|
+
customType: "view",
|
|
143
|
+
content: `**Chronos**\n\n\`\`\`\n${result.stdout.trim()}\n\`\`\``,
|
|
144
|
+
display: true,
|
|
145
|
+
});
|
|
146
|
+
},
|
|
147
|
+
});
|
|
148
|
+
}
|