@confiqure/cli 0.1.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/LICENSE +21 -0
- package/README.md +68 -0
- package/dist/api.js +106 -0
- package/dist/api.js.map +1 -0
- package/dist/classTree.js +280 -0
- package/dist/classTree.js.map +1 -0
- package/dist/commands/diff.js +27 -0
- package/dist/commands/diff.js.map +1 -0
- package/dist/commands/init.js +49 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/login.js +60 -0
- package/dist/commands/login.js.map +1 -0
- package/dist/commands/push.js +227 -0
- package/dist/commands/push.js.map +1 -0
- package/dist/commands/status.js +47 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/tools.js +75 -0
- package/dist/commands/tools.js.map +1 -0
- package/dist/commands/workspace.js +50 -0
- package/dist/commands/workspace.js.map +1 -0
- package/dist/config.js +53 -0
- package/dist/config.js.map +1 -0
- package/dist/credentials.js +67 -0
- package/dist/credentials.js.map +1 -0
- package/dist/diff.js +98 -0
- package/dist/diff.js.map +1 -0
- package/dist/git.js +93 -0
- package/dist/git.js.map +1 -0
- package/dist/index.js +28 -0
- package/dist/index.js.map +1 -0
- package/dist/scan.js +120 -0
- package/dist/scan.js.map +1 -0
- package/package.json +54 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 confiqure.ai
|
|
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,68 @@
|
|
|
1
|
+
# @confiqure/cli
|
|
2
|
+
|
|
3
|
+
The official CLI for [confiqure.ai](https://confiqure.ai) — push `@Confiqure`-annotated classes to your workspace.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install -g @confiqure/cli
|
|
9
|
+
# or run without installing:
|
|
10
|
+
npx @confiqure/cli <command>
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Quick start
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
confiqure login # paste an API key from https://confiqure.ai/dashboard
|
|
17
|
+
confiqure init # scaffold confiqure.config.json in the project root
|
|
18
|
+
confiqure diff # preview which classes will be added / changed / deleted
|
|
19
|
+
confiqure push # upload the changeset; backend generates the chat playbook
|
|
20
|
+
confiqure status # check the most recent push result
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## How the scan works
|
|
24
|
+
|
|
25
|
+
`confiqure push` parses each `@Confiqure`-annotated class with tree-sitter, walks the field-type graph, and ships every file transitively reachable from a root — not just the file with the annotation on it. This means nested configuration classes (e.g. `EmailPreferences` referenced from a root `NotificationPreferences`) come along automatically, without needing their own `@Confiqure` tag.
|
|
26
|
+
|
|
27
|
+
Sample push output:
|
|
28
|
+
|
|
29
|
+
```
|
|
30
|
+
Scanned 10 files; 1 @Confiqure root.
|
|
31
|
+
|
|
32
|
+
⏵ Root: NotificationPreferences — 10 reachable files
|
|
33
|
+
├─ src/main/java/com/example/notifications/NotificationPreferences.java root
|
|
34
|
+
├─ src/main/java/com/example/notifications/EmailPreferences.java referenced
|
|
35
|
+
├─ src/main/java/com/example/notifications/AlertPreferences.java referenced
|
|
36
|
+
├─ src/main/java/com/example/model/Channel.java referenced
|
|
37
|
+
└─ … (6 more)
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Supported languages
|
|
41
|
+
|
|
42
|
+
V1 ships tree-sitter parsing for **Java**. The other 8 languages (Kotlin, Scala, Python, TypeScript, C#, Rust, PHP, Swift) use a keyword-scan fallback until their grammars are wired in. Track progress at [github.com/Omer-Ozturk-SJSU/confiqure-cli/issues](https://github.com/Omer-Ozturk-SJSU/confiqure-cli/issues).
|
|
43
|
+
|
|
44
|
+
## Configuration
|
|
45
|
+
|
|
46
|
+
`confiqure init` writes `confiqure.config.json`:
|
|
47
|
+
|
|
48
|
+
```json
|
|
49
|
+
{
|
|
50
|
+
"scanPaths": ["src/main/java"],
|
|
51
|
+
"ignore": ["target", ".git", ".idea"],
|
|
52
|
+
"languages": {
|
|
53
|
+
"java": { "extensions": [".java"], "tokenPattern": "@Confiqure" }
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Environment variables
|
|
59
|
+
|
|
60
|
+
Override the file-based credentials for CI:
|
|
61
|
+
|
|
62
|
+
- `CONFIQURE_API_KEY` — workspace API key (`cqai_…`)
|
|
63
|
+
- `CONFIQURE_WORKSPACE_KEY` — workspace URL key
|
|
64
|
+
- `CONFIQURE_API_BASE` — backend URL (defaults to `https://api.confiqure.ai`)
|
|
65
|
+
|
|
66
|
+
## License
|
|
67
|
+
|
|
68
|
+
MIT — see [LICENSE](./LICENSE).
|
package/dist/api.js
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
export class ApiError extends Error {
|
|
2
|
+
status;
|
|
3
|
+
constructor(status, message) {
|
|
4
|
+
super(message);
|
|
5
|
+
this.status = status;
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Resolve an API token to its workspace identity without requiring the
|
|
10
|
+
* caller to know the workspaceKey upfront. Used by `confiqure login` so
|
|
11
|
+
* the user only has to paste the token.
|
|
12
|
+
*/
|
|
13
|
+
export async function getWhoami(apiBase, token) {
|
|
14
|
+
const res = await fetch(`${apiBase}/api/cli/whoami`, {
|
|
15
|
+
headers: { Authorization: `Bearer ${token}` },
|
|
16
|
+
});
|
|
17
|
+
if (!res.ok) {
|
|
18
|
+
throw new ApiError(res.status, `GET /api/cli/whoami failed: ${res.status} ${await res.text()}`);
|
|
19
|
+
}
|
|
20
|
+
return (await res.json());
|
|
21
|
+
}
|
|
22
|
+
export async function getPushStatus(creds, pushHistoryId) {
|
|
23
|
+
const res = await fetch(`${creds.apiBase}/api/${creds.workspaceKey}/upload/status/${pushHistoryId}`, { headers: { Authorization: `Bearer ${creds.token}` } });
|
|
24
|
+
if (!res.ok) {
|
|
25
|
+
throw new ApiError(res.status, `GET /upload/status/${pushHistoryId} failed: ${res.status} ${await res.text()}`);
|
|
26
|
+
}
|
|
27
|
+
return (await res.json());
|
|
28
|
+
}
|
|
29
|
+
export async function getRegistry(creds) {
|
|
30
|
+
const res = await fetch(`${creds.apiBase}/api/${creds.workspaceKey}/upload`, { headers: { Authorization: `Bearer ${creds.token}` } });
|
|
31
|
+
if (!res.ok) {
|
|
32
|
+
throw new ApiError(res.status, `GET /upload failed: ${res.status} ${await res.text()}`);
|
|
33
|
+
}
|
|
34
|
+
return (await res.json());
|
|
35
|
+
}
|
|
36
|
+
export async function getWorkspace(creds) {
|
|
37
|
+
const res = await fetch(`${creds.apiBase}/api/${creds.workspaceKey}/cli/workspace`, { headers: { Authorization: `Bearer ${creds.token}` } });
|
|
38
|
+
if (!res.ok) {
|
|
39
|
+
throw new ApiError(res.status, `GET /cli/workspace failed: ${res.status} ${await res.text()}`);
|
|
40
|
+
}
|
|
41
|
+
return (await res.json());
|
|
42
|
+
}
|
|
43
|
+
export async function updateWorkspace(creds, changes) {
|
|
44
|
+
const res = await fetch(`${creds.apiBase}/api/${creds.workspaceKey}/cli/workspace`, {
|
|
45
|
+
method: "PUT",
|
|
46
|
+
headers: {
|
|
47
|
+
Authorization: `Bearer ${creds.token}`,
|
|
48
|
+
"Content-Type": "application/json",
|
|
49
|
+
},
|
|
50
|
+
body: JSON.stringify(changes),
|
|
51
|
+
});
|
|
52
|
+
if (!res.ok) {
|
|
53
|
+
throw new ApiError(res.status, `PUT /cli/workspace failed: ${res.status} ${await res.text()}`);
|
|
54
|
+
}
|
|
55
|
+
return (await res.json());
|
|
56
|
+
}
|
|
57
|
+
export async function listTools(creds) {
|
|
58
|
+
const res = await fetch(`${creds.apiBase}/api/${creds.workspaceKey}/cli/tools`, { headers: { Authorization: `Bearer ${creds.token}` } });
|
|
59
|
+
if (!res.ok) {
|
|
60
|
+
throw new ApiError(res.status, `GET /cli/tools failed: ${res.status} ${await res.text()}`);
|
|
61
|
+
}
|
|
62
|
+
return (await res.json());
|
|
63
|
+
}
|
|
64
|
+
export async function upsertTool(creds, name, url, instructions) {
|
|
65
|
+
const res = await fetch(`${creds.apiBase}/api/${creds.workspaceKey}/cli/tools/${encodeURIComponent(name)}`, {
|
|
66
|
+
method: "PUT",
|
|
67
|
+
headers: {
|
|
68
|
+
Authorization: `Bearer ${creds.token}`,
|
|
69
|
+
"Content-Type": "application/json",
|
|
70
|
+
},
|
|
71
|
+
body: JSON.stringify({ url, instructions: instructions ?? null }),
|
|
72
|
+
});
|
|
73
|
+
if (!res.ok) {
|
|
74
|
+
throw new ApiError(res.status, `PUT /cli/tools/${name} failed: ${res.status} ${await res.text()}`);
|
|
75
|
+
}
|
|
76
|
+
return (await res.json());
|
|
77
|
+
}
|
|
78
|
+
export async function deleteTool(creds, name) {
|
|
79
|
+
const res = await fetch(`${creds.apiBase}/api/${creds.workspaceKey}/cli/tools/${encodeURIComponent(name)}`, {
|
|
80
|
+
method: "DELETE",
|
|
81
|
+
headers: { Authorization: `Bearer ${creds.token}` },
|
|
82
|
+
});
|
|
83
|
+
if (!res.ok && res.status !== 404) {
|
|
84
|
+
throw new ApiError(res.status, `DELETE /cli/tools/${name} failed: ${res.status} ${await res.text()}`);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
export async function postUpload(creds, manifest, files) {
|
|
88
|
+
const form = new FormData();
|
|
89
|
+
form.append("manifest", JSON.stringify(manifest));
|
|
90
|
+
// Paths can contain slashes; URL-encode for the filename slot so the server
|
|
91
|
+
// can decode without the multipart parser dropping directory components.
|
|
92
|
+
for (const [path, content] of files) {
|
|
93
|
+
const blob = new Blob([content], { type: "text/plain;charset=utf-8" });
|
|
94
|
+
form.append("sources", blob, encodeURIComponent(path));
|
|
95
|
+
}
|
|
96
|
+
const res = await fetch(`${creds.apiBase}/api/${creds.workspaceKey}/upload`, {
|
|
97
|
+
method: "POST",
|
|
98
|
+
headers: { Authorization: `Bearer ${creds.token}` },
|
|
99
|
+
body: form,
|
|
100
|
+
});
|
|
101
|
+
if (!res.ok) {
|
|
102
|
+
throw new ApiError(res.status, `POST /upload failed: ${res.status} ${await res.text()}`);
|
|
103
|
+
}
|
|
104
|
+
return (await res.json());
|
|
105
|
+
}
|
|
106
|
+
//# sourceMappingURL=api.js.map
|
package/dist/api.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.js","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
import { dirname, join } from "node:path";
|
|
3
|
+
import { readFile } from "node:fs/promises";
|
|
4
|
+
import Parser from "web-tree-sitter";
|
|
5
|
+
/**
|
|
6
|
+
* Tree-sitter-driven reachability for `@Confiqure`-rooted class graphs.
|
|
7
|
+
*
|
|
8
|
+
* The classic confiqure scan was "does this file contain `@Confiqure`?" — which
|
|
9
|
+
* silently dropped every nested class the AI needs to understand. This module
|
|
10
|
+
* parses each candidate source file into an AST, then walks the field-type
|
|
11
|
+
* graph from each annotated root so we send the backend exactly the files that
|
|
12
|
+
* matter (root + everything transitively referenced), not the whole scanPath.
|
|
13
|
+
*
|
|
14
|
+
* V1 supports Java. The factory wires `web-tree-sitter` + a bundled `.wasm`
|
|
15
|
+
* grammar; adding Kotlin/Scala/etc. is a matter of registering another grammar
|
|
16
|
+
* here and providing matching node-type extractors.
|
|
17
|
+
*/
|
|
18
|
+
const require = createRequire(import.meta.url);
|
|
19
|
+
function resolveGrammarWasm(grammarFile) {
|
|
20
|
+
const pkgJson = require.resolve("tree-sitter-wasms/package.json");
|
|
21
|
+
return join(dirname(pkgJson), "out", grammarFile);
|
|
22
|
+
}
|
|
23
|
+
let parserReady = null;
|
|
24
|
+
let javaLanguage = null;
|
|
25
|
+
async function ensureJavaParser() {
|
|
26
|
+
if (!parserReady) {
|
|
27
|
+
parserReady = Parser.init();
|
|
28
|
+
}
|
|
29
|
+
await parserReady;
|
|
30
|
+
if (!javaLanguage) {
|
|
31
|
+
javaLanguage = await Parser.Language.load(resolveGrammarWasm("tree-sitter-java.wasm"));
|
|
32
|
+
}
|
|
33
|
+
const parser = new Parser();
|
|
34
|
+
parser.setLanguage(javaLanguage);
|
|
35
|
+
return parser;
|
|
36
|
+
}
|
|
37
|
+
/** Parse every Java file in `allFiles`. Non-Java files are skipped silently. */
|
|
38
|
+
export async function parseJavaFiles(allFiles) {
|
|
39
|
+
const javaPaths = Array.from(allFiles.keys()).filter((p) => p.endsWith(".java"));
|
|
40
|
+
if (javaPaths.length === 0)
|
|
41
|
+
return [];
|
|
42
|
+
const parser = await ensureJavaParser();
|
|
43
|
+
const result = [];
|
|
44
|
+
try {
|
|
45
|
+
for (const filePath of javaPaths) {
|
|
46
|
+
const source = allFiles.get(filePath);
|
|
47
|
+
if (source == null)
|
|
48
|
+
continue;
|
|
49
|
+
const tree = parser.parse(source);
|
|
50
|
+
if (!tree)
|
|
51
|
+
continue;
|
|
52
|
+
result.push(extractFile(filePath, tree.rootNode));
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
finally {
|
|
56
|
+
parser.delete();
|
|
57
|
+
}
|
|
58
|
+
return result;
|
|
59
|
+
}
|
|
60
|
+
/** Parse a single Java file from disk. */
|
|
61
|
+
export async function parseJavaFile(filePath) {
|
|
62
|
+
const parser = await ensureJavaParser();
|
|
63
|
+
try {
|
|
64
|
+
const source = await readFile(filePath, "utf8");
|
|
65
|
+
const tree = parser.parse(source);
|
|
66
|
+
if (!tree)
|
|
67
|
+
return null;
|
|
68
|
+
return extractFile(filePath, tree.rootNode);
|
|
69
|
+
}
|
|
70
|
+
finally {
|
|
71
|
+
parser.delete();
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
function extractFile(filePath, root) {
|
|
75
|
+
let packageName = null;
|
|
76
|
+
const declarations = [];
|
|
77
|
+
for (const child of root.namedChildren) {
|
|
78
|
+
if (!child)
|
|
79
|
+
continue;
|
|
80
|
+
if (child.type === "package_declaration") {
|
|
81
|
+
packageName = extractPackageName(child);
|
|
82
|
+
}
|
|
83
|
+
else if (isTypeDeclaration(child.type)) {
|
|
84
|
+
const decl = extractDeclaration(child);
|
|
85
|
+
if (decl)
|
|
86
|
+
declarations.push(decl);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return { filePath, packageName, declarations };
|
|
90
|
+
}
|
|
91
|
+
function isTypeDeclaration(type) {
|
|
92
|
+
return (type === "class_declaration" ||
|
|
93
|
+
type === "interface_declaration" ||
|
|
94
|
+
type === "enum_declaration" ||
|
|
95
|
+
type === "record_declaration");
|
|
96
|
+
}
|
|
97
|
+
function extractPackageName(node) {
|
|
98
|
+
for (const child of node.namedChildren) {
|
|
99
|
+
if (!child)
|
|
100
|
+
continue;
|
|
101
|
+
if (child.type === "scoped_identifier" || child.type === "identifier") {
|
|
102
|
+
return child.text;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return null;
|
|
106
|
+
}
|
|
107
|
+
function extractDeclaration(node) {
|
|
108
|
+
const kind = node.type === "class_declaration"
|
|
109
|
+
? "class"
|
|
110
|
+
: node.type === "interface_declaration"
|
|
111
|
+
? "interface"
|
|
112
|
+
: node.type === "enum_declaration"
|
|
113
|
+
? "enum"
|
|
114
|
+
: "record";
|
|
115
|
+
const nameNode = node.childForFieldName("name");
|
|
116
|
+
if (!nameNode)
|
|
117
|
+
return null;
|
|
118
|
+
const name = nameNode.text;
|
|
119
|
+
const hasConfiqureAnnotation = declarationHasConfiqure(node);
|
|
120
|
+
const body = node.childForFieldName("body");
|
|
121
|
+
const fields = [];
|
|
122
|
+
if (body && (kind === "class" || kind === "record")) {
|
|
123
|
+
let pendingDoc = null;
|
|
124
|
+
for (const child of body.namedChildren) {
|
|
125
|
+
if (!child)
|
|
126
|
+
continue;
|
|
127
|
+
if (child.type === "block_comment" || child.type === "line_comment") {
|
|
128
|
+
pendingDoc = pendingDoc ? `${pendingDoc}\n${child.text}` : child.text;
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
if (child.type === "field_declaration") {
|
|
132
|
+
const extracted = extractFields(child, pendingDoc);
|
|
133
|
+
fields.push(...extracted);
|
|
134
|
+
}
|
|
135
|
+
pendingDoc = null;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
return { kind, name, hasConfiqureAnnotation, fields };
|
|
139
|
+
}
|
|
140
|
+
function declarationHasConfiqure(node) {
|
|
141
|
+
for (const child of node.children) {
|
|
142
|
+
if (!child)
|
|
143
|
+
continue;
|
|
144
|
+
if (child.type !== "modifiers")
|
|
145
|
+
continue;
|
|
146
|
+
for (const mod of child.namedChildren) {
|
|
147
|
+
if (!mod)
|
|
148
|
+
continue;
|
|
149
|
+
if (mod.type !== "marker_annotation" && mod.type !== "annotation")
|
|
150
|
+
continue;
|
|
151
|
+
const annName = mod.childForFieldName("name");
|
|
152
|
+
if (!annName)
|
|
153
|
+
continue;
|
|
154
|
+
const simple = lastSegment(annName.text);
|
|
155
|
+
if (simple === "Confiqure")
|
|
156
|
+
return true;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
return false;
|
|
160
|
+
}
|
|
161
|
+
function lastSegment(name) {
|
|
162
|
+
const dot = name.lastIndexOf(".");
|
|
163
|
+
return dot === -1 ? name : name.slice(dot + 1);
|
|
164
|
+
}
|
|
165
|
+
function extractFields(fieldDecl, doc) {
|
|
166
|
+
const typeNode = fieldDecl.childForFieldName("type");
|
|
167
|
+
if (!typeNode)
|
|
168
|
+
return [];
|
|
169
|
+
const typeText = typeNode.text;
|
|
170
|
+
const typeNames = collectTypeIdentifiers(typeNode);
|
|
171
|
+
const out = [];
|
|
172
|
+
for (const child of fieldDecl.namedChildren) {
|
|
173
|
+
if (!child)
|
|
174
|
+
continue;
|
|
175
|
+
if (child.type !== "variable_declarator")
|
|
176
|
+
continue;
|
|
177
|
+
const nameNode = child.childForFieldName("name");
|
|
178
|
+
if (!nameNode)
|
|
179
|
+
continue;
|
|
180
|
+
out.push({
|
|
181
|
+
name: nameNode.text,
|
|
182
|
+
typeText,
|
|
183
|
+
typeNames,
|
|
184
|
+
doc,
|
|
185
|
+
hasConfiqureTag: doc != null && /@confiqure\b/i.test(doc),
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
return out;
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Walk a `type` subtree and return every type identifier we see — the wrapper
|
|
192
|
+
* type plus every generic argument. E.g. `Map<String, List<Channel>>` →
|
|
193
|
+
* ["Map", "String", "List", "Channel"]. The resolver later filters these
|
|
194
|
+
* against the in-project class index, so non-project types (String, etc.)
|
|
195
|
+
* fall away naturally.
|
|
196
|
+
*/
|
|
197
|
+
function collectTypeIdentifiers(node) {
|
|
198
|
+
const out = [];
|
|
199
|
+
const visit = (n) => {
|
|
200
|
+
if (!n)
|
|
201
|
+
return;
|
|
202
|
+
if (n.type === "type_identifier") {
|
|
203
|
+
out.push(n.text);
|
|
204
|
+
}
|
|
205
|
+
else if (n.type === "scoped_type_identifier") {
|
|
206
|
+
out.push(lastSegment(n.text));
|
|
207
|
+
}
|
|
208
|
+
for (const c of n.namedChildren)
|
|
209
|
+
visit(c);
|
|
210
|
+
};
|
|
211
|
+
visit(node);
|
|
212
|
+
return out;
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* From the set of parsed files, build one ClassTree per `@Confiqure` root.
|
|
216
|
+
* If a `@Confiqure` class is reachable from another root, it's marked
|
|
217
|
+
* subsumed instead of producing its own tree — that's how nested
|
|
218
|
+
* configuration classes (e.g. PushPreferences inside NotificationPreferences)
|
|
219
|
+
* stop showing up as duplicate endpoints.
|
|
220
|
+
*/
|
|
221
|
+
export function buildClassTrees(parsed) {
|
|
222
|
+
const classNameToDecl = new Map();
|
|
223
|
+
for (const pf of parsed) {
|
|
224
|
+
for (const decl of pf.declarations) {
|
|
225
|
+
if (!classNameToDecl.has(decl.name)) {
|
|
226
|
+
classNameToDecl.set(decl.name, { file: pf.filePath, decl });
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
const rootCandidates = [];
|
|
231
|
+
for (const pf of parsed) {
|
|
232
|
+
for (const decl of pf.declarations) {
|
|
233
|
+
if (decl.hasConfiqureAnnotation)
|
|
234
|
+
rootCandidates.push({ file: pf.filePath, decl });
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
const rawTrees = rootCandidates.map(({ file, decl }) => {
|
|
238
|
+
const reachableFiles = new Set();
|
|
239
|
+
const visitedClasses = [];
|
|
240
|
+
const stack = [decl.name];
|
|
241
|
+
while (stack.length > 0) {
|
|
242
|
+
const className = stack.pop();
|
|
243
|
+
const found = classNameToDecl.get(className);
|
|
244
|
+
if (!found)
|
|
245
|
+
continue;
|
|
246
|
+
if (reachableFiles.has(found.file))
|
|
247
|
+
continue;
|
|
248
|
+
reachableFiles.add(found.file);
|
|
249
|
+
visitedClasses.push(className);
|
|
250
|
+
if (found.decl.kind === "class" || found.decl.kind === "record") {
|
|
251
|
+
for (const field of found.decl.fields) {
|
|
252
|
+
for (const t of field.typeNames)
|
|
253
|
+
stack.push(t);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
return {
|
|
258
|
+
rootFile: file,
|
|
259
|
+
rootClass: decl.name,
|
|
260
|
+
reachableFiles,
|
|
261
|
+
visitedClasses,
|
|
262
|
+
subsumedConfiqureClasses: [],
|
|
263
|
+
};
|
|
264
|
+
});
|
|
265
|
+
const rootClassNames = new Set(rawTrees.map((t) => t.rootClass));
|
|
266
|
+
const subsumed = new Map();
|
|
267
|
+
for (const tree of rawTrees) {
|
|
268
|
+
for (const cls of tree.visitedClasses) {
|
|
269
|
+
if (cls === tree.rootClass)
|
|
270
|
+
continue;
|
|
271
|
+
if (rootClassNames.has(cls)) {
|
|
272
|
+
tree.subsumedConfiqureClasses.push(cls);
|
|
273
|
+
subsumed.set(cls, tree.rootClass);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
const trees = rawTrees.filter((t) => !subsumed.has(t.rootClass));
|
|
278
|
+
return { trees, subsumed };
|
|
279
|
+
}
|
|
280
|
+
//# sourceMappingURL=classTree.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"classTree.js","sourceRoot":"","sources":["../src/classTree.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
import { requireCredentials } from "../credentials.js";
|
|
3
|
+
import { loadConfig } from "../config.js";
|
|
4
|
+
import { scanProject } from "../scan.js";
|
|
5
|
+
import { diffAgainstRegistry, renderDiff } from "../diff.js";
|
|
6
|
+
import { getRegistry } from "../api.js";
|
|
7
|
+
export function registerDiff(program) {
|
|
8
|
+
program
|
|
9
|
+
.command("diff")
|
|
10
|
+
.description("Compute the change-file vs the backend without uploading")
|
|
11
|
+
.action(async () => {
|
|
12
|
+
const cwd = process.cwd();
|
|
13
|
+
const creds = await requireCredentials();
|
|
14
|
+
const config = await loadConfig(cwd);
|
|
15
|
+
const scan = await scanProject(cwd, config);
|
|
16
|
+
console.log(chalk.dim(`Scanned ${scan.allFiles.size} files; ${scan.annotated.length} annotated.`));
|
|
17
|
+
const registry = await getRegistry(creds);
|
|
18
|
+
console.log(chalk.dim(`Backend registry: ${registry.length} class${registry.length === 1 ? "" : "es"}.`));
|
|
19
|
+
const diff = diffAgainstRegistry(scan.annotated, registry);
|
|
20
|
+
console.log();
|
|
21
|
+
console.log(renderDiff(diff, {
|
|
22
|
+
allScannedPaths: Array.from(scan.allFiles.keys()),
|
|
23
|
+
annotatedPaths: scan.annotated.map((c) => c.filePath),
|
|
24
|
+
}));
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=diff.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diff.js","sourceRoot":"","sources":["../../src/commands/diff.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,EAAE,mBAAmB,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAC7D,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAExC,MAAM,UAAU,YAAY,CAAC,OAAgB;IAC3C,OAAO;SACJ,OAAO,CAAC,MAAM,CAAC;SACf,WAAW,CAAC,0DAA0D,CAAC;SACvE,MAAM,CAAC,KAAK,IAAI,EAAE;QACjB,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;QAC1B,MAAM,KAAK,GAAG,MAAM,kBAAkB,EAAE,CAAC;QACzC,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,GAAG,CAAC,CAAC;QAErC,MAAM,IAAI,GAAG,MAAM,WAAW,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;QAC5C,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,WAAW,IAAI,CAAC,QAAQ,CAAC,IAAI,WAAW,IAAI,CAAC,SAAS,CAAC,MAAM,aAAa,CAAC,CAAC,CAAC;QAEnG,MAAM,QAAQ,GAAG,MAAM,WAAW,CAAC,KAAK,CAAC,CAAC;QAC1C,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,qBAAqB,QAAQ,CAAC,MAAM,SAAS,QAAQ,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC;QAE1G,MAAM,IAAI,GAAG,mBAAmB,CAAC,IAAI,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;QAC3D,OAAO,CAAC,GAAG,EAAE,CAAC;QACd,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,EAAE;YAC3B,eAAe,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;YACjD,cAAc,EAAE,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC;SACtD,CAAC,CAAC,CAAC;IACN,CAAC,CAAC,CAAC;AACP,CAAC"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { confirm, input } from "@inquirer/prompts";
|
|
2
|
+
import chalk from "chalk";
|
|
3
|
+
import { existsSync } from "node:fs";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
import { CONFIG_FILE, DEFAULT_CONFIG, loadConfig, saveConfig, } from "../config.js";
|
|
6
|
+
export function registerInit(program) {
|
|
7
|
+
program
|
|
8
|
+
.command("init")
|
|
9
|
+
.description(`Generate or update ${CONFIG_FILE} in the current directory`)
|
|
10
|
+
.option("-y, --yes", "accept defaults without prompting")
|
|
11
|
+
.action(async (opts) => {
|
|
12
|
+
const cwd = process.cwd();
|
|
13
|
+
const path = join(cwd, CONFIG_FILE);
|
|
14
|
+
const exists = existsSync(path);
|
|
15
|
+
if (exists && !opts.yes) {
|
|
16
|
+
const overwrite = await confirm({
|
|
17
|
+
message: `${CONFIG_FILE} already exists. Update it?`,
|
|
18
|
+
default: true,
|
|
19
|
+
});
|
|
20
|
+
if (!overwrite) {
|
|
21
|
+
console.log(chalk.yellow("Aborted."));
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
const existing = exists ? await loadConfig(cwd) : DEFAULT_CONFIG;
|
|
26
|
+
let config = existing;
|
|
27
|
+
if (!opts.yes) {
|
|
28
|
+
const scanPathsRaw = await input({
|
|
29
|
+
message: "Scan paths (comma-separated globs):",
|
|
30
|
+
default: existing.scanPaths.join(", "),
|
|
31
|
+
});
|
|
32
|
+
const ignoreRaw = await input({
|
|
33
|
+
message: "Directories to ignore (comma-separated):",
|
|
34
|
+
default: existing.ignore.join(", "),
|
|
35
|
+
});
|
|
36
|
+
config = {
|
|
37
|
+
...existing,
|
|
38
|
+
scanPaths: scanPathsRaw.split(",").map((s) => s.trim()).filter(Boolean),
|
|
39
|
+
ignore: ignoreRaw.split(",").map((s) => s.trim()).filter(Boolean),
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
await saveConfig(cwd, config);
|
|
43
|
+
console.log(chalk.green("✓"), `Wrote ${path}`);
|
|
44
|
+
console.log(chalk.dim(` scanPaths: ${config.scanPaths.join(", ")}`));
|
|
45
|
+
console.log(chalk.dim(` ignore: ${config.ignore.join(", ")}`));
|
|
46
|
+
console.log(chalk.dim(` languages: ${Object.keys(config.languages).join(", ")}`));
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=init.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { input, password } from "@inquirer/prompts";
|
|
2
|
+
import chalk from "chalk";
|
|
3
|
+
import { credentialsPath, loadCredentials, saveCredentials, } from "../credentials.js";
|
|
4
|
+
import { ApiError, getWhoami } from "../api.js";
|
|
5
|
+
export function registerLogin(program) {
|
|
6
|
+
program
|
|
7
|
+
.command("login")
|
|
8
|
+
.description("Save a workspace API key for the CLI to use")
|
|
9
|
+
.option("--api-base <url>", "confiqure API base URL")
|
|
10
|
+
.option("--workspace <key>", "workspace key (6-letter) — skips the whoami lookup; useful for offline/scripted setup")
|
|
11
|
+
.option("--token <token>", "API token (cqai_…)")
|
|
12
|
+
.action(async (opts) => {
|
|
13
|
+
const existing = await loadCredentials();
|
|
14
|
+
const apiBase = opts.apiBase ??
|
|
15
|
+
(await input({
|
|
16
|
+
message: "API base URL:",
|
|
17
|
+
default: existing?.apiBase ?? "https://api.confiqure.ai",
|
|
18
|
+
}));
|
|
19
|
+
const token = opts.token ??
|
|
20
|
+
(await password({
|
|
21
|
+
message: "API token (cqai_…):",
|
|
22
|
+
mask: "*",
|
|
23
|
+
validate: (v) => v.startsWith("cqai_") && v.length >= 16 ? true : "Token must start with cqai_",
|
|
24
|
+
}));
|
|
25
|
+
// Resolve workspaceKey. Manual override skips the network call (useful
|
|
26
|
+
// for CI / offline setup); otherwise we ask the backend.
|
|
27
|
+
let workspaceKey;
|
|
28
|
+
let workspaceName = null;
|
|
29
|
+
if (opts.workspace) {
|
|
30
|
+
workspaceKey = opts.workspace;
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
try {
|
|
34
|
+
const me = await getWhoami(apiBase, token);
|
|
35
|
+
workspaceKey = me.workspaceKey;
|
|
36
|
+
workspaceName = me.workspaceName;
|
|
37
|
+
}
|
|
38
|
+
catch (e) {
|
|
39
|
+
if (e instanceof ApiError && e.status === 401) {
|
|
40
|
+
console.error(chalk.red("✗"), "Invalid token — the server rejected this key.");
|
|
41
|
+
}
|
|
42
|
+
else if (e instanceof ApiError) {
|
|
43
|
+
console.error(chalk.red("✗"), `whoami failed (${e.status}): ${e.message}`);
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
47
|
+
console.error(chalk.red("✗"), `Couldn't reach ${apiBase}: ${msg}`);
|
|
48
|
+
}
|
|
49
|
+
process.exit(1);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
const creds = { apiBase, workspaceKey, token };
|
|
53
|
+
await saveCredentials(creds);
|
|
54
|
+
const who = workspaceName ? `${workspaceName} (${workspaceKey})` : workspaceKey;
|
|
55
|
+
console.log(chalk.green("✓"), `Logged in as ${who}`);
|
|
56
|
+
console.log(chalk.dim(` apiBase: ${apiBase}`));
|
|
57
|
+
console.log(chalk.dim(` saved: ${credentialsPath()}`));
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=login.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"login.js","sourceRoot":"","sources":["../../src/commands/login.ts"],"names":[],"mappings":"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"}
|