@ainova-systems/intelligence 0.11.0-rc.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/LICENSE +21 -0
- package/README.md +46 -0
- package/bin/intelligence.js +59 -0
- package/cli/commands/add.sh +133 -0
- package/cli/commands/doctor.sh +100 -0
- package/cli/commands/init.sh +96 -0
- package/cli/commands/install.sh +84 -0
- package/cli/commands/list.sh +28 -0
- package/cli/commands/migrate.sh +251 -0
- package/cli/commands/registry.sh +51 -0
- package/cli/commands/remove.sh +39 -0
- package/cli/commands/status.sh +34 -0
- package/cli/commands/sync.sh +22 -0
- package/cli/commands/update.sh +59 -0
- package/cli/commands/upgrade.sh +27 -0
- package/cli/intelligence +71 -0
- package/cli/lib/cli-common.sh +149 -0
- package/cli/lib/lockfile.sh +97 -0
- package/cli/lib/manifest.sh +211 -0
- package/cli/lib/registry.sh +141 -0
- package/cli/lib/semver.sh +127 -0
- package/engine/INIT.md +498 -0
- package/engine/agents/intelligence-architect.md +53 -0
- package/engine/agents/intelligence-operator.md +49 -0
- package/engine/docs/ADAPTERS.md +212 -0
- package/engine/docs/CLI.md +91 -0
- package/engine/docs/CONVENTIONS.md +440 -0
- package/engine/rules/intelligence-authoring.md +114 -0
- package/engine/scripts/VERSION +1 -0
- package/engine/scripts/adapters/_template.sh +86 -0
- package/engine/scripts/adapters/agents.sh +299 -0
- package/engine/scripts/adapters/claude.sh +136 -0
- package/engine/scripts/adapters/codex.sh +118 -0
- package/engine/scripts/adapters/copilot.sh +193 -0
- package/engine/scripts/adapters/cursor.sh +146 -0
- package/engine/scripts/adapters/opencode.sh +200 -0
- package/engine/scripts/adapters/pi.sh +256 -0
- package/engine/scripts/lib/common.sh +1602 -0
- package/engine/scripts/lib/layout.sh +51 -0
- package/engine/scripts/lib/migrations.sh +708 -0
- package/engine/scripts/sync.sh +311 -0
- package/engine/scripts/update.sh +237 -0
- package/engine/skills/intelligence-add-agent/SKILL.md +62 -0
- package/engine/skills/intelligence-add-rule/SKILL.md +54 -0
- package/engine/skills/intelligence-add-skill/SKILL.md +53 -0
- package/engine/skills/intelligence-extract-skill/SKILL.md +47 -0
- package/engine/skills/intelligence-install-adapter/SKILL.md +31 -0
- package/engine/skills/intelligence-learn-from-context/SKILL.md +69 -0
- package/engine/skills/intelligence-review-skills/SKILL.md +86 -0
- package/engine/skills/intelligence-sync/SKILL.md +18 -0
- package/engine/skills/intelligence-uninstall-adapter/SKILL.md +42 -0
- package/engine/skills/intelligence-update/SKILL.md +159 -0
- package/package.json +39 -0
- package/registry/index.yaml +15 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025-2026 Ainova Systems (Dmitrij Zykovic)
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# @ainova-systems/intelligence
|
|
2
|
+
|
|
3
|
+
**npm for AI agent intelligence.** One CLI that builds, versions and distributes the rules, agents and skills your AI coding tools run on — rendered natively for Claude Code, Cursor, GitHub Copilot, OpenAI Codex, Pi, OpenCode and `AGENTS.md`.
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
npm install -g @ainova-systems/intelligence
|
|
7
|
+
|
|
8
|
+
cd your-project
|
|
9
|
+
intelligence init
|
|
10
|
+
intelligence add @ainova-systems/core
|
|
11
|
+
intelligence sync
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
That's the whole setup. Your project gets:
|
|
15
|
+
|
|
16
|
+
```
|
|
17
|
+
intelligence.yaml # manifest — what the project consumes, where it goes
|
|
18
|
+
intelligence.lock # resolved versions (commit it)
|
|
19
|
+
intelligence/ # your own rules / agents / skills
|
|
20
|
+
.intelligence/ # installed packages + engine content (gitignored)
|
|
21
|
+
.claude/ .cursor/ … # generated per-tool output
|
|
22
|
+
AGENTS.md
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Teammates need one command after cloning:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
intelligence install
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Commands
|
|
32
|
+
|
|
33
|
+
| Command | What it does |
|
|
34
|
+
|---|---|
|
|
35
|
+
| `intelligence init` | Detect your tools, write the manifest, first sync |
|
|
36
|
+
| `intelligence add <pkg>` | `@scope/name[@range]`, `github:org/repo[#path]`, or `git+<url>[@ref][#path]` |
|
|
37
|
+
| `intelligence install [--frozen]` | Restore `.intelligence/` exactly from the lockfile |
|
|
38
|
+
| `intelligence update [pkg]` | Re-resolve version ranges, rewrite the lock |
|
|
39
|
+
| `intelligence sync [target]` | Render intelligence to every enabled tool |
|
|
40
|
+
| `intelligence list` / `doctor` / `status` | Inspect and verify |
|
|
41
|
+
| `intelligence registry add @scope <url>` | Bind a scope to a private registry index |
|
|
42
|
+
| `intelligence migrate` | Convert a vendored intelligence-sync setup to the CLI |
|
|
43
|
+
|
|
44
|
+
Any git repo with `rules/`, `agents/` or `skills/` at its root is already an Intelligence Package: `intelligence add @your-org/your-repo` resolves it straight from GitHub — versions come from its `x.y.z` git tags. A monorepo of packages needs one line in a registry index.
|
|
45
|
+
|
|
46
|
+
Requires `git` (and on Windows the bash it ships with — Git for Windows). Engine and docs: [ainova-systems/intelligence-sync](https://github.com/ainova-systems/intelligence-sync).
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
// Thin launcher for the intelligence CLI. All logic lives in bash (cli/ and
|
|
4
|
+
// engine/ inside this package); this shim only finds a usable bash and execs
|
|
5
|
+
// the dispatcher with stdio passed through. It never rewrites paths — Git
|
|
6
|
+
// Bash accepts forward-slash Windows paths, and the engine re-normalizes.
|
|
7
|
+
|
|
8
|
+
const { spawnSync, execSync } = require('child_process');
|
|
9
|
+
const path = require('path');
|
|
10
|
+
const fs = require('fs');
|
|
11
|
+
|
|
12
|
+
function isWslStub(p) {
|
|
13
|
+
// System32\bash.exe is the WSL launcher: a Linux userland that cannot see
|
|
14
|
+
// this package's files the way Git Bash can. Never pick it.
|
|
15
|
+
return /system32[\\/]+bash\.exe$/i.test(p);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function findBash() {
|
|
19
|
+
const override = process.env.INTELLIGENCE_BASH;
|
|
20
|
+
if (override && fs.existsSync(override)) return override;
|
|
21
|
+
if (process.platform !== 'win32') return 'bash';
|
|
22
|
+
|
|
23
|
+
const candidates = [];
|
|
24
|
+
try {
|
|
25
|
+
const git = execSync('where git', { encoding: 'utf8' }).split(/\r?\n/)[0].trim();
|
|
26
|
+
if (git) {
|
|
27
|
+
// <git-root>\cmd\git.exe (or \bin\git.exe) → <git-root>\bin\bash.exe
|
|
28
|
+
candidates.push(path.join(path.dirname(git), '..', 'bin', 'bash.exe'));
|
|
29
|
+
candidates.push(path.join(path.dirname(git), '..', 'usr', 'bin', 'bash.exe'));
|
|
30
|
+
}
|
|
31
|
+
} catch (_) { /* git not on PATH — fall through to the fixed locations */ }
|
|
32
|
+
candidates.push(
|
|
33
|
+
'C:\\Program Files\\Git\\bin\\bash.exe',
|
|
34
|
+
'C:\\Program Files (x86)\\Git\\bin\\bash.exe'
|
|
35
|
+
);
|
|
36
|
+
for (const c of candidates) {
|
|
37
|
+
if (!isWslStub(c) && fs.existsSync(c)) return c;
|
|
38
|
+
}
|
|
39
|
+
try {
|
|
40
|
+
const found = execSync('where bash', { encoding: 'utf8' })
|
|
41
|
+
.split(/\r?\n/).map((s) => s.trim()).filter((s) => s && !isWslStub(s));
|
|
42
|
+
if (found.length > 0) return found[0];
|
|
43
|
+
} catch (_) { /* no bash anywhere */ }
|
|
44
|
+
console.error('intelligence: bash not found. Install Git for Windows (https://git-scm.com) — its bash is all this CLI needs.');
|
|
45
|
+
process.exit(1);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const cli = path.join(__dirname, '..', 'cli', 'intelligence').replace(/\\/g, '/');
|
|
49
|
+
const pkg = require(path.join(__dirname, '..', 'package.json'));
|
|
50
|
+
|
|
51
|
+
const result = spawnSync(findBash(), [cli].concat(process.argv.slice(2)), {
|
|
52
|
+
stdio: 'inherit',
|
|
53
|
+
env: Object.assign({}, process.env, { INTELLIGENCE_NPM_VERSION: pkg.version }),
|
|
54
|
+
});
|
|
55
|
+
if (result.error) {
|
|
56
|
+
console.error('intelligence: failed to launch bash: ' + result.error.message);
|
|
57
|
+
process.exit(1);
|
|
58
|
+
}
|
|
59
|
+
process.exit(result.status === null ? 1 : result.status);
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# intelligence add <spec> [--name @scope/name] [--no-sync]
|
|
3
|
+
#
|
|
4
|
+
# Specs:
|
|
5
|
+
# @scope/name[@range] resolved via registries / index / convention
|
|
6
|
+
# github:org/repo[#path] direct from GitHub, no registry involved
|
|
7
|
+
# git+<url>[@ref][#path] direct from any git host
|
|
8
|
+
set -euo pipefail
|
|
9
|
+
source "$CLI_DIR/lib/cli-common.sh"
|
|
10
|
+
|
|
11
|
+
spec="${1:-}"
|
|
12
|
+
[ -n "$spec" ] || die "usage: intelligence add <@scope/name[@range] | github:org/repo[#path] | git+<url>[@ref][#path]>"
|
|
13
|
+
shift || true
|
|
14
|
+
|
|
15
|
+
no_sync=0
|
|
16
|
+
name_override=""
|
|
17
|
+
while [ $# -gt 0 ]; do
|
|
18
|
+
case "$1" in
|
|
19
|
+
--no-sync) no_sync=1 ;;
|
|
20
|
+
--name) shift; name_override="${1:-}" ;;
|
|
21
|
+
*) die "unknown option '$1'" ;;
|
|
22
|
+
esac
|
|
23
|
+
shift || true
|
|
24
|
+
done
|
|
25
|
+
|
|
26
|
+
require_v2
|
|
27
|
+
manifest="$IP_ROOT/intelligence.yaml"
|
|
28
|
+
lock="$IP_ROOT/intelligence.lock"
|
|
29
|
+
|
|
30
|
+
name="" range="" url="" path="" ref="" mode=""
|
|
31
|
+
case "$spec" in
|
|
32
|
+
github:*)
|
|
33
|
+
mode="direct"
|
|
34
|
+
rest="${spec#github:}"
|
|
35
|
+
case "$rest" in *#*) path="${rest#*#}"; rest="${rest%%#*}" ;; esac
|
|
36
|
+
org="${rest%%/*}"; repo="${rest#*/}"
|
|
37
|
+
{ [ -n "$org" ] && [ -n "$repo" ] && [ "$repo" != "$rest" ]; } || die "bad spec '$spec' — expected github:org/repo[#path]"
|
|
38
|
+
name="@$org/$repo"
|
|
39
|
+
url="https://github.com/$org/$repo.git"
|
|
40
|
+
;;
|
|
41
|
+
git+*)
|
|
42
|
+
mode="direct"
|
|
43
|
+
rest="${spec#git+}"
|
|
44
|
+
case "$rest" in *#*) path="${rest#*#}"; rest="${rest%%#*}" ;; esac
|
|
45
|
+
# ref = the part after the last `@` in the post-scheme URL, unless it
|
|
46
|
+
# contains `/` (then it is a user@host, not a ref) — the engine's own
|
|
47
|
+
# git+ grammar.
|
|
48
|
+
base="${rest#*://}"
|
|
49
|
+
case "$base" in
|
|
50
|
+
*@*)
|
|
51
|
+
tail="${base##*@}"
|
|
52
|
+
case "$tail" in
|
|
53
|
+
*/*) ;;
|
|
54
|
+
*) ref="$tail"; rest="${rest%@"$tail"}" ;;
|
|
55
|
+
esac
|
|
56
|
+
;;
|
|
57
|
+
esac
|
|
58
|
+
url="$rest"
|
|
59
|
+
repo="$(basename "${url%.git}")"
|
|
60
|
+
org="$(basename "$(dirname "${url%.git}")")"
|
|
61
|
+
name="@${org:-direct}/$repo"
|
|
62
|
+
;;
|
|
63
|
+
@*)
|
|
64
|
+
mode="registry"
|
|
65
|
+
body="${spec#@}"
|
|
66
|
+
case "$body" in
|
|
67
|
+
*@*) range="${body##*@}"; body="${body%@"$range"}" ;;
|
|
68
|
+
esac
|
|
69
|
+
name="@$body"
|
|
70
|
+
;;
|
|
71
|
+
*)
|
|
72
|
+
die "unrecognized spec '$spec' — expected @scope/name, github:…, or git+…"
|
|
73
|
+
;;
|
|
74
|
+
esac
|
|
75
|
+
[ -n "$name_override" ] && name="$name_override"
|
|
76
|
+
assert_valid_pkg_name "$name"
|
|
77
|
+
|
|
78
|
+
if [ "$mode" = "registry" ]; then
|
|
79
|
+
resolve_package_source "$manifest" "$name"
|
|
80
|
+
url="$RES_URL"; path="$RES_PATH"
|
|
81
|
+
echo " resolving $name via $RES_VIA -> $url${path:+ ($path)}"
|
|
82
|
+
fi
|
|
83
|
+
|
|
84
|
+
# Pick the version: an explicit ref pins; otherwise the highest stable tag
|
|
85
|
+
# matching the range (npm's behaviour, `^highest` becoming the requested range
|
|
86
|
+
# when none was given).
|
|
87
|
+
resolved_tag="" requested="$range"
|
|
88
|
+
if [ -z "$ref" ]; then
|
|
89
|
+
picked="$(list_remote_versions "$url" | semver_pick_highest "$range")"
|
|
90
|
+
if [ -n "$picked" ]; then
|
|
91
|
+
read -r resolved_tag _ <<< "$(remote_tag_for_version "$url" "$picked")"
|
|
92
|
+
[ -n "$requested" ] || requested="^$picked"
|
|
93
|
+
else
|
|
94
|
+
if [ -n "$range" ]; then
|
|
95
|
+
die "no tag of $url satisfies '$range' (stable x.y.z tags only)"
|
|
96
|
+
fi
|
|
97
|
+
if [ "$mode" = "registry" ]; then
|
|
98
|
+
die "'$name' has no stable version tags at $url — a registry package must be versioned; use github:/git+ with @<ref> to pin a branch or commit"
|
|
99
|
+
fi
|
|
100
|
+
echo " NOTE: no version tags at $url — pinning the default branch head" >&2
|
|
101
|
+
fi
|
|
102
|
+
fi
|
|
103
|
+
|
|
104
|
+
rel=".intelligence/packages/$name"
|
|
105
|
+
sha="$(fetch_package "$url" "${ref:-$resolved_tag}" "$path" "$IP_ROOT/$rel")"
|
|
106
|
+
|
|
107
|
+
wire_package_sources "$manifest" "$name" "$rel" "$IP_ROOT"
|
|
108
|
+
|
|
109
|
+
# Manifest entry: a registry package records its range; a direct one records
|
|
110
|
+
# its source so resolution never has to guess it again.
|
|
111
|
+
if [ "$mode" = "registry" ]; then
|
|
112
|
+
qmap_set "$manifest" "packages" "$name" "version" "$requested"
|
|
113
|
+
else
|
|
114
|
+
qmap_set "$manifest" "packages" "$name" "url" "$url"
|
|
115
|
+
[ -n "$path" ] && qmap_set "$manifest" "packages" "$name" "path" "$path"
|
|
116
|
+
if [ -n "$ref" ]; then
|
|
117
|
+
qmap_set "$manifest" "packages" "$name" "ref" "$ref"
|
|
118
|
+
elif [ -n "$requested" ]; then
|
|
119
|
+
qmap_set "$manifest" "packages" "$name" "version" "$requested"
|
|
120
|
+
fi
|
|
121
|
+
fi
|
|
122
|
+
|
|
123
|
+
lock_upsert "$lock" "$name" "$requested" "$url" "$path" "${ref:-$resolved_tag}" "$sha"
|
|
124
|
+
|
|
125
|
+
sections=""
|
|
126
|
+
for s in rules agents skills; do
|
|
127
|
+
[ -d "$IP_ROOT/$rel/$s" ] && sections="$sections $s"
|
|
128
|
+
done
|
|
129
|
+
echo "+ $name@${resolved_tag:-${ref:-HEAD}} (${sections# })"
|
|
130
|
+
|
|
131
|
+
if [ "$no_sync" -eq 0 ]; then
|
|
132
|
+
exec bash "$CLI_DIR/commands/sync.sh"
|
|
133
|
+
fi
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# intelligence doctor — consistency checks, no writes. Exit 1 on problems.
|
|
3
|
+
set -euo pipefail
|
|
4
|
+
source "$CLI_DIR/lib/cli-common.sh"
|
|
5
|
+
|
|
6
|
+
problems=0
|
|
7
|
+
warn() { echo " ✗ $*"; problems=$((problems + 1)); }
|
|
8
|
+
ok() { echo " ✓ $*"; }
|
|
9
|
+
|
|
10
|
+
echo "environment:"
|
|
11
|
+
command -v git >/dev/null 2>&1 && ok "git $(git --version | awk '{print $3}')" || warn "git not found"
|
|
12
|
+
command -v awk >/dev/null 2>&1 && ok "awk present" || warn "awk not found"
|
|
13
|
+
ok "bash $BASH_VERSION"
|
|
14
|
+
ok "engine $(bundled_engine_version) at $IS_ENGINE_DIR"
|
|
15
|
+
|
|
16
|
+
detect_project
|
|
17
|
+
case "$IP_MODE" in
|
|
18
|
+
none)
|
|
19
|
+
echo "project: none here — 'intelligence init' starts one"
|
|
20
|
+
exit 0
|
|
21
|
+
;;
|
|
22
|
+
legacy)
|
|
23
|
+
echo "project: vendored (v1) at $IP_ROOT"
|
|
24
|
+
ok "vendored engine $(tr -d ' \t\r\n' < "$IP_MODULE_DIR/scripts/VERSION")"
|
|
25
|
+
echo " → 'intelligence migrate' converts it to the CLI setup"
|
|
26
|
+
exit 0
|
|
27
|
+
;;
|
|
28
|
+
esac
|
|
29
|
+
|
|
30
|
+
echo "project: $IP_ROOT"
|
|
31
|
+
manifest="$IP_ROOT/intelligence.yaml"
|
|
32
|
+
lock="$IP_ROOT/intelligence.lock"
|
|
33
|
+
|
|
34
|
+
stamp="$(read_engine_stamp "$manifest")"
|
|
35
|
+
eng="$(bundled_engine_version)"
|
|
36
|
+
if [ -z "$stamp" ]; then
|
|
37
|
+
warn "manifest has no sync_version — run 'intelligence upgrade'"
|
|
38
|
+
elif _ver_gt "$stamp" "$eng"; then
|
|
39
|
+
warn "manifest schema $stamp is newer than this CLI's engine $eng — update the CLI: npm i -g @ainova-systems/intelligence@latest"
|
|
40
|
+
elif _ver_gt "$eng" "$stamp"; then
|
|
41
|
+
warn "manifest schema $stamp behind engine $eng — run 'intelligence upgrade'"
|
|
42
|
+
else
|
|
43
|
+
ok "sync_version $stamp matches the engine"
|
|
44
|
+
fi
|
|
45
|
+
|
|
46
|
+
if [ -f "$IP_ROOT/.intelligence/engine/.version" ]; then
|
|
47
|
+
staged="$(tr -d ' \t\r\n' < "$IP_ROOT/.intelligence/engine/.version")"
|
|
48
|
+
[ "$staged" = "$eng" ] && ok "engine content staged ($staged)" || warn "staged engine content is $staged, bundled is $eng — run 'intelligence install'"
|
|
49
|
+
else
|
|
50
|
+
warn "engine content not staged — run 'intelligence install'"
|
|
51
|
+
fi
|
|
52
|
+
|
|
53
|
+
# Manifest packages: names valid, locked, installed.
|
|
54
|
+
while IFS= read -r name; do
|
|
55
|
+
[ -n "$name" ] || continue
|
|
56
|
+
assert_valid_pkg_name "$name"
|
|
57
|
+
if [ -z "$(qmap_field "$lock" "packages" "$name" "url")" ]; then
|
|
58
|
+
warn "$name is in the manifest but not in intelligence.lock — run 'intelligence install'"
|
|
59
|
+
elif [ ! -d "$IP_ROOT/.intelligence/packages/$name" ]; then
|
|
60
|
+
warn "$name is locked but not installed — run 'intelligence install'"
|
|
61
|
+
else
|
|
62
|
+
ok "$name @ $(qmap_field "$lock" "packages" "$name" "resolved")"
|
|
63
|
+
fi
|
|
64
|
+
done < <(qmap_keys "$manifest" "packages")
|
|
65
|
+
|
|
66
|
+
# Lock orphans.
|
|
67
|
+
if [ -f "$lock" ]; then
|
|
68
|
+
while IFS= read -r name; do
|
|
69
|
+
[ -n "$name" ] || continue
|
|
70
|
+
found=0
|
|
71
|
+
while IFS= read -r m; do
|
|
72
|
+
[ "$m" = "$name" ] && found=1
|
|
73
|
+
done < <(qmap_keys "$manifest" "packages")
|
|
74
|
+
[ "$found" -eq 1 ] || warn "$name is locked but absent from the manifest — 'intelligence remove $name' cleans it up"
|
|
75
|
+
done < <(qmap_keys "$lock" "packages")
|
|
76
|
+
fi
|
|
77
|
+
|
|
78
|
+
# Sources must exist (a missing dir is silently skipped by the engine, which
|
|
79
|
+
# is exactly why doctor names it).
|
|
80
|
+
for section in rules agents skills; do
|
|
81
|
+
while IFS= read -r src; do
|
|
82
|
+
[ -n "$src" ] || continue
|
|
83
|
+
case "$src" in
|
|
84
|
+
git+*|@*) continue ;;
|
|
85
|
+
esac
|
|
86
|
+
if [ ! -d "$IP_ROOT/$src" ]; then
|
|
87
|
+
case "$src" in
|
|
88
|
+
.intelligence/*) warn "sources.$section '$src' missing — run 'intelligence install'" ;;
|
|
89
|
+
*) warn "sources.$section '$src' does not exist" ;;
|
|
90
|
+
esac
|
|
91
|
+
fi
|
|
92
|
+
done < <(read_yaml_list "$manifest" "$section")
|
|
93
|
+
done
|
|
94
|
+
|
|
95
|
+
if [ "$problems" -eq 0 ]; then
|
|
96
|
+
echo "all good."
|
|
97
|
+
else
|
|
98
|
+
echo "$problems problem(s)."
|
|
99
|
+
exit 1
|
|
100
|
+
fi
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# intelligence init [--targets a,b,c] [--no-sync]
|
|
3
|
+
#
|
|
4
|
+
# Set up a project: root manifest, content skeleton, .gitignore, staged
|
|
5
|
+
# engine content, first sync. Targets are detected from IDE markers unless
|
|
6
|
+
# named explicitly; `agents` and `claude` are always on (AGENTS.md is the
|
|
7
|
+
# canonical carrier of always-on rules, Claude Code does not read it).
|
|
8
|
+
set -euo pipefail
|
|
9
|
+
source "$CLI_DIR/lib/cli-common.sh"
|
|
10
|
+
|
|
11
|
+
targets_arg="" no_sync=0
|
|
12
|
+
while [ $# -gt 0 ]; do
|
|
13
|
+
case "$1" in
|
|
14
|
+
--targets) shift; targets_arg="${1:-}" ;;
|
|
15
|
+
--no-sync) no_sync=1 ;;
|
|
16
|
+
*) die "unknown option '$1'" ;;
|
|
17
|
+
esac
|
|
18
|
+
shift || true
|
|
19
|
+
done
|
|
20
|
+
|
|
21
|
+
detect_project
|
|
22
|
+
case "$IP_MODE" in
|
|
23
|
+
v2) die "already set up — manifest at $IP_ROOT/intelligence.yaml (use 'intelligence status')" ;;
|
|
24
|
+
legacy) die "this is a vendored (v1) setup at $IP_UMBRELLA — run 'intelligence migrate' instead" ;;
|
|
25
|
+
esac
|
|
26
|
+
|
|
27
|
+
root="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
|
|
28
|
+
root="$(cd "$root" && pwd)"
|
|
29
|
+
|
|
30
|
+
targets="agents claude"
|
|
31
|
+
if [ -n "$targets_arg" ]; then
|
|
32
|
+
targets="agents $(printf '%s' "$targets_arg" | tr ',' ' ')"
|
|
33
|
+
else
|
|
34
|
+
[ -d "$root/.cursor" ] && targets="$targets cursor"
|
|
35
|
+
[ -d "$root/.codex" ] && targets="$targets codex"
|
|
36
|
+
[ -d "$root/.pi" ] && targets="$targets pi"
|
|
37
|
+
[ -d "$root/.opencode" ] && targets="$targets opencode"
|
|
38
|
+
[ -d "$root/.github" ] && [ -d "$root/.github/instructions" ] && targets="$targets copilot"
|
|
39
|
+
fi
|
|
40
|
+
|
|
41
|
+
manifest="$root/intelligence.yaml"
|
|
42
|
+
{
|
|
43
|
+
echo "# Intelligence manifest — what this project's AI tooling knows and where it goes."
|
|
44
|
+
echo "# Managed by the intelligence CLI (https://github.com/ainova-systems/intelligence-sync)."
|
|
45
|
+
echo "project:"
|
|
46
|
+
echo " name: \"$(basename "$root")\""
|
|
47
|
+
echo ""
|
|
48
|
+
echo "sync_version: \"$(bundled_engine_version)\""
|
|
49
|
+
echo ""
|
|
50
|
+
echo "sources:"
|
|
51
|
+
echo " rules:"
|
|
52
|
+
echo " - \"intelligence/rules\""
|
|
53
|
+
echo " - \".intelligence/engine/rules\""
|
|
54
|
+
echo " agents:"
|
|
55
|
+
echo " - \"intelligence/agents\""
|
|
56
|
+
echo " - \".intelligence/engine/agents\""
|
|
57
|
+
echo " skills:"
|
|
58
|
+
echo " - \"intelligence/skills\""
|
|
59
|
+
echo " - \".intelligence/engine/skills\""
|
|
60
|
+
echo ""
|
|
61
|
+
echo "targets:"
|
|
62
|
+
for t in $targets; do
|
|
63
|
+
case "$t" in
|
|
64
|
+
agents) echo " agents: { enabled: true, output: \"AGENTS.md\" }" ;;
|
|
65
|
+
*) echo " $t: { enabled: true, output: \".$t\" }" ;;
|
|
66
|
+
esac
|
|
67
|
+
done
|
|
68
|
+
} > "$manifest"
|
|
69
|
+
|
|
70
|
+
mkdir -p "$root/intelligence/rules" "$root/intelligence/agents" "$root/intelligence/skills"
|
|
71
|
+
if [ ! -f "$root/intelligence/rules/context.md" ]; then
|
|
72
|
+
cat > "$root/intelligence/rules/context.md" <<EOF
|
|
73
|
+
# Project Context
|
|
74
|
+
|
|
75
|
+
<!-- Always-on context every AI tool receives. Describe what this project is,
|
|
76
|
+
its stack, and the constraints an agent must respect. -->
|
|
77
|
+
EOF
|
|
78
|
+
fi
|
|
79
|
+
|
|
80
|
+
# The package store is restorable state, never committed — the npm model.
|
|
81
|
+
if [ ! -f "$root/.gitignore" ] || ! grep -q '^\.intelligence/' "$root/.gitignore"; then
|
|
82
|
+
{
|
|
83
|
+
[ -f "$root/.gitignore" ] && [ -n "$(tail -c 1 "$root/.gitignore" 2>/dev/null)" ] && echo ""
|
|
84
|
+
echo "# intelligence CLI package store (restored by 'intelligence install')"
|
|
85
|
+
echo ".intelligence/"
|
|
86
|
+
} >> "$root/.gitignore"
|
|
87
|
+
fi
|
|
88
|
+
|
|
89
|
+
ensure_engine_staged "$root"
|
|
90
|
+
echo "initialized: intelligence.yaml (targets:$(printf ' %s' $targets))"
|
|
91
|
+
echo "next: add intelligence packages — e.g. 'intelligence add @ainova-systems/core'"
|
|
92
|
+
|
|
93
|
+
if [ "$no_sync" -eq 0 ]; then
|
|
94
|
+
cd "$root"
|
|
95
|
+
exec bash "$CLI_DIR/commands/sync.sh"
|
|
96
|
+
fi
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# intelligence install [--frozen] [--force] [--no-sync]
|
|
3
|
+
#
|
|
4
|
+
# Restore .intelligence/ from intelligence.lock — the fresh-clone command.
|
|
5
|
+
# --frozen additionally refuses any manifest/lock divergence (CI mode) and
|
|
6
|
+
# fails on a sha mismatch instead of re-resolving.
|
|
7
|
+
set -euo pipefail
|
|
8
|
+
source "$CLI_DIR/lib/cli-common.sh"
|
|
9
|
+
|
|
10
|
+
frozen=0 force=0 no_sync=0
|
|
11
|
+
while [ $# -gt 0 ]; do
|
|
12
|
+
case "$1" in
|
|
13
|
+
--frozen) frozen=1 ;;
|
|
14
|
+
--force) force=1 ;;
|
|
15
|
+
--no-sync) no_sync=1 ;;
|
|
16
|
+
*) die "unknown option '$1'" ;;
|
|
17
|
+
esac
|
|
18
|
+
shift || true
|
|
19
|
+
done
|
|
20
|
+
|
|
21
|
+
require_v2
|
|
22
|
+
manifest="$IP_ROOT/intelligence.yaml"
|
|
23
|
+
lock="$IP_ROOT/intelligence.lock"
|
|
24
|
+
|
|
25
|
+
ensure_engine_staged "$IP_ROOT"
|
|
26
|
+
|
|
27
|
+
# Manifest packages missing from the lock: resolve them now (npm install
|
|
28
|
+
# semantics). Under --frozen that is an error instead.
|
|
29
|
+
missing=""
|
|
30
|
+
while IFS= read -r name; do
|
|
31
|
+
[ -n "$name" ] || continue
|
|
32
|
+
if [ ! -f "$lock" ] || [ -z "$(qmap_field "$lock" "packages" "$name" "url")" ]; then
|
|
33
|
+
missing="$missing $name"
|
|
34
|
+
fi
|
|
35
|
+
done < <(qmap_keys "$manifest" "packages")
|
|
36
|
+
if [ -n "$missing" ]; then
|
|
37
|
+
[ "$frozen" -eq 1 ] && die "lockfile is missing packages:$missing — run 'intelligence install' without --frozen"
|
|
38
|
+
for name in $missing; do
|
|
39
|
+
url="$(qmap_field "$manifest" "packages" "$name" "url")"
|
|
40
|
+
path="$(qmap_field "$manifest" "packages" "$name" "path")"
|
|
41
|
+
ref="$(qmap_field "$manifest" "packages" "$name" "ref")"
|
|
42
|
+
range="$(qmap_field "$manifest" "packages" "$name" "version")"
|
|
43
|
+
if [ -z "$url" ]; then
|
|
44
|
+
resolve_package_source "$manifest" "$name"
|
|
45
|
+
url="$RES_URL"; path="$RES_PATH"
|
|
46
|
+
fi
|
|
47
|
+
resolved_tag=""
|
|
48
|
+
if [ -z "$ref" ]; then
|
|
49
|
+
picked="$(list_remote_versions "$url" | semver_pick_highest "$range")"
|
|
50
|
+
[ -n "$picked" ] || die "no tag of $url satisfies '${range:-*}' for $name"
|
|
51
|
+
read -r resolved_tag _ <<< "$(remote_tag_for_version "$url" "$picked")"
|
|
52
|
+
fi
|
|
53
|
+
rel=".intelligence/packages/$name"
|
|
54
|
+
sha="$(fetch_package "$url" "${ref:-$resolved_tag}" "$path" "$IP_ROOT/$rel")"
|
|
55
|
+
wire_package_sources "$manifest" "$name" "$rel" "$IP_ROOT"
|
|
56
|
+
lock_upsert "$lock" "$name" "$range" "$url" "$path" "${ref:-$resolved_tag}" "$sha"
|
|
57
|
+
echo "+ $name@${resolved_tag:-${ref:-HEAD}} (resolved)"
|
|
58
|
+
done
|
|
59
|
+
fi
|
|
60
|
+
|
|
61
|
+
# Restore every locked package that is not already in the store.
|
|
62
|
+
if [ -f "$lock" ]; then
|
|
63
|
+
while IFS="$LOCK_SEP" read -r name requested url path resolved sha; do
|
|
64
|
+
[ -n "$name" ] || continue
|
|
65
|
+
rel=".intelligence/packages/$name"
|
|
66
|
+
if [ -d "$IP_ROOT/$rel" ] && [ "$force" -eq 0 ]; then
|
|
67
|
+
continue
|
|
68
|
+
fi
|
|
69
|
+
got="$(fetch_package "$url" "$resolved" "$path" "$IP_ROOT/$rel")"
|
|
70
|
+
if [ -n "$sha" ] && [ "$got" != "$sha" ]; then
|
|
71
|
+
if [ "$frozen" -eq 1 ]; then
|
|
72
|
+
die "$name: fetched $got but the lock pins $sha — the ref moved; refusing under --frozen"
|
|
73
|
+
fi
|
|
74
|
+
echo " WARN: $name resolved to $got, lock had $sha — updating the lock" >&2
|
|
75
|
+
lock_upsert "$lock" "$name" "$requested" "$url" "$path" "$resolved" "$got"
|
|
76
|
+
fi
|
|
77
|
+
wire_package_sources "$manifest" "$name" "$rel" "$IP_ROOT"
|
|
78
|
+
echo "= $name@${resolved:-HEAD}"
|
|
79
|
+
done < <(lock_to_tsv "$lock")
|
|
80
|
+
fi
|
|
81
|
+
|
|
82
|
+
if [ "$no_sync" -eq 0 ]; then
|
|
83
|
+
exec bash "$CLI_DIR/commands/sync.sh"
|
|
84
|
+
fi
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# intelligence list — packages with requested / locked / installed state.
|
|
3
|
+
set -euo pipefail
|
|
4
|
+
source "$CLI_DIR/lib/cli-common.sh"
|
|
5
|
+
|
|
6
|
+
require_v2
|
|
7
|
+
manifest="$IP_ROOT/intelligence.yaml"
|
|
8
|
+
lock="$IP_ROOT/intelligence.lock"
|
|
9
|
+
|
|
10
|
+
count=0
|
|
11
|
+
while IFS= read -r name; do
|
|
12
|
+
[ -n "$name" ] || continue
|
|
13
|
+
count=$((count + 1))
|
|
14
|
+
range="$(qmap_field "$manifest" "packages" "$name" "version")"
|
|
15
|
+
ref="$(qmap_field "$manifest" "packages" "$name" "ref")"
|
|
16
|
+
resolved="$(qmap_field "$lock" "packages" "$name" "resolved")"
|
|
17
|
+
state="missing — run 'intelligence install'"
|
|
18
|
+
[ -d "$IP_ROOT/.intelligence/packages/$name" ] && state="installed"
|
|
19
|
+
printf '%s %s locked:%s %s\n' \
|
|
20
|
+
"$name" \
|
|
21
|
+
"${ref:+ref:$ref}${ref:-${range:-*}}" \
|
|
22
|
+
"${resolved:-<none>}" \
|
|
23
|
+
"$state"
|
|
24
|
+
done < <(qmap_keys "$manifest" "packages")
|
|
25
|
+
|
|
26
|
+
if [ "$count" -eq 0 ]; then
|
|
27
|
+
echo "No packages. Add one: intelligence add @ainova-systems/core"
|
|
28
|
+
fi
|