@playcraft/cli 0.1.9 → 0.1.11

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.
@@ -4,15 +4,19 @@ import { lstat, mkdir, readFile, realpath, rename, rm, writeFile } from 'node:fs
4
4
  import { join } from 'node:path';
5
5
  import { isLocalWorkspaceGitAuthMode, isLocalWorkspaceGitEnvironment, matchWorkspaceGitGatewayCloneUrl, workspacePreparationSchema, workspaceRegistrationSchema, } from '@playcraft/common/cloud-workspace/runtime';
6
6
  import { WorkspaceContextError } from './context-error.js';
7
- /** The caller holds the Workspace lock. Only an absent, never-published checkout may be cloned. */
7
+ /** The caller holds the Workspace lock. Only an absent, never-published directory may be prepared. */
8
8
  export async function prepareWorkspaceCheckout(state, binding, input, leaseFence) {
9
9
  const preparation = workspacePreparationSchema.safeParse(input);
10
10
  if (!preparation.success)
11
11
  throw new WorkspaceContextError('invalid_workspace_preparation');
12
- const source = parseCloneSource(binding.repositoryUrl);
13
- const direct = isLocalWorkspaceGitAuthMode(preparation.data.authMode);
14
- if (direct && (!isLocalWorkspaceGitEnvironment(state.config.environment) || !preparation.data.directAccess
15
- || preparation.data.directAccess.repositoryUrl !== binding.repositoryUrl))
12
+ const standalone = binding.targetKind === 'standalone';
13
+ if (standalone !== (preparation.data.mode === 'empty'))
14
+ throw new WorkspaceContextError('invalid_workspace_preparation');
15
+ const clone = preparation.data.mode === 'clone' ? preparation.data : undefined;
16
+ const source = binding.repositoryUrl ? parseCloneSource(binding.repositoryUrl) : undefined;
17
+ const direct = isLocalWorkspaceGitAuthMode(clone?.authMode);
18
+ if (direct && (!isLocalWorkspaceGitEnvironment(state.config.environment) || !clone?.directAccess
19
+ || clone.directAccess.repositoryUrl !== binding.repositoryUrl))
16
20
  throw new WorkspaceContextError('workspace_git_gateway_unavailable');
17
21
  const parent = await realpath(state.config.workspaceRoot);
18
22
  const target = join(parent, binding.workspaceId);
@@ -42,15 +46,15 @@ export async function prepareWorkspaceCheckout(state, binding, input, leaseFence
42
46
  await writeReceipt(receiptPath, receipt);
43
47
  await rm(staging, { recursive: true, force: true });
44
48
  await mkdir(staging, { mode: 0o700 });
45
- const access = preparation.data.gitAccess;
46
- const credential = preparation.data.directAccess ?? access;
49
+ const access = clone?.gitAccess;
50
+ const credential = clone?.directAccess ?? access;
47
51
  const now = Date.now();
48
52
  if (access &&
49
53
  (Date.parse(access.issuedAt) > now || Date.parse(access.expiresAt) <= now + 10_000)) {
50
54
  await rm(staging, { recursive: true, force: true });
51
55
  throw new WorkspaceContextError('workspace_git_access_expired');
52
56
  }
53
- const transport = preparation.data.transport;
57
+ const transport = clone?.transport;
54
58
  if (transport && !matchWorkspaceGitGatewayCloneUrl(transport.cloneUrl, state.config.gitGatewayOrigins, binding.repositoryUrl).ok) {
55
59
  await rm(staging, { recursive: true, force: true });
56
60
  throw new WorkspaceContextError('workspace_git_gateway_unavailable');
@@ -76,20 +80,25 @@ export async function prepareWorkspaceCheckout(state, binding, input, leaseFence
76
80
  }
77
81
  }
78
82
  try {
79
- await runGit(['check-ref-format', '--branch', binding.branchName], env, deadline);
80
- await runGit([
81
- 'clone',
82
- '--no-checkout',
83
- '--single-branch',
84
- '--branch',
85
- binding.branchName,
86
- '--',
87
- binding.repositoryUrl,
88
- staging,
89
- ], env, deadline);
90
- // Checkout never receives the temporary credential and never invokes repository hooks or global filters.
91
- clearCloneSecrets(env);
92
- await runGit(['-C', staging, 'checkout', '--force', binding.branchName], env, deadline);
83
+ if (standalone) {
84
+ await runGit(['init', '--initial-branch=main', staging], env, deadline);
85
+ }
86
+ else {
87
+ await runGit(['check-ref-format', '--branch', binding.branchName], env, deadline);
88
+ await runGit([
89
+ 'clone',
90
+ '--no-checkout',
91
+ '--single-branch',
92
+ '--branch',
93
+ binding.branchName,
94
+ '--',
95
+ binding.repositoryUrl,
96
+ staging,
97
+ ], env, deadline);
98
+ // Checkout never receives the temporary credential and never invokes repository hooks or global filters.
99
+ clearCloneSecrets(env);
100
+ await runGit(['-C', staging, 'checkout', '--force', binding.branchName], env, deadline);
101
+ }
93
102
  assertCurrent();
94
103
  receipt.status = 'ready';
95
104
  await writeReceipt(receiptPath, receipt);
@@ -46,7 +46,7 @@ async function checkedDirectory(state, workspaceId) {
46
46
  throw new WorkspaceContextError('workspace_not_prepared');
47
47
  }
48
48
  }
49
- /** Registers a fixed checkout; optional first creation is restricted to its trusted binding. */
49
+ /** Registers a fixed directory; optional first creation is restricted to its trusted binding. */
50
50
  export async function registerWorkspace(state, input, leaseFence, preparation) {
51
51
  if (state.config.workspaceMode !== 'multi')
52
52
  throw new WorkspaceContextError('multi_workspace_unavailable');
@@ -87,9 +87,18 @@ export async function registerWorkspace(state, input, leaseFence, preparation) {
87
87
  },
88
88
  })).stdout.trim();
