@automaton-labs/aib 0.0.3 → 0.0.4

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.
Files changed (45) hide show
  1. package/dist/bin/cli.js +2 -2
  2. package/dist/commands/config-command.js +1 -3
  3. package/dist/commands/config-output.js +8 -0
  4. package/dist/commands/init-workspace.js +1 -3
  5. package/dist/commands/inspect-tree.js +3 -3
  6. package/dist/commands/reveal-command.js +5 -0
  7. package/dist/commands/sync-command.js +2 -2
  8. package/dist/config/local-config.js +3 -3
  9. package/dist/config/resolve-command-alias.js +1 -1
  10. package/dist/config/tsconfig-discovery.js +1 -0
  11. package/dist/config/workspace-root.js +3 -3
  12. package/dist/config/workspace-state.js +1 -1
  13. package/dist/dsl/aib-dsl.js +1 -1
  14. package/dist/help/bootstrap.md +21 -11
  15. package/dist/help/docs/first-setup.md +277 -0
  16. package/dist/help/docs/inspect.tree.md +8 -6
  17. package/dist/help/docs/patterns.md +12 -3
  18. package/dist/help/dsl/bootstrap.md +21 -11
  19. package/dist/help/dsl/docs/first-setup.md +277 -0
  20. package/dist/help/dsl/docs/inspect.tree.md +8 -6
  21. package/dist/help/dsl/docs/patterns.md +12 -3
  22. package/dist/help/dsl/full.md +21 -11
  23. package/dist/help/dsl/topics/first-setup.md +275 -0
  24. package/dist/help/dsl/topics/inspect.tree.md +8 -6
  25. package/dist/help/dsl/topics/patterns.md +12 -3
  26. package/dist/help/full.md +21 -11
  27. package/dist/help/help-meta.json +11 -7
  28. package/dist/help/index.md +6 -0
  29. package/dist/help/json/bootstrap.md +21 -11
  30. package/dist/help/json/docs/first-setup.md +277 -0
  31. package/dist/help/json/docs/inspect.tree.md +8 -6
  32. package/dist/help/json/docs/patterns.md +12 -3
  33. package/dist/help/json/full.md +21 -11
  34. package/dist/help/json/topics/first-setup.md +275 -0
  35. package/dist/help/json/topics/inspect.tree.md +8 -6
  36. package/dist/help/json/topics/patterns.md +12 -3
  37. package/dist/help/topics/first-setup.md +275 -0
  38. package/dist/help/topics/inspect.tree.md +8 -6
  39. package/dist/help/topics/patterns.md +12 -3
  40. package/dist/runtime/run-command.js +1 -1
  41. package/extension/vscode-refactor-bridge-extension.vsix +0 -0
  42. package/package.json +1 -1
  43. package/runtimes/launcher/win-x64/aib.exe +0 -0
  44. package/scripts/install-windows-launcher.cjs +1 -0
  45. package/scripts/provision-runtime.cjs +99 -41
@@ -152,10 +152,19 @@ shortestAlias rewrite to the shortest valid alias specifier
152
152
  preferAlias:
