@itznexus/itznexus-cli 1.29.0 → 1.31.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/dist/commands/api/files.js +72 -2
- package/dist/commands/api/files.js.map +1 -1
- package/dist/commands/api/project-instructions.d.ts +2 -0
- package/dist/commands/api/project-instructions.js +134 -0
- package/dist/commands/api/project-instructions.js.map +1 -0
- package/dist/commands/api/projects.js +39 -77
- package/dist/commands/api/projects.js.map +1 -1
- package/dist/commands/api/repositories.js +0 -46
- package/dist/commands/api/repositories.js.map +1 -1
- package/dist/commands/api/upwork-proposal-submissions.d.ts +2 -0
- package/dist/commands/api/upwork-proposal-submissions.js +176 -0
- package/dist/commands/api/upwork-proposal-submissions.js.map +1 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/lib/project-context.d.ts +28 -21
- package/dist/lib/project-context.js +125 -95
- package/dist/lib/project-context.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,7 +1,24 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
1
3
|
import { Command } from "commander";
|
|
2
4
|
import chalk from "chalk";
|
|
3
5
|
import { api } from "../../lib/api.js";
|
|
4
6
|
import { printList, printDetail, handleError } from "../../lib/format.js";
|
|
7
|
+
const MIME_BY_EXTENSION = {
|
|
8
|
+
".mp4": "video/mp4",
|
|
9
|
+
".mov": "video/quicktime",
|
|
10
|
+
".webm": "video/webm",
|
|
11
|
+
".png": "image/png",
|
|
12
|
+
".jpg": "image/jpeg",
|
|
13
|
+
".jpeg": "image/jpeg",
|
|
14
|
+
".gif": "image/gif",
|
|
15
|
+
".webp": "image/webp",
|
|
16
|
+
".pdf": "application/pdf",
|
|
17
|
+
".md": "text/markdown",
|
|
18
|
+
".txt": "text/plain",
|
|
19
|
+
".json": "application/json",
|
|
20
|
+
".zip": "application/zip",
|
|
21
|
+
};
|
|
5
22
|
const listCommand = new Command("list")
|
|
6
23
|
.description("List files")
|
|
7
24
|
.option("--entity-type <type>", "Filter by entity type")
|
|
@@ -86,11 +103,63 @@ const uploadUrlCommand = new Command("upload-url")
|
|
|
86
103
|
console.log(JSON.stringify(data, null, 2));
|
|
87
104
|
}
|
|
88
105
|
else {
|
|
89
|
-
console.log(chalk.green("✓"), `Upload URL ready for ${chalk.bold(data.name)} (${data.id})`);
|
|
106
|
+
console.log(chalk.green("✓"), `Upload URL ready for ${chalk.bold(data.file.name)} (${data.file.id})`);
|
|
90
107
|
console.log();
|
|
91
108
|
console.log(chalk.dim("Next:"));
|
|
92
109
|
console.log(chalk.dim(` 1. PUT the file bytes to:\n ${data.uploadUrl}`));
|
|
93
|
-
console.log(chalk.dim(` 2. itznexus file confirm ${data.id}`));
|
|
110
|
+
console.log(chalk.dim(` 2. itznexus file confirm ${data.file.id}`));
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
catch (err) {
|
|
114
|
+
handleError(err);
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
const uploadCommand = new Command("upload")
|
|
118
|
+
.description("Upload a local file in one step (requests the signed URL, uploads the bytes, confirms)")
|
|
119
|
+
.argument("<path>", "Path to the local file")
|
|
120
|
+
.option("--name <name>", "Stored file name (defaults to the local file name)")
|
|
121
|
+
.option("--mime-type <type>", "MIME type (detected from the extension when omitted)")
|
|
122
|
+
.option("--folder <id>", "Folder ID")
|
|
123
|
+
.option("--entity-type <type>", 'Entity type to attach to (e.g. "lead")')
|
|
124
|
+
.option("--entity-id <id>", "Entity ID to attach to")
|
|
125
|
+
.option("--json", "Output as JSON")
|
|
126
|
+
.action(async (filePath, opts) => {
|
|
127
|
+
try {
|
|
128
|
+
const absolute = path.resolve(filePath);
|
|
129
|
+
if (!fs.existsSync(absolute)) {
|
|
130
|
+
throw new Error(`File not found: ${absolute}`);
|
|
131
|
+
}
|
|
132
|
+
const bytes = fs.readFileSync(absolute);
|
|
133
|
+
const name = opts.name ?? path.basename(absolute);
|
|
134
|
+
const mimeType = opts.mimeType ??
|
|
135
|
+
MIME_BY_EXTENSION[path.extname(absolute).toLowerCase()] ??
|
|
136
|
+
"application/octet-stream";
|
|
137
|
+
const payload = {
|
|
138
|
+
name,
|
|
139
|
+
mimeType,
|
|
140
|
+
size: bytes.length,
|
|
141
|
+
};
|
|
142
|
+
if (opts.folder !== undefined)
|
|
143
|
+
payload.folderId = opts.folder;
|
|
144
|
+
if (opts.entityType !== undefined)
|
|
145
|
+
payload.entityType = opts.entityType;
|
|
146
|
+
if (opts.entityId !== undefined)
|
|
147
|
+
payload.entityId = opts.entityId;
|
|
148
|
+
const requested = await api.post("/files/upload-url", payload);
|
|
149
|
+
const uploadRes = await fetch(requested.uploadUrl, {
|
|
150
|
+
method: "PUT",
|
|
151
|
+
headers: { "Content-Type": mimeType },
|
|
152
|
+
body: bytes,
|
|
153
|
+
});
|
|
154
|
+
if (!uploadRes.ok) {
|
|
155
|
+
throw new Error(`Upload to storage failed: ${uploadRes.status} ${uploadRes.statusText}`);
|
|
156
|
+
}
|
|
157
|
+
const data = await api.post(`/files/${requested.file.id}/confirm`, {});
|
|
158
|
+
if (opts.json) {
|
|
159
|
+
console.log(JSON.stringify(data, null, 2));
|
|
160
|
+
}
|
|
161
|
+
else {
|
|
162
|
+
console.log(chalk.green("✓"), `Uploaded ${chalk.bold(data.name)} (${data.id}, ${data.size} bytes)`);
|
|
94
163
|
}
|
|
95
164
|
}
|
|
96
165
|
catch (err) {
|
|
@@ -159,6 +228,7 @@ export const fileCommand = new Command("file")
|
|
|
159
228
|
.description("Manage files")
|
|
160
229
|
.addCommand(listCommand)
|
|
161
230
|
.addCommand(getCommand)
|
|
231
|
+
.addCommand(uploadCommand)
|
|
162
232
|
.addCommand(uploadUrlCommand)
|
|
163
233
|
.addCommand(confirmCommand)
|
|
164
234
|
.addCommand(folderCommand)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"files.js","sourceRoot":"","sources":["../../../src/commands/api/files.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,GAAG,EAAE,MAAM,kBAAkB,CAAC;AACvC,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"files.js","sourceRoot":"","sources":["../../../src/commands/api/files.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import { Command } from "commander";
|
|
3
|
+
import chalk from "chalk";
|
|
4
|
+
import { api } from "../../lib/api.js";
|
|
5
|
+
import { printList, handleError } from "../../lib/format.js";
|
|
6
|
+
async function findByPath(projectId, filePath) {
|
|
7
|
+
const rows = await api.get(`/projects/${projectId}/agent-instructions`);
|
|
8
|
+
return rows.find((r) => r.path === filePath);
|
|
9
|
+
}
|
|
10
|
+
const listCommand = new Command("list")
|
|
11
|
+
.description("List the project's agent instruction files")
|
|
12
|
+
.argument("<id>", "Project ID or key (e.g. NEX)")
|
|
13
|
+
.option("--json", "Output as JSON")
|
|
14
|
+
.action(async (id, opts) => {
|
|
15
|
+
try {
|
|
16
|
+
const data = await api.get(`/projects/${id}/agent-instructions`);
|
|
17
|
+
printList(data, [
|
|
18
|
+
{ key: "path", label: "Path", width: 40 },
|
|
19
|
+
{ key: "template", label: "Template", width: 10 },
|
|
20
|
+
{ key: "name", label: "Name", width: 24 },
|
|
21
|
+
{ key: "id", label: "ID", width: 38 },
|
|
22
|
+
], opts);
|
|
23
|
+
}
|
|
24
|
+
catch (err) {
|
|
25
|
+
handleError(err);
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
const templatesCommand = new Command("templates")
|
|
29
|
+
.description("List the code-defined templates an instruction file can start from")
|
|
30
|
+
.argument("<id>", "Project ID or key (e.g. NEX)")
|
|
31
|
+
.option("--json", "Output as JSON")
|
|
32
|
+
.action(async (id, opts) => {
|
|
33
|
+
try {
|
|
34
|
+
const data = await api.get(`/projects/${id}/agent-instructions/templates`);
|
|
35
|
+
printList(data, [
|
|
36
|
+
{ key: "name", label: "Name", width: 10 },
|
|
37
|
+
{ key: "title", label: "Default title", width: 24 },
|
|
38
|
+
{ key: "titleOverridable", label: "Name allowed", width: 12 },
|
|
39
|
+
{ key: "description", label: "Description", width: 60 },
|
|
40
|
+
], opts);
|
|
41
|
+
}
|
|
42
|
+
catch (err) {
|
|
43
|
+
handleError(err);
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
const setCommand = new Command("set")
|
|
47
|
+
.description("Create or update the agent instruction file at a path. Only the provided options change; content and template are independent.")
|
|
48
|
+
.argument("<id>", "Project ID or key (e.g. NEX)")
|
|
49
|
+
.argument("<path>", "File path relative to the project folder (root files like CLAUDE.md, or <repo>/CLAUDE.local.md)")
|
|
50
|
+
.option("--template <name>", 'Template to render above the content (see `instructions templates`); "none" to clear')
|
|
51
|
+
.option("--name <name>", 'File title, rendered as the "# ..." heading; needs a template with an overridable title; "none" to clear')
|
|
52
|
+
.option("--content <text>", "Free-text content appended below the template")
|
|
53
|
+
.option("--content-file <file>", "Read the content from a local file")
|
|
54
|
+
.option("--json", "Output as JSON")
|
|
55
|
+
.action(async (id, filePath, opts) => {
|
|
56
|
+
if (opts.content !== undefined && opts.contentFile !== undefined) {
|
|
57
|
+
console.error(chalk.red("✗"), "Provide --content or --content-file, not both.");
|
|
58
|
+
process.exit(1);
|
|
59
|
+
}
|
|
60
|
+
let content;
|
|
61
|
+
if (opts.contentFile !== undefined) {
|
|
62
|
+
if (!fs.existsSync(opts.contentFile)) {
|
|
63
|
+
console.error(chalk.red("✗"), `File not found: ${opts.contentFile}`);
|
|
64
|
+
process.exit(1);
|
|
65
|
+
}
|
|
66
|
+
content = fs.readFileSync(opts.contentFile, "utf-8").trim() || null;
|
|
67
|
+
}
|
|
68
|
+
else if (opts.content !== undefined) {
|
|
69
|
+
content = opts.content.trim() || null;
|
|
70
|
+
}
|
|
71
|
+
const template = opts.template === undefined
|
|
72
|
+
? undefined
|
|
73
|
+
: opts.template === "none"
|
|
74
|
+
? null
|
|
75
|
+
: opts.template;
|
|
76
|
+
const name = opts.name === undefined
|
|
77
|
+
? undefined
|
|
78
|
+
: opts.name === "none"
|
|
79
|
+
? null
|
|
80
|
+
: opts.name;
|
|
81
|
+
if (template === undefined &&
|
|
82
|
+
name === undefined &&
|
|
83
|
+
content === undefined) {
|
|
84
|
+
console.error(chalk.red("✗"), "Nothing to set: provide --template, --name, --content, or --content-file.");
|
|
85
|
+
process.exit(1);
|
|
86
|
+
}
|
|
87
|
+
try {
|
|
88
|
+
const existing = await findByPath(id, filePath);
|
|
89
|
+
const data = existing
|
|
90
|
+
? await api.post(`/projects/${id}/agent-instructions/${existing.id}`, { template, name, content })
|
|
91
|
+
: await api.post(`/projects/${id}/agent-instructions`, {
|
|
92
|
+
path: filePath,
|
|
93
|
+
template: template ?? undefined,
|
|
94
|
+
name: name ?? undefined,
|
|
95
|
+
content: content ?? undefined,
|
|
96
|
+
});
|
|
97
|
+
if (opts.json)
|
|
98
|
+
console.log(JSON.stringify(data, null, 2));
|
|
99
|
+
else
|
|
100
|
+
console.log(chalk.green("✓"), `${existing ? "Updated" : "Created"} ${chalk.bold(data.path)}${data.template ? ` (template: ${data.template})` : ""}. Run \`itznexus project sync\` in the project folder to materialize it.`);
|
|
101
|
+
}
|
|
102
|
+
catch (err) {
|
|
103
|
+
handleError(err);
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
const deleteCommand = new Command("delete")
|
|
107
|
+
.description("Delete the agent instruction file at a path; the local file disappears on the next sync")
|
|
108
|
+
.argument("<id>", "Project ID or key (e.g. NEX)")
|
|
109
|
+
.argument("<path>", "File path, e.g. itznexus-api/CLAUDE.local.md")
|
|
110
|
+
.option("--json", "Output as JSON")
|
|
111
|
+
.action(async (id, filePath, opts) => {
|
|
112
|
+
try {
|
|
113
|
+
const existing = await findByPath(id, filePath);
|
|
114
|
+
if (!existing) {
|
|
115
|
+
console.error(chalk.red("✗"), `No agent instruction file at "${filePath}".`);
|
|
116
|
+
process.exit(1);
|
|
117
|
+
}
|
|
118
|
+
const data = await api.delete(`/projects/${id}/agent-instructions/${existing.id}`);
|
|
119
|
+
if (opts.json)
|
|
120
|
+
console.log(JSON.stringify(data, null, 2));
|
|
121
|
+
else
|
|
122
|
+
console.log(chalk.green("✓"), `Deleted ${chalk.bold(filePath)}. Run \`itznexus project sync\` to remove the local file.`);
|
|
123
|
+
}
|
|
124
|
+
catch (err) {
|
|
125
|
+
handleError(err);
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
export const instructionsCommand = new Command("instructions")
|
|
129
|
+
.description("Manage the project's agent instruction files (path-addressed, optionally template-based), materialized by `itznexus project sync`")
|
|
130
|
+
.addCommand(listCommand)
|
|
131
|
+
.addCommand(templatesCommand)
|
|
132
|
+
.addCommand(setCommand)
|
|
133
|
+
.addCommand(deleteCommand);
|
|
134
|
+
//# sourceMappingURL=project-instructions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project-instructions.js","sourceRoot":"","sources":["../../../src/commands/api/project-instructions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,GAAG,EAAE,MAAM,kBAAkB,CAAC;AACvC,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAyB7D,KAAK,UAAU,UAAU,CACvB,SAAiB,EACjB,QAAgB;IAEhB,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,GAAG,CACxB,aAAa,SAAS,qBAAqB,CAC5C,CAAC;IACF,OAAO,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC;AAC/C,CAAC;AAED,MAAM,WAAW,GAAG,IAAI,OAAO,CAAC,MAAM,CAAC;KACpC,WAAW,CAAC,4CAA4C,CAAC;KACzD,QAAQ,CAAC,MAAM,EAAE,8BAA8B,CAAC;KAChD,MAAM,CAAC,QAAQ,EAAE,gBAAgB,CAAC;KAClC,MAAM,CAAC,KAAK,EAAE,EAAU,EAAE,IAAwB,EAAE,EAAE;IACrD,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,GAAG,CACxB,aAAa,EAAE,qBAAqB,CACrC,CAAC;QACF,SAAS,CACP,IAA4C,EAC5C;YACE,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,EAAE;YACzC,EAAE,GAAG,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,EAAE,EAAE;YACjD,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,EAAE;YACzC,EAAE,GAAG,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,EAAE;SACtC,EACD,IAAI,CACL,CAAC;IACJ,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,WAAW,CAAC,GAAG,CAAC,CAAC;IACnB,CAAC;AACH,CAAC,CAAC,CAAC;AAEL,MAAM,gBAAgB,GAAG,IAAI,OAAO,CAAC,WAAW,CAAC;KAC9C,WAAW,CACV,oEAAoE,CACrE;KACA,QAAQ,CAAC,MAAM,EAAE,8BAA8B,CAAC;KAChD,MAAM,CAAC,QAAQ,EAAE,gBAAgB,CAAC;KAClC,MAAM,CAAC,KAAK,EAAE,EAAU,EAAE,IAAwB,EAAE,EAAE;IACrD,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,GAAG,CACxB,aAAa,EAAE,+BAA+B,CAC/C,CAAC;QACF,SAAS,CACP,IAA4C,EAC5C;YACE,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,EAAE;YACzC,EAAE,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,eAAe,EAAE,KAAK,EAAE,EAAE,EAAE;YACnD,EAAE,GAAG,EAAE,kBAAkB,EAAE,KAAK,EAAE,cAAc,EAAE,KAAK,EAAE,EAAE,EAAE;YAC7D,EAAE,GAAG,EAAE,aAAa,EAAE,KAAK,EAAE,aAAa,EAAE,KAAK,EAAE,EAAE,EAAE;SACxD,EACD,IAAI,CACL,CAAC;IACJ,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,WAAW,CAAC,GAAG,CAAC,CAAC;IACnB,CAAC;AACH,CAAC,CAAC,CAAC;AAEL,MAAM,UAAU,GAAG,IAAI,OAAO,CAAC,KAAK,CAAC;KAClC,WAAW,CACV,gIAAgI,CACjI;KACA,QAAQ,CAAC,MAAM,EAAE,8BAA8B,CAAC;KAChD,QAAQ,CACP,QAAQ,EACR,iGAAiG,CAClG;KACA,MAAM,CACL,mBAAmB,EACnB,sFAAsF,CACvF;KACA,MAAM,CACL,eAAe,EACf,0GAA0G,CAC3G;KACA,MAAM,CAAC,kBAAkB,EAAE,+CAA+C,CAAC;KAC3E,MAAM,CAAC,uBAAuB,EAAE,oCAAoC,CAAC;KACrE,MAAM,CAAC,QAAQ,EAAE,gBAAgB,CAAC;KAClC,MAAM,CACL,KAAK,EACH,EAAU,EACV,QAAgB,EAChB,IAMC,EACD,EAAE;IACF,IAAI,IAAI,CAAC,OAAO,KAAK,SAAS,IAAI,IAAI,CAAC,WAAW,KAAK,SAAS,EAAE,CAAC;QACjE,OAAO,CAAC,KAAK,CACX,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,EACd,gDAAgD,CACjD,CAAC;QACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,IAAI,OAAkC,CAAC;IACvC,IAAI,IAAI,CAAC,WAAW,KAAK,SAAS,EAAE,CAAC;QACnC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC;YACrC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,mBAAmB,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;YACrE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QACD,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC,IAAI,EAAE,IAAI,IAAI,CAAC;IACtE,CAAC;SAAM,IAAI,IAAI,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;QACtC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,IAAI,CAAC;IACxC,CAAC;IAED,MAAM,QAAQ,GACZ,IAAI,CAAC,QAAQ,KAAK,SAAS;QACzB,CAAC,CAAC,SAAS;QACX,CAAC,CAAC,IAAI,CAAC,QAAQ,KAAK,MAAM;YACxB,CAAC,CAAC,IAAI;YACN,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC;IACtB,MAAM,IAAI,GACR,IAAI,CAAC,IAAI,KAAK,SAAS;QACrB,CAAC,CAAC,SAAS;QACX,CAAC,CAAC,IAAI,CAAC,IAAI,KAAK,MAAM;YACpB,CAAC,CAAC,IAAI;YACN,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;IAElB,IACE,QAAQ,KAAK,SAAS;QACtB,IAAI,KAAK,SAAS;QAClB,OAAO,KAAK,SAAS,EACrB,CAAC;QACD,OAAO,CAAC,KAAK,CACX,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,EACd,2EAA2E,CAC5E,CAAC;QACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,UAAU,CAAC,EAAE,EAAE,QAAQ,CAAC,CAAC;QAChD,MAAM,IAAI,GAAG,QAAQ;YACnB,CAAC,CAAC,MAAM,GAAG,CAAC,IAAI,CACZ,aAAa,EAAE,uBAAuB,QAAQ,CAAC,EAAE,EAAE,EACnD,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,EAAE,CAC5B;YACH,CAAC,CAAC,MAAM,GAAG,CAAC,IAAI,CACZ,aAAa,EAAE,qBAAqB,EACpC;gBACE,IAAI,EAAE,QAAQ;gBACd,QAAQ,EAAE,QAAQ,IAAI,SAAS;gBAC/B,IAAI,EAAE,IAAI,IAAI,SAAS;gBACvB,OAAO,EAAE,OAAO,IAAI,SAAS;aAC9B,CACF,CAAC;QACN,IAAI,IAAI,CAAC,IAAI;YAAE,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;;YAExD,OAAO,CAAC,GAAG,CACT,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,EAChB,GAAG,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,IAAI,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,eAAe,IAAI,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC,EAAE,0EAA0E,CAC9L,CAAC;IACN,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,WAAW,CAAC,GAAG,CAAC,CAAC;IACnB,CAAC;AACH,CAAC,CACF,CAAC;AAEJ,MAAM,aAAa,GAAG,IAAI,OAAO,CAAC,QAAQ,CAAC;KACxC,WAAW,CACV,yFAAyF,CAC1F;KACA,QAAQ,CAAC,MAAM,EAAE,8BAA8B,CAAC;KAChD,QAAQ,CAAC,QAAQ,EAAE,8CAA8C,CAAC;KAClE,MAAM,CAAC,QAAQ,EAAE,gBAAgB,CAAC;KAClC,MAAM,CAAC,KAAK,EAAE,EAAU,EAAE,QAAgB,EAAE,IAAwB,EAAE,EAAE;IACvE,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,UAAU,CAAC,EAAE,EAAE,QAAQ,CAAC,CAAC;QAChD,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,OAAO,CAAC,KAAK,CACX,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,EACd,iCAAiC,QAAQ,IAAI,CAC9C,CAAC;YACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QACD,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,MAAM,CAC3B,aAAa,EAAE,uBAAuB,QAAQ,CAAC,EAAE,EAAE,CACpD,CAAC;QACF,IAAI,IAAI,CAAC,IAAI;YAAE,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;;YAExD,OAAO,CAAC,GAAG,CACT,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,EAChB,WAAW,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,2DAA2D,CAC3F,CAAC;IACN,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,WAAW,CAAC,GAAG,CAAC,CAAC;IACnB,CAAC;AACH,CAAC,CAAC,CAAC;AAEL,MAAM,CAAC,MAAM,mBAAmB,GAAG,IAAI,OAAO,CAAC,cAAc,CAAC;KAC3D,WAAW,CACV,mIAAmI,CACpI;KACA,UAAU,CAAC,WAAW,CAAC;KACvB,UAAU,CAAC,gBAAgB,CAAC;KAC5B,UAAU,CAAC,UAAU,CAAC;KACtB,UAAU,CAAC,aAAa,CAAC,CAAC"}
|
|
@@ -5,7 +5,8 @@ import { Command } from "commander";
|
|
|
5
5
|
import chalk from "chalk";
|
|
6
6
|
import { api } from "../../lib/api.js";
|
|
7
7
|
import { printList, printDetail, handleError } from "../../lib/format.js";
|
|
8
|
-
import {
|
|
8
|
+
import { cleanupStaleInstructionFiles, fetchProjectBySlug, fetchRenderedInstructions, findInstructionConflicts, syncInstructionFiles, } from "../../lib/project-context.js";
|
|
9
|
+
import { instructionsCommand } from "./project-instructions.js";
|
|
9
10
|
const listCommand = new Command("list")
|
|
10
11
|
.description("List all projects")
|
|
11
12
|
.option("--status <status>", "Filter by status (draft, active, paused, completed, cancelled)")
|
|
@@ -26,9 +27,10 @@ const listCommand = new Command("list")
|
|
|
26
27
|
printList(data, [
|
|
27
28
|
{ key: "name", label: "Name", width: 30 },
|
|
28
29
|
{ key: "key", label: "Key", width: 12 },
|
|
30
|
+
{ key: "organizationName", label: "Organization", width: 20 },
|
|
29
31
|
{ key: "status", label: "Status", width: 12 },
|
|
30
32
|
{ key: "sprintCount", label: "Sprints", width: 10 },
|
|
31
|
-
{ key: "
|
|
33
|
+
{ key: "lastActivityAt", label: "Activity", width: 24 },
|
|
32
34
|
], opts);
|
|
33
35
|
}
|
|
34
36
|
catch (err) {
|
|
@@ -215,43 +217,6 @@ const technicalDescriptionCommand = new Command("technical-description")
|
|
|
215
217
|
handleError(err);
|
|
216
218
|
}
|
|
217
219
|
});
|
|
218
|
-
const projectSetInstructionsCommand = new Command("set-instructions")
|
|
219
|
-
.description("Set the project's agent instructions, rendered verbatim as the <instructions> section of the agent context (root CLAUDE.md)")
|
|
220
|
-
.argument("<id>", "Project ID or key (e.g. NEX)")
|
|
221
|
-
.argument("[instructions]", "Instruction text (or use --file / --clear)")
|
|
222
|
-
.option("--file <path>", "Read instructions from a file")
|
|
223
|
-
.option("--clear", "Clear the instructions")
|
|
224
|
-
.option("--json", "Output as JSON")
|
|
225
|
-
.action(async (id, instructions, opts) => {
|
|
226
|
-
const sources = [instructions, opts.file, opts.clear].filter((v) => v !== undefined && v !== false);
|
|
227
|
-
if (sources.length !== 1) {
|
|
228
|
-
console.error(chalk.red("✗"), "Provide exactly one of: instruction text, --file <path>, or --clear.");
|
|
229
|
-
process.exit(1);
|
|
230
|
-
}
|
|
231
|
-
let value = null;
|
|
232
|
-
if (opts.file) {
|
|
233
|
-
if (!fs.existsSync(opts.file)) {
|
|
234
|
-
console.error(chalk.red("✗"), `File not found: ${opts.file}`);
|
|
235
|
-
process.exit(1);
|
|
236
|
-
}
|
|
237
|
-
value = fs.readFileSync(opts.file, "utf-8").trim() || null;
|
|
238
|
-
}
|
|
239
|
-
else if (instructions !== undefined) {
|
|
240
|
-
value = instructions.trim() || null;
|
|
241
|
-
}
|
|
242
|
-
try {
|
|
243
|
-
const data = await api.post(`/projects/${id}/agent-instructions`, { agentInstructions: value });
|
|
244
|
-
if (opts.json)
|
|
245
|
-
console.log(JSON.stringify(data, null, 2));
|
|
246
|
-
else
|
|
247
|
-
console.log(chalk.green("✓"), value
|
|
248
|
-
? `Agent instructions set for ${chalk.bold(data.name)} (${value.length} chars). Run \`itznexus project sync\` in the project folder to refresh CLAUDE.md.`
|
|
249
|
-
: `Agent instructions cleared for ${chalk.bold(data.name)}. Run \`itznexus project sync\` to refresh CLAUDE.md.`);
|
|
250
|
-
}
|
|
251
|
-
catch (err) {
|
|
252
|
-
handleError(err);
|
|
253
|
-
}
|
|
254
|
-
});
|
|
255
220
|
const organizationCommand = new Command("organization")
|
|
256
221
|
.description("Set project organization")
|
|
257
222
|
.argument("<id>", "Project ID or key (e.g. NEX)")
|
|
@@ -458,32 +423,27 @@ const dossierCommand = new Command("dossier")
|
|
|
458
423
|
handleError(err);
|
|
459
424
|
}
|
|
460
425
|
});
|
|
461
|
-
// Prints per-
|
|
462
|
-
//
|
|
463
|
-
function
|
|
426
|
+
// Prints per-file sync outcomes and returns true when any file errored
|
|
427
|
+
// (tracked file, ignore rule not applying), so callers can exit non-zero.
|
|
428
|
+
function reportInstructionFiles(results, removed) {
|
|
464
429
|
let hasError = false;
|
|
465
430
|
for (const r of results) {
|
|
466
431
|
switch (r.status) {
|
|
467
432
|
case "written":
|
|
468
|
-
console.log(chalk.green("
|
|
469
|
-
break;
|
|
470
|
-
case "removed":
|
|
471
|
-
console.log(chalk.green("✓"), `${r.repo}/CLAUDE.local.md removed (instructions cleared in Nexus)`);
|
|
433
|
+
console.log(chalk.green("\u2713"), `${r.path} synced${r.gitignoreUpdated ? " (.gitignore updated)" : ""}`);
|
|
472
434
|
break;
|
|
473
435
|
case "skipped-no-folder":
|
|
474
|
-
console.error(chalk.yellow("!"), `${r.
|
|
475
|
-
break;
|
|
476
|
-
case "skipped-not-git":
|
|
477
|
-
console.error(chalk.yellow("!"), `${r.repo}: folder exists but is not a git repo, skipping CLAUDE.local.md`);
|
|
436
|
+
console.error(chalk.yellow("!"), `${r.path}: repo folder is not cloned here, skipping`);
|
|
478
437
|
break;
|
|
479
438
|
case "error":
|
|
480
439
|
hasError = true;
|
|
481
|
-
console.error(chalk.red("
|
|
482
|
-
break;
|
|
483
|
-
case "unchanged":
|
|
440
|
+
console.error(chalk.red("\u2717"), `${r.path}: ${r.error}`);
|
|
484
441
|
break;
|
|
485
442
|
}
|
|
486
443
|
}
|
|
444
|
+
for (const rel of removed) {
|
|
445
|
+
console.log(chalk.green("\u2713"), `${rel} removed (deleted in Nexus)`);
|
|
446
|
+
}
|
|
487
447
|
return hasError;
|
|
488
448
|
}
|
|
489
449
|
function git(args, cwd) {
|
|
@@ -495,27 +455,32 @@ function cloneUrl(repo, https) {
|
|
|
495
455
|
: `git@github.com:${repo.owner}/${repo.name}.git`;
|
|
496
456
|
}
|
|
497
457
|
const syncCommand = new Command("sync")
|
|
498
|
-
.description("Sync the project folder from Nexus: clone missing repositories
|
|
458
|
+
.description("Sync the project folder from Nexus: clone missing repositories and materialize the project's agent instruction files (root CLAUDE.md, gitignored CLAUDE.local.md inside repos). Nexus-managed files are overwritten and files deleted in Nexus are removed; existing repos' git state is never touched. Run inside the project folder; slug defaults to the folder name.")
|
|
499
459
|
.argument("[slug]", "Project slug (defaults to the current folder name)")
|
|
500
460
|
.option("--https", "Clone over HTTPS instead of SSH")
|
|
501
461
|
.option("--all", "Include archived repositories")
|
|
502
|
-
.option("--force", "Overwrite
|
|
462
|
+
.option("--force", "Overwrite instruction files that exist but are not Nexus-managed")
|
|
503
463
|
.option("--json", "Output as JSON")
|
|
504
464
|
.action(async (slug, opts) => {
|
|
505
465
|
const cwd = process.cwd();
|
|
506
466
|
const resolvedSlug = (slug ?? path.basename(cwd)).trim();
|
|
507
467
|
if (!resolvedSlug) {
|
|
508
|
-
console.error(chalk.red("
|
|
509
|
-
process.exit(1);
|
|
510
|
-
}
|
|
511
|
-
// Fail fast before cloning anything: never clobber a hand-written CLAUDE.md.
|
|
512
|
-
if (!opts.force && hasHandWrittenClaudeMd(cwd)) {
|
|
513
|
-
console.error(chalk.red("✗"), CLAUDE_MD_CONFLICT_MESSAGE);
|
|
468
|
+
console.error(chalk.red("\u2717"), "Could not determine a project slug.");
|
|
514
469
|
process.exit(1);
|
|
515
470
|
}
|
|
516
471
|
try {
|
|
517
472
|
const project = await fetchProjectBySlug(resolvedSlug);
|
|
518
|
-
const
|
|
473
|
+
const files = await fetchRenderedInstructions(project.id);
|
|
474
|
+
// Fail fast before cloning anything: never clobber hand-written files.
|
|
475
|
+
if (!opts.force) {
|
|
476
|
+
const conflicts = findInstructionConflicts(cwd, files);
|
|
477
|
+
if (conflicts.length > 0) {
|
|
478
|
+
for (const rel of conflicts) {
|
|
479
|
+
console.error(chalk.red("\u2717"), `${rel} exists and is not Nexus-managed. Pass --force to overwrite.`);
|
|
480
|
+
}
|
|
481
|
+
process.exit(1);
|
|
482
|
+
}
|
|
483
|
+
}
|
|
519
484
|
const archivedSkipped = opts.all
|
|
520
485
|
? []
|
|
521
486
|
: project.repositories.filter((r) => r.archived);
|
|
@@ -530,7 +495,7 @@ const syncCommand = new Command("sync")
|
|
|
530
495
|
if (fs.existsSync(path.join(cwd, repo.name)))
|
|
531
496
|
continue;
|
|
532
497
|
if (!opts.json)
|
|
533
|
-
console.log(chalk.dim(`\n
|
|
498
|
+
console.log(chalk.dim(`\n\u2192 ${repo.name} (clone)`));
|
|
534
499
|
if (git(["clone", cloneUrl(repo, !!opts.https), repo.name], cwd)) {
|
|
535
500
|
cloned.push(repo.name);
|
|
536
501
|
}
|
|
@@ -538,13 +503,9 @@ const syncCommand = new Command("sync")
|
|
|
538
503
|
failed.push(repo.name);
|
|
539
504
|
}
|
|
540
505
|
}
|
|
541
|
-
const
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
}
|
|
545
|
-
const repoInstructions = syncRepoInstructions(cwd, repos);
|
|
546
|
-
const hasError = failed.length > 0 ||
|
|
547
|
-
repoInstructions.some((r) => r.status === "error");
|
|
506
|
+
const fileResults = syncInstructionFiles(cwd, files);
|
|
507
|
+
const removed = cleanupStaleInstructionFiles(cwd, files, repos.map((r) => r.name));
|
|
508
|
+
const hasError = failed.length > 0 || fileResults.some((r) => r.status === "error");
|
|
548
509
|
const label = project.key ?? project.name;
|
|
549
510
|
if (opts.json) {
|
|
550
511
|
console.log(JSON.stringify({
|
|
@@ -556,24 +517,25 @@ const syncCommand = new Command("sync")
|
|
|
556
517
|
cloned,
|
|
557
518
|
failed,
|
|
558
519
|
archivedSkipped: archivedSkipped.map((r) => r.name),
|
|
559
|
-
|
|
560
|
-
|
|
520
|
+
files: fileResults,
|
|
521
|
+
removed,
|
|
561
522
|
}));
|
|
562
523
|
if (hasError)
|
|
563
524
|
process.exitCode = 1;
|
|
564
525
|
return;
|
|
565
526
|
}
|
|
566
|
-
console.log(chalk.green("\n
|
|
527
|
+
console.log(chalk.green("\n\u2713"), `Synced ${chalk.bold(label)} in ${cwd}`);
|
|
528
|
+
const written = fileResults.filter((r) => r.status === "written").length;
|
|
567
529
|
const parts = [
|
|
568
|
-
|
|
530
|
+
`${written}/${files.length} instruction files`,
|
|
569
531
|
`${cloned.length} cloned`,
|
|
570
532
|
];
|
|
571
533
|
if (failed.length)
|
|
572
534
|
parts.push(chalk.red(`${failed.length} clone failed`));
|
|
573
535
|
if (archivedSkipped.length)
|
|
574
536
|
parts.push(chalk.dim(`${archivedSkipped.length} archived (use --all)`));
|
|
575
|
-
console.log(chalk.dim(` ${parts.join("
|
|
576
|
-
|
|
537
|
+
console.log(chalk.dim(` ${parts.join(" \u00b7 ")}`));
|
|
538
|
+
reportInstructionFiles(fileResults, removed);
|
|
577
539
|
if (hasError)
|
|
578
540
|
process.exitCode = 1;
|
|
579
541
|
}
|
|
@@ -1013,7 +975,7 @@ export const projectCommand = new Command("project")
|
|
|
1013
975
|
.addCommand(nameCommand)
|
|
1014
976
|
.addCommand(descriptionCommand)
|
|
1015
977
|
.addCommand(technicalDescriptionCommand)
|
|
1016
|
-
.addCommand(
|
|
978
|
+
.addCommand(instructionsCommand)
|
|
1017
979
|
.addCommand(organizationCommand)
|
|
1018
980
|
.addCommand(personCommand)
|
|
1019
981
|
.addCommand(leadCommand)
|