89
89
  try {
90
- if ((await realpath(await git('rev-parse', '--show-toplevel'))) !== root ||
91
- (await git('config', '--get', 'remote.origin.url')) !== binding.repositoryUrl ||
92
- (await git('symbolic-ref', '--short', 'HEAD')) !== binding.branchName) {
90
+ let checkoutMatches;
91
+ if (binding.targetKind === 'standalone') {
92
+ const gitDirectory = await lstat(join(root, '.git'));
93
+ checkoutMatches = gitDirectory.isDirectory() && !gitDirectory.isSymbolicLink()
94
+ && (await git('rev-parse', '--absolute-git-dir')) === join(root, '.git')
95
+ && (await git('remote')) === '';
96
+ }
97
+ else {
98
+ checkoutMatches = (await git('config', '--get', 'remote.origin.url')) === binding.repositoryUrl
99
+ && (await git('symbolic-ref', '--short', 'HEAD')) === binding.branchName;
100
+ }
101
+ if ((await realpath(await git('rev-parse', '--show-toplevel'))) !== root || !checkoutMatches) {
93
102
  throw new WorkspaceContextError('workspace_checkout_mismatch');
94
103
  }
95
104
  }
@@ -102,7 +111,7 @@ export async function registerWorkspace(state, input, leaseFence, preparation) {
102
111
  throw new WorkspaceContextError('runtime_destroyed');
103
112
  if (leaseFence < state.acceptedLeaseFence)
104
113
  throw new WorkspaceContextError('stale_lease');
105
- if (preparation?.transport?.kind === 'git-gateway-v2' || isLocalWorkspaceGitAuthMode(preparation?.authMode)) {
114
+ if (preparation?.mode === 'clone' && (preparation.transport?.kind === 'git-gateway-v2' || isLocalWorkspaceGitAuthMode(preparation.authMode))) {
106
115
  if (!state.gitCredentials)
107
116
  throw new WorkspaceContextError('workspace_git_gateway_unavailable');
108
117
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@playcraft/cli",
3
- "version": "0.1.9",
3
+ "version": "0.1.11",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "engines": {
@@ -48,8 +48,8 @@
48
48
  "@gltf-transform/core": "^4.3.0",
49
49
  "@gltf-transform/extensions": "^4.3.0",
50
50
  "@gltf-transform/functions": "^4.3.0",
51
- "@playcraft/build": "^0.1.9",
52
- "@playcraft/common": "^0.1.9",
51
+ "@playcraft/build": "^0.1.11",
52
+ "@playcraft/common": "^0.1.11",
53
53
  "better-sqlite3-pinned": "npm:better-sqlite3@13.0.3",
54
54
  "chokidar": "^4.0.3",
55
55
  "commander": "^13.1.0",
@@ -4,147 +4,147 @@
4
4
  {
5
5
  "skillRef": "platform/playcraft-3d-flip-sprite",
6
6
  "version": "1.0.0",
7
- "artifactHash": "bfea71413bf9f0b57eda4c79c1c9e5d73061becaf9c1ece066ffcc32890ad1ea",
7
+ "artifactHash": "95183007861a4dae5b67440ea9beed1c360eb616d17e4aa04b97383cc2b63516",
8
8
  "surface": "portal-agent",
9
9
  "mountPath": ".playcraft/skills/platform__playcraft-3d-flip-sprite"
10
10
  },
11
11
  {
12
12
  "skillRef": "platform/playcraft-asset-management",
13
13
  "version": "1.0.0",
14
- "artifactHash": "11ae4c6b1e9e9cb8639e22cfc9568f70cc7fc526bb9632e601e2886ba50fb0f3",
14
+ "artifactHash": "27209dba24f6e1851dc83682fbd24165894c802794c797cac32d8871f740cf14",
15
15
  "surface": "portal-agent",
16
16
  "mountPath": ".playcraft/skills/platform__playcraft-asset-management"
17
17
  },
18
18
  {
19
19
  "skillRef": "platform/playcraft-build",
20
20
  "version": "1.0.0",
21
- "artifactHash": "7fbd4ba060efc9409e8da9aa7d4edfe2cdb2734de7a497b79299a7061cacf3ac",
21
+ "artifactHash": "2ca96916041bcc04ee48e827599dd819072e67a626bf59a1c20281f337e4063a",
22
22
  "surface": "portal-agent",
23
23
  "mountPath": ".playcraft/skills/platform__playcraft-build"
24
24
  },
25
25
  {
26
26
  "skillRef": "platform/playcraft-code-editor",
27
27
  "version": "1.0.0",
28
- "artifactHash": "4db2b7e60762ba0ccc249ea4023dcb81701dac38d54af0e6757b5337ea489a32",
28
+ "artifactHash": "abcc9aafe2b15adb8de62eb89921dbcb35c7dc634055b937fe34bdf83ca6685d",
29
29
  "surface": "portal-agent",
30
30
  "mountPath": ".playcraft/skills/platform__playcraft-code-editor"
31
31
  },
32
32
  {
33
33
  "skillRef": "platform/playcraft-create-remix",
34
34
  "version": "1.0.0",
35
- "artifactHash": "76f7cfd4b7441184805e07550f687651225a3baf27e306f0ee7c4347e58f3f19",
35
+ "artifactHash": "8d2a4d4d096433ccec090f1003c050471ddfbc50d69c1c0c66f88424b52bacf6",
36
36
  "surface": "portal-agent",
37
37
  "mountPath": ".playcraft/skills/platform__playcraft-create-remix"
38
38
  },
39
39
  {
40
40
  "skillRef": "platform/playcraft-deploy",
41
- "version": "1.0.0",
42
- "artifactHash": "e619cee8bea40b2a0c9b69a02d387369a3628a73c0a0504b3c92b1330bc12e86",
41
+ "version": "1.0.1",
42
+ "artifactHash": "31ac7f90d93606eb40c2113d56204e09b97ecd9e49b910b2ce05445b824ccfdc",
43
43
  "surface": "portal-agent",
44
44
  "mountPath": ".playcraft/skills/platform__playcraft-deploy"
45
45
  },
46
46
  {
47
47
  "skillRef": "platform/playcraft-iteration-methodology",
48
- "version": "1.0.0",
49
- "artifactHash": "42c5219f6f8a8d63787efeef6da8522cf7400442dc75dc8dee6d0c49b0ed28b7",
48
+ "version": "1.1.0",
49
+ "artifactHash": "f67a2f1806e08a48a903408383a06802622da3760d24d72a0dcbbea202349be2",
50
50
  "surface": "portal-agent",
51
51
  "mountPath": ".playcraft/skills/platform__playcraft-iteration-methodology"
52
52
  },
53
53
  {
54
54
  "skillRef": "platform/playcraft-platform-intro",
55
55
  "version": "1.0.0",
56
- "artifactHash": "d32001cff62516d343707fdbe4812ed9dde6651c749f2aadc848d06196f07c15",
56
+ "artifactHash": "b37f6b0515a79822f5f69519fcddd1182d420b90eb9ba40298bb1ed73eced281",
57
57
  "surface": "portal-agent",
58
58
  "mountPath": ".playcraft/skills/platform__playcraft-platform-intro"
59
59
  },
60
60
  {
61
61
  "skillRef": "platform/playcraft-prefab",
62
62
  "version": "1.0.0",
63
- "artifactHash": "7089e5b346ce99dbc25f61e2645e67fce057e6a108445975c99a03b062c84007",
63
+ "artifactHash": "a4a991302922d6846a2e313dc4cd4514f54820040dc2166ccc864803053c1ea5",
64
64
  "surface": "portal-agent",
65
65
  "mountPath": ".playcraft/skills/platform__playcraft-prefab"
66
66
  },
67
67
  {
68
68
  "skillRef": "platform/playcraft-project-management",
69
69
  "version": "1.0.0",
70
- "artifactHash": "32459786cdd17ece2df094be1f13387802325191531939c40c1ddfde3590a17b",
70
+ "artifactHash": "e7e4bffe80e0737362a5cac4234056a7d7fb048f0c8b5e41041e61ee914495e3",
71
71
  "surface": "portal-agent",
72
72
  "mountPath": ".playcraft/skills/platform__playcraft-project-management"
73
73
  },
74
74
  {
75
75
  "skillRef": "platform/playcraft-remix-workflow",
76
- "version": "1.0.0",
77
- "artifactHash": "07a25c34042dabbde9a166d4e49c977dd8b2459eff27c9c1bc9cafe0a56a08ef",
76
+ "version": "1.0.1",
77
+ "artifactHash": "23807ff591b4bd08c87daa4e9b2c9900b0505e4f2f601c47de51a96d6ebbed19",
78
78
  "surface": "portal-agent",
79
79
  "mountPath": ".playcraft/skills/platform__playcraft-remix-workflow"
80
80
  },
81
81
  {
82
82
  "skillRef": "platform/playcraft-save",
83
- "version": "1.0.0",
84
- "artifactHash": "100d6d66ac449bc8b7f183b8165587bcef6bb5d138d2ddfa07035f229275bc3d",
83
+ "version": "1.0.1",
84
+ "artifactHash": "6d42c681f91f849603bf3c4f235411ea05189a0d5e3ca1d3a8f92b69e536bdd1",
85
85
  "surface": "portal-agent",
86
86
  "mountPath": ".playcraft/skills/platform__playcraft-save"
87
87
  },
88
88
  {
89
89
  "skillRef": "platform/playcraft-template-upgrade-merge",
90
90
  "version": "1.0.0",
91
- "artifactHash": "459e87e02c45b5a859d1c79daf0c53cd7ee9426d6d55ef8d1156a052e557a52f",
91
+ "artifactHash": "354da60f395f3eb7a267db667783344f54567e12abcfec454b269193a5af1cb6",
92
92
  "surface": "portal-agent",
93
93
  "mountPath": ".playcraft/skills/platform__playcraft-template-upgrade-merge"
94
94
  },
95
95
  {
96
96
  "skillRef": "platform/sound-effects",
97
97
  "version": "1.0.0",
98
- "artifactHash": "3a2235197c23ca5b38c46fbb0ff1686f509c094ba206f199f78cdd5f1a07aa95",
98
+ "artifactHash": "a6ba7ea91ddbf4f5a04ae8340a69c3725c5d97b239e8636bf64886928e8dd1da",
99
99
  "surface": "portal-agent",
100
100
  "mountPath": ".playcraft/skills/platform__sound-effects"
101
101
  },
102
102
  {
103
103
  "skillRef": "remix/playcraft-adsdk",
104
104
  "version": "1.0.0",
105
- "artifactHash": "9b2e784b167372c6d3e14a3636dac2af8cf64af46c1bef1e082b77c0db51a9c2",
105
+ "artifactHash": "0de877b122246ed5c665a893f8dc408282007d0950b0f6c44876f87ceddb519f",
106
106
  "surface": "sandbox-agent",
107
107
  "mountPath": ".playcraft/skills/remix__playcraft-adsdk"
108
108
  },
109
109
  {
110
110
  "skillRef": "remix/playcraft-audio-generation",
111
111
  "version": "1.0.0",
112
- "artifactHash": "0f171e4e739d3b1a5b1f00a0b20cf13d0897c69c9d4e30dd3477acd6b982c8c8",
112
+ "artifactHash": "8d1b035b289545ca8fd6c247b9417bf34bddf5a26b31e114c35d001aa3a9ebf0",
113
113
  "surface": "sandbox-agent",
114
114
  "mountPath": ".playcraft/skills/remix__playcraft-audio-generation"
115
115
  },
116
116
  {
117
117
  "skillRef": "remix/playcraft-dist-publish",
118
118
  "version": "1.0.0",
119
- "artifactHash": "0c2396be7fed8b1a0fa2990eee2a23ed9b6abe02ead68c15648f45de7c11e254",
119
+ "artifactHash": "9a00acc9b3b6f140f276032b722bbe7bbf3a9b1fa61fe71cb65913ebcd118772",
120
120
  "surface": "sandbox-agent",
121
121
  "mountPath": ".playcraft/skills/remix__playcraft-dist-publish"
122
122
  },
123
123
  {
124
124
  "skillRef": "remix/playcraft-image-generation",
125
125
  "version": "1.0.0",
126
- "artifactHash": "a7bd5e50c62250f9c84c600239a57d71f197b88d4dedfa9eec6befc10cb4239a",
126
+ "artifactHash": "91bec2422c750d9d47d5be2796ec5aaffb48de561f2c2d8b92112f37d576f489",
127
127
  "surface": "sandbox-agent",
128
128
  "mountPath": ".playcraft/skills/remix__playcraft-image-generation"
129
129
  },
130
130
  {
131
131
  "skillRef": "remix/playcraft-image-processing",
132
132
  "version": "1.0.0",
133
- "artifactHash": "137ce0b8b76d591148dc0158b5e38abc2fc17f04471fc0d027b0a19d3dde709d",
133
+ "artifactHash": "d845c067bed103c3d1d3f145b1cb8246ffbd6a9ae91efcfbce2eae456819212d",
134
134
  "surface": "sandbox-agent",
135
135
  "mountPath": ".playcraft/skills/remix__playcraft-image-processing"
136
136
  },
137
137
  {
138
138
  "skillRef": "remix/playcraft-prefab",
139
139
  "version": "1.0.0",
140
- "artifactHash": "eb1de9851f842e475bb2ae8bb239d5f9b5ab6bd28fe0c83ae96d8570e1a8b814",
140
+ "artifactHash": "3cce28f5b67398fffaaa6295d27cf514c8e1e1e998d142524facaff7d2c25561",
141
141
  "surface": "sandbox-agent",
142
142
  "mountPath": ".playcraft/skills/remix__playcraft-prefab"
143
143
  },
144
144
  {
145
145
  "skillRef": "remix/playcraft-remix-workflow",
146
146
  "version": "1.0.0",
147
- "artifactHash": "cf5ed218579d49887d6bf2c5f4eb7512ea86684984f57546676df2d6378cd054",
147
+ "artifactHash": "e2a59c61ef5b094a821fbbab3b0f65f906bfc0dfda6f3d8c0b33a6f460dd0963",
148
148
  "surface": "sandbox-agent",
149
149
  "mountPath": ".playcraft/skills/remix__playcraft-remix-workflow"
150
150
  }