153
153
  @shared/* prefer one alias pattern when several aliases can resolve the same file
154
154
 
155
- inspect.graph.exclude skips files before graph builds the model.
156
- Use it for generated files, backups, local copies, or other paths that make graph output noisy.
155
+ AIB has four config exclude fields:
156
+ inspect.graph.exclude
157
+ inspect.tree.files.exclude
158
+ inspect.tree.onlyDirs.exclude
159
+ sync.tsconfig.exclude
157
160
 
158
- Excluded files do not affect graph counts, hubs, entrypoints, leaves, edges, imports, importedBy, or saved graph files.
161
+ For all of them, node_modules, .git, dist, build, out, and .tmp are skipped by default.
162
+
163
+ Use config excludes for generated files, backups, local copies, nested workspaces, seed projects, or other repository-specific noise.
164
+
165
+ Graph excludes affect graph counts, hubs, entrypoints, leaves, edges, imports, importedBy, and saved graph files.
166
+ Tree excludes affect directory/file discovery output.
167
+ Tsconfig excludes affect which TypeScript configs AIB syncs and watches.
159
168
 
160
169
  Leave feedback while working.
161
170
 
@@ -0,0 +1,275 @@
1
+ Use this when the user asks you to set up AIB for a repository.
2
+
3
+ If you have not loaded the current bootstrap, run:
4
+ aib help bootstrap
5
+
6
+ 1. Detect existing setup
7
+
8
+ Run:
9
+
10
+ aib config
11
+
12
+ If AIB reports that no config exists, continue to initialization.
13
+
14
+ If config exists:
15
+ - verify that root is the intended repository root;
16
+ - keep existing settings if they are still valid and useful;
17
+ - only add missing project-specific aliases, rules, or excludes;
18
+ - do not regenerate aib.json.
19
+
20
+ If config resolves from a parent directory, verify that this is intentional.
21
+ Do not continue setup inside a nested worktree or copied project if AIB is using the parent repository config.
22
+
23
+ 2. Initialize if missing
24
+
25
+ From the repository root, run:
26
+
27
+ aib init --session-dir .tmp/aib
28
+
29
+ Use the output to check:
30
+ - root is the intended repository root;
31
+ - config is <root>/aib.json;
32
+ - sessionDir is set;
33
+ - cleanup/deletion/runtime TTLs are shown;
34
+ - not set includes the setup sections that still need decisions.
35
+
36
+ Do not create sessions yet.
37
+
38
+ 3. Configure repository-specific behavior
39
+
40
+ Edit aib.json directly.
41
+
42
+ Keep existing settings if they are still valid and useful.
43
+ Update settings that are stale, noisy, too broad, or no longer match the repository.
44
+
45
+ Use not set as the checklist for the setup sections below.
46
+
47
+ 4. Configure path aliases
48
+
49
+ Run:
50
+
51
+ aib reveal tsaliases
52
+
53
+ Use this to see existing tsconfig paths and baseUrl values.
54
+ They can reveal stable work areas, but they are not a list to copy.
55
+
56
+ Add pathAliases for long paths that are likely to appear repeatedly in AIB requests.
57
+ Prefer aliases for real work areas, package roots, or deep directories.
58
+
59
+ A good alias:
60
+ - saves meaningful path tokens;
61
+ - points to a stable work area;
62
+ - is easy to recognize later.
63
+
64
+ A bad alias:
65
+ - duplicates a short path like "src": "src";
66
+ - points to a rarely used folder;
67
+ - mirrors the directory tree without a workflow reason.
68
+
69
+ Having 20-30 good aliases is fine for a large repo or monorepo.
70
+
71
+ Example:
72
+
73
+ "pathAliases": {
74
+ "wstore": "apps/web/src/shared/store",
75
+ "wapi": "apps/web/src/shared/api",
76
+ "whooks": "apps/web/src/shared/utils/hooks",
77
+ "pmail": "packages/email/src",
78
+ "putils": "packages/utils/src",
79
+ "arules": "docs/agent/rules"
80
+ }
81
+
82
+ 5. Configure import rules
83
+
84
+ Set importRules to the import style this repository should use after move/modulePlan mutations.
85
+
86
+ If the repository has one style, use one broad rule:
87
+
88
+ "importRules": [
89
+ {
90
+ "scope": ".",
91
+ "specifier": "shortest",
92
+ "ending": "auto",
93
+ "builtin": "node",
94
+ "unusedImports": "remove"
95
+ }
96
+ ]
97
+
98
+ Use scoped rules only when areas differ by style, for example packages use aliases but scripts use relative imports:
99
+
100
+ "importRules": [
101
+ {
102
+ "scope": "packages",
103
+ "specifier": "shortest",
104
+ "ending": "auto",
105
+ "builtin": "node",
106
+ "unusedImports": "remove"
107
+ },
108
+ {
109
+ "scope": "scripts",
110
+ "specifier": "relative",
111
+ "ending": "auto",
112
+ "builtin": "node",
113
+ "unusedImports": "remove"
114
+ }
115
+ ]
116
+
117
+ Use the most specific scope that matches the real convention.
118
+ Do not add scoped rules just because directories exist.
119
+
120
+ 6. Configure import normalization
121
+
122
+ Add importNormalize only for cleanup commands the agent is likely to run more than once.
123
+
124
+ Use it when the repo has a clear normalization target:
125
+
126
+ "importNormalize": [
127
+ {
128
+ "scope": "src",
129
+ "to": "shortestAlias",
130
+ "preferAlias": "@/*",
131
+ "exclude": [
132
+ "src/generated",
133
+ "src/**/dist"
134
+ ]
135
+ },
136
+ {
137
+ "scope": "scripts",
138
+ "to": "relative",
139
+ "exclude": [
140
+ "scripts/**/*.cjs",
141
+ "scripts/**/*.mjs"
142
+ ]
143
+ }
144
+ ]
145
+
146
+ Choose scopes from real repo conventions.
147
+ Do not copy importRules into importNormalize automatically.
148
+ Leave it unset if normalization is not a repeated workflow.
149
+
150
+ 7. Configure tree and graph excludes
151
+
152
+ Add excludes for noise the repository is known to contain.
153
+
154
+ Use tree excludes for what the agent should not see while mapping folders.
155
+ Use graph excludes for files that should not affect graph counts, hubs, entrypoints, leaves, edges, or saved graph views.
156
+
157
+ Built-in excludes already skip common noise such as node_modules, .git, dist, build, out, and .tmp.
158
+ Add config excludes for repository-specific noise.
159
+
160
+ For example, if the user often creates hard-copy directories or backup files before risky edits, those copies can make tree and graph output noisy.
161
+ Exclude them explicitly:
162
+
163
+ "inspect.tree.onlyDirs.exclude": [
164
+ "**/*copy",
165
+ "**/*copy/**"
166
+ ],
167
+ "inspect.tree.files.exclude": [
168
+ "**/* copy.ts",
169
+ "**/*.generated.ts"
170
+ ],
171
+ "inspect.graph.exclude": [
172
+ "**/* copy.ts",
173
+ "**/*.generated.ts",
174
+ "src/generated/**"
175
+ ]
176
+
177
+ Prefer narrow patterns for known noise:
178
+ - generated files;
179
+ - local copy/backup folders;
180
+ - build artifacts not already skipped by defaults;
181
+ - vendored or checked-in output.
182
+
183
+ These are common cases, not mandatory rules.
184
+ If the repository needs one of these areas for reasoning or mutation impact checks, do not exclude it.
185
+
186
+ Do not exclude broad source areas to make output smaller.
187
+ If output is too large, use scope, depth, limit, graph view, or graph toggles first.
188
+
189
+ 8. Configure TypeScript config discovery
190
+
191
+ Check which TypeScript configs AIB will sync and watch:
192
+
193
+ aib reveal tsconfigs +all
194
+
195
+ If output includes nested workspaces, seed projects, snapshots, backups, copied apps, or other non-primary projects, exclude them:
196
+
197
+ "sync.tsconfig.exclude": [
198
+ "dev-seed/**",
199
+ "snapshots/**"
200
+ ]
201
+
202
+ Do not exclude real package/app configs just to reduce output.
203
+
204
+ After editing aib.json, run:
205
+
206
+ aib sync
207
+
208
+ Then check again:
209
+
210
+ aib reveal tsconfigs +all
211
+
212
+ Visible tsconfigs should describe the active project surface.
213
+ Excluded tsconfigs should be things the agent should not use for setup decisions.
214
+
215
+ Use +nec only when you need to compare visible configs with config-excluded configs:
216
+
217
+ aib reveal tsconfigs +nec
218
+
219
+ 9. Sync and verify
220
+
221
+ After all aib.json edits, run:
222
+
223
+ aib sync
224
+
225
+ If sync fails, fix aib.json and rerun sync.
226
+
227
+ Check the final config summary:
228
+
229
+ aib config
230
+
231
+ Run one compact tree batch using important aliases:
232
+
233
+ aib inspect --stdin
234
+
235
+ Input:
236
+ tree @<important-alias> depth=3 +onlyDirs limit=80
237
+ tree @<another-important-alias> depth=3 +onlyDirs limit=80
238
+
239
+ Check final TypeScript config discovery:
240
+
241
+ aib reveal tsconfigs
242
+
243
+ Confirm:
244
+ - aliases resolve;
245
+ - obvious tree noise is hidden;
246
+ - visible tsconfigs match the active project surface;
247
+ - config sections are set intentionally.
248
+
249
+ 10. Note operational constraints
250
+
251
+ Before reporting back, identify any constraints the user should know.
252
+
253
+ Worktrees:
254
+ AIB resolves config from the nearest parent aib.json.
255
+ If the repository uses nested copied projects or worktrees inside the repo root, AIB may resolve the parent config.
256
+ Do not set up AIB inside nested worktrees that should behave as independent repositories.
257
+ Independent worktrees should live outside the main repo root or have their own intended aib.json boundary.
258
+
259
+ TTL:
260
+ Sessions and managed runtime are cleaned up after inactivity according to aib config session.
261
+ Tell the user if you changed these defaults or left them as-is.
262
+
263
+ Watchers:
264
+ AIB watches aib.json and visible tsconfig files after sync.
265
+ If config changes are not reflected, run aib sync.
266
+
267
+ 11. Report to user
268
+
269
+ Report:
270
+ - whether AIB config already existed or was initialized;
271
+ - which aliases were added and why;
272
+ - which importRules/importNormalize settings were added or intentionally left unset;
273
+ - which tree/graph/tsconfig excludes were added;
274
+ - whether sync and verification passed;
275
+ - any worktree, TTL, watcher, or tsconfig discovery constraints the user should know.
@@ -1,20 +1,22 @@
1
1
  Use tree to list a compact directory layout.
