@ainova-systems/intelligence 0.25.0 → 0.25.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/engine/ENGINE_SHA +1 -1
- package/engine/VERSION +1 -1
- package/engine/lib/common.sh +99 -53
- package/package.json +1 -1
package/engine/ENGINE_SHA
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
6dcb00c874ff7a12df5b838d3391f2dd96b06df0
|
package/engine/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.25.
|
|
1
|
+
0.25.1
|
package/engine/lib/common.sh
CHANGED
|
@@ -18,19 +18,34 @@ normalize_file_to_lf() {
|
|
|
18
18
|
#
|
|
19
19
|
# The content directory is named by the project (`intelligence/`,
|
|
20
20
|
# `Intelligence/`, a codename), so package-shipped artifacts cannot hardcode
|
|
21
|
-
# it. Layout-sensitive paths and commands use tokens expanded at output time
|
|
21
|
+
# it. Layout-sensitive paths and commands use tokens expanded at output time,
|
|
22
|
+
# in EVERY generated file, frontmatter and body alike, so a scoped rule reaches
|
|
23
|
+
# Claude's `paths:`, Cursor's `globs:` and Copilot's `applyTo:` already
|
|
24
|
+
# carrying the project's real folder name.
|
|
22
25
|
#
|
|
23
|
-
#
|
|
24
|
-
#
|
|
25
|
-
#
|
|
26
|
-
#
|
|
27
|
-
#
|
|
28
|
-
#
|
|
29
|
-
#
|
|
30
|
-
#
|
|
31
|
-
#
|
|
32
|
-
#
|
|
33
|
-
#
|
|
26
|
+
# IS_LAYOUT_TOKENS is the one declaration of them, a `<name> <variable>
|
|
27
|
+
# <default>` row per token: `<name>` renders as the value of <variable>, which
|
|
28
|
+
# the CLI derives from the detected layout (never hardcoded) and exports
|
|
29
|
+
# before any adapter runs, or as <default>, the rest of the row, while that
|
|
30
|
+
# variable is unset or empty. Expansion (fin_line), the backslash that keeps a
|
|
31
|
+
# token as written (fin_keep, token_keep_var) and the source lint that warns
|
|
32
|
+
# about a token reading as ordinary text (_IS_AWK_LINT) all derive from these
|
|
33
|
+
# rows, so a new token is one row here plus its entry in the reference tables
|
|
34
|
+
# (packages/sync/references/conventions.md and adapters.md). A name is
|
|
35
|
+
# lowercase letters, digits and `-`: it is spliced into awk text and a Bash
|
|
36
|
+
# pattern.
|
|
37
|
+
IS_LAYOUT_TOKENS=(
|
|
38
|
+
'content-dir IS_CONTENT_REL intelligence'
|
|
39
|
+
'module IS_MODULE_REL .intelligence/packages/@ainova-systems/sync'
|
|
40
|
+
'manifest IS_MANIFEST_NAME intelligence.yaml'
|
|
41
|
+
'sync-cmd IS_SYNC_CMD intelligence sync'
|
|
42
|
+
)
|
|
43
|
+
IS_LAYOUT_NAMES=()
|
|
44
|
+
_is_names=""
|
|
45
|
+
for _is_row in "${IS_LAYOUT_TOKENS[@]}"; do
|
|
46
|
+
IS_LAYOUT_NAMES+=("${_is_row%% *}")
|
|
47
|
+
_is_names="$_is_names${_is_names:+ }${_is_row%% *}"
|
|
48
|
+
done
|
|
34
49
|
|
|
35
50
|
# Process spawns dominate sync time on Git Bash for Windows: one fork costs
|
|
36
51
|
# tens of milliseconds against ~1ms on Linux, so a helper that runs awk per
|
|
@@ -42,8 +57,10 @@ normalize_file_to_lf() {
|
|
|
42
57
|
#
|
|
43
58
|
# fin_line() uses literal (index-based) substitution, not gsub: a regex
|
|
44
59
|
# replacement would give `&` in a path its special meaning, and POSIX awk has
|
|
45
|
-
# no way to pass a replacement string verbatim.
|
|
46
|
-
#
|
|
60
|
+
# no way to pass a replacement string verbatim. The token names are part of
|
|
61
|
+
# the program text, so fin_keep works in every program that includes this
|
|
62
|
+
# library; the values are read in BEGIN from the environment variables that
|
|
63
|
+
# is_fin_awk_vars fills and names in IS_FIN_V.
|
|
47
64
|
IS_AWK_LIB='
|
|
48
65
|
function is_repl(s, from, to, out, i) {
|
|
49
66
|
out = ""
|
|
@@ -53,23 +70,35 @@ IS_AWK_LIB='
|
|
|
53
70
|
}
|
|
54
71
|
return out s
|
|
55
72
|
}
|
|
73
|
+
# FIN_TOK[k] is the k-th token of IS_LAYOUT_TOKENS, FIN_VAL[k] its value,
|
|
74
|
+
# FIN_ESC[k] the token escaped and FIN_HOLD[k] what fin_keep turns that into.
|
|
75
|
+
BEGIN {
|
|
76
|
+
FIN_N = split("'"$_is_names"'", is_tn, " ")
|
|
77
|
+
for (is_tk = 1; is_tk <= FIN_N; is_tk++) {
|
|
78
|
+
FIN_TOK[is_tk] = "<" is_tn[is_tk] ">"
|
|
79
|
+
FIN_ESC[is_tk] = "\\" FIN_TOK[is_tk]
|
|
80
|
+
FIN_HOLD[is_tk] = "\034" is_tn[is_tk] ">"
|
|
81
|
+
if (FIN_ENV != "") FIN_VAL[is_tk] = ENVIRON[FIN_ENV is_tk]
|
|
82
|
+
}
|
|
83
|
+
}
|
|
56
84
|
# A backslash keeps a token as written: `\<module>` renders as `<module>`.
|
|
57
85
|
# The escaped token waits on a control character while the others expand.
|
|
58
86
|
# A writer that doubles backslashes for YAML or TOML calls fin_keep (or
|
|
59
87
|
# token_keep_var) first: once escaped, `\\<module>` no longer reads as one.
|
|
60
|
-
function fin_keep(s) {
|
|
88
|
+
function fin_keep(s, k) {
|
|
61
89
|
if (!index(s, "\\<")) return s
|
|
62
|
-
s = is_repl(s,
|
|
63
|
-
|
|
64
|
-
s = is_repl(s, "\\<module>", "\034module>")
|
|
65
|
-
return is_repl(s, "\\<content-dir>", "\034content-dir>")
|
|
90
|
+
for (k = 1; k <= FIN_N; k++) s = is_repl(s, FIN_ESC[k], FIN_HOLD[k])
|
|
91
|
+
return s
|
|
66
92
|
}
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
93
|
+
# Every line of every rendered file passes here, and most hold no `<`, so
|
|
94
|
+
# those skip the token loop. Tokens expand from the last declared to the
|
|
95
|
+
# first, the order the engine has always used: a value that itself holds a
|
|
96
|
+
# token renders as it always did.
|
|
97
|
+
function fin_line(s, k) {
|
|
98
|
+
if (index(s, "<")) {
|
|
99
|
+
s = fin_keep(s)
|
|
100
|
+
for (k = FIN_N; k > 0; k--) s = is_repl(s, FIN_TOK[k], FIN_VAL[k])
|
|
101
|
+
}
|
|
73
102
|
if (index(s, "\034")) s = is_repl(s, "\034", "<")
|
|
74
103
|
return s
|
|
75
104
|
}
|
|
@@ -128,17 +157,28 @@ IS_AWK_LIB='
|
|
|
128
157
|
return 1
|
|
129
158
|
}
|
|
130
159
|
'
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
#
|
|
134
|
-
#
|
|
160
|
+
unset _is_row _is_names
|
|
161
|
+
|
|
162
|
+
# is_fin_awk_vars — export each token's value as IS_LAYOUT_VALUE_<k>, <k> its
|
|
163
|
+
# row in IS_LAYOUT_TOKENS, and set the global IS_FIN_V to the -v binding that
|
|
164
|
+
# points IS_AWK_LIB at those variables; a program run without IS_FIN_V
|
|
165
|
+
# expands every token to nothing, as it always did. The values travel through
|
|
166
|
+
# the environment, which awk reads verbatim: a -v value has its backslashes
|
|
167
|
+
# read as escapes, and BSD awk refuses one that holds a newline. One variable
|
|
168
|
+
# per token, so no byte a value holds can split it into two. Rebuilt on every
|
|
169
|
+
# call: the IS_* env contract is exported after this file is sourced, and a
|
|
170
|
+
# caller may set one variable for a single call.
|
|
135
171
|
is_fin_awk_vars() {
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
172
|
+
local row rest var def k=0
|
|
173
|
+
for row in "${IS_LAYOUT_TOKENS[@]}"; do
|
|
174
|
+
rest="${row#* }"
|
|
175
|
+
var="${rest%% *}"
|
|
176
|
+
def=""
|
|
177
|
+
case "$rest" in *' '*) def="${rest#* }" ;; esac
|
|
178
|
+
k=$((k + 1))
|
|
179
|
+
export "IS_LAYOUT_VALUE_$k=${!var:-$def}"
|
|
180
|
+
done
|
|
181
|
+
IS_FIN_V=(-v FIN_ENV=IS_LAYOUT_VALUE_)
|
|
142
182
|
}
|
|
143
183
|
|
|
144
184
|
# finalize_output_files <file>...
|
|
@@ -311,7 +351,7 @@ token_keep_var() {
|
|
|
311
351
|
local s="$1" fs=$'\034' t
|
|
312
352
|
case "$s" in
|
|
313
353
|
*'\<'*)
|
|
314
|
-
for t in
|
|
354
|
+
for t in "${IS_LAYOUT_NAMES[@]}"; do
|
|
315
355
|
s="${s//\\<$t>/$fs$t>}"
|
|
316
356
|
done
|
|
317
357
|
;;
|
|
@@ -1107,6 +1147,9 @@ enforce_authored_invocation_policies() {
|
|
|
1107
1147
|
# warning names the source exactly once however many tools render it. Unlike
|
|
1108
1148
|
# the lint notes it is an unindented `WARNING:` line, because `sync --compact`
|
|
1109
1149
|
# (and so `init`) keeps only those (decision 0015).
|
|
1150
|
+
# This form takes no repository root, so its warnings name each file as the
|
|
1151
|
+
# caller passed it; the engine's pass, source_frontmatter_scan, names it
|
|
1152
|
+
# relative to the root.
|
|
1110
1153
|
# Usage: lint_frontmatter_files "a.md" "b.md" ...
|
|
1111
1154
|
lint_frontmatter_files() {
|
|
1112
1155
|
[ "$#" -gt 0 ] || return 0
|
|
@@ -1115,7 +1158,10 @@ lint_frontmatter_files() {
|
|
|
1115
1158
|
|
|
1116
1159
|
# The lint rules, shared with source_frontmatter_scan, which runs them in the
|
|
1117
1160
|
# same pass that reads routing fields. Every rule may end with `next`, so a
|
|
1118
|
-
# program that joins them puts its own rules first.
|
|
1161
|
+
# program that joins them puts its own rules first. Every warning names the
|
|
1162
|
+
# source as lint_src: relative to ENVIRON["IS_LINT_ROOT"] when the file lies
|
|
1163
|
+
# under it, so a warning reads the same from any checkout, from the private
|
|
1164
|
+
# copy `sync --check` renders in, and in the replay of an unchanged sync.
|
|
1119
1165
|
_IS_AWK_LINT='
|
|
1120
1166
|
BEGIN {
|
|
1121
1167
|
nl = split(levels, LV, " ")
|
|
@@ -1124,19 +1170,17 @@ _IS_AWK_LINT='
|
|
|
1124
1170
|
LEVEL[LV[li]] = 1
|
|
1125
1171
|
allowed = allowed (li > 1 ? ", " : "") LV[li]
|
|
1126
1172
|
}
|
|
1127
|
-
|
|
1128
|
-
split("<content-dir> <module> <manifest> <sync-cmd>", TOK, " ")
|
|
1129
|
-
TOKV[1] = FIN_CONTENT; TOKV[2] = FIN_MOD; TOKV[3] = FIN_MF; TOKV[4] = FIN_SC
|
|
1173
|
+
lint_root = ENVIRON["IS_LINT_ROOT"]
|
|
1130
1174
|
}
|
|
1131
1175
|
# A layout token that cannot mean what it renders as: joined to a word
|
|
1132
1176
|
# or a path around it, or an XML element closed on the same line. A
|
|
1133
1177
|
# module-name placeholder `<module>_update_N` rendered as the package
|
|
1134
1178
|
# path. Packages use tokens by design, so only project sources (under
|
|
1135
1179
|
# the root, outside its package store) are read, and an escaped token
|
|
1136
|
-
# (`\<module>`) is literal.
|
|
1180
|
+
# (`\<module>`) is literal. The tokens are FIN_TOK from IS_AWK_LIB.
|
|
1137
1181
|
function tok_check(l, k, t, n, at, p, b, a) {
|
|
1138
|
-
for (k = 1; k <=
|
|
1139
|
-
t =
|
|
1182
|
+
for (k = 1; k <= FIN_N; k++) {
|
|
1183
|
+
t = FIN_TOK[k]; n = length(t); at = 0
|
|
1140
1184
|
while ((p = index(substr(l, at + 1), t)) > 0) {
|
|
1141
1185
|
at += p
|
|
1142
1186
|
b = (at > 1) ? substr(l, at - 1, 1) : ""
|
|
@@ -1146,7 +1190,7 @@ _IS_AWK_LINT='
|
|
|
1146
1190
|
if (b ~ /[[:alnum:]_]/ || b == "/" || a ~ /^([[:alnum:]_-]|[.][[:alnum:]_])/ \
|
|
1147
1191
|
|| index(l, "</" substr(t, 2))) {
|
|
1148
1192
|
printf "WARNING: %s:%d %s is part of the text around it, but sync renders this layout token as %s; write \\%s to keep it as written\n", \
|
|
1149
|
-
|
|
1193
|
+
lint_src, FNR, t, FIN_VAL[k], t > "/dev/stderr"
|
|
1150
1194
|
break
|
|
1151
1195
|
}
|
|
1152
1196
|
}
|
|
@@ -1154,8 +1198,9 @@ _IS_AWK_LINT='
|
|
|
1154
1198
|
}
|
|
1155
1199
|
FNR == 1 {
|
|
1156
1200
|
in_fm = 0; done = 0; effort_seen = 0
|
|
1157
|
-
|
|
1158
|
-
|
|
1201
|
+
lint_under = lint_root != "" && index(FILENAME, lint_root "/") == 1
|
|
1202
|
+
lint_src = lint_under ? substr(FILENAME, length(lint_root) + 2) : FILENAME
|
|
1203
|
+
tok_own = lint_under && index(FILENAME, lint_root "/.intelligence/") != 1
|
|
1159
1204
|
}
|
|
1160
1205
|
{ sub(/\r$/, "") }
|
|
1161
1206
|
tok_own && index($0, ">") { tok_check($0) }
|
|
@@ -1166,11 +1211,11 @@ _IS_AWK_LINT='
|
|
|
1166
1211
|
in_fm && substr($0, 1, 7) == "effort:" && !effort_seen++ {
|
|
1167
1212
|
effort = fm_value_strip(substr($0, 8))
|
|
1168
1213
|
if (effort != "" && !(effort in LEVEL)) {
|
|
1169
|
-
printf "WARNING: %s:%d effort \"%s\" is not one of %s — ignored, so no tool receives an effort from this file\n",
|
|
1214
|
+
printf "WARNING: %s:%d effort \"%s\" is not one of %s — ignored, so no tool receives an effort from this file\n", lint_src, FNR, effort, allowed > "/dev/stderr"
|
|
1170
1215
|
}
|
|
1171
1216
|
}
|
|
1172
1217
|
in_fm && /^\t/ {
|
|
1173
|
-
printf "WARNING: %s:%d leading tab in frontmatter (use spaces)\n",
|
|
1218
|
+
printf "WARNING: %s:%d leading tab in frontmatter (use spaces)\n", lint_src, FNR > "/dev/stderr"
|
|
1174
1219
|
}
|
|
1175
1220
|
in_fm && /^[a-zA-Z0-9_-]+:[[:space:]]+[^"\047|>[{]/ {
|
|
1176
1221
|
value_start = index($0, ":") + 1
|
|
@@ -1178,10 +1223,10 @@ _IS_AWK_LINT='
|
|
|
1178
1223
|
sub(/^[[:space:]]+/, "", value)
|
|
1179
1224
|
if (value ~ /:[[:space:]]/ || value ~ /:$/) {
|
|
1180
1225
|
col = index(value, ":") + value_start
|
|
1181
|
-
printf "WARNING: %s:%d unquoted colon in value at column %d — wrap value in quotes\n",
|
|
1226
|
+
printf "WARNING: %s:%d unquoted colon in value at column %d — wrap value in quotes\n", lint_src, FNR, col > "/dev/stderr"
|
|
1182
1227
|
}
|
|
1183
1228
|
if (value ~ /"/) {
|
|
1184
|
-
printf "WARNING: %s:%d literal double quote in unquoted value — wrap value in single quotes or escape as \\\" so strict-YAML targets accept it\n",
|
|
1229
|
+
printf "WARNING: %s:%d literal double quote in unquoted value — wrap value in single quotes or escape as \\\" so strict-YAML targets accept it\n", lint_src, FNR > "/dev/stderr"
|
|
1185
1230
|
}
|
|
1186
1231
|
}
|
|
1187
1232
|
# Field-length limits. Both Claude Code and the Agent Skills standard
|
|
@@ -1200,7 +1245,7 @@ _IS_AWK_LINT='
|
|
|
1200
1245
|
}
|
|
1201
1246
|
limit = (key == "name") ? 64 : 1024
|
|
1202
1247
|
if (length(val) > limit) {
|
|
1203
|
-
printf "WARNING: %s:%d %s is %d chars — over the %d-char limit; the skill/agent will be REJECTED at load time\n",
|
|
1248
|
+
printf "WARNING: %s:%d %s is %d chars — over the %d-char limit; the skill/agent will be REJECTED at load time\n", lint_src, FNR, key, length(val), limit > "/dev/stderr"
|
|
1204
1249
|
}
|
|
1205
1250
|
}
|
|
1206
1251
|
'
|
|
@@ -2542,13 +2587,14 @@ source_catalog_build() {
|
|
|
2542
2587
|
# occurrence of a key wins, and a key with no value at all is not set
|
|
2543
2588
|
# (`targets: []` is: it is the empty list). With <lint-root>, the repository
|
|
2544
2589
|
# root, the same pass runs lint_frontmatter_files over every file and the
|
|
2545
|
-
# layout-token check over the project's own; warnings go to stderr
|
|
2590
|
+
# layout-token check over the project's own; warnings go to stderr and name
|
|
2591
|
+
# each source relative to that root.
|
|
2546
2592
|
source_frontmatter_scan() {
|
|
2547
2593
|
local do_lint=0 root="$1"
|
|
2548
2594
|
[ -z "$root" ] || do_lint=1
|
|
2549
2595
|
shift
|
|
2550
2596
|
is_fin_awk_vars
|
|
2551
|
-
|
|
2597
|
+
IS_LINT_ROOT="$root" awk -v levels="$IS_EFFORT_LEVELS" -v do_lint="$do_lint" "${IS_FIN_V[@]}" "$IS_AWK_LIB"'
|
|
2552
2598
|
BEGIN { SX_US = sprintf("%c", 31) }
|
|
2553
2599
|
function sx_items(s, k, parts, m, j, v, q) {
|
|
2554
2600
|
m = split(s, parts, ",")
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ainova-systems/intelligence",
|
|
3
|
-
"version": "0.25.
|
|
3
|
+
"version": "0.25.1",
|
|
4
4
|
"description": "Build, version and distribute AI agent intelligence across your organization — one CLI, versioned Intelligence Packages, and a sync engine for Claude Code, Cursor, Copilot, Codex, Pi and OpenCode.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"intelligence": "bin/intelligence.js"
|