@hechura/noreaster-cli 0.1.1 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/docs.js +63 -2
- package/dist/commands/draft-runs.js +44 -0
- package/dist/commands/features.js +67 -0
- package/dist/commands/my-work.js +13 -0
- package/dist/commands/reviews.js +73 -0
- package/dist/commands/skill.js +47 -0
- package/dist/commands/tasks.js +24 -0
- package/dist/document-templates.js +327 -0
- package/dist/index.js +11 -1
- package/package.json +9 -6
- package/skills/hechura-manager-noreaster/SKILL.md +225 -0
package/dist/commands/docs.js
CHANGED
|
@@ -2,14 +2,32 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.registerDocumentCommands = registerDocumentCommands;
|
|
4
4
|
const http_1 = require("../http");
|
|
5
|
+
const document_templates_1 = require("../document-templates");
|
|
5
6
|
function registerDocumentCommands(parent) {
|
|
6
7
|
const docs = parent.command("docs").description("Manage documents");
|
|
8
|
+
docs
|
|
9
|
+
.command("template")
|
|
10
|
+
.description("Print the markdown template for a document type")
|
|
11
|
+
.argument("<docType>", "Document type (feature_description, design_spec, adr, ...)")
|
|
12
|
+
.action((docType) => {
|
|
13
|
+
const template = (0, document_templates_1.templateForDocType)(docType);
|
|
14
|
+
if (!template) {
|
|
15
|
+
console.error(`No template for doc type: ${docType}`);
|
|
16
|
+
process.exitCode = 1;
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
console.log(template);
|
|
20
|
+
});
|
|
7
21
|
docs
|
|
8
22
|
.command("list")
|
|
9
23
|
.description("List documents")
|
|
10
24
|
.option("--project-id <projectId>")
|
|
11
25
|
.option("--customer-id <customerId>")
|
|
12
26
|
.option("--prospect-id <prospectId>")
|
|
27
|
+
.option("--feature <featureId>")
|
|
28
|
+
.option("--type <docType>")
|
|
29
|
+
.option("--status <status>")
|
|
30
|
+
.option("--include-drafts", "Include non-approved documents")
|
|
13
31
|
.option("--limit <limit>")
|
|
14
32
|
.action(async (options) => {
|
|
15
33
|
const params = new URLSearchParams();
|
|
@@ -19,6 +37,14 @@ function registerDocumentCommands(parent) {
|
|
|
19
37
|
params.set("customer_id", options.customerId);
|
|
20
38
|
if (options.prospectId)
|
|
21
39
|
params.set("prospect_id", options.prospectId);
|
|
40
|
+
if (options.feature)
|
|
41
|
+
params.set("feature_id", options.feature);
|
|
42
|
+
if (options.type)
|
|
43
|
+
params.set("doc_type", options.type);
|
|
44
|
+
if (options.status)
|
|
45
|
+
params.set("status", options.status);
|
|
46
|
+
if (options.includeDrafts)
|
|
47
|
+
params.set("include_drafts", "true");
|
|
22
48
|
if (options.limit)
|
|
23
49
|
params.set("limit", options.limit);
|
|
24
50
|
const query = params.toString();
|
|
@@ -29,8 +55,13 @@ function registerDocumentCommands(parent) {
|
|
|
29
55
|
.command("get")
|
|
30
56
|
.description("Get document by id")
|
|
31
57
|
.argument("<id>")
|
|
32
|
-
.
|
|
33
|
-
|
|
58
|
+
.option("--include-drafts", "Include non-approved documents")
|
|
59
|
+
.action(async (id, options) => {
|
|
60
|
+
const params = new URLSearchParams();
|
|
61
|
+
if (options.includeDrafts)
|
|
62
|
+
params.set("include_drafts", "true");
|
|
63
|
+
const query = params.toString();
|
|
64
|
+
const result = await (0, http_1.apiRequest)((0, http_1.resolveConfig)(), "GET", `/api/agent/documents/${id}${query ? `?${query}` : ""}`);
|
|
34
65
|
console.log(JSON.stringify(result, null, 2));
|
|
35
66
|
});
|
|
36
67
|
docs
|
|
@@ -50,6 +81,36 @@ function registerDocumentCommands(parent) {
|
|
|
50
81
|
const result = await (0, http_1.apiRequest)((0, http_1.resolveConfig)(), "PATCH", `/api/agent/documents/${id}`, (0, http_1.parsePayload)(options.data));
|
|
51
82
|
console.log(JSON.stringify(result, null, 2));
|
|
52
83
|
});
|
|
84
|
+
docs
|
|
85
|
+
.command("transition")
|
|
86
|
+
.description("Transition document status")
|
|
87
|
+
.argument("<id>")
|
|
88
|
+
.requiredOption("--status <status>", "Target status")
|
|
89
|
+
.option("--summary <summary>", "Change summary")
|
|
90
|
+
.action(async (id, options) => {
|
|
91
|
+
const payload = { status: options.status };
|
|
92
|
+
if (options.summary)
|
|
93
|
+
payload.change_summary = options.summary;
|
|
94
|
+
const result = await (0, http_1.apiRequest)((0, http_1.resolveConfig)(), "PATCH", `/api/agent/documents/${id}`, payload);
|
|
95
|
+
console.log(JSON.stringify(result, null, 2));
|
|
96
|
+
});
|
|
97
|
+
docs
|
|
98
|
+
.command("revisions")
|
|
99
|
+
.description("List document revisions")
|
|
100
|
+
.argument("<id>")
|
|
101
|
+
.option("--include-drafts", "Include revisions for non-approved documents")
|
|
102
|
+
.option("--version <version>", "Fetch a specific revision version")
|
|
103
|
+
.action(async (id, options) => {
|
|
104
|
+
const params = new URLSearchParams();
|
|
105
|
+
if (options.includeDrafts)
|
|
106
|
+
params.set("include_drafts", "true");
|
|
107
|
+
const query = params.toString();
|
|
108
|
+
const path = options.version
|
|
109
|
+
? `/api/agent/documents/${id}/revisions/${options.version}`
|
|
110
|
+
: `/api/agent/documents/${id}/revisions`;
|
|
111
|
+
const result = await (0, http_1.apiRequest)((0, http_1.resolveConfig)(), "GET", `${path}${query ? `?${query}` : ""}`);
|
|
112
|
+
console.log(JSON.stringify(result, null, 2));
|
|
113
|
+
});
|
|
53
114
|
docs
|
|
54
115
|
.command("delete")
|
|
55
116
|
.description("Delete document")
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.registerDraftRunCommands = registerDraftRunCommands;
|
|
4
|
+
const http_1 = require("../http");
|
|
5
|
+
function registerDraftRunCommands(parent) {
|
|
6
|
+
const draftRuns = parent.command("draft-runs").description("Manage external draft work-item runs");
|
|
7
|
+
draftRuns
|
|
8
|
+
.command("list")
|
|
9
|
+
.description("List draft runs for a feature")
|
|
10
|
+
.argument("<featureId>")
|
|
11
|
+
.action(async (featureId) => {
|
|
12
|
+
const result = await (0, http_1.apiRequest)((0, http_1.resolveConfig)(), "GET", `/api/agent/features/${featureId}/draft-runs`);
|
|
13
|
+
console.log(JSON.stringify(result, null, 2));
|
|
14
|
+
});
|
|
15
|
+
draftRuns
|
|
16
|
+
.command("get")
|
|
17
|
+
.description("Get a draft run")
|
|
18
|
+
.argument("<featureId>")
|
|
19
|
+
.argument("<runId>")
|
|
20
|
+
.action(async (featureId, runId) => {
|
|
21
|
+
const result = await (0, http_1.apiRequest)((0, http_1.resolveConfig)(), "GET", `/api/agent/features/${featureId}/draft-runs/${runId}`);
|
|
22
|
+
console.log(JSON.stringify(result, null, 2));
|
|
23
|
+
});
|
|
24
|
+
draftRuns
|
|
25
|
+
.command("submit")
|
|
26
|
+
.description("Submit a draft run for a feature")
|
|
27
|
+
.argument("<featureId>")
|
|
28
|
+
.requiredOption("--data <json>", "JSON payload with source_document_id and items")
|
|
29
|
+
.action(async (featureId, options) => {
|
|
30
|
+
const result = await (0, http_1.apiRequest)((0, http_1.resolveConfig)(), "POST", `/api/agent/features/${featureId}/draft-runs`, (0, http_1.parsePayload)(options.data));
|
|
31
|
+
console.log(JSON.stringify(result, null, 2));
|
|
32
|
+
});
|
|
33
|
+
draftRuns
|
|
34
|
+
.command("apply")
|
|
35
|
+
.description("Apply a draft run (creates work items)")
|
|
36
|
+
.argument("<featureId>")
|
|
37
|
+
.argument("<runId>")
|
|
38
|
+
.option("--data <json>", "Optional edited items payload")
|
|
39
|
+
.action(async (featureId, runId, options) => {
|
|
40
|
+
const payload = options.data ? (0, http_1.parsePayload)(options.data) : {};
|
|
41
|
+
const result = await (0, http_1.apiRequest)((0, http_1.resolveConfig)(), "POST", `/api/agent/features/${featureId}/draft-runs/${runId}/apply`, payload);
|
|
42
|
+
console.log(JSON.stringify(result, null, 2));
|
|
43
|
+
});
|
|
44
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.registerFeatureCommands = registerFeatureCommands;
|
|
4
|
+
const http_1 = require("../http");
|
|
5
|
+
function registerFeatureCommands(parent) {
|
|
6
|
+
const features = parent.command("features").description("Manage features");
|
|
7
|
+
features
|
|
8
|
+
.command("list")
|
|
9
|
+
.description("List features")
|
|
10
|
+
.option("--project-id <projectId>")
|
|
11
|
+
.option("--status <status>")
|
|
12
|
+
.option("--limit <limit>")
|
|
13
|
+
.action(async (options) => {
|
|
14
|
+
const params = new URLSearchParams();
|
|
15
|
+
if (options.projectId)
|
|
16
|
+
params.set("project_id", options.projectId);
|
|
17
|
+
if (options.status)
|
|
18
|
+
params.set("status", options.status);
|
|
19
|
+
if (options.limit)
|
|
20
|
+
params.set("limit", options.limit);
|
|
21
|
+
const query = params.toString();
|
|
22
|
+
const result = await (0, http_1.apiRequest)((0, http_1.resolveConfig)(), "GET", `/api/agent/features${query ? `?${query}` : ""}`);
|
|
23
|
+
console.log(JSON.stringify(result, null, 2));
|
|
24
|
+
});
|
|
25
|
+
features
|
|
26
|
+
.command("get")
|
|
27
|
+
.description("Get feature by id")
|
|
28
|
+
.argument("<id>")
|
|
29
|
+
.action(async (id) => {
|
|
30
|
+
const result = await (0, http_1.apiRequest)((0, http_1.resolveConfig)(), "GET", `/api/agent/features/${id}`);
|
|
31
|
+
console.log(JSON.stringify(result, null, 2));
|
|
32
|
+
});
|
|
33
|
+
features
|
|
34
|
+
.command("create")
|
|
35
|
+
.description("Create feature")
|
|
36
|
+
.requiredOption("--data <json>", "JSON payload")
|
|
37
|
+
.action(async (options) => {
|
|
38
|
+
const result = await (0, http_1.apiRequest)((0, http_1.resolveConfig)(), "POST", "/api/agent/features", (0, http_1.parsePayload)(options.data));
|
|
39
|
+
console.log(JSON.stringify(result, null, 2));
|
|
40
|
+
});
|
|
41
|
+
features
|
|
42
|
+
.command("update")
|
|
43
|
+
.description("Update feature")
|
|
44
|
+
.argument("<id>")
|
|
45
|
+
.requiredOption("--data <json>", "JSON payload")
|
|
46
|
+
.action(async (id, options) => {
|
|
47
|
+
const result = await (0, http_1.apiRequest)((0, http_1.resolveConfig)(), "PATCH", `/api/agent/features/${id}`, (0, http_1.parsePayload)(options.data));
|
|
48
|
+
console.log(JSON.stringify(result, null, 2));
|
|
49
|
+
});
|
|
50
|
+
features
|
|
51
|
+
.command("transition")
|
|
52
|
+
.description("Transition feature status")
|
|
53
|
+
.argument("<id>")
|
|
54
|
+
.requiredOption("--status <status>", "Target status")
|
|
55
|
+
.action(async (id, options) => {
|
|
56
|
+
const result = await (0, http_1.apiRequest)((0, http_1.resolveConfig)(), "PATCH", `/api/agent/features/${id}`, { status: options.status });
|
|
57
|
+
console.log(JSON.stringify(result, null, 2));
|
|
58
|
+
});
|
|
59
|
+
features
|
|
60
|
+
.command("delete")
|
|
61
|
+
.description("Delete feature")
|
|
62
|
+
.argument("<id>")
|
|
63
|
+
.action(async (id) => {
|
|
64
|
+
const result = await (0, http_1.apiRequest)((0, http_1.resolveConfig)(), "DELETE", `/api/agent/features/${id}`);
|
|
65
|
+
console.log(JSON.stringify(result, null, 2));
|
|
66
|
+
});
|
|
67
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.registerMyWorkCommands = registerMyWorkCommands;
|
|
4
|
+
const http_1 = require("../http");
|
|
5
|
+
function registerMyWorkCommands(parent) {
|
|
6
|
+
parent
|
|
7
|
+
.command("my-work")
|
|
8
|
+
.description("Discover assigned work items, pending reviews, open gates, and draft runs")
|
|
9
|
+
.action(async () => {
|
|
10
|
+
const result = await (0, http_1.apiRequest)((0, http_1.resolveConfig)(), "GET", "/api/agent/my-work");
|
|
11
|
+
console.log(JSON.stringify(result, null, 2));
|
|
12
|
+
});
|
|
13
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.registerReviewCommands = registerReviewCommands;
|
|
4
|
+
const http_1 = require("../http");
|
|
5
|
+
function registerReviewCommands(parent) {
|
|
6
|
+
const reviews = parent.command("reviews").description("Manage document reviews");
|
|
7
|
+
reviews
|
|
8
|
+
.command("list")
|
|
9
|
+
.description("List reviews for a document")
|
|
10
|
+
.argument("<documentId>")
|
|
11
|
+
.action(async (documentId) => {
|
|
12
|
+
const result = await (0, http_1.apiRequest)((0, http_1.resolveConfig)(), "GET", `/api/agent/documents/${documentId}/reviews`);
|
|
13
|
+
console.log(JSON.stringify(result, null, 2));
|
|
14
|
+
});
|
|
15
|
+
reviews
|
|
16
|
+
.command("request")
|
|
17
|
+
.description("Request a review on a document")
|
|
18
|
+
.argument("<documentId>")
|
|
19
|
+
.option("--data <json>", "JSON payload with reviewers")
|
|
20
|
+
.action(async (documentId, options) => {
|
|
21
|
+
const payload = options.data ? (0, http_1.parsePayload)(options.data) : {};
|
|
22
|
+
const result = await (0, http_1.apiRequest)((0, http_1.resolveConfig)(), "POST", `/api/agent/documents/${documentId}/reviews`, payload);
|
|
23
|
+
console.log(JSON.stringify(result, null, 2));
|
|
24
|
+
});
|
|
25
|
+
reviews
|
|
26
|
+
.command("approve")
|
|
27
|
+
.description("Approve a review")
|
|
28
|
+
.argument("<documentId>")
|
|
29
|
+
.argument("<reviewId>")
|
|
30
|
+
.action(async (documentId, reviewId) => {
|
|
31
|
+
const result = await (0, http_1.apiRequest)((0, http_1.resolveConfig)(), "PATCH", `/api/agent/documents/${documentId}/reviews/${reviewId}`, { action: "approve" });
|
|
32
|
+
console.log(JSON.stringify(result, null, 2));
|
|
33
|
+
});
|
|
34
|
+
reviews
|
|
35
|
+
.command("request-changes")
|
|
36
|
+
.description("Request changes on a review")
|
|
37
|
+
.argument("<documentId>")
|
|
38
|
+
.argument("<reviewId>")
|
|
39
|
+
.action(async (documentId, reviewId) => {
|
|
40
|
+
const result = await (0, http_1.apiRequest)((0, http_1.resolveConfig)(), "PATCH", `/api/agent/documents/${documentId}/reviews/${reviewId}`, { action: "request_changes" });
|
|
41
|
+
console.log(JSON.stringify(result, null, 2));
|
|
42
|
+
});
|
|
43
|
+
reviews
|
|
44
|
+
.command("check")
|
|
45
|
+
.description("Tick a checklist item")
|
|
46
|
+
.argument("<documentId>")
|
|
47
|
+
.argument("<reviewId>")
|
|
48
|
+
.argument("<itemKey>")
|
|
49
|
+
.option("--unchecked", "Mark item unchecked")
|
|
50
|
+
.action(async (documentId, reviewId, itemKey, options) => {
|
|
51
|
+
const result = await (0, http_1.apiRequest)((0, http_1.resolveConfig)(), "PATCH", `/api/agent/documents/${documentId}/reviews/${reviewId}`, { action: "check", item_key: itemKey, checked: !options.unchecked });
|
|
52
|
+
console.log(JSON.stringify(result, null, 2));
|
|
53
|
+
});
|
|
54
|
+
reviews
|
|
55
|
+
.command("comment")
|
|
56
|
+
.description("Add a comment to a document")
|
|
57
|
+
.argument("<documentId>")
|
|
58
|
+
.requiredOption("--body <text>", "Comment body")
|
|
59
|
+
.option("--review-id <reviewId>")
|
|
60
|
+
.action(async (documentId, options) => {
|
|
61
|
+
const result = await (0, http_1.apiRequest)((0, http_1.resolveConfig)(), "POST", `/api/agent/documents/${documentId}/comments`, { body: options.body, review_id: options.reviewId ?? null });
|
|
62
|
+
console.log(JSON.stringify(result, null, 2));
|
|
63
|
+
});
|
|
64
|
+
reviews
|
|
65
|
+
.command("resolve-comment")
|
|
66
|
+
.description("Resolve a comment")
|
|
67
|
+
.argument("<documentId>")
|
|
68
|
+
.argument("<commentId>")
|
|
69
|
+
.action(async (documentId, commentId) => {
|
|
70
|
+
const result = await (0, http_1.apiRequest)((0, http_1.resolveConfig)(), "PATCH", `/api/agent/documents/${documentId}/comments/${commentId}`, { action: "resolve" });
|
|
71
|
+
console.log(JSON.stringify(result, null, 2));
|
|
72
|
+
});
|
|
73
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.registerSkillCommands = registerSkillCommands;
|
|
4
|
+
const node_fs_1 = require("node:fs");
|
|
5
|
+
const node_os_1 = require("node:os");
|
|
6
|
+
const node_path_1 = require("node:path");
|
|
7
|
+
function resolvePackagedSkillPath() {
|
|
8
|
+
const candidates = [
|
|
9
|
+
(0, node_path_1.join)(__dirname, "../../skills/hechura-manager-noreaster/SKILL.md"),
|
|
10
|
+
(0, node_path_1.join)(__dirname, "../../../.agents/skills/hechura-manager-noreaster/SKILL.md"),
|
|
11
|
+
(0, node_path_1.join)(process.cwd(), "packages/noreaster-cli/skills/hechura-manager-noreaster/SKILL.md"),
|
|
12
|
+
(0, node_path_1.join)(process.cwd(), ".agents/skills/hechura-manager-noreaster/SKILL.md"),
|
|
13
|
+
];
|
|
14
|
+
for (const candidate of candidates) {
|
|
15
|
+
if ((0, node_fs_1.existsSync)(candidate))
|
|
16
|
+
return candidate;
|
|
17
|
+
}
|
|
18
|
+
throw new Error("Packaged skill file not found");
|
|
19
|
+
}
|
|
20
|
+
function installTargets() {
|
|
21
|
+
const home = (0, node_os_1.homedir)();
|
|
22
|
+
return [
|
|
23
|
+
(0, node_path_1.join)(home, ".claude/skills/hechura-manager-noreaster/SKILL.md"),
|
|
24
|
+
(0, node_path_1.join)(home, ".cursor/skills/hechura-manager-noreaster/SKILL.md"),
|
|
25
|
+
];
|
|
26
|
+
}
|
|
27
|
+
function registerSkillCommands(parent) {
|
|
28
|
+
const skill = parent.command("skill").description("Manage the Noreaster agent skill");
|
|
29
|
+
skill
|
|
30
|
+
.command("install")
|
|
31
|
+
.description("Copy the packaged hechura-manager-noreaster skill into local skill directories")
|
|
32
|
+
.action(() => {
|
|
33
|
+
const source = resolvePackagedSkillPath();
|
|
34
|
+
const installed = [];
|
|
35
|
+
for (const target of installTargets()) {
|
|
36
|
+
(0, node_fs_1.mkdirSync)((0, node_path_1.dirname)(target), { recursive: true });
|
|
37
|
+
(0, node_fs_1.copyFileSync)(source, target);
|
|
38
|
+
installed.push(target);
|
|
39
|
+
}
|
|
40
|
+
console.log(JSON.stringify({
|
|
41
|
+
data: {
|
|
42
|
+
source,
|
|
43
|
+
installed,
|
|
44
|
+
},
|
|
45
|
+
}, null, 2));
|
|
46
|
+
});
|
|
47
|
+
}
|
package/dist/commands/tasks.js
CHANGED
|
@@ -9,6 +9,7 @@ function registerTaskCommands(parent) {
|
|
|
9
9
|
.description("List tasks")
|
|
10
10
|
.option("--project-id <projectId>")
|
|
11
11
|
.option("--status <status>")
|
|
12
|
+
.option("--area <area>", "Filter by project area key")
|
|
12
13
|
.option("--limit <limit>")
|
|
13
14
|
.action(async (options) => {
|
|
14
15
|
const params = new URLSearchParams();
|
|
@@ -16,6 +17,8 @@ function registerTaskCommands(parent) {
|
|
|
16
17
|
params.set("project_id", options.projectId);
|
|
17
18
|
if (options.status)
|
|
18
19
|
params.set("status", options.status);
|
|
20
|
+
if (options.area)
|
|
21
|
+
params.set("area", options.area);
|
|
19
22
|
if (options.limit)
|
|
20
23
|
params.set("limit", options.limit);
|
|
21
24
|
const query = params.toString();
|
|
@@ -55,4 +58,25 @@ function registerTaskCommands(parent) {
|
|
|
55
58
|
const result = await (0, http_1.apiRequest)((0, http_1.resolveConfig)(), "DELETE", `/api/agent/tasks/${id}`);
|
|
56
59
|
console.log(JSON.stringify(result, null, 2));
|
|
57
60
|
});
|
|
61
|
+
tasks
|
|
62
|
+
.command("pr-link")
|
|
63
|
+
.description("Link a GitHub pull request URL to a task")
|
|
64
|
+
.argument("<id>")
|
|
65
|
+
.requiredOption("--url <url>", "GitHub pull request URL")
|
|
66
|
+
.action(async (id, options) => {
|
|
67
|
+
const result = await (0, http_1.apiRequest)((0, http_1.resolveConfig)(), "POST", `/api/agent/tasks/${id}/pull-requests`, {
|
|
68
|
+
url: options.url,
|
|
69
|
+
});
|
|
70
|
+
console.log(JSON.stringify(result, null, 2));
|
|
71
|
+
});
|
|
72
|
+
tasks
|
|
73
|
+
.command("pr-unlink")
|
|
74
|
+
.description("Unlink a GitHub pull request URL from a task")
|
|
75
|
+
.argument("<id>")
|
|
76
|
+
.requiredOption("--url <url>", "GitHub pull request URL")
|
|
77
|
+
.action(async (id, options) => {
|
|
78
|
+
const params = new URLSearchParams({ url: options.url });
|
|
79
|
+
const result = await (0, http_1.apiRequest)((0, http_1.resolveConfig)(), "DELETE", `/api/agent/tasks/${id}/pull-requests?${params.toString()}`);
|
|
80
|
+
console.log(JSON.stringify(result, null, 2));
|
|
81
|
+
});
|
|
58
82
|
}
|
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TEMPLATE_DOC_TYPES = void 0;
|
|
4
|
+
exports.isTemplateDocType = isTemplateDocType;
|
|
5
|
+
exports.templateForDocType = templateForDocType;
|
|
6
|
+
exports.resolveDocumentContent = resolveDocumentContent;
|
|
7
|
+
exports.TEMPLATE_DOC_TYPES = [
|
|
8
|
+
"feature_description",
|
|
9
|
+
"design_spec",
|
|
10
|
+
"adr",
|
|
11
|
+
"architecture",
|
|
12
|
+
"design_system",
|
|
13
|
+
"implementation_plan",
|
|
14
|
+
"prd",
|
|
15
|
+
];
|
|
16
|
+
const AI_WRITING_HINT = `<!-- Writing for AI tools:
|
|
17
|
+
- Be explicit with exact values ("max file size: 10MB", not "reasonable").
|
|
18
|
+
- Describe UI in words — AI tools cannot parse Figma links.
|
|
19
|
+
- Edge-case table rows become test cases; be exhaustive.
|
|
20
|
+
- Include API request/response shapes so handlers can be generated directly.
|
|
21
|
+
-->`;
|
|
22
|
+
const FEATURE_DESCRIPTION_TEMPLATE = `# Feature Description
|
|
23
|
+
|
|
24
|
+
${AI_WRITING_HINT}
|
|
25
|
+
|
|
26
|
+
## Problem Statement
|
|
27
|
+
|
|
28
|
+
<!-- 2-3 sentences describing the user or business problem this feature solves.
|
|
29
|
+
Be specific about who is affected and what pain they experience. -->
|
|
30
|
+
|
|
31
|
+
## Goals & Success Metrics
|
|
32
|
+
|
|
33
|
+
| Goal | Success Metric | Baseline | Target |
|
|
34
|
+
|------|---------------|----------|--------|
|
|
35
|
+
| | | | |
|
|
36
|
+
|
|
37
|
+
## User Stories
|
|
38
|
+
|
|
39
|
+
- As a [persona], I want to [action] so that [outcome].
|
|
40
|
+
|
|
41
|
+
## Requirements
|
|
42
|
+
|
|
43
|
+
### Functional Requirements
|
|
44
|
+
|
|
45
|
+
1. The system must [specific behavior].
|
|
46
|
+
2. When a user [action], the system must [specific response].
|
|
47
|
+
|
|
48
|
+
### Non-Functional Requirements
|
|
49
|
+
|
|
50
|
+
- **Performance:**
|
|
51
|
+
- **Accessibility:**
|
|
52
|
+
- **Security:**
|
|
53
|
+
- **Scalability:**
|
|
54
|
+
|
|
55
|
+
## Scope
|
|
56
|
+
|
|
57
|
+
### In Scope
|
|
58
|
+
|
|
59
|
+
-
|
|
60
|
+
|
|
61
|
+
### Out of Scope
|
|
62
|
+
|
|
63
|
+
-
|
|
64
|
+
|
|
65
|
+
## UX / Design
|
|
66
|
+
|
|
67
|
+
**Design Link:**
|
|
68
|
+
|
|
69
|
+
### Key Screens & Flows
|
|
70
|
+
|
|
71
|
+
**Screen: [Name]**
|
|
72
|
+
- Layout:
|
|
73
|
+
- Primary action:
|
|
74
|
+
- Feedback states:
|
|
75
|
+
|
|
76
|
+
**Flow: [Name]**
|
|
77
|
+
1. User [action] → System shows [response]
|
|
78
|
+
|
|
79
|
+
## Open Questions
|
|
80
|
+
|
|
81
|
+
- [ ]
|
|
82
|
+
`;
|
|
83
|
+
const DESIGN_SPEC_TEMPLATE = `# Feature Design Spec
|
|
84
|
+
|
|
85
|
+
${AI_WRITING_HINT}
|
|
86
|
+
|
|
87
|
+
## Technical Context
|
|
88
|
+
|
|
89
|
+
<!-- Co-authored with engineering after requirements approval. -->
|
|
90
|
+
|
|
91
|
+
## Affected Areas
|
|
92
|
+
|
|
93
|
+
<!-- One subsection per project area. Each developer walks their area to generate work items. -->
|
|
94
|
+
|
|
95
|
+
### Frontend
|
|
96
|
+
|
|
97
|
+
- Services & APIs Affected:
|
|
98
|
+
- Changes needed:
|
|
99
|
+
|
|
100
|
+
### Backend
|
|
101
|
+
|
|
102
|
+
- Services & APIs Affected:
|
|
103
|
+
- Changes needed:
|
|
104
|
+
|
|
105
|
+
## API Contract
|
|
106
|
+
|
|
107
|
+
\`\`\`
|
|
108
|
+
POST /api/v1/[resource]
|
|
109
|
+
Request:
|
|
110
|
+
{
|
|
111
|
+
"field": "type — description"
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
Response (200):
|
|
115
|
+
{
|
|
116
|
+
"field": "type — description"
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
Response (400):
|
|
120
|
+
{
|
|
121
|
+
"error": "VALIDATION_ERROR",
|
|
122
|
+
"message": "Human-readable description"
|
|
123
|
+
}
|
|
124
|
+
\`\`\`
|
|
125
|
+
|
|
126
|
+
## Data Model Changes
|
|
127
|
+
|
|
128
|
+
\`\`\`
|
|
129
|
+
Table: [table_name]
|
|
130
|
+
+ new_column (type, constraints)
|
|
131
|
+
~ modified_column (old_type → new_type)
|
|
132
|
+
\`\`\`
|
|
133
|
+
|
|
134
|
+
## Edge Cases & Error Handling
|
|
135
|
+
|
|
136
|
+
| # | Scenario | Expected Behavior | Error Message (if applicable) |
|
|
137
|
+
|---|----------|-------------------|-------------------------------|
|
|
138
|
+
| 1 | | | |
|
|
139
|
+
|
|
140
|
+
## Dependencies & Risks
|
|
141
|
+
|
|
142
|
+
-
|
|
143
|
+
|
|
144
|
+
## Open Questions
|
|
145
|
+
|
|
146
|
+
- [ ]
|
|
147
|
+
|
|
148
|
+
## Decision Log
|
|
149
|
+
|
|
150
|
+
| Date | Decision | Rationale | Decided By |
|
|
151
|
+
|------|----------|-----------|------------|
|
|
152
|
+
| | | | |
|
|
153
|
+
`;
|
|
154
|
+
const ADR_TEMPLATE = `# ADR: [Title]
|
|
155
|
+
|
|
156
|
+
${AI_WRITING_HINT}
|
|
157
|
+
|
|
158
|
+
## Context
|
|
159
|
+
|
|
160
|
+
<!-- What issue motivates this decision? Include constraints and forces. -->
|
|
161
|
+
|
|
162
|
+
## Decision
|
|
163
|
+
|
|
164
|
+
<!-- State the change clearly and concisely. -->
|
|
165
|
+
|
|
166
|
+
## Consequences
|
|
167
|
+
|
|
168
|
+
### Positive
|
|
169
|
+
|
|
170
|
+
-
|
|
171
|
+
|
|
172
|
+
### Negative
|
|
173
|
+
|
|
174
|
+
-
|
|
175
|
+
|
|
176
|
+
### Neutral
|
|
177
|
+
|
|
178
|
+
-
|
|
179
|
+
|
|
180
|
+
## Alternatives Considered
|
|
181
|
+
|
|
182
|
+
### [Alternative 1]
|
|
183
|
+
|
|
184
|
+
- **Description:**
|
|
185
|
+
- **Rejected because:**
|
|
186
|
+
|
|
187
|
+
### [Alternative 2]
|
|
188
|
+
|
|
189
|
+
- **Description:**
|
|
190
|
+
- **Rejected because:**
|
|
191
|
+
`;
|
|
192
|
+
const ARCHITECTURE_TEMPLATE = `# Architecture Overview
|
|
193
|
+
|
|
194
|
+
${AI_WRITING_HINT}
|
|
195
|
+
|
|
196
|
+
## Service Map
|
|
197
|
+
|
|
198
|
+
<!-- List services and how they relate. -->
|
|
199
|
+
|
|
200
|
+
-
|
|
201
|
+
|
|
202
|
+
## Cross-Service Data Flows
|
|
203
|
+
|
|
204
|
+
<!-- Describe the important flows that no single service owns. -->
|
|
205
|
+
|
|
206
|
+
-
|
|
207
|
+
|
|
208
|
+
## Shared Infrastructure
|
|
209
|
+
|
|
210
|
+
<!-- Auth, storage, messaging, observability, etc. -->
|
|
211
|
+
|
|
212
|
+
-
|
|
213
|
+
|
|
214
|
+
## Conventions
|
|
215
|
+
|
|
216
|
+
-
|
|
217
|
+
`;
|
|
218
|
+
const DESIGN_SYSTEM_TEMPLATE = `# Design System
|
|
219
|
+
|
|
220
|
+
${AI_WRITING_HINT}
|
|
221
|
+
|
|
222
|
+
## Tokens
|
|
223
|
+
|
|
224
|
+
<!-- Colors, spacing, radii, elevation. Prefer exact values AI tools can apply. -->
|
|
225
|
+
|
|
226
|
+
| Token | Value | Usage |
|
|
227
|
+
|-------|-------|-------|
|
|
228
|
+
| | | |
|
|
229
|
+
|
|
230
|
+
## Typography
|
|
231
|
+
|
|
232
|
+
| Role | Font | Size / Line height | Weight |
|
|
233
|
+
|------|------|--------------------|--------|
|
|
234
|
+
| Display | | | |
|
|
235
|
+
| Body | | | |
|
|
236
|
+
| Caption | | | |
|
|
237
|
+
|
|
238
|
+
## Components
|
|
239
|
+
|
|
240
|
+
### [Component name]
|
|
241
|
+
|
|
242
|
+
- Purpose:
|
|
243
|
+
- Variants:
|
|
244
|
+
- States (default / hover / focus / disabled / error):
|
|
245
|
+
- Content rules:
|
|
246
|
+
|
|
247
|
+
## Interaction Patterns
|
|
248
|
+
|
|
249
|
+
- Navigation:
|
|
250
|
+
- Forms & validation:
|
|
251
|
+
- Feedback (toasts, empty states, loading):
|
|
252
|
+
|
|
253
|
+
## Accessibility
|
|
254
|
+
|
|
255
|
+
- Contrast:
|
|
256
|
+
- Keyboard:
|
|
257
|
+
- Screen reader / labels:
|
|
258
|
+
- Motion:
|
|
259
|
+
`;
|
|
260
|
+
const IMPLEMENTATION_PLAN_TEMPLATE = `# Implementation Plan
|
|
261
|
+
|
|
262
|
+
${AI_WRITING_HINT}
|
|
263
|
+
|
|
264
|
+
## Plan
|
|
265
|
+
|
|
266
|
+
<!-- Steps, sequencing, and ownership for this work item. -->
|
|
267
|
+
|
|
268
|
+
1.
|
|
269
|
+
|
|
270
|
+
## Risks & Dependencies
|
|
271
|
+
|
|
272
|
+
-
|
|
273
|
+
|
|
274
|
+
## Implementation Notes
|
|
275
|
+
|
|
276
|
+
<!-- Fill in AFTER development, not before. -->
|
|
277
|
+
|
|
278
|
+
### Deviations from Spec
|
|
279
|
+
|
|
280
|
+
-
|
|
281
|
+
|
|
282
|
+
### Key Implementation Details
|
|
283
|
+
|
|
284
|
+
-
|
|
285
|
+
|
|
286
|
+
### Known Limitations
|
|
287
|
+
|
|
288
|
+
-
|
|
289
|
+
`;
|
|
290
|
+
const PRD_TEMPLATE = `# Product Requirements Document
|
|
291
|
+
|
|
292
|
+
${AI_WRITING_HINT}
|
|
293
|
+
|
|
294
|
+
## Problem
|
|
295
|
+
|
|
296
|
+
## Goals
|
|
297
|
+
|
|
298
|
+
## Personas
|
|
299
|
+
|
|
300
|
+
## Feature List
|
|
301
|
+
|
|
302
|
+
-
|
|
303
|
+
`;
|
|
304
|
+
const TEMPLATES = {
|
|
305
|
+
feature_description: FEATURE_DESCRIPTION_TEMPLATE,
|
|
306
|
+
design_spec: DESIGN_SPEC_TEMPLATE,
|
|
307
|
+
adr: ADR_TEMPLATE,
|
|
308
|
+
architecture: ARCHITECTURE_TEMPLATE,
|
|
309
|
+
design_system: DESIGN_SYSTEM_TEMPLATE,
|
|
310
|
+
implementation_plan: IMPLEMENTATION_PLAN_TEMPLATE,
|
|
311
|
+
prd: PRD_TEMPLATE,
|
|
312
|
+
};
|
|
313
|
+
function isTemplateDocType(value) {
|
|
314
|
+
return value != null && exports.TEMPLATE_DOC_TYPES.includes(value);
|
|
315
|
+
}
|
|
316
|
+
function templateForDocType(docType) {
|
|
317
|
+
if (!isTemplateDocType(docType))
|
|
318
|
+
return null;
|
|
319
|
+
return TEMPLATES[docType];
|
|
320
|
+
}
|
|
321
|
+
/** Seed template content when creating a doc with empty content. Explicit content always wins. */
|
|
322
|
+
function resolveDocumentContent(docType, content) {
|
|
323
|
+
if (content != null && content.trim().length > 0) {
|
|
324
|
+
return content;
|
|
325
|
+
}
|
|
326
|
+
return templateForDocType(docType);
|
|
327
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -13,13 +13,23 @@ const customers_1 = require("./commands/customers");
|
|
|
13
13
|
const prospects_1 = require("./commands/prospects");
|
|
14
14
|
const meetings_1 = require("./commands/meetings");
|
|
15
15
|
const timeline_1 = require("./commands/timeline");
|
|
16
|
+
const features_1 = require("./commands/features");
|
|
17
|
+
const reviews_1 = require("./commands/reviews");
|
|
18
|
+
const draft_runs_1 = require("./commands/draft-runs");
|
|
19
|
+
const my_work_1 = require("./commands/my-work");
|
|
20
|
+
const skill_1 = require("./commands/skill");
|
|
16
21
|
async function main() {
|
|
17
22
|
const program = new commander_1.Command()
|
|
18
23
|
.name("noreaster")
|
|
19
24
|
.description("CLI for admin-equivalent AI agent API access")
|
|
20
|
-
.version("0.1.
|
|
25
|
+
.version("0.1.1");
|
|
21
26
|
(0, tasks_1.registerTaskCommands)(program);
|
|
22
27
|
(0, docs_1.registerDocumentCommands)(program);
|
|
28
|
+
(0, features_1.registerFeatureCommands)(program);
|
|
29
|
+
(0, reviews_1.registerReviewCommands)(program);
|
|
30
|
+
(0, draft_runs_1.registerDraftRunCommands)(program);
|
|
31
|
+
(0, my_work_1.registerMyWorkCommands)(program);
|
|
32
|
+
(0, skill_1.registerSkillCommands)(program);
|
|
23
33
|
(0, projects_1.registerProjectCommands)(program);
|
|
24
34
|
(0, team_1.registerTeamCommands)(program);
|
|
25
35
|
(0, messages_1.registerMessageCommands)(program);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hechura/noreaster-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "CLI for Hechura Noreaster agent API access",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -11,17 +11,19 @@
|
|
|
11
11
|
"access": "public"
|
|
12
12
|
},
|
|
13
13
|
"bin": {
|
|
14
|
-
"noreaster": "
|
|
15
|
-
"hechura-agent": "
|
|
14
|
+
"noreaster": "dist/index.js",
|
|
15
|
+
"hechura-agent": "dist/index.js"
|
|
16
16
|
},
|
|
17
17
|
"files": [
|
|
18
|
-
"dist"
|
|
18
|
+
"dist",
|
|
19
|
+
"skills"
|
|
19
20
|
],
|
|
20
21
|
"scripts": {
|
|
21
|
-
"build": "npx tsc -p tsconfig.json",
|
|
22
|
+
"build": "npx tsc -p tsconfig.json && node -e \"require('node:fs').chmodSync('dist/index.js', 0o755)\"",
|
|
22
23
|
"clean": "node -e \"require('node:fs').rmSync('dist', { recursive: true, force: true })\"",
|
|
23
24
|
"prepack": "npm run clean && npm run build",
|
|
24
|
-
"pack:dry-run": "npm pack --dry-run"
|
|
25
|
+
"pack:dry-run": "npm pack --dry-run",
|
|
26
|
+
"publish:package": "npm publish --access public"
|
|
25
27
|
},
|
|
26
28
|
"engines": {
|
|
27
29
|
"node": ">=18"
|
|
@@ -30,6 +32,7 @@
|
|
|
30
32
|
"commander": "^14.0.3"
|
|
31
33
|
},
|
|
32
34
|
"devDependencies": {
|
|
35
|
+
"@types/node": "^22.20.1",
|
|
33
36
|
"typescript": "^5.7.3"
|
|
34
37
|
}
|
|
35
38
|
}
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: hechura-manager-noreaster
|
|
3
|
+
description: Operates Hechura Manager / Noreaster via the official agent CLI and PAT-scoped APIs, including the feature-spec process chain. Use when the user asks to manage Noreaster projects, tasks, sprints, customers, prospects, meetings, timeline entries, documents, features, reviews, draft runs, PR links, team/admin agent routes, or references HECHURA_AGENT_TOKEN, agent scopes, or noreaster.vercel.app docs. Also trigger for process phrases like "pick up my next work item", "submit the breakdown for review", "what gates are open", "link this PR", or "install the noreaster skill".
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Hechura Manager / Noreaster Operations
|
|
7
|
+
|
|
8
|
+
Use this skill for operational work in Noreaster through the official agent CLI surface.
|
|
9
|
+
|
|
10
|
+
## Execution Defaults
|
|
11
|
+
|
|
12
|
+
1. Prefer the published CLI:
|
|
13
|
+
- `npx @hechura/noreaster-cli@0.2.1 <command>` or `noreaster <command>` after global install (`npm install -g @hechura/noreaster-cli@0.2.1`)
|
|
14
|
+
- In this repo: `npm run agent -- <command>`
|
|
15
|
+
2. Default API base URL:
|
|
16
|
+
- `https://noreaster.vercel.app`
|
|
17
|
+
3. Required runtime credentials:
|
|
18
|
+
- `HECHURA_API_BASE_URL`
|
|
19
|
+
- `HECHURA_AGENT_TOKEN`
|
|
20
|
+
4. Before any write/delete operation, preview with a list/get command first.
|
|
21
|
+
5. Never run delete/destructive commands without explicit user confirmation.
|
|
22
|
+
6. After upgrading the CLI, always run `noreaster skill install` so local skill copies stay current.
|
|
23
|
+
|
|
24
|
+
## Spec Process Chain
|
|
25
|
+
|
|
26
|
+
Noreaster is the system of record. External agents (or humans) drive generation and transitions. Chain:
|
|
27
|
+
|
|
28
|
+
```
|
|
29
|
+
PRD → Feature → Feature PRD (feature_description) → Feature Spec (design_spec)
|
|
30
|
+
→ Work Items → Implementation Plan docs → GitHub PRs
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### Doc types vs labels
|
|
34
|
+
|
|
35
|
+
UI labels are for humans; CLI/API payloads use `doc_type` values:
|
|
36
|
+
|
|
37
|
+
| UI label | `doc_type` |
|
|
38
|
+
| --- | --- |
|
|
39
|
+
| Feature PRD | `feature_description` |
|
|
40
|
+
| Feature Spec | `design_spec` |
|
|
41
|
+
| Technical Architecture | `architecture` |
|
|
42
|
+
| Design System | `design_system` |
|
|
43
|
+
| PRD | `prd` |
|
|
44
|
+
|
|
45
|
+
Do not invent types like `feature_prd`. Use the `doc_type` column in create/update payloads and `docs template <docType>`.
|
|
46
|
+
|
|
47
|
+
Ownership defaults:
|
|
48
|
+
|
|
49
|
+
- PRD / Feature / Feature PRD: PM-owned
|
|
50
|
+
- Feature Spec: engineering-owned
|
|
51
|
+
- Work-item breakdowns: submitted by external agents as draft runs; humans review/apply
|
|
52
|
+
- Implementation plans: authored by a developer's agent, linked to a work item
|
|
53
|
+
- PRs: linked manually or via inbound webhook matching `NOR-<n>`
|
|
54
|
+
|
|
55
|
+
## Lifecycle Gates
|
|
56
|
+
|
|
57
|
+
Illegal transitions are refused server-side with HTTP 409 and `gate_not_satisfied`.
|
|
58
|
+
|
|
59
|
+
Common gates:
|
|
60
|
+
|
|
61
|
+
- Feature PRD (`feature_description`) must be approved before Feature Spec (`design_spec`) can be approved
|
|
62
|
+
- Feature Spec must be approved before draft-run apply creates work items
|
|
63
|
+
- Document → `approved` requires a matching approved review
|
|
64
|
+
- Agent document reads return `approved` docs by default; use `--include-drafts` only when intentionally working on drafts
|
|
65
|
+
|
|
66
|
+
When refused, read the `gate` / `error` fields, fix the missing prerequisite, then retry.
|
|
67
|
+
|
|
68
|
+
## Consuming project documents
|
|
69
|
+
|
|
70
|
+
Before implementing a work item, load the governing docs — do not invent contracts from memory.
|
|
71
|
+
|
|
72
|
+
1. Fetch the work item: `tasks get <id>`
|
|
73
|
+
2. Follow `source_document_id` (or the feature's Feature Spec / `design_spec`) and read it: `docs get <id>`
|
|
74
|
+
3. Load project foundation docs:
|
|
75
|
+
- `docs list --project-id <id> --type architecture`
|
|
76
|
+
- `docs list --project-id <id> --type design_system`
|
|
77
|
+
4. If an ADR governs the change, read it (`--type adr`) before contradicting prior decisions.
|
|
78
|
+
|
|
79
|
+
Compliance rules while coding:
|
|
80
|
+
|
|
81
|
+
- Honor the Feature Spec's API contract and data model verbatim
|
|
82
|
+
- Every edge-case table row becomes a required test
|
|
83
|
+
- UI work must conform to the approved design-system doc (tokens, components, a11y)
|
|
84
|
+
- Do not contradict an approved ADR — propose a new ADR instead
|
|
85
|
+
- Prefer exact values from the spec over "reasonable" guesses
|
|
86
|
+
|
|
87
|
+
On completion:
|
|
88
|
+
|
|
89
|
+
- Record deviations under the design/implementation notes **Deviations from Spec** section
|
|
90
|
+
- Link the PR with `NOR-<n>` in the branch name or title (`tasks pr-link` if needed)
|
|
91
|
+
|
|
92
|
+
## Work Discovery
|
|
93
|
+
|
|
94
|
+
Start here when asked to pick up next work:
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
noreaster my-work
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Returns:
|
|
101
|
+
|
|
102
|
+
- assigned work items for this agent
|
|
103
|
+
- open reviews for the principal owner (or unassigned open reviews)
|
|
104
|
+
- features with open gates (Feature PRD approved awaiting Feature Spec; Feature Spec approved awaiting draft apply)
|
|
105
|
+
- draft runs awaiting apply
|
|
106
|
+
|
|
107
|
+
## Draft Runs
|
|
108
|
+
|
|
109
|
+
1. Submit breakdown: `draft-runs submit <featureId> --data '...'`
|
|
110
|
+
2. Humans review in the dashboard
|
|
111
|
+
3. Apply after Feature Spec approval: `draft-runs apply <featureId> <runId> [--data '...']`
|
|
112
|
+
|
|
113
|
+
Do not invent silent auto-apply behavior.
|
|
114
|
+
|
|
115
|
+
## NOR Short IDs and PR Linking
|
|
116
|
+
|
|
117
|
+
- Work items have global short IDs rendered as `NOR-<n>`
|
|
118
|
+
- Branch convention: `nor-<n>-<kebab-title>`
|
|
119
|
+
- Put `NOR-<n>` in the branch name or PR title so the webhook can auto-link
|
|
120
|
+
- Manual link: `tasks pr-link <id> --url <github-pr-url>`
|
|
121
|
+
- Unlink: `tasks pr-unlink <id> --url <github-pr-url>`
|
|
122
|
+
- PR merge never silently moves work-item status; humans accept "PR merged — move to done?"
|
|
123
|
+
|
|
124
|
+
## Work Item Authoring Conventions
|
|
125
|
+
|
|
126
|
+
When creating or editing work items, prefer:
|
|
127
|
+
|
|
128
|
+
- **What**: concrete outcome
|
|
129
|
+
- **Why**: user/business reason (include a link back to the source spec)
|
|
130
|
+
- **Acceptance Criteria**: testable checklist of observable outcomes — not implementation details
|
|
131
|
+
|
|
132
|
+
Breakdown rules (ported from the CTF jira-tickets skill):
|
|
133
|
+
|
|
134
|
+
- Emit **one work item per affected area** from the project's area registry — never bundle FE and BE into a single item
|
|
135
|
+
- Prefix titles with the area label: `[FE - web] …`, `[BE - api] …` (use `[<area label>]`)
|
|
136
|
+
- Use `tasks list --area <key>` / `my-work` to stay in your lane
|
|
137
|
+
|
|
138
|
+
Writing for AI tools when authoring specs:
|
|
139
|
+
|
|
140
|
+
- Prefer exact values ("max file size: 10MB") over vague language
|
|
141
|
+
- Describe UI in words — tools cannot parse Figma links
|
|
142
|
+
- Edge-case table rows become test cases; be exhaustive
|
|
143
|
+
- Include API request/response shapes
|
|
144
|
+
|
|
145
|
+
Document templates:
|
|
146
|
+
|
|
147
|
+
```bash
|
|
148
|
+
noreaster docs template design_spec
|
|
149
|
+
noreaster docs template feature_description
|
|
150
|
+
noreaster docs create --data '{"name":"Feature Spec","doc_type":"design_spec","project_id":"<id>","feature_id":"<id>"}'
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
Empty `content` on create is seeded from the template for that `doc_type`.
|
|
154
|
+
|
|
155
|
+
## Command Rules
|
|
156
|
+
|
|
157
|
+
- `--data` must be a JSON object (not an array).
|
|
158
|
+
- Use single quotes around JSON payloads:
|
|
159
|
+
- `--data '{"title":"Follow up"}'`
|
|
160
|
+
- API failures should be treated as blocking:
|
|
161
|
+
- non-zero exit code means the command did not complete.
|
|
162
|
+
|
|
163
|
+
## Auth, Scopes, and Admin Flags
|
|
164
|
+
|
|
165
|
+
- Operational routes require PAT auth plus route-level scopes (for example `projects.write`, `work_items.write`, `features.write`).
|
|
166
|
+
- Agent scopes come from `ai_agents.metadata.scopes`; `*` grants all scopes.
|
|
167
|
+
- Admin PAT routes depend on feature flags:
|
|
168
|
+
- `AGENT_ADMIN_PAT_ENABLED=true`
|
|
169
|
+
- `AGENT_ADMIN_PAT_AGENTS_ENABLED=true`
|
|
170
|
+
- `AGENT_ADMIN_PAT_TOKENS_ENABLED=true`
|
|
171
|
+
- `AGENT_ADMIN_PAT_MONITORING_ENABLED=true`
|
|
172
|
+
- If PAT is not supplied on admin routes, fallback auth may use admin session behavior where enabled.
|
|
173
|
+
|
|
174
|
+
## Core Command Surface
|
|
175
|
+
|
|
176
|
+
- `my-work`: work discovery inbox
|
|
177
|
+
- `skill install`: copy this skill into local Claude/Cursor skill dirs
|
|
178
|
+
- `tasks`: list/get/create/update/delete + `pr-link` / `pr-unlink`
|
|
179
|
+
- `projects`: list/get/create/update/delete + assignees/calendar color helpers (`github_repos` via update payload)
|
|
180
|
+
- `sprints`: list/get/create/update/delete
|
|
181
|
+
- `customers`: list/get/create/update/delete
|
|
182
|
+
- `prospects`: list/get/create/update/delete + convert
|
|
183
|
+
- `meetings`: list/get/create/update/delete
|
|
184
|
+
- `timeline`: list/get/create/update/delete
|
|
185
|
+
- `docs`: list/get/create/update/transition/revisions/delete
|
|
186
|
+
- `features`: list/get/create/update/transition/delete
|
|
187
|
+
- `reviews`: request/approve/request-changes/check/comment/resolve-comment
|
|
188
|
+
- `draft-runs`: list/get/submit/apply
|
|
189
|
+
- `messages`: list/create
|
|
190
|
+
- `team`: invite/update-role/remove
|
|
191
|
+
- `admin`: agents/tokens/monitoring lifecycle commands
|
|
192
|
+
|
|
193
|
+
## Standard Workflow
|
|
194
|
+
|
|
195
|
+
1. Validate environment (`HECHURA_API_BASE_URL`, `HECHURA_AGENT_TOKEN`)
|
|
196
|
+
2. Discover work with `my-work` or targeted list/get
|
|
197
|
+
3. Execute with strict JSON payloads
|
|
198
|
+
4. Verify with get/list
|
|
199
|
+
5. Report concise outcomes and next gates
|
|
200
|
+
|
|
201
|
+
## Quick Command Examples
|
|
202
|
+
|
|
203
|
+
```bash
|
|
204
|
+
npm install -g @hechura/noreaster-cli@0.2.1
|
|
205
|
+
noreaster skill install
|
|
206
|
+
noreaster my-work
|
|
207
|
+
noreaster features list --project-id <project-id>
|
|
208
|
+
noreaster draft-runs submit <feature-id> --data '{"document_id":"<design-spec-id>","generated_items":[{"title":"Add login","type":"task","priority":"high"}]}'
|
|
209
|
+
noreaster tasks pr-link <task-id> --url 'https://github.com/owner/repo/pull/12'
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
## Troubleshooting Playbook
|
|
213
|
+
|
|
214
|
+
- `Missing token`: set `HECHURA_AGENT_TOKEN` and retry.
|
|
215
|
+
- `Invalid JSON payload`: ensure `--data` is a valid JSON object in single quotes.
|
|
216
|
+
- `401 Unauthorized`: token missing, expired, or revoked.
|
|
217
|
+
- `403 Forbidden`: token scope mismatch or admin PAT route disabled by flags.
|
|
218
|
+
- `409 gate_not_satisfied`: missing lifecycle prerequisite; inspect `gate` and unblock.
|
|
219
|
+
- `429 Too Many Requests`: respect `retry_after_seconds` before retrying.
|
|
220
|
+
- Stale process guidance after a CLI upgrade: run `noreaster skill install` again.
|
|
221
|
+
|
|
222
|
+
## Known Divergence
|
|
223
|
+
|
|
224
|
+
- Team admin MCP tools are planned but not primary yet; CLI/API are complete for team operations.
|
|
225
|
+
- Some bulk/reorder/image task workflows still use session routes under `/api/work-items/*` and are not fully mirrored in `/api/agent/tasks/*`.
|