2
2
  It is useful before focused inspect when you know the area but not the exact file.
3
3
 
4
- node_modules, .git, dist, build, out, and .tmp are skipped by default.
5
-
6
4
  Controls:
7
- scope, depth, minDepth, limit, include, exclude, onlyDirs
5
+ scope, depth, minDepth, limit, only, exclude, onlyDirs, ned, nec
8
6
 
9
7
  Specific:
10
8
  depth max nesting depth; depth=N
11
9
  minDepth hide shallower paths; minDepth=N
12
10
  onlyDirs show directories only; +onlyDirs
13
- include only matching files/dirs; include=[...]
11
+ only only matching files/dirs; only=[...]
12
+ exclude skip matching files/dirs; exclude=[...]
13
+ ned no-default-exclude; ignore built-in excludes; +ned
14
+ nec no-config-exclude; ignore aib.json tree excludes; +nec
14
15
 
15
16
  Run:
16
17
  aib inspect --stdin
17
18
 
18
19
  Input:
19
- tree src depth=4 +onlyDirs limit=200
20
- tree @svc depth=3 include=["**/*.ts"] exclude=["**/*.test.ts","**/* copy.ts"]
20
+ tree src depth=4 +onlyDirs limit=200 +ned +nec
21
+ tree @svc depth=3 only=["**/*.ts"] exclude=["**/*.test.ts","**/* copy.ts"]
22
+ tree src depth=3 only=["src/services/**"] limit=80
@@ -152,10 +152,19 @@ shortestAlias rewrite to the shortest valid alias specifier
152
152
  preferAlias:
