@nac3/forge-cli 0.2.0-alpha.2 → 0.2.0-alpha.21
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/bin/yf.d.ts.map +1 -1
- package/dist/bin/yf.js +25 -0
- package/dist/bin/yf.js.map +1 -1
- package/dist/chat/claude.d.ts +22 -15
- package/dist/chat/claude.d.ts.map +1 -1
- package/dist/chat/claude.js +75 -22
- package/dist/chat/claude.js.map +1 -1
- package/dist/chat/panel.d.ts.map +1 -1
- package/dist/chat/panel.js +102 -3
- package/dist/chat/panel.js.map +1 -1
- package/dist/chat/server.js +498 -32
- package/dist/chat/server.js.map +1 -1
- package/dist/chat/tools/audit_consumers.d.ts +66 -0
- package/dist/chat/tools/audit_consumers.d.ts.map +1 -0
- package/dist/chat/tools/audit_consumers.js +231 -0
- package/dist/chat/tools/audit_consumers.js.map +1 -0
- package/dist/chat/tools/git.js +4 -4
- package/dist/chat/tools/github.js +3 -3
- package/dist/chat/tools/lifecycle.js +3 -3
- package/dist/chat/tools/manual.js +1 -1
- package/dist/chat/tools/reader.js +8 -8
- package/dist/chat/tools/workflow.d.ts +45 -0
- package/dist/chat/tools/workflow.d.ts.map +1 -0
- package/dist/chat/tools/workflow.js +404 -0
- package/dist/chat/tools/workflow.js.map +1 -0
- package/dist/chat/tools.d.ts.map +1 -1
- package/dist/chat/tools.js +23 -4
- package/dist/chat/tools.js.map +1 -1
- package/dist/commands/approve.d.ts +32 -0
- package/dist/commands/approve.d.ts.map +1 -0
- package/dist/commands/approve.js +198 -0
- package/dist/commands/approve.js.map +1 -0
- package/dist/commands/block.d.ts +28 -0
- package/dist/commands/block.d.ts.map +1 -0
- package/dist/commands/block.js +189 -0
- package/dist/commands/block.js.map +1 -0
- package/dist/commands/bootstrap.d.ts +35 -0
- package/dist/commands/bootstrap.d.ts.map +1 -0
- package/dist/commands/bootstrap.js +205 -0
- package/dist/commands/bootstrap.js.map +1 -0
- package/dist/commands/chat.d.ts +3 -0
- package/dist/commands/chat.d.ts.map +1 -1
- package/dist/commands/chat.js +46 -1
- package/dist/commands/chat.js.map +1 -1
- package/dist/commands/clarify.d.ts +30 -0
- package/dist/commands/clarify.d.ts.map +1 -0
- package/dist/commands/clarify.js +671 -0
- package/dist/commands/clarify.js.map +1 -0
- package/dist/commands/discover.d.ts +30 -0
- package/dist/commands/discover.d.ts.map +1 -0
- package/dist/commands/discover.js +178 -0
- package/dist/commands/discover.js.map +1 -0
- package/dist/commands/doctor.js +94 -42
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/keys_setup.d.ts +53 -0
- package/dist/commands/keys_setup.d.ts.map +1 -0
- package/dist/commands/keys_setup.js +487 -0
- package/dist/commands/keys_setup.js.map +1 -0
- package/dist/commands/legacy-audit.d.ts +34 -0
- package/dist/commands/legacy-audit.d.ts.map +1 -0
- package/dist/commands/legacy-audit.js +270 -0
- package/dist/commands/legacy-audit.js.map +1 -0
- package/dist/commands/license.d.ts.map +1 -1
- package/dist/commands/license.js +41 -0
- package/dist/commands/license.js.map +1 -1
- package/dist/commands/operate.d.ts +22 -0
- package/dist/commands/operate.d.ts.map +1 -0
- package/dist/commands/operate.js +483 -0
- package/dist/commands/operate.js.map +1 -0
- package/dist/commands/spec.d.ts +38 -0
- package/dist/commands/spec.d.ts.map +1 -0
- package/dist/commands/spec.js +256 -0
- package/dist/commands/spec.js.map +1 -0
- package/dist/commands/triage.d.ts +34 -0
- package/dist/commands/triage.d.ts.map +1 -0
- package/dist/commands/triage.js +228 -0
- package/dist/commands/triage.js.map +1 -0
- package/dist/commands/vault-inventory.d.ts +30 -0
- package/dist/commands/vault-inventory.d.ts.map +1 -0
- package/dist/commands/vault-inventory.js +214 -0
- package/dist/commands/vault-inventory.js.map +1 -0
- package/dist/commands/vault.d.ts.map +1 -1
- package/dist/commands/vault.js +5 -0
- package/dist/commands/vault.js.map +1 -1
- package/dist/commands/voice.js +1 -1
- package/dist/commands/voice.js.map +1 -1
- package/dist/commands/workflow-coverage.d.ts +30 -0
- package/dist/commands/workflow-coverage.d.ts.map +1 -0
- package/dist/commands/workflow-coverage.js +138 -0
- package/dist/commands/workflow-coverage.js.map +1 -0
- package/dist/core/keys_envelope.d.ts +13 -0
- package/dist/core/keys_envelope.d.ts.map +1 -1
- package/dist/core/keys_envelope.js.map +1 -1
- package/dist/deploy/adapter.d.ts +93 -0
- package/dist/deploy/adapter.d.ts.map +1 -0
- package/dist/deploy/adapter.js +42 -0
- package/dist/deploy/adapter.js.map +1 -0
- package/dist/deploy/aws_adapter.d.ts +28 -0
- package/dist/deploy/aws_adapter.d.ts.map +1 -0
- package/dist/deploy/aws_adapter.js +65 -0
- package/dist/deploy/aws_adapter.js.map +1 -0
- package/dist/deploy/cloudflare.d.ts +24 -0
- package/dist/deploy/cloudflare.d.ts.map +1 -0
- package/dist/deploy/cloudflare.js +169 -0
- package/dist/deploy/cloudflare.js.map +1 -0
- package/dist/license/hito4_client.d.ts +17 -1
- package/dist/license/hito4_client.d.ts.map +1 -1
- package/dist/license/hito4_client.js +71 -10
- package/dist/license/hito4_client.js.map +1 -1
- package/dist/license/index.d.ts.map +1 -1
- package/dist/license/index.js +7 -0
- package/dist/license/index.js.map +1 -1
- package/dist/license/sync.d.ts +54 -0
- package/dist/license/sync.d.ts.map +1 -0
- package/dist/license/sync.js +131 -0
- package/dist/license/sync.js.map +1 -0
- package/dist/telemetry/usage.d.ts +67 -0
- package/dist/telemetry/usage.d.ts.map +1 -0
- package/dist/telemetry/usage.js +208 -0
- package/dist/telemetry/usage.js.map +1 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.d.ts.map +1 -1
- package/dist/version.js +1 -1
- package/dist/version.js.map +1 -1
- package/dist/voice/intents.d.ts +1 -1
- package/dist/voice/intents.js +0 -0
- package/dist/voice/providers/google.d.ts.map +1 -1
- package/dist/voice/providers/google.js +157 -27
- package/dist/voice/providers/google.js.map +1 -1
- package/dist/voice/router.d.ts +10 -0
- package/dist/voice/router.d.ts.map +1 -1
- package/dist/voice/router.js +39 -20
- package/dist/voice/router.js.map +1 -1
- package/dist/voice/types.d.ts +5 -2
- package/dist/voice/types.d.ts.map +1 -1
- package/dist/voice/types.js.map +1 -1
- package/dist/workflow/state.d.ts +190 -0
- package/dist/workflow/state.d.ts.map +1 -0
- package/dist/workflow/state.js +119 -0
- package/dist/workflow/state.js.map +1 -0
- package/package.json +13 -15
- package/templates/nextjs-app/README.md +48 -0
- package/templates/nextjs-app/next.config.js +8 -0
- package/templates/nextjs-app/package.json +33 -0
- package/templates/nextjs-app/src/app/globals.css +43 -0
- package/templates/nextjs-app/src/app/layout.tsx +29 -0
- package/templates/nextjs-app/src/app/page.tsx +63 -0
- package/templates/nextjs-app/src/nac/manifest.ts +36 -0
- package/templates/nextjs-app/tsconfig.json +21 -0
- package/templates/nextjs-app/yujin.forge.json +11 -0
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Yujin Forge -- Product Workflow state.
|
|
3
|
+
*
|
|
4
|
+
* Shared persistence layer for the 18-step methodology defined
|
|
5
|
+
* in docs/PRODUCT_WORKFLOW.md. State lives in the project's
|
|
6
|
+
* yujin.forge.json under `workflow.*` so it survives across
|
|
7
|
+
* sessions + can be inspected + shared via the git repo.
|
|
8
|
+
*
|
|
9
|
+
* Every command in the workflow (yf triage, yf discover, yf
|
|
10
|
+
* clarify, yf spec, yf approve, yf bootstrap, yf block dev, yf
|
|
11
|
+
* deploy, yf manual, yf metrics, yf iterate) reads + writes
|
|
12
|
+
* through this module. The chat tool surface (forge_triage,
|
|
13
|
+
* forge_discover, etc) does the same -- the underlying state
|
|
14
|
+
* is identical regardless of entry point.
|
|
15
|
+
*
|
|
16
|
+
* Schema:
|
|
17
|
+
*
|
|
18
|
+
* workflow: {
|
|
19
|
+
* tier: 'simple' | 'medium' | 'full' | null,
|
|
20
|
+
* tier_reason: string,
|
|
21
|
+
* tier_decided_at: ISO,
|
|
22
|
+
*
|
|
23
|
+
* intent: { ... } // Phase I step 3
|
|
24
|
+
* legacy_audit: { ... } // Phase I step 3.5
|
|
25
|
+
* vault_inventory: { ... } // Phase I step 2 audit
|
|
26
|
+
*
|
|
27
|
+
* clarification: {
|
|
28
|
+
* functional: { done_at, summary, doc_path }, // step 4
|
|
29
|
+
* nfr_quantitative: { done_at, summary, doc_path }, // step 5
|
|
30
|
+
* nfr_structural: { done_at, summary, doc_path }, // step 6
|
|
31
|
+
* nfr_governance: { done_at, summary, doc_path }, // step 7
|
|
32
|
+
* nfr_operational: { done_at, summary, doc_path }, // step 8
|
|
33
|
+
* blocks: { done_at, blocks: [...] }, // step 9
|
|
34
|
+
* },
|
|
35
|
+
*
|
|
36
|
+
* specs: {
|
|
37
|
+
* rfp: { done_at, version, doc_path, sha256 }, // step 10
|
|
38
|
+
* arch: { done_at, version, doc_path, sha256 }, // step 11
|
|
39
|
+
* design: { done_at, version, doc_path, sha256 }, // step 12
|
|
40
|
+
* },
|
|
41
|
+
*
|
|
42
|
+
* approvals: {
|
|
43
|
+
* rfp: { approved_at, version_sha256 }, // step 13
|
|
44
|
+
* arch: { approved_at, version_sha256 }, // step 13
|
|
45
|
+
* design: { approved_at, version_sha256 }, // step 13
|
|
46
|
+
* },
|
|
47
|
+
*
|
|
48
|
+
* bootstrap: { done_at, stack, ci_set }, // step 14
|
|
49
|
+
*
|
|
50
|
+
* blocks_progress: [ // step 15
|
|
51
|
+
* { block_id, status, tests_green_at, deployed_at }
|
|
52
|
+
* ],
|
|
53
|
+
*
|
|
54
|
+
* deploy: { ... } // step 16
|
|
55
|
+
* postlaunch:{ ... } // step 17
|
|
56
|
+
* iterations:[{ at, type, summary }] // step 18
|
|
57
|
+
* }
|
|
58
|
+
*
|
|
59
|
+
* ASCII-only.
|
|
60
|
+
*/
|
|
61
|
+
export type WorkflowTier = 'simple' | 'medium' | 'full';
|
|
62
|
+
export interface IntentState {
|
|
63
|
+
operation: 'migrate' | 'new' | 'modify' | null;
|
|
64
|
+
target: 'desktop' | 'mobile' | 'responsive' | 'web-and-mobile' | null;
|
|
65
|
+
input_channel: 'chat-text' | 'voice' | 'document-paste' | null;
|
|
66
|
+
project_state: 'no-code' | 'local-repo' | 'remote-repo' | 'deployed' | null;
|
|
67
|
+
legacy_framework: string | null;
|
|
68
|
+
preferred_stack: string | null;
|
|
69
|
+
use_case: 'hobby' | 'poc' | 'internal' | 'commercial' | null;
|
|
70
|
+
decided_at: string;
|
|
71
|
+
}
|
|
72
|
+
export interface LegacyAuditState {
|
|
73
|
+
ran_at: string;
|
|
74
|
+
framework: string;
|
|
75
|
+
framework_version: string;
|
|
76
|
+
total_files: number;
|
|
77
|
+
tsx_files: number;
|
|
78
|
+
has_tests: boolean;
|
|
79
|
+
nac3_readiness: number;
|
|
80
|
+
tech_debt_signals: string[];
|
|
81
|
+
deprecated_deps: string[];
|
|
82
|
+
}
|
|
83
|
+
export interface VaultInventoryState {
|
|
84
|
+
ran_at: string;
|
|
85
|
+
/** Per family: configured | skipped | unknown.
|
|
86
|
+
* Skipped families are flagged as debt for step 16 (deploy). */
|
|
87
|
+
families: Record<string, 'configured' | 'skipped' | 'unknown'>;
|
|
88
|
+
}
|
|
89
|
+
export interface ClarificationRoundState {
|
|
90
|
+
done_at: string;
|
|
91
|
+
summary: string;
|
|
92
|
+
doc_path?: string;
|
|
93
|
+
}
|
|
94
|
+
export interface BlockPlanItem {
|
|
95
|
+
id: string;
|
|
96
|
+
name: string;
|
|
97
|
+
effort: 'S' | 'M' | 'L' | 'XL';
|
|
98
|
+
dependencies: string[];
|
|
99
|
+
mvp: boolean;
|
|
100
|
+
}
|
|
101
|
+
export interface ClarificationState {
|
|
102
|
+
functional?: ClarificationRoundState;
|
|
103
|
+
nfr_quantitative?: ClarificationRoundState;
|
|
104
|
+
nfr_structural?: ClarificationRoundState;
|
|
105
|
+
nfr_governance?: ClarificationRoundState;
|
|
106
|
+
nfr_operational?: ClarificationRoundState;
|
|
107
|
+
blocks?: {
|
|
108
|
+
done_at: string;
|
|
109
|
+
blocks: BlockPlanItem[];
|
|
110
|
+
mvp_path: string[];
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
export interface SpecDocState {
|
|
114
|
+
done_at: string;
|
|
115
|
+
version: number;
|
|
116
|
+
doc_path: string;
|
|
117
|
+
sha256: string;
|
|
118
|
+
}
|
|
119
|
+
export interface ApprovalState {
|
|
120
|
+
approved_at: string;
|
|
121
|
+
version_sha256: string;
|
|
122
|
+
}
|
|
123
|
+
export interface BootstrapState {
|
|
124
|
+
done_at: string;
|
|
125
|
+
stack: string;
|
|
126
|
+
ci_set: boolean;
|
|
127
|
+
}
|
|
128
|
+
export interface BlockProgressState {
|
|
129
|
+
block_id: string;
|
|
130
|
+
status: 'pending' | 'in_progress' | 'green' | 'failed';
|
|
131
|
+
tests_green_at?: string;
|
|
132
|
+
deployed_at?: string;
|
|
133
|
+
}
|
|
134
|
+
export interface DeployState {
|
|
135
|
+
done_at: string;
|
|
136
|
+
pipeline: string;
|
|
137
|
+
url: string;
|
|
138
|
+
smoke_at: string;
|
|
139
|
+
}
|
|
140
|
+
export interface PostLaunchState {
|
|
141
|
+
manual_at: string;
|
|
142
|
+
dashboards_at: string;
|
|
143
|
+
feedback_channel: string;
|
|
144
|
+
}
|
|
145
|
+
export interface IterationEntry {
|
|
146
|
+
at: string;
|
|
147
|
+
type: 'bug' | 'feature_small' | 'feature_large' | 'nfr_change' | 'pivot';
|
|
148
|
+
summary: string;
|
|
149
|
+
}
|
|
150
|
+
export interface WorkflowState {
|
|
151
|
+
tier?: WorkflowTier;
|
|
152
|
+
tier_reason?: string;
|
|
153
|
+
tier_decided_at?: string;
|
|
154
|
+
intent?: IntentState;
|
|
155
|
+
legacy_audit?: LegacyAuditState;
|
|
156
|
+
vault_inventory?: VaultInventoryState;
|
|
157
|
+
clarification?: ClarificationState;
|
|
158
|
+
specs?: {
|
|
159
|
+
rfp?: SpecDocState;
|
|
160
|
+
arch?: SpecDocState;
|
|
161
|
+
design?: SpecDocState;
|
|
162
|
+
};
|
|
163
|
+
approvals?: {
|
|
164
|
+
rfp?: ApprovalState;
|
|
165
|
+
arch?: ApprovalState;
|
|
166
|
+
design?: ApprovalState;
|
|
167
|
+
};
|
|
168
|
+
bootstrap?: BootstrapState;
|
|
169
|
+
blocks_progress?: BlockProgressState[];
|
|
170
|
+
deploy?: DeployState;
|
|
171
|
+
postlaunch?: PostLaunchState;
|
|
172
|
+
iterations?: IterationEntry[];
|
|
173
|
+
}
|
|
174
|
+
interface ProjectConfig {
|
|
175
|
+
workflow?: WorkflowState;
|
|
176
|
+
[key: string]: unknown;
|
|
177
|
+
}
|
|
178
|
+
export declare function loadConfig(projectRoot: string): Promise<ProjectConfig>;
|
|
179
|
+
export declare function saveConfig(projectRoot: string, cfg: ProjectConfig): Promise<void>;
|
|
180
|
+
export declare function readWorkflow(projectRoot: string): Promise<WorkflowState>;
|
|
181
|
+
export declare function writeWorkflow(projectRoot: string, patch: Partial<WorkflowState>): Promise<WorkflowState>;
|
|
182
|
+
/** Update a NESTED key under workflow.<group> (clarification,
|
|
183
|
+
* specs, approvals, blocks_progress) without overwriting sibling
|
|
184
|
+
* keys at the same level. */
|
|
185
|
+
export declare function patchWorkflowGroup<K extends keyof WorkflowState>(projectRoot: string, group: K, patch: Partial<NonNullable<WorkflowState[K]>>): Promise<WorkflowState>;
|
|
186
|
+
/** Append to workflow.iterations[]. Idempotent: callers should
|
|
187
|
+
* generate a unique-ish `at` per call so duplicates do not stack. */
|
|
188
|
+
export declare function appendIteration(projectRoot: string, entry: IterationEntry): Promise<WorkflowState>;
|
|
189
|
+
export {};
|
|
190
|
+
//# sourceMappingURL=state.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../src/workflow/state.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Yujin Forge -- Product Workflow state.
|
|
3
|
+
*
|
|
4
|
+
* Shared persistence layer for the 18-step methodology defined
|
|
5
|
+
* in docs/PRODUCT_WORKFLOW.md. State lives in the project's
|
|
6
|
+
* yujin.forge.json under `workflow.*` so it survives across
|
|
7
|
+
* sessions + can be inspected + shared via the git repo.
|
|
8
|
+
*
|
|
9
|
+
* Every command in the workflow (yf triage, yf discover, yf
|
|
10
|
+
* clarify, yf spec, yf approve, yf bootstrap, yf block dev, yf
|
|
11
|
+
* deploy, yf manual, yf metrics, yf iterate) reads + writes
|
|
12
|
+
* through this module. The chat tool surface (forge_triage,
|
|
13
|
+
* forge_discover, etc) does the same -- the underlying state
|
|
14
|
+
* is identical regardless of entry point.
|
|
15
|
+
*
|
|
16
|
+
* Schema:
|
|
17
|
+
*
|
|
18
|
+
* workflow: {
|
|
19
|
+
* tier: 'simple' | 'medium' | 'full' | null,
|
|
20
|
+
* tier_reason: string,
|
|
21
|
+
* tier_decided_at: ISO,
|
|
22
|
+
*
|
|
23
|
+
* intent: { ... } // Phase I step 3
|
|
24
|
+
* legacy_audit: { ... } // Phase I step 3.5
|
|
25
|
+
* vault_inventory: { ... } // Phase I step 2 audit
|
|
26
|
+
*
|
|
27
|
+
* clarification: {
|
|
28
|
+
* functional: { done_at, summary, doc_path }, // step 4
|
|
29
|
+
* nfr_quantitative: { done_at, summary, doc_path }, // step 5
|
|
30
|
+
* nfr_structural: { done_at, summary, doc_path }, // step 6
|
|
31
|
+
* nfr_governance: { done_at, summary, doc_path }, // step 7
|
|
32
|
+
* nfr_operational: { done_at, summary, doc_path }, // step 8
|
|
33
|
+
* blocks: { done_at, blocks: [...] }, // step 9
|
|
34
|
+
* },
|
|
35
|
+
*
|
|
36
|
+
* specs: {
|
|
37
|
+
* rfp: { done_at, version, doc_path, sha256 }, // step 10
|
|
38
|
+
* arch: { done_at, version, doc_path, sha256 }, // step 11
|
|
39
|
+
* design: { done_at, version, doc_path, sha256 }, // step 12
|
|
40
|
+
* },
|
|
41
|
+
*
|
|
42
|
+
* approvals: {
|
|
43
|
+
* rfp: { approved_at, version_sha256 }, // step 13
|
|
44
|
+
* arch: { approved_at, version_sha256 }, // step 13
|
|
45
|
+
* design: { approved_at, version_sha256 }, // step 13
|
|
46
|
+
* },
|
|
47
|
+
*
|
|
48
|
+
* bootstrap: { done_at, stack, ci_set }, // step 14
|
|
49
|
+
*
|
|
50
|
+
* blocks_progress: [ // step 15
|
|
51
|
+
* { block_id, status, tests_green_at, deployed_at }
|
|
52
|
+
* ],
|
|
53
|
+
*
|
|
54
|
+
* deploy: { ... } // step 16
|
|
55
|
+
* postlaunch:{ ... } // step 17
|
|
56
|
+
* iterations:[{ at, type, summary }] // step 18
|
|
57
|
+
* }
|
|
58
|
+
*
|
|
59
|
+
* ASCII-only.
|
|
60
|
+
*/
|
|
61
|
+
import { promises as fs } from 'node:fs';
|
|
62
|
+
import path from 'node:path';
|
|
63
|
+
const CONFIG_FILE = 'yujin.forge.json';
|
|
64
|
+
function configPath(projectRoot) {
|
|
65
|
+
return path.join(projectRoot, CONFIG_FILE);
|
|
66
|
+
}
|
|
67
|
+
export async function loadConfig(projectRoot) {
|
|
68
|
+
try {
|
|
69
|
+
const raw = await fs.readFile(configPath(projectRoot), 'utf-8');
|
|
70
|
+
const parsed = JSON.parse(raw);
|
|
71
|
+
if (parsed && typeof parsed === 'object')
|
|
72
|
+
return parsed;
|
|
73
|
+
}
|
|
74
|
+
catch (err) {
|
|
75
|
+
if (err.code !== 'ENOENT'
|
|
76
|
+
&& !(err instanceof SyntaxError)) {
|
|
77
|
+
throw err;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return {};
|
|
81
|
+
}
|
|
82
|
+
export async function saveConfig(projectRoot, cfg) {
|
|
83
|
+
const text = JSON.stringify(cfg, null, 2) + '\n';
|
|
84
|
+
await fs.writeFile(configPath(projectRoot), text, 'utf-8');
|
|
85
|
+
}
|
|
86
|
+
export async function readWorkflow(projectRoot) {
|
|
87
|
+
const cfg = await loadConfig(projectRoot);
|
|
88
|
+
return cfg.workflow ?? {};
|
|
89
|
+
}
|
|
90
|
+
export async function writeWorkflow(projectRoot, patch) {
|
|
91
|
+
const cfg = await loadConfig(projectRoot);
|
|
92
|
+
cfg.workflow = { ...(cfg.workflow ?? {}), ...patch };
|
|
93
|
+
await saveConfig(projectRoot, cfg);
|
|
94
|
+
return cfg.workflow;
|
|
95
|
+
}
|
|
96
|
+
/** Update a NESTED key under workflow.<group> (clarification,
|
|
97
|
+
* specs, approvals, blocks_progress) without overwriting sibling
|
|
98
|
+
* keys at the same level. */
|
|
99
|
+
export async function patchWorkflowGroup(projectRoot, group, patch) {
|
|
100
|
+
const cfg = await loadConfig(projectRoot);
|
|
101
|
+
const wf = cfg.workflow ?? {};
|
|
102
|
+
const prev = (wf[group] ?? {});
|
|
103
|
+
const merged = { ...prev, ...patch };
|
|
104
|
+
cfg.workflow = { ...wf, [group]: merged };
|
|
105
|
+
await saveConfig(projectRoot, cfg);
|
|
106
|
+
return cfg.workflow;
|
|
107
|
+
}
|
|
108
|
+
/** Append to workflow.iterations[]. Idempotent: callers should
|
|
109
|
+
* generate a unique-ish `at` per call so duplicates do not stack. */
|
|
110
|
+
export async function appendIteration(projectRoot, entry) {
|
|
111
|
+
const cfg = await loadConfig(projectRoot);
|
|
112
|
+
const wf = cfg.workflow ?? {};
|
|
113
|
+
const list = Array.isArray(wf.iterations) ? wf.iterations : [];
|
|
114
|
+
list.push(entry);
|
|
115
|
+
cfg.workflow = { ...wf, iterations: list };
|
|
116
|
+
await saveConfig(projectRoot, cfg);
|
|
117
|
+
return cfg.workflow;
|
|
118
|
+
}
|
|
119
|
+
//# sourceMappingURL=state.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state.js","sourceRoot":"","sources":["../../src/workflow/state.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nac3/forge-cli",
|
|
3
|
-
"version": "0.2.0-alpha.
|
|
3
|
+
"version": "0.2.0-alpha.21",
|
|
4
4
|
"description": "Yujin Forge -- voice-first NAC-3 React development framework. CLI + chat panel + spec ingest + 10-format document reader + voice loop.",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE",
|
|
6
6
|
"author": "Pablo Kuschnirof <pablo@rpaforce.com>",
|
|
@@ -15,17 +15,6 @@
|
|
|
15
15
|
"exports": {
|
|
16
16
|
".": "./dist/index.js"
|
|
17
17
|
},
|
|
18
|
-
"scripts": {
|
|
19
|
-
"build": "tsc",
|
|
20
|
-
"dev": "tsx watch src/bin/yf.ts",
|
|
21
|
-
"typecheck": "tsc --noEmit",
|
|
22
|
-
"test": "vitest run",
|
|
23
|
-
"test:watch": "vitest",
|
|
24
|
-
"lint": "tsc --noEmit",
|
|
25
|
-
"yf": "tsx src/bin/yf.ts",
|
|
26
|
-
"catalog:lint": "node scripts/catalog_lint.mjs",
|
|
27
|
-
"prepublishOnly": "pnpm run build && pnpm run typecheck && pnpm run catalog:lint && pnpm run test"
|
|
28
|
-
},
|
|
29
18
|
"dependencies": {
|
|
30
19
|
"@anthropic-ai/sdk": "^0.32.1",
|
|
31
20
|
"@aws-sdk/client-ecs": "^3.1053.0",
|
|
@@ -50,9 +39,8 @@
|
|
|
50
39
|
},
|
|
51
40
|
"engines": {
|
|
52
41
|
"node": ">=18.17",
|
|
53
|
-
"pnpm": ">=
|
|
42
|
+
"pnpm": ">=9"
|
|
54
43
|
},
|
|
55
|
-
"packageManager": "pnpm@11.3.0",
|
|
56
44
|
"files": [
|
|
57
45
|
"dist",
|
|
58
46
|
"templates",
|
|
@@ -90,5 +78,15 @@
|
|
|
90
78
|
"publishConfig": {
|
|
91
79
|
"access": "public",
|
|
92
80
|
"tag": "alpha"
|
|
81
|
+
},
|
|
82
|
+
"scripts": {
|
|
83
|
+
"build": "tsc",
|
|
84
|
+
"dev": "tsx watch src/bin/yf.ts",
|
|
85
|
+
"typecheck": "tsc --noEmit",
|
|
86
|
+
"test": "vitest run",
|
|
87
|
+
"test:watch": "vitest",
|
|
88
|
+
"lint": "tsc --noEmit",
|
|
89
|
+
"yf": "tsx src/bin/yf.ts",
|
|
90
|
+
"catalog:lint": "node scripts/catalog_lint.mjs"
|
|
93
91
|
}
|
|
94
|
-
}
|
|
92
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# %%PROJECT_NAME%%
|
|
2
|
+
|
|
3
|
+
A Yujin Forge **Next.js (App Router)** starter, NAC-3 conformant by construction.
|
|
4
|
+
|
|
5
|
+
## Stack
|
|
6
|
+
|
|
7
|
+
- **Next.js 15** with the App Router (`src/app/`).
|
|
8
|
+
- **React 18** + TypeScript 5.
|
|
9
|
+
- **@yujin/nac 2.3.x** -- NAC-3 runtime + manifest types.
|
|
10
|
+
- **Vitest** for unit tests, **Playwright** for e2e.
|
|
11
|
+
|
|
12
|
+
## Why Next.js (vs the react-app starter)
|
|
13
|
+
|
|
14
|
+
Pick this starter when you need:
|
|
15
|
+
- Server-side rendering / streaming for SEO or fast first paint.
|
|
16
|
+
- Route-level code splitting + edge runtime.
|
|
17
|
+
- Built-in API routes (no separate backend yet).
|
|
18
|
+
- File-based routing (App Router conventions).
|
|
19
|
+
|
|
20
|
+
If you just want a SPA, the `react-app` template is leaner (Vite,
|
|
21
|
+
no server runtime, fastest dev).
|
|
22
|
+
|
|
23
|
+
## Quick start
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
npm install
|
|
27
|
+
npm run dev # http://localhost:3000
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Tests
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
npm run test # Vitest unit tests
|
|
34
|
+
npm run test:e2e # Playwright e2e (requires `npx playwright install` once)
|
|
35
|
+
npm run typecheck # TypeScript strict mode
|
|
36
|
+
npm run lint # next lint (eslint-config-next)
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Yujin Forge integration
|
|
40
|
+
|
|
41
|
+
Open the project in `yf chat` to drive development via voice + chat:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
yf chat
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
The chat panel reads `src/nac/manifest.ts` and exposes each
|
|
48
|
+
manifest element as a tool the AI can invoke.
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "%%PROJECT_SLUG%%",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"description": "%%PROJECT_NAME%% -- Yujin Forge Next.js app (App Router), NAC-3 conformant by construction.",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"dev": "next dev",
|
|
8
|
+
"build": "next build",
|
|
9
|
+
"start": "next start",
|
|
10
|
+
"test": "vitest run",
|
|
11
|
+
"test:watch": "vitest",
|
|
12
|
+
"test:e2e": "playwright test",
|
|
13
|
+
"lint": "next lint",
|
|
14
|
+
"typecheck": "tsc --noEmit",
|
|
15
|
+
"yf": "yf"
|
|
16
|
+
},
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"next": "15.0.4",
|
|
19
|
+
"react": "18.3.1",
|
|
20
|
+
"react-dom": "18.3.1",
|
|
21
|
+
"@yujin/nac": "^2.3.0"
|
|
22
|
+
},
|
|
23
|
+
"devDependencies": {
|
|
24
|
+
"@types/node": "22.10.2",
|
|
25
|
+
"@types/react": "18.3.18",
|
|
26
|
+
"@types/react-dom": "18.3.5",
|
|
27
|
+
"@playwright/test": "1.49.1",
|
|
28
|
+
"eslint": "9.17.0",
|
|
29
|
+
"eslint-config-next": "15.0.4",
|
|
30
|
+
"typescript": "5.7.2",
|
|
31
|
+
"vitest": "2.1.8"
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
:root {
|
|
2
|
+
--bg: #fafafa;
|
|
3
|
+
--fg: #1a1a1a;
|
|
4
|
+
--accent: #c0392b;
|
|
5
|
+
--border: #e0e0e0;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
* { box-sizing: border-box; }
|
|
9
|
+
|
|
10
|
+
body {
|
|
11
|
+
margin: 0;
|
|
12
|
+
padding: 2rem;
|
|
13
|
+
font-family: ui-sans-serif, system-ui, -apple-system, sans-serif;
|
|
14
|
+
background: var(--bg);
|
|
15
|
+
color: var(--fg);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
main {
|
|
19
|
+
max-width: 32rem;
|
|
20
|
+
margin: 0 auto;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
h1 { font-weight: 500; margin-bottom: 1rem; }
|
|
24
|
+
|
|
25
|
+
input {
|
|
26
|
+
width: 70%;
|
|
27
|
+
padding: 0.5rem 0.75rem;
|
|
28
|
+
border: 1px solid var(--border);
|
|
29
|
+
border-radius: 0.25rem;
|
|
30
|
+
margin-right: 0.5rem;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
button {
|
|
34
|
+
padding: 0.5rem 1rem;
|
|
35
|
+
background: var(--accent);
|
|
36
|
+
color: white;
|
|
37
|
+
border: none;
|
|
38
|
+
border-radius: 0.25rem;
|
|
39
|
+
cursor: pointer;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
ul { list-style: none; padding: 0; margin: 1.5rem 0 0; }
|
|
43
|
+
li { padding: 0.5rem; border-bottom: 1px solid var(--border); }
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Root layout for the App Router. Every route renders inside
|
|
3
|
+
* the <html> + <body> here, so this is where Yujin Pilot would
|
|
4
|
+
* inject its panel + NAC-3 runtime in a real project.
|
|
5
|
+
*/
|
|
6
|
+
import type { Metadata, Viewport } from 'next';
|
|
7
|
+
import './globals.css';
|
|
8
|
+
|
|
9
|
+
export const metadata: Metadata = {
|
|
10
|
+
title: '%%PROJECT_NAME%%',
|
|
11
|
+
description: 'Built with Yujin Forge -- NAC-3 by construction.',
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export const viewport: Viewport = {
|
|
15
|
+
width: 'device-width',
|
|
16
|
+
initialScale: 1,
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export default function RootLayout({
|
|
20
|
+
children,
|
|
21
|
+
}: {
|
|
22
|
+
children: React.ReactNode;
|
|
23
|
+
}) {
|
|
24
|
+
return (
|
|
25
|
+
<html lang="es" data-nac-app="%%PROJECT_SLUG%%">
|
|
26
|
+
<body>{children}</body>
|
|
27
|
+
</html>
|
|
28
|
+
);
|
|
29
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
/**
|
|
3
|
+
* Home page -- a single-input todo list, decorated with NAC-3 attrs
|
|
4
|
+
* so the chat panel can drive it ("add task X", "mark task 1 done").
|
|
5
|
+
*
|
|
6
|
+
* Same shape as the react-app template's App.tsx, ported to the
|
|
7
|
+
* Next.js App Router. Client component because we use useState.
|
|
8
|
+
*/
|
|
9
|
+
import { useState } from 'react';
|
|
10
|
+
|
|
11
|
+
interface Todo { id: number; text: string; done: boolean }
|
|
12
|
+
|
|
13
|
+
export default function Home() {
|
|
14
|
+
const [todos, setTodos] = useState<Todo[]>([]);
|
|
15
|
+
const [draft, setDraft] = useState('');
|
|
16
|
+
|
|
17
|
+
function addTodo(): void {
|
|
18
|
+
const text = draft.trim();
|
|
19
|
+
if (!text) return;
|
|
20
|
+
setTodos((cur) => [...cur, { id: Date.now(), text, done: false }]);
|
|
21
|
+
setDraft('');
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function toggleTodo(id: number): void {
|
|
25
|
+
setTodos((cur) => cur.map((t) =>
|
|
26
|
+
t.id === id ? { ...t, done: !t.done } : t,
|
|
27
|
+
));
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return (
|
|
31
|
+
<main data-nac-id="todos.app">
|
|
32
|
+
<h1>%%PROJECT_NAME%%</h1>
|
|
33
|
+
<input
|
|
34
|
+
type="text"
|
|
35
|
+
value={draft}
|
|
36
|
+
onChange={(e) => setDraft(e.target.value)}
|
|
37
|
+
onKeyDown={(e) => { if (e.key === 'Enter') addTodo(); }}
|
|
38
|
+
data-nac-id="todos.input"
|
|
39
|
+
data-nac-role="field"
|
|
40
|
+
data-nac-action="input"
|
|
41
|
+
placeholder="New task..."
|
|
42
|
+
/>
|
|
43
|
+
<button
|
|
44
|
+
onClick={addTodo}
|
|
45
|
+
data-nac-id="todos.add_button"
|
|
46
|
+
data-nac-role="action"
|
|
47
|
+
data-nac-action="add_todo"
|
|
48
|
+
>Add</button>
|
|
49
|
+
<ul data-nac-id="todos.list" data-nac-role="list">
|
|
50
|
+
{todos.map((t) => (
|
|
51
|
+
<li
|
|
52
|
+
key={t.id}
|
|
53
|
+
data-nac-id={'todos.item.' + t.id}
|
|
54
|
+
data-nac-role="item"
|
|
55
|
+
data-nac-state={t.done ? 'done' : 'pending'}
|
|
56
|
+
onClick={() => toggleTodo(t.id)}
|
|
57
|
+
style={{ textDecoration: t.done ? 'line-through' : 'none', cursor: 'pointer' }}
|
|
58
|
+
>{t.text}</li>
|
|
59
|
+
))}
|
|
60
|
+
</ul>
|
|
61
|
+
</main>
|
|
62
|
+
);
|
|
63
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* NAC-3 manifest for the todos plugin. Same shape as the
|
|
3
|
+
* react-app template; the runtime reads this on boot and
|
|
4
|
+
* exposes each verb to agents + the chat panel.
|
|
5
|
+
*
|
|
6
|
+
* label_i18n covers the 10 NAC default locales.
|
|
7
|
+
*/
|
|
8
|
+
import type { Manifest } from '@yujin/nac';
|
|
9
|
+
|
|
10
|
+
export const TODOS_MANIFEST: Manifest = {
|
|
11
|
+
plugin: 'todos',
|
|
12
|
+
version: '1.0.0',
|
|
13
|
+
elements: [
|
|
14
|
+
{
|
|
15
|
+
nac_id: 'todos.input',
|
|
16
|
+
role: 'field',
|
|
17
|
+
kind: 'text',
|
|
18
|
+
label_i18n: {
|
|
19
|
+
es: 'Nueva tarea', en: 'New task', pt: 'Nova tarefa',
|
|
20
|
+
fr: 'Nouvelle tache', de: 'Neue Aufgabe', it: 'Nuovo compito',
|
|
21
|
+
ja: 'New task', zh: 'New task', hi: 'New task',
|
|
22
|
+
ar: 'New task',
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
nac_id: 'todos.add_button',
|
|
27
|
+
role: 'action',
|
|
28
|
+
verb: 'add_todo',
|
|
29
|
+
label_i18n: {
|
|
30
|
+
es: 'Agregar', en: 'Add', pt: 'Adicionar', fr: 'Ajouter',
|
|
31
|
+
de: 'Add', it: 'Add', ja: 'Add', zh: 'Add',
|
|
32
|
+
hi: 'Add', ar: 'Add',
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
],
|
|
36
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"lib": ["dom", "dom.iterable", "esnext"],
|
|
5
|
+
"module": "esnext",
|
|
6
|
+
"moduleResolution": "bundler",
|
|
7
|
+
"jsx": "preserve",
|
|
8
|
+
"strict": true,
|
|
9
|
+
"noEmit": true,
|
|
10
|
+
"esModuleInterop": true,
|
|
11
|
+
"skipLibCheck": true,
|
|
12
|
+
"allowJs": true,
|
|
13
|
+
"incremental": true,
|
|
14
|
+
"resolveJsonModule": true,
|
|
15
|
+
"isolatedModules": true,
|
|
16
|
+
"plugins": [{ "name": "next" }],
|
|
17
|
+
"paths": { "@/*": ["./src/*"] }
|
|
18
|
+
},
|
|
19
|
+
"include": ["next-env.d.ts", "src/**/*.ts", "src/**/*.tsx"],
|
|
20
|
+
"exclude": ["node_modules", ".next"]
|
|
21
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://yujin.app/schemas/yujin.forge.json",
|
|
3
|
+
"project_slug": "%%PROJECT_SLUG%%",
|
|
4
|
+
"project_name": "%%PROJECT_NAME%%",
|
|
5
|
+
"forge_version": "0.1.0",
|
|
6
|
+
"nac_version": "2.3.x",
|
|
7
|
+
"license_ref": "%%LICENSE_REF%%",
|
|
8
|
+
"framework": "nextjs",
|
|
9
|
+
"telemetry": { "opt_out": false },
|
|
10
|
+
"generate": { "tests": true, "mocks": true }
|
|
11
|
+
}
|