create-izi-noir 0.2.5 → 0.2.6
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/index.js +832 -3
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -68,6 +68,16 @@ async function promptProjectOptions(defaults) {
|
|
|
68
68
|
name: "initGit",
|
|
69
69
|
message: "Initialize git repository?",
|
|
70
70
|
initial: !defaults.skipGit
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
type: "select",
|
|
74
|
+
name: "aiTool",
|
|
75
|
+
message: "Which AI coding assistant do you use?",
|
|
76
|
+
choices: [
|
|
77
|
+
{ title: "Claude Code", value: "claude", description: "Install IZI-NOIR circuit patterns skill" },
|
|
78
|
+
{ title: "None / Other", value: "none", description: "Skip AI assistant configuration" }
|
|
79
|
+
],
|
|
80
|
+
initial: 0
|
|
71
81
|
}
|
|
72
82
|
);
|
|
73
83
|
try {
|
|
@@ -82,7 +92,8 @@ async function promptProjectOptions(defaults) {
|
|
|
82
92
|
template: response.template || defaults.template || "default",
|
|
83
93
|
provider: networkToProvider(network),
|
|
84
94
|
skipInstall: response.installDeps === false,
|
|
85
|
-
skipGit: response.initGit === false
|
|
95
|
+
skipGit: response.initGit === false,
|
|
96
|
+
aiTool: response.aiTool || "none"
|
|
86
97
|
};
|
|
87
98
|
} catch {
|
|
88
99
|
return null;
|
|
@@ -1760,6 +1771,810 @@ export function EditableCodeBlock({
|
|
|
1760
1771
|
`;
|
|
1761
1772
|
}
|
|
1762
1773
|
|
|
1774
|
+
// src/generators/claude-skills.ts
|
|
1775
|
+
function generateClaudeSkills() {
|
|
1776
|
+
return {
|
|
1777
|
+
".claude/skills/izi-noir-circuit-patterns/SKILL.md": SKILL_MD,
|
|
1778
|
+
".claude/skills/izi-noir-circuit-patterns/assets/valid-examples.ts": VALID_EXAMPLES_TS,
|
|
1779
|
+
".claude/skills/izi-noir-circuit-patterns/assets/operator-mapping.md": OPERATOR_MAPPING_MD
|
|
1780
|
+
};
|
|
1781
|
+
}
|
|
1782
|
+
var SKILL_MD = `---
|
|
1783
|
+
name: izi-noir-circuit-patterns
|
|
1784
|
+
description: >
|
|
1785
|
+
Patterns for writing JS/TS code that transpiles to Noir ZK circuits.
|
|
1786
|
+
Trigger: When writing circuit functions, IziNoir API, Solana deployment, Provider/Chain selection, or JS-to-Noir transformations.
|
|
1787
|
+
license: MIT
|
|
1788
|
+
metadata:
|
|
1789
|
+
author: izi-noir
|
|
1790
|
+
version: "2.0"
|
|
1791
|
+
scope: [sdk, frontend, solana-contracts]
|
|
1792
|
+
auto_invoke:
|
|
1793
|
+
- "circuit function"
|
|
1794
|
+
- "createProof"
|
|
1795
|
+
- "IziNoir"
|
|
1796
|
+
- "assert statement"
|
|
1797
|
+
- "JS to Noir"
|
|
1798
|
+
- "zero knowledge"
|
|
1799
|
+
- "Solana proof"
|
|
1800
|
+
- "Chain.Solana"
|
|
1801
|
+
- "Provider.Arkworks"
|
|
1802
|
+
allowed-tools: Read, Glob, Grep
|
|
1803
|
+
---
|
|
1804
|
+
|
|
1805
|
+
# IZI-NOIR Circuit Patterns
|
|
1806
|
+
|
|
1807
|
+
Patterns for writing JavaScript/TypeScript code that the SDK can parse and transpile 1:1 to Noir ZK circuits, with Solana on-chain verification support.
|
|
1808
|
+
|
|
1809
|
+
## When to Use
|
|
1810
|
+
|
|
1811
|
+
- Writing circuit functions for \`createProof()\`
|
|
1812
|
+
- Using the IziNoir class API (init, compile, prove, deploy, verifyOnChain)
|
|
1813
|
+
- Deploying proofs to Solana
|
|
1814
|
+
- Choosing between providers (Arkworks, Barretenberg)
|
|
1815
|
+
- Debugging parsing or Noir generation errors
|
|
1816
|
+
- Understanding JS \u2192 Noir type mapping
|
|
1817
|
+
|
|
1818
|
+
## Architecture Overview
|
|
1819
|
+
|
|
1820
|
+
\`\`\`
|
|
1821
|
+
JS Function \u2192 AcornParser \u2192 NoirGenerator \u2192 Noir WASM \u2192 ArkworksWasm \u2192 Solana
|
|
1822
|
+
\`\`\`
|
|
1823
|
+
|
|
1824
|
+
**Pipeline layers:**
|
|
1825
|
+
1. **Domain Layer** - Core types: Circuit, Proof, VerifyingKey, Provider, Chain, Network
|
|
1826
|
+
2. **Application Layer** - Services: NoirGenerator, createProof orchestration
|
|
1827
|
+
3. **Infrastructure Layer** - Parsers (Acorn), Compilers (Noir WASM), Provers (Arkworks/BB)
|
|
1828
|
+
|
|
1829
|
+
## IziNoir Class API
|
|
1830
|
+
|
|
1831
|
+
### Initialization
|
|
1832
|
+
|
|
1833
|
+
\`\`\`typescript
|
|
1834
|
+
import { IziNoir, Provider, Chain, Network } from '@izi-noir/sdk';
|
|
1835
|
+
|
|
1836
|
+
// Basic initialization (development)
|
|
1837
|
+
const izi = await IziNoir.init({
|
|
1838
|
+
provider: Provider.Arkworks,
|
|
1839
|
+
});
|
|
1840
|
+
|
|
1841
|
+
// With Solana chain targeting
|
|
1842
|
+
const izi = await IziNoir.init({
|
|
1843
|
+
provider: Provider.Arkworks,
|
|
1844
|
+
chain: Chain.Solana,
|
|
1845
|
+
network: Network.Devnet,
|
|
1846
|
+
});
|
|
1847
|
+
\`\`\`
|
|
1848
|
+
|
|
1849
|
+
### Providers
|
|
1850
|
+
|
|
1851
|
+
| Provider | Use Case | Proof Size | Notes |
|
|
1852
|
+
|----------|----------|------------|-------|
|
|
1853
|
+
| \`Provider.Arkworks\` | **Solana production** | 256 bytes | Groth16, native syscalls |
|
|
1854
|
+
| \`Provider.Barretenberg\` | Development/testing | ~2KB | UltraPlonk, faster setup |
|
|
1855
|
+
|
|
1856
|
+
**Rule:** Always use \`Provider.Arkworks\` for Solana on-chain verification.
|
|
1857
|
+
|
|
1858
|
+
### Chain and Network
|
|
1859
|
+
|
|
1860
|
+
\`\`\`typescript
|
|
1861
|
+
// Chain enum
|
|
1862
|
+
Chain.Solana // Format proofs for Solana verification
|
|
1863
|
+
Chain.EVM // Format proofs for EVM verification (future)
|
|
1864
|
+
|
|
1865
|
+
// Network enum
|
|
1866
|
+
Network.Devnet // Solana devnet
|
|
1867
|
+
Network.Mainnet // Solana mainnet
|
|
1868
|
+
Network.Localnet // Local validator
|
|
1869
|
+
\`\`\`
|
|
1870
|
+
|
|
1871
|
+
### Creating Proofs
|
|
1872
|
+
|
|
1873
|
+
\`\`\`typescript
|
|
1874
|
+
// Define circuit function
|
|
1875
|
+
const balanceProof = (
|
|
1876
|
+
[threshold]: [number], // public inputs
|
|
1877
|
+
[balance]: [number] // private inputs
|
|
1878
|
+
) => {
|
|
1879
|
+
assert(balance >= threshold);
|
|
1880
|
+
};
|
|
1881
|
+
|
|
1882
|
+
// Generate proof
|
|
1883
|
+
const result = await izi.createProof(
|
|
1884
|
+
balanceProof,
|
|
1885
|
+
[100], // public: threshold
|
|
1886
|
+
[1500] // private: actual balance
|
|
1887
|
+
);
|
|
1888
|
+
|
|
1889
|
+
console.log(result.verified); // true
|
|
1890
|
+
console.log(result.proof); // Uint8Array (256 bytes for Arkworks)
|
|
1891
|
+
\`\`\`
|
|
1892
|
+
|
|
1893
|
+
### Solana Deployment
|
|
1894
|
+
|
|
1895
|
+
\`\`\`typescript
|
|
1896
|
+
// Deploy verifying key to Solana
|
|
1897
|
+
const deployment = await izi.deploy(balanceProof, {
|
|
1898
|
+
payer: wallet,
|
|
1899
|
+
network: Network.Devnet,
|
|
1900
|
+
});
|
|
1901
|
+
|
|
1902
|
+
console.log(deployment.vkAccount); // PublicKey of VK account
|
|
1903
|
+
console.log(deployment.programId); // Verifier program ID
|
|
1904
|
+
|
|
1905
|
+
// Verify proof on-chain
|
|
1906
|
+
const txSignature = await izi.verifyOnChain(result.proof, {
|
|
1907
|
+
vkAccount: deployment.vkAccount,
|
|
1908
|
+
payer: wallet,
|
|
1909
|
+
});
|
|
1910
|
+
\`\`\`
|
|
1911
|
+
|
|
1912
|
+
### SolanaProofData Structure
|
|
1913
|
+
|
|
1914
|
+
When \`chain: Chain.Solana\`, proof data is formatted as:
|
|
1915
|
+
|
|
1916
|
+
\`\`\`typescript
|
|
1917
|
+
interface SolanaProofData {
|
|
1918
|
+
verifyingKey: {
|
|
1919
|
+
nr_pubinputs: number;
|
|
1920
|
+
vk_alpha_g1: number[]; // 64 bytes
|
|
1921
|
+
vk_beta_g2: number[]; // 128 bytes
|
|
1922
|
+
vk_gamma_g2: number[]; // 128 bytes
|
|
1923
|
+
vk_delta_g2: number[]; // 128 bytes
|
|
1924
|
+
vk_ic: number[][]; // (nr_pubinputs + 1) \xD7 64 bytes
|
|
1925
|
+
};
|
|
1926
|
+
proof: {
|
|
1927
|
+
ar: number[]; // 64 bytes - A point (G1)
|
|
1928
|
+
bs: number[]; // 128 bytes - B point (G2)
|
|
1929
|
+
krs: number[]; // 64 bytes - C point (G1)
|
|
1930
|
+
};
|
|
1931
|
+
publicInputs: number[][]; // Each input as 32-byte array
|
|
1932
|
+
}
|
|
1933
|
+
\`\`\`
|
|
1934
|
+
|
|
1935
|
+
## Critical Patterns
|
|
1936
|
+
|
|
1937
|
+
### 1. Function Signature (REQUIRED)
|
|
1938
|
+
|
|
1939
|
+
\`\`\`typescript
|
|
1940
|
+
// MUST use array destructuring for both parameters
|
|
1941
|
+
([publicInputs], [privateInputs]) => {
|
|
1942
|
+
// body with assert statements
|
|
1943
|
+
}
|
|
1944
|
+
|
|
1945
|
+
// Example with multiple inputs
|
|
1946
|
+
([expected, threshold], [secret, salt]) => {
|
|
1947
|
+
assert(secret * secret == expected);
|
|
1948
|
+
assert(secret > threshold);
|
|
1949
|
+
}
|
|
1950
|
+
\`\`\`
|
|
1951
|
+
|
|
1952
|
+
- First array: **public inputs** (marked \`pub\` in Noir)
|
|
1953
|
+
- Second array: **private inputs** (witness values)
|
|
1954
|
+
- Arrow function or function expression
|
|
1955
|
+
- Body: block statement \`{ }\` or single expression
|
|
1956
|
+
|
|
1957
|
+
### 2. Mutability Convention
|
|
1958
|
+
|
|
1959
|
+
\`\`\`typescript
|
|
1960
|
+
// Immutable (default)
|
|
1961
|
+
let x = a + b; // \u2192 let x: Field = a + b;
|
|
1962
|
+
|
|
1963
|
+
// Mutable (use mut_ prefix)
|
|
1964
|
+
let mut_sum = 0; // \u2192 let mut sum: Field = 0;
|
|
1965
|
+
mut_sum = mut_sum + 1; // \u2192 sum = sum + 1;
|
|
1966
|
+
\`\`\`
|
|
1967
|
+
|
|
1968
|
+
**Rule:** Prefix variable name with \`mut_\` for mutable variables. The prefix is stripped in generated Noir.
|
|
1969
|
+
|
|
1970
|
+
### 3. Operators
|
|
1971
|
+
|
|
1972
|
+
| JavaScript | Noir | Notes |
|
|
1973
|
+
|------------|------|-------|
|
|
1974
|
+
| \`==\` / \`===\` | \`==\` | Both map to equality |
|
|
1975
|
+
| \`!=\` / \`!==\` | \`!=\` | Both map to inequality |
|
|
1976
|
+
| \`+\` | \`+\` | Addition |
|
|
1977
|
+
| \`-\` | \`-\` | Subtraction |
|
|
1978
|
+
| \`*\` | \`*\` | Multiplication |
|
|
1979
|
+
| \`/\` | \`/\` | Division |
|
|
1980
|
+
| \`%\` | \`%\` | Modulo |
|
|
1981
|
+
| \`<\` | \`<\` | Less than |
|
|
1982
|
+
| \`>\` | \`>\` | Greater than |
|
|
1983
|
+
| \`<=\` | \`<=\` | Less than or equal |
|
|
1984
|
+
| \`>=\` | \`>=\` | Greater than or equal |
|
|
1985
|
+
| \`&&\` | \`&\` | **Converted to bitwise AND** |
|
|
1986
|
+
| \`\\|\\|\` | \`\\|\` | **Converted to bitwise OR** |
|
|
1987
|
+
| \`!\` | \`!\` | Logical NOT |
|
|
1988
|
+
| \`-x\` | \`-x\` | Negation |
|
|
1989
|
+
|
|
1990
|
+
**Warning:** \`&&\` and \`||\` are converted to bitwise operators in Noir!
|
|
1991
|
+
|
|
1992
|
+
### 4. Statements
|
|
1993
|
+
|
|
1994
|
+
#### Assert
|
|
1995
|
+
\`\`\`typescript
|
|
1996
|
+
assert(condition); // Basic assertion
|
|
1997
|
+
assert(condition, "message"); // With error message
|
|
1998
|
+
\`\`\`
|
|
1999
|
+
|
|
2000
|
+
#### Variable Declaration
|
|
2001
|
+
\`\`\`typescript
|
|
2002
|
+
let x = a + b; // Immutable
|
|
2003
|
+
let mut_counter = 0; // Mutable (mut_ prefix)
|
|
2004
|
+
const y = 10; // Immutable (const supported)
|
|
2005
|
+
\`\`\`
|
|
2006
|
+
|
|
2007
|
+
#### Assignment (mutable only)
|
|
2008
|
+
\`\`\`typescript
|
|
2009
|
+
mut_x = mut_x + 1; // Only valid for mut_ variables
|
|
2010
|
+
\`\`\`
|
|
2011
|
+
|
|
2012
|
+
#### If/Else
|
|
2013
|
+
\`\`\`typescript
|
|
2014
|
+
if (condition) {
|
|
2015
|
+
// consequent
|
|
2016
|
+
} else {
|
|
2017
|
+
// alternate
|
|
2018
|
+
}
|
|
2019
|
+
\`\`\`
|
|
2020
|
+
|
|
2021
|
+
#### For Loop
|
|
2022
|
+
\`\`\`typescript
|
|
2023
|
+
// Exclusive range (i < end)
|
|
2024
|
+
for (let i = 0; i < 10; i++) { }
|
|
2025
|
+
// \u2192 for i in 0..10 { }
|
|
2026
|
+
|
|
2027
|
+
// Inclusive range (i <= end)
|
|
2028
|
+
for (let i = 1; i <= 5; i++) { }
|
|
2029
|
+
// \u2192 for i in 1..=5 { }
|
|
2030
|
+
|
|
2031
|
+
// Variable bounds
|
|
2032
|
+
for (let i = start; i < end; i++) { }
|
|
2033
|
+
// \u2192 for i in start..end { }
|
|
2034
|
+
\`\`\`
|
|
2035
|
+
|
|
2036
|
+
**Loop constraints:**
|
|
2037
|
+
- Init: \`let i = start\`
|
|
2038
|
+
- Test: \`i < end\` or \`i <= end\`
|
|
2039
|
+
- Update: \`i++\`, \`++i\`, or \`i = i + 1\`
|
|
2040
|
+
|
|
2041
|
+
### 5. Expressions
|
|
2042
|
+
|
|
2043
|
+
#### Literals
|
|
2044
|
+
\`\`\`typescript
|
|
2045
|
+
5 // number \u2192 Field
|
|
2046
|
+
100n // bigint \u2192 Field
|
|
2047
|
+
"string" // string literal
|
|
2048
|
+
0x1234 // hex value
|
|
2049
|
+
true / false // boolean \u2192 bool
|
|
2050
|
+
\`\`\`
|
|
2051
|
+
|
|
2052
|
+
#### Arrays
|
|
2053
|
+
\`\`\`typescript
|
|
2054
|
+
let arr = [a, b, c]; // \u2192 [Field; 3]
|
|
2055
|
+
arr[0] // static index
|
|
2056
|
+
arr[i] // dynamic index
|
|
2057
|
+
arr.length // \u2192 arr.len()
|
|
2058
|
+
\`\`\`
|
|
2059
|
+
|
|
2060
|
+
#### Ternary (conditional)
|
|
2061
|
+
\`\`\`typescript
|
|
2062
|
+
let result = cond ? a : b;
|
|
2063
|
+
// \u2192 let result: Field = if cond { a } else { b };
|
|
2064
|
+
\`\`\`
|
|
2065
|
+
|
|
2066
|
+
#### Method Calls
|
|
2067
|
+
\`\`\`typescript
|
|
2068
|
+
arr.len() // Array length
|
|
2069
|
+
\`\`\`
|
|
2070
|
+
|
|
2071
|
+
### 6. Type Mapping
|
|
2072
|
+
|
|
2073
|
+
| JavaScript | Noir Type | Notes |
|
|
2074
|
+
|------------|-----------|-------|
|
|
2075
|
+
| \`number\` | \`Field\` | Default for all numerics |
|
|
2076
|
+
| \`bigint\` | \`Field\` | Converted to string |
|
|
2077
|
+
| \`boolean\` | \`bool\` | Only \`true\`/\`false\` literals |
|
|
2078
|
+
| \`[a,b,c]\` | \`[Field; 3]\` | Fixed-size array |
|
|
2079
|
+
|
|
2080
|
+
**Default type:** Everything is \`Field\` unless explicitly boolean.
|
|
2081
|
+
|
|
2082
|
+
## NOT Supported
|
|
2083
|
+
|
|
2084
|
+
These JavaScript features **cannot** be parsed:
|
|
2085
|
+
|
|
2086
|
+
- Object literals \`{ key: value }\`
|
|
2087
|
+
- Destructuring (except function parameters)
|
|
2088
|
+
- Spread operator \`...\`
|
|
2089
|
+
- Rest parameters \`...args\`
|
|
2090
|
+
- Template literals \`\\\`\${x}\\\`\`
|
|
2091
|
+
- Async/await
|
|
2092
|
+
- While/do-while loops
|
|
2093
|
+
- Switch statements
|
|
2094
|
+
- Function declarations inside circuit
|
|
2095
|
+
- Closures over external variables
|
|
2096
|
+
- Class methods
|
|
2097
|
+
- Regular expressions
|
|
2098
|
+
- Try/catch
|
|
2099
|
+
- Break/continue
|
|
2100
|
+
- Return statements
|
|
2101
|
+
- Computed property assignment \`arr[i] = x\`
|
|
2102
|
+
|
|
2103
|
+
## Code Examples
|
|
2104
|
+
|
|
2105
|
+
See [assets/valid-examples.ts](assets/valid-examples.ts) for complete working examples.
|
|
2106
|
+
|
|
2107
|
+
## CLI: create-izi-noir
|
|
2108
|
+
|
|
2109
|
+
Scaffold new projects quickly:
|
|
2110
|
+
|
|
2111
|
+
\`\`\`bash
|
|
2112
|
+
# Interactive mode
|
|
2113
|
+
npx create-izi-noir
|
|
2114
|
+
|
|
2115
|
+
# Quick setup
|
|
2116
|
+
npx create-izi-noir my-project --yes
|
|
2117
|
+
|
|
2118
|
+
# With specific template
|
|
2119
|
+
npx create-izi-noir my-project --template balance-proof
|
|
2120
|
+
|
|
2121
|
+
# With specific provider
|
|
2122
|
+
npx create-izi-noir my-project --provider arkworks
|
|
2123
|
+
\`\`\`
|
|
2124
|
+
|
|
2125
|
+
**Templates:**
|
|
2126
|
+
- \`default\` - Balance proof + age verification circuits
|
|
2127
|
+
- \`minimal\` - Blank canvas with empty circuit
|
|
2128
|
+
- \`balance-proof\` - Just balance proof circuit
|
|
2129
|
+
|
|
2130
|
+
**Options:**
|
|
2131
|
+
- \`-t, --template <template>\` - Template to use
|
|
2132
|
+
- \`-p, --provider <provider>\` - Proving provider (arkworks/barretenberg)
|
|
2133
|
+
- \`-y, --yes\` - Skip prompts
|
|
2134
|
+
- \`--skip-install\` - Skip npm install
|
|
2135
|
+
- \`--skip-git\` - Skip git init
|
|
2136
|
+
|
|
2137
|
+
## Frontend Integration (Vite)
|
|
2138
|
+
|
|
2139
|
+
\`\`\`typescript
|
|
2140
|
+
// vite.config.ts
|
|
2141
|
+
export default defineConfig({
|
|
2142
|
+
optimizeDeps: {
|
|
2143
|
+
exclude: ['@noir-lang/noirc_abi', '@noir-lang/acvm_js'],
|
|
2144
|
+
},
|
|
2145
|
+
});
|
|
2146
|
+
|
|
2147
|
+
// main.ts - Initialize WASM before use
|
|
2148
|
+
import initNoirC from '@noir-lang/noirc_abi';
|
|
2149
|
+
import initACVM from '@noir-lang/acvm_js';
|
|
2150
|
+
import acvm from '@noir-lang/acvm_js/web/acvm_js_bg.wasm?url';
|
|
2151
|
+
import noirc from '@noir-lang/noirc_abi/web/noirc_abi_wasm_bg.wasm?url';
|
|
2152
|
+
import { markWasmInitialized, IziNoir, Provider } from '@izi-noir/sdk';
|
|
2153
|
+
|
|
2154
|
+
await Promise.all([initACVM(fetch(acvm)), initNoirC(fetch(noirc))]);
|
|
2155
|
+
markWasmInitialized();
|
|
2156
|
+
|
|
2157
|
+
// Now IziNoir is ready
|
|
2158
|
+
const izi = await IziNoir.init({ provider: Provider.Arkworks });
|
|
2159
|
+
\`\`\`
|
|
2160
|
+
|
|
2161
|
+
## Resources
|
|
2162
|
+
|
|
2163
|
+
- [Operator Mapping Table](assets/operator-mapping.md)
|
|
2164
|
+
- Parser: \`packages/sdk/src/infra/parser/AcornParser.ts\`
|
|
2165
|
+
- Generator: \`packages/sdk/src/application/services/NoirGenerator.ts\`
|
|
2166
|
+
- IziNoir Class: \`packages/sdk/src/IziNoir.ts\`
|
|
2167
|
+
`;
|
|
2168
|
+
var VALID_EXAMPLES_TS = `/**
|
|
2169
|
+
* Valid JS/TS Circuit Patterns for IZI-NOIR
|
|
2170
|
+
*
|
|
2171
|
+
* Each example shows the JS input and the generated Noir output.
|
|
2172
|
+
* All examples are valid and can be used with createProof().
|
|
2173
|
+
*/
|
|
2174
|
+
|
|
2175
|
+
// Declare assert for TypeScript (SDK parses it, not executed)
|
|
2176
|
+
declare function assert(condition: boolean, message?: string): void;
|
|
2177
|
+
|
|
2178
|
+
// =============================================================================
|
|
2179
|
+
// Example 1: Basic Assertion (simplest circuit)
|
|
2180
|
+
// =============================================================================
|
|
2181
|
+
/**
|
|
2182
|
+
* JS Input:
|
|
2183
|
+
*/
|
|
2184
|
+
export const basicAssertion = ([expected]: number[], [secret]: number[]) => {
|
|
2185
|
+
assert(secret * secret == expected);
|
|
2186
|
+
};
|
|
2187
|
+
/**
|
|
2188
|
+
* Generated Noir:
|
|
2189
|
+
* \`\`\`noir
|
|
2190
|
+
* fn main(secret: Field, expected: pub Field) {
|
|
2191
|
+
* assert(secret * secret == expected);
|
|
2192
|
+
* }
|
|
2193
|
+
* \`\`\`
|
|
2194
|
+
*/
|
|
2195
|
+
|
|
2196
|
+
// =============================================================================
|
|
2197
|
+
// Example 2: Multiple Inputs with Arithmetic
|
|
2198
|
+
// =============================================================================
|
|
2199
|
+
/**
|
|
2200
|
+
* JS Input:
|
|
2201
|
+
*/
|
|
2202
|
+
export const multipleInputs = (
|
|
2203
|
+
[sum, product]: number[],
|
|
2204
|
+
[a, b]: number[]
|
|
2205
|
+
) => {
|
|
2206
|
+
assert(a + b == sum);
|
|
2207
|
+
assert(a * b == product);
|
|
2208
|
+
};
|
|
2209
|
+
/**
|
|
2210
|
+
* Generated Noir:
|
|
2211
|
+
* \`\`\`noir
|
|
2212
|
+
* fn main(a: Field, b: Field, sum: pub Field, product: pub Field) {
|
|
2213
|
+
* assert(a + b == sum);
|
|
2214
|
+
* assert(a * b == product);
|
|
2215
|
+
* }
|
|
2216
|
+
* \`\`\`
|
|
2217
|
+
*/
|
|
2218
|
+
|
|
2219
|
+
// =============================================================================
|
|
2220
|
+
// Example 3: Variables and Mutability
|
|
2221
|
+
// =============================================================================
|
|
2222
|
+
/**
|
|
2223
|
+
* JS Input:
|
|
2224
|
+
*/
|
|
2225
|
+
export const variablesAndMutability = (
|
|
2226
|
+
[expected]: number[],
|
|
2227
|
+
[a, b]: number[]
|
|
2228
|
+
) => {
|
|
2229
|
+
// Immutable variable
|
|
2230
|
+
let sum = a + b;
|
|
2231
|
+
|
|
2232
|
+
// Mutable variable (mut_ prefix)
|
|
2233
|
+
let mut_result = 0;
|
|
2234
|
+
mut_result = sum * 2;
|
|
2235
|
+
|
|
2236
|
+
assert(mut_result == expected);
|
|
2237
|
+
};
|
|
2238
|
+
/**
|
|
2239
|
+
* Generated Noir:
|
|
2240
|
+
* \`\`\`noir
|
|
2241
|
+
* fn main(a: Field, b: Field, expected: pub Field) {
|
|
2242
|
+
* let sum: Field = a + b;
|
|
2243
|
+
* let mut result: Field = 0;
|
|
2244
|
+
* result = sum * 2;
|
|
2245
|
+
* assert(result == expected);
|
|
2246
|
+
* }
|
|
2247
|
+
* \`\`\`
|
|
2248
|
+
*/
|
|
2249
|
+
|
|
2250
|
+
// =============================================================================
|
|
2251
|
+
// Example 4: Conditional Logic (if/else)
|
|
2252
|
+
// =============================================================================
|
|
2253
|
+
/**
|
|
2254
|
+
* JS Input:
|
|
2255
|
+
*/
|
|
2256
|
+
export const conditionalLogic = (
|
|
2257
|
+
[threshold]: number[],
|
|
2258
|
+
[value]: number[]
|
|
2259
|
+
) => {
|
|
2260
|
+
let mut_result = 0;
|
|
2261
|
+
|
|
2262
|
+
if (value > threshold) {
|
|
2263
|
+
mut_result = 1;
|
|
2264
|
+
} else {
|
|
2265
|
+
mut_result = 0;
|
|
2266
|
+
}
|
|
2267
|
+
|
|
2268
|
+
assert(mut_result == 1);
|
|
2269
|
+
};
|
|
2270
|
+
/**
|
|
2271
|
+
* Generated Noir:
|
|
2272
|
+
* \`\`\`noir
|
|
2273
|
+
* fn main(value: Field, threshold: pub Field) {
|
|
2274
|
+
* let mut result: Field = 0;
|
|
2275
|
+
* if value > threshold {
|
|
2276
|
+
* result = 1;
|
|
2277
|
+
* } else {
|
|
2278
|
+
* result = 0;
|
|
2279
|
+
* }
|
|
2280
|
+
* assert(result == 1);
|
|
2281
|
+
* }
|
|
2282
|
+
* \`\`\`
|
|
2283
|
+
*/
|
|
2284
|
+
|
|
2285
|
+
// =============================================================================
|
|
2286
|
+
// Example 5: Ternary Expression
|
|
2287
|
+
// =============================================================================
|
|
2288
|
+
/**
|
|
2289
|
+
* JS Input:
|
|
2290
|
+
*/
|
|
2291
|
+
export const ternaryExpression = (
|
|
2292
|
+
[threshold]: number[],
|
|
2293
|
+
[value]: number[]
|
|
2294
|
+
) => {
|
|
2295
|
+
// Ternary converts to Noir if-expression
|
|
2296
|
+
let result = value > threshold ? 1 : 0;
|
|
2297
|
+
assert(result == 1);
|
|
2298
|
+
};
|
|
2299
|
+
/**
|
|
2300
|
+
* Generated Noir:
|
|
2301
|
+
* \`\`\`noir
|
|
2302
|
+
* fn main(value: Field, threshold: pub Field) {
|
|
2303
|
+
* let result: Field = if value > threshold { 1 } else { 0 };
|
|
2304
|
+
* assert(result == 1);
|
|
2305
|
+
* }
|
|
2306
|
+
* \`\`\`
|
|
2307
|
+
*/
|
|
2308
|
+
|
|
2309
|
+
// =============================================================================
|
|
2310
|
+
// Example 6: For Loop with Array
|
|
2311
|
+
// =============================================================================
|
|
2312
|
+
/**
|
|
2313
|
+
* JS Input:
|
|
2314
|
+
*/
|
|
2315
|
+
export const forLoopWithArray = (
|
|
2316
|
+
[expected]: number[],
|
|
2317
|
+
[a, b, c, d]: number[]
|
|
2318
|
+
) => {
|
|
2319
|
+
let arr = [a, b, c, d];
|
|
2320
|
+
let mut_sum = 0;
|
|
2321
|
+
|
|
2322
|
+
// Exclusive range: i < 4 \u2192 for i in 0..4
|
|
2323
|
+
for (let i = 0; i < 4; i++) {
|
|
2324
|
+
mut_sum = mut_sum + arr[i];
|
|
2325
|
+
}
|
|
2326
|
+
|
|
2327
|
+
assert(mut_sum == expected);
|
|
2328
|
+
};
|
|
2329
|
+
/**
|
|
2330
|
+
* Generated Noir:
|
|
2331
|
+
* \`\`\`noir
|
|
2332
|
+
* fn main(a: Field, b: Field, c: Field, d: Field, expected: pub Field) {
|
|
2333
|
+
* let arr: [Field; 4] = [a, b, c, d];
|
|
2334
|
+
* let mut sum: Field = 0;
|
|
2335
|
+
* for i in 0..4 {
|
|
2336
|
+
* sum = sum + arr[i];
|
|
2337
|
+
* }
|
|
2338
|
+
* assert(sum == expected);
|
|
2339
|
+
* }
|
|
2340
|
+
* \`\`\`
|
|
2341
|
+
*/
|
|
2342
|
+
|
|
2343
|
+
// =============================================================================
|
|
2344
|
+
// Example 7: Inclusive Range Loop
|
|
2345
|
+
// =============================================================================
|
|
2346
|
+
/**
|
|
2347
|
+
* JS Input:
|
|
2348
|
+
*/
|
|
2349
|
+
export const inclusiveRangeLoop = ([expected]: number[], [n]: number[]) => {
|
|
2350
|
+
let mut_sum = 0;
|
|
2351
|
+
|
|
2352
|
+
// Inclusive range: i <= n \u2192 for i in 1..=n
|
|
2353
|
+
for (let i = 1; i <= n; i++) {
|
|
2354
|
+
mut_sum = mut_sum + i;
|
|
2355
|
+
}
|
|
2356
|
+
|
|
2357
|
+
assert(mut_sum == expected);
|
|
2358
|
+
};
|
|
2359
|
+
/**
|
|
2360
|
+
* Generated Noir:
|
|
2361
|
+
* \`\`\`noir
|
|
2362
|
+
* fn main(n: Field, expected: pub Field) {
|
|
2363
|
+
* let mut sum: Field = 0;
|
|
2364
|
+
* for i in 1..=n {
|
|
2365
|
+
* sum = sum + i;
|
|
2366
|
+
* }
|
|
2367
|
+
* assert(sum == expected);
|
|
2368
|
+
* }
|
|
2369
|
+
* \`\`\`
|
|
2370
|
+
*/
|
|
2371
|
+
|
|
2372
|
+
// =============================================================================
|
|
2373
|
+
// Example 8: Nested Control Flow
|
|
2374
|
+
// =============================================================================
|
|
2375
|
+
/**
|
|
2376
|
+
* JS Input:
|
|
2377
|
+
*/
|
|
2378
|
+
export const nestedControlFlow = ([max]: number[], []: number[]) => {
|
|
2379
|
+
let mut_evenSum = 0;
|
|
2380
|
+
|
|
2381
|
+
for (let i = 1; i <= max; i++) {
|
|
2382
|
+
// Nested if inside loop
|
|
2383
|
+
if (i % 2 == 0) {
|
|
2384
|
+
mut_evenSum = mut_evenSum + i;
|
|
2385
|
+
}
|
|
2386
|
+
}
|
|
2387
|
+
|
|
2388
|
+
assert(mut_evenSum > 0);
|
|
2389
|
+
};
|
|
2390
|
+
/**
|
|
2391
|
+
* Generated Noir:
|
|
2392
|
+
* \`\`\`noir
|
|
2393
|
+
* fn main(max: pub Field) {
|
|
2394
|
+
* let mut evenSum: Field = 0;
|
|
2395
|
+
* for i in 1..=max {
|
|
2396
|
+
* if i % 2 == 0 {
|
|
2397
|
+
* evenSum = evenSum + i;
|
|
2398
|
+
* }
|
|
2399
|
+
* }
|
|
2400
|
+
* assert(evenSum > 0);
|
|
2401
|
+
* }
|
|
2402
|
+
* \`\`\`
|
|
2403
|
+
*/
|
|
2404
|
+
|
|
2405
|
+
// =============================================================================
|
|
2406
|
+
// Example 9: Comparison Operators
|
|
2407
|
+
// =============================================================================
|
|
2408
|
+
/**
|
|
2409
|
+
* JS Input:
|
|
2410
|
+
*/
|
|
2411
|
+
export const comparisonOperators = (
|
|
2412
|
+
[min, max]: number[],
|
|
2413
|
+
[value]: number[]
|
|
2414
|
+
) => {
|
|
2415
|
+
// All comparison operators
|
|
2416
|
+
assert(value >= min);
|
|
2417
|
+
assert(value <= max);
|
|
2418
|
+
assert(value != 0);
|
|
2419
|
+
|
|
2420
|
+
// Combined with arithmetic
|
|
2421
|
+
let doubled = value * 2;
|
|
2422
|
+
assert(doubled < max * 2);
|
|
2423
|
+
};
|
|
2424
|
+
/**
|
|
2425
|
+
* Generated Noir:
|
|
2426
|
+
* \`\`\`noir
|
|
2427
|
+
* fn main(value: Field, min: pub Field, max: pub Field) {
|
|
2428
|
+
* assert(value >= min);
|
|
2429
|
+
* assert(value <= max);
|
|
2430
|
+
* assert(value != 0);
|
|
2431
|
+
* let doubled: Field = value * 2;
|
|
2432
|
+
* assert(doubled < max * 2);
|
|
2433
|
+
* }
|
|
2434
|
+
* \`\`\`
|
|
2435
|
+
*/
|
|
2436
|
+
|
|
2437
|
+
// =============================================================================
|
|
2438
|
+
// Example 10: Array Length Access
|
|
2439
|
+
// =============================================================================
|
|
2440
|
+
/**
|
|
2441
|
+
* JS Input:
|
|
2442
|
+
*/
|
|
2443
|
+
export const arrayLengthAccess = (
|
|
2444
|
+
[expectedLen]: number[],
|
|
2445
|
+
[a, b, c]: number[]
|
|
2446
|
+
) => {
|
|
2447
|
+
let arr = [a, b, c];
|
|
2448
|
+
|
|
2449
|
+
// .length converts to .len() in Noir
|
|
2450
|
+
assert(arr.length == expectedLen);
|
|
2451
|
+
};
|
|
2452
|
+
/**
|
|
2453
|
+
* Generated Noir:
|
|
2454
|
+
* \`\`\`noir
|
|
2455
|
+
* fn main(a: Field, b: Field, c: Field, expectedLen: pub Field) {
|
|
2456
|
+
* let arr: [Field; 3] = [a, b, c];
|
|
2457
|
+
* assert(arr.len() == expectedLen);
|
|
2458
|
+
* }
|
|
2459
|
+
* \`\`\`
|
|
2460
|
+
*/
|
|
2461
|
+
`;
|
|
2462
|
+
var OPERATOR_MAPPING_MD = `# JavaScript to Noir Mapping Reference
|
|
2463
|
+
|
|
2464
|
+
Complete mapping of JavaScript constructs to their Noir equivalents.
|
|
2465
|
+
|
|
2466
|
+
## Binary Operators
|
|
2467
|
+
|
|
2468
|
+
| JavaScript | Noir | Category | Example |
|
|
2469
|
+
|------------|------|----------|---------|
|
|
2470
|
+
| \`==\` | \`==\` | Equality | \`a == b\` \u2192 \`a == b\` |
|
|
2471
|
+
| \`===\` | \`==\` | Strict equality | \`a === b\` \u2192 \`a == b\` |
|
|
2472
|
+
| \`!=\` | \`!=\` | Inequality | \`a != b\` \u2192 \`a != b\` |
|
|
2473
|
+
| \`!==\` | \`!=\` | Strict inequality | \`a !== b\` \u2192 \`a != b\` |
|
|
2474
|
+
| \`+\` | \`+\` | Addition | \`a + b\` \u2192 \`a + b\` |
|
|
2475
|
+
| \`-\` | \`-\` | Subtraction | \`a - b\` \u2192 \`a - b\` |
|
|
2476
|
+
| \`*\` | \`*\` | Multiplication | \`a * b\` \u2192 \`a * b\` |
|
|
2477
|
+
| \`/\` | \`/\` | Division | \`a / b\` \u2192 \`a / b\` |
|
|
2478
|
+
| \`%\` | \`%\` | Modulo | \`a % b\` \u2192 \`a % b\` |
|
|
2479
|
+
| \`<\` | \`<\` | Less than | \`a < b\` \u2192 \`a < b\` |
|
|
2480
|
+
| \`>\` | \`>\` | Greater than | \`a > b\` \u2192 \`a > b\` |
|
|
2481
|
+
| \`<=\` | \`<=\` | Less or equal | \`a <= b\` \u2192 \`a <= b\` |
|
|
2482
|
+
| \`>=\` | \`>=\` | Greater or equal | \`a >= b\` \u2192 \`a >= b\` |
|
|
2483
|
+
| \`&&\` | \`&\` | Logical AND | \`a && b\` \u2192 \`a & b\` |
|
|
2484
|
+
| \`\\|\\|\` | \`\\|\` | Logical OR | \`a \\|\\| b\` \u2192 \`a \\| b\` |
|
|
2485
|
+
|
|
2486
|
+
> **Warning:** Logical operators \`&&\` and \`||\` are converted to bitwise operators \`&\` and \`|\` in Noir.
|
|
2487
|
+
|
|
2488
|
+
## Unary Operators
|
|
2489
|
+
|
|
2490
|
+
| JavaScript | Noir | Category | Example |
|
|
2491
|
+
|------------|------|----------|---------|
|
|
2492
|
+
| \`!\` | \`!\` | Logical NOT | \`!a\` \u2192 \`!a\` |
|
|
2493
|
+
| \`-\` (prefix) | \`-\` | Negation | \`-a\` \u2192 \`-a\` |
|
|
2494
|
+
|
|
2495
|
+
## Type Mapping
|
|
2496
|
+
|
|
2497
|
+
| JavaScript Type | Noir Type | Notes |
|
|
2498
|
+
|-----------------|-----------|-------|
|
|
2499
|
+
| \`number\` | \`Field\` | Default numeric type |
|
|
2500
|
+
| \`bigint\` | \`Field\` | Converted to string |
|
|
2501
|
+
| \`boolean\` | \`bool\` | Only \`true\`/\`false\` literals |
|
|
2502
|
+
| \`string\` | String literal | Quoted in Noir |
|
|
2503
|
+
| \`number[]\` | \`[Field; N]\` | Fixed-size array |
|
|
2504
|
+
|
|
2505
|
+
## Statement Mapping
|
|
2506
|
+
|
|
2507
|
+
| JavaScript | Noir | Notes |
|
|
2508
|
+
|------------|------|-------|
|
|
2509
|
+
| \`assert(cond)\` | \`assert(cond)\` | Direct mapping |
|
|
2510
|
+
| \`assert(cond, "msg")\` | \`assert(cond, "msg")\` | With message |
|
|
2511
|
+
| \`let x = expr\` | \`let x: Type = expr\` | Immutable |
|
|
2512
|
+
| \`let mut_x = expr\` | \`let mut x: Type = expr\` | Mutable (prefix stripped) |
|
|
2513
|
+
| \`const x = expr\` | \`let x: Type = expr\` | Treated as let |
|
|
2514
|
+
| \`mut_x = expr\` | \`x = expr\` | Assignment (mutable only) |
|
|
2515
|
+
| \`if (c) { } else { }\` | \`if c { } else { }\` | No parens in Noir |
|
|
2516
|
+
| \`for (let i=s; i<e; i++)\` | \`for i in s..e { }\` | Exclusive range |
|
|
2517
|
+
| \`for (let i=s; i<=e; i++)\` | \`for i in s..=e { }\` | Inclusive range |
|
|
2518
|
+
|
|
2519
|
+
## Expression Mapping
|
|
2520
|
+
|
|
2521
|
+
| JavaScript | Noir | Notes |
|
|
2522
|
+
|------------|------|-------|
|
|
2523
|
+
| \`x\` | \`x\` | Identifier |
|
|
2524
|
+
| \`5\` | \`5\` | Number literal |
|
|
2525
|
+
| \`100n\` | \`100\` | BigInt to Field |
|
|
2526
|
+
| \`"str"\` | \`"str"\` | String literal |
|
|
2527
|
+
| \`0x1234\` | \`0x1234\` | Hex preserved |
|
|
2528
|
+
| \`true\` / \`false\` | \`true\` / \`false\` | Boolean |
|
|
2529
|
+
| \`[a, b, c]\` | \`[a, b, c]\` | Array literal |
|
|
2530
|
+
| \`arr[i]\` | \`arr[i]\` | Index access |
|
|
2531
|
+
| \`arr.length\` | \`arr.len()\` | Length method |
|
|
2532
|
+
| \`c ? a : b\` | \`if c { a } else { b }\` | Ternary \u2192 if expr |
|
|
2533
|
+
| \`a + b * c\` | \`a + b * c\` | Precedence preserved |
|
|
2534
|
+
|
|
2535
|
+
## Function Parameter Mapping
|
|
2536
|
+
|
|
2537
|
+
\`\`\`typescript
|
|
2538
|
+
// JavaScript
|
|
2539
|
+
([pub1, pub2], [priv1, priv2]) => { ... }
|
|
2540
|
+
|
|
2541
|
+
// Noir (private params first, then public with 'pub')
|
|
2542
|
+
fn main(priv1: Field, priv2: Field, pub1: pub Field, pub2: pub Field) { ... }
|
|
2543
|
+
\`\`\`
|
|
2544
|
+
|
|
2545
|
+
## Variable Naming Convention
|
|
2546
|
+
|
|
2547
|
+
| JavaScript | Noir | Rule |
|
|
2548
|
+
|------------|------|------|
|
|
2549
|
+
| \`x\` | \`x\` | Regular immutable |
|
|
2550
|
+
| \`mut_x\` | \`mut x\` | Mutable (prefix stripped) |
|
|
2551
|
+
| \`mut_counter\` | \`mut counter\` | Mutable (prefix stripped) |
|
|
2552
|
+
|
|
2553
|
+
## For Loop Patterns
|
|
2554
|
+
|
|
2555
|
+
| JavaScript | Noir | Range Type |
|
|
2556
|
+
|------------|------|------------|
|
|
2557
|
+
| \`for (let i = 0; i < 10; i++)\` | \`for i in 0..10\` | Exclusive |
|
|
2558
|
+
| \`for (let i = 1; i <= 5; i++)\` | \`for i in 1..=5\` | Inclusive |
|
|
2559
|
+
| \`for (let i = start; i < end; i++)\` | \`for i in start..end\` | Variable bounds |
|
|
2560
|
+
| \`for (let i = 0; i < n; i = i + 1)\` | \`for i in 0..n\` | Alternative update |
|
|
2561
|
+
|
|
2562
|
+
## Unsupported Operators
|
|
2563
|
+
|
|
2564
|
+
| JavaScript | Status | Alternative |
|
|
2565
|
+
|------------|--------|-------------|
|
|
2566
|
+
| \`**\` (exponent) | Not supported | Use multiplication loop |
|
|
2567
|
+
| \`<<\` (left shift) | Not supported | N/A |
|
|
2568
|
+
| \`>>\` (right shift) | Not supported | N/A |
|
|
2569
|
+
| \`>>>\` (unsigned shift) | Not supported | N/A |
|
|
2570
|
+
| \`&\` (bitwise AND) | Use \`&&\` | Converted to \`&\` |
|
|
2571
|
+
| \`\\|\` (bitwise OR) | Use \`\\|\\|\` | Converted to \`\\|\` |
|
|
2572
|
+
| \`^\` (XOR) | Not supported | N/A |
|
|
2573
|
+
| \`~\` (NOT) | Not supported | N/A |
|
|
2574
|
+
| \`in\` | Not supported | N/A |
|
|
2575
|
+
| \`instanceof\` | Not supported | N/A |
|
|
2576
|
+
`;
|
|
2577
|
+
|
|
1763
2578
|
// src/commands/init.ts
|
|
1764
2579
|
async function initCommand(projectName, options) {
|
|
1765
2580
|
let projectOptions;
|
|
@@ -1769,7 +2584,8 @@ async function initCommand(projectName, options) {
|
|
|
1769
2584
|
template: options.template,
|
|
1770
2585
|
provider: options.provider,
|
|
1771
2586
|
skipInstall: options.skipInstall,
|
|
1772
|
-
skipGit: options.skipGit
|
|
2587
|
+
skipGit: options.skipGit,
|
|
2588
|
+
aiTool: "none"
|
|
1773
2589
|
};
|
|
1774
2590
|
} else {
|
|
1775
2591
|
projectOptions = await promptProjectOptions({
|
|
@@ -1873,15 +2689,28 @@ async function createProjectStructure(projectDir, options, progress) {
|
|
|
1873
2689
|
}
|
|
1874
2690
|
files.push(["circuits/index.ts", generateCircuitsIndex(options.template)]);
|
|
1875
2691
|
files.push(["circuits/types.d.ts", generateCircuitTypes()]);
|
|
2692
|
+
const hasSkills = options.aiTool === "claude";
|
|
1876
2693
|
for (let i = 0; i < files.length; i++) {
|
|
1877
2694
|
const [relativePath, content] = files[i];
|
|
1878
2695
|
await writeFile(path2.join(projectDir, relativePath), content);
|
|
1879
|
-
await progress.reportFile(relativePath, i === files.length - 1);
|
|
2696
|
+
await progress.reportFile(relativePath, !hasSkills && i === files.length - 1);
|
|
2697
|
+
}
|
|
2698
|
+
if (hasSkills) {
|
|
2699
|
+
const skillFiles = generateClaudeSkills();
|
|
2700
|
+
const skillEntries = Object.entries(skillFiles);
|
|
2701
|
+
for (let i = 0; i < skillEntries.length; i++) {
|
|
2702
|
+
const [relativePath, content] = skillEntries[i];
|
|
2703
|
+
await writeFile(path2.join(projectDir, relativePath), content);
|
|
2704
|
+
await progress.reportFile(relativePath, i === skillEntries.length - 1);
|
|
2705
|
+
}
|
|
1880
2706
|
}
|
|
1881
2707
|
}
|
|
1882
2708
|
function printSuccessMessage(options) {
|
|
1883
2709
|
console.log();
|
|
1884
2710
|
console.log(pc3.green("\u2713") + " Project created successfully!");
|
|
2711
|
+
if (options.aiTool === "claude") {
|
|
2712
|
+
console.log(pc3.green("\u2713") + " Claude Code skill installed " + pc3.dim("(.claude/skills/izi-noir-circuit-patterns)"));
|
|
2713
|
+
}
|
|
1885
2714
|
console.log();
|
|
1886
2715
|
console.log("Next steps:");
|
|
1887
2716
|
console.log();
|