153
153
  @shared/* prefer one alias pattern when several aliases can resolve the same file
154
154
 
155
- inspect.graph.exclude skips files before graph builds the model.
156
- Use it for generated files, backups, local copies, or other paths that make graph output noisy.
155
+ AIB has four config exclude fields:
156
+ inspect.graph.exclude
157
+ inspect.tree.files.exclude
158
+ inspect.tree.onlyDirs.exclude
159
+ sync.tsconfig.exclude
157
160
 
158
- Excluded files do not affect graph counts, hubs, entrypoints, leaves, edges, imports, importedBy, or saved graph files.
161
+ For all of them, node_modules, .git, dist, build, out, and .tmp are skipped by default.
162
+
163
+ Use config excludes for generated files, backups, local copies, nested workspaces, seed projects, or other repository-specific noise.
164
+
165
+ Graph excludes affect graph counts, hubs, entrypoints, leaves, edges, imports, importedBy, and saved graph files.
166
+ Tree excludes affect directory/file discovery output.
167
+ Tsconfig excludes affect which TypeScript configs AIB syncs and watches.
159
168
 
160
169
  Leave feedback while working.
161
170
 
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.runCommand=$;const P=require("../commands/list-instances"),b=require("../commands/ping"),k=require("../commands/runtime-info"),S=require("../commands/print-config"),x=require("../commands/init-skill-usage"),R=require("../commands/init-workspace"),A=require("../commands/inspect"),c=require("../commands/captured-input"),E=require("../commands/module-plan-command"),D=require("../commands/rename-command"),N=require("../commands/move-command"),O=require("../commands/refactor-command"),U=require("../commands/imports-command"),W=require("../commands/execution-command"),T=require("../commands/observability-command"),M=require("../commands/help-command"),F=require("../commands/generate-docs-command"),j=require("../commands/feedback-command"),Q=require("../commands/doctor"),G=require("../commands/diagnostics-command"),H=require("../commands/session-workspace"),I=require("../commands/session-workspace"),v=require("../config/path-aliases"),J=require("../commands/runtime-command"),K=require("../commands/sync-command"),l=require("../client/transport-options"),m=require("../shared/errors"),p=require("./input-source"),L=require("../config/workspace-state");async function $(n){return(0,I.runWithSessionOverride)(n.sessionId,()=>z(n))}async function z(n){const{command:o,restArgs:d,cwd:r,instanceId:_,metricsSpans:g}=n,u=B(o)?(0,L.ensureWorkspaceState)(r):null,w=u?(0,I.readSessionPathAliasOverrides)(r):{},f={...u?.pathAliases??{},...w},e=(0,v.expandPathAliasesInArgs)(r,d,f),a=await(0,p.resolveCommandInputSource)({command:o,cwd:r,restArgs:e,...n.stdinPayload!==void 0?{preResolvedPayload:(0,v.expandPathAliasesInJson)(r,n.stdinPayload,f)}:{},...n.stdinInputSource!==void 0?{preResolvedSource:n.stdinInputSource}:{}}),s=a.payload,t={};_!==void 0&&(t.explicitInstanceId=_),n.autoStartIde!==void 0&&(t.autoStartIde=n.autoStartIde),n.transport!==void 0&&(t.transport=n.transport),n.metricsEnabled===!0&&(t.metricsEnabled=!0),u&&(t.importRules=u.importRules,t.mutationComments=u.mutationComments);const C=(0,l.getPreferredTransport)();n.transport&&(0,l.setPreferredTransport)(n.transport);try{switch(o){case"doctor":return(0,Q.runDoctor)({cwd:r,runtime:e.includes("--runtime"),verbose:e.includes("--verbose"),json:e.includes("--json")});case"diagnostics":return await(0,G.runDiagnosticsCommand)(e),{ok:!0,command:"diagnostics"};case"session":return(0,H.runSessionWorkspaceCommand)(r,e,s);case"init":return(0,R.runInitWorkspace)(r,d);case"help":return(0,M.runHelpCommand)(e);case"generate-docs":return(0,F.runGenerateDocsCommand)(r,d);case"sync":return(0,K.runSyncCommand)(r,e);case"observability":return(0,T.runObservabilityCommand)(r,e);case"feedback":case"note":return(0,j.runFeedbackCommand)(r,d,o);case"runtime":return(0,J.runRuntimeCommand)(r,e);case"imports":return(0,c.attachCapturedInput)(r,"imports",s,await(0,U.runImportsCommand)(r,e,s,t,g),a.source);case"listInstances":return(0,P.runListInstances)();case"ping":return(0,b.runPing)(r,t);case"runtimeInfo":return(0,k.runRuntimeInfo)(r,t);case"printConfig":return(0,S.runPrintConfig)(r,t);case"initSkillUsage":case"init-skill-usage":{const i=e.findIndex(h=>h==="--cli-name"),q=i>=0&&e[i+1]?e[i+1]:"aib",y={cwd:r,cliName:q??"aib"};return y.resolveOptions=t,(0,x.runInitSkillUsage)(y)}case"inspect":return(0,c.attachCapturedInput)(r,e[0]==="graph"?"graph":"inspect",s,await(0,A.runInspect)(r,e,s,t),a.source);case"modulePlan":return(0,c.attachCapturedInput)(r,"modulePlan",s,await(0,E.runModulePlanCommand)(r,e,s,t,n.modulePlanExecutionId?{executionId:n.modulePlanExecutionId}:{}),a.source);case"execution":return(0,W.runExecutionCommand)(r,e);case"rename":{if(!(e[0]==="apply"&&typeof e[1]=="string"&&!e[1].startsWith("--"))&&(0,p.commandRequiresPayload)(o,e,a))throw new m.CliError("STDIN_REQUIRED","rename preview/apply/validate expects a payload on stdin or --from, except preview-id apply/help.");return(0,c.attachCapturedInput)(r,"rename",s,await(0,D.runRenameCommand)(r,e,s,t),a.source)}case"move":{if(!(e[0]==="toFile"&&e[1]==="apply"&&typeof e[2]=="string"&&!e[2].startsWith("--"))&&(0,p.commandRequiresPayload)(o,e,a))throw new m.CliError("STDIN_REQUIRED","move toFile preview/apply/validate expects a payload on stdin or --from.");return(0,c.attachCapturedInput)(r,"move",s,await(0,N.runMoveCommand)(r,e,s,t),a.source)}case"refactor":{if(!(e[0]==="batch"&&e[1]==="apply"&&typeof e[2]=="string"&&!e[2].startsWith("--"))&&(0,p.commandRequiresPayload)(o,e,a))throw new m.CliError("STDIN_REQUIRED","refactor batch preview/apply/validate expects a payload on stdin or --from, except preview-id apply/help.");return(0,c.attachCapturedInput)(r,"refactor",s,await(0,O.runRefactorCommand)(r,e,s,t),a.source)}default:throw new m.CliError("UNKNOWN_COMMAND",`Unknown command: ${o}`,{availableCommands:["doctor","diagnostics","listInstances","ping","runtimeInfo","printConfig","init-skill-usage","init","help","generate-docs","sync","inspect","imports","execution","move","rename","refactor","modulePlan","session","runtime","trace","observability","feedback","note"]})}}finally{(0,l.setPreferredTransport)(C)}}function B(n){return n!=="init"&&n!=="help"&&n!=="generate-docs"&&n!=="observability"&&n!=="feedback"&&n!=="note"&&n!=="runtime"&&n!=="diagnostics"&&n!=="doctor"}
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.runCommand=z;const P=require("../commands/list-instances"),b=require("../commands/ping"),k=require("../commands/runtime-info"),S=require("../commands/print-config"),R=require("../commands/init-skill-usage"),x=require("../commands/init-workspace"),A=require("../commands/inspect"),c=require("../commands/captured-input"),E=require("../commands/module-plan-command"),D=require("../commands/rename-command"),N=require("../commands/move-command"),O=require("../commands/refactor-command"),U=require("../commands/imports-command"),W=require("../commands/execution-command"),T=require("../commands/observability-command"),M=require("../commands/help-command"),F=require("../commands/generate-docs-command"),j=require("../commands/feedback-command"),Q=require("../commands/doctor"),G=require("../commands/diagnostics-command"),H=require("../commands/session-workspace"),y=require("../commands/session-workspace"),I=require("../config/path-aliases"),J=require("../commands/runtime-command"),K=require("../commands/sync-command"),L=require("../commands/reveal-command"),p=require("../client/transport-options"),m=require("../shared/errors"),l=require("./input-source"),$=require("../config/workspace-state");async function z(n){return(0,y.runWithSessionOverride)(n.sessionId,()=>B(n))}async function B(n){const{command:o,restArgs:d,cwd:r,instanceId:_,metricsSpans:C}=n,u=V(o)?(0,$.ensureWorkspaceState)(r):null,g=u?(0,y.readSessionPathAliasOverrides)(r):{},f={...u?.pathAliases??{},...g},e=(0,I.expandPathAliasesInArgs)(r,d,f),a=await(0,l.resolveCommandInputSource)({command:o,cwd:r,restArgs:e,...n.stdinPayload!==void 0?{preResolvedPayload:(0,I.expandPathAliasesInJson)(r,n.stdinPayload,f)}:{},...n.stdinInputSource!==void 0?{preResolvedSource:n.stdinInputSource}:{}}),s=a.payload,t={};_!==void 0&&(t.explicitInstanceId=_),n.autoStartIde!==void 0&&(t.autoStartIde=n.autoStartIde),n.transport!==void 0&&(t.transport=n.transport),n.metricsEnabled===!0&&(t.metricsEnabled=!0),u&&(t.importRules=u.importRules,t.mutationComments=u.mutationComments);const w=(0,p.getPreferredTransport)();n.transport&&(0,p.setPreferredTransport)(n.transport);try{switch(o){case"doctor":return(0,Q.runDoctor)({cwd:r,runtime:e.includes("--runtime"),verbose:e.includes("--verbose"),json:e.includes("--json")});case"diagnostics":return await(0,G.runDiagnosticsCommand)(e),{ok:!0,command:"diagnostics"};case"session":return(0,H.runSessionWorkspaceCommand)(r,e,s);case"init":return(0,x.runInitWorkspace)(r,d);case"help":return(0,M.runHelpCommand)(e);case"generate-docs":return(0,F.runGenerateDocsCommand)(r,d);case"sync":return(0,K.runSyncCommand)(r,e);case"reveal":return(0,L.runRevealCommand)(r,e);case"observability":return(0,T.runObservabilityCommand)(r,e);case"feedback":case"note":return(0,j.runFeedbackCommand)(r,d,o);case"runtime":return(0,J.runRuntimeCommand)(r,e);case"imports":return(0,c.attachCapturedInput)(r,"imports",s,await(0,U.runImportsCommand)(r,e,s,t,C),a.source);case"listInstances":return(0,P.runListInstances)();case"ping":return(0,b.runPing)(r,t);case"runtimeInfo":return(0,k.runRuntimeInfo)(r,t);case"printConfig":return(0,S.runPrintConfig)(r,t);case"initSkillUsage":case"init-skill-usage":{const i=e.findIndex(h=>h==="--cli-name"),q=i>=0&&e[i+1]?e[i+1]:"aib",v={cwd:r,cliName:q??"aib"};return v.resolveOptions=t,(0,R.runInitSkillUsage)(v)}case"inspect":return(0,c.attachCapturedInput)(r,e[0]==="graph"?"graph":"inspect",s,await(0,A.runInspect)(r,e,s,t),a.source);case"modulePlan":return(0,c.attachCapturedInput)(r,"modulePlan",s,await(0,E.runModulePlanCommand)(r,e,s,t,n.modulePlanExecutionId?{executionId:n.modulePlanExecutionId}:{}),a.source);case"execution":return(0,W.runExecutionCommand)(r,e);case"rename":{if(!(e[0]==="apply"&&typeof e[1]=="string"&&!e[1].startsWith("--"))&&(0,l.commandRequiresPayload)(o,e,a))throw new m.CliError("STDIN_REQUIRED","rename preview/apply/validate expects a payload on stdin or --from, except preview-id apply/help.");return(0,c.attachCapturedInput)(r,"rename",s,await(0,D.runRenameCommand)(r,e,s,t),a.source)}case"move":{if(!(e[0]==="toFile"&&e[1]==="apply"&&typeof e[2]=="string"&&!e[2].startsWith("--"))&&(0,l.commandRequiresPayload)(o,e,a))throw new m.CliError("STDIN_REQUIRED","move toFile preview/apply/validate expects a payload on stdin or --from.");return(0,c.attachCapturedInput)(r,"move",s,await(0,N.runMoveCommand)(r,e,s,t),a.source)}case"refactor":{if(!(e[0]==="batch"&&e[1]==="apply"&&typeof e[2]=="string"&&!e[2].startsWith("--"))&&(0,l.commandRequiresPayload)(o,e,a))throw new m.CliError("STDIN_REQUIRED","refactor batch preview/apply/validate expects a payload on stdin or --from, except preview-id apply/help.");return(0,c.attachCapturedInput)(r,"refactor",s,await(0,O.runRefactorCommand)(r,e,s,t),a.source)}default:throw new m.CliError("UNKNOWN_COMMAND",`Unknown command: ${o}`,{availableCommands:["doctor","diagnostics","listInstances","ping","runtimeInfo","printConfig","init-skill-usage","init","help","generate-docs","sync","reveal","inspect","imports","execution","move","rename","refactor","modulePlan","session","runtime","trace","observability","feedback","note"]})}}finally{(0,p.setPreferredTransport)(w)}}function V(n){return n!=="init"&&n!=="help"&&n!=="generate-docs"&&n!=="observability"&&n!=="feedback"&&n!=="note"&&n!=="runtime"&&n!=="diagnostics"&&n!=="doctor"&&n!=="reveal"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@automaton-labs/aib",
3
- "version": "0.0.3",
3
+ "version": "0.0.4",
4
4
  "description": "CLI for discovering and calling the local aib IDE extension runtime.",
5
5
  "publishConfig": {
6
6
  "access": "public"
Binary file
@@ -50,6 +50,7 @@ if (!npmPrefix) {
50
50
 
51
51
  fs.mkdirSync(npmPrefix, { recursive: true });
52
52
  fs.copyFileSync(launcherPath, path.join(npmPrefix, "aib.exe"));
53
+ fs.writeFileSync(path.join(npmPrefix, "aib.node-cli.txt"), `${path.join(packageRoot, "dist", "bin", "aib.js")}\n`, "utf8");
53
54
 
54
55
  const ps1ShimPath = path.join(npmPrefix, "aib.ps1");
55
56
  const ps1BackupPath = path.join(npmPrefix, "aib.ps1.bak");
@@ -24,6 +24,8 @@ main().catch((error) => {
24
24
  });
25
25
 
26
26
  async function main() {
27
+ cleanupOldTempDownloads();
28
+
27
29
  if (runtimeComplete()) {
28
30
  if (!options.quiet) {
29
31
  reporter.info(`aib runtime ready: ${path.relative(process.cwd(), runtimesDir) || runtimesDir}`);
@@ -57,27 +59,31 @@ async function main() {
57
59
 
58
60
  reporter.info(`aib runtime: provisioning ${platformKey}`);
59
61
  const resolution = source || url
60
- ? { archivePath: source ? path.resolve(source) : await downloadRuntimeArchive(url, "runtime archive"), expectedSha256: options.sha256 ?? process.env.AIB_RUNTIME_SHA256 ?? null }
62
+ ? { ...(source ? { archivePath: path.resolve(source), tempDir: null } : await downloadRuntimeArchive(url, "runtime archive")), expectedSha256: options.sha256 ?? process.env.AIB_RUNTIME_SHA256 ?? null }
61
63
  : await resolveFromManifest(manifestSource, manifestUrl);
62
64
  const archivePath = resolution.archivePath;
63
- if (!fs.existsSync(archivePath)) {
64
- throw new Error(`Runtime archive not found: ${archivePath}`);
65
- }
66
- if (resolution.expectedSha256) {
67
- reporter.info("aib runtime: verifying checksum");
68
- assertSha256(archivePath, resolution.expectedSha256);
69
- }
65
+ try {
66
+ if (!fs.existsSync(archivePath)) {
67
+ throw new Error(`Runtime archive not found: ${archivePath}`);
68
+ }
69
+ if (resolution.expectedSha256) {
70
+ reporter.info("aib runtime: verifying checksum");
71
+ assertSha256(archivePath, resolution.expectedSha256);
72
+ }
70
73
 
71
- fs.mkdirSync(runtimesDir, { recursive: true });
72
- reporter.info("aib runtime: extracting archive");
73
- extractRuntimeArchive(archivePath);
74
+ fs.mkdirSync(runtimesDir, { recursive: true });
75
+ reporter.info("aib runtime: extracting archive");
76
+ extractRuntimeArchive(archivePath);
74
77
 
75
- if (!runtimeComplete()) {
76
- throw new Error(`Runtime archive did not provision a complete runtime under ${runtimesDir}`);
78
+ if (!runtimeComplete()) {
79
+ throw new Error(`Runtime archive did not provision a complete runtime under ${runtimesDir}`);
80
+ }
81
+ } finally {
82
+ cleanupOwnedTempDownload(resolution.tempDir);
77
83
  }
78
84
 
79
85
  if (!options.quiet) {
80
- reporter.info(`aib runtime provisioned: ${path.relative(process.cwd(), runtimesDir) || runtimesDir}`);
86
+ reporter.info("aib runtime: ready");
81
87
  }
82
88
  }
83
89
 
@@ -138,21 +144,72 @@ async function resolveFromManifest(manifestSource, manifestUrl) {
138
144
  }
139
145
  const archivePath = artifact.file && manifestSource
140
146
  ? path.resolve(path.dirname(path.resolve(manifestSource)), String(artifact.file))
141
- : artifact.url
142
- ? await downloadRuntimeArchive(String(artifact.url))
143
- : null;
144
- if (!archivePath) {
147
+ : null;
148
+ const downloaded = !archivePath && artifact.url
149
+ ? await downloadRuntimeArchive(String(artifact.url))
150
+ : null;
151
+ const resolvedArchivePath = archivePath ?? downloaded?.archivePath ?? null;
152
+ const tempDir = downloaded?.tempDir ?? null;
153
+ if (!resolvedArchivePath) {
145
154
  throw new Error(`Runtime manifest artifact for ${platformKey} has no url or local file.`);
146
155
  }
147
156
  return {
148
- archivePath,
157
+ archivePath: resolvedArchivePath,
158
+ tempDir,
149
159
  expectedSha256: typeof artifact.sha256 === "string" ? artifact.sha256 : null
150
160
  };
151
161
  }
152
162
 
153
163
  async function downloadJson(url) {
154
- const filePath = await downloadRuntimeArchive(url, "runtime manifest");
155
- return JSON.parse(fs.readFileSync(filePath, "utf8"));
164
+ const download = await downloadRuntimeArchive(url, "runtime manifest");
165
+ try {
166
+ return JSON.parse(fs.readFileSync(download.archivePath, "utf8"));
167
+ } finally {
168
+ cleanupOwnedTempDownload(download.tempDir);
169
+ }
170
+ }
171
+
172
+ function cleanupOldTempDownloads() {
173
+ const cutoffMs = Date.now() - 24 * 60 * 60 * 1000;
174
+ let entries = [];
175
+ try {
176
+ entries = fs.readdirSync(os.tmpdir(), { withFileTypes: true });
177
+ } catch {
178
+ return;
179
+ }
180
+ for (const entry of entries) {
181
+ if (!entry.isDirectory() || !entry.name.startsWith("aib-runtime-")) {
182
+ continue;
183
+ }
184
+ const tempDir = path.join(os.tmpdir(), entry.name);
185
+ try {
186
+ const stat = fs.statSync(tempDir);
187
+ if (stat.mtimeMs < cutoffMs) {
188
+ fs.rmSync(tempDir, { recursive: true, force: true });
189
+ }
190
+ } catch {
191
+ // Best-effort cleanup only.
192
+ }
193
+ }
194
+ }
195
+
196
+ function cleanupOwnedTempDownload(tempDir) {
197
+ if (!tempDir) {
198
+ return;
199
+ }
200
+ try {
201
+ const resolvedTemp = path.resolve(tempDir);
202
+ const resolvedOsTemp = path.resolve(os.tmpdir());
203
+ const relative = path.relative(resolvedOsTemp, resolvedTemp);
204
+ if (path.basename(resolvedTemp).startsWith("aib-runtime-")
205
+ && relative
206
+ && !relative.startsWith("..")
207
+ && !path.isAbsolute(relative)) {
208
+ fs.rmSync(resolvedTemp, { recursive: true, force: true });
209
+ }
210
+ } catch {
211
+ // Best-effort cleanup only.
212
+ }
156
213
  }
157
214
 
158
215
  function defaultManifestUrl() {
@@ -281,12 +338,14 @@ function downloadRuntimeArchive(url, label = "runtime archive") {
281
338
  if (response.statusCode && response.statusCode >= 300 && response.statusCode < 400 && response.headers.location) {
282
339
  file.close();
283
340
  fs.rmSync(targetPath, { force: true });
341
+ cleanupOwnedTempDownload(tempDir);
284
342
  downloadRuntimeArchive(new URL(response.headers.location, url).toString(), label).then(resolve, reject);
285
343
  return;
286
344
  }
287
345
  if (response.statusCode !== 200) {
288
346
  file.close();
289
347
  fs.rmSync(targetPath, { force: true });
348
+ cleanupOwnedTempDownload(tempDir);
290
349
  reject(new Error(`Runtime download failed with HTTP ${response.statusCode}: ${url}`));
291
350
  return;
292
351
  }
@@ -297,13 +356,14 @@ function downloadRuntimeArchive(url, label = "runtime archive") {
297
356
  file.on("finish", () => {
298
357
  file.close(() => {
299
358
  progress.done();
300
- resolve(targetPath);
359
+ resolve({ archivePath: targetPath, tempDir });
301
360
  });
302
361
  });
303
362
  });
304
363
  request.on("error", (error) => {
305
364
  file.close();
306
365
  fs.rmSync(targetPath, { force: true });
366
+ cleanupOwnedTempDownload(tempDir);
307
367
  reject(error);
308
368
  });
309
369
  });
@@ -311,7 +371,6 @@ function downloadRuntimeArchive(url, label = "runtime archive") {
311
371
 
312
372
  function createReporter(enabled) {
313
373
  const stream = process.stderr;
314
- const useCarriageReturn = Boolean(stream.isTTY);
315
374
  return {
316
375
  info(message) {
317
376
  if (!enabled) {
@@ -324,37 +383,36 @@ function createReporter(enabled) {
324
383
  return { add() {}, done() {} };
325
384
  }
326
385
  let downloadedBytes = 0;
327
- let lastWriteMs = 0;
328
386
  let ended = false;
329
- const startedMs = Date.now();
330
- const minIntervalMs = useCarriageReturn ? 750 : 5000;
331
- const write = (force = false) => {
332
- const now = Date.now();
333
- if (!force && now - lastWriteMs < minIntervalMs) {
387
+ let nextPercent = 10;
388
+ const totalKnown = Number.isFinite(totalBytes) && totalBytes > 0;
389
+ const showPercentProgress = totalKnown && totalBytes >= 1024 * 1024;
390
+ stream.write(totalKnown
391
+ ? `${label} ${formatBytes(totalBytes)}\n`
392
+ : `${label}\n`);
393
+ const writeProgress = () => {
394
+ if (!showPercentProgress) {
334
395
  return;
335
396
  }
336
- lastWriteMs = now;
337
- const percent = totalBytes ? Math.min(100, (downloadedBytes / totalBytes) * 100) : null;
338
- const elapsedSeconds = Math.max(0.001, (now - startedMs) / 1000);
339
- const rateBytes = downloadedBytes / elapsedSeconds;
340
- const text = percent === null
341
- ? `${label}: ${formatBytes(downloadedBytes)} downloaded (${formatBytes(rateBytes)}/s)`
342
- : `${label}: ${percent.toFixed(1)}% ${formatBytes(downloadedBytes)} / ${formatBytes(totalBytes)} (${formatBytes(rateBytes)}/s)`;
343
- stream.write(useCarriageReturn ? `\r${text}` : `${text}\n`);
397
+ const percent = Math.floor(Math.min(100, (downloadedBytes / totalBytes) * 100));
398
+ while (percent >= nextPercent && nextPercent <= 100) {
399
+ const thresholdBytes = Math.min(totalBytes, Math.round((totalBytes * nextPercent) / 100));
400
+ stream.write(`aib runtime: ${nextPercent}% ${formatBytes(thresholdBytes)} / ${formatBytes(totalBytes)}\n`);
401
+ nextPercent += 10;
402
+ }
344
403
  };
345
- write(true);
346
404
  return {
347
405
  add(byteCount) {
348
406
  downloadedBytes += byteCount;
349
- write(false);
407
+ writeProgress();
350
408
  },
351
409
  done() {
352
410
  if (ended) {
353
411
  return;
354
412
  }
355
413
  ended = true;
356
- write(true);
357
- stream.write(useCarriageReturn ? "\n" : "");
414
+ downloadedBytes = Math.max(downloadedBytes, totalBytes ?? downloadedBytes);
415
+ writeProgress();
358
416
  }
359
417
  };
360
418
  }