@hraness/dawg 0.6.1 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +118 -0
- package/DAWG.md +454 -140
- package/README.md +30 -26
- package/core/autotune.ts +1119 -0
- package/core/chords.ts +271 -23
- package/core/clips.ts +499 -0
- package/core/diff.ts +184 -104
- package/core/expression.ts +15 -0
- package/core/fx.ts +99 -29
- package/core/ids.ts +52 -0
- package/core/instruments.ts +19 -0
- package/core/keys.ts +3 -3
- package/core/loop.ts +8 -0
- package/core/lyrics.ts +297 -0
- package/core/master.ts +3 -3
- package/core/range.ts +581 -0
- package/core/resonators.ts +16 -2
- package/core/routing.ts +165 -0
- package/core/score.ts +955 -14
- package/core/sdk/eval-child.ts +7 -2
- package/core/sdk/eval.ts +35 -6
- package/core/sdk/print.ts +287 -5
- package/core/sdk/sync-lyrics.ts +49 -0
- package/core/sdk/v1.ts +2132 -46
- package/core/sections.ts +480 -35
- package/core/sing.ts +815 -0
- package/core/style-provenance.ts +80 -0
- package/core/styles/africa-mena-southasia.ts +2893 -0
- package/core/styles/americas.ts +3810 -0
- package/core/styles/art.ts +4993 -0
- package/core/styles/base.ts +123 -0
- package/core/styles/cycles.ts +106 -0
- package/core/styles/electronic.ts +2723 -0
- package/core/styles/europe-asia-pacific.ts +2838 -0
- package/core/styles/excerpt.ts +29 -0
- package/core/styles/gamelan.ts +283 -0
- package/core/styles/generate.ts +2199 -0
- package/core/styles/index.ts +515 -0
- package/core/styles/parts.ts +106 -0
- package/core/styles/pop.ts +3189 -0
- package/core/styles/rock.ts +2993 -0
- package/core/styles/roots.ts +4175 -0
- package/core/styles/schema.ts +429 -0
- package/core/styles/taxonomy.ts +940 -0
- package/core/styles/validate.ts +528 -0
- package/core/tempo.ts +32 -2
- package/core/tuning.ts +19 -3
- package/core/vocoder.ts +524 -0
- package/guides/agent.md +29 -0
- package/guides/arrange.md +31 -0
- package/guides/audio.md +31 -0
- package/guides/audition.md +20 -14
- package/guides/automation.md +12 -7
- package/guides/chords.md +15 -15
- package/guides/effects.md +17 -16
- package/guides/faders.md +20 -16
- package/guides/files.md +13 -9
- package/guides/getting-started.md +15 -11
- package/guides/keys.md +19 -15
- package/guides/media.md +17 -12
- package/guides/mix.md +15 -7
- package/guides/music.md +23 -8
- package/guides/notes.md +15 -9
- package/guides/panes.md +32 -0
- package/guides/performance.md +15 -13
- package/guides/play.md +21 -13
- package/guides/project.md +26 -8
- package/guides/providers.md +20 -14
- package/guides/resample.md +15 -9
- package/guides/rhythm.md +18 -13
- package/guides/sessions.md +17 -7
- package/guides/show-me.md +31 -0
- package/guides/sound.md +25 -9
- package/guides/sounds.md +15 -13
- package/guides/styles.md +31 -0
- package/guides/tape.md +32 -0
- package/guides/tempo.md +15 -10
- package/guides/tracks.md +15 -10
- package/guides/tuning.md +32 -0
- package/guides/voice.md +31 -0
- package/guides/web-search.md +18 -8
- package/native/prebuilt/darwin-arm64/libdawg_sink.dylib +0 -0
- package/native/prebuilt/darwin-x64/libdawg_sink.dylib +0 -0
- package/native/prebuilt/linux-arm64/libdawg_sink.so +0 -0
- package/native/prebuilt/linux-x64/libdawg_sink.so +0 -0
- package/native/prebuilt/manifest.json +21 -0
- package/package.json +6 -2
- package/src/agent/agent.ts +130 -18
- package/src/agent/calibration-tools.ts +53 -0
- package/src/agent/clip-tools.ts +453 -0
- package/src/agent/command-agent.ts +378 -0
- package/src/agent/drum-tools.ts +2 -2
- package/src/agent/expression-tools.ts +1 -1
- package/src/agent/gateway.ts +246 -60
- package/src/agent/models.ts +53 -12
- package/src/agent/ops.ts +27 -1
- package/src/agent/pack-tools.ts +1 -1
- package/src/agent/planner.ts +25 -0
- package/src/agent/portable-schema.ts +80 -0
- package/src/agent/preview-tool.ts +4 -1
- package/src/agent/provider.ts +22 -8
- package/src/agent/range-tools.ts +216 -0
- package/src/agent/rhythm-tools.ts +1 -1
- package/src/agent/section-tools.ts +1 -1
- package/src/agent/show-me.ts +497 -0
- package/src/agent/steer.ts +15 -0
- package/src/agent/style-tools.ts +217 -0
- package/src/agent/tool-error.ts +12 -0
- package/src/agent/tools.ts +110 -23
- package/src/agent/usage.ts +2 -2
- package/src/agent/voice-tools.ts +925 -0
- package/src/agent/xcb-agent.ts +13 -10
- package/src/argv.ts +38 -0
- package/src/audio/analysis.ts +253 -0
- package/src/audio/arrange.ts +49 -5
- package/src/audio/audio-command.ts +218 -0
- package/src/audio/autotune-engine.ts +101 -0
- package/src/audio/autotune.ts +640 -0
- package/src/audio/clips.ts +240 -0
- package/src/audio/devices.ts +264 -0
- package/src/audio/doctor.ts +157 -0
- package/src/audio/dsp/bandbank.ts +138 -0
- package/src/audio/dsp/envelope.ts +10 -0
- package/src/audio/dsp/follow.ts +120 -0
- package/src/audio/dsp/formant.ts +427 -0
- package/src/audio/dsp/glottal.ts +243 -0
- package/src/audio/dsp/interp.ts +7 -2
- package/src/audio/dsp/lpc.ts +50 -0
- package/src/audio/dsp/periodicity.ts +59 -0
- package/src/audio/dsp/pitch.ts +995 -0
- package/src/audio/dsp/psola.ts +199 -0
- package/src/audio/effects/chain.ts +3 -1
- package/src/audio/effects/common.ts +43 -0
- package/src/audio/effects/convolution.ts +7 -4
- package/src/audio/effects/filter.ts +48 -69
- package/src/audio/effects/formant.ts +263 -0
- package/src/audio/engine.ts +360 -40
- package/src/audio/fit.ts +35 -3
- package/src/audio/instrument-check.ts +59 -43
- package/src/audio/instruments.ts +4 -0
- package/src/audio/keys/calibration.ts +56 -0
- package/src/audio/keys/electric.ts +8 -1
- package/src/audio/keys/engine.ts +13 -1
- package/src/audio/keys/piano.ts +22 -2
- package/src/audio/kits.ts +135 -6
- package/src/audio/live.ts +114 -20
- package/src/audio/native.ts +615 -0
- package/src/audio/preview.ts +30 -2
- package/src/audio/render-worker.ts +2 -0
- package/src/audio/renderer.ts +2 -0
- package/src/audio/resample.ts +2 -1
- package/src/audio/sampler.ts +85 -4
- package/src/audio/samples.ts +20 -2
- package/src/audio/sing/analysis.ts +193 -0
- package/src/audio/sing/engine.ts +949 -0
- package/src/audio/strings/bow.ts +48 -5
- package/src/audio/strings/engine.ts +8 -2
- package/src/audio/synth/oscillators.ts +31 -21
- package/src/audio/synth/voice.ts +34 -1
- package/src/audio/vocoder/bank.ts +314 -0
- package/src/audio/vocoder/carrier.ts +165 -0
- package/src/audio/vocoder/control.ts +68 -0
- package/src/audio/vocoder/detect.ts +50 -0
- package/src/audio/vocoder/index.ts +304 -0
- package/src/audio/vocoder/talkbox.ts +143 -0
- package/src/audio/wav.ts +500 -77
- package/src/audio/winds/engine.ts +5 -1
- package/src/audio/winds/trim.ts +28 -4
- package/src/audio/winds/trims1.ts +297 -0
- package/src/audio/winds/voice.ts +15 -2
- package/src/auth/cli.ts +38 -36
- package/src/auth/credentials.ts +30 -1
- package/src/auth/login.ts +15 -9
- package/src/auth/tui.ts +19 -10
- package/src/commands/arrange.ts +82 -32
- package/src/commands/autotune.ts +421 -0
- package/src/commands/calibration.ts +74 -0
- package/src/commands/clips.ts +887 -0
- package/src/commands/drums.ts +3 -2
- package/src/commands/edit.ts +11 -4
- package/src/commands/expression.ts +1 -1
- package/src/commands/formant.ts +221 -0
- package/src/commands/fx.ts +101 -32
- package/src/commands/grammar.ts +560 -0
- package/src/commands/help.ts +774 -366
- package/src/commands/history.ts +139 -10
- package/src/commands/keys.ts +25 -8
- package/src/commands/modal.ts +1 -1
- package/src/commands/music.ts +1 -1
- package/src/commands/nearest.ts +53 -0
- package/src/commands/pack.ts +9 -2
- package/src/commands/param-range.ts +56 -0
- package/src/commands/parses.ts +135 -0
- package/src/commands/progression.ts +170 -0
- package/src/commands/range.ts +763 -0
- package/src/commands/resample.ts +13 -10
- package/src/commands/rhythm.ts +3 -0
- package/src/commands/rig.ts +3 -24
- package/src/commands/sample.ts +11 -1
- package/src/commands/sing.ts +474 -0
- package/src/commands/strum.ts +13 -1
- package/src/commands/style.ts +415 -0
- package/src/commands/time.ts +6 -3
- package/src/commands/tuning.ts +3 -3
- package/src/commands/vocal-pitch.ts +617 -0
- package/src/commands/vocal.ts +147 -0
- package/src/commands/vocoder.ts +627 -0
- package/src/commands/wind.ts +2 -2
- package/src/fs/durable.ts +50 -0
- package/src/identity/actor.ts +127 -0
- package/src/lang/glossary.ts +511 -0
- package/src/launch-args.ts +267 -0
- package/src/main.ts +2508 -308
- package/src/media/cli.ts +20 -3
- package/src/media/import.ts +3 -1
- package/src/project/check.ts +21 -2
- package/src/project/clip-pins.ts +72 -0
- package/src/project/init.ts +23 -8
- package/src/project/sync.ts +418 -86
- package/src/render.ts +20 -1
- package/src/session/client.ts +107 -3
- package/src/session/clipboard.ts +79 -0
- package/src/session/daemon.ts +199 -5
- package/src/session/live-host.ts +232 -0
- package/src/session/meta.ts +14 -0
- package/src/session/origin.ts +174 -0
- package/src/session/port.ts +109 -14
- package/src/session/presence.ts +34 -4
- package/src/session/protocol.ts +365 -7
- package/src/session/rebase.ts +63 -12
- package/src/session/receipt.ts +265 -0
- package/src/session/shared-live.ts +131 -0
- package/src/session/store.ts +126 -45
- package/src/tui/arrange-menu.ts +225 -23
- package/src/tui/audition.ts +1 -1
- package/src/tui/euclid.ts +113 -27
- package/src/tui/fader.ts +282 -42
- package/src/tui/granular-menu.ts +2 -4
- package/src/tui/knob-fields.ts +107 -0
- package/src/tui/knob-map.ts +198 -0
- package/src/tui/menu-clips.ts +297 -0
- package/src/tui/menu-time.ts +20 -13
- package/src/tui/menu-voice.ts +405 -0
- package/src/tui/menu.ts +987 -179
- package/src/tui/modal-menu.ts +6 -6
- package/src/tui/performance-menu.ts +5 -2
- package/src/tui/play-chords.ts +4 -2
- package/src/tui/play-mode.ts +15 -1
- package/src/tui/play-session.ts +243 -28
- package/src/tui/sing-menu.ts +278 -0
- package/src/tui/style-menu.ts +104 -0
- package/src/tui/tape-mode.ts +580 -0
- package/src/tui/tape-view.ts +263 -0
- package/src/tui/vocoder-menu.ts +244 -0
- package/src/tui/wind-menu.ts +3 -3
- package/src/version.ts +8 -0
- package/src/web/fetch.ts +115 -29
- package/tui/activity.ts +180 -9
- package/tui/app.ts +491 -84
- package/tui/clip-row.ts +132 -0
- package/tui/delight.ts +193 -0
- package/tui/drawer.ts +233 -27
- package/tui/frame-gate.ts +76 -0
- package/tui/grammar.ts +143 -65
- package/tui/guide.ts +50 -5
- package/tui/highway.ts +309 -30
- package/tui/hints.ts +197 -0
- package/tui/hits.ts +7 -1
- package/tui/input.ts +60 -9
- package/tui/keys.ts +1 -1
- package/tui/knobs.ts +268 -0
- package/tui/play-strip.ts +80 -14
- package/tui/prompt.ts +1 -1
- package/tui/screen.ts +151 -18
- package/tui/tape.ts +439 -0
- package/tui/text.ts +35 -2
- package/tui/theme.ts +46 -1
package/src/media/cli.ts
CHANGED
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
*/
|
|
17
17
|
import { systemRunner, type CommandRunner } from "../auth/runner.ts";
|
|
18
18
|
import { doctor, formatDoctor } from "./backend.ts";
|
|
19
|
+
import { analysisCacheStatus, analysisDoctorLine } from "../audio/analysis.ts";
|
|
19
20
|
import { trackSlug } from "./paths.ts";
|
|
20
21
|
import { MediaAbortError } from "./process.ts";
|
|
21
22
|
import { findMediaTool } from "./registry.ts";
|
|
@@ -26,7 +27,7 @@ export type Output = { write(text: string): unknown };
|
|
|
26
27
|
|
|
27
28
|
export const MEDIA_HELP = `dawg media — local media tools (see DAWG.md "Media tools")
|
|
28
29
|
|
|
29
|
-
dawg media doctor backend + binaries + install commands
|
|
30
|
+
dawg media doctor backend + binaries + install commands + analysis cache
|
|
30
31
|
dawg media download <url> [--name n] YouTube audio → tracks/<slug>/downloads/<n>.wav
|
|
31
32
|
dawg media stems <file> six stems → <file>.stems/
|
|
32
33
|
dawg media analyze <file> tempo, key, beat grid, peaks → <file>.analysis.json
|
|
@@ -68,6 +69,15 @@ export function parseMediaArgv(argv: readonly string[]): {
|
|
|
68
69
|
json: boolean;
|
|
69
70
|
help: boolean;
|
|
70
71
|
} {
|
|
72
|
+
// `dawg media --help` (or `-h`): a leading help flag is not a verb.
|
|
73
|
+
if (argv[0] === "--help" || argv[0] === "-h")
|
|
74
|
+
return {
|
|
75
|
+
verb: undefined,
|
|
76
|
+
args: {},
|
|
77
|
+
track: "main",
|
|
78
|
+
json: false,
|
|
79
|
+
help: true,
|
|
80
|
+
};
|
|
71
81
|
const [verb, ...rest] = argv;
|
|
72
82
|
const args: Record<string, unknown> = {};
|
|
73
83
|
const positional: string[] = [];
|
|
@@ -139,8 +149,15 @@ export async function runMediaCommand(
|
|
|
139
149
|
...host,
|
|
140
150
|
...(options.signal ? { signal: options.signal } : {}),
|
|
141
151
|
});
|
|
142
|
-
|
|
143
|
-
|
|
152
|
+
const analysis = await analysisCacheStatus(cwd);
|
|
153
|
+
if (parsed.json)
|
|
154
|
+
stdout.write(
|
|
155
|
+
`${JSON.stringify({ ...report, analysisCache: analysis }, null, 2)}\n`,
|
|
156
|
+
);
|
|
157
|
+
else
|
|
158
|
+
stdout.write(
|
|
159
|
+
`${[...formatDoctor(report), await analysisDoctorLine(cwd)].join("\n")}\n`,
|
|
160
|
+
);
|
|
144
161
|
return 0;
|
|
145
162
|
}
|
|
146
163
|
const spec = VERBS[parsed.verb];
|
package/src/media/import.ts
CHANGED
|
@@ -38,6 +38,8 @@ export type ImportSampleArgs = Readonly<{
|
|
|
38
38
|
end?: number;
|
|
39
39
|
/** Root note name or MIDI number the sample is pitched at (default C4). */
|
|
40
40
|
root?: string | number;
|
|
41
|
+
/** 1 folds to mono (0.7 audio clips); absent keeps today's stereo. */
|
|
42
|
+
channels?: 1 | 2;
|
|
41
43
|
}>;
|
|
42
44
|
|
|
43
45
|
export async function importSample(
|
|
@@ -68,7 +70,7 @@ export async function importSample(
|
|
|
68
70
|
"-ar",
|
|
69
71
|
String(SAMPLE_LIMITS.sampleRate),
|
|
70
72
|
"-ac",
|
|
71
|
-
|
|
73
|
+
String(args.channels ?? 2),
|
|
72
74
|
"-c:a",
|
|
73
75
|
"pcm_s16le",
|
|
74
76
|
temp,
|
package/src/project/check.ts
CHANGED
|
@@ -13,7 +13,9 @@ import {
|
|
|
13
13
|
modalPairWarnings,
|
|
14
14
|
} from "../../core/resonators.ts";
|
|
15
15
|
import { plainSineWarnings } from "../audio/instrument-check.ts";
|
|
16
|
+
import { clipPinDiagnostics } from "./clip-pins.ts";
|
|
16
17
|
import { isProject } from "./init.ts";
|
|
18
|
+
import { parseSimpleArgv } from "../argv.ts";
|
|
17
19
|
import { typecheckProject } from "./typecheck.ts";
|
|
18
20
|
|
|
19
21
|
export type CheckDeps = Readonly<{
|
|
@@ -41,12 +43,18 @@ export async function checkProject(
|
|
|
41
43
|
(deps.typecheck ?? typecheckProject)(project),
|
|
42
44
|
(deps.evaluate ?? evaluateProject)(project),
|
|
43
45
|
]);
|
|
46
|
+
// 0.7: a clip or take whose file no longer matches its pinned sha256
|
|
47
|
+
// fails like a type error.
|
|
48
|
+
const pins = evaluated.ok
|
|
49
|
+
? await clipPinDiagnostics(project, evaluated.score)
|
|
50
|
+
: [];
|
|
44
51
|
const diagnostics = [
|
|
45
52
|
...types.diagnostics,
|
|
46
53
|
...(evaluated.ok ? [] : evaluated.diagnostics),
|
|
54
|
+
...pins,
|
|
47
55
|
];
|
|
48
56
|
return Object.freeze({
|
|
49
|
-
ok: types.ok && evaluated.ok,
|
|
57
|
+
ok: types.ok && evaluated.ok && pins.length === 0,
|
|
50
58
|
diagnostics: Object.freeze(diagnostics),
|
|
51
59
|
typesMs: types.ms,
|
|
52
60
|
evalMs: evaluated.ms,
|
|
@@ -64,6 +72,9 @@ export async function checkProject(
|
|
|
64
72
|
});
|
|
65
73
|
}
|
|
66
74
|
|
|
75
|
+
export const CHECK_USAGE =
|
|
76
|
+
"usage: dawg check · typecheck and evaluate the project in this directory; exit 1 on problems";
|
|
77
|
+
|
|
67
78
|
export async function runCheckCommand(
|
|
68
79
|
argv: readonly string[],
|
|
69
80
|
cwd: string,
|
|
@@ -71,6 +82,15 @@ export async function runCheckCommand(
|
|
|
71
82
|
stderr: { write(text: string): unknown },
|
|
72
83
|
deps: CheckDeps = {},
|
|
73
84
|
): Promise<number> {
|
|
85
|
+
const parsed = parseSimpleArgv(argv.slice(1), 0);
|
|
86
|
+
if (parsed.kind === "help") {
|
|
87
|
+
stdout.write(`${CHECK_USAGE}\n`);
|
|
88
|
+
return 0;
|
|
89
|
+
}
|
|
90
|
+
if (parsed.kind === "error") {
|
|
91
|
+
stderr.write(`${parsed.problem} · ${CHECK_USAGE}\n`);
|
|
92
|
+
return 2;
|
|
93
|
+
}
|
|
74
94
|
const project = cwd;
|
|
75
95
|
if (!(await isProject(project))) {
|
|
76
96
|
stderr.write(
|
|
@@ -92,6 +112,5 @@ export async function runCheckCommand(
|
|
|
92
112
|
}
|
|
93
113
|
const count = report.diagnostics.length;
|
|
94
114
|
stderr.write(`${count} problem${count === 1 ? "" : "s"}\n`);
|
|
95
|
-
void argv;
|
|
96
115
|
return 1;
|
|
97
116
|
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `dawg check` re-hashes every audio clip and take (0.7) and reports a file
|
|
3
|
+
* that is missing or no longer matches its pinned sha256, pointing at the
|
|
4
|
+
* track file the way a type error does.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { createHash } from "node:crypto";
|
|
8
|
+
import { readFile, stat } from "node:fs/promises";
|
|
9
|
+
import { relative, resolve } from "node:path";
|
|
10
|
+
import type { Diagnostic } from "../../core/sdk/eval.ts";
|
|
11
|
+
import type { TrackScore } from "../../core/score.ts";
|
|
12
|
+
import { trackDirectories } from "../../core/sdk/print.ts";
|
|
13
|
+
|
|
14
|
+
const MAX_CLIP_FILE_BYTES = 50 * 1024 * 1024;
|
|
15
|
+
|
|
16
|
+
export async function clipPinDiagnostics(
|
|
17
|
+
project: string,
|
|
18
|
+
score: TrackScore,
|
|
19
|
+
): Promise<Diagnostic[]> {
|
|
20
|
+
const out: Diagnostic[] = [];
|
|
21
|
+
const hashes = new Map<string, string | undefined>();
|
|
22
|
+
const hashOf = async (src: string): Promise<string | undefined> => {
|
|
23
|
+
if (hashes.has(src)) return hashes.get(src);
|
|
24
|
+
let hash: string | undefined;
|
|
25
|
+
const path = resolve(project, src);
|
|
26
|
+
if (!relative(project, path).startsWith("..")) {
|
|
27
|
+
try {
|
|
28
|
+
const info = await stat(path);
|
|
29
|
+
if (info.isFile() && info.size <= MAX_CLIP_FILE_BYTES)
|
|
30
|
+
hash = createHash("sha256")
|
|
31
|
+
.update(await readFile(path))
|
|
32
|
+
.digest("hex");
|
|
33
|
+
} catch {
|
|
34
|
+
hash = undefined;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
hashes.set(src, hash);
|
|
38
|
+
return hash;
|
|
39
|
+
};
|
|
40
|
+
const dirs = trackDirectories(score);
|
|
41
|
+
for (const track of score.tracks) {
|
|
42
|
+
const file = `tracks/${dirs.get(track.id) ?? track.id}/track.ts`;
|
|
43
|
+
const items: [string, string, string][] = [
|
|
44
|
+
...(track.takes ?? []).map(
|
|
45
|
+
(t) => [`take ${t.name}`, t.src, t.sha256] as [string, string, string],
|
|
46
|
+
),
|
|
47
|
+
...(track.clips ?? []).map(
|
|
48
|
+
(c) => [`clip ${c.id}`, c.src, c.sha256] as [string, string, string],
|
|
49
|
+
),
|
|
50
|
+
];
|
|
51
|
+
const usedTakes = new Set((track.clips ?? []).map((c) => c.take));
|
|
52
|
+
for (const [label, src, pinned] of items) {
|
|
53
|
+
const actual = await hashOf(src);
|
|
54
|
+
if (actual === pinned) continue;
|
|
55
|
+
// An unused take that is gone is only advice (sources.md 6).
|
|
56
|
+
if (
|
|
57
|
+
actual === undefined &&
|
|
58
|
+
label.startsWith("take ") &&
|
|
59
|
+
!usedTakes.has(label.slice(5))
|
|
60
|
+
)
|
|
61
|
+
continue;
|
|
62
|
+
out.push({
|
|
63
|
+
file,
|
|
64
|
+
message:
|
|
65
|
+
actual === undefined
|
|
66
|
+
? `${label}: ${src} is missing (re-import it or remove the clip)`
|
|
67
|
+
: `${label}: ${src} does not match its sha256 pin (${pinned.slice(0, 8)} pinned, ${actual.slice(0, 8)} on disk); delete the sha256 line to re-pin`,
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return out;
|
|
72
|
+
}
|
package/src/project/init.ts
CHANGED
|
@@ -15,9 +15,11 @@
|
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
17
|
import { createHash } from "node:crypto";
|
|
18
|
-
import { mkdir, readFile
|
|
18
|
+
import { mkdir, readFile } from "node:fs/promises";
|
|
19
19
|
import { dirname, join, resolve } from "node:path";
|
|
20
20
|
import { fileURLToPath } from "node:url";
|
|
21
|
+
import { parseSimpleArgv } from "../argv.ts";
|
|
22
|
+
import { durableWrite } from "../fs/durable.ts";
|
|
21
23
|
|
|
22
24
|
export const PROJECT_FILE = "dawg.json";
|
|
23
25
|
export const PROJECT_FORMAT = "dawg.project/v1";
|
|
@@ -78,6 +80,7 @@ export default song({
|
|
|
78
80
|
meter: [4, 4],
|
|
79
81
|
bars: 4,
|
|
80
82
|
tracks: [],
|
|
83
|
+
calibration: 1,
|
|
81
84
|
});
|
|
82
85
|
`;
|
|
83
86
|
|
|
@@ -210,6 +213,9 @@ export async function initProject(
|
|
|
210
213
|
return Object.freeze({ wrote: Object.freeze(wrote), sdkVersion });
|
|
211
214
|
}
|
|
212
215
|
|
|
216
|
+
export const INIT_USAGE =
|
|
217
|
+
"usage: dawg init [dir] · writes song.ts, dawg.json, tsconfig.json and .dawg/sdk (existing files are kept)";
|
|
218
|
+
|
|
213
219
|
/** `dawg init [dir]`: creates the project and prints what it wrote. */
|
|
214
220
|
export async function runInitCommand(
|
|
215
221
|
argv: readonly string[],
|
|
@@ -217,8 +223,17 @@ export async function runInitCommand(
|
|
|
217
223
|
stdout: { write(text: string): unknown },
|
|
218
224
|
stderr: { write(text: string): unknown },
|
|
219
225
|
): Promise<number> {
|
|
220
|
-
const
|
|
221
|
-
|
|
226
|
+
const parsed = parseSimpleArgv(argv.slice(1), 1);
|
|
227
|
+
if (parsed.kind === "help") {
|
|
228
|
+
stdout.write(`${INIT_USAGE}\n`);
|
|
229
|
+
return 0;
|
|
230
|
+
}
|
|
231
|
+
if (parsed.kind === "error") {
|
|
232
|
+
stderr.write(`${parsed.problem} · ${INIT_USAGE}\n`);
|
|
233
|
+
return 2;
|
|
234
|
+
}
|
|
235
|
+
const dir = parsed.positionals[0];
|
|
236
|
+
const target = dir ? resolve(cwd, dir) : cwd;
|
|
222
237
|
try {
|
|
223
238
|
const result = await initProject(target);
|
|
224
239
|
if (result.wrote.length === 0)
|
|
@@ -241,13 +256,13 @@ async function readOptional(path: string): Promise<string | undefined> {
|
|
|
241
256
|
}
|
|
242
257
|
}
|
|
243
258
|
|
|
244
|
-
/**
|
|
259
|
+
/**
|
|
260
|
+
* Temp file + fsync + rename + directory fsync, so a reader never sees a
|
|
261
|
+
* partial file and a crash never loses a write `.dawg/sync.json` vouches for.
|
|
262
|
+
*/
|
|
245
263
|
export async function writeAtomic(
|
|
246
264
|
path: string,
|
|
247
265
|
contents: string,
|
|
248
266
|
): Promise<void> {
|
|
249
|
-
await
|
|
250
|
-
const temporary = `${path}.${process.pid}.tmp`;
|
|
251
|
-
await writeFile(temporary, contents, "utf8");
|
|
252
|
-
await rename(temporary, path);
|
|
267
|
+
await durableWrite(path, contents);
|
|
253
268
|
}
|