phewsh 0.15.68 → 0.15.70
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/bin/phewsh.js +2 -0
- package/commands/task.js +50 -3
- package/package.json +1 -1
package/bin/phewsh.js
CHANGED
|
@@ -112,6 +112,7 @@ const COMMANDS = {
|
|
|
112
112
|
work: () => require('../commands/work')(),
|
|
113
113
|
remember: () => require('../commands/remember')(),
|
|
114
114
|
task: () => require('../commands/task')(),
|
|
115
|
+
dispatch: () => require('../commands/task')(),
|
|
115
116
|
pack: () => require('../commands/pack')(),
|
|
116
117
|
hook: () => require('../commands/hook')(),
|
|
117
118
|
welcome: () => require('../commands/welcome')(),
|
|
@@ -163,6 +164,7 @@ function showHelp() {
|
|
|
163
164
|
console.log(` ${cyan('shim')} ${g('Guaranteed launch banner — phewsh prints status before each tool')}`);
|
|
164
165
|
console.log(` ${cyan('pack')} ${g('Opt-in workflow packs (Karpathy guidelines, GSD…) — attributed, reversible')}`);
|
|
165
166
|
console.log(` ${cyan('task')} ${g('Shared tasks — request, claim, and ship teammate work via branch + PR')}
|
|
167
|
+
${cyan('dispatch')} ${g('Friendly verb over task: dispatch "<title>" to request, <id>|next to claim')}
|
|
166
168
|
${cyan('receipts')} ${g('Proof trail — what agents actually did, with evidence')}`);
|
|
167
169
|
console.log(` ${cyan('remember')} ${g('Jot a decision to .intent/decisions.md — every tool inherits it')}`);
|
|
168
170
|
console.log(` ${cyan('outcomes')} ${g('Decision record — what was kept, reverted, or failed')}`);
|
package/commands/task.js
CHANGED
|
@@ -142,6 +142,33 @@ async function listTasks(config) {
|
|
|
142
142
|
console.log(`\n ${g('Claim one:')} ${w('phewsh task claim <id>')}\n`);
|
|
143
143
|
}
|
|
144
144
|
|
|
145
|
+
async function inviteTeammate(config, email) {
|
|
146
|
+
if (!email || !email.includes('@')) throw new Error('Usage: phewsh task invite <email>');
|
|
147
|
+
const project = await loadProject(config);
|
|
148
|
+
if (project.user_id !== config.supabaseUserId) throw new Error('Only the project owner can invite (Phase 2).');
|
|
149
|
+
await supa.insert('project_invites', {
|
|
150
|
+
project_id: project.id, email, invited_by: config.supabaseUserId,
|
|
151
|
+
}, config.supabaseAccessToken);
|
|
152
|
+
console.log(`\n ${green('✓')} Invited ${w(email)} to ${w(project.name)}`);
|
|
153
|
+
console.log(` ${g('They join with')} ${w('phewsh task join')} ${g('(CLI) or the Join banner on phewsh.com/intent/dashboard')}\n`);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
async function joinProjects(config) {
|
|
157
|
+
// RLS also shows an owner their own outbound invites — only accept ours.
|
|
158
|
+
const invites = (await supa.select('project_invites',
|
|
159
|
+
'accepted_at=is.null&select=id,project_id,email,created_at', config.supabaseAccessToken))
|
|
160
|
+
.filter((inv) => inv.email?.toLowerCase() === (config.email || '').toLowerCase());
|
|
161
|
+
if (!invites.length) {
|
|
162
|
+
console.log(`\n ${g('No pending invites for your account.')}\n`);
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
for (const inv of invites) {
|
|
166
|
+
await supa.rpc('accept_project_invite', { invite_id: inv.id }, config.supabaseAccessToken);
|
|
167
|
+
console.log(`\n ${green('✓')} Joined project ${w(inv.project_id)}`);
|
|
168
|
+
}
|
|
169
|
+
console.log(` ${g('See its tasks from the project repo:')} ${w('phewsh task')}\n`);
|
|
170
|
+
}
|
|
171
|
+
|
|
145
172
|
async function newTask(config, title) {
|
|
146
173
|
if (!title) throw new Error('Usage: phewsh task new "<title>"');
|
|
147
174
|
const project = await loadProject(config);
|
|
@@ -166,7 +193,13 @@ async function claimTask(config, idArg, viaFlag) {
|
|
|
166
193
|
throw new Error('`gh` is not installed or not authenticated — needed to open the PR. Run `gh auth login`.');
|
|
167
194
|
}
|
|
168
195
|
|
|
169
|
-
//
|
|
196
|
+
// `claim next` = the oldest open task; otherwise resolve a short id prefix.
|
|
197
|
+
if (idArg === 'next') {
|
|
198
|
+
const open = await supa.select('tasks',
|
|
199
|
+
`project_id=eq.${project.id}&status=eq.open&select=id&order=created_at.asc&limit=1`, config.supabaseAccessToken);
|
|
200
|
+
if (!open.length) throw new Error('No open tasks to claim.');
|
|
201
|
+
idArg = open[0].id;
|
|
202
|
+
}
|
|
170
203
|
const candidates = await supa.select('tasks',
|
|
171
204
|
`project_id=eq.${project.id}&id=like.${idArg}*&select=*`, config.supabaseAccessToken)
|
|
172
205
|
.catch(() => []);
|
|
@@ -239,8 +272,18 @@ async function claimTask(config, idArg, viaFlag) {
|
|
|
239
272
|
console.log(` ${g('Clean up later:')} ${w(`git worktree remove ${worktree}`)}\n`);
|
|
240
273
|
}
|
|
241
274
|
|
|
275
|
+
// `phewsh dispatch` is the friendly verb over the same machinery — no second
|
|
276
|
+
// architecture. Bare = list; an id prefix = claim; anything else = new task.
|
|
277
|
+
function dispatchToTaskArgs(args) {
|
|
278
|
+
const positional = args.filter((a, i) => !a.startsWith('--') && !(i > 0 && args[i - 1].startsWith('--')));
|
|
279
|
+
if (!positional.length) return ['list'];
|
|
280
|
+
if (positional.length === 1 && (positional[0] === 'next' || /^[0-9a-f-]{6,36}$/i.test(positional[0]))) return ['claim', ...args];
|
|
281
|
+
return ['new', ...args];
|
|
282
|
+
}
|
|
283
|
+
|
|
242
284
|
module.exports = async function run() {
|
|
243
|
-
|
|
285
|
+
let args = process.argv.slice(3);
|
|
286
|
+
if (process.argv[2] === 'dispatch') args = dispatchToTaskArgs(args);
|
|
244
287
|
const sub = args[0] || 'list';
|
|
245
288
|
const viaIdx = args.indexOf('--via');
|
|
246
289
|
const via = viaIdx !== -1 ? args[viaIdx + 1] : null;
|
|
@@ -251,9 +294,13 @@ module.exports = async function run() {
|
|
|
251
294
|
if (sub === 'list') return await listTasks(config);
|
|
252
295
|
if (sub === 'new') return await newTask(config, rest.join(' ').trim());
|
|
253
296
|
if (sub === 'claim') return await claimTask(config, rest[0], via);
|
|
254
|
-
|
|
297
|
+
if (sub === 'invite') return await inviteTeammate(config, rest[0]);
|
|
298
|
+
if (sub === 'join') return await joinProjects(config);
|
|
299
|
+
console.log(`\n Usage: phewsh task [list | new "<title>" | claim <id> [--via <harness>] | invite <email> | join]\n phewsh dispatch ["<title>" | <id> | next] [--via <harness>]\n`);
|
|
255
300
|
} catch (err) {
|
|
256
301
|
console.error(`\n ${red('✗')} ${err.message}\n`);
|
|
257
302
|
process.exitCode = 1;
|
|
258
303
|
}
|
|
259
304
|
};
|
|
305
|
+
|
|
306
|
+
module.exports.dispatchToTaskArgs = dispatchToTaskArgs;
|