@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.
@@ -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
- .action(async (id) => {
33
- const result = await (0, http_1.apiRequest)((0, http_1.resolveConfig)(), "GET", `/api/agent/documents/${id}`);
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
+ }
@@ -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.0");
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.1.1",
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": "./dist/index.js",
15
- "hechura-agent": "./dist/index.js"
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/*`.